From 3518ea6d65f59108d809059004dcf39f1f1ff7b2 Mon Sep 17 00:00:00 2001 From: mmmray Date: Wed, 18 Sep 2024 10:58:43 +0000 Subject: [PATCH] deploy: XTLS/Xray-docs-next@81733cec22d5bdb79f7a23f20e94d7ec66f6f1c3 --- 404.html | 8 ++++---- about/news.html | 6 +++--- .../{404.html-BZTO9xBK.js => 404.html-B0Jvu-JI.js} | 2 +- assets/{Mermaid-D_ImV7ws.js => Mermaid-wJbLESOb.js} | 4 ++-- assets/{Tab-BFTIeLDp.js => Tab-BCE01DFa.js} | 2 +- assets/{Tabs-2T1W4IpS.js => Tabs-CcpaQpRZ.js} | 2 +- .../{api.html-BSTC8zd0.js => api.html-By3Hi2cL.js} | 2 +- .../{api.html-MH0dPqio.js => api.html-CQYAnjeD.js} | 2 +- .../{api.html-BIbKaUtc.js => api.html-D47_38rn.js} | 2 +- assets/{app-DBM4OJyw.js => app-D7uBbsY3.js} | 4 ++-- assets/{arc-CO2v8jBL.js => arc-9Itq1iXl.js} | 2 +- ...basePickBy-BXIHjUx3.js => basePickBy-DpnmgMOi.js} | 2 +- .../{baseUniq-ZJgB7efo.js => baseUniq-D0lZO5yp.js} | 2 +- ...e.html-C9mvdUl-.js => blackhole.html-B1ejrmD3.js} | 2 +- ...e.html-BwT5tNQJ.js => blackhole.html-CguJu2fJ.js} | 2 +- ...e.html-Nc1ubt3S.js => blackhole.html-Cllw1jwu.js} | 2 +- ...C4OVhM5p.js => blockDiagram-V6UOASA5-Dajk3X5E.js} | 2 +- ...l-BcXJ4Ezq.js => browser_dialer.html-B6OwvO3Q.js} | 2 +- ...l-DGUfP3Xp.js => browser_dialer.html-C44hFL-t.js} | 2 +- ...l-bGDmhYds.js => browser_dialer.html-ClnZpsOW.js} | 2 +- ...WV-20XrCBlj.js => c4Diagram-ZHOUKFWV-rVMnyU9f.js} | 2 +- ...tml-Rzsgtj_M.js => ch01-preface.html-B45aaai4.js} | 2 +- ...tml-BQg5DEiN.js => ch01-preface.html-CTOjY6Js.js} | 2 +- ...tml-CFrG0T3Z.js => ch01-preface.html-DOL1zdys.js} | 2 +- ...DaAKcAJL.js => ch02-preparation.html-CBvgJlzh.js} | 2 +- ...B3KTTdXe.js => ch02-preparation.html-CTibWJno.js} | 2 +- ...CpQikq-R.js => ch02-preparation.html-D2OoAhSr.js} | 2 +- ...sh.html-D4Fp2rOo.js => ch03-ssh.html-ChZfg0hU.js} | 2 +- ...sh.html-GVNNjQoi.js => ch03-ssh.html-DYiYMrsa.js} | 2 +- ...sh.html-C-e-7t3_.js => ch03-ssh.html-Dm-1-GXk.js} | 2 +- ...ml-BmDPDZZi.js => ch04-security.html-BxNi21Mp.js} | 2 +- ...ml-C34Buqpd.js => ch04-security.html-DF1Uapzz.js} | 2 +- ...ml-UQusRUO6.js => ch04-security.html-Odh5MrhM.js} | 2 +- ...tml-CE51MwWG.js => ch05-webpage.html-BX0vFLsv.js} | 2 +- ...tml-d_ZCA_oR.js => ch05-webpage.html-D5rnT9ca.js} | 2 +- ...tml-DzMKIlk9.js => ch05-webpage.html-yQkzjvqw.js} | 2 +- ...t0w3WX5.js => ch06-certificates.html-B4kZdJAn.js} | 2 +- ...TgSQmX4.js => ch06-certificates.html-DPu9Gv70.js} | 2 +- ...wdk6ToP.js => ch06-certificates.html-INcZvyys.js} | 2 +- ...o9DNRP9E.js => ch07-xray-server.html-BkxuKbOE.js} | 2 +- ...BDc78tiF.js => ch07-xray-server.html-C8Y2-LpN.js} | 2 +- ...BpVDHJdR.js => ch07-xray-server.html-DacKAZFX.js} | 2 +- ...5SRFBa5.js => ch08-xray-clients.html-CXbOJkkz.js} | 2 +- ...ACa2yr0.js => ch08-xray-clients.html-D4O5No-H.js} | 2 +- ...PrKhFMK.js => ch08-xray-clients.html-djwoDk-t.js} | 2 +- ...ml-Bek16BV4.js => ch09-appendix.html-BLhf4FLL.js} | 2 +- ...ml-DQ43Ovyc.js => ch09-appendix.html-CAGkKWfM.js} | 2 +- ...ml-DH1J1Cus.js => ch09-appendix.html-Z0-Hyrvi.js} | 2 +- assets/channel-BHWICgEe.js | 1 - assets/channel-uApa1cOK.js | 1 + ...UMCIBP-g55d6rFj.js => chunk-AIUMCIBP-v8d5o65o.js} | 2 +- ...CX6ULS-BW7zNCW8.js => chunk-FBCX6ULS-B99hIK7X.js} | 2 +- ...IDI54P-DcJSRBm9.js => chunk-FUIDI54P-B3wdDwu1.js} | 2 +- ...IA4ERB-Cq5yRPLn.js => chunk-IBIA4ERB-LOBGu4Xm.js} | 2 +- ...ENOPKO-CSqkWYi8.js => chunk-JJENOPKO-7opA8rsx.js} | 2 +- ...CO53Z4-RQMWNvLJ.js => chunk-PDCO53Z4-BcfC0Pnz.js} | 2 +- ...GOEX7Z-7nrOxk8C.js => chunk-SVGOEX7Z-FYkNEjJq.js} | 2 +- ...VRG6XP-DsASRjJ5.js => chunk-Z2VRG6XP-CV0pyCU1.js} | 2 +- ...D7Ouc99y.js => classDiagram-MQQPYQM5-p-htZl6Q.js} | 2 +- ...Cgw14.js => classDiagram-v2-4S5WAI72-Dw_LLb4W.js} | 2 +- assets/clone-B3i2nD77.js | 1 - assets/clone-DWnk59eF.js | 1 + ...and.html-DM-t2Q6w.js => command.html-BD6DsLl0.js} | 2 +- ...and.html-CrJVUr4J.js => command.html-BeR19Y5B.js} | 2 +- ...and.html-mB_BYdZd.js => command.html-DwCdhhuq.js} | 2 +- ...ile.html-ZO7e59Ko.js => compile.html-B_SG4Rjg.js} | 2 +- ...ile.html-DXk7Z9BM.js => compile.html-BaQu-P3E.js} | 2 +- ...ile.html-B9Zh6vRY.js => compile.html-sA6hddT4.js} | 2 +- ...nfig.html-DFUKOYQn.js => config.html-BQlgOjHP.js} | 2 +- ...nfig.html-DmHh-Zu1.js => config.html-ByKuPk47.js} | 2 +- ...nfig.html-P39U8JiI.js => config.html-Cx5EaDWl.js} | 2 +- ...6OS2HX-BRwnzFkj.js => dagre-CQ6OS2HX-BAsLDm3b.js} | 2 +- ...sign.html-Tm1rZHD2.js => design.html-B_2qYX1J.js} | 2 +- ...sign.html-CLTK1zJY.js => design.html-CPqW5c51.js} | 2 +- ...sign.html-Cz-hmEoU.js => design.html-DiDr282f.js} | 2 +- ...QLJB-BEfwcC9f.js => diagram-KYCGQLJB-BYpHU2_P.js} | 2 +- .../{dns.html-pLhH-MPA.js => dns.html-36NnIjPg.js} | 2 +- .../{dns.html-C9qEefIG.js => dns.html-DAIzKfOg.js} | 2 +- .../{dns.html-BZs6b75V.js => dns.html-DXkA41xv.js} | 2 +- .../{dns.html-BiECdzTI.js => dns.html-LlEGGVq6.js} | 2 +- .../{dns.html-BqlRMu7q.js => dns.html-TjxOpc7L.js} | 2 +- .../{dns.html-B4w4YpWq.js => dns.html-aOkEAe83.js} | 2 +- ...nt.html-BI9FxX1n.js => document.html-CL3-jl55.js} | 2 +- ...nt.html-BU1vIcEy.js => document.html-XdgZ3aKf.js} | 2 +- ...nt.html-C8cPqOIW.js => document.html-djabafZA.js} | 2 +- ...mo.html-B1Zv0rHv.js => dokodemo.html-BjerEOtA.js} | 2 +- ...mo.html-LpEbF-JC.js => dokodemo.html-DEix7lbM.js} | 2 +- ...mo.html-LnG90uyS.js => dokodemo.html-LPhond1Y.js} | 2 +- .../{env.html-CnZRKI06.js => env.html-BJIm3TxY.js} | 2 +- .../{env.html-0B8aFJq0.js => env.html-CY9_QX-K.js} | 2 +- .../{env.html-BGX1tEf1.js => env.html-D3uMVVBG.js} | 2 +- ...OR-CtIJPNj4.js => erDiagram-762WSSOR-CqJrM1JX.js} | 2 +- ...dns.html-BQH6Y2PN.js => fakedns.html-CTFi8abb.js} | 2 +- ...dns.html-xFYf-feg.js => fakedns.html-D0qX2V-i.js} | 2 +- ...dns.html-DHh-5fVH.js => fakedns.html-Dy1ai5db.js} | 2 +- ...ck.html-DHH-5c7i.js => fallback.html-BEtjGlT0.js} | 2 +- ...ck.html-DyfId2wt.js => fallback.html-CEhYGCcm.js} | 2 +- ...ck.html-BrxCKulv.js => fallback.html-DhKkR0oG.js} | 2 +- ...ml-Dfkic9nm.js => fallbacks-lv1.html-BJFkz_Io.js} | 2 +- ...ml-D0PORcDs.js => fallbacks-lv1.html-D3I9arTU.js} | 2 +- ...ml-BWGggl2y.js => fallbacks-lv1.html-djmxllKD.js} | 2 +- ...H1uh5I.js => fallbacks-with-sni.html-CV6F-_Vm.js} | 2 +- ...7kexlI.js => fallbacks-with-sni.html-DtIkqYxV.js} | 2 +- ...m7wLPL.js => fallbacks-with-sni.html-tnl-ymRI.js} | 2 +- ...-B7tCuQuY.js => flowDiagram-TGP4CI55-c9v2Ypd8.js} | 2 +- ...dom.html-DJ9fcQEp.js => freedom.html-B_annG2n.js} | 2 +- ...dom.html-Bxk1yqEk.js => freedom.html-C35JVucM.js} | 2 +- ...dom.html--UBGeVII.js => freedom.html-DxvEh0kc.js} | 2 +- ...p-lGuXqL.js => ganttDiagram-GAYIUD5S-BewWMKoe.js} | 2 +- ...AW4-IXsRUTzt.js => gitGraph-F2EDSAW4-Df57CYyu.js} | 2 +- ...oDc6j.js => gitGraphDiagram-LGD5RUNZ-CGesRPAa.js} | 2 +- assets/{graph-Oq3lz9SV.js => graph-Cjb-DGHB.js} | 2 +- .../{grpc.html-3jmQQAel.js => grpc.html-C-k3ZkUy.js} | 2 +- .../{grpc.html-Dw2s9Pxy.js => grpc.html-D7RhLn8X.js} | 2 +- .../{grpc.html-3Z809VPJ.js => grpc.html-DKDNkwiH.js} | 2 +- ...guide.html-CzsX8pED.js => guide.html-BFvmPsJG.js} | 2 +- ...guide.html-BmyZZjJ4.js => guide.html-Ce6Zjox0.js} | 2 +- ...guide.html-DwQuBDQN.js => guide.html-CumYazlz.js} | 2 +- assets/{h2.html-DH2CM7PJ.js => h2.html-BBDDvcJa.js} | 2 +- assets/{h2.html-xtI0nSPz.js => h2.html-DKeq75z1.js} | 2 +- assets/{h2.html-C9hnsppv.js => h2.html-DfcDyfAy.js} | 2 +- .../{http.html-Cv9NIFOF.js => http.html-BST5YIxM.js} | 2 +- .../{http.html-Do070lJz.js => http.html-BV-A6WLZ.js} | 2 +- .../{http.html-CXn_nB9h.js => http.html-BiHwk-wd.js} | 2 +- .../{http.html-DKb1_aBq.js => http.html-CwukuwGj.js} | 2 +- .../{http.html-DSD926Zv.js => http.html-DopHzb3b.js} | 2 +- .../{http.html-DgkiVHJm.js => http.html-Y4HdDC5h.js} | 2 +- ...html-mAe7j4MC.js => httpupgrade.html-BD23lJKx.js} | 2 +- ...html-DBZL0AAW.js => httpupgrade.html-BP4DQ20m.js} | 2 +- ...html-DCnMDttv.js => httpupgrade.html-BlNHRqh5.js} | 2 +- ...und.html-BPQMtrP7.js => inbound.html-7zvu4h9X.js} | 2 +- ...und.html-Bl2le8Jm.js => inbound.html-BU0rgh7R.js} | 2 +- ...und.html-B_YBnicn.js => inbound.html-CPFBK2Je.js} | 2 +- ...index.html-BvSm0ea0.js => index.html-1dnJ9JdM.js} | 2 +- ...index.html-D_B2zS6C.js => index.html-BWQkkF3k.js} | 2 +- ...index.html-EU8APivD.js => index.html-BWRtCA19.js} | 2 +- ...index.html-Cprk0yv3.js => index.html-BjEZWu-b.js} | 2 +- ...index.html-DcKrVYG-.js => index.html-C4GmwqWT.js} | 2 +- ...index.html-BYpCGpl_.js => index.html-C7UV3jAp.js} | 2 +- ...index.html-BZQpQc5L.js => index.html-CEGHaj0m.js} | 2 +- ...index.html-BS27sHaP.js => index.html-CZxj-MAp.js} | 2 +- ...index.html-DRWQxS_s.js => index.html-CbpQ50tV.js} | 2 +- ...index.html-BiUJ4Vho.js => index.html-CoQcU5ho.js} | 2 +- ...index.html-qOpCoWzE.js => index.html-D8JovJUC.js} | 2 +- ...index.html-DD2Y-q71.js => index.html-D8QPUz8j.js} | 2 +- ...index.html-Ba-V9K2O.js => index.html-DKW9Z_BK.js} | 2 +- ...index.html-CLXQYZCk.js => index.html-DOOHsyE6.js} | 2 +- ...index.html-DamtlSYx.js => index.html-DZCwNSUw.js} | 2 +- ...index.html-DrIaJd6V.js => index.html-DaFDB0pu.js} | 2 +- ...index.html-Cl2CfXNF.js => index.html-DdCQTcSZ.js} | 2 +- ...index.html-BKL86b_Z.js => index.html-DgnGOa7Z.js} | 2 +- ...index.html-BYuUObTq.js => index.html-Dvi2iZCq.js} | 2 +- ...index.html-Nkob2LGl.js => index.html-Dw7aezrN.js} | 2 +- ...index.html-BBL6nyUH.js => index.html-SiiWkWVt.js} | 2 +- ...-BldMtTiD.js => infoDiagram-GSXZ5C4N-Dq_SIlpy.js} | 2 +- ...all.html-BGuTjt8M.js => install.html-6LqhKuK1.js} | 2 +- ...all.html-f4BUU2Xm.js => install.html-CDzfP6zr.js} | 2 +- ...all.html-CdOf2M5I.js => install.html-DrULhBgt.js} | 2 +- ...tml-BaYh0Fhk.js => iptables_gid.html-CA7RPeCB.js} | 2 +- ...tml-CszhZSj9.js => iptables_gid.html-CD1EfJBO.js} | 2 +- ...tml-CNg7E9Pm.js => iptables_gid.html-DHq3P8hi.js} | 2 +- ...vG2OsD.js => journeyDiagram-35ZZFJAM-CX8IC_rs.js} | 2 +- assets/{json-BFhFIfeY.js => json-31kD9U7J.js} | 2 +- assets/{layout-7AWYeW5Q.js => layout-CHeuV-iP.js} | 2 +- assets/{linear-D4Bza9R9.js => linear-hDJDjKgB.js} | 2 +- .../{log.html-CWv0qLIE.js => log.html-D-t8wlxQ.js} | 2 +- .../{log.html-CA6mG-aB.js => log.html-DnBUJw34.js} | 2 +- .../{log.html-CTirYPei.js => log.html-WdHz5f6a.js} | 2 +- ...ck.html-CyxLLiRu.js => loopback.html-CBRQTJB4.js} | 2 +- ...ck.html-EJfWzfAq.js => loopback.html-DKif3g9A.js} | 2 +- ...ck.html-_BhTQZ0O.js => loopback.html-o32NwpT2.js} | 2 +- ...aid.core-DapiNGBY.js => mermaid.core-D8igZDel.js} | 8 ++++---- ...ics.html-BT-2HBU5.js => metrics.html-CgPI3fiS.js} | 2 +- ...ics.html-Bf2B_O2D.js => metrics.html-DaweKFfI.js} | 2 +- ...ics.html-DSYbmHxQ.js => metrics.html-JNEl1HLA.js} | 2 +- ...EC.js => mindmap-definition-6NGNQFMS-Bk10sQyA.js} | 2 +- .../{mkcp.html-C_htobT5.js => mkcp.html-B5Aq1d1a.js} | 2 +- .../{mkcp.html-BmeTqtsZ.js => mkcp.html-BXKgWezP.js} | 2 +- .../{mkcp.html-CL2dbaXb.js => mkcp.html-C779sbex.js} | 2 +- .../{mkcp.html-OQhbYtWS.js => mkcp.html-DkNOr0bl.js} | 2 +- .../{mkcp.html-ZQWAw5BE.js => mkcp.html-JU6IuAPN.js} | 2 +- .../{mkcp.html-zExRKUGX.js => mkcp.html-uDvBjn0p.js} | 2 +- ...le.html-ByHUK-DJ.js => multiple.html-CyWT5XGQ.js} | 2 +- ...le.html-DUUJue4s.js => multiple.html-D008nLUw.js} | 2 +- ...le.html-Bjf8GHFS.js => multiple.html-D1DFWDpc.js} | 2 +- ...ool.html-DuGDfdPl.js => muxcool.html-C8vY0L1H.js} | 2 +- ...ool.html-u7BHHyP5.js => muxcool.html-CiEIIjvK.js} | 2 +- ...ool.html-DJdC30Uv.js => muxcool.html-DTO-WOrE.js} | 2 +- .../{news.html-AUkvoQ5N.js => news.html-BZwUtxlV.js} | 2 +- .../{news.html-DY4EgGn2.js => news.html-BeMBU7o5.js} | 2 +- .../{news.html-UWoLxj1_.js => news.html-BzYbyEWd.js} | 2 +- ... => nginx_or_haproxy_tls_tunnel.html-CYGy05Cb.js} | 2 +- ... => nginx_or_haproxy_tls_tunnel.html-DR7z7Hc7.js} | 2 +- ... => nginx_or_haproxy_tls_tunnel.html-ojUDrBVB.js} | 2 +- ...html-BbQKQJhA.js => observatory.html-BL0BAmEr.js} | 2 +- ...html-BMuTIcPE.js => observatory.html-CYfqKbFA.js} | 2 +- ...html-Bqwm-FiF.js => observatory.html-i7tnhJjx.js} | 2 +- ...nd.html-w2bkUi_e.js => outbound.html-BpCUakwX.js} | 2 +- ...nd.html-B5z5DraB.js => outbound.html-DVewdwtU.js} | 2 +- ...nd.html-CpUBTknQ.js => outbound.html-lqQ_d0C5.js} | 2 +- ...G-BT3MbsDU.js => pieDiagram-WEX7LNAG-DSCpd-br.js} | 2 +- ...licy.html-BALvOnk-.js => policy.html-CA7G3Iy7.js} | 2 +- ...licy.html-B5iTeN8-.js => policy.html-CzEm0fhQ.js} | 2 +- ...licy.html-Dor87Wko.js => policy.html-DmXgvAr6.js} | 2 +- ...EpiPS.js => quadrantDiagram-SRYJ5FP7-DIAY3wdM.js} | 2 +- ...ct.html-CZZO3MVR.js => redirect.html-B5Y1mNVs.js} | 2 +- ...ct.html-DToMsmqC.js => redirect.html-C82dlL2o.js} | 2 +- ...ct.html-C39Qzzo5.js => redirect.html-VwFhzSui.js} | 2 +- ...70.js => requirementDiagram-V7TESSIR-kqo49K2z.js} | 2 +- ...rse.html-CW54AkoO.js => reverse.html-7Uo0yIWr.js} | 2 +- ...rse.html-DLWtaE_H.js => reverse.html-CfQGiukd.js} | 2 +- ...rse.html-BNoHKOBx.js => reverse.html-CpkNXRut.js} | 2 +- ...M6bRG4P.js => routing-lv1-part1.html-BYLEkwqC.js} | 2 +- ...S-Lwun1.js => routing-lv1-part1.html-Byn2h66N.js} | 2 +- ...XlYZzcq.js => routing-lv1-part1.html-nqov9OAV.js} | 2 +- ...6Xae5-1.js => routing-lv1-part2.html-DNcAgdJC.js} | 2 +- ...X-deabM.js => routing-lv1-part2.html-DfZ-Hwqj.js} | 2 +- ...9GASUUF.js => routing-lv1-part2.html-DlBr3dUB.js} | 2 +- ...ing.html-xbGVqnxN.js => routing.html-BzSZN0AZ.js} | 2 +- ...ing.html-DwJ4ma_9.js => routing.html-CPw6r5Sh.js} | 2 +- ...ing.html-JmIqwiJt.js => routing.html-DxkdJQtA.js} | 2 +- ...44r2-sr.js => sankeyDiagram-XVFEVEVI-BznKSljg.js} | 2 +- ...IUlAD.js => sequenceDiagram-6SD7JOPP-BbpXK4ej.js} | 2 +- ...html-4Bp3Pe-I.js => shadowsocks.html-1_shLAxP.js} | 2 +- ...html-IdnyE_QW.js => shadowsocks.html-BFqzUOKa.js} | 2 +- ...html-k_BIRk0d.js => shadowsocks.html-B_N0lWJn.js} | 2 +- ...html-DTzQHKas.js => shadowsocks.html-Dn_DI_z1.js} | 2 +- ...html-BQ1nQK54.js => shadowsocks.html-Dqj7OTrt.js} | 2 +- ...html-CDcJbYW-.js => shadowsocks.html-nM24MAPY.js} | 2 +- ...socks.html-D6GgkO4d.js => socks.html-BjLWN2Q8.js} | 2 +- ...socks.html-Bo00BDL8.js => socks.html-BqrlqbK0.js} | 2 +- ...socks.html-CMWA8dIs.js => socks.html-CXgansFd.js} | 2 +- ...socks.html-4M7JIsdb.js => socks.html-CdTGmIt-.js} | 2 +- ...socks.html-COrUwqQj.js => socks.html-Cf97X7VI.js} | 2 +- ...socks.html-DN04JS2D.js => socks.html-D_fUXvUa.js} | 2 +- ...p.html-C1SjdxYM.js => splithttp.html-B8IT_7av.js} | 2 +- ...p.html-Ewo4WhOB.js => splithttp.html-BE0bqGcK.js} | 6 +++--- ...p.html-CkMHeQ1D.js => splithttp.html-Cb2yAPj6.js} | 2 +- ...p.html-Bu9SdRS8.js => splithttp.html-Cs2Z785s.js} | 2 +- ...p.html-Dz9QMH4-.js => splithttp.html-CyHPUrRH.js} | 6 +++--- ...p.html-DstjiOIY.js => splithttp.html-DZKLCVFH.js} | 2 +- ...BFbyHmsw.js => stateDiagram-N22R6T2Y-ClLx8lyS.js} | 2 +- assets/stateDiagram-v2-QXVA2PVL-C7QgvS5i.js | 1 - assets/stateDiagram-v2-QXVA2PVL-Cuqsw1mS.js | 1 + ...stats.html-j3PBvFA5.js => stats.html-2bJtqbfP.js} | 2 +- ...stats.html-Bop9jH-f.js => stats.html-Bm3zQ0hO.js} | 2 +- ...stats.html-B7OBry98.js => stats.html-Bx0KYi9t.js} | 2 +- .../{tcp.html-MnZXrAQL.js => tcp.html-CwUsir3D.js} | 2 +- .../{tcp.html-D_ggphrp.js => tcp.html-Cxfh7siK.js} | 2 +- .../{tcp.html-D3RB1Z2i.js => tcp.html-HofSOy7q.js} | 2 +- ...R.js => timeline-definition-SFF34UE4-GwiTm9yo.js} | 2 +- ...roxy.html-2EI4CZc5.js => tproxy.html-BuzTQD_L.js} | 2 +- ...roxy.html-DOLwYTgg.js => tproxy.html-CR4rpIqz.js} | 2 +- ...roxy.html-D5vAMDfU.js => tproxy.html-CVfbj2d5.js} | 2 +- ...pS1d.js => tproxy_ipv4_and_ipv6.html-BDAlrSaS.js} | 2 +- ...13dZ.js => tproxy_ipv4_and_ipv6.html-CpYyYPCl.js} | 2 +- ...R2Id.js => tproxy_ipv4_and_ipv6.html-D1QYhYGk.js} | 2 +- ...ml-mKRKbS-b.js => traffic_stats.html-BVpwRqGM.js} | 2 +- ...ml-BvcqGaeo.js => traffic_stats.html-B_7LVx9s.js} | 2 +- ...ml--hyCQe7p.js => traffic_stats.html-DsMiCXCX.js} | 2 +- ...UyvRv2I.js => transparent_proxy.html-BipaDG8r.js} | 2 +- ..._505nHB.js => transparent_proxy.html-BjCgSdfC.js} | 2 +- ...N6RzNfw.js => transparent_proxy.html-Dbpkmzp6.js} | 2 +- ...t.html-8xgD8RRD.js => transport.html-7DOFUUXD.js} | 2 +- ...t.html-CoXY-KCW.js => transport.html-B2ArwUNN.js} | 2 +- ...t.html-BsB3pOlv.js => transport.html-CBxA3wPn.js} | 2 +- ...ojan.html-2IKlUogk.js => trojan.html-C2P8Dv-p.js} | 2 +- ...ojan.html-1FTyRSM5.js => trojan.html-CeUnbQFN.js} | 2 +- ...ojan.html-UWktEtCO.js => trojan.html-DekTkRrf.js} | 2 +- ...ojan.html-BuFAAu0c.js => trojan.html-DwB8yBqZ.js} | 2 +- ...ojan.html-6FO_V9lu.js => trojan.html-_w6ndVja.js} | 2 +- ...ojan.html-WioOgQKT.js => trojan.html-xViDkd9I.js} | 2 +- ...vless.html-CVgOe_Ra.js => vless.html-B6mgaUnb.js} | 2 +- ...vless.html-CvVYC0xa.js => vless.html-BCUjxVGw.js} | 2 +- ...vless.html-DPYoRUM4.js => vless.html-BYWxnSoj.js} | 2 +- ...vless.html-DH2x8Lsm.js => vless.html-BnbvG0no.js} | 2 +- ...vless.html-BlWWjzcK.js => vless.html-CeF81Ekr.js} | 2 +- ...vless.html-D5OyDM4i.js => vless.html-kZ8IonU8.js} | 2 +- ...vless.html-jHwTWi4h.js => vless.html-oiH3sQfV.js} | 2 +- ...vless.html-Bfk9b9AR.js => vless.html-syxK1TrS.js} | 2 +- ...vless.html-DAk5toqP.js => vless.html-zQehtVf0.js} | 2 +- ...vmess.html-CxHRDmLK.js => vmess.html-3nJoWs8G.js} | 2 +- ...vmess.html-9ma69iWT.js => vmess.html-B3TZl91-.js} | 2 +- ...vmess.html-BQ6qtjqJ.js => vmess.html-Btr59-Cl.js} | 2 +- ...vmess.html-ILF_tpZ9.js => vmess.html-C2MIBK-h.js} | 2 +- ...vmess.html-D8fkP4-1.js => vmess.html-CDBIkJMN.js} | 2 +- ...vmess.html-BR7lDLGa.js => vmess.html-CktEh3JK.js} | 2 +- ...vmess.html-zYdoLiG_.js => vmess.html-D8plPLT5.js} | 2 +- ...vmess.html-Bgid-6Wa.js => vmess.html-DUx4NlE2.js} | 2 +- ...vmess.html-uLwk-fUW.js => vmess.html-RimzC-nX.js} | 2 +- .../{warp.html-DjzUs3nN.js => warp.html-Ck2P9Tg0.js} | 2 +- .../{warp.html-BFiya00c.js => warp.html-CqXxUSeb.js} | 2 +- .../{warp.html-B33XWZbi.js => warp.html-mob0uukM.js} | 2 +- ...t.html-BZsgtVoW.js => websocket.html-2zGXYi2c.js} | 2 +- ...t.html-MgdanL8C.js => websocket.html-DvhOz-O4.js} | 2 +- ...t.html-D2_1H1Lb.js => websocket.html-XpyUndOJ.js} | 2 +- ...d.html-AcuxmEqH.js => wireguard.html-B6z9zn0C.js} | 2 +- ...d.html-BRdIxC_E.js => wireguard.html-BSlNcaJF.js} | 2 +- ...d.html--TSe5kNc.js => wireguard.html-C7TRB15X.js} | 2 +- ...d.html-D8U2MJad.js => wireguard.html-CAQPxeg-.js} | 2 +- ...d.html-C7zjxZ_o.js => wireguard.html-CTyw04SG.js} | 2 +- ...d.html-Da2wnVY_.js => wireguard.html-CtnQlY0W.js} | 2 +- .../{work.html-SMvM6VpF.js => work.html-BzVygHoH.js} | 2 +- .../{work.html-CmnVL4Vh.js => work.html-C4aNtZOg.js} | 2 +- .../{work.html-DS7NfRpF.js => work.html-CmqVWG7K.js} | 2 +- .../{xtls.html-C840N25V.js => xtls.html-7ni9fSNN.js} | 2 +- .../{xtls.html-BK7C9n7n.js => xtls.html-CX-lgDou.js} | 2 +- .../{xtls.html-DYo3Adlx.js => xtls.html-DkIUVXSC.js} | 2 +- ...QiVXRw.js => xychartDiagram-BZZU7QT5-v7lh-lWp.js} | 2 +- config/api.html | 6 +++--- config/dns.html | 6 +++--- config/fakedns.html | 6 +++--- config/features/browser_dialer.html | 6 +++--- config/features/env.html | 6 +++--- config/features/fallback.html | 6 +++--- config/features/multiple.html | 6 +++--- config/features/xtls.html | 6 +++--- config/inbound.html | 6 +++--- config/inbounds/dokodemo.html | 6 +++--- config/inbounds/http.html | 6 +++--- config/inbounds/shadowsocks.html | 6 +++--- config/inbounds/socks.html | 6 +++--- config/inbounds/trojan.html | 6 +++--- config/inbounds/vless.html | 6 +++--- config/inbounds/vmess.html | 6 +++--- config/inbounds/wireguard.html | 6 +++--- config/index.html | 6 +++--- config/log.html | 6 +++--- config/metrics.html | 6 +++--- config/observatory.html | 6 +++--- config/outbound.html | 6 +++--- config/outbounds/blackhole.html | 6 +++--- config/outbounds/dns.html | 6 +++--- config/outbounds/freedom.html | 6 +++--- config/outbounds/http.html | 6 +++--- config/outbounds/loopback.html | 6 +++--- config/outbounds/shadowsocks.html | 6 +++--- config/outbounds/socks.html | 6 +++--- config/outbounds/trojan.html | 6 +++--- config/outbounds/vless.html | 6 +++--- config/outbounds/vmess.html | 6 +++--- config/outbounds/wireguard.html | 6 +++--- config/policy.html | 6 +++--- config/reverse.html | 6 +++--- config/routing.html | 6 +++--- config/stats.html | 6 +++--- config/transport.html | 6 +++--- config/transports/grpc.html | 6 +++--- config/transports/h2.html | 6 +++--- config/transports/httpupgrade.html | 6 +++--- config/transports/mkcp.html | 6 +++--- config/transports/splithttp.html | 10 +++++----- config/transports/tcp.html | 6 +++--- config/transports/websocket.html | 6 +++--- development/index.html | 6 +++--- development/intro/compile.html | 6 +++--- development/intro/design.html | 6 +++--- development/intro/guide.html | 6 +++--- development/protocols/mkcp.html | 6 +++--- development/protocols/muxcool.html | 6 +++--- development/protocols/vless.html | 6 +++--- development/protocols/vmess.html | 6 +++--- document/command.html | 6 +++--- document/config.html | 6 +++--- document/document.html | 6 +++--- document/index.html | 6 +++--- document/install.html | 6 +++--- document/level-0/ch01-preface.html | 6 +++--- document/level-0/ch02-preparation.html | 6 +++--- document/level-0/ch03-ssh.html | 6 +++--- document/level-0/ch04-security.html | 6 +++--- document/level-0/ch05-webpage.html | 6 +++--- document/level-0/ch06-certificates.html | 6 +++--- document/level-0/ch07-xray-server.html | 6 +++--- document/level-0/ch08-xray-clients.html | 6 +++--- document/level-0/ch09-appendix.html | 6 +++--- document/level-0/index.html | 6 +++--- document/level-1/fallbacks-lv1.html | 6 +++--- document/level-1/fallbacks-with-sni.html | 6 +++--- document/level-1/index.html | 6 +++--- document/level-1/routing-lv1-part1.html | 6 +++--- document/level-1/routing-lv1-part2.html | 6 +++--- document/level-1/work.html | 6 +++--- document/level-2/index.html | 6 +++--- document/level-2/iptables_gid.html | 6 +++--- document/level-2/nginx_or_haproxy_tls_tunnel.html | 6 +++--- document/level-2/redirect.html | 6 +++--- document/level-2/tproxy.html | 6 +++--- document/level-2/tproxy_ipv4_and_ipv6.html | 6 +++--- document/level-2/traffic_stats.html | 6 +++--- .../level-2/transparent_proxy/transparent_proxy.html | 6 +++--- document/level-2/warp.html | 6 +++--- en/about/news.html | 6 +++--- en/config/api.html | 6 +++--- en/config/dns.html | 6 +++--- en/config/fakedns.html | 6 +++--- en/config/features/browser_dialer.html | 6 +++--- en/config/features/env.html | 6 +++--- en/config/features/fallback.html | 6 +++--- en/config/features/multiple.html | 6 +++--- en/config/features/xtls.html | 6 +++--- en/config/inbound.html | 6 +++--- en/config/inbounds/dokodemo.html | 6 +++--- en/config/inbounds/http.html | 6 +++--- en/config/inbounds/shadowsocks.html | 6 +++--- en/config/inbounds/socks.html | 6 +++--- en/config/inbounds/trojan.html | 6 +++--- en/config/inbounds/vless.html | 6 +++--- en/config/inbounds/vmess.html | 6 +++--- en/config/inbounds/wireguard.html | 6 +++--- en/config/index.html | 6 +++--- en/config/log.html | 6 +++--- en/config/metrics.html | 6 +++--- en/config/observatory.html | 6 +++--- en/config/outbound.html | 6 +++--- en/config/outbounds/blackhole.html | 6 +++--- en/config/outbounds/dns.html | 6 +++--- en/config/outbounds/freedom.html | 6 +++--- en/config/outbounds/http.html | 6 +++--- en/config/outbounds/loopback.html | 6 +++--- en/config/outbounds/shadowsocks.html | 6 +++--- en/config/outbounds/socks.html | 6 +++--- en/config/outbounds/trojan.html | 6 +++--- en/config/outbounds/vless.html | 6 +++--- en/config/outbounds/vmess.html | 6 +++--- en/config/outbounds/wireguard.html | 6 +++--- en/config/policy.html | 6 +++--- en/config/reverse.html | 6 +++--- en/config/routing.html | 6 +++--- en/config/stats.html | 6 +++--- en/config/transport.html | 6 +++--- en/config/transports/grpc.html | 6 +++--- en/config/transports/h2.html | 6 +++--- en/config/transports/httpupgrade.html | 6 +++--- en/config/transports/mkcp.html | 6 +++--- en/config/transports/splithttp.html | 12 ++++++------ en/config/transports/tcp.html | 6 +++--- en/config/transports/websocket.html | 6 +++--- en/development/index.html | 6 +++--- en/development/intro/compile.html | 6 +++--- en/development/intro/design.html | 6 +++--- en/development/intro/guide.html | 6 +++--- en/development/protocols/mkcp.html | 6 +++--- en/development/protocols/muxcool.html | 6 +++--- en/development/protocols/vless.html | 6 +++--- en/development/protocols/vmess.html | 6 +++--- en/document/command.html | 6 +++--- en/document/config.html | 6 +++--- en/document/document.html | 6 +++--- en/document/index.html | 6 +++--- en/document/install.html | 6 +++--- en/document/level-0/ch01-preface.html | 6 +++--- en/document/level-0/ch02-preparation.html | 6 +++--- en/document/level-0/ch03-ssh.html | 6 +++--- en/document/level-0/ch04-security.html | 6 +++--- en/document/level-0/ch05-webpage.html | 6 +++--- en/document/level-0/ch06-certificates.html | 6 +++--- en/document/level-0/ch07-xray-server.html | 6 +++--- en/document/level-0/ch08-xray-clients.html | 6 +++--- en/document/level-0/ch09-appendix.html | 6 +++--- en/document/level-0/index.html | 6 +++--- en/document/level-1/fallbacks-lv1.html | 6 +++--- en/document/level-1/fallbacks-with-sni.html | 6 +++--- en/document/level-1/index.html | 6 +++--- en/document/level-1/routing-lv1-part1.html | 6 +++--- en/document/level-1/routing-lv1-part2.html | 6 +++--- en/document/level-1/work.html | 6 +++--- en/document/level-2/index.html | 6 +++--- en/document/level-2/iptables_gid.html | 6 +++--- en/document/level-2/nginx_or_haproxy_tls_tunnel.html | 6 +++--- en/document/level-2/redirect.html | 6 +++--- en/document/level-2/tproxy.html | 6 +++--- en/document/level-2/tproxy_ipv4_and_ipv6.html | 6 +++--- en/document/level-2/traffic_stats.html | 6 +++--- .../level-2/transparent_proxy/transparent_proxy.html | 6 +++--- en/document/level-2/warp.html | 6 +++--- en/index.html | 6 +++--- index.html | 6 +++--- ru/about/news.html | 6 +++--- ru/config/api.html | 6 +++--- ru/config/dns.html | 6 +++--- ru/config/fakedns.html | 6 +++--- ru/config/features/browser_dialer.html | 6 +++--- ru/config/features/env.html | 6 +++--- ru/config/features/fallback.html | 6 +++--- ru/config/features/multiple.html | 6 +++--- ru/config/features/xtls.html | 6 +++--- ru/config/inbound.html | 6 +++--- ru/config/inbounds/dokodemo.html | 6 +++--- ru/config/inbounds/http.html | 6 +++--- ru/config/inbounds/shadowsocks.html | 6 +++--- ru/config/inbounds/socks.html | 6 +++--- ru/config/inbounds/trojan.html | 6 +++--- ru/config/inbounds/vless.html | 6 +++--- ru/config/inbounds/vmess.html | 6 +++--- ru/config/inbounds/wireguard.html | 6 +++--- ru/config/index.html | 6 +++--- ru/config/log.html | 6 +++--- ru/config/metrics.html | 6 +++--- ru/config/observatory.html | 6 +++--- ru/config/outbound.html | 6 +++--- ru/config/outbounds/blackhole.html | 6 +++--- ru/config/outbounds/dns.html | 6 +++--- ru/config/outbounds/freedom.html | 6 +++--- ru/config/outbounds/http.html | 6 +++--- ru/config/outbounds/loopback.html | 6 +++--- ru/config/outbounds/shadowsocks.html | 6 +++--- ru/config/outbounds/socks.html | 6 +++--- ru/config/outbounds/trojan.html | 6 +++--- ru/config/outbounds/vless.html | 6 +++--- ru/config/outbounds/vmess.html | 6 +++--- ru/config/outbounds/wireguard.html | 6 +++--- ru/config/policy.html | 6 +++--- ru/config/reverse.html | 6 +++--- ru/config/routing.html | 6 +++--- ru/config/stats.html | 6 +++--- ru/config/transport.html | 6 +++--- ru/config/transports/grpc.html | 6 +++--- ru/config/transports/h2.html | 6 +++--- ru/config/transports/httpupgrade.html | 6 +++--- ru/config/transports/mkcp.html | 6 +++--- ru/config/transports/splithttp.html | 6 +++--- ru/config/transports/tcp.html | 6 +++--- ru/config/transports/websocket.html | 6 +++--- ru/development/index.html | 6 +++--- ru/development/intro/compile.html | 6 +++--- ru/development/intro/design.html | 6 +++--- ru/development/intro/guide.html | 6 +++--- ru/development/protocols/mkcp.html | 6 +++--- ru/development/protocols/muxcool.html | 6 +++--- ru/development/protocols/vless.html | 6 +++--- ru/development/protocols/vmess.html | 6 +++--- ru/document/command.html | 6 +++--- ru/document/config.html | 6 +++--- ru/document/document.html | 6 +++--- ru/document/index.html | 6 +++--- ru/document/install.html | 6 +++--- ru/document/level-0/ch01-preface.html | 6 +++--- ru/document/level-0/ch02-preparation.html | 6 +++--- ru/document/level-0/ch03-ssh.html | 6 +++--- ru/document/level-0/ch04-security.html | 6 +++--- ru/document/level-0/ch05-webpage.html | 6 +++--- ru/document/level-0/ch06-certificates.html | 6 +++--- ru/document/level-0/ch07-xray-server.html | 6 +++--- ru/document/level-0/ch08-xray-clients.html | 6 +++--- ru/document/level-0/ch09-appendix.html | 6 +++--- ru/document/level-0/index.html | 6 +++--- ru/document/level-1/fallbacks-lv1.html | 6 +++--- ru/document/level-1/fallbacks-with-sni.html | 6 +++--- ru/document/level-1/index.html | 6 +++--- ru/document/level-1/routing-lv1-part1.html | 6 +++--- ru/document/level-1/routing-lv1-part2.html | 6 +++--- ru/document/level-1/work.html | 6 +++--- ru/document/level-2/index.html | 6 +++--- ru/document/level-2/iptables_gid.html | 6 +++--- ru/document/level-2/nginx_or_haproxy_tls_tunnel.html | 6 +++--- ru/document/level-2/redirect.html | 6 +++--- ru/document/level-2/tproxy.html | 6 +++--- ru/document/level-2/tproxy_ipv4_and_ipv6.html | 6 +++--- ru/document/level-2/traffic_stats.html | 6 +++--- .../level-2/transparent_proxy/transparent_proxy.html | 6 +++--- ru/document/level-2/warp.html | 6 +++--- ru/index.html | 6 +++--- 563 files changed, 1087 insertions(+), 1087 deletions(-) rename assets/{404.html-BZTO9xBK.js => 404.html-B0Jvu-JI.js} (63%) rename assets/{Mermaid-D_ImV7ws.js => Mermaid-wJbLESOb.js} (89%) rename assets/{Tab-BFTIeLDp.js => Tab-BCE01DFa.js} (89%) rename assets/{Tabs-2T1W4IpS.js => Tabs-CcpaQpRZ.js} (95%) rename assets/{api.html-BSTC8zd0.js => api.html-By3Hi2cL.js} (99%) rename assets/{api.html-MH0dPqio.js => api.html-CQYAnjeD.js} (99%) rename assets/{api.html-BIbKaUtc.js => api.html-D47_38rn.js} (99%) rename assets/{app-DBM4OJyw.js => app-D7uBbsY3.js} (88%) rename assets/{arc-CO2v8jBL.js => arc-9Itq1iXl.js} (98%) rename assets/{basePickBy-BXIHjUx3.js => basePickBy-DpnmgMOi.js} (94%) rename assets/{baseUniq-ZJgB7efo.js => baseUniq-D0lZO5yp.js} (98%) rename assets/{blackhole.html-C9mvdUl-.js => blackhole.html-B1ejrmD3.js} (98%) rename assets/{blackhole.html-BwT5tNQJ.js => blackhole.html-CguJu2fJ.js} (97%) rename assets/{blackhole.html-Nc1ubt3S.js => blackhole.html-Cllw1jwu.js} (97%) rename assets/{blockDiagram-V6UOASA5-C4OVhM5p.js => blockDiagram-V6UOASA5-Dajk3X5E.js} (99%) rename assets/{browser_dialer.html-BcXJ4Ezq.js => browser_dialer.html-B6OwvO3Q.js} (99%) rename assets/{browser_dialer.html-DGUfP3Xp.js => browser_dialer.html-C44hFL-t.js} (98%) rename assets/{browser_dialer.html-bGDmhYds.js => browser_dialer.html-ClnZpsOW.js} (99%) rename assets/{c4Diagram-ZHOUKFWV-20XrCBlj.js => c4Diagram-ZHOUKFWV-rVMnyU9f.js} (99%) rename assets/{ch01-preface.html-Rzsgtj_M.js => ch01-preface.html-B45aaai4.js} (99%) rename assets/{ch01-preface.html-BQg5DEiN.js => ch01-preface.html-CTOjY6Js.js} (99%) rename assets/{ch01-preface.html-CFrG0T3Z.js => ch01-preface.html-DOL1zdys.js} (99%) rename assets/{ch02-preparation.html-DaAKcAJL.js => ch02-preparation.html-CBvgJlzh.js} (99%) rename assets/{ch02-preparation.html-B3KTTdXe.js => ch02-preparation.html-CTibWJno.js} (98%) rename assets/{ch02-preparation.html-CpQikq-R.js => ch02-preparation.html-D2OoAhSr.js} (98%) rename assets/{ch03-ssh.html-D4Fp2rOo.js => ch03-ssh.html-ChZfg0hU.js} (99%) rename assets/{ch03-ssh.html-GVNNjQoi.js => ch03-ssh.html-DYiYMrsa.js} (99%) rename assets/{ch03-ssh.html-C-e-7t3_.js => ch03-ssh.html-Dm-1-GXk.js} (99%) rename assets/{ch04-security.html-BmDPDZZi.js => ch04-security.html-BxNi21Mp.js} (99%) rename assets/{ch04-security.html-C34Buqpd.js => ch04-security.html-DF1Uapzz.js} (99%) rename assets/{ch04-security.html-UQusRUO6.js => ch04-security.html-Odh5MrhM.js} (99%) rename assets/{ch05-webpage.html-CE51MwWG.js => ch05-webpage.html-BX0vFLsv.js} (99%) rename assets/{ch05-webpage.html-d_ZCA_oR.js => ch05-webpage.html-D5rnT9ca.js} (99%) rename assets/{ch05-webpage.html-DzMKIlk9.js => ch05-webpage.html-yQkzjvqw.js} (99%) rename assets/{ch06-certificates.html-bt0w3WX5.js => ch06-certificates.html-B4kZdJAn.js} (99%) rename assets/{ch06-certificates.html-BTgSQmX4.js => ch06-certificates.html-DPu9Gv70.js} (99%) rename assets/{ch06-certificates.html-Dwdk6ToP.js => ch06-certificates.html-INcZvyys.js} (99%) rename assets/{ch07-xray-server.html-o9DNRP9E.js => ch07-xray-server.html-BkxuKbOE.js} (99%) rename assets/{ch07-xray-server.html-BDc78tiF.js => ch07-xray-server.html-C8Y2-LpN.js} (99%) rename assets/{ch07-xray-server.html-BpVDHJdR.js => ch07-xray-server.html-DacKAZFX.js} (99%) rename assets/{ch08-xray-clients.html-D5SRFBa5.js => ch08-xray-clients.html-CXbOJkkz.js} (99%) rename assets/{ch08-xray-clients.html-BACa2yr0.js => ch08-xray-clients.html-D4O5No-H.js} (99%) rename assets/{ch08-xray-clients.html-BPrKhFMK.js => ch08-xray-clients.html-djwoDk-t.js} (99%) rename assets/{ch09-appendix.html-Bek16BV4.js => ch09-appendix.html-BLhf4FLL.js} (99%) rename assets/{ch09-appendix.html-DQ43Ovyc.js => ch09-appendix.html-CAGkKWfM.js} (99%) rename assets/{ch09-appendix.html-DH1J1Cus.js => ch09-appendix.html-Z0-Hyrvi.js} (99%) delete mode 100644 assets/channel-BHWICgEe.js create mode 100644 assets/channel-uApa1cOK.js rename assets/{chunk-AIUMCIBP-g55d6rFj.js => chunk-AIUMCIBP-v8d5o65o.js} (95%) rename assets/{chunk-FBCX6ULS-BW7zNCW8.js => chunk-FBCX6ULS-B99hIK7X.js} (66%) rename assets/{chunk-FUIDI54P-DcJSRBm9.js => chunk-FUIDI54P-B3wdDwu1.js} (90%) rename assets/{chunk-IBIA4ERB-Cq5yRPLn.js => chunk-IBIA4ERB-LOBGu4Xm.js} (99%) rename assets/{chunk-JJENOPKO-CSqkWYi8.js => chunk-JJENOPKO-7opA8rsx.js} (78%) rename assets/{chunk-PDCO53Z4-RQMWNvLJ.js => chunk-PDCO53Z4-BcfC0Pnz.js} (98%) rename assets/{chunk-SVGOEX7Z-7nrOxk8C.js => chunk-SVGOEX7Z-FYkNEjJq.js} (99%) rename assets/{chunk-Z2VRG6XP-DsASRjJ5.js => chunk-Z2VRG6XP-CV0pyCU1.js} (99%) rename assets/{classDiagram-MQQPYQM5-D7Ouc99y.js => classDiagram-MQQPYQM5-p-htZl6Q.js} (96%) rename assets/{classDiagram-v2-4S5WAI72-OQWCgw14.js => classDiagram-v2-4S5WAI72-Dw_LLb4W.js} (96%) delete mode 100644 assets/clone-B3i2nD77.js create mode 100644 assets/clone-DWnk59eF.js rename assets/{command.html-DM-t2Q6w.js => command.html-BD6DsLl0.js} (99%) rename assets/{command.html-CrJVUr4J.js => command.html-BeR19Y5B.js} (99%) rename assets/{command.html-mB_BYdZd.js => command.html-DwCdhhuq.js} (99%) rename assets/{compile.html-ZO7e59Ko.js => compile.html-B_SG4Rjg.js} (99%) rename assets/{compile.html-DXk7Z9BM.js => compile.html-BaQu-P3E.js} (99%) rename assets/{compile.html-B9Zh6vRY.js => compile.html-sA6hddT4.js} (99%) rename assets/{config.html-DFUKOYQn.js => config.html-BQlgOjHP.js} (99%) rename assets/{config.html-DmHh-Zu1.js => config.html-ByKuPk47.js} (99%) rename assets/{config.html-P39U8JiI.js => config.html-Cx5EaDWl.js} (99%) rename assets/{dagre-CQ6OS2HX-BRwnzFkj.js => dagre-CQ6OS2HX-BAsLDm3b.js} (97%) rename assets/{design.html-Tm1rZHD2.js => design.html-B_2qYX1J.js} (97%) rename assets/{design.html-CLTK1zJY.js => design.html-CPqW5c51.js} (98%) rename assets/{design.html-Cz-hmEoU.js => design.html-DiDr282f.js} (97%) rename assets/{diagram-KYCGQLJB-BEfwcC9f.js => diagram-KYCGQLJB-BYpHU2_P.js} (91%) rename assets/{dns.html-pLhH-MPA.js => dns.html-36NnIjPg.js} (98%) rename assets/{dns.html-C9qEefIG.js => dns.html-DAIzKfOg.js} (99%) rename assets/{dns.html-BZs6b75V.js => dns.html-DXkA41xv.js} (99%) rename assets/{dns.html-BiECdzTI.js => dns.html-LlEGGVq6.js} (99%) rename assets/{dns.html-BqlRMu7q.js => dns.html-TjxOpc7L.js} (98%) rename assets/{dns.html-B4w4YpWq.js => dns.html-aOkEAe83.js} (98%) rename assets/{document.html-BI9FxX1n.js => document.html-CL3-jl55.js} (98%) rename assets/{document.html-BU1vIcEy.js => document.html-XdgZ3aKf.js} (98%) rename assets/{document.html-C8cPqOIW.js => document.html-djabafZA.js} (98%) rename assets/{dokodemo.html-B1Zv0rHv.js => dokodemo.html-BjerEOtA.js} (99%) rename assets/{dokodemo.html-LpEbF-JC.js => dokodemo.html-DEix7lbM.js} (99%) rename assets/{dokodemo.html-LnG90uyS.js => dokodemo.html-LPhond1Y.js} (99%) rename assets/{env.html-CnZRKI06.js => env.html-BJIm3TxY.js} (98%) rename assets/{env.html-0B8aFJq0.js => env.html-CY9_QX-K.js} (97%) rename assets/{env.html-BGX1tEf1.js => env.html-D3uMVVBG.js} (97%) rename assets/{erDiagram-762WSSOR-CtIJPNj4.js => erDiagram-762WSSOR-CqJrM1JX.js} (99%) rename assets/{fakedns.html-BQH6Y2PN.js => fakedns.html-CTFi8abb.js} (99%) rename assets/{fakedns.html-xFYf-feg.js => fakedns.html-D0qX2V-i.js} (99%) rename assets/{fakedns.html-DHh-5fVH.js => fakedns.html-Dy1ai5db.js} (99%) rename assets/{fallback.html-DHH-5c7i.js => fallback.html-BEtjGlT0.js} (99%) rename assets/{fallback.html-DyfId2wt.js => fallback.html-CEhYGCcm.js} (99%) rename assets/{fallback.html-BrxCKulv.js => fallback.html-DhKkR0oG.js} (99%) rename assets/{fallbacks-lv1.html-Dfkic9nm.js => fallbacks-lv1.html-BJFkz_Io.js} (99%) rename assets/{fallbacks-lv1.html-D0PORcDs.js => fallbacks-lv1.html-D3I9arTU.js} (99%) rename assets/{fallbacks-lv1.html-BWGggl2y.js => fallbacks-lv1.html-djmxllKD.js} (99%) rename assets/{fallbacks-with-sni.html-wlH1uh5I.js => fallbacks-with-sni.html-CV6F-_Vm.js} (99%) rename assets/{fallbacks-with-sni.html-Qo7kexlI.js => fallbacks-with-sni.html-DtIkqYxV.js} (99%) rename assets/{fallbacks-with-sni.html-2lm7wLPL.js => fallbacks-with-sni.html-tnl-ymRI.js} (99%) rename assets/{flowDiagram-TGP4CI55-B7tCuQuY.js => flowDiagram-TGP4CI55-c9v2Ypd8.js} (99%) rename assets/{freedom.html-DJ9fcQEp.js => freedom.html-B_annG2n.js} (99%) rename assets/{freedom.html-Bxk1yqEk.js => freedom.html-C35JVucM.js} (99%) rename assets/{freedom.html--UBGeVII.js => freedom.html-DxvEh0kc.js} (99%) rename assets/{ganttDiagram-GAYIUD5S-p-lGuXqL.js => ganttDiagram-GAYIUD5S-BewWMKoe.js} (99%) rename assets/{gitGraph-F2EDSAW4-IXsRUTzt.js => gitGraph-F2EDSAW4-Df57CYyu.js} (99%) rename assets/{gitGraphDiagram-LGD5RUNZ-DqNoDc6j.js => gitGraphDiagram-LGD5RUNZ-CGesRPAa.js} (98%) rename assets/{graph-Oq3lz9SV.js => graph-Cjb-DGHB.js} (97%) rename assets/{grpc.html-3jmQQAel.js => grpc.html-C-k3ZkUy.js} (99%) rename assets/{grpc.html-Dw2s9Pxy.js => grpc.html-D7RhLn8X.js} (99%) rename assets/{grpc.html-3Z809VPJ.js => grpc.html-DKDNkwiH.js} (99%) rename assets/{guide.html-CzsX8pED.js => guide.html-BFvmPsJG.js} (99%) rename assets/{guide.html-BmyZZjJ4.js => guide.html-Ce6Zjox0.js} (99%) rename assets/{guide.html-DwQuBDQN.js => guide.html-CumYazlz.js} (99%) rename assets/{h2.html-DH2CM7PJ.js => h2.html-BBDDvcJa.js} (99%) rename assets/{h2.html-xtI0nSPz.js => h2.html-DKeq75z1.js} (98%) rename assets/{h2.html-C9hnsppv.js => h2.html-DfcDyfAy.js} (98%) rename assets/{http.html-Cv9NIFOF.js => http.html-BST5YIxM.js} (98%) rename assets/{http.html-Do070lJz.js => http.html-BV-A6WLZ.js} (99%) rename assets/{http.html-CXn_nB9h.js => http.html-BiHwk-wd.js} (98%) rename assets/{http.html-DKb1_aBq.js => http.html-CwukuwGj.js} (98%) rename assets/{http.html-DSD926Zv.js => http.html-DopHzb3b.js} (98%) rename assets/{http.html-DgkiVHJm.js => http.html-Y4HdDC5h.js} (98%) rename assets/{httpupgrade.html-mAe7j4MC.js => httpupgrade.html-BD23lJKx.js} (98%) rename assets/{httpupgrade.html-DBZL0AAW.js => httpupgrade.html-BP4DQ20m.js} (98%) rename assets/{httpupgrade.html-DCnMDttv.js => httpupgrade.html-BlNHRqh5.js} (98%) rename assets/{inbound.html-BPQMtrP7.js => inbound.html-7zvu4h9X.js} (99%) rename assets/{inbound.html-Bl2le8Jm.js => inbound.html-BU0rgh7R.js} (99%) rename assets/{inbound.html-B_YBnicn.js => inbound.html-CPFBK2Je.js} (99%) rename assets/{index.html-BvSm0ea0.js => index.html-1dnJ9JdM.js} (97%) rename assets/{index.html-D_B2zS6C.js => index.html-BWQkkF3k.js} (98%) rename assets/{index.html-EU8APivD.js => index.html-BWRtCA19.js} (96%) rename assets/{index.html-Cprk0yv3.js => index.html-BjEZWu-b.js} (99%) rename assets/{index.html-DcKrVYG-.js => index.html-C4GmwqWT.js} (99%) rename assets/{index.html-BYpCGpl_.js => index.html-C7UV3jAp.js} (94%) rename assets/{index.html-BZQpQc5L.js => index.html-CEGHaj0m.js} (98%) rename assets/{index.html-BS27sHaP.js => index.html-CZxj-MAp.js} (98%) rename assets/{index.html-DRWQxS_s.js => index.html-CbpQ50tV.js} (98%) rename assets/{index.html-BiUJ4Vho.js => index.html-CoQcU5ho.js} (97%) rename assets/{index.html-qOpCoWzE.js => index.html-D8JovJUC.js} (98%) rename assets/{index.html-DD2Y-q71.js => index.html-D8QPUz8j.js} (94%) rename assets/{index.html-Ba-V9K2O.js => index.html-DKW9Z_BK.js} (98%) rename assets/{index.html-CLXQYZCk.js => index.html-DOOHsyE6.js} (98%) rename assets/{index.html-DamtlSYx.js => index.html-DZCwNSUw.js} (99%) rename assets/{index.html-DrIaJd6V.js => index.html-DaFDB0pu.js} (98%) rename assets/{index.html-Cl2CfXNF.js => index.html-DdCQTcSZ.js} (98%) rename assets/{index.html-BKL86b_Z.js => index.html-DgnGOa7Z.js} (98%) rename assets/{index.html-BYuUObTq.js => index.html-Dvi2iZCq.js} (99%) rename assets/{index.html-Nkob2LGl.js => index.html-Dw7aezrN.js} (98%) rename assets/{index.html-BBL6nyUH.js => index.html-SiiWkWVt.js} (97%) rename assets/{infoDiagram-GSXZ5C4N-BldMtTiD.js => infoDiagram-GSXZ5C4N-Dq_SIlpy.js} (62%) rename assets/{install.html-BGuTjt8M.js => install.html-6LqhKuK1.js} (99%) rename assets/{install.html-f4BUU2Xm.js => install.html-CDzfP6zr.js} (99%) rename assets/{install.html-CdOf2M5I.js => install.html-DrULhBgt.js} (99%) rename assets/{iptables_gid.html-BaYh0Fhk.js => iptables_gid.html-CA7RPeCB.js} (99%) rename assets/{iptables_gid.html-CszhZSj9.js => iptables_gid.html-CD1EfJBO.js} (99%) rename assets/{iptables_gid.html-CNg7E9Pm.js => iptables_gid.html-DHq3P8hi.js} (99%) rename assets/{journeyDiagram-35ZZFJAM-BivG2OsD.js => journeyDiagram-35ZZFJAM-CX8IC_rs.js} (98%) rename assets/{json-BFhFIfeY.js => json-31kD9U7J.js} (68%) rename assets/{layout-7AWYeW5Q.js => layout-CHeuV-iP.js} (99%) rename assets/{linear-D4Bza9R9.js => linear-hDJDjKgB.js} (99%) rename assets/{log.html-CWv0qLIE.js => log.html-D-t8wlxQ.js} (98%) rename assets/{log.html-CA6mG-aB.js => log.html-DnBUJw34.js} (96%) rename assets/{log.html-CTirYPei.js => log.html-WdHz5f6a.js} (97%) rename assets/{loopback.html-CyxLLiRu.js => loopback.html-CBRQTJB4.js} (96%) rename assets/{loopback.html-EJfWzfAq.js => loopback.html-DKif3g9A.js} (99%) rename assets/{loopback.html-_BhTQZ0O.js => loopback.html-o32NwpT2.js} (99%) rename assets/{mermaid.core-DapiNGBY.js => mermaid.core-D8igZDel.js} (99%) rename assets/{metrics.html-BT-2HBU5.js => metrics.html-CgPI3fiS.js} (99%) rename assets/{metrics.html-Bf2B_O2D.js => metrics.html-DaweKFfI.js} (99%) rename assets/{metrics.html-DSYbmHxQ.js => metrics.html-JNEl1HLA.js} (99%) rename assets/{mindmap-definition-6NGNQFMS-BtFGEdEC.js => mindmap-definition-6NGNQFMS-Bk10sQyA.js} (99%) rename assets/{mkcp.html-C_htobT5.js => mkcp.html-B5Aq1d1a.js} (99%) rename assets/{mkcp.html-BmeTqtsZ.js => mkcp.html-BXKgWezP.js} (98%) rename assets/{mkcp.html-CL2dbaXb.js => mkcp.html-C779sbex.js} (99%) rename assets/{mkcp.html-OQhbYtWS.js => mkcp.html-DkNOr0bl.js} (99%) rename assets/{mkcp.html-ZQWAw5BE.js => mkcp.html-JU6IuAPN.js} (98%) rename assets/{mkcp.html-zExRKUGX.js => mkcp.html-uDvBjn0p.js} (98%) rename assets/{multiple.html-ByHUK-DJ.js => multiple.html-CyWT5XGQ.js} (99%) rename assets/{multiple.html-DUUJue4s.js => multiple.html-D008nLUw.js} (99%) rename assets/{multiple.html-Bjf8GHFS.js => multiple.html-D1DFWDpc.js} (99%) rename assets/{muxcool.html-DuGDfdPl.js => muxcool.html-C8vY0L1H.js} (99%) rename assets/{muxcool.html-u7BHHyP5.js => muxcool.html-CiEIIjvK.js} (99%) rename assets/{muxcool.html-DJdC30Uv.js => muxcool.html-DTO-WOrE.js} (98%) rename assets/{news.html-AUkvoQ5N.js => news.html-BZwUtxlV.js} (99%) rename assets/{news.html-DY4EgGn2.js => news.html-BeMBU7o5.js} (99%) rename assets/{news.html-UWoLxj1_.js => news.html-BzYbyEWd.js} (99%) rename assets/{nginx_or_haproxy_tls_tunnel.html-CMszb--u.js => nginx_or_haproxy_tls_tunnel.html-CYGy05Cb.js} (99%) rename assets/{nginx_or_haproxy_tls_tunnel.html-DOANhXpE.js => nginx_or_haproxy_tls_tunnel.html-DR7z7Hc7.js} (99%) rename assets/{nginx_or_haproxy_tls_tunnel.html-DkUD4xx5.js => nginx_or_haproxy_tls_tunnel.html-ojUDrBVB.js} (99%) rename assets/{observatory.html-BbQKQJhA.js => observatory.html-BL0BAmEr.js} (99%) rename assets/{observatory.html-BMuTIcPE.js => observatory.html-CYfqKbFA.js} (99%) rename assets/{observatory.html-Bqwm-FiF.js => observatory.html-i7tnhJjx.js} (99%) rename assets/{outbound.html-w2bkUi_e.js => outbound.html-BpCUakwX.js} (99%) rename assets/{outbound.html-B5z5DraB.js => outbound.html-DVewdwtU.js} (99%) rename assets/{outbound.html-CpUBTknQ.js => outbound.html-lqQ_d0C5.js} (99%) rename assets/{pieDiagram-WEX7LNAG-BT3MbsDU.js => pieDiagram-WEX7LNAG-DSCpd-br.js} (92%) rename assets/{policy.html-BALvOnk-.js => policy.html-CA7G3Iy7.js} (98%) rename assets/{policy.html-B5iTeN8-.js => policy.html-CzEm0fhQ.js} (99%) rename assets/{policy.html-Dor87Wko.js => policy.html-DmXgvAr6.js} (98%) rename assets/{quadrantDiagram-SRYJ5FP7-DraEpiPS.js => quadrantDiagram-SRYJ5FP7-DIAY3wdM.js} (99%) rename assets/{redirect.html-CZZO3MVR.js => redirect.html-B5Y1mNVs.js} (99%) rename assets/{redirect.html-DToMsmqC.js => redirect.html-C82dlL2o.js} (99%) rename assets/{redirect.html-C39Qzzo5.js => redirect.html-VwFhzSui.js} (99%) rename assets/{requirementDiagram-V7TESSIR-ptPfSQ70.js => requirementDiagram-V7TESSIR-kqo49K2z.js} (99%) rename assets/{reverse.html-CW54AkoO.js => reverse.html-7Uo0yIWr.js} (99%) rename assets/{reverse.html-DLWtaE_H.js => reverse.html-CfQGiukd.js} (99%) rename assets/{reverse.html-BNoHKOBx.js => reverse.html-CpkNXRut.js} (99%) rename assets/{routing-lv1-part1.html-CM6bRG4P.js => routing-lv1-part1.html-BYLEkwqC.js} (99%) rename assets/{routing-lv1-part1.html-lS-Lwun1.js => routing-lv1-part1.html-Byn2h66N.js} (99%) rename assets/{routing-lv1-part1.html-DXlYZzcq.js => routing-lv1-part1.html-nqov9OAV.js} (99%) rename assets/{routing-lv1-part2.html-C6Xae5-1.js => routing-lv1-part2.html-DNcAgdJC.js} (99%) rename assets/{routing-lv1-part2.html-iX-deabM.js => routing-lv1-part2.html-DfZ-Hwqj.js} (99%) rename assets/{routing-lv1-part2.html-D9GASUUF.js => routing-lv1-part2.html-DlBr3dUB.js} (99%) rename assets/{routing.html-xbGVqnxN.js => routing.html-BzSZN0AZ.js} (99%) rename assets/{routing.html-DwJ4ma_9.js => routing.html-CPw6r5Sh.js} (99%) rename assets/{routing.html-JmIqwiJt.js => routing.html-DxkdJQtA.js} (99%) rename assets/{sankeyDiagram-XVFEVEVI-B44r2-sr.js => sankeyDiagram-XVFEVEVI-BznKSljg.js} (99%) rename assets/{sequenceDiagram-6SD7JOPP-BG3IUlAD.js => sequenceDiagram-6SD7JOPP-BbpXK4ej.js} (99%) rename assets/{shadowsocks.html-4Bp3Pe-I.js => shadowsocks.html-1_shLAxP.js} (99%) rename assets/{shadowsocks.html-IdnyE_QW.js => shadowsocks.html-BFqzUOKa.js} (99%) rename assets/{shadowsocks.html-k_BIRk0d.js => shadowsocks.html-B_N0lWJn.js} (99%) rename assets/{shadowsocks.html-DTzQHKas.js => shadowsocks.html-Dn_DI_z1.js} (99%) rename assets/{shadowsocks.html-BQ1nQK54.js => shadowsocks.html-Dqj7OTrt.js} (99%) rename assets/{shadowsocks.html-CDcJbYW-.js => shadowsocks.html-nM24MAPY.js} (99%) rename assets/{socks.html-D6GgkO4d.js => socks.html-BjLWN2Q8.js} (98%) rename assets/{socks.html-Bo00BDL8.js => socks.html-BqrlqbK0.js} (99%) rename assets/{socks.html-CMWA8dIs.js => socks.html-CXgansFd.js} (99%) rename assets/{socks.html-4M7JIsdb.js => socks.html-CdTGmIt-.js} (98%) rename assets/{socks.html-COrUwqQj.js => socks.html-Cf97X7VI.js} (99%) rename assets/{socks.html-DN04JS2D.js => socks.html-D_fUXvUa.js} (99%) rename assets/{splithttp.html-C1SjdxYM.js => splithttp.html-B8IT_7av.js} (92%) rename assets/{splithttp.html-Ewo4WhOB.js => splithttp.html-BE0bqGcK.js} (95%) rename assets/{splithttp.html-CkMHeQ1D.js => splithttp.html-Cb2yAPj6.js} (85%) rename assets/{splithttp.html-Bu9SdRS8.js => splithttp.html-Cs2Z785s.js} (99%) rename assets/{splithttp.html-Dz9QMH4-.js => splithttp.html-CyHPUrRH.js} (95%) rename assets/{splithttp.html-DstjiOIY.js => splithttp.html-DZKLCVFH.js} (79%) rename assets/{stateDiagram-N22R6T2Y-BFbyHmsw.js => stateDiagram-N22R6T2Y-ClLx8lyS.js} (96%) delete mode 100644 assets/stateDiagram-v2-QXVA2PVL-C7QgvS5i.js create mode 100644 assets/stateDiagram-v2-QXVA2PVL-Cuqsw1mS.js rename assets/{stats.html-j3PBvFA5.js => stats.html-2bJtqbfP.js} (97%) rename assets/{stats.html-Bop9jH-f.js => stats.html-Bm3zQ0hO.js} (98%) rename assets/{stats.html-B7OBry98.js => stats.html-Bx0KYi9t.js} (97%) rename assets/{tcp.html-MnZXrAQL.js => tcp.html-CwUsir3D.js} (99%) rename assets/{tcp.html-D_ggphrp.js => tcp.html-Cxfh7siK.js} (99%) rename assets/{tcp.html-D3RB1Z2i.js => tcp.html-HofSOy7q.js} (99%) rename assets/{timeline-definition-SFF34UE4-Ct_WbDfR.js => timeline-definition-SFF34UE4-GwiTm9yo.js} (99%) rename assets/{tproxy.html-2EI4CZc5.js => tproxy.html-BuzTQD_L.js} (99%) rename assets/{tproxy.html-DOLwYTgg.js => tproxy.html-CR4rpIqz.js} (99%) rename assets/{tproxy.html-D5vAMDfU.js => tproxy.html-CVfbj2d5.js} (99%) rename assets/{tproxy_ipv4_and_ipv6.html-LFerpS1d.js => tproxy_ipv4_and_ipv6.html-BDAlrSaS.js} (99%) rename assets/{tproxy_ipv4_and_ipv6.html-CI5U13dZ.js => tproxy_ipv4_and_ipv6.html-CpYyYPCl.js} (99%) rename assets/{tproxy_ipv4_and_ipv6.html-875AR2Id.js => tproxy_ipv4_and_ipv6.html-D1QYhYGk.js} (99%) rename assets/{traffic_stats.html-mKRKbS-b.js => traffic_stats.html-BVpwRqGM.js} (99%) rename assets/{traffic_stats.html-BvcqGaeo.js => traffic_stats.html-B_7LVx9s.js} (99%) rename assets/{traffic_stats.html--hyCQe7p.js => traffic_stats.html-DsMiCXCX.js} (99%) rename assets/{transparent_proxy.html-CUyvRv2I.js => transparent_proxy.html-BipaDG8r.js} (99%) rename assets/{transparent_proxy.html-D_505nHB.js => transparent_proxy.html-BjCgSdfC.js} (99%) rename assets/{transparent_proxy.html-CN6RzNfw.js => transparent_proxy.html-Dbpkmzp6.js} (99%) rename assets/{transport.html-8xgD8RRD.js => transport.html-7DOFUUXD.js} (99%) rename assets/{transport.html-CoXY-KCW.js => transport.html-B2ArwUNN.js} (99%) rename assets/{transport.html-BsB3pOlv.js => transport.html-CBxA3wPn.js} (99%) rename assets/{trojan.html-2IKlUogk.js => trojan.html-C2P8Dv-p.js} (98%) rename assets/{trojan.html-1FTyRSM5.js => trojan.html-CeUnbQFN.js} (98%) rename assets/{trojan.html-UWktEtCO.js => trojan.html-DekTkRrf.js} (98%) rename assets/{trojan.html-BuFAAu0c.js => trojan.html-DwB8yBqZ.js} (99%) rename assets/{trojan.html-6FO_V9lu.js => trojan.html-_w6ndVja.js} (98%) rename assets/{trojan.html-WioOgQKT.js => trojan.html-xViDkd9I.js} (98%) rename assets/{vless.html-CVgOe_Ra.js => vless.html-B6mgaUnb.js} (99%) rename assets/{vless.html-CvVYC0xa.js => vless.html-BCUjxVGw.js} (99%) rename assets/{vless.html-DPYoRUM4.js => vless.html-BYWxnSoj.js} (99%) rename assets/{vless.html-DH2x8Lsm.js => vless.html-BnbvG0no.js} (99%) rename assets/{vless.html-BlWWjzcK.js => vless.html-CeF81Ekr.js} (99%) rename assets/{vless.html-D5OyDM4i.js => vless.html-kZ8IonU8.js} (99%) rename assets/{vless.html-jHwTWi4h.js => vless.html-oiH3sQfV.js} (99%) rename assets/{vless.html-Bfk9b9AR.js => vless.html-syxK1TrS.js} (99%) rename assets/{vless.html-DAk5toqP.js => vless.html-zQehtVf0.js} (99%) rename assets/{vmess.html-CxHRDmLK.js => vmess.html-3nJoWs8G.js} (99%) rename assets/{vmess.html-9ma69iWT.js => vmess.html-B3TZl91-.js} (99%) rename assets/{vmess.html-BQ6qtjqJ.js => vmess.html-Btr59-Cl.js} (99%) rename assets/{vmess.html-ILF_tpZ9.js => vmess.html-C2MIBK-h.js} (99%) rename assets/{vmess.html-D8fkP4-1.js => vmess.html-CDBIkJMN.js} (99%) rename assets/{vmess.html-BR7lDLGa.js => vmess.html-CktEh3JK.js} (99%) rename assets/{vmess.html-zYdoLiG_.js => vmess.html-D8plPLT5.js} (99%) rename assets/{vmess.html-Bgid-6Wa.js => vmess.html-DUx4NlE2.js} (99%) rename assets/{vmess.html-uLwk-fUW.js => vmess.html-RimzC-nX.js} (99%) rename assets/{warp.html-DjzUs3nN.js => warp.html-Ck2P9Tg0.js} (99%) rename assets/{warp.html-BFiya00c.js => warp.html-CqXxUSeb.js} (99%) rename assets/{warp.html-B33XWZbi.js => warp.html-mob0uukM.js} (99%) rename assets/{websocket.html-BZsgtVoW.js => websocket.html-2zGXYi2c.js} (98%) rename assets/{websocket.html-MgdanL8C.js => websocket.html-DvhOz-O4.js} (98%) rename assets/{websocket.html-D2_1H1Lb.js => websocket.html-XpyUndOJ.js} (98%) rename assets/{wireguard.html-AcuxmEqH.js => wireguard.html-B6z9zn0C.js} (99%) rename assets/{wireguard.html-BRdIxC_E.js => wireguard.html-BSlNcaJF.js} (99%) rename assets/{wireguard.html--TSe5kNc.js => wireguard.html-C7TRB15X.js} (97%) rename assets/{wireguard.html-D8U2MJad.js => wireguard.html-CAQPxeg-.js} (97%) rename assets/{wireguard.html-C7zjxZ_o.js => wireguard.html-CTyw04SG.js} (97%) rename assets/{wireguard.html-Da2wnVY_.js => wireguard.html-CtnQlY0W.js} (99%) rename assets/{work.html-SMvM6VpF.js => work.html-BzVygHoH.js} (98%) rename assets/{work.html-CmnVL4Vh.js => work.html-C4aNtZOg.js} (98%) rename assets/{work.html-DS7NfRpF.js => work.html-CmqVWG7K.js} (98%) rename assets/{xtls.html-C840N25V.js => xtls.html-7ni9fSNN.js} (79%) rename assets/{xtls.html-BK7C9n7n.js => xtls.html-CX-lgDou.js} (83%) rename assets/{xtls.html-DYo3Adlx.js => xtls.html-DkIUVXSC.js} (77%) rename assets/{xychartDiagram-BZZU7QT5-VXQiVXRw.js => xychartDiagram-BZZU7QT5-v7lh-lWp.js} (99%) diff --git a/404.html b/404.html index 550efa9538..934bd5f8e3 100644 --- a/404.html +++ b/404.html @@ -24,11 +24,11 @@ Project X - - + + -

404

That's a Four-Oh-Four.
- +

404

How did we get here?
+ diff --git a/about/news.html b/about/news.html index 0c7a5f7e5a..0078da6965 100644 --- a/about/news.html +++ b/about/news.html @@ -24,11 +24,11 @@ 大史记 | Project X - - + +

大史记

2024.9.12

大史记重出江湖?!

2024.9.7 v24.9.7open in new tag

更改版本号之后的首次发版。

  • 这次移除了 QUIC 以及 DomainSocket 传输,移除了两处远古配置遗留代码。
    • 二进制大小比 v1.8.24 减小了 1MB。
  • 依然有每次必备的 bug 修复。

2024.8.30 v1.8.24open in new tag

在等待 SplitHTTP multiplex controller 期间,main 分支已经积累了大量重要更新,所以我们决定先发一个版本。

  • Socks 入站现在默认兼容 HTTP 代理请求。
  • UDP noise (preview)
  • 还有一些改进。

由于传统版本号的存在,为每个版本规划功能、进行排期已经严重阻碍了新功能的开发、合并、发布。所以我们决定从下个版本开始弃用传统的版本号,改用发版日期作为版本号,如 v24.8.30,并取消版本规划,全面采用流式更新,写好的功能直接合并,不再等待,预计每月月底发一个版本。

毕竟对于反审查软件来说,相较于传统的版本号,新功能的及时性、每月更新更为重要,而不是发一个功能确定的版本并长期维护。

下个版本会移除一些历史久远的代码,以后日常积累新代码、提醒迁移,跨年新版删代码、breaking。

我们相信有了各位的捐款以及对发版形式的革新,Xray-core 这个项目会发展得更好。

2024.8.26

Project VLESS 群组创立。

We have created Project VLESSopen in new tag for non-Chinese users (mainly Russian).

2024.8.3

第一个 Project X NFTopen in new tag 正式发行!

就像 Xray 开创过很多历史一样,发行 NFT 也是这个领域前无古人的操作。这些 NFT 非常有纪念意义,甚至可以说是有历史意义,远大于现在的初始价格,假以时日它们必将价值连城。最后再次感谢大家对 Project X 的支持。

2024.7.29 v1.8.23open in new tag

  • 恭喜 @mmmrayopen in new tag 贡献了 Xray-core 的第 1000 个 commit!
  • 优化了 SplitHTTP 上行的稳定性,服务端必须升级到该版本以支持新版客户端。
  • 更多 SplitHTTP 上的变化。

2024.7.22 v1.8.21open in new tag

中间似乎回到了最初的腹泻式发版状态……

正如 v1.8.16 所预告的,SplitHTTP 现已初步支持 HTTP/3(QUIC)。毫无疑问,SplitHTTP H3 已经开启了一个崭新的时代。

  • SplitHTTP H3 是第一个完全基于标准 H3、支持套 CDN 的 QUIC 类代理,亦可用反代、Browser Dialer 来隐蔽自身。

2024.7.16

Project X 文档迎来了俄语版!感谢 @iambabyninjaopen in new tag 的翻译!

Привет, друзья из России!

2024.7.15

通过已知信息以及努力,Xray-core 现在重新支持 Windows 7!在后续的发版中,Windows 7 用户下载名为 Xray-win7-32.zip 或 Xray-win7-64.zip 的压缩包解压即可享受,感谢大家的支持!具体使用方式请点这里

虽然日后随着各方面升级 Windows 7 最终会离开,但是现在还是可以让这个时间来得稍微晚一些。

2024.6.18 v1.8.16open in new tag

新传输来了,它目前叫 SplitHTTP。

  • 实现进一步的流量混淆有两种刚好相反的方式:多路复用与拆分连接。
  • 可以通过不支持 WebSocket、gRPC 的 CDN,实现与 Meek 相同的目标,且 SplitHTTP 比 Meek 更简单、效率更高。
  • SplitHTTP 没有 WebSocket 的 ALPN 问题,这是一大优势,未来还会支持 HTTP/3(QUIC)。
  • 另外 SplitHTTP 也已经加入分享链接套餐~

2024.6.2

一个新的传输方式正在被打造……

2024.4.26 v1.8.11open in new tag

  • 现在有了生成 ECH 密钥的工具。
  • 增强、修复,并移除了一点不再使用的代码。

2024.4.20

我们现在有了 issues 模板,感谢 @Fanglidingopen in new tag

2024.4.13

VLESS Seed 整备完毕,待势而发。

2024.3.18 v1.8.10open in new tag

和 WebSocket 一样,HTTPUpgrade 也有 0-RTT 了。

2024.3.11 v1.8.9open in new tag

新增 HTTPUpgrade 传输,听说比 WebSocket 要轻。

  • 已加入分享链接套餐~

2024.2.29

gRPC 传输现在也有 Host 一样的配置字段了!它叫 authority。这下 gRPC 也能“域前置”了,没有 ALPN 问题。

2024.2.25 v1.8.8open in new tag

  • 现在 XUDP 流量统一使用 Vision 填充了,速来体验。
  • 新增了 leastLoad balancer。
  • 修复错误、优化性能……

2024.1.9

惊闻 Win7 无法运行新版 Xray-core?探索之下竟发现 Go 放弃了对 Win7 的支持。有什么办法能继续支持这个有些古老但是依然优雅的操作系统吗?

2023.11.21

发表在 USENIX 顶会的论文open in new tag证实,XTLS Vision 已经达到它的设计目标。

而 XTLS 也不会止步于此,如 X 射线一般穿破高耸的围墙。

2023.11.18 v1.8.6open in new tag

  • WireGuard 现在也有了对应的入站。Freedom 出站也终于有了 splice。
  • 现在出站的 domainStrategy 也得到了统一。
  • 更多的美味小点心。
  • 因为 不可抗力 功能变更,Dragonfly BSD 支持黯然离场。
  • 我们真的要对一代经典 Windows 7 说再见了吗?

2023.9.30

为 v2rayNG 设计了全新的配色,安装最新的 Pre-release 版本即可体验。

2023.8.29 v1.8.4open in new tag

1.8.x 在经过半年的打磨后终于来到了第一个认可的正式版了。

同样地,这次集成的改进也不少,速来品尝!

2023.7.22

又修好了一个 HTTP/2 传输的历史遗留断流问题。

2023.7.7

即将给 Vision 添加 Seed 支持。

2023.6.30

下一个 XTLS 流控:xtls-rprx-switch 🍪

  • XTLS 的 0-RTT 已经预告几个月了,本来也是想保留神秘感。
  • 对比现有的 XTLS Vision 和 Mux 有着更加不错的优势。

2023.6.27

如何选取 REALITY 目标域名?来看这里助你事半功倍!open in new tag

2023.6.19 v1.8.3open in new tag

  • 精简代码计划后的第一个版本,VMess (MD5)、MTProto 以及 Starlark 相关代码已被卸下。轻装上阵。
  • 对代码进重构也是轻装上阵的一部分。
  • 同时我们也没有忘记增添一些增强功能,还有修复漏洞。
  • v1.8.3 为今年的最后一个版本。

2023.6.6

好消息:下一个 XTLS 流控不叫 Vision。 🍪

2023.4.21

也许我们可以借助一下 RealiTLScanneropen in new tag……

2023.4.20

经过长年累月的开发,累积代码不计其数…… 精简代码计划open in new tag 被提出了!

2023.4.19

xtls-0rtt-vision(-udp443) 🍪

2023.4.18 v1.8.1open in new tag

升级后的 XUDP 也来了!

  • 现在 XUDP 也带有连接迁移、端口复用的特性,并且带有全局 Session ID ,麻麻再也不用担心意外断线的时候怎么办了
  • 同时我们也添加了 XUDP 的控制配置,让你能更好掌控它~
  • 新的 XUDP 配合 XTLS Vision 食用风味更好喔~
  • 惯例还有小甜点,欢迎品尝~

2023.4.6

XUDP 也在悄然升级……

2023.3.29

PLUX protocol 🍪

2023.3.19

对 REALITY 的分享链接标准也已经出现了。

2023.3.9 v1.8.0open in new tag

THE NEXT FUTURE, REALITY is NOW release on Xray-core

REALITY 已经实装发版!欢迎体验! XTLS Vision 也已经完善,请两端升级至最新版食用。

  • 因为这次 Vision 填充算法改变,XTLS Vision 旧版和新版之间会存在兼容性问题。
  • HTTP/2 传输也已经做了改善,现在使用新版即可纵享丝滑~
  • 还有大量小改进欢迎体验~

2023.3.4

Legends never die, they become a part of you VLESS.

They simply fade away.

2023.3.2

HTTP/2 传输的一些遗留问题已经被改善,欢迎搭配 REALITY 测试纵享丝滑~

2023.2.16

THE NEXT FUTURE becomes THE REALITY NOW!

2023.2.9

REALITY is reality now!

2023.2.8 v1.7.5open in new tag

Keep riding and never look back.

  • 恭喜 @yuhan6665open in new tag 贡献了 Xray-core 的第 500 个 commit!
  • XTLS Vision 流控已经接近完善,即将实用。
  • 现在对 uTLS 指纹模拟添加了更多可选项,有哪一款适合你?
  • 分享链接也支持同时分享 uTLS 指纹配置了。
  • 还有更多的功能增强和修复。
  • 这一版也是能最后一次看到 XTLS Origin、Direct 和 Splice 流控的一版了。 有点伤感不是吗?

2023.1.29

Winter cannot cover the NEXT FUTURE...

2022.12.26 v1.7.0open in new tag

因为手滑,这次的版本号直接大升,感谢大家支持!

  • 以后将会严格执行 Semantic Versioning。

2022.11.28 v1.6.5open in new tag

这次我们有了 WireGuard 出站。

  • 使用 WireGuard 搭配 CF WARP 使用可以解锁有趣的新玩法呢。
  • 同样安全更新和修复也不会少。

2022.11.7 v1.6.3open in new tag

现在 Vision 流控也能使用 uTLS 指纹模拟了,这就是使用 tlsSettings 带来的好处吗!

2022.10.29 v1.6.2open in new tag

第一个包含 Vision 流控的发行版已经放出!欢迎试用并提交反馈!

2022.10.22 v1.6.1open in new tag

  • 为 WebSocket、HTTP/2 以及 gRPC 传输带来了 uTLS 指纹支持!
    • 之前只有普通 TLS 下 TCP 传输能用的选项现在更好用了。
  • Linux 下可以单独为出入口设置 TCP 拥塞控制了。

2022.10.3

天气渐凉,但是并没有凉下开发的脚步。封锁天降,但无法阻止前行……

  • 新的 XTLS 流控酝酿中……
    • 解决之前流控已有的问题;
    • 对 TLS 1.3 直接启用 splice;
    • 增加 TLS 握手长度混淆;
    • 简化代码,使用 tlsSettings 而不是 xtlsSettings……

2022.8.28 v1.5.10open in new tag

底层传输支持更合理的 TCP Keepalive 配置了。

2022.6.20 v1.5.8open in new tag

现在 Shadowsocks-2022 的 relay 中转也受支持了。

2022.5.29 v1.5.6open in new tag

Shadowsocks-2022 协议来到了 Xray-core!

Shadowsocks-2022 是重新设计的全新协议:

  • 在保留 Shadowsocks 原生 udp 的基础上解决了重放攻击等安全问题(与 vmess 一样使用时间戳,因此客户端与服务端需要时间一致)。
  • 支持单端口多用户,并且参考 quic、wireguard 等协议设计与实现使用了 session 机制,减低加密负担,保证网络变动时的无缝迁移。

2022.4.24 v1.5.5open in new tag

这次带来了方便可视化的检测数据接口!快来体验!

  • 顺便修复了一些影响使用体验的问题。

2022.3.13 v1.5.4open in new tag

给 Windows 平台加上了没有黑窗冒出的 wxray.exe 文件,并带来了对 UDS 监听的增强。

2022.1.29 v1.5.3open in new tag

牛辞胜岁,虎跃新程。🧨

  • 这次带来了对 QUIC 传输的流分配改进,使用 QUIC 传输现在更丝滑了。

2021.12.24 v1.5.2open in new tag

为 gRPC 添加了一个新的选项,在通过 CDN 时变得更好用了。

2021.12.15 v1.5.1open in new tag

“过渡时期的阶段性的维护版本”

  • 新功能、增强还有大量修复陆续有来。
  • 记得将 VMess 配置中的 alterID 去掉!

2021.10.20 v1.5.0open in new tag

真的是巨大的改动!

  • 重构了 DNS 组件,支持的协议和细化配置更多了。
  • 增强了 gRPC 传输以及 FakeDNS。
  • 现在终于支持 Windows ARM64 了。
  • 更多新功能和改进等待体验。

2021.9.23 v1.4.5open in new tag

中秋快乐,阖家团圆。

  • 修正了版本号过低,版本号不吉利的 bug。
  • 这次移除了 Shadowsocks 里面已经不安全的加密方式。要尽快迁移到 AEAD 加密上面喔。
  • 这次修复了远古时期开始就存在的历史问题:开启流量统计功能可能会使性能下降。简单来说,不论什么配置现在打开统计都不会对性能有任何影响了。
  • 还有对 XTLS 的安全性更新以及大量修复。
  • 对了,因为 TLS 库的更新,cipherSuites 不能再指定加密套件顺序了,而 preferServerCipherSuites 已经被彻底弃用。事实上这些变化在 Xray-core v1.4.3 中已经产生了。

2021.9.16

2021.9.8 v1.4.3open in new tag

这是一个阶段性维护版本。开发仍在继续……

  • 在此期间累积了大量改进和新功能。
  • 加入新的 DomainMatcher,现在域名规则匹配性能更好了。
  • 加入对 HTTP/2 和 gRPC 传输的健康检查、对未知 SNI 的处理改进,以及修复了一大堆 bug。

Helden sterben nicht!

2021.7.14

  • AnXray 重金设计 的新图标已经上线!
    • 现在图标的辨识度更高了。
  • 过去三个星期,AnXray 共积累了 600 stars、2K+ 频道订阅数和 11K+ GitHub 下载量,感谢大家的支持。
  • AX 为 AnXray 的缩写,推荐用 AX 指代 AnXray,简短方便

2021.6.21

现在一个以 Xray-core 为核心的开源、自由的 Android 客户端已经出现——AnXrayopen in new tag!由 @nekohasekaiopen in new tag 维护。

  • 支持众多协议、插件.
  • 首席视觉设计师 @RPRXopen in new tag 设计了 X-style 的 logo、slogan,以及独一无二的 material 黑白主题。
  • APP 内还有个小彩蛋等你去发现。

前两天从早到晚反复打磨细节,希望大家多多 Star、关注。

2021.5.1

对 tun2socks 的改进出现在 v2rayNG 上面了。

2021.4.26

给 tun2socks 带来了一个改进。后续有可能能吃到它~

2021.4.12

现在带来了 X-flutter 前瞻,可以期待一下会是什么样子呢~ 🍪

2021.4.6

  • VuePress Next.
  • With Dark Mode.

2021.4.4

  • 本文档迎来的新的首页。
  • 本文档迎来了暗黑模式。
  • 当然,暗黑模式还有各种各样的问题。具体的内容还需要慢慢调整。
  • 另:Telegram 群聊突破了 5000 人!还加入了 Anti-Spam 机器人!
  • 🎉🎉🎉

2021.4.1 v1.4.2open in new tag

  • 不是愚人节玩笑,今天更新。
  • 加入 Browser Dialer,用与改变 TLS 指纹与行为。
  • 加入 uTLS,用与改变 TLS Client Hello 的指纹。
  • 顺便修复了一大堆奇妙的问题,具体的内容见更新日志。

2021.3.25

没错还在变。 -_-

2021.3.15

文档网站正在悄悄的进行着某些神秘的变化。。。,🙊🙊🙊

2021.3.14 v1.4.0open in new tag

  • Happy Pi-Day!
  • 这次是个大更新:
    • 为链式代理引入了传输层支持。
    • 为 Dialer 引入了 Domain Strategy,解决奇妙的 DNS 问题。
    • 添加了 gRPC 传输方式,与更快一点的 Multi Mode。
    • 添加了 WebSocket Early-Data 功能,减少了 WebSocket 的延迟。
    • 添加了 FakeDNS。
    • 还修复了系列的问题,添加了各类功能,详情请见更新日志。
  • 还是 VuePress 比较爽啊(

2021.3.3 1.3.1open in new tag

  • 这个版本使用了 Golang 1.16,正式原生支持 Apple Silicon。
  • 同时修复了一个会导致 Panic 的 bug。Holmium_认为这是在骗、在偷袭。
  • 修复了几个遗留问题。

2021.2.14 1.3.0open in new tag

  • Happy 🐮 Year 🎉!
  • v1.3.0 通过非常巧妙的机制实现了 V 系协议全部 FullCone,同时保证了一定的兼容性。
  • OHHHHHHHHHHHH!

2021.01.31 1.2.4open in new tag

  • 解决两个“连接至标准 Socks 服务端时可能出错”的历史遗留问题。
  • 似乎这个版本没有什么改变,但这只是暴风雨前的宁静。
  • (没错我就是先知)

    你个傻子,你拿的是 UNO 牌。

2021.01.25

  • 全互联网最好最详细的秘籍入门篇同学们练熟了吗? 🍉 老师开始连载秘籍第一层咯...
  • 英文版文档网站逐渐增加内容 ing, 感谢各位大佬的辛苦付出~!

2021.01.22 1.2.3open in new tag

  • 对 SS 协议的支持变强了, 支持单端口多用户!
  • 对 trojan 协议的支持也变强了, trojan 的回落也解锁 SNI 分流的新姿势啦~!
  • (VLESS: 嘤嘤嘤)
  • UDP 奇奇怪怪的 BUG 被干掉了, 一个字, "稳定".
  • 嗅探可以排除你不想嗅探的域名, 可以开启一些新玩法.
  • 向发现问题->开 issue->自行测试->自行分析->自行找到问题->自行解决->然后给上下游提交 PR 的大佬 @Bohan Yangopen in new tag 致敬!
  • 其他美味小樱桃, 惯例更新品尝就对啦.

2021.01.19

  • 一些数字
    • 版本发布了 10   个 tag
    • 解决掉了 100  个 issue
    • 复刻了 300  个 fork
    • 点了 2000 个 star
    • 群 3000 个 人

2021.01.17

2021.01.15 1.2.2open in new tag

  • 回落分流又解锁了奇怪的新姿势! 回落中可以根据 SNI 分流啦~!
  • 之前预告的 UUID 修改正式上线.(往下看往下看)
  • 日志现在看起来比上一次顺眼又更顺眼了一丢丢.
  • 远程 DOH 和其他的 DNS 模式一样学会了走路由分流.
  • 当然还有其他各种小糖果.(更新品尝就对了)
  • 啊, 还有, 世界上第一個 M1 上跑起 Xray 的男人是 Anthony TSE

2021.01.12

  • 将要到来的 UUID 修改, 支持自定义字符串和 UUID 之间的映射. 这意味着你将可以这样在配置文件中写 id 来对应用户.
    • 客户端写 "id": "我爱 🍉 老师 1314",
    • 服务端写 "id": "5783a3e7-e373-51cd-8642-c83782b807c5" (此 UUID 是 我爱🍉老师1314 的 UUID 映射)
  • 🍉 老师的小小白白话文大结局, 撒花.

2021.01.10 1.2.1open in new tag

  • 大量的 UDP 相关修复, 甚至可以在育碧的土豆服务器上玩彩虹六号!
  • Google Voice 应该也可以正常使用 v2rayNG 拨打了.
  • 日志现在看起来更顺眼.

2021.01.07

  • 礼貌和尊重本应是社区不需要明说的准则之一。

2021.01.05

  • 文档网站正在悄悄的进行着某些神秘的变化。。。,🙊🙊🙊

2021.01.03

2021.01.01

【祝大家新年快乐,嗨皮牛耶!】🎆🎇🎆 1.2.0open in new tag

🎁 在元旦的最后几分钟,v1.2.0 它来了,带着周五必更的惯例,带着各位贡献大佬的心血以及 @rprxx 的黑眼圈,不负众望的来了!

  • 圣诞礼物v1.1.5后的元旦礼物 🎁,游戏玩家大福利,全面 FullCone。
  • (UDP 还会继续增强!)
  • 如果你已经拆过圣诞礼物,这次还有比圣诞礼物更精美的包装和小糖果哦。(同样不用问,更新品尝就对了)
  • (不,下面不是广告,是里程碑。)
  • Xray 是有史以来第一个不受限制的多协议平台:只需 Xray 即可解决问题,无需借力其它实现。
    • 一人扛起了所有!支持各大主流协议!
    • 一骑绝尘的性能!
    • 日趋完善的功能!
    • 可怕的生命力与社区亲和力!
  • Xray 将继续保持前行! 因此 Xray 需要更多的英雄!!open in new tag
  • PS:请品,请细品release notesopen in new tag每一句。似乎有一个小秘密小彩蛋 (啊,有人敲门...我一会和你们说)

2020.12.29

透明代理的游戏玩家利好! Xray-core tproxy 入站, socks 出站 UDP FullCone 测试版, TG 群open in new tag火热测试中

2020.12.25 1.1.5open in new tag

圣诞节快乐!

  • 游戏玩家的圣诞礼物!你可以用 xray 爽快的打游戏啦!因为有了 SS/trojan UDP fullcone
  • 你可以用你喜欢的格式写配置文件了,比如 yaml,比如 toml...
  • (VLESS 的 UDP fullcone 和更多增强很快就到!)
  • 无须再担心证书验证被墙,OCSP stapling 已经上线!
  • kirin 带来了一大波 脚本更新.脚本在此open in new tag
  • 还有更多美味小樱桃!(不用问,更新品尝就对了)

2020.12.24

因为某些不可描述的原因,Xray 的文档网站已在发布日前偷跑上线。 网址为:没错你正在看的就是open in new tag

大家可以查阅各种内容也欢迎纠错/提出建议(可发往文档 github 仓库的 issue 区)

文档网站需要不断完善和增加内容,以及完善设计。 因此更欢迎大家一起为文档建设添砖加瓦。 文档的仓库open in new tag

仓库的 readme 中有简略教程说明如何帮助 xray 改进文档网站. 欢迎大家查看,纠错,修改,增加心得。

2020.12.23

Xray-core Shadowsocks UDP FullCone 测试版, TG 群open in new tag火热测试中

2020.12.21

  • Project X 群人数 2000+
  • 群消息(含游戏群) 日均破万

2020.12.18 1.1.4open in new tag

  • 更低的启动内占用和内存使用优化
  • 随意定制的 TLS 提高你的 SSL 评级
  • 支持 XTLS 入站的 Splice 以及支持 trojan 的 XTLS
  • 还有在您路由器上使用的 Splice 最佳使用模式建议

2020.12.17

鉴于日益增长群人数和游戏需求, 开启了TG 游戏群open in new tag

2020.12.15

安装脚本 dev 分支open in new tag开启, 持续更新功能中.

2020.12.11 1.1.3open in new tag

  • 完整版本的 REDIRECT 透明代理模式.
  • 软路由 splice 流控模式的优化建议.

2020.12.06 1.1.2open in new tag

  • 流控增加 splice 模式, Linux 限定, 性能一骑绝尘.
  • 增强了 API 兼容

2020.12.04

增加 splice 模式

2020.11.27

  • Project X 的 GitHub 主仓库 Xray-core 已获 500+ stars
  • 登上了 GitHub Trending
  • Project X 群人数破千,频道订阅数 500+

2020.11.25 1.0.0open in new tag

Xray 的第一个版本.

  • 基于 v2ray-core 修改而来,改动较大
  • 全面增强, 性能卓越, 完全兼容

2020.11.23

project X start

梦开始的时候

- + diff --git a/assets/404.html-BZTO9xBK.js b/assets/404.html-B0Jvu-JI.js similarity index 63% rename from assets/404.html-BZTO9xBK.js rename to assets/404.html-B0Jvu-JI.js index 06cca5fa13..356203ea2c 100644 --- a/assets/404.html-BZTO9xBK.js +++ b/assets/404.html-B0Jvu-JI.js @@ -1 +1 @@ -import{_ as e,o as c,c as t}from"./app-DBM4OJyw.js";const _={};function o(r,n){return c(),t("div")}const a=e(_,[["render",o],["__file","404.html.vue"]]);export{a as default}; +import{_ as e,o as c,c as t}from"./app-D7uBbsY3.js";const _={};function o(r,n){return c(),t("div")}const a=e(_,[["render",o],["__file","404.html.vue"]]);export{a as default}; diff --git a/assets/Mermaid-D_ImV7ws.js b/assets/Mermaid-wJbLESOb.js similarity index 89% rename from assets/Mermaid-D_ImV7ws.js rename to assets/Mermaid-wJbLESOb.js index 0ac6b177ae..556201bd31 100644 --- a/assets/Mermaid-D_ImV7ws.js +++ b/assets/Mermaid-wJbLESOb.js @@ -1,7 +1,7 @@ -import{u as y,j as M,k as S,l as m,m as v,n as _,p as h,q as g,f as E,s as O,v as f,x as D,h as H,_ as L,o as R,c as T}from"./app-DBM4OJyw.js";function $(e){return M()?(S(e),!0):!1}function w(e){return typeof e=="function"?e():y(e)}const x=typeof window<"u"&&typeof document<"u";typeof WorkerGlobalScope<"u"&&globalThis instanceof WorkerGlobalScope;const A=e=>e!=null;function C(e){var t;const o=w(e);return(t=o==null?void 0:o.$el)!=null?t:o}const I=x?window:void 0;function W(){const e=_(!1),t=g();return t&&h(()=>{e.value=!0},t),e}function q(e){const t=W();return m(()=>(t.value,!!e()))}function B(e,t,o={}){const{window:i=I,...r}=o;let n;const u=q(()=>i&&"MutationObserver"in i),a=()=>{n&&(n.disconnect(),n=void 0)},d=m(()=>{const s=w(e),c=(Array.isArray(s)?s:[s]).map(C).filter(A);return new Set(c)}),b=v(()=>d.value,s=>{a(),u.value&&s.size&&(n=new MutationObserver(t),s.forEach(c=>n.observe(c,r)))},{immediate:!0,flush:"post"}),k=()=>n==null?void 0:n.takeRecords(),l=()=>{b(),a()};return $(l),{isSupported:u,stop:l,takeRecords:k}}const p=()=>{const e=document.documentElement;return e.classList.contains("dark")||e.getAttribute("data-theme")==="dark"},G=E({name:"Mermaid",props:{id:{type:String,required:!0},code:{type:String,required:!0}},setup(e){const t=O({innerHtml:""}),o=f(e,"id"),i=f(e,"code"),r=_(!1),n=async()=>{const u=await H(()=>import("./mermaid.core-DapiNGBY.js").then(a=>a.bw),__vite__mapDeps([0,1]));u.default.initialize({theme:r.value?"dark":"default",startOnLoad:!1}),u.default.render(o.value,decodeURI(i.value)).then(({svg:a,bindFunctions:d})=>{t.innerHtml=a})};return h(()=>{r.value=p(),D(n)}),typeof document<"u"&&B(document.documentElement,()=>{r.value=p()},{attributeFilter:["class","data-theme"],attributes:!0}),v(r,()=>n()),{tag:o,payload:t}}}),z=["innerHTML"];function F(e,t,o,i,r,n){return R(),T("div",{innerHTML:e.payload.innerHtml},null,8,z)}const V=L(G,[["render",F],["__file","Mermaid.vue"]]);export{V as default}; +import{u as y,j as M,k as S,l as m,m as v,n as _,p as h,q as g,f as E,s as O,v as f,x as D,h as H,_ as L,o as R,c as T}from"./app-D7uBbsY3.js";function $(e){return M()?(S(e),!0):!1}function w(e){return typeof e=="function"?e():y(e)}const x=typeof window<"u"&&typeof document<"u";typeof WorkerGlobalScope<"u"&&globalThis instanceof WorkerGlobalScope;const A=e=>e!=null;function C(e){var t;const o=w(e);return(t=o==null?void 0:o.$el)!=null?t:o}const I=x?window:void 0;function W(){const e=_(!1),t=g();return t&&h(()=>{e.value=!0},t),e}function q(e){const t=W();return m(()=>(t.value,!!e()))}function B(e,t,o={}){const{window:i=I,...r}=o;let n;const u=q(()=>i&&"MutationObserver"in i),a=()=>{n&&(n.disconnect(),n=void 0)},d=m(()=>{const s=w(e),c=(Array.isArray(s)?s:[s]).map(C).filter(A);return new Set(c)}),b=v(()=>d.value,s=>{a(),u.value&&s.size&&(n=new MutationObserver(t),s.forEach(c=>n.observe(c,r)))},{immediate:!0,flush:"post"}),k=()=>n==null?void 0:n.takeRecords(),l=()=>{b(),a()};return $(l),{isSupported:u,stop:l,takeRecords:k}}const p=()=>{const e=document.documentElement;return e.classList.contains("dark")||e.getAttribute("data-theme")==="dark"},G=E({name:"Mermaid",props:{id:{type:String,required:!0},code:{type:String,required:!0}},setup(e){const t=O({innerHtml:""}),o=f(e,"id"),i=f(e,"code"),r=_(!1),n=async()=>{const u=await H(()=>import("./mermaid.core-D8igZDel.js").then(a=>a.bw),__vite__mapDeps([0,1]));u.default.initialize({theme:r.value?"dark":"default",startOnLoad:!1}),u.default.render(o.value,decodeURI(i.value)).then(({svg:a,bindFunctions:d})=>{t.innerHtml=a})};return h(()=>{r.value=p(),D(n)}),typeof document<"u"&&B(document.documentElement,()=>{r.value=p()},{attributeFilter:["class","data-theme"],attributes:!0}),v(r,()=>n()),{tag:o,payload:t}}}),z=["innerHTML"];function F(e,t,o,i,r,n){return R(),T("div",{innerHTML:e.payload.innerHtml},null,8,z)}const V=L(G,[["render",F],["__file","Mermaid.vue"]]);export{V as default}; function __vite__mapDeps(indexes) { if (!__vite__mapDeps.viteFileDeps) { - __vite__mapDeps.viteFileDeps = ["assets/mermaid.core-DapiNGBY.js","assets/app-DBM4OJyw.js"] + __vite__mapDeps.viteFileDeps = ["assets/mermaid.core-D8igZDel.js","assets/app-D7uBbsY3.js"] } return indexes.map((i) => __vite__mapDeps.viteFileDeps[i]) } diff --git a/assets/Tab-BFTIeLDp.js b/assets/Tab-BCE01DFa.js similarity index 89% rename from assets/Tab-BFTIeLDp.js rename to assets/Tab-BCE01DFa.js index cd3b9da8c5..ecc5e42956 100644 --- a/assets/Tab-BFTIeLDp.js +++ b/assets/Tab-BCE01DFa.js @@ -1 +1 @@ -import{f as e,_ as a,o as s,c as l,g as r}from"./app-DBM4OJyw.js";const i=e({props:{title:{type:String}},data(){return{tabID:this.title}},mounted(){this.tabID="tab-"+Math.random().toString(36).substring(2),this.$parent.$data.children.push({id:this.tabID,title:this.title})},computed:{labelID(){return this.tabID+"-label"}}}),o=["id","aria-labelledby"];function n(t,d,b,p,c,u){return s(),l("div",{class:"tab-pane fade",id:t.tabID,role:"tabpanel","aria-labelledby":t.labelID},[r(t.$slots,"default",{},void 0,!0)],8,o)}const f=a(i,[["render",n],["__scopeId","data-v-88372a6c"],["__file","Tab.vue"]]);export{f as default}; +import{f as e,_ as a,o as s,c as l,g as r}from"./app-D7uBbsY3.js";const i=e({props:{title:{type:String}},data(){return{tabID:this.title}},mounted(){this.tabID="tab-"+Math.random().toString(36).substring(2),this.$parent.$data.children.push({id:this.tabID,title:this.title})},computed:{labelID(){return this.tabID+"-label"}}}),o=["id","aria-labelledby"];function n(t,d,b,p,c,u){return s(),l("div",{class:"tab-pane fade",id:t.tabID,role:"tabpanel","aria-labelledby":t.labelID},[r(t.$slots,"default",{},void 0,!0)],8,o)}const f=a(i,[["render",n],["__scopeId","data-v-88372a6c"],["__file","Tab.vue"]]);export{f as default}; diff --git a/assets/Tabs-2T1W4IpS.js b/assets/Tabs-CcpaQpRZ.js similarity index 95% rename from assets/Tabs-2T1W4IpS.js rename to assets/Tabs-CcpaQpRZ.js index 1cc1b53926..bd1cb86e57 100644 --- a/assets/Tabs-2T1W4IpS.js +++ b/assets/Tabs-CcpaQpRZ.js @@ -1,4 +1,4 @@ -import{f as i,h as r,_ as d,o as a,c as n,b as s,F as l,i as c,g as u,t as _}from"./app-DBM4OJyw.js";const p=i({props:{title:{type:String}},data(){return{children:[]}},beforeMount(){this.children=[]},mounted(){this.$nextTick(async function(){const t=await r(()=>import("./bootstrap.esm-DrZxKEFm.js"),__vite__mapDeps([]));let o=document.getElementById(this.children[0].id+"-label");new t.Tab(o).show()})},computed:{tag:function(){return"tabs-"+this.title},contentTag:function(){return"tabs-"+this.title+"-content"}}}),b={class:"container"},h=["id"],f=["id","aria-controls","data-bs-target"],g=["id"];function v(t,o,m,T,$,y){return a(),n("div",b,[s("nav",null,[s("div",{id:t.tag,class:"nav nav-pills",role:"tablist"},[(a(!0),n(l,null,c(t.children,e=>(a(),n("button",{id:e.id+"-label","aria-controls":e.id,"data-bs-target":"#"+e.id,"aria-selected":"false",class:"nav-link","data-bs-toggle":"tab",role:"tab",type:"button"},_(e.title),9,f))),256))],8,h)]),s("div",{id:t.contentTag,class:"tab-content"},[u(t.$slots,"default",{},void 0,!0)],8,g)])}const k=d(p,[["render",v],["__scopeId","data-v-b533ae34"],["__file","Tabs.vue"]]);export{k as default}; +import{f as i,h as r,_ as d,o as a,c as n,b as s,F as l,i as c,g as u,t as _}from"./app-D7uBbsY3.js";const p=i({props:{title:{type:String}},data(){return{children:[]}},beforeMount(){this.children=[]},mounted(){this.$nextTick(async function(){const t=await r(()=>import("./bootstrap.esm-DrZxKEFm.js"),__vite__mapDeps([]));let o=document.getElementById(this.children[0].id+"-label");new t.Tab(o).show()})},computed:{tag:function(){return"tabs-"+this.title},contentTag:function(){return"tabs-"+this.title+"-content"}}}),b={class:"container"},h=["id"],f=["id","aria-controls","data-bs-target"],g=["id"];function v(t,o,m,T,$,y){return a(),n("div",b,[s("nav",null,[s("div",{id:t.tag,class:"nav nav-pills",role:"tablist"},[(a(!0),n(l,null,c(t.children,e=>(a(),n("button",{id:e.id+"-label","aria-controls":e.id,"data-bs-target":"#"+e.id,"aria-selected":"false",class:"nav-link","data-bs-toggle":"tab",role:"tab",type:"button"},_(e.title),9,f))),256))],8,h)]),s("div",{id:t.contentTag,class:"tab-content"},[u(t.$slots,"default",{},void 0,!0)],8,g)])}const k=d(p,[["render",v],["__scopeId","data-v-b533ae34"],["__file","Tabs.vue"]]);export{k as default}; function __vite__mapDeps(indexes) { if (!__vite__mapDeps.viteFileDeps) { __vite__mapDeps.viteFileDeps = [] diff --git a/assets/api.html-BSTC8zd0.js b/assets/api.html-By3Hi2cL.js similarity index 99% rename from assets/api.html-BSTC8zd0.js rename to assets/api.html-By3Hi2cL.js index 40d76da595..1abfd6ea47 100644 --- a/assets/api.html-BSTC8zd0.js +++ b/assets/api.html-By3Hi2cL.js @@ -1,4 +1,4 @@ -import{_ as l,r as t,o as c,c as u,a,b as s,d as n,w as p,e as i}from"./app-DBM4OJyw.js";const d={},v=s("h1",{id:"api",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#api"},[s("span",null,"API")])],-1),k={href:"https://grpc.io/",target:"_blank",rel:"noopener noreferrer"},b=s("br",null,null,-1),h=s("br",null,null,-1),m=s("a",{href:"#%D1%81%D0%B2%D1%8F%D0%B7%D0%B0%D0%BD%D0%BD%D1%8B%D0%B5-%D0%BD%D0%B0%D1%81%D1%82%D1%80%D0%BE%D0%B9%D0%BA%D0%B8"},"Связанные настройки",-1),g={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.12",target:"_blank",rel:"noopener noreferrer"},q=s("br",null,null,-1),D=i(`

Внимание

Большинству пользователей не нужен этот API, новички могут просто пропустить этот раздел.

ApiObject

ApiObject соответствует полю api в конфигурационном файле.

{
+import{_ as l,r as t,o as c,c as u,a,b as s,d as n,w as p,e as i}from"./app-D7uBbsY3.js";const d={},v=s("h1",{id:"api",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#api"},[s("span",null,"API")])],-1),k={href:"https://grpc.io/",target:"_blank",rel:"noopener noreferrer"},b=s("br",null,null,-1),h=s("br",null,null,-1),m=s("a",{href:"#%D1%81%D0%B2%D1%8F%D0%B7%D0%B0%D0%BD%D0%BD%D1%8B%D0%B5-%D0%BD%D0%B0%D1%81%D1%82%D1%80%D0%BE%D0%B9%D0%BA%D0%B8"},"Связанные настройки",-1),g={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.12",target:"_blank",rel:"noopener noreferrer"},q=s("br",null,null,-1),D=i(`

Внимание

Большинству пользователей не нужен этот API, новички могут просто пропустить этот раздел.

ApiObject

ApiObject соответствует полю api в конфигурационном файле.

{
   "api": {
     "tag": "api",
     "listen": "127.0.0.1:8080",
diff --git a/assets/api.html-MH0dPqio.js b/assets/api.html-CQYAnjeD.js
similarity index 99%
rename from assets/api.html-MH0dPqio.js
rename to assets/api.html-CQYAnjeD.js
index 9b543ddf08..b88f39dd74 100644
--- a/assets/api.html-MH0dPqio.js
+++ b/assets/api.html-CQYAnjeD.js
@@ -1,4 +1,4 @@
-import{_ as c,r as t,o as l,c as u,a,b as s,d as n,w as p,e as i}from"./app-DBM4OJyw.js";const d={},v=s("h1",{id:"api-接口",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#api-接口"},[s("span",null,"API 接口")])],-1),k={href:"https://grpc.io/",target:"_blank",rel:"noopener noreferrer"},b=s("a",{href:"#%E7%9B%B8%E5%85%B3%E9%85%8D%E7%BD%AE"},"相关配置",-1),h={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.12",target:"_blank",rel:"noopener noreferrer"},m=i(`

注意

大多数用户并不会用到此 API,新手可以直接忽略这一项。

ApiObject

ApiObject 对应配置文件的 api 项。

{
+import{_ as c,r as t,o as l,c as u,a,b as s,d as n,w as p,e as i}from"./app-D7uBbsY3.js";const d={},v=s("h1",{id:"api-接口",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#api-接口"},[s("span",null,"API 接口")])],-1),k={href:"https://grpc.io/",target:"_blank",rel:"noopener noreferrer"},b=s("a",{href:"#%E7%9B%B8%E5%85%B3%E9%85%8D%E7%BD%AE"},"相关配置",-1),h={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.12",target:"_blank",rel:"noopener noreferrer"},m=i(`

注意

大多数用户并不会用到此 API,新手可以直接忽略这一项。

ApiObject

ApiObject 对应配置文件的 api 项。

{
   "api": {
     "tag": "api",
     "listen": "127.0.0.1:8080",
diff --git a/assets/api.html-BIbKaUtc.js b/assets/api.html-D47_38rn.js
similarity index 99%
rename from assets/api.html-BIbKaUtc.js
rename to assets/api.html-D47_38rn.js
index c4ac71341c..1967bb2f2f 100644
--- a/assets/api.html-BIbKaUtc.js
+++ b/assets/api.html-D47_38rn.js
@@ -1,4 +1,4 @@
-import{_ as l,r as s,o as c,c as u,a as e,b as a,d as n,w as i,e as r}from"./app-DBM4OJyw.js";const d={},v=a("h1",{id:"api-interface",tabindex:"-1"},[a("a",{class:"header-anchor",href:"#api-interface"},[a("span",null,"API Interface")])],-1),h={href:"https://grpc.io/",target:"_blank",rel:"noopener noreferrer"},b=r(`

Please refer to the related configuration in this section.

Warning

Most users do not need to use this API. Novices can ignore this page entirely.

ApiObject

ApiObject corresponds to the api item in the configuration file.

{
+import{_ as l,r as s,o as c,c as u,a as e,b as a,d as n,w as i,e as r}from"./app-D7uBbsY3.js";const d={},v=a("h1",{id:"api-interface",tabindex:"-1"},[a("a",{class:"header-anchor",href:"#api-interface"},[a("span",null,"API Interface")])],-1),h={href:"https://grpc.io/",target:"_blank",rel:"noopener noreferrer"},b=r(`

Please refer to the related configuration in this section.

Warning

Most users do not need to use this API. Novices can ignore this page entirely.

ApiObject

ApiObject corresponds to the api item in the configuration file.

{
   "api": {
     "tag": "api",
     "listen": "127.0.0.1:8080",
diff --git a/assets/app-DBM4OJyw.js b/assets/app-D7uBbsY3.js
similarity index 88%
rename from assets/app-DBM4OJyw.js
rename to assets/app-D7uBbsY3.js
index 02414ff7a7..16bad732ab 100644
--- a/assets/app-DBM4OJyw.js
+++ b/assets/app-D7uBbsY3.js
@@ -1,4 +1,4 @@
-function bn(e,t){const l=Object.create(null),i=e.split(",");for(let n=0;n!!l[n]}const ye={},il=[],ut=()=>{},ec=()=>!1,Bl=e=>e.charCodeAt(0)===111&&e.charCodeAt(1)===110&&(e.charCodeAt(2)>122||e.charCodeAt(2)<97),kn=e=>e.startsWith("onUpdate:"),Ie=Object.assign,En=(e,t)=>{const l=e.indexOf(t);l>-1&&e.splice(l,1)},tc=Object.prototype.hasOwnProperty,de=(e,t)=>tc.call(e,t),te=Array.isArray,nl=e=>Oi(e)==="[object Map]",mo=e=>Oi(e)==="[object Set]",oe=e=>typeof e=="function",we=e=>typeof e=="string",fl=e=>typeof e=="symbol",Ee=e=>e!==null&&typeof e=="object",bo=e=>(Ee(e)||oe(e))&&oe(e.then)&&oe(e.catch),ko=Object.prototype.toString,Oi=e=>ko.call(e),lc=e=>Oi(e).slice(8,-1),Eo=e=>Oi(e)==="[object Object]",yn=e=>we(e)&&e!=="NaN"&&e[0]!=="-"&&""+parseInt(e,10)===e,Al=bn(",key,ref,ref_for,ref_key,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted"),Pi=e=>{const t=Object.create(null);return l=>t[l]||(t[l]=e(l))},ic=/-(\w)/g,dt=Pi(e=>e.replace(ic,(t,l)=>l?l.toUpperCase():"")),nc=/\B([A-Z])/g,Jt=Pi(e=>e.replace(nc,"-$1").toLowerCase()),Ai=Pi(e=>e.charAt(0).toUpperCase()+e.slice(1)),Mi=Pi(e=>e?`on${Ai(e)}`:""),Yt=(e,t)=>!Object.is(e,t),$i=(e,t)=>{for(let l=0;l{Object.defineProperty(e,t,{configurable:!0,enumerable:!1,value:l})},rc=e=>{const t=parseFloat(e);return isNaN(t)?e:t},oc=e=>{const t=we(e)?Number(e):NaN;return isNaN(t)?e:t};let tr;const ln=()=>tr||(tr=typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:typeof global<"u"?global:{});function Wl(e){if(te(e)){const t={};for(let l=0;l{if(l){const i=l.split(cc);i.length>1&&(t[i[0].trim()]=i[1].trim())}}),t}function $e(e){let t="";if(we(e))t=e;else if(te(e))for(let l=0;lwe(e)?e:e==null?"":te(e)||Ee(e)&&(e.toString===ko||!oe(e.toString))?JSON.stringify(e,xo,2):String(e),xo=(e,t)=>t&&t.__v_isRef?xo(e,t.value):nl(t)?{[`Map(${t.size})`]:[...t.entries()].reduce((l,[i,n],r)=>(l[Bi(i,r)+" =>"]=n,l),{})}:mo(t)?{[`Set(${t.size})`]:[...t.values()].map(l=>Bi(l))}:fl(t)?Bi(t):Ee(t)&&!te(t)&&!Eo(t)?String(t):t,Bi=(e,t="")=>{var l;return fl(e)?`Symbol(${(l=e.description)!=null?l:t})`:e};let qe;class vc{constructor(t=!1){this.detached=t,this._active=!0,this.effects=[],this.cleanups=[],this.parent=qe,!t&&qe&&(this.index=(qe.scopes||(qe.scopes=[])).push(this)-1)}get active(){return this._active}run(t){if(this._active){const l=qe;try{return qe=this,t()}finally{qe=l}}}on(){qe=this}off(){qe=this.parent}stop(t){if(this._active){let l,i;for(l=0,i=this.effects.length;l{const t=new Set(e);return t.w=0,t.n=0,t},To=e=>(e.w&jt)>0,Oo=e=>(e.n&jt)>0,gc=({deps:e})=>{if(e.length)for(let t=0;t{const{deps:t}=e;if(t.length){let l=0;for(let i=0;i{(d==="length"||!fl(d)&&d>=a)&&c.push(u)})}else switch(l!==void 0&&c.push(o.get(l)),t){case"add":te(e)?yn(l)&&c.push(o.get("length")):(c.push(o.get(Ut)),nl(e)&&c.push(o.get(rn)));break;case"delete":te(e)||(c.push(o.get(Ut)),nl(e)&&c.push(o.get(rn)));break;case"set":nl(e)&&c.push(o.get(Ut));break}if(c.length===1)c[0]&&on(c[0]);else{const a=[];for(const u of c)u&&a.push(...u);on(xn(a))}}function on(e,t){const l=te(e)?e:[...e];for(const i of l)i.computed&&ir(i);for(const i of l)i.computed||ir(i)}function ir(e,t){(e!==lt||e.allowRecurse)&&(e.scheduler?e.scheduler():e.run())}function mc(e,t){var l;return(l=fi.get(e))==null?void 0:l.get(t)}const bc=bn("__proto__,__v_isRef,__isVue"),wo=new Set(Object.getOwnPropertyNames(Symbol).filter(e=>e!=="arguments"&&e!=="caller").map(e=>Symbol[e]).filter(fl)),nr=kc();function kc(){const e={};return["includes","indexOf","lastIndexOf"].forEach(t=>{e[t]=function(...l){const i=ve(this);for(let r=0,o=this.length;r{e[t]=function(...l){gl();const i=ve(this)[t].apply(this,l);return pl(),i}}),e}function Ec(e){const t=ve(this);return Xe(t,"has",e),t.hasOwnProperty(e)}class Ro{constructor(t=!1,l=!1){this._isReadonly=t,this._shallow=l}get(t,l,i){const n=this._isReadonly,r=this._shallow;if(l==="__v_isReactive")return!n;if(l==="__v_isReadonly")return n;if(l==="__v_isShallow")return r;if(l==="__v_raw")return i===(n?r?Sc:So:r?jo:Do).get(t)||Object.getPrototypeOf(t)===Object.getPrototypeOf(i)?t:void 0;const o=te(t);if(!n){if(o&&de(nr,l))return Reflect.get(nr,l,i);if(l==="hasOwnProperty")return Ec}const c=Reflect.get(t,l,i);return(fl(l)?wo.has(l):bc(l))||(n||Xe(t,"get",l),r)?c:Ne(c)?o&&yn(l)?c:c.value:Ee(c)?n?Ri(c):zl(c):c}}class Io extends Ro{constructor(t=!1){super(!1,t)}set(t,l,i,n){let r=t[l];if(!this._shallow){const a=cl(r);if(!gi(i)&&!cl(i)&&(r=ve(r),i=ve(i)),!te(t)&&Ne(r)&&!Ne(i))return a?!1:(r.value=i,!0)}const o=te(t)&&yn(l)?Number(l)e,wi=e=>Reflect.getPrototypeOf(e);function Ql(e,t,l=!1,i=!1){e=e.__v_raw;const n=ve(e),r=ve(t);l||(Yt(t,r)&&Xe(n,"get",t),Xe(n,"get",r));const{has:o}=wi(n),c=i?Tn:l?An:Sl;if(o.call(n,t))return c(e.get(t));if(o.call(n,r))return c(e.get(r));e!==n&&e.get(t)}function Zl(e,t=!1){const l=this.__v_raw,i=ve(l),n=ve(e);return t||(Yt(e,n)&&Xe(i,"has",e),Xe(i,"has",n)),e===n?l.has(e):l.has(e)||l.has(n)}function ei(e,t=!1){return e=e.__v_raw,!t&&Xe(ve(e),"iterate",Ut),Reflect.get(e,"size",e)}function rr(e){e=ve(e);const t=ve(this);return wi(t).has.call(t,e)||(t.add(e),gt(t,"add",e,e)),this}function or(e,t){t=ve(t);const l=ve(this),{has:i,get:n}=wi(l);let r=i.call(l,e);r||(e=ve(e),r=i.call(l,e));const o=n.call(l,e);return l.set(e,t),r?Yt(t,o)&>(l,"set",e,t):gt(l,"add",e,t),this}function sr(e){const t=ve(this),{has:l,get:i}=wi(t);let n=l.call(t,e);n||(e=ve(e),n=l.call(t,e)),i&&i.call(t,e);const r=t.delete(e);return n&>(t,"delete",e,void 0),r}function cr(){const e=ve(this),t=e.size!==0,l=e.clear();return t&>(e,"clear",void 0,void 0),l}function ti(e,t){return function(i,n){const r=this,o=r.__v_raw,c=ve(o),a=t?Tn:e?An:Sl;return!e&&Xe(c,"iterate",Ut),o.forEach((u,d)=>i.call(n,a(u),a(d),r))}}function li(e,t,l){return function(...i){const n=this.__v_raw,r=ve(n),o=nl(r),c=e==="entries"||e===Symbol.iterator&&o,a=e==="keys"&&o,u=n[e](...i),d=l?Tn:t?An:Sl;return!t&&Xe(r,"iterate",a?rn:Ut),{next(){const{value:v,done:_}=u.next();return _?{value:v,done:_}:{value:c?[d(v[0]),d(v[1])]:d(v),done:_}},[Symbol.iterator](){return this}}}}function Lt(e){return function(...t){return e==="delete"?!1:e==="clear"?void 0:this}}function Oc(){const e={get(r){return Ql(this,r)},get size(){return ei(this)},has:Zl,add:rr,set:or,delete:sr,clear:cr,forEach:ti(!1,!1)},t={get(r){return Ql(this,r,!1,!0)},get size(){return ei(this)},has:Zl,add:rr,set:or,delete:sr,clear:cr,forEach:ti(!1,!0)},l={get(r){return Ql(this,r,!0)},get size(){return ei(this,!0)},has(r){return Zl.call(this,r,!0)},add:Lt("add"),set:Lt("set"),delete:Lt("delete"),clear:Lt("clear"),forEach:ti(!0,!1)},i={get(r){return Ql(this,r,!0,!0)},get size(){return ei(this,!0)},has(r){return Zl.call(this,r,!0)},add:Lt("add"),set:Lt("set"),delete:Lt("delete"),clear:Lt("clear"),forEach:ti(!0,!0)};return["keys","values","entries",Symbol.iterator].forEach(r=>{e[r]=li(r,!1,!1),l[r]=li(r,!0,!1),t[r]=li(r,!1,!0),i[r]=li(r,!0,!0)}),[e,l,t,i]}const[Pc,Ac,wc,Rc]=Oc();function On(e,t){const l=t?e?Rc:wc:e?Ac:Pc;return(i,n,r)=>n==="__v_isReactive"?!e:n==="__v_isReadonly"?e:n==="__v_raw"?i:Reflect.get(de(l,n)&&n in i?l:i,n,r)}const Ic={get:On(!1,!1)},Dc={get:On(!1,!0)},jc={get:On(!0,!1)},Do=new WeakMap,jo=new WeakMap,So=new WeakMap,Sc=new WeakMap;function Cc(e){switch(e){case"Object":case"Array":return 1;case"Map":case"Set":case"WeakMap":case"WeakSet":return 2;default:return 0}}function Vc(e){return e.__v_skip||!Object.isExtensible(e)?0:Cc(lc(e))}function zl(e){return cl(e)?e:Pn(e,!1,xc,Ic,Do)}function Co(e){return Pn(e,!1,Tc,Dc,jo)}function Ri(e){return Pn(e,!0,Lc,jc,So)}function Pn(e,t,l,i,n){if(!Ee(e)||e.__v_raw&&!(t&&e.__v_isReactive))return e;const r=n.get(e);if(r)return r;const o=Vc(e);if(o===0)return e;const c=new Proxy(e,o===2?i:l);return n.set(e,c),c}function rl(e){return cl(e)?rl(e.__v_raw):!!(e&&e.__v_isReactive)}function cl(e){return!!(e&&e.__v_isReadonly)}function gi(e){return!!(e&&e.__v_isShallow)}function Vo(e){return rl(e)||cl(e)}function ve(e){const t=e&&e.__v_raw;return t?ve(t):e}function Fo(e){return _i(e,"__v_skip",!0),e}const Sl=e=>Ee(e)?zl(e):e,An=e=>Ee(e)?Ri(e):e;function wn(e){It&<&&(e=ve(e),Ao(e.dep||(e.dep=xn())))}function Rn(e,t){e=ve(e);const l=e.dep;l&&on(l)}function Ne(e){return!!(e&&e.__v_isRef===!0)}function ge(e){return Ho(e,!1)}function No(e){return Ho(e,!0)}function Ho(e,t){return Ne(e)?e:new Fc(e,t)}class Fc{constructor(t,l){this.__v_isShallow=l,this.dep=void 0,this.__v_isRef=!0,this._rawValue=l?t:ve(t),this._value=l?t:Sl(t)}get value(){return wn(this),this._value}set value(t){const l=this.__v_isShallow||gi(t)||cl(t);t=l?t:ve(t),Yt(t,this._rawValue)&&(this._rawValue=t,this._value=l?t:Sl(t),Rn(this))}}function Xt(e){return Ne(e)?e.value:e}const Nc={get:(e,t,l)=>Xt(Reflect.get(e,t,l)),set:(e,t,l,i)=>{const n=e[t];return Ne(n)&&!Ne(l)?(n.value=l,!0):Reflect.set(e,t,l,i)}};function Mo(e){return rl(e)?e:new Proxy(e,Nc)}class Hc{constructor(t){this.dep=void 0,this.__v_isRef=!0;const{get:l,set:i}=t(()=>wn(this),()=>Rn(this));this._get=l,this._set=i}get value(){return this._get()}set value(t){this._set(t)}}function Mc(e){return new Hc(e)}function Ii(e){const t=te(e)?new Array(e.length):{};for(const l in e)t[l]=$o(e,l);return t}class $c{constructor(t,l,i){this._object=t,this._key=l,this._defaultValue=i,this.__v_isRef=!0}get value(){const t=this._object[this._key];return t===void 0?this._defaultValue:t}set value(t){this._object[this._key]=t}get dep(){return mc(ve(this._object),this._key)}}class Bc{constructor(t){this._getter=t,this.__v_isRef=!0,this.__v_isReadonly=!0}get value(){return this._getter()}}function Ef(e,t,l){return Ne(e)?e:oe(e)?new Bc(e):Ee(e)&&arguments.length>1?$o(e,t,l):ge(e)}function $o(e,t,l){const i=e[t];return Ne(i)?i:new $c(e,t,l)}class Wc{constructor(t,l,i,n){this._setter=l,this.dep=void 0,this.__v_isRef=!0,this.__v_isReadonly=!1,this._dirty=!0,this.effect=new Ln(t,()=>{this._dirty||(this._dirty=!0,Rn(this))}),this.effect.computed=this,this.effect.active=this._cacheable=!n,this.__v_isReadonly=i}get value(){const t=ve(this);return wn(t),(t._dirty||!t._cacheable)&&(t._dirty=!1,t._value=t.effect.run()),t._value}set value(t){this._setter(t)}}function zc(e,t,l=!1){let i,n;const r=oe(e);return r?(i=e,n=ut):(i=e.get,n=e.set),new Wc(i,n,r||!n,l)}function Dt(e,t,l,i){let n;try{n=i?e(...i):e()}catch(r){Ul(r,t,l)}return n}function Ze(e,t,l,i){if(oe(e)){const r=Dt(e,t,l,i);return r&&bo(r)&&r.catch(o=>{Ul(o,t,l)}),r}const n=[];for(let r=0;r>>1,n=Me[i],r=Vl(n);rat&&Me.splice(t,1)}function qc(e){te(e)?ol.push(...e):(!ft||!ft.includes(e,e.allowRecurse?$t+1:$t))&&ol.push(e),Wo()}function ar(e,t,l=Cl?at+1:0){for(;lVl(l)-Vl(i)),$t=0;$te.id==null?1/0:e.id,Gc=(e,t)=>{const l=Vl(e)-Vl(t);if(l===0){if(e.pre&&!t.pre)return-1;if(t.pre&&!e.pre)return 1}return l};function zo(e){sn=!1,Cl=!0,Me.sort(Gc);try{for(at=0;atwe(p)?p.trim():p)),v&&(n=l.map(rc))}let c,a=i[c=Mi(t)]||i[c=Mi(dt(t))];!a&&r&&(a=i[c=Mi(Jt(t))]),a&&Ze(a,e,6,n);const u=i[c+"Once"];if(u){if(!e.emitted)e.emitted={};else if(e.emitted[c])return;e.emitted[c]=!0,Ze(u,e,6,n)}}function Uo(e,t,l=!1){const i=t.emitsCache,n=i.get(e);if(n!==void 0)return n;const r=e.emits;let o={},c=!1;if(!oe(e)){const a=u=>{const d=Uo(u,t,!0);d&&(c=!0,Ie(o,d))};!l&&t.mixins.length&&t.mixins.forEach(a),e.extends&&a(e.extends),e.mixins&&e.mixins.forEach(a)}return!r&&!c?(Ee(e)&&i.set(e,null),null):(te(r)?r.forEach(a=>o[a]=null):Ie(o,r),Ee(e)&&i.set(e,o),o)}function ji(e,t){return!e||!Bl(t)?!1:(t=t.slice(2).replace(/Once$/,""),de(e,t[0].toLowerCase()+t.slice(1))||de(e,Jt(t))||de(e,t))}let Ve=null,Xo=null;function mi(e){const t=Ve;return Ve=e,Xo=e&&e.type.__scopeId||null,t}function Ce(e,t=Ve,l){if(!t||e._n)return e;const i=(...n)=>{i._d&&Er(-1);const r=mi(t);let o;try{o=e(...n)}finally{mi(r),i._d&&Er(1)}return o};return i._n=!0,i._c=!0,i._d=!0,i}function Wi(e){const{type:t,vnode:l,proxy:i,withProxy:n,props:r,propsOptions:[o],slots:c,attrs:a,emit:u,render:d,renderCache:v,data:_,setupState:p,ctx:m,inheritAttrs:x}=e;let A,D;const O=mi(e);try{if(l.shapeFlag&4){const y=n||i,H=y;A=tt(d.call(H,y,v,r,p,_,m)),D=a}else{const y=t;A=tt(y.length>1?y(r,{attrs:a,slots:c,emit:u}):y(r,null)),D=t.props?a:Jc(a)}}catch(y){Il.length=0,Ul(y,e,1),A=ne(Ye)}let b=A;if(D&&x!==!1){const y=Object.keys(D),{shapeFlag:H}=b;y.length&&H&7&&(o&&y.some(kn)&&(D=Qc(D,o)),b=Ct(b,D))}return l.dirs&&(b=Ct(b),b.dirs=b.dirs?b.dirs.concat(l.dirs):l.dirs),l.transition&&(b.transition=l.transition),A=b,mi(O),A}const Jc=e=>{let t;for(const l in e)(l==="class"||l==="style"||Bl(l))&&((t||(t={}))[l]=e[l]);return t},Qc=(e,t)=>{const l={};for(const i in e)(!kn(i)||!(i.slice(9)in t))&&(l[i]=e[i]);return l};function Zc(e,t,l){const{props:i,children:n,component:r}=e,{props:o,children:c,patchFlag:a}=t,u=r.emitsOptions;if(t.dirs||t.transition)return!0;if(l&&a>=0){if(a&1024)return!0;if(a&16)return i?ur(i,o,u):!!o;if(a&8){const d=t.dynamicProps;for(let v=0;ve.__isSuspense;function Ko(e,t){t&&t.pendingBranch?te(e)?t.effects.push(...e):t.effects.push(e):qc(e)}function ra(e,t){return Dn(e,null,t)}const ii={};function Ge(e,t,l){return Dn(e,t,l)}function Dn(e,t,{immediate:l,deep:i,flush:n,onTrack:r,onTrigger:o}=ye){var c;const a=Lo()===((c=Re)==null?void 0:c.scope)?Re:null;let u,d=!1,v=!1;if(Ne(e)?(u=()=>e.value,d=gi(e)):rl(e)?(u=()=>e,i=!0):te(e)?(v=!0,d=e.some(y=>rl(y)||gi(y)),u=()=>e.map(y=>{if(Ne(y))return y.value;if(rl(y))return zt(y);if(oe(y))return Dt(y,a,2)})):oe(e)?t?u=()=>Dt(e,a,2):u=()=>{if(!(a&&a.isUnmounted))return _&&_(),Ze(e,a,3,[p])}:u=ut,t&&i){const y=u;u=()=>zt(y())}let _,p=y=>{_=O.onStop=()=>{Dt(y,a,4),_=O.onStop=void 0}},m;if(dl)if(p=ut,t?l&&Ze(t,a,3,[u(),v?[]:void 0,p]):u(),n==="sync"){const y=Qa();m=y.__watcherHandles||(y.__watcherHandles=[])}else return ut;let x=v?new Array(e.length).fill(ii):ii;const A=()=>{if(O.active)if(t){const y=O.run();(i||d||(v?y.some((H,G)=>Yt(H,x[G])):Yt(y,x)))&&(_&&_(),Ze(t,a,3,[y,x===ii?void 0:v&&x[0]===ii?[]:x,p]),x=y)}else O.run()};A.allowRecurse=!!t;let D;n==="sync"?D=A:n==="post"?D=()=>Ue(A,a&&a.suspense):(A.pre=!0,a&&(A.id=a.uid),D=()=>Di(A));const O=new Ln(u,D);t?l?A():x=O.run():n==="post"?Ue(O.run.bind(O),a&&a.suspense):O.run();const b=()=>{O.stop(),a&&a.scope&&En(a.scope.effects,O)};return m&&m.push(b),b}function oa(e,t,l){const i=this.proxy,n=we(e)?e.includes(".")?qo(i,e):()=>i[e]:e.bind(i,i);let r;oe(t)?r=t:(r=t.handler,l=t);const o=Re;ul(this);const c=Dn(n,r.bind(i),l);return o?ul(o):qt(),c}function qo(e,t){const l=t.split(".");return()=>{let i=e;for(let n=0;n{zt(l,t)});else if(Eo(e))for(const l in e)zt(e[l],t);return e}function bi(e,t){const l=Ve;if(l===null)return e;const i=Fi(l)||l.proxy,n=e.dirs||(e.dirs=[]);for(let r=0;r{e.isMounted=!0}),ql(()=>{e.isUnmounting=!0}),e}const Je=[Function,Array],Go={mode:String,appear:Boolean,persisted:Boolean,onBeforeEnter:Je,onEnter:Je,onAfterEnter:Je,onEnterCancelled:Je,onBeforeLeave:Je,onLeave:Je,onAfterLeave:Je,onLeaveCancelled:Je,onBeforeAppear:Je,onAppear:Je,onAfterAppear:Je,onAppearCancelled:Je},ca={name:"BaseTransition",props:Go,setup(e,{slots:t}){const l=Vn(),i=sa();let n;return()=>{const r=t.default&&Jo(t.default(),!0);if(!r||!r.length)return;let o=r[0];if(r.length>1){for(const x of r)if(x.type!==Ye){o=x;break}}const c=ve(e),{mode:a}=c;if(i.isLeaving)return zi(o);const u=hr(o);if(!u)return zi(o);const d=cn(u,c,i,l);an(u,d);const v=l.subTree,_=v&&hr(v);let p=!1;const{getTransitionKey:m}=u.type;if(m){const x=m();n===void 0?n=x:x!==n&&(n=x,p=!0)}if(_&&_.type!==Ye&&(!Bt(u,_)||p)){const x=cn(_,c,i,l);if(an(_,x),a==="out-in")return i.isLeaving=!0,x.afterLeave=()=>{i.isLeaving=!1,l.update.active!==!1&&l.update()},zi(o);a==="in-out"&&u.type!==Ye&&(x.delayLeave=(A,D,O)=>{const b=Yo(i,_);b[String(_.key)]=_,A[At]=()=>{D(),A[At]=void 0,delete d.delayedLeave},d.delayedLeave=O})}return o}}},aa=ca;function Yo(e,t){const{leavingVNodes:l}=e;let i=l.get(t.type);return i||(i=Object.create(null),l.set(t.type,i)),i}function cn(e,t,l,i){const{appear:n,mode:r,persisted:o=!1,onBeforeEnter:c,onEnter:a,onAfterEnter:u,onEnterCancelled:d,onBeforeLeave:v,onLeave:_,onAfterLeave:p,onLeaveCancelled:m,onBeforeAppear:x,onAppear:A,onAfterAppear:D,onAppearCancelled:O}=t,b=String(e.key),y=Yo(l,e),H=(E,K)=>{E&&Ze(E,i,9,K)},G=(E,K)=>{const w=K[1];H(E,K),te(E)?E.every(U=>U.length<=1)&&w():E.length<=1&&w()},N={mode:r,persisted:o,beforeEnter(E){let K=c;if(!l.isMounted)if(n)K=x||c;else return;E[At]&&E[At](!0);const w=y[b];w&&Bt(e,w)&&w.el[At]&&w.el[At](),H(K,[E])},enter(E){let K=a,w=u,U=d;if(!l.isMounted)if(n)K=A||a,w=D||u,U=O||d;else return;let L=!1;const V=E[ni]=le=>{L||(L=!0,le?H(U,[E]):H(w,[E]),N.delayedLeave&&N.delayedLeave(),E[ni]=void 0)};K?G(K,[E,V]):V()},leave(E,K){const w=String(e.key);if(E[ni]&&E[ni](!0),l.isUnmounting)return K();H(v,[E]);let U=!1;const L=E[At]=V=>{U||(U=!0,K(),V?H(m,[E]):H(p,[E]),E[At]=void 0,y[w]===e&&delete y[w])};y[w]=e,_?G(_,[E,L]):L()},clone(E){return cn(E,t,l,i)}};return N}function zi(e){if(Kl(e))return e=Ct(e),e.children=null,e}function hr(e){return Kl(e)?e.children?e.children[0]:void 0:e}function an(e,t){e.shapeFlag&6&&e.component?an(e.component.subTree,t):e.shapeFlag&128?(e.ssContent.transition=t.clone(e.ssContent),e.ssFallback.transition=t.clone(e.ssFallback)):e.transition=t}function Jo(e,t=!1,l){let i=[],n=0;for(let r=0;r1)for(let r=0;r!!e.type.__asyncLoader;/*! #__NO_SIDE_EFFECTS__ */function h(e){oe(e)&&(e={loader:e});const{loader:t,loadingComponent:l,errorComponent:i,delay:n=200,timeout:r,suspensible:o=!0,onError:c}=e;let a=null,u,d=0;const v=()=>(d++,a=null,_()),_=()=>{let p;return a||(p=a=t().catch(m=>{if(m=m instanceof Error?m:new Error(String(m)),c)return new Promise((x,A)=>{c(m,()=>x(v()),()=>A(m),d+1)});throw m}).then(m=>p!==a&&a?a:(m&&(m.__esModule||m[Symbol.toStringTag]==="Module")&&(m=m.default),u=m,m)))};return _e({name:"AsyncComponentWrapper",__asyncLoader:_,get __asyncResolved(){return u},setup(){const p=Re;if(u)return()=>Ui(u,p);const m=O=>{a=null,Ul(O,p,13,!i)};if(o&&p.suspense||dl)return _().then(O=>()=>Ui(O,p)).catch(O=>(m(O),()=>i?ne(i,{error:O}):null));const x=ge(!1),A=ge(),D=ge(!!n);return n&&setTimeout(()=>{D.value=!1},n),r!=null&&setTimeout(()=>{if(!x.value&&!A.value){const O=new Error(`Async component timed out after ${r}ms.`);m(O),A.value=O}},r),_().then(()=>{x.value=!0,p.parent&&Kl(p.parent.vnode)&&Di(p.parent.update)}).catch(O=>{m(O),A.value=O}),()=>{if(x.value&&u)return Ui(u,p);if(A.value&&i)return ne(i,{error:A.value});if(l&&!D.value)return ne(l)}}})}function Ui(e,t){const{ref:l,props:i,children:n,ce:r}=t.vnode,o=ne(e,i,n);return o.ref=l,o.ce=r,delete t.vnode.ce,o}const Kl=e=>e.type.__isKeepAlive;function ua(e,t){Qo(e,"a",t)}function da(e,t){Qo(e,"da",t)}function Qo(e,t,l=Re){const i=e.__wdc||(e.__wdc=()=>{let n=l;for(;n;){if(n.isDeactivated)return;n=n.parent}return e()});if(Si(t,i,l),l){let n=l.parent;for(;n&&n.parent;)Kl(n.parent.vnode)&&ha(i,t,l,n),n=n.parent}}function ha(e,t,l,i){const n=Si(t,e,i,!0);Ci(()=>{En(i[t],n)},l)}function Si(e,t,l=Re,i=!1){if(l){const n=l[e]||(l[e]=[]),r=t.__weh||(t.__weh=(...o)=>{if(l.isUnmounted)return;gl(),ul(l);const c=Ze(t,l,e,o);return qt(),pl(),c});return i?n.unshift(r):n.push(r),r}}const kt=e=>(t,l=Re)=>(!dl||e==="sp")&&Si(e,(...i)=>t(...i),l),va=kt("bm"),We=kt("m"),_a=kt("bu"),fa=kt("u"),ql=kt("bum"),Ci=kt("um"),ga=kt("sp"),pa=kt("rtg"),ma=kt("rtc");function ba(e,t=Re){Si("ec",e,t)}function St(e,t,l,i){let n;const r=l;if(te(e)||we(e)){n=new Array(e.length);for(let o=0,c=e.length;ot(o,c,void 0,r));else{const o=Object.keys(e);n=new Array(o.length);for(let c=0,a=o.length;cxi(t)?!(t.type===Ye||t.type===ke&&!Zo(t.children)):!0)?e:null}const un=e=>e?ds(e)?Fi(e)||e.proxy:un(e.parent):null,wl=Ie(Object.create(null),{$:e=>e,$el:e=>e.vnode.el,$data:e=>e.data,$props:e=>e.props,$attrs:e=>e.attrs,$slots:e=>e.slots,$refs:e=>e.refs,$parent:e=>un(e.parent),$root:e=>un(e.root),$emit:e=>e.emit,$options:e=>jn(e),$forceUpdate:e=>e.f||(e.f=()=>Di(e.update)),$nextTick:e=>e.n||(e.n=Xl.bind(e.proxy)),$watch:e=>oa.bind(e)}),Xi=(e,t)=>e!==ye&&!e.__isScriptSetup&&de(e,t),ka={get({_:e},t){const{ctx:l,setupState:i,data:n,props:r,accessCache:o,type:c,appContext:a}=e;let u;if(t[0]!=="$"){const p=o[t];if(p!==void 0)switch(p){case 1:return i[t];case 2:return n[t];case 4:return l[t];case 3:return r[t]}else{if(Xi(i,t))return o[t]=1,i[t];if(n!==ye&&de(n,t))return o[t]=2,n[t];if((u=e.propsOptions[0])&&de(u,t))return o[t]=3,r[t];if(l!==ye&&de(l,t))return o[t]=4,l[t];dn&&(o[t]=0)}}const d=wl[t];let v,_;if(d)return t==="$attrs"&&Xe(e,"get",t),d(e);if((v=c.__cssModules)&&(v=v[t]))return v;if(l!==ye&&de(l,t))return o[t]=4,l[t];if(_=a.config.globalProperties,de(_,t))return _[t]},set({_:e},t,l){const{data:i,setupState:n,ctx:r}=e;return Xi(n,t)?(n[t]=l,!0):i!==ye&&de(i,t)?(i[t]=l,!0):de(e.props,t)||t[0]==="$"&&t.slice(1)in e?!1:(r[t]=l,!0)},has({_:{data:e,setupState:t,accessCache:l,ctx:i,appContext:n,propsOptions:r}},o){let c;return!!l[o]||e!==ye&&de(e,o)||Xi(t,o)||(c=r[0])&&de(c,o)||de(i,o)||de(wl,o)||de(n.config.globalProperties,o)},defineProperty(e,t,l){return l.get!=null?e._.accessCache[t]=0:de(l,"value")&&this.set(e,t,l.value,null),Reflect.defineProperty(e,t,l)}};function vr(e){return te(e)?e.reduce((t,l)=>(t[l]=null,t),{}):e}let dn=!0;function Ea(e){const t=jn(e),l=e.proxy,i=e.ctx;dn=!1,t.beforeCreate&&_r(t.beforeCreate,e,"bc");const{data:n,computed:r,methods:o,watch:c,provide:a,inject:u,created:d,beforeMount:v,mounted:_,beforeUpdate:p,updated:m,activated:x,deactivated:A,beforeDestroy:D,beforeUnmount:O,destroyed:b,unmounted:y,render:H,renderTracked:G,renderTriggered:N,errorCaptured:E,serverPrefetch:K,expose:w,inheritAttrs:U,components:L,directives:V,filters:le}=t;if(u&&ya(u,i,null),o)for(const J in o){const X=o[J];oe(X)&&(i[J]=X.bind(l))}if(n){const J=n.call(l,l);Ee(J)&&(e.data=zl(J))}if(dn=!0,r)for(const J in r){const X=r[J],De=oe(X)?X.bind(l,l):oe(X.get)?X.get.bind(l,l):ut,Se=!oe(X)&&oe(X.set)?X.set.bind(l):ut,ze=C({get:De,set:Se});Object.defineProperty(i,J,{enumerable:!0,configurable:!0,get:()=>ze.value,set:He=>ze.value=He})}if(c)for(const J in c)es(c[J],i,l,J);if(a){const J=oe(a)?a.call(l):a;Reflect.ownKeys(J).forEach(X=>{Kt(X,J[X])})}d&&_r(d,e,"c");function S(J,X){te(X)?X.forEach(De=>J(De.bind(l))):X&&J(X.bind(l))}if(S(va,v),S(We,_),S(_a,p),S(fa,m),S(ua,x),S(da,A),S(ba,E),S(ma,G),S(pa,N),S(ql,O),S(Ci,y),S(ga,K),te(w))if(w.length){const J=e.exposed||(e.exposed={});w.forEach(X=>{Object.defineProperty(J,X,{get:()=>l[X],set:De=>l[X]=De})})}else e.exposed||(e.exposed={});H&&e.render===ut&&(e.render=H),U!=null&&(e.inheritAttrs=U),L&&(e.components=L),V&&(e.directives=V)}function ya(e,t,l=ut){te(e)&&(e=hn(e));for(const i in e){const n=e[i];let r;Ee(n)?"default"in n?r=Te(n.from||i,n.default,!0):r=Te(n.from||i):r=Te(n),Ne(r)?Object.defineProperty(t,i,{enumerable:!0,configurable:!0,get:()=>r.value,set:o=>r.value=o}):t[i]=r}}function _r(e,t,l){Ze(te(e)?e.map(i=>i.bind(t.proxy)):e.bind(t.proxy),t,l)}function es(e,t,l,i){const n=i.includes(".")?qo(l,i):()=>l[i];if(we(e)){const r=t[e];oe(r)&&Ge(n,r)}else if(oe(e))Ge(n,e.bind(l));else if(Ee(e))if(te(e))e.forEach(r=>es(r,t,l,i));else{const r=oe(e.handler)?e.handler.bind(l):t[e.handler];oe(r)&&Ge(n,r,e)}}function jn(e){const t=e.type,{mixins:l,extends:i}=t,{mixins:n,optionsCache:r,config:{optionMergeStrategies:o}}=e.appContext,c=r.get(t);let a;return c?a=c:!n.length&&!l&&!i?a=t:(a={},n.length&&n.forEach(u=>ki(a,u,o,!0)),ki(a,t,o)),Ee(t)&&r.set(t,a),a}function ki(e,t,l,i=!1){const{mixins:n,extends:r}=t;r&&ki(e,r,l,!0),n&&n.forEach(o=>ki(e,o,l,!0));for(const o in t)if(!(i&&o==="expose")){const c=xa[o]||l&&l[o];e[o]=c?c(e[o],t[o]):t[o]}return e}const xa={data:fr,props:gr,emits:gr,methods:Pl,computed:Pl,beforeCreate:Be,created:Be,beforeMount:Be,mounted:Be,beforeUpdate:Be,updated:Be,beforeDestroy:Be,beforeUnmount:Be,destroyed:Be,unmounted:Be,activated:Be,deactivated:Be,errorCaptured:Be,serverPrefetch:Be,components:Pl,directives:Pl,watch:Ta,provide:fr,inject:La};function fr(e,t){return t?e?function(){return Ie(oe(e)?e.call(this,this):e,oe(t)?t.call(this,this):t)}:t:e}function La(e,t){return Pl(hn(e),hn(t))}function hn(e){if(te(e)){const t={};for(let l=0;l1)return l&&oe(t)?t.call(i&&i.proxy):t}}function Aa(e,t,l,i=!1){const n={},r={};_i(r,Vi,1),e.propsDefaults=Object.create(null),ls(e,t,n,r);for(const o in e.propsOptions[0])o in n||(n[o]=void 0);l?e.props=i?n:Co(n):e.type.props?e.props=n:e.props=r,e.attrs=r}function wa(e,t,l,i){const{props:n,attrs:r,vnode:{patchFlag:o}}=e,c=ve(n),[a]=e.propsOptions;let u=!1;if((i||o>0)&&!(o&16)){if(o&8){const d=e.vnode.dynamicProps;for(let v=0;v{a=!0;const[_,p]=is(v,t,!0);Ie(o,_),p&&c.push(...p)};!l&&t.mixins.length&&t.mixins.forEach(d),e.extends&&d(e.extends),e.mixins&&e.mixins.forEach(d)}if(!r&&!a)return Ee(e)&&i.set(e,il),il;if(te(r))for(let d=0;d-1,p[1]=x<0||m-1||de(p,"default"))&&c.push(v)}}}const u=[o,c];return Ee(e)&&i.set(e,u),u}function pr(e){return e[0]!=="$"}function mr(e){const t=e&&e.toString().match(/^\s*(function|class) (\w+)/);return t?t[2]:e===null?"null":""}function br(e,t){return mr(e)===mr(t)}function kr(e,t){return te(t)?t.findIndex(l=>br(l,e)):oe(t)&&br(t,e)?0:-1}const ns=e=>e[0]==="_"||e==="$stable",Sn=e=>te(e)?e.map(tt):[tt(e)],Ra=(e,t,l)=>{if(t._n)return t;const i=Ce((...n)=>Sn(t(...n)),l);return i._c=!1,i},rs=(e,t,l)=>{const i=e._ctx;for(const n in e){if(ns(n))continue;const r=e[n];if(oe(r))t[n]=Ra(n,r,i);else if(r!=null){const o=Sn(r);t[n]=()=>o}}},os=(e,t)=>{const l=Sn(t);e.slots.default=()=>l},Ia=(e,t)=>{if(e.vnode.shapeFlag&32){const l=t._;l?(e.slots=ve(t),_i(t,"_",l)):rs(t,e.slots={})}else e.slots={},t&&os(e,t);_i(e.slots,Vi,1)},Da=(e,t,l)=>{const{vnode:i,slots:n}=e;let r=!0,o=ye;if(i.shapeFlag&32){const c=t._;c?l&&c===1?r=!1:(Ie(n,t),!l&&c===1&&delete n._):(r=!t.$stable,rs(t,n)),o=t}else t&&(os(e,t),o={default:1});if(r)for(const c in n)!ns(c)&&o[c]==null&&delete n[c]};function yi(e,t,l,i,n=!1){if(te(e)){e.forEach((_,p)=>yi(_,t&&(te(t)?t[p]:t),l,i,n));return}if(sl(i)&&!n)return;const r=i.shapeFlag&4?Fi(i.component)||i.component.proxy:i.el,o=n?null:r,{i:c,r:a}=e,u=t&&t.r,d=c.refs===ye?c.refs={}:c.refs,v=c.setupState;if(u!=null&&u!==a&&(we(u)?(d[u]=null,de(v,u)&&(v[u]=null)):Ne(u)&&(u.value=null)),oe(a))Dt(a,c,12,[o,d]);else{const _=we(a),p=Ne(a);if(_||p){const m=()=>{if(e.f){const x=_?de(v,a)?v[a]:d[a]:a.value;n?te(x)&&En(x,r):te(x)?x.includes(r)||x.push(r):_?(d[a]=[r],de(v,a)&&(v[a]=d[a])):(a.value=[r],e.k&&(d[e.k]=a.value))}else _?(d[a]=o,de(v,a)&&(v[a]=o)):p&&(a.value=o,e.k&&(d[e.k]=o))};o?(m.id=-1,Ue(m,l)):m()}}}let Tt=!1;const ri=e=>/svg/.test(e.namespaceURI)&&e.tagName!=="foreignObject",oi=e=>e.nodeType===8;function ja(e){const{mt:t,p:l,o:{patchProp:i,createText:n,nextSibling:r,parentNode:o,remove:c,insert:a,createComment:u}}=e,d=(b,y)=>{if(!y.hasChildNodes()){l(null,b,y),pi(),y._vnode=b;return}Tt=!1,v(y.firstChild,b,null,null,null),pi(),y._vnode=b,Tt&&console.error("Hydration completed but contains mismatches.")},v=(b,y,H,G,N,E=!1)=>{const K=oi(b)&&b.data==="[",w=()=>x(b,y,H,G,N,K),{type:U,ref:L,shapeFlag:V,patchFlag:le}=y;let ie=b.nodeType;y.el=b,le===-2&&(E=!1,y.dynamicChildren=null);let S=null;switch(U){case al:ie!==3?y.children===""?(a(y.el=n(""),o(b),b),S=b):S=w():(b.data!==y.children&&(Tt=!0,b.data=y.children),S=r(b));break;case Ye:O(b)?(S=r(b),D(y.el=b.content.firstChild,b,H)):ie!==8||K?S=w():S=r(b);break;case Rl:if(K&&(b=r(b),ie=b.nodeType),ie===1||ie===3){S=b;const J=!y.children.length;for(let X=0;X{E=E||!!y.dynamicChildren;const{type:K,props:w,patchFlag:U,shapeFlag:L,dirs:V,transition:le}=y,ie=K==="input"||K==="option";if(ie||U!==-1){V&&ct(y,null,H,"created");let S=!1;if(O(b)){S=ss(G,le)&&H&&H.vnode.props&&H.vnode.props.appear;const X=b.content.firstChild;S&&le.beforeEnter(X),D(X,b,H),y.el=b=X}if(w)if(ie||!E||U&48)for(const X in w)(ie&&(X.endsWith("value")||X==="indeterminate")||Bl(X)&&!Al(X)||X[0]===".")&&i(b,X,null,w[X],!1,void 0,H);else w.onClick&&i(b,"onClick",null,w.onClick,!1,void 0,H);let J;if((J=w&&w.onVnodeBeforeMount)&&Qe(J,H,y),V&&ct(y,null,H,"beforeMount"),((J=w&&w.onVnodeMounted)||V||S)&&Ko(()=>{J&&Qe(J,H,y),S&&le.enter(b),V&&ct(y,null,H,"mounted")},G),L&16&&!(w&&(w.innerHTML||w.textContent))){let X=p(b.firstChild,y,b,H,G,N,E);for(;X;){Tt=!0;const De=X;X=X.nextSibling,c(De)}}else L&8&&b.textContent!==y.children&&(Tt=!0,b.textContent=y.children)}return b.nextSibling},p=(b,y,H,G,N,E,K)=>{K=K||!!y.dynamicChildren;const w=y.children,U=w.length;for(let L=0;L{const{slotScopeIds:K}=y;K&&(N=N?N.concat(K):K);const w=o(b),U=p(r(b),y,w,H,G,N,E);return U&&oi(U)&&U.data==="]"?r(y.anchor=U):(Tt=!0,a(y.anchor=u("]"),w,U),U)},x=(b,y,H,G,N,E)=>{if(Tt=!0,y.el=null,E){const U=A(b);for(;;){const L=r(b);if(L&&L!==U)c(L);else break}}const K=r(b),w=o(b);return c(b),l(null,y,w,K,H,G,ri(w),N),K},A=(b,y="[",H="]")=>{let G=0;for(;b;)if(b=r(b),b&&oi(b)&&(b.data===y&&G++,b.data===H)){if(G===0)return r(b);G--}return b},D=(b,y,H)=>{const G=y.parentNode;G&&G.replaceChild(b,y);let N=H;for(;N;)N.vnode.el===y&&(N.vnode.el=N.subTree.el=b),N=N.parent},O=b=>b.nodeType===1&&b.tagName.toLowerCase()==="template";return[d,v]}const Ue=Ko;function Sa(e){return Ca(e,ja)}function Ca(e,t){const l=ln();l.__VUE__=!0;const{insert:i,remove:n,patchProp:r,createElement:o,createText:c,createComment:a,setText:u,setElementText:d,parentNode:v,nextSibling:_,setScopeId:p=ut,insertStaticContent:m}=e,x=(f,g,k,T=null,R=null,I=null,B=!1,F=null,$=!!g.dynamicChildren)=>{if(f===g)return;f&&!Bt(f,g)&&(T=P(f),He(f,R,I,!0),f=null),g.patchFlag===-2&&($=!1,g.dynamicChildren=null);const{type:j,ref:Q,shapeFlag:q}=g;switch(j){case al:A(f,g,k,T);break;case Ye:D(f,g,k,T);break;case Rl:f==null&&O(g,k,T,B);break;case ke:L(f,g,k,T,R,I,B,F,$);break;default:q&1?H(f,g,k,T,R,I,B,F,$):q&6?V(f,g,k,T,R,I,B,F,$):(q&64||q&128)&&j.process(f,g,k,T,R,I,B,F,$,M)}Q!=null&&R&&yi(Q,f&&f.ref,I,g||f,!g)},A=(f,g,k,T)=>{if(f==null)i(g.el=c(g.children),k,T);else{const R=g.el=f.el;g.children!==f.children&&u(R,g.children)}},D=(f,g,k,T)=>{f==null?i(g.el=a(g.children||""),k,T):g.el=f.el},O=(f,g,k,T)=>{[f.el,f.anchor]=m(f.children,g,k,T,f.el,f.anchor)},b=({el:f,anchor:g},k,T)=>{let R;for(;f&&f!==g;)R=_(f),i(f,k,T),f=R;i(g,k,T)},y=({el:f,anchor:g})=>{let k;for(;f&&f!==g;)k=_(f),n(f),f=k;n(g)},H=(f,g,k,T,R,I,B,F,$)=>{B=B||g.type==="svg",f==null?G(g,k,T,R,I,B,F,$):K(f,g,R,I,B,F,$)},G=(f,g,k,T,R,I,B,F)=>{let $,j;const{type:Q,props:q,shapeFlag:Z,transition:re,dirs:se}=f;if($=f.el=o(f.type,I,q&&q.is,q),Z&8?d($,f.children):Z&16&&E(f.children,$,null,T,R,I&&Q!=="foreignObject",B,F),se&&ct(f,null,T,"created"),N($,f,f.scopeId,B,T),q){for(const pe in q)pe!=="value"&&!Al(pe)&&r($,pe,null,q[pe],I,f.children,T,R,je);"value"in q&&r($,"value",null,q.value),(j=q.onVnodeBeforeMount)&&Qe(j,T,f)}se&&ct(f,null,T,"beforeMount");const me=ss(R,re);me&&re.beforeEnter($),i($,g,k),((j=q&&q.onVnodeMounted)||me||se)&&Ue(()=>{j&&Qe(j,T,f),me&&re.enter($),se&&ct(f,null,T,"mounted")},R)},N=(f,g,k,T,R)=>{if(k&&p(f,k),T)for(let I=0;I{for(let j=$;j{const F=g.el=f.el;let{patchFlag:$,dynamicChildren:j,dirs:Q}=g;$|=f.patchFlag&16;const q=f.props||ye,Z=g.props||ye;let re;k&&Ft(k,!1),(re=Z.onVnodeBeforeUpdate)&&Qe(re,k,g,f),Q&&ct(g,f,k,"beforeUpdate"),k&&Ft(k,!0);const se=R&&g.type!=="foreignObject";if(j?w(f.dynamicChildren,j,F,k,T,se,I):B||X(f,g,F,null,k,T,se,I,!1),$>0){if($&16)U(F,g,q,Z,k,T,R);else if($&2&&q.class!==Z.class&&r(F,"class",null,Z.class,R),$&4&&r(F,"style",q.style,Z.style,R),$&8){const me=g.dynamicProps;for(let pe=0;pe{re&&Qe(re,k,g,f),Q&&ct(g,f,k,"updated")},T)},w=(f,g,k,T,R,I,B)=>{for(let F=0;F{if(k!==T){if(k!==ye)for(const F in k)!Al(F)&&!(F in T)&&r(f,F,k[F],null,B,g.children,R,I,je);for(const F in T){if(Al(F))continue;const $=T[F],j=k[F];$!==j&&F!=="value"&&r(f,F,j,$,B,g.children,R,I,je)}"value"in T&&r(f,"value",k.value,T.value)}},L=(f,g,k,T,R,I,B,F,$)=>{const j=g.el=f?f.el:c(""),Q=g.anchor=f?f.anchor:c("");let{patchFlag:q,dynamicChildren:Z,slotScopeIds:re}=g;re&&(F=F?F.concat(re):re),f==null?(i(j,k,T),i(Q,k,T),E(g.children,k,Q,R,I,B,F,$)):q>0&&q&64&&Z&&f.dynamicChildren?(w(f.dynamicChildren,Z,k,R,I,B,F),(g.key!=null||R&&g===R.subTree)&&cs(f,g,!0)):X(f,g,k,Q,R,I,B,F,$)},V=(f,g,k,T,R,I,B,F,$)=>{g.slotScopeIds=F,f==null?g.shapeFlag&512?R.ctx.activate(g,k,T,B,$):le(g,k,T,R,I,B,$):ie(f,g,$)},le=(f,g,k,T,R,I,B)=>{const F=f.component=za(f,T,R);if(Kl(f)&&(F.ctx.renderer=M),Ua(F),F.asyncDep){if(R&&R.registerDep(F,S),!f.el){const $=F.subTree=ne(Ye);D(null,$,g,k)}return}S(F,f,g,k,R,I,B)},ie=(f,g,k)=>{const T=g.component=f.component;if(Zc(f,g,k))if(T.asyncDep&&!T.asyncResolved){J(T,g,k);return}else T.next=g,Kc(T.update),T.update();else g.el=f.el,T.vnode=g},S=(f,g,k,T,R,I,B)=>{const F=()=>{if(f.isMounted){let{next:Q,bu:q,u:Z,parent:re,vnode:se}=f,me=Q,pe;Ft(f,!1),Q?(Q.el=se.el,J(f,Q,B)):Q=se,q&&$i(q),(pe=Q.props&&Q.props.onVnodeBeforeUpdate)&&Qe(pe,re,Q,se),Ft(f,!0);const Oe=Wi(f),et=f.subTree;f.subTree=Oe,x(et,Oe,v(et.el),P(et),f,R,I),Q.el=Oe.el,me===null&&ea(f,Oe.el),Z&&Ue(Z,R),(pe=Q.props&&Q.props.onVnodeUpdated)&&Ue(()=>Qe(pe,re,Q,se),R)}else{let Q;const{el:q,props:Z}=g,{bm:re,m:se,parent:me}=f,pe=sl(g);if(Ft(f,!1),re&&$i(re),!pe&&(Q=Z&&Z.onVnodeBeforeMount)&&Qe(Q,me,g),Ft(f,!0),q&&ae){const Oe=()=>{f.subTree=Wi(f),ae(q,f.subTree,f,R,null)};pe?g.type.__asyncLoader().then(()=>!f.isUnmounted&&Oe()):Oe()}else{const Oe=f.subTree=Wi(f);x(null,Oe,k,T,f,R,I),g.el=Oe.el}if(se&&Ue(se,R),!pe&&(Q=Z&&Z.onVnodeMounted)){const Oe=g;Ue(()=>Qe(Q,me,Oe),R)}(g.shapeFlag&256||me&&sl(me.vnode)&&me.vnode.shapeFlag&256)&&f.a&&Ue(f.a,R),f.isMounted=!0,g=k=T=null}},$=f.effect=new Ln(F,()=>Di(j),f.scope),j=f.update=()=>$.run();j.id=f.uid,Ft(f,!0),j()},J=(f,g,k)=>{g.component=f;const T=f.vnode.props;f.vnode=g,f.next=null,wa(f,g.props,T,k),Da(f,g.children,k),gl(),ar(f),pl()},X=(f,g,k,T,R,I,B,F,$=!1)=>{const j=f&&f.children,Q=f?f.shapeFlag:0,q=g.children,{patchFlag:Z,shapeFlag:re}=g;if(Z>0){if(Z&128){Se(j,q,k,T,R,I,B,F,$);return}else if(Z&256){De(j,q,k,T,R,I,B,F,$);return}}re&8?(Q&16&&je(j,R,I),q!==j&&d(k,q)):Q&16?re&16?Se(j,q,k,T,R,I,B,F,$):je(j,R,I,!0):(Q&8&&d(k,""),re&16&&E(q,k,T,R,I,B,F,$))},De=(f,g,k,T,R,I,B,F,$)=>{f=f||il,g=g||il;const j=f.length,Q=g.length,q=Math.min(j,Q);let Z;for(Z=0;ZQ?je(f,R,I,!0,!1,q):E(g,k,T,R,I,B,F,$,q)},Se=(f,g,k,T,R,I,B,F,$)=>{let j=0;const Q=g.length;let q=f.length-1,Z=Q-1;for(;j<=q&&j<=Z;){const re=f[j],se=g[j]=$?wt(g[j]):tt(g[j]);if(Bt(re,se))x(re,se,k,null,R,I,B,F,$);else break;j++}for(;j<=q&&j<=Z;){const re=f[q],se=g[Z]=$?wt(g[Z]):tt(g[Z]);if(Bt(re,se))x(re,se,k,null,R,I,B,F,$);else break;q--,Z--}if(j>q){if(j<=Z){const re=Z+1,se=reZ)for(;j<=q;)He(f[j],R,I,!0),j++;else{const re=j,se=j,me=new Map;for(j=se;j<=Z;j++){const Ke=g[j]=$?wt(g[j]):tt(g[j]);Ke.key!=null&&me.set(Ke.key,j)}let pe,Oe=0;const et=Z-se+1;let Qt=!1,Qn=0;const kl=new Array(et);for(j=0;j=et){He(Ke,R,I,!0);continue}let st;if(Ke.key!=null)st=me.get(Ke.key);else for(pe=se;pe<=Z;pe++)if(kl[pe-se]===0&&Bt(Ke,g[pe])){st=pe;break}st===void 0?He(Ke,R,I,!0):(kl[st-se]=j+1,st>=Qn?Qn=st:Qt=!0,x(Ke,g[st],k,null,R,I,B,F,$),Oe++)}const Zn=Qt?Va(kl):il;for(pe=Zn.length-1,j=et-1;j>=0;j--){const Ke=se+j,st=g[Ke],er=Ke+1{const{el:I,type:B,transition:F,children:$,shapeFlag:j}=f;if(j&6){ze(f.component.subTree,g,k,T);return}if(j&128){f.suspense.move(g,k,T);return}if(j&64){B.move(f,g,k,M);return}if(B===ke){i(I,g,k);for(let q=0;q<$.length;q++)ze($[q],g,k,T);i(f.anchor,g,k);return}if(B===Rl){b(f,g,k);return}if(T!==2&&j&1&&F)if(T===0)F.beforeEnter(I),i(I,g,k),Ue(()=>F.enter(I),R);else{const{leave:q,delayLeave:Z,afterLeave:re}=F,se=()=>i(I,g,k),me=()=>{q(I,()=>{se(),re&&re()})};Z?Z(I,se,me):me()}else i(I,g,k)},He=(f,g,k,T=!1,R=!1)=>{const{type:I,props:B,ref:F,children:$,dynamicChildren:j,shapeFlag:Q,patchFlag:q,dirs:Z}=f;if(F!=null&&yi(F,null,k,f,!0),Q&256){g.ctx.deactivate(f);return}const re=Q&1&&Z,se=!sl(f);let me;if(se&&(me=B&&B.onVnodeBeforeUnmount)&&Qe(me,g,f),Q&6)ot(f.component,k,T);else{if(Q&128){f.suspense.unmount(k,T);return}re&&ct(f,null,g,"beforeUnmount"),Q&64?f.type.remove(f,g,k,R,M,T):j&&(I!==ke||q>0&&q&64)?je(j,g,k,!1,!0):(I===ke&&q&384||!R&&Q&16)&&je($,g,k),T&&yt(f)}(se&&(me=B&&B.onVnodeUnmounted)||re)&&Ue(()=>{me&&Qe(me,g,f),re&&ct(f,null,g,"unmounted")},k)},yt=f=>{const{type:g,el:k,anchor:T,transition:R}=f;if(g===ke){xt(k,T);return}if(g===Rl){y(f);return}const I=()=>{n(k),R&&!R.persisted&&R.afterLeave&&R.afterLeave()};if(f.shapeFlag&1&&R&&!R.persisted){const{leave:B,delayLeave:F}=R,$=()=>B(k,I);F?F(f.el,I,$):$()}else I()},xt=(f,g)=>{let k;for(;f!==g;)k=_(f),n(f),f=k;n(g)},ot=(f,g,k)=>{const{bum:T,scope:R,update:I,subTree:B,um:F}=f;T&&$i(T),R.stop(),I&&(I.active=!1,He(B,f,g,k)),F&&Ue(F,g),Ue(()=>{f.isUnmounted=!0},g),g&&g.pendingBranch&&!g.isUnmounted&&f.asyncDep&&!f.asyncResolved&&f.suspenseId===g.pendingId&&(g.deps--,g.deps===0&&g.resolve())},je=(f,g,k,T=!1,R=!1,I=0)=>{for(let B=I;Bf.shapeFlag&6?P(f.component.subTree):f.shapeFlag&128?f.suspense.next():_(f.anchor||f.el),z=(f,g,k)=>{f==null?g._vnode&&He(g._vnode,null,null,!0):x(g._vnode||null,f,g,null,null,null,k),ar(),pi(),g._vnode=f},M={p:x,um:He,m:ze,r:yt,mt:le,mc:E,pc:X,pbc:w,n:P,o:e};let Y,ae;return t&&([Y,ae]=t(M)),{render:z,hydrate:Y,createApp:Pa(z,Y)}}function Ft({effect:e,update:t},l){e.allowRecurse=t.allowRecurse=l}function ss(e,t){return(!e||e&&!e.pendingBranch)&&t&&!t.persisted}function cs(e,t,l=!1){const i=e.children,n=t.children;if(te(i)&&te(n))for(let r=0;r>1,e[l[c]]0&&(t[i]=l[r-1]),l[r]=i)}}for(r=l.length,o=l[r-1];r-- >0;)l[r]=o,o=t[o];return l}const Fa=e=>e.__isTeleport,ke=Symbol.for("v-fgt"),al=Symbol.for("v-txt"),Ye=Symbol.for("v-cmt"),Rl=Symbol.for("v-stc"),Il=[];let it=null;function W(e=!1){Il.push(it=e?null:[])}function Na(){Il.pop(),it=Il[Il.length-1]||null}let Fl=1;function Er(e){Fl+=e}function as(e){return e.dynamicChildren=Fl>0?it||il:null,Na(),Fl>0&&it&&it.push(e),e}function ee(e,t,l,i,n,r){return as(ce(e,t,l,i,n,r,!0))}function Ae(e,t,l,i,n){return as(ne(e,t,l,i,n,!0))}function xi(e){return e?e.__v_isVNode===!0:!1}function Bt(e,t){return e.type===t.type&&e.key===t.key}const Vi="__vInternal",us=({key:e})=>e??null,hi=({ref:e,ref_key:t,ref_for:l})=>(typeof e=="number"&&(e=""+e),e!=null?we(e)||Ne(e)||oe(e)?{i:Ve,r:e,k:t,f:!!l}:e:null);function ce(e,t=null,l=null,i=0,n=null,r=e===ke?0:1,o=!1,c=!1){const a={__v_isVNode:!0,__v_skip:!0,type:e,props:t,key:t&&us(t),ref:t&&hi(t),scopeId:Xo,slotScopeIds:null,children:l,component:null,suspense:null,ssContent:null,ssFallback:null,dirs:null,transition:null,el:null,anchor:null,target:null,targetAnchor:null,staticCount:0,shapeFlag:r,patchFlag:i,dynamicProps:n,dynamicChildren:null,appContext:null,ctx:Ve};return c?(Cn(a,l),r&128&&e.normalize(a)):l&&(a.shapeFlag|=we(l)?8:16),Fl>0&&!o&&it&&(a.patchFlag>0||r&6)&&a.patchFlag!==32&&it.push(a),a}const ne=Ha;function Ha(e,t=null,l=null,i=0,n=null,r=!1){if((!e||e===la)&&(e=Ye),xi(e)){const c=Ct(e,t,!0);return l&&Cn(c,l),Fl>0&&!r&&it&&(c.shapeFlag&6?it[it.indexOf(e)]=c:it.push(c)),c.patchFlag|=-2,c}if(Ya(e)&&(e=e.__vccOpts),t){t=Ma(t);let{class:c,style:a}=t;c&&!we(c)&&(t.class=$e(c)),Ee(a)&&(Vo(a)&&!te(a)&&(a=Ie({},a)),t.style=Wl(a))}const o=we(e)?1:na(e)?128:Fa(e)?64:Ee(e)?4:oe(e)?2:0;return ce(e,t,l,i,n,o,r,!0)}function Ma(e){return e?Vo(e)||Vi in e?Ie({},e):e:null}function Ct(e,t,l=!1){const{props:i,ref:n,patchFlag:r,children:o}=e,c=t?_n(i||{},t):i;return{__v_isVNode:!0,__v_skip:!0,type:e.type,props:c,key:c&&us(c),ref:t&&t.ref?l&&n?te(n)?n.concat(hi(t)):[n,hi(t)]:hi(t):n,scopeId:e.scopeId,slotScopeIds:e.slotScopeIds,children:o,target:e.target,targetAnchor:e.targetAnchor,staticCount:e.staticCount,shapeFlag:e.shapeFlag,patchFlag:t&&e.type!==ke?r===-1?16:r|16:r,dynamicProps:e.dynamicProps,dynamicChildren:e.dynamicChildren,appContext:e.appContext,dirs:e.dirs,transition:e.transition,component:e.component,suspense:e.suspense,ssContent:e.ssContent&&Ct(e.ssContent),ssFallback:e.ssFallback&&Ct(e.ssFallback),el:e.el,anchor:e.anchor,ctx:e.ctx,ce:e.ce}}function Vt(e=" ",t=0){return ne(al,null,e,t)}function $a(e,t){const l=ne(Rl,null,e);return l.staticCount=t,l}function Le(e="",t=!1){return t?(W(),Ae(Ye,null,e)):ne(Ye,null,e)}function tt(e){return e==null||typeof e=="boolean"?ne(Ye):te(e)?ne(ke,null,e.slice()):typeof e=="object"?wt(e):ne(al,null,String(e))}function wt(e){return e.el===null&&e.patchFlag!==-1||e.memo?e:Ct(e)}function Cn(e,t){let l=0;const{shapeFlag:i}=e;if(t==null)t=null;else if(te(t))l=16;else if(typeof t=="object")if(i&65){const n=t.default;n&&(n._c&&(n._d=!1),Cn(e,n()),n._c&&(n._d=!0));return}else{l=32;const n=t._;!n&&!(Vi in t)?t._ctx=Ve:n===3&&Ve&&(Ve.slots._===1?t._=1:(t._=2,e.patchFlag|=1024))}else oe(t)?(t={default:t,_ctx:Ve},l=32):(t=String(t),i&64?(l=16,t=[Vt(t)]):l=8);e.children=t,e.shapeFlag|=l}function _n(...e){const t={};for(let l=0;lRe||Ve;let Fn,Zt,yr="__VUE_INSTANCE_SETTERS__";(Zt=ln()[yr])||(Zt=ln()[yr]=[]),Zt.push(e=>Re=e),Fn=e=>{Zt.length>1?Zt.forEach(t=>t(e)):Zt[0](e)};const ul=e=>{Fn(e),e.scope.on()},qt=()=>{Re&&Re.scope.off(),Fn(null)};function ds(e){return e.vnode.shapeFlag&4}let dl=!1;function Ua(e,t=!1){dl=t;const{props:l,children:i}=e.vnode,n=ds(e);Aa(e,l,n,t),Ia(e,i);const r=n?Xa(e,t):void 0;return dl=!1,r}function Xa(e,t){const l=e.type;e.accessCache=Object.create(null),e.proxy=Fo(new Proxy(e.ctx,ka));const{setup:i}=l;if(i){const n=e.setupContext=i.length>1?qa(e):null;ul(e),gl();const r=Dt(i,e,0,[e.props,n]);if(pl(),qt(),bo(r)){if(r.then(qt,qt),t)return r.then(o=>{xr(e,o,t)}).catch(o=>{Ul(o,e,0)});e.asyncDep=r}else xr(e,r,t)}else hs(e,t)}function xr(e,t,l){oe(t)?e.type.__ssrInlineRender?e.ssrRender=t:e.render=t:Ee(t)&&(e.setupState=Mo(t)),hs(e,l)}let Lr;function hs(e,t,l){const i=e.type;if(!e.render){if(!t&&Lr&&!i.render){const n=i.template||jn(e).template;if(n){const{isCustomElement:r,compilerOptions:o}=e.appContext.config,{delimiters:c,compilerOptions:a}=i,u=Ie(Ie({isCustomElement:r,delimiters:c},o),a);i.render=Lr(n,u)}}e.render=i.render||ut}{ul(e),gl();try{Ea(e)}finally{pl(),qt()}}}function Ka(e){return e.attrsProxy||(e.attrsProxy=new Proxy(e.attrs,{get(t,l){return Xe(e,"get","$attrs"),t[l]}}))}function qa(e){const t=l=>{e.exposed=l||{}};return{get attrs(){return Ka(e)},slots:e.slots,emit:e.emit,expose:t}}function Fi(e){if(e.exposed)return e.exposeProxy||(e.exposeProxy=new Proxy(Mo(Fo(e.exposed)),{get(t,l){if(l in t)return t[l];if(l in wl)return wl[l](e)},has(t,l){return l in t||l in wl}}))}function Ga(e,t=!0){return oe(e)?e.displayName||e.name:e.name||t&&e.__name}function Ya(e){return oe(e)&&"__vccOpts"in e}const C=(e,t)=>zc(e,t,dl);function he(e,t,l){const i=arguments.length;return i===2?Ee(t)&&!te(t)?xi(t)?ne(e,null,[t]):ne(e,t):ne(e,null,t):(i>3?l=Array.prototype.slice.call(arguments,2):i===3&&xi(l)&&(l=[l]),ne(e,t,l))}const Ja=Symbol.for("v-scx"),Qa=()=>Te(Ja),Za="3.3.13",eu="http://www.w3.org/2000/svg",Wt=typeof document<"u"?document:null,Tr=Wt&&Wt.createElement("template"),tu={insert:(e,t,l)=>{t.insertBefore(e,l||null)},remove:e=>{const t=e.parentNode;t&&t.removeChild(e)},createElement:(e,t,l,i)=>{const n=t?Wt.createElementNS(eu,e):Wt.createElement(e,l?{is:l}:void 0);return e==="select"&&i&&i.multiple!=null&&n.setAttribute("multiple",i.multiple),n},createText:e=>Wt.createTextNode(e),createComment:e=>Wt.createComment(e),setText:(e,t)=>{e.nodeValue=t},setElementText:(e,t)=>{e.textContent=t},parentNode:e=>e.parentNode,nextSibling:e=>e.nextSibling,querySelector:e=>Wt.querySelector(e),setScopeId(e,t){e.setAttribute(t,"")},insertStaticContent(e,t,l,i,n,r){const o=l?l.previousSibling:t.lastChild;if(n&&(n===r||n.nextSibling))for(;t.insertBefore(n.cloneNode(!0),l),!(n===r||!(n=n.nextSibling)););else{Tr.innerHTML=i?`${e}`:e;const c=Tr.content;if(i){const a=c.firstChild;for(;a.firstChild;)c.appendChild(a.firstChild);c.removeChild(a)}t.insertBefore(c,l)}return[o?o.nextSibling:t.firstChild,l?l.previousSibling:t.lastChild]}},Ot="transition",El="animation",Nl=Symbol("_vtc"),Gl=(e,{slots:t})=>he(aa,lu(e),t);Gl.displayName="Transition";const vs={name:String,type:String,css:{type:Boolean,default:!0},duration:[String,Number,Object],enterFromClass:String,enterActiveClass:String,enterToClass:String,appearFromClass:String,appearActiveClass:String,appearToClass:String,leaveFromClass:String,leaveActiveClass:String,leaveToClass:String};Gl.props=Ie({},Go,vs);const Nt=(e,t=[])=>{te(e)?e.forEach(l=>l(...t)):e&&e(...t)},Or=e=>e?te(e)?e.some(t=>t.length>1):e.length>1:!1;function lu(e){const t={};for(const L in e)L in vs||(t[L]=e[L]);if(e.css===!1)return t;const{name:l="v",type:i,duration:n,enterFromClass:r=`${l}-enter-from`,enterActiveClass:o=`${l}-enter-active`,enterToClass:c=`${l}-enter-to`,appearFromClass:a=r,appearActiveClass:u=o,appearToClass:d=c,leaveFromClass:v=`${l}-leave-from`,leaveActiveClass:_=`${l}-leave-active`,leaveToClass:p=`${l}-leave-to`}=e,m=iu(n),x=m&&m[0],A=m&&m[1],{onBeforeEnter:D,onEnter:O,onEnterCancelled:b,onLeave:y,onLeaveCancelled:H,onBeforeAppear:G=D,onAppear:N=O,onAppearCancelled:E=b}=t,K=(L,V,le)=>{Ht(L,V?d:c),Ht(L,V?u:o),le&&le()},w=(L,V)=>{L._isLeaving=!1,Ht(L,v),Ht(L,p),Ht(L,_),V&&V()},U=L=>(V,le)=>{const ie=L?N:O,S=()=>K(V,L,le);Nt(ie,[V,S]),Pr(()=>{Ht(V,L?a:r),Pt(V,L?d:c),Or(ie)||Ar(V,i,x,S)})};return Ie(t,{onBeforeEnter(L){Nt(D,[L]),Pt(L,r),Pt(L,o)},onBeforeAppear(L){Nt(G,[L]),Pt(L,a),Pt(L,u)},onEnter:U(!1),onAppear:U(!0),onLeave(L,V){L._isLeaving=!0;const le=()=>w(L,V);Pt(L,v),ou(),Pt(L,_),Pr(()=>{L._isLeaving&&(Ht(L,v),Pt(L,p),Or(y)||Ar(L,i,A,le))}),Nt(y,[L,le])},onEnterCancelled(L){K(L,!1),Nt(b,[L])},onAppearCancelled(L){K(L,!0),Nt(E,[L])},onLeaveCancelled(L){w(L),Nt(H,[L])}})}function iu(e){if(e==null)return null;if(Ee(e))return[Ki(e.enter),Ki(e.leave)];{const t=Ki(e);return[t,t]}}function Ki(e){return oc(e)}function Pt(e,t){t.split(/\s+/).forEach(l=>l&&e.classList.add(l)),(e[Nl]||(e[Nl]=new Set)).add(t)}function Ht(e,t){t.split(/\s+/).forEach(i=>i&&e.classList.remove(i));const l=e[Nl];l&&(l.delete(t),l.size||(e[Nl]=void 0))}function Pr(e){requestAnimationFrame(()=>{requestAnimationFrame(e)})}let nu=0;function Ar(e,t,l,i){const n=e._endId=++nu,r=()=>{n===e._endId&&i()};if(l)return setTimeout(r,l);const{type:o,timeout:c,propCount:a}=ru(e,t);if(!o)return i();const u=o+"end";let d=0;const v=()=>{e.removeEventListener(u,_),r()},_=p=>{p.target===e&&++d>=a&&v()};setTimeout(()=>{d(l[m]||"").split(", "),n=i(`${Ot}Delay`),r=i(`${Ot}Duration`),o=wr(n,r),c=i(`${El}Delay`),a=i(`${El}Duration`),u=wr(c,a);let d=null,v=0,_=0;t===Ot?o>0&&(d=Ot,v=o,_=r.length):t===El?u>0&&(d=El,v=u,_=a.length):(v=Math.max(o,u),d=v>0?o>u?Ot:El:null,_=d?d===Ot?r.length:a.length:0);const p=d===Ot&&/\b(transform|all)(,|$)/.test(i(`${Ot}Property`).toString());return{type:d,timeout:v,propCount:_,hasTransform:p}}function wr(e,t){for(;e.lengthRr(l)+Rr(e[i])))}function Rr(e){return e==="auto"?0:Number(e.slice(0,-1).replace(",","."))*1e3}function ou(){return document.body.offsetHeight}function su(e,t,l){const i=e[Nl];i&&(t=(t?[t,...i]:[...i]).join(" ")),t==null?e.removeAttribute("class"):l?e.setAttribute("class",t):e.className=t}const Nn=Symbol("_vod"),Li={beforeMount(e,{value:t},{transition:l}){e[Nn]=e.style.display==="none"?"":e.style.display,l&&t?l.beforeEnter(e):yl(e,t)},mounted(e,{value:t},{transition:l}){l&&t&&l.enter(e)},updated(e,{value:t,oldValue:l},{transition:i}){!t!=!l&&(i?t?(i.beforeEnter(e),yl(e,!0),i.enter(e)):i.leave(e,()=>{yl(e,!1)}):yl(e,t))},beforeUnmount(e,{value:t}){yl(e,t)}};function yl(e,t){e.style.display=t?e[Nn]:"none"}const cu=Symbol("");function au(e,t,l){const i=e.style,n=we(l);if(l&&!n){if(t&&!we(t))for(const r in t)l[r]==null&&fn(i,r,"");for(const r in l)fn(i,r,l[r])}else{const r=i.display;if(n){if(t!==l){const o=i[cu];o&&(l+=";"+o),i.cssText=l}}else t&&e.removeAttribute("style");Nn in e&&(i.display=r)}}const Ir=/\s*!important$/;function fn(e,t,l){if(te(l))l.forEach(i=>fn(e,t,i));else if(l==null&&(l=""),t.startsWith("--"))e.setProperty(t,l);else{const i=uu(e,t);Ir.test(l)?e.setProperty(Jt(i),l.replace(Ir,""),"important"):e[i]=l}}const Dr=["Webkit","Moz","ms"],qi={};function uu(e,t){const l=qi[t];if(l)return l;let i=dt(t);if(i!=="filter"&&i in e)return qi[t]=i;i=Ai(i);for(let n=0;nGi||(pu.then(()=>Gi=0),Gi=Date.now());function bu(e,t){const l=i=>{if(!i._vts)i._vts=Date.now();else if(i._vts<=l.attached)return;Ze(ku(i,l.value),t,5,[i])};return l.value=e,l.attached=mu(),l}function ku(e,t){if(te(t)){const l=e.stopImmediatePropagation;return e.stopImmediatePropagation=()=>{l.call(e),e._stopped=!0},t.map(i=>n=>!n._stopped&&i&&i(n))}else return t}const Vr=e=>e.charCodeAt(0)===111&&e.charCodeAt(1)===110&&e.charCodeAt(2)>96&&e.charCodeAt(2)<123,Eu=(e,t,l,i,n=!1,r,o,c,a)=>{t==="class"?su(e,i,n):t==="style"?au(e,l,i):Bl(t)?kn(t)||fu(e,t,l,i,o):(t[0]==="."?(t=t.slice(1),!0):t[0]==="^"?(t=t.slice(1),!1):yu(e,t,i,n))?hu(e,t,i,r,o,c,a):(t==="true-value"?e._trueValue=i:t==="false-value"&&(e._falseValue=i),du(e,t,i,n))};function yu(e,t,l,i){if(i)return!!(t==="innerHTML"||t==="textContent"||t in e&&Vr(t)&&oe(l));if(t==="spellcheck"||t==="draggable"||t==="translate"||t==="form"||t==="list"&&e.tagName==="INPUT"||t==="type"&&e.tagName==="TEXTAREA")return!1;if(t==="width"||t==="height"){const n=e.tagName;if(n==="IMG"||n==="VIDEO"||n==="CANVAS"||n==="SOURCE")return!1}return Vr(t)&&we(l)?!1:t in e}const xu={esc:"escape",space:" ",up:"arrow-up",left:"arrow-left",right:"arrow-right",down:"arrow-down",delete:"backspace"},Lu=(e,t)=>{const l=e._withKeys||(e._withKeys={}),i=t.join(".");return l[i]||(l[i]=n=>{if(!("key"in n))return;const r=Jt(n.key);if(t.some(o=>o===r||xu[o]===r))return e(n)})},Tu=Ie({patchProp:Eu},tu);let Yi,Fr=!1;function Ou(){return Yi=Fr?Yi:Sa(Tu),Fr=!0,Yi}const Pu=(...e)=>{const t=Ou().createApp(...e),{mount:l}=t;return t.mount=i=>{const n=Au(i);if(n)return l(n,!0,n instanceof SVGElement)},t};function Au(e){return we(e)?document.querySelector(e):e}const wu="modulepreload",Ru=function(e){return"/"+e},Nr={},s=function(t,l,i){let n=Promise.resolve();return l&&l.length>0&&(document.getElementsByTagName("link"),n=Promise.all(l.map(r=>{if(r=Ru(r),r in Nr)return;Nr[r]=!0;const o=r.endsWith(".css"),c=o?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${r}"]${c}`))return;const a=document.createElement("link");if(a.rel=o?"stylesheet":wu,o||(a.as="script",a.crossOrigin=""),a.href=r,document.head.appendChild(a),o)return new Promise((u,d)=>{a.addEventListener("load",u),a.addEventListener("error",()=>d(new Error(`Unable to preload CSS for ${r}`)))})}))),n.then(()=>t()).catch(r=>{const o=new Event("vite:preloadError",{cancelable:!0});if(o.payload=r,window.dispatchEvent(o),!o.defaultPrevented)throw r})},Iu={"v-8daa1a0e":()=>s(()=>import("./index.html-DsdONe9B.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-aad48c6a":()=>s(()=>import("./news.html-Cw8MfCXZ.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-f7496066":()=>s(()=>import("./index.html-CTbMiGG2.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-ba934fd8":()=>s(()=>import("./index.html-B2ETL5pY.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-41ade9da":()=>s(()=>import("./api.html-5y-QWEO9.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-83dedd38":()=>s(()=>import("./dns.html-BfPt-22g.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-192a19b9":()=>s(()=>import("./fakedns.html-BSHcVJMt.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-7f6279d8":()=>s(()=>import("./inbound.html-2Gs5XIZT.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-1d860c29":()=>s(()=>import("./log.html-DOIV41-g.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-fbaf47ec":()=>s(()=>import("./metrics.html-C1kvghj5.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-24956213":()=>s(()=>import("./observatory.html-Dkgoiajw.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-2367d756":()=>s(()=>import("./outbound.html-C10j64xi.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-4ebec35a":()=>s(()=>import("./policy.html-CErsqhDk.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-31b7756a":()=>s(()=>import("./reverse.html-BzUnx5j0.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-70677432":()=>s(()=>import("./routing.html-N1Zy6QRq.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-7e21d6ae":()=>s(()=>import("./stats.html-DHCl8ess.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-e3dfff38":()=>s(()=>import("./transport.html-CnZXw5hX.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-36b1a79b":()=>s(()=>import("./index.html-CA-WluU-.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-09a64f89":()=>s(()=>import("./command.html-Sco1d_Iq.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-2b1adf48":()=>s(()=>import("./config.html-O0hv2z0b.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-86ee963a":()=>s(()=>import("./document.html-vroedGik.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-0e5d7b39":()=>s(()=>import("./install.html-CtHiKZjZ.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-2d0a870d":()=>s(()=>import("./index.html-BR6NUj4D.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-2d0ab8b3":()=>s(()=>import("./index.html-Cm8mQKPu.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-6a9e8054":()=>s(()=>import("./compile.html-C08Er0mK.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-95e3eaea":()=>s(()=>import("./design.html-JvR3o2wW.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-61e7eea6":()=>s(()=>import("./guide.html-CIw6ZqK-.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-6e6c37e6":()=>s(()=>import("./mkcp.html-BECLirWp.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-13168a21":()=>s(()=>import("./muxcool.html-DxsTQuoq.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-5c48c82b":()=>s(()=>import("./vless.html-bx0zLtjU.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-1ee591a8":()=>s(()=>import("./vmess.html-DH5KSkx4.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-0d714d87":()=>s(()=>import("./browser_dialer.html-DYjgEhDN.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-0da7880a":()=>s(()=>import("./env.html-x3PGFNW0.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-2aeb21f9":()=>s(()=>import("./fallback.html-BCz8baOr.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-3acf20ea":()=>s(()=>import("./multiple.html-CA4IQdBs.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-792e28f8":()=>s(()=>import("./xtls.html-DTQkH1EU.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-b50d2334":()=>s(()=>import("./dokodemo.html-CwfBRGLx.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-593408b0":()=>s(()=>import("./http.html-BtBoaSJk.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-802a842a":()=>s(()=>import("./shadowsocks.html-Bog2IQ_X.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-29995cea":()=>s(()=>import("./socks.html-B_KFCfGa.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-2a1b3d72":()=>s(()=>import("./trojan.html-BkQCt-32.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-fb92e8aa":()=>s(()=>import("./vless.html-CxK3eXqB.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-167afaac":()=>s(()=>import("./vmess.html-BSAH9EwQ.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-5588d0cc":()=>s(()=>import("./wireguard.html-DI0HSIg5.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-749ad71a":()=>s(()=>import("./blackhole.html-C3j-gtFm.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-6d39b970":()=>s(()=>import("./dns.html-IaJfUMdl.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-d76e893a":()=>s(()=>import("./freedom.html-DFU9EbHR.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-c6b4b59e":()=>s(()=>import("./http.html-CqFywJ_o.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-41ec0e0e":()=>s(()=>import("./loopback.html-CYltRkS6.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-7b293e4a":()=>s(()=>import("./shadowsocks.html-BdSAub8s.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-15f5452a":()=>s(()=>import("./socks.html-C_Ryg_Zn.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-5797bdb3":()=>s(()=>import("./trojan.html-_aC10_zp.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-a60f016c":()=>s(()=>import("./vless.html-sPPpqcW_.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-413cee4b":()=>s(()=>import("./vmess.html-3bHG9IEs.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-208ca3b9":()=>s(()=>import("./wireguard.html-DMp0Htsq.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-2877542a":()=>s(()=>import("./grpc.html-BOwRBc6V.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-03a28284":()=>s(()=>import("./h2.html-B-_cdxSw.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-04158536":()=>s(()=>import("./httpupgrade.html-DNm5DiZb.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-3167b1dd":()=>s(()=>import("./mkcp.html-CmaMJX_Q.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-eeea2fb0":()=>s(()=>import("./splithttp.html-CkMHeQ1D.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-33b1b709":()=>s(()=>import("./tcp.html-tAb-Rdu-.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-1ff57bba":()=>s(()=>import("./websocket.html-J4zD0ZXr.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-3f09dcfa":()=>s(()=>import("./index.html-CpLT_ZsY.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-fb444906":()=>s(()=>import("./ch01-preface.html-DmNJxKif.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-075f3ae5":()=>s(()=>import("./ch02-preparation.html-BTKGqj9u.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-726d0633":()=>s(()=>import("./ch03-ssh.html-Bs4sxOG7.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-430c6ab8":()=>s(()=>import("./ch04-security.html-BgZQf6Zy.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-717c6376":()=>s(()=>import("./ch05-webpage.html-C3ISjTL0.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-278039be":()=>s(()=>import("./ch06-certificates.html-g-a588dM.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-a0c7f88e":()=>s(()=>import("./ch07-xray-server.html-CL7ODUGu.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-86586ca2":()=>s(()=>import("./ch08-xray-clients.html-D0DH-0jR.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-3eb62514":()=>s(()=>import("./ch09-appendix.html-B-sOxmCt.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-3f09dcbc":()=>s(()=>import("./index.html-Z8xBvZ8J.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-b21a2a20":()=>s(()=>import("./fallbacks-lv1.html-Dyr_PhvB.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-da623318":()=>s(()=>import("./fallbacks-with-sni.html-V5VzGt_a.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-fdd722ac":()=>s(()=>import("./routing-lv1-part1.html-C-IzJ3qA.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-fa6d716e":()=>s(()=>import("./routing-lv1-part2.html-Shikx9Ih.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-2f29e106":()=>s(()=>import("./work.html-CEe4qs2X.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-3f09dc7e":()=>s(()=>import("./index.html-DC6-KGmE.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-1c17916e":()=>s(()=>import("./iptables_gid.html-BMSyFQlC.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-a001cfa6":()=>s(()=>import("./nginx_or_haproxy_tls_tunnel.html-pJln5JiT.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-46333b48":()=>s(()=>import("./redirect.html-qKHxqUqo.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-338bc63e":()=>s(()=>import("./tproxy.html-ByDe25dh.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-d68f7d58":()=>s(()=>import("./tproxy_ipv4_and_ipv6.html-D-5zdr32.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-e533e2c6":()=>s(()=>import("./traffic_stats.html-0T5V4GoX.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-1e465ab0":()=>s(()=>import("./warp.html-BDXJx2co.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-1080fb37":()=>s(()=>import("./news.html-CYLnHfpK.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-317fc580":()=>s(()=>import("./index.html-CVcFP_qj.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-45144c7f":()=>s(()=>import("./api.html-Kao4_KiT.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-23fbd2d0":()=>s(()=>import("./dns.html-CvTCwYNS.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-2b7ec525":()=>s(()=>import("./fakedns.html-Dvu3AZyj.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-5ab92300":()=>s(()=>import("./inbound.html-DMVoiGk7.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-f91d64d6":()=>s(()=>import("./log.html--3F9JN_2.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-d705f114":()=>s(()=>import("./metrics.html-BLJ8GVn6.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-5c8e777f":()=>s(()=>import("./observatory.html-CcNQ0eYH.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-268cd669":()=>s(()=>import("./outbound.html-CzOKWWkv.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-4492d567":()=>s(()=>import("./policy.html-C8ASaUzS.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-0d0e1e92":()=>s(()=>import("./reverse.html-BnnvxzqT.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-4bbe1d5a":()=>s(()=>import("./routing.html-zynaWMFD.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-16426d1a":()=>s(()=>import("./stats.html-DGZuatV1.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-5de780d0":()=>s(()=>import("./transport.html-j20KTFMX.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-f88d343e":()=>s(()=>import("./index.html-CFqc6OBy.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-38d56a07":()=>s(()=>import("./index.html-DFwA2xNy.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-4d046016":()=>s(()=>import("./command.html-B7s0-Piq.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-22b35270":()=>s(()=>import("./config.html-DrlSKA0W.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-30bd7c12":()=>s(()=>import("./document.html-CBY4dmVD.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-439608b6":()=>s(()=>import("./install.html-Vhx-_q7N.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-408e88d1":()=>s(()=>import("./news.html-BJEpDr2m.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-b1cce5cc":()=>s(()=>import("./index.html-Br3dj_2c.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-7521da19":()=>s(()=>import("./api.html-DLDnYtg0.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-5409606a":()=>s(()=>import("./dns.html-DfoiH0ad.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-5877f5bf":()=>s(()=>import("./fakedns.html-DFAPe69C.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-00c6c1cc":()=>s(()=>import("./inbound.html-7L6d18D5.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-990249a2":()=>s(()=>import("./log.html-DjmhB4xx.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-7d138fe0":()=>s(()=>import("./metrics.html-wNzErJVc.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-11e9cb19":()=>s(()=>import("./observatory.html-CQ1B9WMF.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-ce8c8de2":()=>s(()=>import("./outbound.html-BaSyw3Ug.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-3dc4298d":()=>s(()=>import("./policy.html-CZXmUkYI.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-26722151":()=>s(()=>import("./reverse.html-B5DaFRsx.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-071a21ed":()=>s(()=>import("./routing.html-C1g2i1zS.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-7922fc34":()=>s(()=>import("./stats.html-CkQuuoBx.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-3156f2ea":()=>s(()=>import("./transport.html-DfxqUj3F.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-40ee4e87":()=>s(()=>import("./index.html-BBMcLiPC.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-a1c899be":()=>s(()=>import("./index.html-B-J-mqnv.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-a6257be2":()=>s(()=>import("./command.html-CKVtMSxh.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-d63f95d4":()=>s(()=>import("./config.html-CpMF1H3m.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-fbbfd9c6":()=>s(()=>import("./document.html-Cv2iGxpB.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-9cb72482":()=>s(()=>import("./install.html-BUGXoodV.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-51a51d87":()=>s(()=>import("./transparent_proxy.html-DZNi96TQ.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-76b9a0f3":()=>s(()=>import("./browser_dialer.html-Bdbrov2m.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-565dbfc4":()=>s(()=>import("./env.html-kVBaIisu.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-0fbd1336":()=>s(()=>import("./fallback.html-Cz26Rtbk.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-a0627812":()=>s(()=>import("./multiple.html-672DYUik.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-d190d938":()=>s(()=>import("./xtls.html-enE-oLop.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-72afc2d2":()=>s(()=>import("./dokodemo.html-DpZKpCsl.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-773d731c":()=>s(()=>import("./http.html-CbEwhYAM.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-f555fc02":()=>s(()=>import("./shadowsocks.html-nKE9-JwE.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-e35196c2":()=>s(()=>import("./socks.html-BYoEVGSJ.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-29188644":()=>s(()=>import("./trojan.html-2VAwem9J.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-255a6ebf":()=>s(()=>import("./vless.html-BCCfQS7T.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-8cc24480":()=>s(()=>import("./vmess.html-DmF6uMmY.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-a2605ea4":()=>s(()=>import("./wireguard.html-BIApe7Jj.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-64e47ef4":()=>s(()=>import("./blackhole.html-Cv99Ln_e.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-e979b848":()=>s(()=>import("./dns.html-1tf_wTEw.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-617f0fcf":()=>s(()=>import("./freedom.html-CGstSPGu.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-3fc98845":()=>s(()=>import("./http.html-BW71su7G.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-1b804722":()=>s(()=>import("./loopback.html-DBZDnpde.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-63077cb6":()=>s(()=>import("./shadowsocks.html-Cfe33M9q.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-516476d4":()=>s(()=>import("./socks.html-ZsLxpdI_.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-7d61a872":()=>s(()=>import("./trojan.html-C_OdgAQH.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-6e50feb6":()=>s(()=>import("./vless.html-DNT9jIbN.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-02956db7":()=>s(()=>import("./vmess.html-BnKkO-oz.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-797f8d25":()=>s(()=>import("./wireguard.html-B1zHQq-E.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-2c6058d4":()=>s(()=>import("./grpc.html-D7nAIvyK.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-1c38292a":()=>s(()=>import("./h2.html-9I7eRGud.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-17ff144a":()=>s(()=>import("./httpupgrade.html-DpYANPWG.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-1a7f9d6e":()=>s(()=>import("./mkcp.html-D1BaSNsx.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-4df52c3c":()=>s(()=>import("./splithttp.html-DstjiOIY.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-5254cbc6":()=>s(()=>import("./tcp.html-Dvv-qFsr.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-9520f392":()=>s(()=>import("./websocket.html-CDgG-JKn.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-b7760e2c":()=>s(()=>import("./compile.html-CSlVqiWd.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-fb774212":()=>s(()=>import("./design.html-CnO0gj1h.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-38c376c1":()=>s(()=>import("./guide.html-C1S7IA49.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-21bccd79":()=>s(()=>import("./mkcp.html-VU4-Z4x2.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-27001935":()=>s(()=>import("./muxcool.html-CEJDgOyw.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-21b30c3f":()=>s(()=>import("./vless.html-DH9DXlDy.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-94110980":()=>s(()=>import("./vmess.html-DRYwVgEC.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-789ba7ef":()=>s(()=>import("./index.html-B7FLw-wS.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-d3712ade":()=>s(()=>import("./ch01-preface.html-CpS2RBBO.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-41f9c00e":()=>s(()=>import("./ch02-preparation.html-nD3-r55P.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-4c013f47":()=>s(()=>import("./ch03-ssh.html-6Lvt6PUL.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-a75683b8":()=>s(()=>import("./ch04-security.html-B6qoKme-.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-f5341aec":()=>s(()=>import("./ch05-webpage.html-DzsY94d_.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-4458f72a":()=>s(()=>import("./ch06-certificates.html-Ddg6ioji.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-f1802e66":()=>s(()=>import("./ch07-xray-server.html-C13N5hD6.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-4ca6f1ca":()=>s(()=>import("./ch08-xray-clients.html-DQ22p1_O.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-b0030f00":()=>s(()=>import("./ch09-appendix.html-CgxfJw0n.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-789ba80e":()=>s(()=>import("./index.html-NEtYQEGC.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-103b3e5c":()=>s(()=>import("./fallbacks-lv1.html-DzqMpBvO.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-110dd688":()=>s(()=>import("./fallbacks-with-sni.html--6P9o5e1.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-c425a7d4":()=>s(()=>import("./routing-lv1-part1.html-CLrmD7am.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-c0bbf696":()=>s(()=>import("./routing-lv1-part2.html-BeZDTPEs.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-5b6477cc":()=>s(()=>import("./work.html-bZWwnav2.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-789ba82d":()=>s(()=>import("./index.html-CL_S8-vB.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-05ddc65d":()=>s(()=>import("./iptables_gid.html-C-yflUZU.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-474afe99":()=>s(()=>import("./nginx_or_haproxy_tls_tunnel.html-Gb-c4jql.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-930ac920":()=>s(()=>import("./redirect.html-CkD_E0gF.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-c579975c":()=>s(()=>import("./tproxy.html-BW6K5LzA.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-7efb7c68":()=>s(()=>import("./tproxy_ipv4_and_ipv6.html-BQJ6GusY.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-12a33bee":()=>s(()=>import("./traffic_stats.html-DD1S40Up.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-7d2b8478":()=>s(()=>import("./warp.html-C4DFBgRI.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-1cfb44e6":()=>s(()=>import("./browser_dialer.html-DHvZocHd.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-6a3f8078":()=>s(()=>import("./env.html-BcRLB4iC.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-74f22e7f":()=>s(()=>import("./fallback.html-BtkFw_Xq.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-2c9f7c11":()=>s(()=>import("./multiple.html-L9QltWwj.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-630c687e":()=>s(()=>import("./xtls.html-ByQJIYGC.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-20ff0a28":()=>s(()=>import("./dokodemo.html-6k4BnhfY.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-43124836":()=>s(()=>import("./http.html-CXH6I19f.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-6a351ba5":()=>s(()=>import("./shadowsocks.html-Dq6vO-NY.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-3d1d02c5":()=>s(()=>import("./socks.html-HP5cpkrw.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-1567b378":()=>s(()=>import("./trojan.html-ur2ZEK_x.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-57bf8636":()=>s(()=>import("./vless.html-Dp7gCWtk.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-6864abe6":()=>s(()=>import("./vmess.html-BtGpHvfz.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-67d3c858":()=>s(()=>import("./wireguard.html-DFWWl4Re.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-5910da20":()=>s(()=>import("./blackhole.html-DWoVmjiZ.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-5717f8f6":()=>s(()=>import("./dns.html-COClhUcF.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-4360702e":()=>s(()=>import("./freedom.html-BnDskwJS.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-22e1532a":()=>s(()=>import("./http.html-o0wpiHQf.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-38c69248":()=>s(()=>import("./loopback.html-BcZmhFf5.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-1a2a97d0":()=>s(()=>import("./shadowsocks.html-S-jhNF8h.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-0141bb30":()=>s(()=>import("./socks.html-zyIZHHJ4.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-544bef26":()=>s(()=>import("./trojan.html-2ngT_7cs.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-cf761560":()=>s(()=>import("./vless.html-CNa_dakW.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-2c896451":()=>s(()=>import("./vmess.html-D5q0vDPy.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-0502a6bf":()=>s(()=>import("./wireguard.html-DILhdRFk.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-13c3ca30":()=>s(()=>import("./grpc.html-1JoA2je9.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-2fe60378":()=>s(()=>import("./h2.html-BOxtTm8R.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-453f5c70":()=>s(()=>import("./httpupgrade.html-C5iPswVE.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-1cb427e3":()=>s(()=>import("./mkcp.html-DILru_l-.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-32d545e2":()=>s(()=>import("./splithttp.html-C1SjdxYM.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-f4c92f7a":()=>s(()=>import("./tcp.html-BgZgnk7j.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-cb60c046":()=>s(()=>import("./websocket.html-DNoxTZYE.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-7ce977e0":()=>s(()=>import("./compile.html-D59MH5rf.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-01d5d1de":()=>s(()=>import("./design.html-Ddh8g14z.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-4d4e5367":()=>s(()=>import("./guide.html-BdEYZrHF.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-a58031da":()=>s(()=>import("./mkcp.html-DAmKBEn3.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-5440615b":()=>s(()=>import("./muxcool.html-mhoEooTk.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-069325e5":()=>s(()=>import("./vless.html-CkQDajpI.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-ca50d634":()=>s(()=>import("./vmess.html-DtwTJf0_.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-490791ee":()=>s(()=>import("./index.html-CpXf73_p.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-78f09a92":()=>s(()=>import("./ch01-preface.html-w7EJag-g.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-64f6e51f":()=>s(()=>import("./ch02-preparation.html-Dgjcbj9R.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-69478a6d":()=>s(()=>import("./ch03-ssh.html-SW0FgDU9.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-271d7abe":()=>s(()=>import("./ch04-security.html-DMyIYFbc.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-9ab38aa0":()=>s(()=>import("./ch05-webpage.html-BJ9Dh4eq.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-7cddd6c4":()=>s(()=>import("./ch06-certificates.html-CYpwWYQK.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-0d33adf3":()=>s(()=>import("./ch07-xray-server.html-BMC39V_R.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-123166b5":()=>s(()=>import("./ch08-xray-clients.html-SOUUSYfz.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-22c7351a":()=>s(()=>import("./ch09-appendix.html-CaY0Q2De.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-490791b0":()=>s(()=>import("./index.html-DIt_Qwmg.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-e9f80a14":()=>s(()=>import("./fallbacks-lv1.html-Cj8_C__Y.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-2db62ba4":()=>s(()=>import("./fallbacks-with-sni.html-UrPS3PK0.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-531be8a0":()=>s(()=>import("./routing-lv1-part1.html-CrCZge13.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-4fb23762":()=>s(()=>import("./routing-lv1-part2.html-BNHKIWxf.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-fdd8db80":()=>s(()=>import("./work.html-nNVb3F6P.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-49079172":()=>s(()=>import("./index.html-nyT_8_ff.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-331e0e83":()=>s(()=>import("./iptables_gid.html-5z8dtoE5.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-7418a5b3":()=>s(()=>import("./nginx_or_haproxy_tls_tunnel.html-CZEav5bi.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-587e32d4":()=>s(()=>import("./redirect.html-IdxcHO8c.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-9c63de10":()=>s(()=>import("./tproxy.html-BHj4GcZZ.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-a4c782e4":()=>s(()=>import("./tproxy_ipv4_and_ipv6.html-D9HsaVXj.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-71771ea3":()=>s(()=>import("./traffic_stats.html-D5bPdgjj.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-70300bea":()=>s(()=>import("./warp.html-Dj49TU1P.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-7689d7f3":()=>s(()=>import("./transparent_proxy.html-C4cGXidp.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-39b3c50d":()=>s(()=>import("./transparent_proxy.html-CdU0iNrm.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-3706649a":()=>s(()=>import("./404.html-CnfmQthm.js"),__vite__mapDeps([])).then(({data:e})=>e)},Du=JSON.parse('{"base":"/","lang":"en-US","title":"","description":"","head":[["link",{"rel":"icon","href":"/logo.png"}]],"locales":{"/":{"lang":"zh-CN","title":"Project X","description":"Xray 官方文档"},"/en/":{"lang":"en-US","title":"Project X","description":"Official document of Xray"},"/ru/":{"lang":"ru-RU","title":"Project X","description":"Официальная документация Xray"}}}');var ju=["link","meta","script","style","noscript","template"],Su=["title","base"],Cu=([e,t,l])=>Su.includes(e)?e:ju.includes(e)?e==="meta"&&t.name?`${e}.${t.name}`:e==="template"&&t.id?`${e}.${t.id}`:JSON.stringify([e,Object.entries(t).map(([i,n])=>typeof n=="boolean"?n?[i,""]:null:[i,n]).filter(i=>i!=null).sort(([i],[n])=>i.localeCompare(n)),l]):null,Vu=e=>{const t=new Set,l=[];return e.forEach(i=>{const n=Cu(i);n&&!t.has(n)&&(t.add(n),l.push(i))}),l},Yl=e=>/^(https?:)?\/\//.test(e),Fu=e=>/^[a-z][a-z0-9+.-]*:/.test(e),Hn=e=>Object.prototype.toString.call(e)==="[object Object]",_s=e=>e[e.length-1]==="/"?e.slice(0,-1):e,fs=e=>e[0]==="/"?e.slice(1):e,gs=(e,t)=>{const l=Object.keys(e).sort((i,n)=>{const r=n.split("/").length-i.split("/").length;return r!==0?r:n.length-i.length});for(const i of l)if(t.startsWith(i))return i;return"/"},Nu=e=>typeof e=="function",nt=e=>typeof e=="string";const ps={"v-8daa1a0e":h(()=>s(()=>import("./index.html-CLXQYZCk.js"),__vite__mapDeps([]))),"v-aad48c6a":h(()=>s(()=>import("./news.html-DY4EgGn2.js"),__vite__mapDeps([]))),"v-f7496066":h(()=>s(()=>import("./index.html-DrIaJd6V.js"),__vite__mapDeps([]))),"v-ba934fd8":h(()=>s(()=>import("./index.html-DamtlSYx.js"),__vite__mapDeps([]))),"v-41ade9da":h(()=>s(()=>import("./api.html-MH0dPqio.js"),__vite__mapDeps([]))),"v-83dedd38":h(()=>s(()=>import("./dns.html-BiECdzTI.js"),__vite__mapDeps([]))),"v-192a19b9":h(()=>s(()=>import("./fakedns.html-DHh-5fVH.js"),__vite__mapDeps([]))),"v-7f6279d8":h(()=>s(()=>import("./inbound.html-Bl2le8Jm.js"),__vite__mapDeps([]))),"v-1d860c29":h(()=>s(()=>import("./log.html-CTirYPei.js"),__vite__mapDeps([]))),"v-fbaf47ec":h(()=>s(()=>import("./metrics.html-DSYbmHxQ.js"),__vite__mapDeps([]))),"v-24956213":h(()=>s(()=>import("./observatory.html-BMuTIcPE.js"),__vite__mapDeps([]))),"v-2367d756":h(()=>s(()=>import("./outbound.html-w2bkUi_e.js"),__vite__mapDeps([]))),"v-4ebec35a":h(()=>s(()=>import("./policy.html-Dor87Wko.js"),__vite__mapDeps([]))),"v-31b7756a":h(()=>s(()=>import("./reverse.html-CW54AkoO.js"),__vite__mapDeps([]))),"v-70677432":h(()=>s(()=>import("./routing.html-DwJ4ma_9.js"),__vite__mapDeps([]))),"v-7e21d6ae":h(()=>s(()=>import("./stats.html-B7OBry98.js"),__vite__mapDeps([]))),"v-e3dfff38":h(()=>s(()=>import("./transport.html-BsB3pOlv.js"),__vite__mapDeps([]))),"v-36b1a79b":h(()=>s(()=>import("./index.html-DRWQxS_s.js"),__vite__mapDeps([]))),"v-09a64f89":h(()=>s(()=>import("./command.html-DM-t2Q6w.js"),__vite__mapDeps([]))),"v-2b1adf48":h(()=>s(()=>import("./config.html-DFUKOYQn.js"),__vite__mapDeps([]))),"v-86ee963a":h(()=>s(()=>import("./document.html-BI9FxX1n.js"),__vite__mapDeps([]))),"v-0e5d7b39":h(()=>s(()=>import("./install.html-f4BUU2Xm.js"),__vite__mapDeps([]))),"v-2d0a870d":h(()=>s(()=>import("./index.html-BKL86b_Z.js"),__vite__mapDeps([]))),"v-2d0ab8b3":h(()=>s(()=>import("./index.html-Cprk0yv3.js"),__vite__mapDeps([]))),"v-6a9e8054":h(()=>s(()=>import("./compile.html-DXk7Z9BM.js"),__vite__mapDeps([]))),"v-95e3eaea":h(()=>s(()=>import("./design.html-Cz-hmEoU.js"),__vite__mapDeps([]))),"v-61e7eea6":h(()=>s(()=>import("./guide.html-BmyZZjJ4.js"),__vite__mapDeps([]))),"v-6e6c37e6":h(()=>s(()=>import("./mkcp.html-zExRKUGX.js"),__vite__mapDeps([]))),"v-13168a21":h(()=>s(()=>import("./muxcool.html-u7BHHyP5.js"),__vite__mapDeps([]))),"v-5c48c82b":h(()=>s(()=>import("./vless.html-DPYoRUM4.js"),__vite__mapDeps([]))),"v-1ee591a8":h(()=>s(()=>import("./vmess.html-zYdoLiG_.js"),__vite__mapDeps([]))),"v-0d714d87":h(()=>s(()=>import("./browser_dialer.html-DGUfP3Xp.js"),__vite__mapDeps([]))),"v-0da7880a":h(()=>s(()=>import("./env.html-BGX1tEf1.js"),__vite__mapDeps([]))),"v-2aeb21f9":h(()=>s(()=>import("./fallback.html-DyfId2wt.js"),__vite__mapDeps([]))),"v-3acf20ea":h(()=>s(()=>import("./multiple.html-ByHUK-DJ.js"),__vite__mapDeps([]))),"v-792e28f8":h(()=>s(()=>import("./xtls.html-DYo3Adlx.js"),__vite__mapDeps([]))),"v-b50d2334":h(()=>s(()=>import("./dokodemo.html-LnG90uyS.js"),__vite__mapDeps([]))),"v-593408b0":h(()=>s(()=>import("./http.html-CXn_nB9h.js"),__vite__mapDeps([]))),"v-802a842a":h(()=>s(()=>import("./shadowsocks.html-BQ1nQK54.js"),__vite__mapDeps([]))),"v-29995cea":h(()=>s(()=>import("./socks.html-D6GgkO4d.js"),__vite__mapDeps([]))),"v-2a1b3d72":h(()=>s(()=>import("./trojan.html-6FO_V9lu.js"),__vite__mapDeps([]))),"v-fb92e8aa":h(()=>s(()=>import("./vless.html-D5OyDM4i.js"),__vite__mapDeps([]))),"v-167afaac":h(()=>s(()=>import("./vmess.html-uLwk-fUW.js"),__vite__mapDeps([]))),"v-5588d0cc":h(()=>s(()=>import("./wireguard.html-C7zjxZ_o.js"),__vite__mapDeps([]))),"v-749ad71a":h(()=>s(()=>import("./blackhole.html-BwT5tNQJ.js"),__vite__mapDeps([]))),"v-6d39b970":h(()=>s(()=>import("./dns.html-pLhH-MPA.js"),__vite__mapDeps([]))),"v-d76e893a":h(()=>s(()=>import("./freedom.html-DJ9fcQEp.js"),__vite__mapDeps([]))),"v-c6b4b59e":h(()=>s(()=>import("./http.html-DgkiVHJm.js"),__vite__mapDeps([]))),"v-41ec0e0e":h(()=>s(()=>import("./loopback.html-_BhTQZ0O.js"),__vite__mapDeps([]))),"v-7b293e4a":h(()=>s(()=>import("./shadowsocks.html-DTzQHKas.js"),__vite__mapDeps([]))),"v-15f5452a":h(()=>s(()=>import("./socks.html-Bo00BDL8.js"),__vite__mapDeps([]))),"v-5797bdb3":h(()=>s(()=>import("./trojan.html-2IKlUogk.js"),__vite__mapDeps([]))),"v-a60f016c":h(()=>s(()=>import("./vless.html-CVgOe_Ra.js"),__vite__mapDeps([]))),"v-413cee4b":h(()=>s(()=>import("./vmess.html-ILF_tpZ9.js"),__vite__mapDeps([]))),"v-208ca3b9":h(()=>s(()=>import("./wireguard.html-BRdIxC_E.js"),__vite__mapDeps([]))),"v-2877542a":h(()=>s(()=>import("./grpc.html-3Z809VPJ.js"),__vite__mapDeps([]))),"v-03a28284":h(()=>s(()=>import("./h2.html-xtI0nSPz.js"),__vite__mapDeps([]))),"v-04158536":h(()=>s(()=>import("./httpupgrade.html-DBZL0AAW.js"),__vite__mapDeps([]))),"v-3167b1dd":h(()=>s(()=>import("./mkcp.html-C_htobT5.js"),__vite__mapDeps([]))),"v-eeea2fb0":h(()=>s(()=>import("./splithttp.html-Dz9QMH4-.js"),__vite__mapDeps([]))),"v-33b1b709":h(()=>s(()=>import("./tcp.html-D_ggphrp.js"),__vite__mapDeps([]))),"v-1ff57bba":h(()=>s(()=>import("./websocket.html-MgdanL8C.js"),__vite__mapDeps([]))),"v-3f09dcfa":h(()=>s(()=>import("./index.html-BvSm0ea0.js"),__vite__mapDeps([]))),"v-fb444906":h(()=>s(()=>import("./ch01-preface.html-Rzsgtj_M.js"),__vite__mapDeps([]))),"v-075f3ae5":h(()=>s(()=>import("./ch02-preparation.html-B3KTTdXe.js"),__vite__mapDeps([]))),"v-726d0633":h(()=>s(()=>import("./ch03-ssh.html-D4Fp2rOo.js"),__vite__mapDeps([]))),"v-430c6ab8":h(()=>s(()=>import("./ch04-security.html-BmDPDZZi.js"),__vite__mapDeps([]))),"v-717c6376":h(()=>s(()=>import("./ch05-webpage.html-d_ZCA_oR.js"),__vite__mapDeps([]))),"v-278039be":h(()=>s(()=>import("./ch06-certificates.html-Dwdk6ToP.js"),__vite__mapDeps([]))),"v-a0c7f88e":h(()=>s(()=>import("./ch07-xray-server.html-o9DNRP9E.js"),__vite__mapDeps([]))),"v-86586ca2":h(()=>s(()=>import("./ch08-xray-clients.html-BACa2yr0.js"),__vite__mapDeps([]))),"v-3eb62514":h(()=>s(()=>import("./ch09-appendix.html-DH1J1Cus.js"),__vite__mapDeps([]))),"v-3f09dcbc":h(()=>s(()=>import("./index.html-DD2Y-q71.js"),__vite__mapDeps([]))),"v-b21a2a20":h(()=>s(()=>import("./fallbacks-lv1.html-Dfkic9nm.js"),__vite__mapDeps([]))),"v-da623318":h(()=>s(()=>import("./fallbacks-with-sni.html-2lm7wLPL.js"),__vite__mapDeps([]))),"v-fdd722ac":h(()=>s(()=>import("./routing-lv1-part1.html-CM6bRG4P.js"),__vite__mapDeps([]))),"v-fa6d716e":h(()=>s(()=>import("./routing-lv1-part2.html-C6Xae5-1.js"),__vite__mapDeps([]))),"v-2f29e106":h(()=>s(()=>import("./work.html-SMvM6VpF.js"),__vite__mapDeps([]))),"v-3f09dc7e":h(()=>s(()=>import("./index.html-Nkob2LGl.js"),__vite__mapDeps([]))),"v-1c17916e":h(()=>s(()=>import("./iptables_gid.html-CszhZSj9.js"),__vite__mapDeps([]))),"v-a001cfa6":h(()=>s(()=>import("./nginx_or_haproxy_tls_tunnel.html-DkUD4xx5.js"),__vite__mapDeps([]))),"v-46333b48":h(()=>s(()=>import("./redirect.html-CZZO3MVR.js"),__vite__mapDeps([]))),"v-338bc63e":h(()=>s(()=>import("./tproxy.html-D5vAMDfU.js"),__vite__mapDeps([]))),"v-d68f7d58":h(()=>s(()=>import("./tproxy_ipv4_and_ipv6.html-CI5U13dZ.js"),__vite__mapDeps([]))),"v-e533e2c6":h(()=>s(()=>import("./traffic_stats.html-BvcqGaeo.js"),__vite__mapDeps([]))),"v-1e465ab0":h(()=>s(()=>import("./warp.html-B33XWZbi.js"),__vite__mapDeps([]))),"v-1080fb37":h(()=>s(()=>import("./news.html-AUkvoQ5N.js"),__vite__mapDeps([]))),"v-317fc580":h(()=>s(()=>import("./index.html-BYuUObTq.js"),__vite__mapDeps([]))),"v-45144c7f":h(()=>s(()=>import("./api.html-BIbKaUtc.js"),__vite__mapDeps([]))),"v-23fbd2d0":h(()=>s(()=>import("./dns.html-BZs6b75V.js"),__vite__mapDeps([]))),"v-2b7ec525":h(()=>s(()=>import("./fakedns.html-BQH6Y2PN.js"),__vite__mapDeps([]))),"v-5ab92300":h(()=>s(()=>import("./inbound.html-BPQMtrP7.js"),__vite__mapDeps([]))),"v-f91d64d6":h(()=>s(()=>import("./log.html-CA6mG-aB.js"),__vite__mapDeps([]))),"v-d705f114":h(()=>s(()=>import("./metrics.html-Bf2B_O2D.js"),__vite__mapDeps([]))),"v-5c8e777f":h(()=>s(()=>import("./observatory.html-BbQKQJhA.js"),__vite__mapDeps([]))),"v-268cd669":h(()=>s(()=>import("./outbound.html-CpUBTknQ.js"),__vite__mapDeps([]))),"v-4492d567":h(()=>s(()=>import("./policy.html-BALvOnk-.js"),__vite__mapDeps([]))),"v-0d0e1e92":h(()=>s(()=>import("./reverse.html-BNoHKOBx.js"),__vite__mapDeps([]))),"v-4bbe1d5a":h(()=>s(()=>import("./routing.html-xbGVqnxN.js"),__vite__mapDeps([]))),"v-16426d1a":h(()=>s(()=>import("./stats.html-j3PBvFA5.js"),__vite__mapDeps([]))),"v-5de780d0":h(()=>s(()=>import("./transport.html-CoXY-KCW.js"),__vite__mapDeps([]))),"v-f88d343e":h(()=>s(()=>import("./index.html-Ba-V9K2O.js"),__vite__mapDeps([]))),"v-38d56a07":h(()=>s(()=>import("./index.html-BS27sHaP.js"),__vite__mapDeps([]))),"v-4d046016":h(()=>s(()=>import("./command.html-CrJVUr4J.js"),__vite__mapDeps([]))),"v-22b35270":h(()=>s(()=>import("./config.html-P39U8JiI.js"),__vite__mapDeps([]))),"v-30bd7c12":h(()=>s(()=>import("./document.html-C8cPqOIW.js"),__vite__mapDeps([]))),"v-439608b6":h(()=>s(()=>import("./install.html-CdOf2M5I.js"),__vite__mapDeps([]))),"v-408e88d1":h(()=>s(()=>import("./news.html-UWoLxj1_.js"),__vite__mapDeps([]))),"v-b1cce5cc":h(()=>s(()=>import("./index.html-DcKrVYG-.js"),__vite__mapDeps([]))),"v-7521da19":h(()=>s(()=>import("./api.html-BSTC8zd0.js"),__vite__mapDeps([]))),"v-5409606a":h(()=>s(()=>import("./dns.html-C9qEefIG.js"),__vite__mapDeps([]))),"v-5877f5bf":h(()=>s(()=>import("./fakedns.html-xFYf-feg.js"),__vite__mapDeps([]))),"v-00c6c1cc":h(()=>s(()=>import("./inbound.html-B_YBnicn.js"),__vite__mapDeps([]))),"v-990249a2":h(()=>s(()=>import("./log.html-CWv0qLIE.js"),__vite__mapDeps([]))),"v-7d138fe0":h(()=>s(()=>import("./metrics.html-BT-2HBU5.js"),__vite__mapDeps([]))),"v-11e9cb19":h(()=>s(()=>import("./observatory.html-Bqwm-FiF.js"),__vite__mapDeps([]))),"v-ce8c8de2":h(()=>s(()=>import("./outbound.html-B5z5DraB.js"),__vite__mapDeps([]))),"v-3dc4298d":h(()=>s(()=>import("./policy.html-B5iTeN8-.js"),__vite__mapDeps([]))),"v-26722151":h(()=>s(()=>import("./reverse.html-DLWtaE_H.js"),__vite__mapDeps([]))),"v-071a21ed":h(()=>s(()=>import("./routing.html-JmIqwiJt.js"),__vite__mapDeps([]))),"v-7922fc34":h(()=>s(()=>import("./stats.html-Bop9jH-f.js"),__vite__mapDeps([]))),"v-3156f2ea":h(()=>s(()=>import("./transport.html-8xgD8RRD.js"),__vite__mapDeps([]))),"v-40ee4e87":h(()=>s(()=>import("./index.html-BZQpQc5L.js"),__vite__mapDeps([]))),"v-a1c899be":h(()=>s(()=>import("./index.html-Cl2CfXNF.js"),__vite__mapDeps([]))),"v-a6257be2":h(()=>s(()=>import("./command.html-mB_BYdZd.js"),__vite__mapDeps([]))),"v-d63f95d4":h(()=>s(()=>import("./config.html-DmHh-Zu1.js"),__vite__mapDeps([]))),"v-fbbfd9c6":h(()=>s(()=>import("./document.html-BU1vIcEy.js"),__vite__mapDeps([]))),"v-9cb72482":h(()=>s(()=>import("./install.html-BGuTjt8M.js"),__vite__mapDeps([]))),"v-51a51d87":h(()=>s(()=>import("./transparent_proxy.html-CUyvRv2I.js"),__vite__mapDeps([]))),"v-76b9a0f3":h(()=>s(()=>import("./browser_dialer.html-BcXJ4Ezq.js"),__vite__mapDeps([]))),"v-565dbfc4":h(()=>s(()=>import("./env.html-0B8aFJq0.js"),__vite__mapDeps([]))),"v-0fbd1336":h(()=>s(()=>import("./fallback.html-DHH-5c7i.js"),__vite__mapDeps([]))),"v-a0627812":h(()=>s(()=>import("./multiple.html-DUUJue4s.js"),__vite__mapDeps([]))),"v-d190d938":h(()=>s(()=>import("./xtls.html-C840N25V.js"),__vite__mapDeps([]))),"v-72afc2d2":h(()=>s(()=>import("./dokodemo.html-B1Zv0rHv.js"),__vite__mapDeps([]))),"v-773d731c":h(()=>s(()=>import("./http.html-DSD926Zv.js"),__vite__mapDeps([]))),"v-f555fc02":h(()=>s(()=>import("./shadowsocks.html-4Bp3Pe-I.js"),__vite__mapDeps([]))),"v-e35196c2":h(()=>s(()=>import("./socks.html-4M7JIsdb.js"),__vite__mapDeps([]))),"v-29188644":h(()=>s(()=>import("./trojan.html-1FTyRSM5.js"),__vite__mapDeps([]))),"v-255a6ebf":h(()=>s(()=>import("./vless.html-DH2x8Lsm.js"),__vite__mapDeps([]))),"v-8cc24480":h(()=>s(()=>import("./vmess.html-BQ6qtjqJ.js"),__vite__mapDeps([]))),"v-a2605ea4":h(()=>s(()=>import("./wireguard.html--TSe5kNc.js"),__vite__mapDeps([]))),"v-64e47ef4":h(()=>s(()=>import("./blackhole.html-Nc1ubt3S.js"),__vite__mapDeps([]))),"v-e979b848":h(()=>s(()=>import("./dns.html-BqlRMu7q.js"),__vite__mapDeps([]))),"v-617f0fcf":h(()=>s(()=>import("./freedom.html-Bxk1yqEk.js"),__vite__mapDeps([]))),"v-3fc98845":h(()=>s(()=>import("./http.html-Cv9NIFOF.js"),__vite__mapDeps([]))),"v-1b804722":h(()=>s(()=>import("./loopback.html-CyxLLiRu.js"),__vite__mapDeps([]))),"v-63077cb6":h(()=>s(()=>import("./shadowsocks.html-CDcJbYW-.js"),__vite__mapDeps([]))),"v-516476d4":h(()=>s(()=>import("./socks.html-COrUwqQj.js"),__vite__mapDeps([]))),"v-7d61a872":h(()=>s(()=>import("./trojan.html-UWktEtCO.js"),__vite__mapDeps([]))),"v-6e50feb6":h(()=>s(()=>import("./vless.html-CvVYC0xa.js"),__vite__mapDeps([]))),"v-02956db7":h(()=>s(()=>import("./vmess.html-D8fkP4-1.js"),__vite__mapDeps([]))),"v-797f8d25":h(()=>s(()=>import("./wireguard.html-AcuxmEqH.js"),__vite__mapDeps([]))),"v-2c6058d4":h(()=>s(()=>import("./grpc.html-3jmQQAel.js"),__vite__mapDeps([]))),"v-1c38292a":h(()=>s(()=>import("./h2.html-C9hnsppv.js"),__vite__mapDeps([]))),"v-17ff144a":h(()=>s(()=>import("./httpupgrade.html-mAe7j4MC.js"),__vite__mapDeps([]))),"v-1a7f9d6e":h(()=>s(()=>import("./mkcp.html-CL2dbaXb.js"),__vite__mapDeps([]))),"v-4df52c3c":h(()=>s(()=>import("./splithttp.html-Ewo4WhOB.js"),__vite__mapDeps([]))),"v-5254cbc6":h(()=>s(()=>import("./tcp.html-D3RB1Z2i.js"),__vite__mapDeps([]))),"v-9520f392":h(()=>s(()=>import("./websocket.html-BZsgtVoW.js"),__vite__mapDeps([]))),"v-b7760e2c":h(()=>s(()=>import("./compile.html-B9Zh6vRY.js"),__vite__mapDeps([]))),"v-fb774212":h(()=>s(()=>import("./design.html-CLTK1zJY.js"),__vite__mapDeps([]))),"v-38c376c1":h(()=>s(()=>import("./guide.html-DwQuBDQN.js"),__vite__mapDeps([]))),"v-21bccd79":h(()=>s(()=>import("./mkcp.html-ZQWAw5BE.js"),__vite__mapDeps([]))),"v-27001935":h(()=>s(()=>import("./muxcool.html-DJdC30Uv.js"),__vite__mapDeps([]))),"v-21b30c3f":h(()=>s(()=>import("./vless.html-BlWWjzcK.js"),__vite__mapDeps([]))),"v-94110980":h(()=>s(()=>import("./vmess.html-9ma69iWT.js"),__vite__mapDeps([]))),"v-789ba7ef":h(()=>s(()=>import("./index.html-BiUJ4Vho.js"),__vite__mapDeps([]))),"v-d3712ade":h(()=>s(()=>import("./ch01-preface.html-CFrG0T3Z.js"),__vite__mapDeps([]))),"v-41f9c00e":h(()=>s(()=>import("./ch02-preparation.html-CpQikq-R.js"),__vite__mapDeps([]))),"v-4c013f47":h(()=>s(()=>import("./ch03-ssh.html-GVNNjQoi.js"),__vite__mapDeps([]))),"v-a75683b8":h(()=>s(()=>import("./ch04-security.html-C34Buqpd.js"),__vite__mapDeps([]))),"v-f5341aec":h(()=>s(()=>import("./ch05-webpage.html-CE51MwWG.js"),__vite__mapDeps([]))),"v-4458f72a":h(()=>s(()=>import("./ch06-certificates.html-bt0w3WX5.js"),__vite__mapDeps([]))),"v-f1802e66":h(()=>s(()=>import("./ch07-xray-server.html-BpVDHJdR.js"),__vite__mapDeps([]))),"v-4ca6f1ca":h(()=>s(()=>import("./ch08-xray-clients.html-BPrKhFMK.js"),__vite__mapDeps([]))),"v-b0030f00":h(()=>s(()=>import("./ch09-appendix.html-DQ43Ovyc.js"),__vite__mapDeps([]))),"v-789ba80e":h(()=>s(()=>import("./index.html-BYpCGpl_.js"),__vite__mapDeps([]))),"v-103b3e5c":h(()=>s(()=>import("./fallbacks-lv1.html-D0PORcDs.js"),__vite__mapDeps([]))),"v-110dd688":h(()=>s(()=>import("./fallbacks-with-sni.html-Qo7kexlI.js"),__vite__mapDeps([]))),"v-c425a7d4":h(()=>s(()=>import("./routing-lv1-part1.html-DXlYZzcq.js"),__vite__mapDeps([]))),"v-c0bbf696":h(()=>s(()=>import("./routing-lv1-part2.html-D9GASUUF.js"),__vite__mapDeps([]))),"v-5b6477cc":h(()=>s(()=>import("./work.html-DS7NfRpF.js"),__vite__mapDeps([]))),"v-789ba82d":h(()=>s(()=>import("./index.html-qOpCoWzE.js"),__vite__mapDeps([]))),"v-05ddc65d":h(()=>s(()=>import("./iptables_gid.html-BaYh0Fhk.js"),__vite__mapDeps([]))),"v-474afe99":h(()=>s(()=>import("./nginx_or_haproxy_tls_tunnel.html-DOANhXpE.js"),__vite__mapDeps([]))),"v-930ac920":h(()=>s(()=>import("./redirect.html-C39Qzzo5.js"),__vite__mapDeps([]))),"v-c579975c":h(()=>s(()=>import("./tproxy.html-DOLwYTgg.js"),__vite__mapDeps([]))),"v-7efb7c68":h(()=>s(()=>import("./tproxy_ipv4_and_ipv6.html-875AR2Id.js"),__vite__mapDeps([]))),"v-12a33bee":h(()=>s(()=>import("./traffic_stats.html--hyCQe7p.js"),__vite__mapDeps([]))),"v-7d2b8478":h(()=>s(()=>import("./warp.html-BFiya00c.js"),__vite__mapDeps([]))),"v-1cfb44e6":h(()=>s(()=>import("./browser_dialer.html-bGDmhYds.js"),__vite__mapDeps([]))),"v-6a3f8078":h(()=>s(()=>import("./env.html-CnZRKI06.js"),__vite__mapDeps([]))),"v-74f22e7f":h(()=>s(()=>import("./fallback.html-BrxCKulv.js"),__vite__mapDeps([]))),"v-2c9f7c11":h(()=>s(()=>import("./multiple.html-Bjf8GHFS.js"),__vite__mapDeps([]))),"v-630c687e":h(()=>s(()=>import("./xtls.html-BK7C9n7n.js"),__vite__mapDeps([]))),"v-20ff0a28":h(()=>s(()=>import("./dokodemo.html-LpEbF-JC.js"),__vite__mapDeps([]))),"v-43124836":h(()=>s(()=>import("./http.html-Do070lJz.js"),__vite__mapDeps([]))),"v-6a351ba5":h(()=>s(()=>import("./shadowsocks.html-k_BIRk0d.js"),__vite__mapDeps([]))),"v-3d1d02c5":h(()=>s(()=>import("./socks.html-CMWA8dIs.js"),__vite__mapDeps([]))),"v-1567b378":h(()=>s(()=>import("./trojan.html-BuFAAu0c.js"),__vite__mapDeps([]))),"v-57bf8636":h(()=>s(()=>import("./vless.html-DAk5toqP.js"),__vite__mapDeps([]))),"v-6864abe6":h(()=>s(()=>import("./vmess.html-BR7lDLGa.js"),__vite__mapDeps([]))),"v-67d3c858":h(()=>s(()=>import("./wireguard.html-D8U2MJad.js"),__vite__mapDeps([]))),"v-5910da20":h(()=>s(()=>import("./blackhole.html-C9mvdUl-.js"),__vite__mapDeps([]))),"v-5717f8f6":h(()=>s(()=>import("./dns.html-B4w4YpWq.js"),__vite__mapDeps([]))),"v-4360702e":h(()=>s(()=>import("./freedom.html--UBGeVII.js"),__vite__mapDeps([]))),"v-22e1532a":h(()=>s(()=>import("./http.html-DKb1_aBq.js"),__vite__mapDeps([]))),"v-38c69248":h(()=>s(()=>import("./loopback.html-EJfWzfAq.js"),__vite__mapDeps([]))),"v-1a2a97d0":h(()=>s(()=>import("./shadowsocks.html-IdnyE_QW.js"),__vite__mapDeps([]))),"v-0141bb30":h(()=>s(()=>import("./socks.html-DN04JS2D.js"),__vite__mapDeps([]))),"v-544bef26":h(()=>s(()=>import("./trojan.html-WioOgQKT.js"),__vite__mapDeps([]))),"v-cf761560":h(()=>s(()=>import("./vless.html-jHwTWi4h.js"),__vite__mapDeps([]))),"v-2c896451":h(()=>s(()=>import("./vmess.html-Bgid-6Wa.js"),__vite__mapDeps([]))),"v-0502a6bf":h(()=>s(()=>import("./wireguard.html-Da2wnVY_.js"),__vite__mapDeps([]))),"v-13c3ca30":h(()=>s(()=>import("./grpc.html-Dw2s9Pxy.js"),__vite__mapDeps([]))),"v-2fe60378":h(()=>s(()=>import("./h2.html-DH2CM7PJ.js"),__vite__mapDeps([]))),"v-453f5c70":h(()=>s(()=>import("./httpupgrade.html-DCnMDttv.js"),__vite__mapDeps([]))),"v-1cb427e3":h(()=>s(()=>import("./mkcp.html-OQhbYtWS.js"),__vite__mapDeps([]))),"v-32d545e2":h(()=>s(()=>import("./splithttp.html-Bu9SdRS8.js"),__vite__mapDeps([]))),"v-f4c92f7a":h(()=>s(()=>import("./tcp.html-MnZXrAQL.js"),__vite__mapDeps([]))),"v-cb60c046":h(()=>s(()=>import("./websocket.html-D2_1H1Lb.js"),__vite__mapDeps([]))),"v-7ce977e0":h(()=>s(()=>import("./compile.html-ZO7e59Ko.js"),__vite__mapDeps([]))),"v-01d5d1de":h(()=>s(()=>import("./design.html-Tm1rZHD2.js"),__vite__mapDeps([]))),"v-4d4e5367":h(()=>s(()=>import("./guide.html-CzsX8pED.js"),__vite__mapDeps([]))),"v-a58031da":h(()=>s(()=>import("./mkcp.html-BmeTqtsZ.js"),__vite__mapDeps([]))),"v-5440615b":h(()=>s(()=>import("./muxcool.html-DuGDfdPl.js"),__vite__mapDeps([]))),"v-069325e5":h(()=>s(()=>import("./vless.html-Bfk9b9AR.js"),__vite__mapDeps([]))),"v-ca50d634":h(()=>s(()=>import("./vmess.html-CxHRDmLK.js"),__vite__mapDeps([]))),"v-490791ee":h(()=>s(()=>import("./index.html-BBL6nyUH.js"),__vite__mapDeps([]))),"v-78f09a92":h(()=>s(()=>import("./ch01-preface.html-BQg5DEiN.js"),__vite__mapDeps([]))),"v-64f6e51f":h(()=>s(()=>import("./ch02-preparation.html-DaAKcAJL.js"),__vite__mapDeps([]))),"v-69478a6d":h(()=>s(()=>import("./ch03-ssh.html-C-e-7t3_.js"),__vite__mapDeps([]))),"v-271d7abe":h(()=>s(()=>import("./ch04-security.html-UQusRUO6.js"),__vite__mapDeps([]))),"v-9ab38aa0":h(()=>s(()=>import("./ch05-webpage.html-DzMKIlk9.js"),__vite__mapDeps([]))),"v-7cddd6c4":h(()=>s(()=>import("./ch06-certificates.html-BTgSQmX4.js"),__vite__mapDeps([]))),"v-0d33adf3":h(()=>s(()=>import("./ch07-xray-server.html-BDc78tiF.js"),__vite__mapDeps([]))),"v-123166b5":h(()=>s(()=>import("./ch08-xray-clients.html-D5SRFBa5.js"),__vite__mapDeps([]))),"v-22c7351a":h(()=>s(()=>import("./ch09-appendix.html-Bek16BV4.js"),__vite__mapDeps([]))),"v-490791b0":h(()=>s(()=>import("./index.html-EU8APivD.js"),__vite__mapDeps([]))),"v-e9f80a14":h(()=>s(()=>import("./fallbacks-lv1.html-BWGggl2y.js"),__vite__mapDeps([]))),"v-2db62ba4":h(()=>s(()=>import("./fallbacks-with-sni.html-wlH1uh5I.js"),__vite__mapDeps([]))),"v-531be8a0":h(()=>s(()=>import("./routing-lv1-part1.html-lS-Lwun1.js"),__vite__mapDeps([]))),"v-4fb23762":h(()=>s(()=>import("./routing-lv1-part2.html-iX-deabM.js"),__vite__mapDeps([]))),"v-fdd8db80":h(()=>s(()=>import("./work.html-CmnVL4Vh.js"),__vite__mapDeps([]))),"v-49079172":h(()=>s(()=>import("./index.html-D_B2zS6C.js"),__vite__mapDeps([]))),"v-331e0e83":h(()=>s(()=>import("./iptables_gid.html-CNg7E9Pm.js"),__vite__mapDeps([]))),"v-7418a5b3":h(()=>s(()=>import("./nginx_or_haproxy_tls_tunnel.html-CMszb--u.js"),__vite__mapDeps([]))),"v-587e32d4":h(()=>s(()=>import("./redirect.html-DToMsmqC.js"),__vite__mapDeps([]))),"v-9c63de10":h(()=>s(()=>import("./tproxy.html-2EI4CZc5.js"),__vite__mapDeps([]))),"v-a4c782e4":h(()=>s(()=>import("./tproxy_ipv4_and_ipv6.html-LFerpS1d.js"),__vite__mapDeps([]))),"v-71771ea3":h(()=>s(()=>import("./traffic_stats.html-mKRKbS-b.js"),__vite__mapDeps([]))),"v-70300bea":h(()=>s(()=>import("./warp.html-DjzUs3nN.js"),__vite__mapDeps([]))),"v-7689d7f3":h(()=>s(()=>import("./transparent_proxy.html-D_505nHB.js"),__vite__mapDeps([]))),"v-39b3c50d":h(()=>s(()=>import("./transparent_proxy.html-CN6RzNfw.js"),__vite__mapDeps([]))),"v-3706649a":h(()=>s(()=>import("./404.html-BZTO9xBK.js"),__vite__mapDeps([])))};var Hu=Symbol(""),ms=Symbol(""),Mu=Ri({key:"",path:"",title:"",lang:"",frontmatter:{},headers:[]}),Gt=()=>{const e=Te(ms);if(!e)throw new Error("pageData() is called without provider.");return e},bs=Symbol(""),pt=()=>{const e=Te(bs);if(!e)throw new Error("usePageFrontmatter() is called without provider.");return e},ks=Symbol(""),$u=()=>{const e=Te(ks);if(!e)throw new Error("usePageHead() is called without provider.");return e},Bu=Symbol(""),Es=Symbol(""),Wu=()=>{const e=Te(Es);if(!e)throw new Error("usePageLang() is called without provider.");return e},ys=Symbol(""),zu=()=>{const e=Te(ys);if(!e)throw new Error("usePageLayout() is called without provider.");return e},Uu=ge(Iu),Mn=Symbol(""),Jl=()=>{const e=Te(Mn);if(!e)throw new Error("useRouteLocale() is called without provider.");return e},ll=ge(Du),xs=()=>ll,Ls=Symbol(""),$n=()=>{const e=Te(Ls);if(!e)throw new Error("useSiteLocaleData() is called without provider.");return e},Xu=Symbol(""),Ku="Layout",qu="NotFound",vt=zl({resolveLayouts:e=>e.reduce((t,l)=>({...t,...l.layouts}),{}),resolvePageData:async e=>{const t=Uu.value[e];return await(t==null?void 0:t())??Mu},resolvePageFrontmatter:e=>e.frontmatter,resolvePageHead:(e,t,l)=>{const i=nt(t.description)?t.description:l.description,n=[...Array.isArray(t.head)?t.head:[],...l.head,["title",{},e],["meta",{name:"description",content:i}]];return Vu(n)},resolvePageHeadTitle:(e,t)=>[e.title,t.title].filter(l=>!!l).join(" | "),resolvePageLang:(e,t)=>e.lang||t.lang||"en-US",resolvePageLayout:(e,t)=>{let l;if(e.path){const i=e.frontmatter.layout;nt(i)?l=i:l=Ku}else l=qu;return t[l]},resolveRouteLocale:(e,t)=>gs(e,t),resolveSiteLocaleData:(e,t)=>{var l;return{...e,...e.locales[t],head:[...((l=e.locales[t])==null?void 0:l.head)??[],...e.head??[]]}}}),Bn=_e({name:"ClientOnly",setup(e,t){const l=ge(!1);return We(()=>{l.value=!0}),()=>{var i,n;return l.value?(n=(i=t.slots).default)==null?void 0:n.call(i):null}}}),Gu=_e({name:"Content",props:{pageKey:{type:String,required:!1,default:""}},setup(e){const t=Gt(),l=C(()=>ps[e.pageKey||t.value.key]);return()=>l.value?he(l.value):he("div","404 Not Found")}}),Et=(e={})=>e,Wn=e=>Yl(e)?e:`/${fs(e)}`;function Ts(e,t,l){var i,n,r;t===void 0&&(t=50),l===void 0&&(l={});var o=(i=l.isImmediate)!=null&&i,c=(n=l.callback)!=null&&n,a=l.maxWait,u=Date.now(),d=[];function v(){if(a!==void 0){var p=Date.now()-u;if(p+t>=a)return a-p}return t}var _=function(){var p=[].slice.call(arguments),m=this;return new Promise(function(x,A){var D=o&&r===void 0;if(r!==void 0&&clearTimeout(r),r=setTimeout(function(){if(r=void 0,u=Date.now(),!o){var b=e.apply(m,p);c&&c(b),d.forEach(function(y){return(0,y.resolve)(b)}),d=[]}},v()),D){var O=e.apply(m,p);return c&&c(O),x(O)}d.push({resolve:x,reject:A})})};return _.cancel=function(p){r!==void 0&&clearTimeout(r),d.forEach(function(m){return(0,m.reject)(p)}),d=[]},_}/*!
+function bn(e,t){const l=Object.create(null),i=e.split(",");for(let n=0;n!!l[n]}const ye={},il=[],ut=()=>{},ec=()=>!1,Bl=e=>e.charCodeAt(0)===111&&e.charCodeAt(1)===110&&(e.charCodeAt(2)>122||e.charCodeAt(2)<97),kn=e=>e.startsWith("onUpdate:"),Ie=Object.assign,En=(e,t)=>{const l=e.indexOf(t);l>-1&&e.splice(l,1)},tc=Object.prototype.hasOwnProperty,de=(e,t)=>tc.call(e,t),te=Array.isArray,nl=e=>Oi(e)==="[object Map]",mo=e=>Oi(e)==="[object Set]",oe=e=>typeof e=="function",we=e=>typeof e=="string",fl=e=>typeof e=="symbol",Ee=e=>e!==null&&typeof e=="object",bo=e=>(Ee(e)||oe(e))&&oe(e.then)&&oe(e.catch),ko=Object.prototype.toString,Oi=e=>ko.call(e),lc=e=>Oi(e).slice(8,-1),Eo=e=>Oi(e)==="[object Object]",yn=e=>we(e)&&e!=="NaN"&&e[0]!=="-"&&""+parseInt(e,10)===e,Al=bn(",key,ref,ref_for,ref_key,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted"),Pi=e=>{const t=Object.create(null);return l=>t[l]||(t[l]=e(l))},ic=/-(\w)/g,dt=Pi(e=>e.replace(ic,(t,l)=>l?l.toUpperCase():"")),nc=/\B([A-Z])/g,Jt=Pi(e=>e.replace(nc,"-$1").toLowerCase()),Ai=Pi(e=>e.charAt(0).toUpperCase()+e.slice(1)),Mi=Pi(e=>e?`on${Ai(e)}`:""),Yt=(e,t)=>!Object.is(e,t),$i=(e,t)=>{for(let l=0;l{Object.defineProperty(e,t,{configurable:!0,enumerable:!1,value:l})},rc=e=>{const t=parseFloat(e);return isNaN(t)?e:t},oc=e=>{const t=we(e)?Number(e):NaN;return isNaN(t)?e:t};let tr;const ln=()=>tr||(tr=typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:typeof global<"u"?global:{});function Wl(e){if(te(e)){const t={};for(let l=0;l{if(l){const i=l.split(cc);i.length>1&&(t[i[0].trim()]=i[1].trim())}}),t}function $e(e){let t="";if(we(e))t=e;else if(te(e))for(let l=0;lwe(e)?e:e==null?"":te(e)||Ee(e)&&(e.toString===ko||!oe(e.toString))?JSON.stringify(e,xo,2):String(e),xo=(e,t)=>t&&t.__v_isRef?xo(e,t.value):nl(t)?{[`Map(${t.size})`]:[...t.entries()].reduce((l,[i,n],r)=>(l[Bi(i,r)+" =>"]=n,l),{})}:mo(t)?{[`Set(${t.size})`]:[...t.values()].map(l=>Bi(l))}:fl(t)?Bi(t):Ee(t)&&!te(t)&&!Eo(t)?String(t):t,Bi=(e,t="")=>{var l;return fl(e)?`Symbol(${(l=e.description)!=null?l:t})`:e};let qe;class vc{constructor(t=!1){this.detached=t,this._active=!0,this.effects=[],this.cleanups=[],this.parent=qe,!t&&qe&&(this.index=(qe.scopes||(qe.scopes=[])).push(this)-1)}get active(){return this._active}run(t){if(this._active){const l=qe;try{return qe=this,t()}finally{qe=l}}}on(){qe=this}off(){qe=this.parent}stop(t){if(this._active){let l,i;for(l=0,i=this.effects.length;l{const t=new Set(e);return t.w=0,t.n=0,t},To=e=>(e.w&jt)>0,Oo=e=>(e.n&jt)>0,gc=({deps:e})=>{if(e.length)for(let t=0;t{const{deps:t}=e;if(t.length){let l=0;for(let i=0;i{(d==="length"||!fl(d)&&d>=a)&&c.push(u)})}else switch(l!==void 0&&c.push(o.get(l)),t){case"add":te(e)?yn(l)&&c.push(o.get("length")):(c.push(o.get(Ut)),nl(e)&&c.push(o.get(rn)));break;case"delete":te(e)||(c.push(o.get(Ut)),nl(e)&&c.push(o.get(rn)));break;case"set":nl(e)&&c.push(o.get(Ut));break}if(c.length===1)c[0]&&on(c[0]);else{const a=[];for(const u of c)u&&a.push(...u);on(xn(a))}}function on(e,t){const l=te(e)?e:[...e];for(const i of l)i.computed&&ir(i);for(const i of l)i.computed||ir(i)}function ir(e,t){(e!==lt||e.allowRecurse)&&(e.scheduler?e.scheduler():e.run())}function mc(e,t){var l;return(l=fi.get(e))==null?void 0:l.get(t)}const bc=bn("__proto__,__v_isRef,__isVue"),wo=new Set(Object.getOwnPropertyNames(Symbol).filter(e=>e!=="arguments"&&e!=="caller").map(e=>Symbol[e]).filter(fl)),nr=kc();function kc(){const e={};return["includes","indexOf","lastIndexOf"].forEach(t=>{e[t]=function(...l){const i=ve(this);for(let r=0,o=this.length;r{e[t]=function(...l){gl();const i=ve(this)[t].apply(this,l);return pl(),i}}),e}function Ec(e){const t=ve(this);return Xe(t,"has",e),t.hasOwnProperty(e)}class Ro{constructor(t=!1,l=!1){this._isReadonly=t,this._shallow=l}get(t,l,i){const n=this._isReadonly,r=this._shallow;if(l==="__v_isReactive")return!n;if(l==="__v_isReadonly")return n;if(l==="__v_isShallow")return r;if(l==="__v_raw")return i===(n?r?Sc:So:r?jo:Do).get(t)||Object.getPrototypeOf(t)===Object.getPrototypeOf(i)?t:void 0;const o=te(t);if(!n){if(o&&de(nr,l))return Reflect.get(nr,l,i);if(l==="hasOwnProperty")return Ec}const c=Reflect.get(t,l,i);return(fl(l)?wo.has(l):bc(l))||(n||Xe(t,"get",l),r)?c:Ne(c)?o&&yn(l)?c:c.value:Ee(c)?n?Ri(c):zl(c):c}}class Io extends Ro{constructor(t=!1){super(!1,t)}set(t,l,i,n){let r=t[l];if(!this._shallow){const a=cl(r);if(!gi(i)&&!cl(i)&&(r=ve(r),i=ve(i)),!te(t)&&Ne(r)&&!Ne(i))return a?!1:(r.value=i,!0)}const o=te(t)&&yn(l)?Number(l)e,wi=e=>Reflect.getPrototypeOf(e);function Ql(e,t,l=!1,i=!1){e=e.__v_raw;const n=ve(e),r=ve(t);l||(Yt(t,r)&&Xe(n,"get",t),Xe(n,"get",r));const{has:o}=wi(n),c=i?Tn:l?An:Sl;if(o.call(n,t))return c(e.get(t));if(o.call(n,r))return c(e.get(r));e!==n&&e.get(t)}function Zl(e,t=!1){const l=this.__v_raw,i=ve(l),n=ve(e);return t||(Yt(e,n)&&Xe(i,"has",e),Xe(i,"has",n)),e===n?l.has(e):l.has(e)||l.has(n)}function ei(e,t=!1){return e=e.__v_raw,!t&&Xe(ve(e),"iterate",Ut),Reflect.get(e,"size",e)}function rr(e){e=ve(e);const t=ve(this);return wi(t).has.call(t,e)||(t.add(e),gt(t,"add",e,e)),this}function or(e,t){t=ve(t);const l=ve(this),{has:i,get:n}=wi(l);let r=i.call(l,e);r||(e=ve(e),r=i.call(l,e));const o=n.call(l,e);return l.set(e,t),r?Yt(t,o)&>(l,"set",e,t):gt(l,"add",e,t),this}function sr(e){const t=ve(this),{has:l,get:i}=wi(t);let n=l.call(t,e);n||(e=ve(e),n=l.call(t,e)),i&&i.call(t,e);const r=t.delete(e);return n&>(t,"delete",e,void 0),r}function cr(){const e=ve(this),t=e.size!==0,l=e.clear();return t&>(e,"clear",void 0,void 0),l}function ti(e,t){return function(i,n){const r=this,o=r.__v_raw,c=ve(o),a=t?Tn:e?An:Sl;return!e&&Xe(c,"iterate",Ut),o.forEach((u,d)=>i.call(n,a(u),a(d),r))}}function li(e,t,l){return function(...i){const n=this.__v_raw,r=ve(n),o=nl(r),c=e==="entries"||e===Symbol.iterator&&o,a=e==="keys"&&o,u=n[e](...i),d=l?Tn:t?An:Sl;return!t&&Xe(r,"iterate",a?rn:Ut),{next(){const{value:v,done:_}=u.next();return _?{value:v,done:_}:{value:c?[d(v[0]),d(v[1])]:d(v),done:_}},[Symbol.iterator](){return this}}}}function Lt(e){return function(...t){return e==="delete"?!1:e==="clear"?void 0:this}}function Oc(){const e={get(r){return Ql(this,r)},get size(){return ei(this)},has:Zl,add:rr,set:or,delete:sr,clear:cr,forEach:ti(!1,!1)},t={get(r){return Ql(this,r,!1,!0)},get size(){return ei(this)},has:Zl,add:rr,set:or,delete:sr,clear:cr,forEach:ti(!1,!0)},l={get(r){return Ql(this,r,!0)},get size(){return ei(this,!0)},has(r){return Zl.call(this,r,!0)},add:Lt("add"),set:Lt("set"),delete:Lt("delete"),clear:Lt("clear"),forEach:ti(!0,!1)},i={get(r){return Ql(this,r,!0,!0)},get size(){return ei(this,!0)},has(r){return Zl.call(this,r,!0)},add:Lt("add"),set:Lt("set"),delete:Lt("delete"),clear:Lt("clear"),forEach:ti(!0,!0)};return["keys","values","entries",Symbol.iterator].forEach(r=>{e[r]=li(r,!1,!1),l[r]=li(r,!0,!1),t[r]=li(r,!1,!0),i[r]=li(r,!0,!0)}),[e,l,t,i]}const[Pc,Ac,wc,Rc]=Oc();function On(e,t){const l=t?e?Rc:wc:e?Ac:Pc;return(i,n,r)=>n==="__v_isReactive"?!e:n==="__v_isReadonly"?e:n==="__v_raw"?i:Reflect.get(de(l,n)&&n in i?l:i,n,r)}const Ic={get:On(!1,!1)},Dc={get:On(!1,!0)},jc={get:On(!0,!1)},Do=new WeakMap,jo=new WeakMap,So=new WeakMap,Sc=new WeakMap;function Cc(e){switch(e){case"Object":case"Array":return 1;case"Map":case"Set":case"WeakMap":case"WeakSet":return 2;default:return 0}}function Vc(e){return e.__v_skip||!Object.isExtensible(e)?0:Cc(lc(e))}function zl(e){return cl(e)?e:Pn(e,!1,xc,Ic,Do)}function Co(e){return Pn(e,!1,Tc,Dc,jo)}function Ri(e){return Pn(e,!0,Lc,jc,So)}function Pn(e,t,l,i,n){if(!Ee(e)||e.__v_raw&&!(t&&e.__v_isReactive))return e;const r=n.get(e);if(r)return r;const o=Vc(e);if(o===0)return e;const c=new Proxy(e,o===2?i:l);return n.set(e,c),c}function rl(e){return cl(e)?rl(e.__v_raw):!!(e&&e.__v_isReactive)}function cl(e){return!!(e&&e.__v_isReadonly)}function gi(e){return!!(e&&e.__v_isShallow)}function Vo(e){return rl(e)||cl(e)}function ve(e){const t=e&&e.__v_raw;return t?ve(t):e}function Fo(e){return _i(e,"__v_skip",!0),e}const Sl=e=>Ee(e)?zl(e):e,An=e=>Ee(e)?Ri(e):e;function wn(e){It&<&&(e=ve(e),Ao(e.dep||(e.dep=xn())))}function Rn(e,t){e=ve(e);const l=e.dep;l&&on(l)}function Ne(e){return!!(e&&e.__v_isRef===!0)}function ge(e){return Ho(e,!1)}function No(e){return Ho(e,!0)}function Ho(e,t){return Ne(e)?e:new Fc(e,t)}class Fc{constructor(t,l){this.__v_isShallow=l,this.dep=void 0,this.__v_isRef=!0,this._rawValue=l?t:ve(t),this._value=l?t:Sl(t)}get value(){return wn(this),this._value}set value(t){const l=this.__v_isShallow||gi(t)||cl(t);t=l?t:ve(t),Yt(t,this._rawValue)&&(this._rawValue=t,this._value=l?t:Sl(t),Rn(this))}}function Xt(e){return Ne(e)?e.value:e}const Nc={get:(e,t,l)=>Xt(Reflect.get(e,t,l)),set:(e,t,l,i)=>{const n=e[t];return Ne(n)&&!Ne(l)?(n.value=l,!0):Reflect.set(e,t,l,i)}};function Mo(e){return rl(e)?e:new Proxy(e,Nc)}class Hc{constructor(t){this.dep=void 0,this.__v_isRef=!0;const{get:l,set:i}=t(()=>wn(this),()=>Rn(this));this._get=l,this._set=i}get value(){return this._get()}set value(t){this._set(t)}}function Mc(e){return new Hc(e)}function Ii(e){const t=te(e)?new Array(e.length):{};for(const l in e)t[l]=$o(e,l);return t}class $c{constructor(t,l,i){this._object=t,this._key=l,this._defaultValue=i,this.__v_isRef=!0}get value(){const t=this._object[this._key];return t===void 0?this._defaultValue:t}set value(t){this._object[this._key]=t}get dep(){return mc(ve(this._object),this._key)}}class Bc{constructor(t){this._getter=t,this.__v_isRef=!0,this.__v_isReadonly=!0}get value(){return this._getter()}}function Ef(e,t,l){return Ne(e)?e:oe(e)?new Bc(e):Ee(e)&&arguments.length>1?$o(e,t,l):ge(e)}function $o(e,t,l){const i=e[t];return Ne(i)?i:new $c(e,t,l)}class Wc{constructor(t,l,i,n){this._setter=l,this.dep=void 0,this.__v_isRef=!0,this.__v_isReadonly=!1,this._dirty=!0,this.effect=new Ln(t,()=>{this._dirty||(this._dirty=!0,Rn(this))}),this.effect.computed=this,this.effect.active=this._cacheable=!n,this.__v_isReadonly=i}get value(){const t=ve(this);return wn(t),(t._dirty||!t._cacheable)&&(t._dirty=!1,t._value=t.effect.run()),t._value}set value(t){this._setter(t)}}function zc(e,t,l=!1){let i,n;const r=oe(e);return r?(i=e,n=ut):(i=e.get,n=e.set),new Wc(i,n,r||!n,l)}function Dt(e,t,l,i){let n;try{n=i?e(...i):e()}catch(r){Ul(r,t,l)}return n}function Ze(e,t,l,i){if(oe(e)){const r=Dt(e,t,l,i);return r&&bo(r)&&r.catch(o=>{Ul(o,t,l)}),r}const n=[];for(let r=0;r>>1,n=Me[i],r=Vl(n);rat&&Me.splice(t,1)}function qc(e){te(e)?ol.push(...e):(!ft||!ft.includes(e,e.allowRecurse?$t+1:$t))&&ol.push(e),Wo()}function ar(e,t,l=Cl?at+1:0){for(;lVl(l)-Vl(i)),$t=0;$te.id==null?1/0:e.id,Gc=(e,t)=>{const l=Vl(e)-Vl(t);if(l===0){if(e.pre&&!t.pre)return-1;if(t.pre&&!e.pre)return 1}return l};function zo(e){sn=!1,Cl=!0,Me.sort(Gc);try{for(at=0;atwe(p)?p.trim():p)),v&&(n=l.map(rc))}let c,a=i[c=Mi(t)]||i[c=Mi(dt(t))];!a&&r&&(a=i[c=Mi(Jt(t))]),a&&Ze(a,e,6,n);const u=i[c+"Once"];if(u){if(!e.emitted)e.emitted={};else if(e.emitted[c])return;e.emitted[c]=!0,Ze(u,e,6,n)}}function Uo(e,t,l=!1){const i=t.emitsCache,n=i.get(e);if(n!==void 0)return n;const r=e.emits;let o={},c=!1;if(!oe(e)){const a=u=>{const d=Uo(u,t,!0);d&&(c=!0,Ie(o,d))};!l&&t.mixins.length&&t.mixins.forEach(a),e.extends&&a(e.extends),e.mixins&&e.mixins.forEach(a)}return!r&&!c?(Ee(e)&&i.set(e,null),null):(te(r)?r.forEach(a=>o[a]=null):Ie(o,r),Ee(e)&&i.set(e,o),o)}function ji(e,t){return!e||!Bl(t)?!1:(t=t.slice(2).replace(/Once$/,""),de(e,t[0].toLowerCase()+t.slice(1))||de(e,Jt(t))||de(e,t))}let Ve=null,Xo=null;function mi(e){const t=Ve;return Ve=e,Xo=e&&e.type.__scopeId||null,t}function Ce(e,t=Ve,l){if(!t||e._n)return e;const i=(...n)=>{i._d&&Er(-1);const r=mi(t);let o;try{o=e(...n)}finally{mi(r),i._d&&Er(1)}return o};return i._n=!0,i._c=!0,i._d=!0,i}function Wi(e){const{type:t,vnode:l,proxy:i,withProxy:n,props:r,propsOptions:[o],slots:c,attrs:a,emit:u,render:d,renderCache:v,data:_,setupState:p,ctx:m,inheritAttrs:x}=e;let A,D;const O=mi(e);try{if(l.shapeFlag&4){const y=n||i,H=y;A=tt(d.call(H,y,v,r,p,_,m)),D=a}else{const y=t;A=tt(y.length>1?y(r,{attrs:a,slots:c,emit:u}):y(r,null)),D=t.props?a:Jc(a)}}catch(y){Il.length=0,Ul(y,e,1),A=ne(Ye)}let b=A;if(D&&x!==!1){const y=Object.keys(D),{shapeFlag:H}=b;y.length&&H&7&&(o&&y.some(kn)&&(D=Qc(D,o)),b=Ct(b,D))}return l.dirs&&(b=Ct(b),b.dirs=b.dirs?b.dirs.concat(l.dirs):l.dirs),l.transition&&(b.transition=l.transition),A=b,mi(O),A}const Jc=e=>{let t;for(const l in e)(l==="class"||l==="style"||Bl(l))&&((t||(t={}))[l]=e[l]);return t},Qc=(e,t)=>{const l={};for(const i in e)(!kn(i)||!(i.slice(9)in t))&&(l[i]=e[i]);return l};function Zc(e,t,l){const{props:i,children:n,component:r}=e,{props:o,children:c,patchFlag:a}=t,u=r.emitsOptions;if(t.dirs||t.transition)return!0;if(l&&a>=0){if(a&1024)return!0;if(a&16)return i?ur(i,o,u):!!o;if(a&8){const d=t.dynamicProps;for(let v=0;ve.__isSuspense;function Ko(e,t){t&&t.pendingBranch?te(e)?t.effects.push(...e):t.effects.push(e):qc(e)}function ra(e,t){return Dn(e,null,t)}const ii={};function Ge(e,t,l){return Dn(e,t,l)}function Dn(e,t,{immediate:l,deep:i,flush:n,onTrack:r,onTrigger:o}=ye){var c;const a=Lo()===((c=Re)==null?void 0:c.scope)?Re:null;let u,d=!1,v=!1;if(Ne(e)?(u=()=>e.value,d=gi(e)):rl(e)?(u=()=>e,i=!0):te(e)?(v=!0,d=e.some(y=>rl(y)||gi(y)),u=()=>e.map(y=>{if(Ne(y))return y.value;if(rl(y))return zt(y);if(oe(y))return Dt(y,a,2)})):oe(e)?t?u=()=>Dt(e,a,2):u=()=>{if(!(a&&a.isUnmounted))return _&&_(),Ze(e,a,3,[p])}:u=ut,t&&i){const y=u;u=()=>zt(y())}let _,p=y=>{_=O.onStop=()=>{Dt(y,a,4),_=O.onStop=void 0}},m;if(dl)if(p=ut,t?l&&Ze(t,a,3,[u(),v?[]:void 0,p]):u(),n==="sync"){const y=Qa();m=y.__watcherHandles||(y.__watcherHandles=[])}else return ut;let x=v?new Array(e.length).fill(ii):ii;const A=()=>{if(O.active)if(t){const y=O.run();(i||d||(v?y.some((H,G)=>Yt(H,x[G])):Yt(y,x)))&&(_&&_(),Ze(t,a,3,[y,x===ii?void 0:v&&x[0]===ii?[]:x,p]),x=y)}else O.run()};A.allowRecurse=!!t;let D;n==="sync"?D=A:n==="post"?D=()=>Ue(A,a&&a.suspense):(A.pre=!0,a&&(A.id=a.uid),D=()=>Di(A));const O=new Ln(u,D);t?l?A():x=O.run():n==="post"?Ue(O.run.bind(O),a&&a.suspense):O.run();const b=()=>{O.stop(),a&&a.scope&&En(a.scope.effects,O)};return m&&m.push(b),b}function oa(e,t,l){const i=this.proxy,n=we(e)?e.includes(".")?qo(i,e):()=>i[e]:e.bind(i,i);let r;oe(t)?r=t:(r=t.handler,l=t);const o=Re;ul(this);const c=Dn(n,r.bind(i),l);return o?ul(o):qt(),c}function qo(e,t){const l=t.split(".");return()=>{let i=e;for(let n=0;n{zt(l,t)});else if(Eo(e))for(const l in e)zt(e[l],t);return e}function bi(e,t){const l=Ve;if(l===null)return e;const i=Fi(l)||l.proxy,n=e.dirs||(e.dirs=[]);for(let r=0;r{e.isMounted=!0}),ql(()=>{e.isUnmounting=!0}),e}const Je=[Function,Array],Go={mode:String,appear:Boolean,persisted:Boolean,onBeforeEnter:Je,onEnter:Je,onAfterEnter:Je,onEnterCancelled:Je,onBeforeLeave:Je,onLeave:Je,onAfterLeave:Je,onLeaveCancelled:Je,onBeforeAppear:Je,onAppear:Je,onAfterAppear:Je,onAppearCancelled:Je},ca={name:"BaseTransition",props:Go,setup(e,{slots:t}){const l=Vn(),i=sa();let n;return()=>{const r=t.default&&Jo(t.default(),!0);if(!r||!r.length)return;let o=r[0];if(r.length>1){for(const x of r)if(x.type!==Ye){o=x;break}}const c=ve(e),{mode:a}=c;if(i.isLeaving)return zi(o);const u=hr(o);if(!u)return zi(o);const d=cn(u,c,i,l);an(u,d);const v=l.subTree,_=v&&hr(v);let p=!1;const{getTransitionKey:m}=u.type;if(m){const x=m();n===void 0?n=x:x!==n&&(n=x,p=!0)}if(_&&_.type!==Ye&&(!Bt(u,_)||p)){const x=cn(_,c,i,l);if(an(_,x),a==="out-in")return i.isLeaving=!0,x.afterLeave=()=>{i.isLeaving=!1,l.update.active!==!1&&l.update()},zi(o);a==="in-out"&&u.type!==Ye&&(x.delayLeave=(A,D,O)=>{const b=Yo(i,_);b[String(_.key)]=_,A[At]=()=>{D(),A[At]=void 0,delete d.delayedLeave},d.delayedLeave=O})}return o}}},aa=ca;function Yo(e,t){const{leavingVNodes:l}=e;let i=l.get(t.type);return i||(i=Object.create(null),l.set(t.type,i)),i}function cn(e,t,l,i){const{appear:n,mode:r,persisted:o=!1,onBeforeEnter:c,onEnter:a,onAfterEnter:u,onEnterCancelled:d,onBeforeLeave:v,onLeave:_,onAfterLeave:p,onLeaveCancelled:m,onBeforeAppear:x,onAppear:A,onAfterAppear:D,onAppearCancelled:O}=t,b=String(e.key),y=Yo(l,e),H=(E,K)=>{E&&Ze(E,i,9,K)},G=(E,K)=>{const w=K[1];H(E,K),te(E)?E.every(U=>U.length<=1)&&w():E.length<=1&&w()},N={mode:r,persisted:o,beforeEnter(E){let K=c;if(!l.isMounted)if(n)K=x||c;else return;E[At]&&E[At](!0);const w=y[b];w&&Bt(e,w)&&w.el[At]&&w.el[At](),H(K,[E])},enter(E){let K=a,w=u,U=d;if(!l.isMounted)if(n)K=A||a,w=D||u,U=O||d;else return;let L=!1;const V=E[ni]=le=>{L||(L=!0,le?H(U,[E]):H(w,[E]),N.delayedLeave&&N.delayedLeave(),E[ni]=void 0)};K?G(K,[E,V]):V()},leave(E,K){const w=String(e.key);if(E[ni]&&E[ni](!0),l.isUnmounting)return K();H(v,[E]);let U=!1;const L=E[At]=V=>{U||(U=!0,K(),V?H(m,[E]):H(p,[E]),E[At]=void 0,y[w]===e&&delete y[w])};y[w]=e,_?G(_,[E,L]):L()},clone(E){return cn(E,t,l,i)}};return N}function zi(e){if(Kl(e))return e=Ct(e),e.children=null,e}function hr(e){return Kl(e)?e.children?e.children[0]:void 0:e}function an(e,t){e.shapeFlag&6&&e.component?an(e.component.subTree,t):e.shapeFlag&128?(e.ssContent.transition=t.clone(e.ssContent),e.ssFallback.transition=t.clone(e.ssFallback)):e.transition=t}function Jo(e,t=!1,l){let i=[],n=0;for(let r=0;r1)for(let r=0;r!!e.type.__asyncLoader;/*! #__NO_SIDE_EFFECTS__ */function h(e){oe(e)&&(e={loader:e});const{loader:t,loadingComponent:l,errorComponent:i,delay:n=200,timeout:r,suspensible:o=!0,onError:c}=e;let a=null,u,d=0;const v=()=>(d++,a=null,_()),_=()=>{let p;return a||(p=a=t().catch(m=>{if(m=m instanceof Error?m:new Error(String(m)),c)return new Promise((x,A)=>{c(m,()=>x(v()),()=>A(m),d+1)});throw m}).then(m=>p!==a&&a?a:(m&&(m.__esModule||m[Symbol.toStringTag]==="Module")&&(m=m.default),u=m,m)))};return _e({name:"AsyncComponentWrapper",__asyncLoader:_,get __asyncResolved(){return u},setup(){const p=Re;if(u)return()=>Ui(u,p);const m=O=>{a=null,Ul(O,p,13,!i)};if(o&&p.suspense||dl)return _().then(O=>()=>Ui(O,p)).catch(O=>(m(O),()=>i?ne(i,{error:O}):null));const x=ge(!1),A=ge(),D=ge(!!n);return n&&setTimeout(()=>{D.value=!1},n),r!=null&&setTimeout(()=>{if(!x.value&&!A.value){const O=new Error(`Async component timed out after ${r}ms.`);m(O),A.value=O}},r),_().then(()=>{x.value=!0,p.parent&&Kl(p.parent.vnode)&&Di(p.parent.update)}).catch(O=>{m(O),A.value=O}),()=>{if(x.value&&u)return Ui(u,p);if(A.value&&i)return ne(i,{error:A.value});if(l&&!D.value)return ne(l)}}})}function Ui(e,t){const{ref:l,props:i,children:n,ce:r}=t.vnode,o=ne(e,i,n);return o.ref=l,o.ce=r,delete t.vnode.ce,o}const Kl=e=>e.type.__isKeepAlive;function ua(e,t){Qo(e,"a",t)}function da(e,t){Qo(e,"da",t)}function Qo(e,t,l=Re){const i=e.__wdc||(e.__wdc=()=>{let n=l;for(;n;){if(n.isDeactivated)return;n=n.parent}return e()});if(Si(t,i,l),l){let n=l.parent;for(;n&&n.parent;)Kl(n.parent.vnode)&&ha(i,t,l,n),n=n.parent}}function ha(e,t,l,i){const n=Si(t,e,i,!0);Ci(()=>{En(i[t],n)},l)}function Si(e,t,l=Re,i=!1){if(l){const n=l[e]||(l[e]=[]),r=t.__weh||(t.__weh=(...o)=>{if(l.isUnmounted)return;gl(),ul(l);const c=Ze(t,l,e,o);return qt(),pl(),c});return i?n.unshift(r):n.push(r),r}}const kt=e=>(t,l=Re)=>(!dl||e==="sp")&&Si(e,(...i)=>t(...i),l),va=kt("bm"),We=kt("m"),_a=kt("bu"),fa=kt("u"),ql=kt("bum"),Ci=kt("um"),ga=kt("sp"),pa=kt("rtg"),ma=kt("rtc");function ba(e,t=Re){Si("ec",e,t)}function St(e,t,l,i){let n;const r=l;if(te(e)||we(e)){n=new Array(e.length);for(let o=0,c=e.length;ot(o,c,void 0,r));else{const o=Object.keys(e);n=new Array(o.length);for(let c=0,a=o.length;cxi(t)?!(t.type===Ye||t.type===ke&&!Zo(t.children)):!0)?e:null}const un=e=>e?ds(e)?Fi(e)||e.proxy:un(e.parent):null,wl=Ie(Object.create(null),{$:e=>e,$el:e=>e.vnode.el,$data:e=>e.data,$props:e=>e.props,$attrs:e=>e.attrs,$slots:e=>e.slots,$refs:e=>e.refs,$parent:e=>un(e.parent),$root:e=>un(e.root),$emit:e=>e.emit,$options:e=>jn(e),$forceUpdate:e=>e.f||(e.f=()=>Di(e.update)),$nextTick:e=>e.n||(e.n=Xl.bind(e.proxy)),$watch:e=>oa.bind(e)}),Xi=(e,t)=>e!==ye&&!e.__isScriptSetup&&de(e,t),ka={get({_:e},t){const{ctx:l,setupState:i,data:n,props:r,accessCache:o,type:c,appContext:a}=e;let u;if(t[0]!=="$"){const p=o[t];if(p!==void 0)switch(p){case 1:return i[t];case 2:return n[t];case 4:return l[t];case 3:return r[t]}else{if(Xi(i,t))return o[t]=1,i[t];if(n!==ye&&de(n,t))return o[t]=2,n[t];if((u=e.propsOptions[0])&&de(u,t))return o[t]=3,r[t];if(l!==ye&&de(l,t))return o[t]=4,l[t];dn&&(o[t]=0)}}const d=wl[t];let v,_;if(d)return t==="$attrs"&&Xe(e,"get",t),d(e);if((v=c.__cssModules)&&(v=v[t]))return v;if(l!==ye&&de(l,t))return o[t]=4,l[t];if(_=a.config.globalProperties,de(_,t))return _[t]},set({_:e},t,l){const{data:i,setupState:n,ctx:r}=e;return Xi(n,t)?(n[t]=l,!0):i!==ye&&de(i,t)?(i[t]=l,!0):de(e.props,t)||t[0]==="$"&&t.slice(1)in e?!1:(r[t]=l,!0)},has({_:{data:e,setupState:t,accessCache:l,ctx:i,appContext:n,propsOptions:r}},o){let c;return!!l[o]||e!==ye&&de(e,o)||Xi(t,o)||(c=r[0])&&de(c,o)||de(i,o)||de(wl,o)||de(n.config.globalProperties,o)},defineProperty(e,t,l){return l.get!=null?e._.accessCache[t]=0:de(l,"value")&&this.set(e,t,l.value,null),Reflect.defineProperty(e,t,l)}};function vr(e){return te(e)?e.reduce((t,l)=>(t[l]=null,t),{}):e}let dn=!0;function Ea(e){const t=jn(e),l=e.proxy,i=e.ctx;dn=!1,t.beforeCreate&&_r(t.beforeCreate,e,"bc");const{data:n,computed:r,methods:o,watch:c,provide:a,inject:u,created:d,beforeMount:v,mounted:_,beforeUpdate:p,updated:m,activated:x,deactivated:A,beforeDestroy:D,beforeUnmount:O,destroyed:b,unmounted:y,render:H,renderTracked:G,renderTriggered:N,errorCaptured:E,serverPrefetch:K,expose:w,inheritAttrs:U,components:L,directives:V,filters:le}=t;if(u&&ya(u,i,null),o)for(const J in o){const X=o[J];oe(X)&&(i[J]=X.bind(l))}if(n){const J=n.call(l,l);Ee(J)&&(e.data=zl(J))}if(dn=!0,r)for(const J in r){const X=r[J],De=oe(X)?X.bind(l,l):oe(X.get)?X.get.bind(l,l):ut,Se=!oe(X)&&oe(X.set)?X.set.bind(l):ut,ze=C({get:De,set:Se});Object.defineProperty(i,J,{enumerable:!0,configurable:!0,get:()=>ze.value,set:He=>ze.value=He})}if(c)for(const J in c)es(c[J],i,l,J);if(a){const J=oe(a)?a.call(l):a;Reflect.ownKeys(J).forEach(X=>{Kt(X,J[X])})}d&&_r(d,e,"c");function S(J,X){te(X)?X.forEach(De=>J(De.bind(l))):X&&J(X.bind(l))}if(S(va,v),S(We,_),S(_a,p),S(fa,m),S(ua,x),S(da,A),S(ba,E),S(ma,G),S(pa,N),S(ql,O),S(Ci,y),S(ga,K),te(w))if(w.length){const J=e.exposed||(e.exposed={});w.forEach(X=>{Object.defineProperty(J,X,{get:()=>l[X],set:De=>l[X]=De})})}else e.exposed||(e.exposed={});H&&e.render===ut&&(e.render=H),U!=null&&(e.inheritAttrs=U),L&&(e.components=L),V&&(e.directives=V)}function ya(e,t,l=ut){te(e)&&(e=hn(e));for(const i in e){const n=e[i];let r;Ee(n)?"default"in n?r=Te(n.from||i,n.default,!0):r=Te(n.from||i):r=Te(n),Ne(r)?Object.defineProperty(t,i,{enumerable:!0,configurable:!0,get:()=>r.value,set:o=>r.value=o}):t[i]=r}}function _r(e,t,l){Ze(te(e)?e.map(i=>i.bind(t.proxy)):e.bind(t.proxy),t,l)}function es(e,t,l,i){const n=i.includes(".")?qo(l,i):()=>l[i];if(we(e)){const r=t[e];oe(r)&&Ge(n,r)}else if(oe(e))Ge(n,e.bind(l));else if(Ee(e))if(te(e))e.forEach(r=>es(r,t,l,i));else{const r=oe(e.handler)?e.handler.bind(l):t[e.handler];oe(r)&&Ge(n,r,e)}}function jn(e){const t=e.type,{mixins:l,extends:i}=t,{mixins:n,optionsCache:r,config:{optionMergeStrategies:o}}=e.appContext,c=r.get(t);let a;return c?a=c:!n.length&&!l&&!i?a=t:(a={},n.length&&n.forEach(u=>ki(a,u,o,!0)),ki(a,t,o)),Ee(t)&&r.set(t,a),a}function ki(e,t,l,i=!1){const{mixins:n,extends:r}=t;r&&ki(e,r,l,!0),n&&n.forEach(o=>ki(e,o,l,!0));for(const o in t)if(!(i&&o==="expose")){const c=xa[o]||l&&l[o];e[o]=c?c(e[o],t[o]):t[o]}return e}const xa={data:fr,props:gr,emits:gr,methods:Pl,computed:Pl,beforeCreate:Be,created:Be,beforeMount:Be,mounted:Be,beforeUpdate:Be,updated:Be,beforeDestroy:Be,beforeUnmount:Be,destroyed:Be,unmounted:Be,activated:Be,deactivated:Be,errorCaptured:Be,serverPrefetch:Be,components:Pl,directives:Pl,watch:Ta,provide:fr,inject:La};function fr(e,t){return t?e?function(){return Ie(oe(e)?e.call(this,this):e,oe(t)?t.call(this,this):t)}:t:e}function La(e,t){return Pl(hn(e),hn(t))}function hn(e){if(te(e)){const t={};for(let l=0;l1)return l&&oe(t)?t.call(i&&i.proxy):t}}function Aa(e,t,l,i=!1){const n={},r={};_i(r,Vi,1),e.propsDefaults=Object.create(null),ls(e,t,n,r);for(const o in e.propsOptions[0])o in n||(n[o]=void 0);l?e.props=i?n:Co(n):e.type.props?e.props=n:e.props=r,e.attrs=r}function wa(e,t,l,i){const{props:n,attrs:r,vnode:{patchFlag:o}}=e,c=ve(n),[a]=e.propsOptions;let u=!1;if((i||o>0)&&!(o&16)){if(o&8){const d=e.vnode.dynamicProps;for(let v=0;v{a=!0;const[_,p]=is(v,t,!0);Ie(o,_),p&&c.push(...p)};!l&&t.mixins.length&&t.mixins.forEach(d),e.extends&&d(e.extends),e.mixins&&e.mixins.forEach(d)}if(!r&&!a)return Ee(e)&&i.set(e,il),il;if(te(r))for(let d=0;d-1,p[1]=x<0||m-1||de(p,"default"))&&c.push(v)}}}const u=[o,c];return Ee(e)&&i.set(e,u),u}function pr(e){return e[0]!=="$"}function mr(e){const t=e&&e.toString().match(/^\s*(function|class) (\w+)/);return t?t[2]:e===null?"null":""}function br(e,t){return mr(e)===mr(t)}function kr(e,t){return te(t)?t.findIndex(l=>br(l,e)):oe(t)&&br(t,e)?0:-1}const ns=e=>e[0]==="_"||e==="$stable",Sn=e=>te(e)?e.map(tt):[tt(e)],Ra=(e,t,l)=>{if(t._n)return t;const i=Ce((...n)=>Sn(t(...n)),l);return i._c=!1,i},rs=(e,t,l)=>{const i=e._ctx;for(const n in e){if(ns(n))continue;const r=e[n];if(oe(r))t[n]=Ra(n,r,i);else if(r!=null){const o=Sn(r);t[n]=()=>o}}},os=(e,t)=>{const l=Sn(t);e.slots.default=()=>l},Ia=(e,t)=>{if(e.vnode.shapeFlag&32){const l=t._;l?(e.slots=ve(t),_i(t,"_",l)):rs(t,e.slots={})}else e.slots={},t&&os(e,t);_i(e.slots,Vi,1)},Da=(e,t,l)=>{const{vnode:i,slots:n}=e;let r=!0,o=ye;if(i.shapeFlag&32){const c=t._;c?l&&c===1?r=!1:(Ie(n,t),!l&&c===1&&delete n._):(r=!t.$stable,rs(t,n)),o=t}else t&&(os(e,t),o={default:1});if(r)for(const c in n)!ns(c)&&o[c]==null&&delete n[c]};function yi(e,t,l,i,n=!1){if(te(e)){e.forEach((_,p)=>yi(_,t&&(te(t)?t[p]:t),l,i,n));return}if(sl(i)&&!n)return;const r=i.shapeFlag&4?Fi(i.component)||i.component.proxy:i.el,o=n?null:r,{i:c,r:a}=e,u=t&&t.r,d=c.refs===ye?c.refs={}:c.refs,v=c.setupState;if(u!=null&&u!==a&&(we(u)?(d[u]=null,de(v,u)&&(v[u]=null)):Ne(u)&&(u.value=null)),oe(a))Dt(a,c,12,[o,d]);else{const _=we(a),p=Ne(a);if(_||p){const m=()=>{if(e.f){const x=_?de(v,a)?v[a]:d[a]:a.value;n?te(x)&&En(x,r):te(x)?x.includes(r)||x.push(r):_?(d[a]=[r],de(v,a)&&(v[a]=d[a])):(a.value=[r],e.k&&(d[e.k]=a.value))}else _?(d[a]=o,de(v,a)&&(v[a]=o)):p&&(a.value=o,e.k&&(d[e.k]=o))};o?(m.id=-1,Ue(m,l)):m()}}}let Tt=!1;const ri=e=>/svg/.test(e.namespaceURI)&&e.tagName!=="foreignObject",oi=e=>e.nodeType===8;function ja(e){const{mt:t,p:l,o:{patchProp:i,createText:n,nextSibling:r,parentNode:o,remove:c,insert:a,createComment:u}}=e,d=(b,y)=>{if(!y.hasChildNodes()){l(null,b,y),pi(),y._vnode=b;return}Tt=!1,v(y.firstChild,b,null,null,null),pi(),y._vnode=b,Tt&&console.error("Hydration completed but contains mismatches.")},v=(b,y,H,G,N,E=!1)=>{const K=oi(b)&&b.data==="[",w=()=>x(b,y,H,G,N,K),{type:U,ref:L,shapeFlag:V,patchFlag:le}=y;let ie=b.nodeType;y.el=b,le===-2&&(E=!1,y.dynamicChildren=null);let S=null;switch(U){case al:ie!==3?y.children===""?(a(y.el=n(""),o(b),b),S=b):S=w():(b.data!==y.children&&(Tt=!0,b.data=y.children),S=r(b));break;case Ye:O(b)?(S=r(b),D(y.el=b.content.firstChild,b,H)):ie!==8||K?S=w():S=r(b);break;case Rl:if(K&&(b=r(b),ie=b.nodeType),ie===1||ie===3){S=b;const J=!y.children.length;for(let X=0;X{E=E||!!y.dynamicChildren;const{type:K,props:w,patchFlag:U,shapeFlag:L,dirs:V,transition:le}=y,ie=K==="input"||K==="option";if(ie||U!==-1){V&&ct(y,null,H,"created");let S=!1;if(O(b)){S=ss(G,le)&&H&&H.vnode.props&&H.vnode.props.appear;const X=b.content.firstChild;S&&le.beforeEnter(X),D(X,b,H),y.el=b=X}if(w)if(ie||!E||U&48)for(const X in w)(ie&&(X.endsWith("value")||X==="indeterminate")||Bl(X)&&!Al(X)||X[0]===".")&&i(b,X,null,w[X],!1,void 0,H);else w.onClick&&i(b,"onClick",null,w.onClick,!1,void 0,H);let J;if((J=w&&w.onVnodeBeforeMount)&&Qe(J,H,y),V&&ct(y,null,H,"beforeMount"),((J=w&&w.onVnodeMounted)||V||S)&&Ko(()=>{J&&Qe(J,H,y),S&&le.enter(b),V&&ct(y,null,H,"mounted")},G),L&16&&!(w&&(w.innerHTML||w.textContent))){let X=p(b.firstChild,y,b,H,G,N,E);for(;X;){Tt=!0;const De=X;X=X.nextSibling,c(De)}}else L&8&&b.textContent!==y.children&&(Tt=!0,b.textContent=y.children)}return b.nextSibling},p=(b,y,H,G,N,E,K)=>{K=K||!!y.dynamicChildren;const w=y.children,U=w.length;for(let L=0;L{const{slotScopeIds:K}=y;K&&(N=N?N.concat(K):K);const w=o(b),U=p(r(b),y,w,H,G,N,E);return U&&oi(U)&&U.data==="]"?r(y.anchor=U):(Tt=!0,a(y.anchor=u("]"),w,U),U)},x=(b,y,H,G,N,E)=>{if(Tt=!0,y.el=null,E){const U=A(b);for(;;){const L=r(b);if(L&&L!==U)c(L);else break}}const K=r(b),w=o(b);return c(b),l(null,y,w,K,H,G,ri(w),N),K},A=(b,y="[",H="]")=>{let G=0;for(;b;)if(b=r(b),b&&oi(b)&&(b.data===y&&G++,b.data===H)){if(G===0)return r(b);G--}return b},D=(b,y,H)=>{const G=y.parentNode;G&&G.replaceChild(b,y);let N=H;for(;N;)N.vnode.el===y&&(N.vnode.el=N.subTree.el=b),N=N.parent},O=b=>b.nodeType===1&&b.tagName.toLowerCase()==="template";return[d,v]}const Ue=Ko;function Sa(e){return Ca(e,ja)}function Ca(e,t){const l=ln();l.__VUE__=!0;const{insert:i,remove:n,patchProp:r,createElement:o,createText:c,createComment:a,setText:u,setElementText:d,parentNode:v,nextSibling:_,setScopeId:p=ut,insertStaticContent:m}=e,x=(f,g,k,T=null,R=null,I=null,B=!1,F=null,$=!!g.dynamicChildren)=>{if(f===g)return;f&&!Bt(f,g)&&(T=P(f),He(f,R,I,!0),f=null),g.patchFlag===-2&&($=!1,g.dynamicChildren=null);const{type:j,ref:Q,shapeFlag:q}=g;switch(j){case al:A(f,g,k,T);break;case Ye:D(f,g,k,T);break;case Rl:f==null&&O(g,k,T,B);break;case ke:L(f,g,k,T,R,I,B,F,$);break;default:q&1?H(f,g,k,T,R,I,B,F,$):q&6?V(f,g,k,T,R,I,B,F,$):(q&64||q&128)&&j.process(f,g,k,T,R,I,B,F,$,M)}Q!=null&&R&&yi(Q,f&&f.ref,I,g||f,!g)},A=(f,g,k,T)=>{if(f==null)i(g.el=c(g.children),k,T);else{const R=g.el=f.el;g.children!==f.children&&u(R,g.children)}},D=(f,g,k,T)=>{f==null?i(g.el=a(g.children||""),k,T):g.el=f.el},O=(f,g,k,T)=>{[f.el,f.anchor]=m(f.children,g,k,T,f.el,f.anchor)},b=({el:f,anchor:g},k,T)=>{let R;for(;f&&f!==g;)R=_(f),i(f,k,T),f=R;i(g,k,T)},y=({el:f,anchor:g})=>{let k;for(;f&&f!==g;)k=_(f),n(f),f=k;n(g)},H=(f,g,k,T,R,I,B,F,$)=>{B=B||g.type==="svg",f==null?G(g,k,T,R,I,B,F,$):K(f,g,R,I,B,F,$)},G=(f,g,k,T,R,I,B,F)=>{let $,j;const{type:Q,props:q,shapeFlag:Z,transition:re,dirs:se}=f;if($=f.el=o(f.type,I,q&&q.is,q),Z&8?d($,f.children):Z&16&&E(f.children,$,null,T,R,I&&Q!=="foreignObject",B,F),se&&ct(f,null,T,"created"),N($,f,f.scopeId,B,T),q){for(const pe in q)pe!=="value"&&!Al(pe)&&r($,pe,null,q[pe],I,f.children,T,R,je);"value"in q&&r($,"value",null,q.value),(j=q.onVnodeBeforeMount)&&Qe(j,T,f)}se&&ct(f,null,T,"beforeMount");const me=ss(R,re);me&&re.beforeEnter($),i($,g,k),((j=q&&q.onVnodeMounted)||me||se)&&Ue(()=>{j&&Qe(j,T,f),me&&re.enter($),se&&ct(f,null,T,"mounted")},R)},N=(f,g,k,T,R)=>{if(k&&p(f,k),T)for(let I=0;I{for(let j=$;j{const F=g.el=f.el;let{patchFlag:$,dynamicChildren:j,dirs:Q}=g;$|=f.patchFlag&16;const q=f.props||ye,Z=g.props||ye;let re;k&&Ft(k,!1),(re=Z.onVnodeBeforeUpdate)&&Qe(re,k,g,f),Q&&ct(g,f,k,"beforeUpdate"),k&&Ft(k,!0);const se=R&&g.type!=="foreignObject";if(j?w(f.dynamicChildren,j,F,k,T,se,I):B||X(f,g,F,null,k,T,se,I,!1),$>0){if($&16)U(F,g,q,Z,k,T,R);else if($&2&&q.class!==Z.class&&r(F,"class",null,Z.class,R),$&4&&r(F,"style",q.style,Z.style,R),$&8){const me=g.dynamicProps;for(let pe=0;pe{re&&Qe(re,k,g,f),Q&&ct(g,f,k,"updated")},T)},w=(f,g,k,T,R,I,B)=>{for(let F=0;F{if(k!==T){if(k!==ye)for(const F in k)!Al(F)&&!(F in T)&&r(f,F,k[F],null,B,g.children,R,I,je);for(const F in T){if(Al(F))continue;const $=T[F],j=k[F];$!==j&&F!=="value"&&r(f,F,j,$,B,g.children,R,I,je)}"value"in T&&r(f,"value",k.value,T.value)}},L=(f,g,k,T,R,I,B,F,$)=>{const j=g.el=f?f.el:c(""),Q=g.anchor=f?f.anchor:c("");let{patchFlag:q,dynamicChildren:Z,slotScopeIds:re}=g;re&&(F=F?F.concat(re):re),f==null?(i(j,k,T),i(Q,k,T),E(g.children,k,Q,R,I,B,F,$)):q>0&&q&64&&Z&&f.dynamicChildren?(w(f.dynamicChildren,Z,k,R,I,B,F),(g.key!=null||R&&g===R.subTree)&&cs(f,g,!0)):X(f,g,k,Q,R,I,B,F,$)},V=(f,g,k,T,R,I,B,F,$)=>{g.slotScopeIds=F,f==null?g.shapeFlag&512?R.ctx.activate(g,k,T,B,$):le(g,k,T,R,I,B,$):ie(f,g,$)},le=(f,g,k,T,R,I,B)=>{const F=f.component=za(f,T,R);if(Kl(f)&&(F.ctx.renderer=M),Ua(F),F.asyncDep){if(R&&R.registerDep(F,S),!f.el){const $=F.subTree=ne(Ye);D(null,$,g,k)}return}S(F,f,g,k,R,I,B)},ie=(f,g,k)=>{const T=g.component=f.component;if(Zc(f,g,k))if(T.asyncDep&&!T.asyncResolved){J(T,g,k);return}else T.next=g,Kc(T.update),T.update();else g.el=f.el,T.vnode=g},S=(f,g,k,T,R,I,B)=>{const F=()=>{if(f.isMounted){let{next:Q,bu:q,u:Z,parent:re,vnode:se}=f,me=Q,pe;Ft(f,!1),Q?(Q.el=se.el,J(f,Q,B)):Q=se,q&&$i(q),(pe=Q.props&&Q.props.onVnodeBeforeUpdate)&&Qe(pe,re,Q,se),Ft(f,!0);const Oe=Wi(f),et=f.subTree;f.subTree=Oe,x(et,Oe,v(et.el),P(et),f,R,I),Q.el=Oe.el,me===null&&ea(f,Oe.el),Z&&Ue(Z,R),(pe=Q.props&&Q.props.onVnodeUpdated)&&Ue(()=>Qe(pe,re,Q,se),R)}else{let Q;const{el:q,props:Z}=g,{bm:re,m:se,parent:me}=f,pe=sl(g);if(Ft(f,!1),re&&$i(re),!pe&&(Q=Z&&Z.onVnodeBeforeMount)&&Qe(Q,me,g),Ft(f,!0),q&&ae){const Oe=()=>{f.subTree=Wi(f),ae(q,f.subTree,f,R,null)};pe?g.type.__asyncLoader().then(()=>!f.isUnmounted&&Oe()):Oe()}else{const Oe=f.subTree=Wi(f);x(null,Oe,k,T,f,R,I),g.el=Oe.el}if(se&&Ue(se,R),!pe&&(Q=Z&&Z.onVnodeMounted)){const Oe=g;Ue(()=>Qe(Q,me,Oe),R)}(g.shapeFlag&256||me&&sl(me.vnode)&&me.vnode.shapeFlag&256)&&f.a&&Ue(f.a,R),f.isMounted=!0,g=k=T=null}},$=f.effect=new Ln(F,()=>Di(j),f.scope),j=f.update=()=>$.run();j.id=f.uid,Ft(f,!0),j()},J=(f,g,k)=>{g.component=f;const T=f.vnode.props;f.vnode=g,f.next=null,wa(f,g.props,T,k),Da(f,g.children,k),gl(),ar(f),pl()},X=(f,g,k,T,R,I,B,F,$=!1)=>{const j=f&&f.children,Q=f?f.shapeFlag:0,q=g.children,{patchFlag:Z,shapeFlag:re}=g;if(Z>0){if(Z&128){Se(j,q,k,T,R,I,B,F,$);return}else if(Z&256){De(j,q,k,T,R,I,B,F,$);return}}re&8?(Q&16&&je(j,R,I),q!==j&&d(k,q)):Q&16?re&16?Se(j,q,k,T,R,I,B,F,$):je(j,R,I,!0):(Q&8&&d(k,""),re&16&&E(q,k,T,R,I,B,F,$))},De=(f,g,k,T,R,I,B,F,$)=>{f=f||il,g=g||il;const j=f.length,Q=g.length,q=Math.min(j,Q);let Z;for(Z=0;ZQ?je(f,R,I,!0,!1,q):E(g,k,T,R,I,B,F,$,q)},Se=(f,g,k,T,R,I,B,F,$)=>{let j=0;const Q=g.length;let q=f.length-1,Z=Q-1;for(;j<=q&&j<=Z;){const re=f[j],se=g[j]=$?wt(g[j]):tt(g[j]);if(Bt(re,se))x(re,se,k,null,R,I,B,F,$);else break;j++}for(;j<=q&&j<=Z;){const re=f[q],se=g[Z]=$?wt(g[Z]):tt(g[Z]);if(Bt(re,se))x(re,se,k,null,R,I,B,F,$);else break;q--,Z--}if(j>q){if(j<=Z){const re=Z+1,se=reZ)for(;j<=q;)He(f[j],R,I,!0),j++;else{const re=j,se=j,me=new Map;for(j=se;j<=Z;j++){const Ke=g[j]=$?wt(g[j]):tt(g[j]);Ke.key!=null&&me.set(Ke.key,j)}let pe,Oe=0;const et=Z-se+1;let Qt=!1,Qn=0;const kl=new Array(et);for(j=0;j=et){He(Ke,R,I,!0);continue}let st;if(Ke.key!=null)st=me.get(Ke.key);else for(pe=se;pe<=Z;pe++)if(kl[pe-se]===0&&Bt(Ke,g[pe])){st=pe;break}st===void 0?He(Ke,R,I,!0):(kl[st-se]=j+1,st>=Qn?Qn=st:Qt=!0,x(Ke,g[st],k,null,R,I,B,F,$),Oe++)}const Zn=Qt?Va(kl):il;for(pe=Zn.length-1,j=et-1;j>=0;j--){const Ke=se+j,st=g[Ke],er=Ke+1{const{el:I,type:B,transition:F,children:$,shapeFlag:j}=f;if(j&6){ze(f.component.subTree,g,k,T);return}if(j&128){f.suspense.move(g,k,T);return}if(j&64){B.move(f,g,k,M);return}if(B===ke){i(I,g,k);for(let q=0;q<$.length;q++)ze($[q],g,k,T);i(f.anchor,g,k);return}if(B===Rl){b(f,g,k);return}if(T!==2&&j&1&&F)if(T===0)F.beforeEnter(I),i(I,g,k),Ue(()=>F.enter(I),R);else{const{leave:q,delayLeave:Z,afterLeave:re}=F,se=()=>i(I,g,k),me=()=>{q(I,()=>{se(),re&&re()})};Z?Z(I,se,me):me()}else i(I,g,k)},He=(f,g,k,T=!1,R=!1)=>{const{type:I,props:B,ref:F,children:$,dynamicChildren:j,shapeFlag:Q,patchFlag:q,dirs:Z}=f;if(F!=null&&yi(F,null,k,f,!0),Q&256){g.ctx.deactivate(f);return}const re=Q&1&&Z,se=!sl(f);let me;if(se&&(me=B&&B.onVnodeBeforeUnmount)&&Qe(me,g,f),Q&6)ot(f.component,k,T);else{if(Q&128){f.suspense.unmount(k,T);return}re&&ct(f,null,g,"beforeUnmount"),Q&64?f.type.remove(f,g,k,R,M,T):j&&(I!==ke||q>0&&q&64)?je(j,g,k,!1,!0):(I===ke&&q&384||!R&&Q&16)&&je($,g,k),T&&yt(f)}(se&&(me=B&&B.onVnodeUnmounted)||re)&&Ue(()=>{me&&Qe(me,g,f),re&&ct(f,null,g,"unmounted")},k)},yt=f=>{const{type:g,el:k,anchor:T,transition:R}=f;if(g===ke){xt(k,T);return}if(g===Rl){y(f);return}const I=()=>{n(k),R&&!R.persisted&&R.afterLeave&&R.afterLeave()};if(f.shapeFlag&1&&R&&!R.persisted){const{leave:B,delayLeave:F}=R,$=()=>B(k,I);F?F(f.el,I,$):$()}else I()},xt=(f,g)=>{let k;for(;f!==g;)k=_(f),n(f),f=k;n(g)},ot=(f,g,k)=>{const{bum:T,scope:R,update:I,subTree:B,um:F}=f;T&&$i(T),R.stop(),I&&(I.active=!1,He(B,f,g,k)),F&&Ue(F,g),Ue(()=>{f.isUnmounted=!0},g),g&&g.pendingBranch&&!g.isUnmounted&&f.asyncDep&&!f.asyncResolved&&f.suspenseId===g.pendingId&&(g.deps--,g.deps===0&&g.resolve())},je=(f,g,k,T=!1,R=!1,I=0)=>{for(let B=I;Bf.shapeFlag&6?P(f.component.subTree):f.shapeFlag&128?f.suspense.next():_(f.anchor||f.el),z=(f,g,k)=>{f==null?g._vnode&&He(g._vnode,null,null,!0):x(g._vnode||null,f,g,null,null,null,k),ar(),pi(),g._vnode=f},M={p:x,um:He,m:ze,r:yt,mt:le,mc:E,pc:X,pbc:w,n:P,o:e};let Y,ae;return t&&([Y,ae]=t(M)),{render:z,hydrate:Y,createApp:Pa(z,Y)}}function Ft({effect:e,update:t},l){e.allowRecurse=t.allowRecurse=l}function ss(e,t){return(!e||e&&!e.pendingBranch)&&t&&!t.persisted}function cs(e,t,l=!1){const i=e.children,n=t.children;if(te(i)&&te(n))for(let r=0;r>1,e[l[c]]0&&(t[i]=l[r-1]),l[r]=i)}}for(r=l.length,o=l[r-1];r-- >0;)l[r]=o,o=t[o];return l}const Fa=e=>e.__isTeleport,ke=Symbol.for("v-fgt"),al=Symbol.for("v-txt"),Ye=Symbol.for("v-cmt"),Rl=Symbol.for("v-stc"),Il=[];let it=null;function W(e=!1){Il.push(it=e?null:[])}function Na(){Il.pop(),it=Il[Il.length-1]||null}let Fl=1;function Er(e){Fl+=e}function as(e){return e.dynamicChildren=Fl>0?it||il:null,Na(),Fl>0&&it&&it.push(e),e}function ee(e,t,l,i,n,r){return as(ce(e,t,l,i,n,r,!0))}function Ae(e,t,l,i,n){return as(ne(e,t,l,i,n,!0))}function xi(e){return e?e.__v_isVNode===!0:!1}function Bt(e,t){return e.type===t.type&&e.key===t.key}const Vi="__vInternal",us=({key:e})=>e??null,hi=({ref:e,ref_key:t,ref_for:l})=>(typeof e=="number"&&(e=""+e),e!=null?we(e)||Ne(e)||oe(e)?{i:Ve,r:e,k:t,f:!!l}:e:null);function ce(e,t=null,l=null,i=0,n=null,r=e===ke?0:1,o=!1,c=!1){const a={__v_isVNode:!0,__v_skip:!0,type:e,props:t,key:t&&us(t),ref:t&&hi(t),scopeId:Xo,slotScopeIds:null,children:l,component:null,suspense:null,ssContent:null,ssFallback:null,dirs:null,transition:null,el:null,anchor:null,target:null,targetAnchor:null,staticCount:0,shapeFlag:r,patchFlag:i,dynamicProps:n,dynamicChildren:null,appContext:null,ctx:Ve};return c?(Cn(a,l),r&128&&e.normalize(a)):l&&(a.shapeFlag|=we(l)?8:16),Fl>0&&!o&&it&&(a.patchFlag>0||r&6)&&a.patchFlag!==32&&it.push(a),a}const ne=Ha;function Ha(e,t=null,l=null,i=0,n=null,r=!1){if((!e||e===la)&&(e=Ye),xi(e)){const c=Ct(e,t,!0);return l&&Cn(c,l),Fl>0&&!r&&it&&(c.shapeFlag&6?it[it.indexOf(e)]=c:it.push(c)),c.patchFlag|=-2,c}if(Ya(e)&&(e=e.__vccOpts),t){t=Ma(t);let{class:c,style:a}=t;c&&!we(c)&&(t.class=$e(c)),Ee(a)&&(Vo(a)&&!te(a)&&(a=Ie({},a)),t.style=Wl(a))}const o=we(e)?1:na(e)?128:Fa(e)?64:Ee(e)?4:oe(e)?2:0;return ce(e,t,l,i,n,o,r,!0)}function Ma(e){return e?Vo(e)||Vi in e?Ie({},e):e:null}function Ct(e,t,l=!1){const{props:i,ref:n,patchFlag:r,children:o}=e,c=t?_n(i||{},t):i;return{__v_isVNode:!0,__v_skip:!0,type:e.type,props:c,key:c&&us(c),ref:t&&t.ref?l&&n?te(n)?n.concat(hi(t)):[n,hi(t)]:hi(t):n,scopeId:e.scopeId,slotScopeIds:e.slotScopeIds,children:o,target:e.target,targetAnchor:e.targetAnchor,staticCount:e.staticCount,shapeFlag:e.shapeFlag,patchFlag:t&&e.type!==ke?r===-1?16:r|16:r,dynamicProps:e.dynamicProps,dynamicChildren:e.dynamicChildren,appContext:e.appContext,dirs:e.dirs,transition:e.transition,component:e.component,suspense:e.suspense,ssContent:e.ssContent&&Ct(e.ssContent),ssFallback:e.ssFallback&&Ct(e.ssFallback),el:e.el,anchor:e.anchor,ctx:e.ctx,ce:e.ce}}function Vt(e=" ",t=0){return ne(al,null,e,t)}function $a(e,t){const l=ne(Rl,null,e);return l.staticCount=t,l}function Le(e="",t=!1){return t?(W(),Ae(Ye,null,e)):ne(Ye,null,e)}function tt(e){return e==null||typeof e=="boolean"?ne(Ye):te(e)?ne(ke,null,e.slice()):typeof e=="object"?wt(e):ne(al,null,String(e))}function wt(e){return e.el===null&&e.patchFlag!==-1||e.memo?e:Ct(e)}function Cn(e,t){let l=0;const{shapeFlag:i}=e;if(t==null)t=null;else if(te(t))l=16;else if(typeof t=="object")if(i&65){const n=t.default;n&&(n._c&&(n._d=!1),Cn(e,n()),n._c&&(n._d=!0));return}else{l=32;const n=t._;!n&&!(Vi in t)?t._ctx=Ve:n===3&&Ve&&(Ve.slots._===1?t._=1:(t._=2,e.patchFlag|=1024))}else oe(t)?(t={default:t,_ctx:Ve},l=32):(t=String(t),i&64?(l=16,t=[Vt(t)]):l=8);e.children=t,e.shapeFlag|=l}function _n(...e){const t={};for(let l=0;lRe||Ve;let Fn,Zt,yr="__VUE_INSTANCE_SETTERS__";(Zt=ln()[yr])||(Zt=ln()[yr]=[]),Zt.push(e=>Re=e),Fn=e=>{Zt.length>1?Zt.forEach(t=>t(e)):Zt[0](e)};const ul=e=>{Fn(e),e.scope.on()},qt=()=>{Re&&Re.scope.off(),Fn(null)};function ds(e){return e.vnode.shapeFlag&4}let dl=!1;function Ua(e,t=!1){dl=t;const{props:l,children:i}=e.vnode,n=ds(e);Aa(e,l,n,t),Ia(e,i);const r=n?Xa(e,t):void 0;return dl=!1,r}function Xa(e,t){const l=e.type;e.accessCache=Object.create(null),e.proxy=Fo(new Proxy(e.ctx,ka));const{setup:i}=l;if(i){const n=e.setupContext=i.length>1?qa(e):null;ul(e),gl();const r=Dt(i,e,0,[e.props,n]);if(pl(),qt(),bo(r)){if(r.then(qt,qt),t)return r.then(o=>{xr(e,o,t)}).catch(o=>{Ul(o,e,0)});e.asyncDep=r}else xr(e,r,t)}else hs(e,t)}function xr(e,t,l){oe(t)?e.type.__ssrInlineRender?e.ssrRender=t:e.render=t:Ee(t)&&(e.setupState=Mo(t)),hs(e,l)}let Lr;function hs(e,t,l){const i=e.type;if(!e.render){if(!t&&Lr&&!i.render){const n=i.template||jn(e).template;if(n){const{isCustomElement:r,compilerOptions:o}=e.appContext.config,{delimiters:c,compilerOptions:a}=i,u=Ie(Ie({isCustomElement:r,delimiters:c},o),a);i.render=Lr(n,u)}}e.render=i.render||ut}{ul(e),gl();try{Ea(e)}finally{pl(),qt()}}}function Ka(e){return e.attrsProxy||(e.attrsProxy=new Proxy(e.attrs,{get(t,l){return Xe(e,"get","$attrs"),t[l]}}))}function qa(e){const t=l=>{e.exposed=l||{}};return{get attrs(){return Ka(e)},slots:e.slots,emit:e.emit,expose:t}}function Fi(e){if(e.exposed)return e.exposeProxy||(e.exposeProxy=new Proxy(Mo(Fo(e.exposed)),{get(t,l){if(l in t)return t[l];if(l in wl)return wl[l](e)},has(t,l){return l in t||l in wl}}))}function Ga(e,t=!0){return oe(e)?e.displayName||e.name:e.name||t&&e.__name}function Ya(e){return oe(e)&&"__vccOpts"in e}const C=(e,t)=>zc(e,t,dl);function he(e,t,l){const i=arguments.length;return i===2?Ee(t)&&!te(t)?xi(t)?ne(e,null,[t]):ne(e,t):ne(e,null,t):(i>3?l=Array.prototype.slice.call(arguments,2):i===3&&xi(l)&&(l=[l]),ne(e,t,l))}const Ja=Symbol.for("v-scx"),Qa=()=>Te(Ja),Za="3.3.13",eu="http://www.w3.org/2000/svg",Wt=typeof document<"u"?document:null,Tr=Wt&&Wt.createElement("template"),tu={insert:(e,t,l)=>{t.insertBefore(e,l||null)},remove:e=>{const t=e.parentNode;t&&t.removeChild(e)},createElement:(e,t,l,i)=>{const n=t?Wt.createElementNS(eu,e):Wt.createElement(e,l?{is:l}:void 0);return e==="select"&&i&&i.multiple!=null&&n.setAttribute("multiple",i.multiple),n},createText:e=>Wt.createTextNode(e),createComment:e=>Wt.createComment(e),setText:(e,t)=>{e.nodeValue=t},setElementText:(e,t)=>{e.textContent=t},parentNode:e=>e.parentNode,nextSibling:e=>e.nextSibling,querySelector:e=>Wt.querySelector(e),setScopeId(e,t){e.setAttribute(t,"")},insertStaticContent(e,t,l,i,n,r){const o=l?l.previousSibling:t.lastChild;if(n&&(n===r||n.nextSibling))for(;t.insertBefore(n.cloneNode(!0),l),!(n===r||!(n=n.nextSibling)););else{Tr.innerHTML=i?`${e}`:e;const c=Tr.content;if(i){const a=c.firstChild;for(;a.firstChild;)c.appendChild(a.firstChild);c.removeChild(a)}t.insertBefore(c,l)}return[o?o.nextSibling:t.firstChild,l?l.previousSibling:t.lastChild]}},Ot="transition",El="animation",Nl=Symbol("_vtc"),Gl=(e,{slots:t})=>he(aa,lu(e),t);Gl.displayName="Transition";const vs={name:String,type:String,css:{type:Boolean,default:!0},duration:[String,Number,Object],enterFromClass:String,enterActiveClass:String,enterToClass:String,appearFromClass:String,appearActiveClass:String,appearToClass:String,leaveFromClass:String,leaveActiveClass:String,leaveToClass:String};Gl.props=Ie({},Go,vs);const Nt=(e,t=[])=>{te(e)?e.forEach(l=>l(...t)):e&&e(...t)},Or=e=>e?te(e)?e.some(t=>t.length>1):e.length>1:!1;function lu(e){const t={};for(const L in e)L in vs||(t[L]=e[L]);if(e.css===!1)return t;const{name:l="v",type:i,duration:n,enterFromClass:r=`${l}-enter-from`,enterActiveClass:o=`${l}-enter-active`,enterToClass:c=`${l}-enter-to`,appearFromClass:a=r,appearActiveClass:u=o,appearToClass:d=c,leaveFromClass:v=`${l}-leave-from`,leaveActiveClass:_=`${l}-leave-active`,leaveToClass:p=`${l}-leave-to`}=e,m=iu(n),x=m&&m[0],A=m&&m[1],{onBeforeEnter:D,onEnter:O,onEnterCancelled:b,onLeave:y,onLeaveCancelled:H,onBeforeAppear:G=D,onAppear:N=O,onAppearCancelled:E=b}=t,K=(L,V,le)=>{Ht(L,V?d:c),Ht(L,V?u:o),le&&le()},w=(L,V)=>{L._isLeaving=!1,Ht(L,v),Ht(L,p),Ht(L,_),V&&V()},U=L=>(V,le)=>{const ie=L?N:O,S=()=>K(V,L,le);Nt(ie,[V,S]),Pr(()=>{Ht(V,L?a:r),Pt(V,L?d:c),Or(ie)||Ar(V,i,x,S)})};return Ie(t,{onBeforeEnter(L){Nt(D,[L]),Pt(L,r),Pt(L,o)},onBeforeAppear(L){Nt(G,[L]),Pt(L,a),Pt(L,u)},onEnter:U(!1),onAppear:U(!0),onLeave(L,V){L._isLeaving=!0;const le=()=>w(L,V);Pt(L,v),ou(),Pt(L,_),Pr(()=>{L._isLeaving&&(Ht(L,v),Pt(L,p),Or(y)||Ar(L,i,A,le))}),Nt(y,[L,le])},onEnterCancelled(L){K(L,!1),Nt(b,[L])},onAppearCancelled(L){K(L,!0),Nt(E,[L])},onLeaveCancelled(L){w(L),Nt(H,[L])}})}function iu(e){if(e==null)return null;if(Ee(e))return[Ki(e.enter),Ki(e.leave)];{const t=Ki(e);return[t,t]}}function Ki(e){return oc(e)}function Pt(e,t){t.split(/\s+/).forEach(l=>l&&e.classList.add(l)),(e[Nl]||(e[Nl]=new Set)).add(t)}function Ht(e,t){t.split(/\s+/).forEach(i=>i&&e.classList.remove(i));const l=e[Nl];l&&(l.delete(t),l.size||(e[Nl]=void 0))}function Pr(e){requestAnimationFrame(()=>{requestAnimationFrame(e)})}let nu=0;function Ar(e,t,l,i){const n=e._endId=++nu,r=()=>{n===e._endId&&i()};if(l)return setTimeout(r,l);const{type:o,timeout:c,propCount:a}=ru(e,t);if(!o)return i();const u=o+"end";let d=0;const v=()=>{e.removeEventListener(u,_),r()},_=p=>{p.target===e&&++d>=a&&v()};setTimeout(()=>{d(l[m]||"").split(", "),n=i(`${Ot}Delay`),r=i(`${Ot}Duration`),o=wr(n,r),c=i(`${El}Delay`),a=i(`${El}Duration`),u=wr(c,a);let d=null,v=0,_=0;t===Ot?o>0&&(d=Ot,v=o,_=r.length):t===El?u>0&&(d=El,v=u,_=a.length):(v=Math.max(o,u),d=v>0?o>u?Ot:El:null,_=d?d===Ot?r.length:a.length:0);const p=d===Ot&&/\b(transform|all)(,|$)/.test(i(`${Ot}Property`).toString());return{type:d,timeout:v,propCount:_,hasTransform:p}}function wr(e,t){for(;e.lengthRr(l)+Rr(e[i])))}function Rr(e){return e==="auto"?0:Number(e.slice(0,-1).replace(",","."))*1e3}function ou(){return document.body.offsetHeight}function su(e,t,l){const i=e[Nl];i&&(t=(t?[t,...i]:[...i]).join(" ")),t==null?e.removeAttribute("class"):l?e.setAttribute("class",t):e.className=t}const Nn=Symbol("_vod"),Li={beforeMount(e,{value:t},{transition:l}){e[Nn]=e.style.display==="none"?"":e.style.display,l&&t?l.beforeEnter(e):yl(e,t)},mounted(e,{value:t},{transition:l}){l&&t&&l.enter(e)},updated(e,{value:t,oldValue:l},{transition:i}){!t!=!l&&(i?t?(i.beforeEnter(e),yl(e,!0),i.enter(e)):i.leave(e,()=>{yl(e,!1)}):yl(e,t))},beforeUnmount(e,{value:t}){yl(e,t)}};function yl(e,t){e.style.display=t?e[Nn]:"none"}const cu=Symbol("");function au(e,t,l){const i=e.style,n=we(l);if(l&&!n){if(t&&!we(t))for(const r in t)l[r]==null&&fn(i,r,"");for(const r in l)fn(i,r,l[r])}else{const r=i.display;if(n){if(t!==l){const o=i[cu];o&&(l+=";"+o),i.cssText=l}}else t&&e.removeAttribute("style");Nn in e&&(i.display=r)}}const Ir=/\s*!important$/;function fn(e,t,l){if(te(l))l.forEach(i=>fn(e,t,i));else if(l==null&&(l=""),t.startsWith("--"))e.setProperty(t,l);else{const i=uu(e,t);Ir.test(l)?e.setProperty(Jt(i),l.replace(Ir,""),"important"):e[i]=l}}const Dr=["Webkit","Moz","ms"],qi={};function uu(e,t){const l=qi[t];if(l)return l;let i=dt(t);if(i!=="filter"&&i in e)return qi[t]=i;i=Ai(i);for(let n=0;nGi||(pu.then(()=>Gi=0),Gi=Date.now());function bu(e,t){const l=i=>{if(!i._vts)i._vts=Date.now();else if(i._vts<=l.attached)return;Ze(ku(i,l.value),t,5,[i])};return l.value=e,l.attached=mu(),l}function ku(e,t){if(te(t)){const l=e.stopImmediatePropagation;return e.stopImmediatePropagation=()=>{l.call(e),e._stopped=!0},t.map(i=>n=>!n._stopped&&i&&i(n))}else return t}const Vr=e=>e.charCodeAt(0)===111&&e.charCodeAt(1)===110&&e.charCodeAt(2)>96&&e.charCodeAt(2)<123,Eu=(e,t,l,i,n=!1,r,o,c,a)=>{t==="class"?su(e,i,n):t==="style"?au(e,l,i):Bl(t)?kn(t)||fu(e,t,l,i,o):(t[0]==="."?(t=t.slice(1),!0):t[0]==="^"?(t=t.slice(1),!1):yu(e,t,i,n))?hu(e,t,i,r,o,c,a):(t==="true-value"?e._trueValue=i:t==="false-value"&&(e._falseValue=i),du(e,t,i,n))};function yu(e,t,l,i){if(i)return!!(t==="innerHTML"||t==="textContent"||t in e&&Vr(t)&&oe(l));if(t==="spellcheck"||t==="draggable"||t==="translate"||t==="form"||t==="list"&&e.tagName==="INPUT"||t==="type"&&e.tagName==="TEXTAREA")return!1;if(t==="width"||t==="height"){const n=e.tagName;if(n==="IMG"||n==="VIDEO"||n==="CANVAS"||n==="SOURCE")return!1}return Vr(t)&&we(l)?!1:t in e}const xu={esc:"escape",space:" ",up:"arrow-up",left:"arrow-left",right:"arrow-right",down:"arrow-down",delete:"backspace"},Lu=(e,t)=>{const l=e._withKeys||(e._withKeys={}),i=t.join(".");return l[i]||(l[i]=n=>{if(!("key"in n))return;const r=Jt(n.key);if(t.some(o=>o===r||xu[o]===r))return e(n)})},Tu=Ie({patchProp:Eu},tu);let Yi,Fr=!1;function Ou(){return Yi=Fr?Yi:Sa(Tu),Fr=!0,Yi}const Pu=(...e)=>{const t=Ou().createApp(...e),{mount:l}=t;return t.mount=i=>{const n=Au(i);if(n)return l(n,!0,n instanceof SVGElement)},t};function Au(e){return we(e)?document.querySelector(e):e}const wu="modulepreload",Ru=function(e){return"/"+e},Nr={},s=function(t,l,i){let n=Promise.resolve();return l&&l.length>0&&(document.getElementsByTagName("link"),n=Promise.all(l.map(r=>{if(r=Ru(r),r in Nr)return;Nr[r]=!0;const o=r.endsWith(".css"),c=o?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${r}"]${c}`))return;const a=document.createElement("link");if(a.rel=o?"stylesheet":wu,o||(a.as="script",a.crossOrigin=""),a.href=r,document.head.appendChild(a),o)return new Promise((u,d)=>{a.addEventListener("load",u),a.addEventListener("error",()=>d(new Error(`Unable to preload CSS for ${r}`)))})}))),n.then(()=>t()).catch(r=>{const o=new Event("vite:preloadError",{cancelable:!0});if(o.payload=r,window.dispatchEvent(o),!o.defaultPrevented)throw r})},Iu={"v-8daa1a0e":()=>s(()=>import("./index.html-DsdONe9B.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-aad48c6a":()=>s(()=>import("./news.html-Cw8MfCXZ.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-ba934fd8":()=>s(()=>import("./index.html-B2ETL5pY.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-41ade9da":()=>s(()=>import("./api.html-5y-QWEO9.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-83dedd38":()=>s(()=>import("./dns.html-BfPt-22g.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-192a19b9":()=>s(()=>import("./fakedns.html-BSHcVJMt.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-7f6279d8":()=>s(()=>import("./inbound.html-2Gs5XIZT.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-1d860c29":()=>s(()=>import("./log.html-DOIV41-g.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-fbaf47ec":()=>s(()=>import("./metrics.html-C1kvghj5.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-24956213":()=>s(()=>import("./observatory.html-Dkgoiajw.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-2367d756":()=>s(()=>import("./outbound.html-C10j64xi.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-4ebec35a":()=>s(()=>import("./policy.html-CErsqhDk.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-31b7756a":()=>s(()=>import("./reverse.html-BzUnx5j0.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-70677432":()=>s(()=>import("./routing.html-N1Zy6QRq.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-7e21d6ae":()=>s(()=>import("./stats.html-DHCl8ess.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-e3dfff38":()=>s(()=>import("./transport.html-CnZXw5hX.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-f7496066":()=>s(()=>import("./index.html-CTbMiGG2.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-36b1a79b":()=>s(()=>import("./index.html-CA-WluU-.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-09a64f89":()=>s(()=>import("./command.html-Sco1d_Iq.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-2b1adf48":()=>s(()=>import("./config.html-O0hv2z0b.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-86ee963a":()=>s(()=>import("./document.html-vroedGik.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-0e5d7b39":()=>s(()=>import("./install.html-CtHiKZjZ.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-2d0a870d":()=>s(()=>import("./index.html-BR6NUj4D.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-2d0ab8b3":()=>s(()=>import("./index.html-Cm8mQKPu.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-0d714d87":()=>s(()=>import("./browser_dialer.html-DYjgEhDN.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-0da7880a":()=>s(()=>import("./env.html-x3PGFNW0.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-2aeb21f9":()=>s(()=>import("./fallback.html-BCz8baOr.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-3acf20ea":()=>s(()=>import("./multiple.html-CA4IQdBs.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-792e28f8":()=>s(()=>import("./xtls.html-DTQkH1EU.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-b50d2334":()=>s(()=>import("./dokodemo.html-CwfBRGLx.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-593408b0":()=>s(()=>import("./http.html-BtBoaSJk.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-802a842a":()=>s(()=>import("./shadowsocks.html-Bog2IQ_X.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-29995cea":()=>s(()=>import("./socks.html-B_KFCfGa.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-2a1b3d72":()=>s(()=>import("./trojan.html-BkQCt-32.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-fb92e8aa":()=>s(()=>import("./vless.html-CxK3eXqB.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-167afaac":()=>s(()=>import("./vmess.html-BSAH9EwQ.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-5588d0cc":()=>s(()=>import("./wireguard.html-DI0HSIg5.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-749ad71a":()=>s(()=>import("./blackhole.html-C3j-gtFm.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-6d39b970":()=>s(()=>import("./dns.html-IaJfUMdl.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-d76e893a":()=>s(()=>import("./freedom.html-DFU9EbHR.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-c6b4b59e":()=>s(()=>import("./http.html-CqFywJ_o.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-41ec0e0e":()=>s(()=>import("./loopback.html-CYltRkS6.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-7b293e4a":()=>s(()=>import("./shadowsocks.html-BdSAub8s.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-15f5452a":()=>s(()=>import("./socks.html-C_Ryg_Zn.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-5797bdb3":()=>s(()=>import("./trojan.html-_aC10_zp.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-a60f016c":()=>s(()=>import("./vless.html-sPPpqcW_.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-413cee4b":()=>s(()=>import("./vmess.html-3bHG9IEs.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-208ca3b9":()=>s(()=>import("./wireguard.html-DMp0Htsq.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-2877542a":()=>s(()=>import("./grpc.html-BOwRBc6V.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-03a28284":()=>s(()=>import("./h2.html-B-_cdxSw.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-04158536":()=>s(()=>import("./httpupgrade.html-DNm5DiZb.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-3167b1dd":()=>s(()=>import("./mkcp.html-CmaMJX_Q.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-eeea2fb0":()=>s(()=>import("./splithttp.html-Cb2yAPj6.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-33b1b709":()=>s(()=>import("./tcp.html-tAb-Rdu-.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-1ff57bba":()=>s(()=>import("./websocket.html-J4zD0ZXr.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-6a9e8054":()=>s(()=>import("./compile.html-C08Er0mK.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-95e3eaea":()=>s(()=>import("./design.html-JvR3o2wW.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-61e7eea6":()=>s(()=>import("./guide.html-CIw6ZqK-.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-6e6c37e6":()=>s(()=>import("./mkcp.html-BECLirWp.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-13168a21":()=>s(()=>import("./muxcool.html-DxsTQuoq.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-5c48c82b":()=>s(()=>import("./vless.html-bx0zLtjU.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-1ee591a8":()=>s(()=>import("./vmess.html-DH5KSkx4.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-3f09dcfa":()=>s(()=>import("./index.html-CpLT_ZsY.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-fb444906":()=>s(()=>import("./ch01-preface.html-DmNJxKif.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-075f3ae5":()=>s(()=>import("./ch02-preparation.html-BTKGqj9u.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-726d0633":()=>s(()=>import("./ch03-ssh.html-Bs4sxOG7.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-430c6ab8":()=>s(()=>import("./ch04-security.html-BgZQf6Zy.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-717c6376":()=>s(()=>import("./ch05-webpage.html-C3ISjTL0.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-278039be":()=>s(()=>import("./ch06-certificates.html-g-a588dM.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-a0c7f88e":()=>s(()=>import("./ch07-xray-server.html-CL7ODUGu.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-86586ca2":()=>s(()=>import("./ch08-xray-clients.html-D0DH-0jR.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-3eb62514":()=>s(()=>import("./ch09-appendix.html-B-sOxmCt.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-3f09dcbc":()=>s(()=>import("./index.html-Z8xBvZ8J.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-b21a2a20":()=>s(()=>import("./fallbacks-lv1.html-Dyr_PhvB.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-da623318":()=>s(()=>import("./fallbacks-with-sni.html-V5VzGt_a.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-fdd722ac":()=>s(()=>import("./routing-lv1-part1.html-C-IzJ3qA.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-fa6d716e":()=>s(()=>import("./routing-lv1-part2.html-Shikx9Ih.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-2f29e106":()=>s(()=>import("./work.html-CEe4qs2X.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-3f09dc7e":()=>s(()=>import("./index.html-DC6-KGmE.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-1c17916e":()=>s(()=>import("./iptables_gid.html-BMSyFQlC.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-a001cfa6":()=>s(()=>import("./nginx_or_haproxy_tls_tunnel.html-pJln5JiT.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-46333b48":()=>s(()=>import("./redirect.html-qKHxqUqo.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-338bc63e":()=>s(()=>import("./tproxy.html-ByDe25dh.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-d68f7d58":()=>s(()=>import("./tproxy_ipv4_and_ipv6.html-D-5zdr32.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-e533e2c6":()=>s(()=>import("./traffic_stats.html-0T5V4GoX.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-1e465ab0":()=>s(()=>import("./warp.html-BDXJx2co.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-1080fb37":()=>s(()=>import("./news.html-CYLnHfpK.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-317fc580":()=>s(()=>import("./index.html-CVcFP_qj.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-45144c7f":()=>s(()=>import("./api.html-Kao4_KiT.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-23fbd2d0":()=>s(()=>import("./dns.html-CvTCwYNS.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-2b7ec525":()=>s(()=>import("./fakedns.html-Dvu3AZyj.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-5ab92300":()=>s(()=>import("./inbound.html-DMVoiGk7.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-f91d64d6":()=>s(()=>import("./log.html--3F9JN_2.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-d705f114":()=>s(()=>import("./metrics.html-BLJ8GVn6.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-5c8e777f":()=>s(()=>import("./observatory.html-CcNQ0eYH.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-268cd669":()=>s(()=>import("./outbound.html-CzOKWWkv.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-4492d567":()=>s(()=>import("./policy.html-C8ASaUzS.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-0d0e1e92":()=>s(()=>import("./reverse.html-BnnvxzqT.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-4bbe1d5a":()=>s(()=>import("./routing.html-zynaWMFD.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-16426d1a":()=>s(()=>import("./stats.html-DGZuatV1.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-5de780d0":()=>s(()=>import("./transport.html-j20KTFMX.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-f88d343e":()=>s(()=>import("./index.html-CFqc6OBy.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-38d56a07":()=>s(()=>import("./index.html-DFwA2xNy.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-4d046016":()=>s(()=>import("./command.html-B7s0-Piq.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-22b35270":()=>s(()=>import("./config.html-DrlSKA0W.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-30bd7c12":()=>s(()=>import("./document.html-CBY4dmVD.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-439608b6":()=>s(()=>import("./install.html-Vhx-_q7N.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-408e88d1":()=>s(()=>import("./news.html-BJEpDr2m.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-b1cce5cc":()=>s(()=>import("./index.html-Br3dj_2c.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-7521da19":()=>s(()=>import("./api.html-DLDnYtg0.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-5409606a":()=>s(()=>import("./dns.html-DfoiH0ad.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-5877f5bf":()=>s(()=>import("./fakedns.html-DFAPe69C.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-00c6c1cc":()=>s(()=>import("./inbound.html-7L6d18D5.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-990249a2":()=>s(()=>import("./log.html-DjmhB4xx.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-7d138fe0":()=>s(()=>import("./metrics.html-wNzErJVc.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-11e9cb19":()=>s(()=>import("./observatory.html-CQ1B9WMF.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-ce8c8de2":()=>s(()=>import("./outbound.html-BaSyw3Ug.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-3dc4298d":()=>s(()=>import("./policy.html-CZXmUkYI.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-26722151":()=>s(()=>import("./reverse.html-B5DaFRsx.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-071a21ed":()=>s(()=>import("./routing.html-C1g2i1zS.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-7922fc34":()=>s(()=>import("./stats.html-CkQuuoBx.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-3156f2ea":()=>s(()=>import("./transport.html-DfxqUj3F.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-40ee4e87":()=>s(()=>import("./index.html-BBMcLiPC.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-a1c899be":()=>s(()=>import("./index.html-B-J-mqnv.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-a6257be2":()=>s(()=>import("./command.html-CKVtMSxh.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-d63f95d4":()=>s(()=>import("./config.html-CpMF1H3m.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-fbbfd9c6":()=>s(()=>import("./document.html-Cv2iGxpB.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-9cb72482":()=>s(()=>import("./install.html-BUGXoodV.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-51a51d87":()=>s(()=>import("./transparent_proxy.html-DZNi96TQ.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-76b9a0f3":()=>s(()=>import("./browser_dialer.html-Bdbrov2m.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-565dbfc4":()=>s(()=>import("./env.html-kVBaIisu.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-0fbd1336":()=>s(()=>import("./fallback.html-Cz26Rtbk.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-a0627812":()=>s(()=>import("./multiple.html-672DYUik.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-d190d938":()=>s(()=>import("./xtls.html-enE-oLop.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-72afc2d2":()=>s(()=>import("./dokodemo.html-DpZKpCsl.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-773d731c":()=>s(()=>import("./http.html-CbEwhYAM.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-f555fc02":()=>s(()=>import("./shadowsocks.html-nKE9-JwE.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-e35196c2":()=>s(()=>import("./socks.html-BYoEVGSJ.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-29188644":()=>s(()=>import("./trojan.html-2VAwem9J.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-255a6ebf":()=>s(()=>import("./vless.html-BCCfQS7T.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-8cc24480":()=>s(()=>import("./vmess.html-DmF6uMmY.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-a2605ea4":()=>s(()=>import("./wireguard.html-BIApe7Jj.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-64e47ef4":()=>s(()=>import("./blackhole.html-Cv99Ln_e.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-e979b848":()=>s(()=>import("./dns.html-1tf_wTEw.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-617f0fcf":()=>s(()=>import("./freedom.html-CGstSPGu.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-3fc98845":()=>s(()=>import("./http.html-BW71su7G.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-1b804722":()=>s(()=>import("./loopback.html-DBZDnpde.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-63077cb6":()=>s(()=>import("./shadowsocks.html-Cfe33M9q.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-516476d4":()=>s(()=>import("./socks.html-ZsLxpdI_.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-7d61a872":()=>s(()=>import("./trojan.html-C_OdgAQH.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-6e50feb6":()=>s(()=>import("./vless.html-DNT9jIbN.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-02956db7":()=>s(()=>import("./vmess.html-BnKkO-oz.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-797f8d25":()=>s(()=>import("./wireguard.html-B1zHQq-E.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-2c6058d4":()=>s(()=>import("./grpc.html-D7nAIvyK.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-1c38292a":()=>s(()=>import("./h2.html-9I7eRGud.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-17ff144a":()=>s(()=>import("./httpupgrade.html-DpYANPWG.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-1a7f9d6e":()=>s(()=>import("./mkcp.html-D1BaSNsx.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-4df52c3c":()=>s(()=>import("./splithttp.html-DZKLCVFH.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-5254cbc6":()=>s(()=>import("./tcp.html-Dvv-qFsr.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-9520f392":()=>s(()=>import("./websocket.html-CDgG-JKn.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-b7760e2c":()=>s(()=>import("./compile.html-CSlVqiWd.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-fb774212":()=>s(()=>import("./design.html-CnO0gj1h.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-38c376c1":()=>s(()=>import("./guide.html-C1S7IA49.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-21bccd79":()=>s(()=>import("./mkcp.html-VU4-Z4x2.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-27001935":()=>s(()=>import("./muxcool.html-CEJDgOyw.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-21b30c3f":()=>s(()=>import("./vless.html-DH9DXlDy.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-94110980":()=>s(()=>import("./vmess.html-DRYwVgEC.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-789ba7ef":()=>s(()=>import("./index.html-B7FLw-wS.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-d3712ade":()=>s(()=>import("./ch01-preface.html-CpS2RBBO.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-41f9c00e":()=>s(()=>import("./ch02-preparation.html-nD3-r55P.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-4c013f47":()=>s(()=>import("./ch03-ssh.html-6Lvt6PUL.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-a75683b8":()=>s(()=>import("./ch04-security.html-B6qoKme-.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-f5341aec":()=>s(()=>import("./ch05-webpage.html-DzsY94d_.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-4458f72a":()=>s(()=>import("./ch06-certificates.html-Ddg6ioji.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-f1802e66":()=>s(()=>import("./ch07-xray-server.html-C13N5hD6.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-4ca6f1ca":()=>s(()=>import("./ch08-xray-clients.html-DQ22p1_O.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-b0030f00":()=>s(()=>import("./ch09-appendix.html-CgxfJw0n.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-789ba80e":()=>s(()=>import("./index.html-NEtYQEGC.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-103b3e5c":()=>s(()=>import("./fallbacks-lv1.html-DzqMpBvO.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-110dd688":()=>s(()=>import("./fallbacks-with-sni.html--6P9o5e1.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-c425a7d4":()=>s(()=>import("./routing-lv1-part1.html-CLrmD7am.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-c0bbf696":()=>s(()=>import("./routing-lv1-part2.html-BeZDTPEs.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-5b6477cc":()=>s(()=>import("./work.html-bZWwnav2.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-789ba82d":()=>s(()=>import("./index.html-CL_S8-vB.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-05ddc65d":()=>s(()=>import("./iptables_gid.html-C-yflUZU.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-474afe99":()=>s(()=>import("./nginx_or_haproxy_tls_tunnel.html-Gb-c4jql.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-930ac920":()=>s(()=>import("./redirect.html-CkD_E0gF.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-c579975c":()=>s(()=>import("./tproxy.html-BW6K5LzA.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-7efb7c68":()=>s(()=>import("./tproxy_ipv4_and_ipv6.html-BQJ6GusY.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-12a33bee":()=>s(()=>import("./traffic_stats.html-DD1S40Up.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-7d2b8478":()=>s(()=>import("./warp.html-C4DFBgRI.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-1cfb44e6":()=>s(()=>import("./browser_dialer.html-DHvZocHd.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-6a3f8078":()=>s(()=>import("./env.html-BcRLB4iC.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-74f22e7f":()=>s(()=>import("./fallback.html-BtkFw_Xq.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-2c9f7c11":()=>s(()=>import("./multiple.html-L9QltWwj.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-630c687e":()=>s(()=>import("./xtls.html-ByQJIYGC.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-20ff0a28":()=>s(()=>import("./dokodemo.html-6k4BnhfY.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-43124836":()=>s(()=>import("./http.html-CXH6I19f.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-6a351ba5":()=>s(()=>import("./shadowsocks.html-Dq6vO-NY.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-3d1d02c5":()=>s(()=>import("./socks.html-HP5cpkrw.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-1567b378":()=>s(()=>import("./trojan.html-ur2ZEK_x.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-57bf8636":()=>s(()=>import("./vless.html-Dp7gCWtk.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-6864abe6":()=>s(()=>import("./vmess.html-BtGpHvfz.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-67d3c858":()=>s(()=>import("./wireguard.html-DFWWl4Re.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-5910da20":()=>s(()=>import("./blackhole.html-DWoVmjiZ.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-5717f8f6":()=>s(()=>import("./dns.html-COClhUcF.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-4360702e":()=>s(()=>import("./freedom.html-BnDskwJS.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-22e1532a":()=>s(()=>import("./http.html-o0wpiHQf.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-38c69248":()=>s(()=>import("./loopback.html-BcZmhFf5.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-1a2a97d0":()=>s(()=>import("./shadowsocks.html-S-jhNF8h.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-0141bb30":()=>s(()=>import("./socks.html-zyIZHHJ4.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-544bef26":()=>s(()=>import("./trojan.html-2ngT_7cs.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-cf761560":()=>s(()=>import("./vless.html-CNa_dakW.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-2c896451":()=>s(()=>import("./vmess.html-D5q0vDPy.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-0502a6bf":()=>s(()=>import("./wireguard.html-DILhdRFk.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-13c3ca30":()=>s(()=>import("./grpc.html-1JoA2je9.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-2fe60378":()=>s(()=>import("./h2.html-BOxtTm8R.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-453f5c70":()=>s(()=>import("./httpupgrade.html-C5iPswVE.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-1cb427e3":()=>s(()=>import("./mkcp.html-DILru_l-.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-32d545e2":()=>s(()=>import("./splithttp.html-B8IT_7av.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-f4c92f7a":()=>s(()=>import("./tcp.html-BgZgnk7j.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-cb60c046":()=>s(()=>import("./websocket.html-DNoxTZYE.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-7ce977e0":()=>s(()=>import("./compile.html-D59MH5rf.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-01d5d1de":()=>s(()=>import("./design.html-Ddh8g14z.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-4d4e5367":()=>s(()=>import("./guide.html-BdEYZrHF.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-a58031da":()=>s(()=>import("./mkcp.html-DAmKBEn3.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-5440615b":()=>s(()=>import("./muxcool.html-mhoEooTk.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-069325e5":()=>s(()=>import("./vless.html-CkQDajpI.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-ca50d634":()=>s(()=>import("./vmess.html-DtwTJf0_.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-490791ee":()=>s(()=>import("./index.html-CpXf73_p.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-78f09a92":()=>s(()=>import("./ch01-preface.html-w7EJag-g.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-64f6e51f":()=>s(()=>import("./ch02-preparation.html-Dgjcbj9R.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-69478a6d":()=>s(()=>import("./ch03-ssh.html-SW0FgDU9.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-271d7abe":()=>s(()=>import("./ch04-security.html-DMyIYFbc.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-9ab38aa0":()=>s(()=>import("./ch05-webpage.html-BJ9Dh4eq.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-7cddd6c4":()=>s(()=>import("./ch06-certificates.html-CYpwWYQK.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-0d33adf3":()=>s(()=>import("./ch07-xray-server.html-BMC39V_R.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-123166b5":()=>s(()=>import("./ch08-xray-clients.html-SOUUSYfz.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-22c7351a":()=>s(()=>import("./ch09-appendix.html-CaY0Q2De.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-490791b0":()=>s(()=>import("./index.html-DIt_Qwmg.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-e9f80a14":()=>s(()=>import("./fallbacks-lv1.html-Cj8_C__Y.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-2db62ba4":()=>s(()=>import("./fallbacks-with-sni.html-UrPS3PK0.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-531be8a0":()=>s(()=>import("./routing-lv1-part1.html-CrCZge13.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-4fb23762":()=>s(()=>import("./routing-lv1-part2.html-BNHKIWxf.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-fdd8db80":()=>s(()=>import("./work.html-nNVb3F6P.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-49079172":()=>s(()=>import("./index.html-nyT_8_ff.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-331e0e83":()=>s(()=>import("./iptables_gid.html-5z8dtoE5.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-7418a5b3":()=>s(()=>import("./nginx_or_haproxy_tls_tunnel.html-CZEav5bi.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-587e32d4":()=>s(()=>import("./redirect.html-IdxcHO8c.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-9c63de10":()=>s(()=>import("./tproxy.html-BHj4GcZZ.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-a4c782e4":()=>s(()=>import("./tproxy_ipv4_and_ipv6.html-D9HsaVXj.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-71771ea3":()=>s(()=>import("./traffic_stats.html-D5bPdgjj.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-70300bea":()=>s(()=>import("./warp.html-Dj49TU1P.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-7689d7f3":()=>s(()=>import("./transparent_proxy.html-C4cGXidp.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-39b3c50d":()=>s(()=>import("./transparent_proxy.html-CdU0iNrm.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-3706649a":()=>s(()=>import("./404.html-CnfmQthm.js"),__vite__mapDeps([])).then(({data:e})=>e)},Du=JSON.parse('{"base":"/","lang":"en-US","title":"","description":"","head":[["link",{"rel":"icon","href":"/logo.png"}]],"locales":{"/":{"lang":"zh-CN","title":"Project X","description":"Xray 官方文档"},"/en/":{"lang":"en-US","title":"Project X","description":"Official document of Xray"},"/ru/":{"lang":"ru-RU","title":"Project X","description":"Официальная документация Xray"}}}');var ju=["link","meta","script","style","noscript","template"],Su=["title","base"],Cu=([e,t,l])=>Su.includes(e)?e:ju.includes(e)?e==="meta"&&t.name?`${e}.${t.name}`:e==="template"&&t.id?`${e}.${t.id}`:JSON.stringify([e,Object.entries(t).map(([i,n])=>typeof n=="boolean"?n?[i,""]:null:[i,n]).filter(i=>i!=null).sort(([i],[n])=>i.localeCompare(n)),l]):null,Vu=e=>{const t=new Set,l=[];return e.forEach(i=>{const n=Cu(i);n&&!t.has(n)&&(t.add(n),l.push(i))}),l},Yl=e=>/^(https?:)?\/\//.test(e),Fu=e=>/^[a-z][a-z0-9+.-]*:/.test(e),Hn=e=>Object.prototype.toString.call(e)==="[object Object]",_s=e=>e[e.length-1]==="/"?e.slice(0,-1):e,fs=e=>e[0]==="/"?e.slice(1):e,gs=(e,t)=>{const l=Object.keys(e).sort((i,n)=>{const r=n.split("/").length-i.split("/").length;return r!==0?r:n.length-i.length});for(const i of l)if(t.startsWith(i))return i;return"/"},Nu=e=>typeof e=="function",nt=e=>typeof e=="string";const ps={"v-8daa1a0e":h(()=>s(()=>import("./index.html-DOOHsyE6.js"),__vite__mapDeps([]))),"v-aad48c6a":h(()=>s(()=>import("./news.html-BeMBU7o5.js"),__vite__mapDeps([]))),"v-ba934fd8":h(()=>s(()=>import("./index.html-DZCwNSUw.js"),__vite__mapDeps([]))),"v-41ade9da":h(()=>s(()=>import("./api.html-CQYAnjeD.js"),__vite__mapDeps([]))),"v-83dedd38":h(()=>s(()=>import("./dns.html-LlEGGVq6.js"),__vite__mapDeps([]))),"v-192a19b9":h(()=>s(()=>import("./fakedns.html-Dy1ai5db.js"),__vite__mapDeps([]))),"v-7f6279d8":h(()=>s(()=>import("./inbound.html-BU0rgh7R.js"),__vite__mapDeps([]))),"v-1d860c29":h(()=>s(()=>import("./log.html-WdHz5f6a.js"),__vite__mapDeps([]))),"v-fbaf47ec":h(()=>s(()=>import("./metrics.html-JNEl1HLA.js"),__vite__mapDeps([]))),"v-24956213":h(()=>s(()=>import("./observatory.html-CYfqKbFA.js"),__vite__mapDeps([]))),"v-2367d756":h(()=>s(()=>import("./outbound.html-BpCUakwX.js"),__vite__mapDeps([]))),"v-4ebec35a":h(()=>s(()=>import("./policy.html-DmXgvAr6.js"),__vite__mapDeps([]))),"v-31b7756a":h(()=>s(()=>import("./reverse.html-7Uo0yIWr.js"),__vite__mapDeps([]))),"v-70677432":h(()=>s(()=>import("./routing.html-CPw6r5Sh.js"),__vite__mapDeps([]))),"v-7e21d6ae":h(()=>s(()=>import("./stats.html-Bx0KYi9t.js"),__vite__mapDeps([]))),"v-e3dfff38":h(()=>s(()=>import("./transport.html-CBxA3wPn.js"),__vite__mapDeps([]))),"v-f7496066":h(()=>s(()=>import("./index.html-DaFDB0pu.js"),__vite__mapDeps([]))),"v-36b1a79b":h(()=>s(()=>import("./index.html-CbpQ50tV.js"),__vite__mapDeps([]))),"v-09a64f89":h(()=>s(()=>import("./command.html-BD6DsLl0.js"),__vite__mapDeps([]))),"v-2b1adf48":h(()=>s(()=>import("./config.html-BQlgOjHP.js"),__vite__mapDeps([]))),"v-86ee963a":h(()=>s(()=>import("./document.html-CL3-jl55.js"),__vite__mapDeps([]))),"v-0e5d7b39":h(()=>s(()=>import("./install.html-CDzfP6zr.js"),__vite__mapDeps([]))),"v-2d0a870d":h(()=>s(()=>import("./index.html-DgnGOa7Z.js"),__vite__mapDeps([]))),"v-2d0ab8b3":h(()=>s(()=>import("./index.html-BjEZWu-b.js"),__vite__mapDeps([]))),"v-0d714d87":h(()=>s(()=>import("./browser_dialer.html-C44hFL-t.js"),__vite__mapDeps([]))),"v-0da7880a":h(()=>s(()=>import("./env.html-D3uMVVBG.js"),__vite__mapDeps([]))),"v-2aeb21f9":h(()=>s(()=>import("./fallback.html-CEhYGCcm.js"),__vite__mapDeps([]))),"v-3acf20ea":h(()=>s(()=>import("./multiple.html-CyWT5XGQ.js"),__vite__mapDeps([]))),"v-792e28f8":h(()=>s(()=>import("./xtls.html-DkIUVXSC.js"),__vite__mapDeps([]))),"v-b50d2334":h(()=>s(()=>import("./dokodemo.html-LPhond1Y.js"),__vite__mapDeps([]))),"v-593408b0":h(()=>s(()=>import("./http.html-BiHwk-wd.js"),__vite__mapDeps([]))),"v-802a842a":h(()=>s(()=>import("./shadowsocks.html-Dqj7OTrt.js"),__vite__mapDeps([]))),"v-29995cea":h(()=>s(()=>import("./socks.html-BjLWN2Q8.js"),__vite__mapDeps([]))),"v-2a1b3d72":h(()=>s(()=>import("./trojan.html-_w6ndVja.js"),__vite__mapDeps([]))),"v-fb92e8aa":h(()=>s(()=>import("./vless.html-kZ8IonU8.js"),__vite__mapDeps([]))),"v-167afaac":h(()=>s(()=>import("./vmess.html-RimzC-nX.js"),__vite__mapDeps([]))),"v-5588d0cc":h(()=>s(()=>import("./wireguard.html-CTyw04SG.js"),__vite__mapDeps([]))),"v-749ad71a":h(()=>s(()=>import("./blackhole.html-CguJu2fJ.js"),__vite__mapDeps([]))),"v-6d39b970":h(()=>s(()=>import("./dns.html-36NnIjPg.js"),__vite__mapDeps([]))),"v-d76e893a":h(()=>s(()=>import("./freedom.html-B_annG2n.js"),__vite__mapDeps([]))),"v-c6b4b59e":h(()=>s(()=>import("./http.html-Y4HdDC5h.js"),__vite__mapDeps([]))),"v-41ec0e0e":h(()=>s(()=>import("./loopback.html-o32NwpT2.js"),__vite__mapDeps([]))),"v-7b293e4a":h(()=>s(()=>import("./shadowsocks.html-Dn_DI_z1.js"),__vite__mapDeps([]))),"v-15f5452a":h(()=>s(()=>import("./socks.html-BqrlqbK0.js"),__vite__mapDeps([]))),"v-5797bdb3":h(()=>s(()=>import("./trojan.html-C2P8Dv-p.js"),__vite__mapDeps([]))),"v-a60f016c":h(()=>s(()=>import("./vless.html-B6mgaUnb.js"),__vite__mapDeps([]))),"v-413cee4b":h(()=>s(()=>import("./vmess.html-C2MIBK-h.js"),__vite__mapDeps([]))),"v-208ca3b9":h(()=>s(()=>import("./wireguard.html-BSlNcaJF.js"),__vite__mapDeps([]))),"v-2877542a":h(()=>s(()=>import("./grpc.html-DKDNkwiH.js"),__vite__mapDeps([]))),"v-03a28284":h(()=>s(()=>import("./h2.html-DKeq75z1.js"),__vite__mapDeps([]))),"v-04158536":h(()=>s(()=>import("./httpupgrade.html-BP4DQ20m.js"),__vite__mapDeps([]))),"v-3167b1dd":h(()=>s(()=>import("./mkcp.html-B5Aq1d1a.js"),__vite__mapDeps([]))),"v-eeea2fb0":h(()=>s(()=>import("./splithttp.html-CyHPUrRH.js"),__vite__mapDeps([]))),"v-33b1b709":h(()=>s(()=>import("./tcp.html-Cxfh7siK.js"),__vite__mapDeps([]))),"v-1ff57bba":h(()=>s(()=>import("./websocket.html-DvhOz-O4.js"),__vite__mapDeps([]))),"v-6a9e8054":h(()=>s(()=>import("./compile.html-BaQu-P3E.js"),__vite__mapDeps([]))),"v-95e3eaea":h(()=>s(()=>import("./design.html-DiDr282f.js"),__vite__mapDeps([]))),"v-61e7eea6":h(()=>s(()=>import("./guide.html-Ce6Zjox0.js"),__vite__mapDeps([]))),"v-6e6c37e6":h(()=>s(()=>import("./mkcp.html-BXKgWezP.js"),__vite__mapDeps([]))),"v-13168a21":h(()=>s(()=>import("./muxcool.html-CiEIIjvK.js"),__vite__mapDeps([]))),"v-5c48c82b":h(()=>s(()=>import("./vless.html-BYWxnSoj.js"),__vite__mapDeps([]))),"v-1ee591a8":h(()=>s(()=>import("./vmess.html-D8plPLT5.js"),__vite__mapDeps([]))),"v-3f09dcfa":h(()=>s(()=>import("./index.html-1dnJ9JdM.js"),__vite__mapDeps([]))),"v-fb444906":h(()=>s(()=>import("./ch01-preface.html-B45aaai4.js"),__vite__mapDeps([]))),"v-075f3ae5":h(()=>s(()=>import("./ch02-preparation.html-CTibWJno.js"),__vite__mapDeps([]))),"v-726d0633":h(()=>s(()=>import("./ch03-ssh.html-ChZfg0hU.js"),__vite__mapDeps([]))),"v-430c6ab8":h(()=>s(()=>import("./ch04-security.html-BxNi21Mp.js"),__vite__mapDeps([]))),"v-717c6376":h(()=>s(()=>import("./ch05-webpage.html-D5rnT9ca.js"),__vite__mapDeps([]))),"v-278039be":h(()=>s(()=>import("./ch06-certificates.html-INcZvyys.js"),__vite__mapDeps([]))),"v-a0c7f88e":h(()=>s(()=>import("./ch07-xray-server.html-BkxuKbOE.js"),__vite__mapDeps([]))),"v-86586ca2":h(()=>s(()=>import("./ch08-xray-clients.html-D4O5No-H.js"),__vite__mapDeps([]))),"v-3eb62514":h(()=>s(()=>import("./ch09-appendix.html-Z0-Hyrvi.js"),__vite__mapDeps([]))),"v-3f09dcbc":h(()=>s(()=>import("./index.html-D8QPUz8j.js"),__vite__mapDeps([]))),"v-b21a2a20":h(()=>s(()=>import("./fallbacks-lv1.html-BJFkz_Io.js"),__vite__mapDeps([]))),"v-da623318":h(()=>s(()=>import("./fallbacks-with-sni.html-tnl-ymRI.js"),__vite__mapDeps([]))),"v-fdd722ac":h(()=>s(()=>import("./routing-lv1-part1.html-BYLEkwqC.js"),__vite__mapDeps([]))),"v-fa6d716e":h(()=>s(()=>import("./routing-lv1-part2.html-DNcAgdJC.js"),__vite__mapDeps([]))),"v-2f29e106":h(()=>s(()=>import("./work.html-CmqVWG7K.js"),__vite__mapDeps([]))),"v-3f09dc7e":h(()=>s(()=>import("./index.html-Dw7aezrN.js"),__vite__mapDeps([]))),"v-1c17916e":h(()=>s(()=>import("./iptables_gid.html-CD1EfJBO.js"),__vite__mapDeps([]))),"v-a001cfa6":h(()=>s(()=>import("./nginx_or_haproxy_tls_tunnel.html-ojUDrBVB.js"),__vite__mapDeps([]))),"v-46333b48":h(()=>s(()=>import("./redirect.html-B5Y1mNVs.js"),__vite__mapDeps([]))),"v-338bc63e":h(()=>s(()=>import("./tproxy.html-CVfbj2d5.js"),__vite__mapDeps([]))),"v-d68f7d58":h(()=>s(()=>import("./tproxy_ipv4_and_ipv6.html-CpYyYPCl.js"),__vite__mapDeps([]))),"v-e533e2c6":h(()=>s(()=>import("./traffic_stats.html-DsMiCXCX.js"),__vite__mapDeps([]))),"v-1e465ab0":h(()=>s(()=>import("./warp.html-mob0uukM.js"),__vite__mapDeps([]))),"v-1080fb37":h(()=>s(()=>import("./news.html-BZwUtxlV.js"),__vite__mapDeps([]))),"v-317fc580":h(()=>s(()=>import("./index.html-Dvi2iZCq.js"),__vite__mapDeps([]))),"v-45144c7f":h(()=>s(()=>import("./api.html-D47_38rn.js"),__vite__mapDeps([]))),"v-23fbd2d0":h(()=>s(()=>import("./dns.html-DXkA41xv.js"),__vite__mapDeps([]))),"v-2b7ec525":h(()=>s(()=>import("./fakedns.html-CTFi8abb.js"),__vite__mapDeps([]))),"v-5ab92300":h(()=>s(()=>import("./inbound.html-7zvu4h9X.js"),__vite__mapDeps([]))),"v-f91d64d6":h(()=>s(()=>import("./log.html-DnBUJw34.js"),__vite__mapDeps([]))),"v-d705f114":h(()=>s(()=>import("./metrics.html-DaweKFfI.js"),__vite__mapDeps([]))),"v-5c8e777f":h(()=>s(()=>import("./observatory.html-BL0BAmEr.js"),__vite__mapDeps([]))),"v-268cd669":h(()=>s(()=>import("./outbound.html-lqQ_d0C5.js"),__vite__mapDeps([]))),"v-4492d567":h(()=>s(()=>import("./policy.html-CA7G3Iy7.js"),__vite__mapDeps([]))),"v-0d0e1e92":h(()=>s(()=>import("./reverse.html-CpkNXRut.js"),__vite__mapDeps([]))),"v-4bbe1d5a":h(()=>s(()=>import("./routing.html-BzSZN0AZ.js"),__vite__mapDeps([]))),"v-16426d1a":h(()=>s(()=>import("./stats.html-2bJtqbfP.js"),__vite__mapDeps([]))),"v-5de780d0":h(()=>s(()=>import("./transport.html-B2ArwUNN.js"),__vite__mapDeps([]))),"v-f88d343e":h(()=>s(()=>import("./index.html-DKW9Z_BK.js"),__vite__mapDeps([]))),"v-38d56a07":h(()=>s(()=>import("./index.html-CZxj-MAp.js"),__vite__mapDeps([]))),"v-4d046016":h(()=>s(()=>import("./command.html-BeR19Y5B.js"),__vite__mapDeps([]))),"v-22b35270":h(()=>s(()=>import("./config.html-Cx5EaDWl.js"),__vite__mapDeps([]))),"v-30bd7c12":h(()=>s(()=>import("./document.html-djabafZA.js"),__vite__mapDeps([]))),"v-439608b6":h(()=>s(()=>import("./install.html-DrULhBgt.js"),__vite__mapDeps([]))),"v-408e88d1":h(()=>s(()=>import("./news.html-BzYbyEWd.js"),__vite__mapDeps([]))),"v-b1cce5cc":h(()=>s(()=>import("./index.html-C4GmwqWT.js"),__vite__mapDeps([]))),"v-7521da19":h(()=>s(()=>import("./api.html-By3Hi2cL.js"),__vite__mapDeps([]))),"v-5409606a":h(()=>s(()=>import("./dns.html-DAIzKfOg.js"),__vite__mapDeps([]))),"v-5877f5bf":h(()=>s(()=>import("./fakedns.html-D0qX2V-i.js"),__vite__mapDeps([]))),"v-00c6c1cc":h(()=>s(()=>import("./inbound.html-CPFBK2Je.js"),__vite__mapDeps([]))),"v-990249a2":h(()=>s(()=>import("./log.html-D-t8wlxQ.js"),__vite__mapDeps([]))),"v-7d138fe0":h(()=>s(()=>import("./metrics.html-CgPI3fiS.js"),__vite__mapDeps([]))),"v-11e9cb19":h(()=>s(()=>import("./observatory.html-i7tnhJjx.js"),__vite__mapDeps([]))),"v-ce8c8de2":h(()=>s(()=>import("./outbound.html-DVewdwtU.js"),__vite__mapDeps([]))),"v-3dc4298d":h(()=>s(()=>import("./policy.html-CzEm0fhQ.js"),__vite__mapDeps([]))),"v-26722151":h(()=>s(()=>import("./reverse.html-CfQGiukd.js"),__vite__mapDeps([]))),"v-071a21ed":h(()=>s(()=>import("./routing.html-DxkdJQtA.js"),__vite__mapDeps([]))),"v-7922fc34":h(()=>s(()=>import("./stats.html-Bm3zQ0hO.js"),__vite__mapDeps([]))),"v-3156f2ea":h(()=>s(()=>import("./transport.html-7DOFUUXD.js"),__vite__mapDeps([]))),"v-40ee4e87":h(()=>s(()=>import("./index.html-CEGHaj0m.js"),__vite__mapDeps([]))),"v-a1c899be":h(()=>s(()=>import("./index.html-DdCQTcSZ.js"),__vite__mapDeps([]))),"v-a6257be2":h(()=>s(()=>import("./command.html-DwCdhhuq.js"),__vite__mapDeps([]))),"v-d63f95d4":h(()=>s(()=>import("./config.html-ByKuPk47.js"),__vite__mapDeps([]))),"v-fbbfd9c6":h(()=>s(()=>import("./document.html-XdgZ3aKf.js"),__vite__mapDeps([]))),"v-9cb72482":h(()=>s(()=>import("./install.html-6LqhKuK1.js"),__vite__mapDeps([]))),"v-51a51d87":h(()=>s(()=>import("./transparent_proxy.html-BipaDG8r.js"),__vite__mapDeps([]))),"v-76b9a0f3":h(()=>s(()=>import("./browser_dialer.html-B6OwvO3Q.js"),__vite__mapDeps([]))),"v-565dbfc4":h(()=>s(()=>import("./env.html-CY9_QX-K.js"),__vite__mapDeps([]))),"v-0fbd1336":h(()=>s(()=>import("./fallback.html-BEtjGlT0.js"),__vite__mapDeps([]))),"v-a0627812":h(()=>s(()=>import("./multiple.html-D008nLUw.js"),__vite__mapDeps([]))),"v-d190d938":h(()=>s(()=>import("./xtls.html-7ni9fSNN.js"),__vite__mapDeps([]))),"v-72afc2d2":h(()=>s(()=>import("./dokodemo.html-BjerEOtA.js"),__vite__mapDeps([]))),"v-773d731c":h(()=>s(()=>import("./http.html-DopHzb3b.js"),__vite__mapDeps([]))),"v-f555fc02":h(()=>s(()=>import("./shadowsocks.html-1_shLAxP.js"),__vite__mapDeps([]))),"v-e35196c2":h(()=>s(()=>import("./socks.html-CdTGmIt-.js"),__vite__mapDeps([]))),"v-29188644":h(()=>s(()=>import("./trojan.html-CeUnbQFN.js"),__vite__mapDeps([]))),"v-255a6ebf":h(()=>s(()=>import("./vless.html-BnbvG0no.js"),__vite__mapDeps([]))),"v-8cc24480":h(()=>s(()=>import("./vmess.html-Btr59-Cl.js"),__vite__mapDeps([]))),"v-a2605ea4":h(()=>s(()=>import("./wireguard.html-C7TRB15X.js"),__vite__mapDeps([]))),"v-64e47ef4":h(()=>s(()=>import("./blackhole.html-Cllw1jwu.js"),__vite__mapDeps([]))),"v-e979b848":h(()=>s(()=>import("./dns.html-TjxOpc7L.js"),__vite__mapDeps([]))),"v-617f0fcf":h(()=>s(()=>import("./freedom.html-C35JVucM.js"),__vite__mapDeps([]))),"v-3fc98845":h(()=>s(()=>import("./http.html-BST5YIxM.js"),__vite__mapDeps([]))),"v-1b804722":h(()=>s(()=>import("./loopback.html-CBRQTJB4.js"),__vite__mapDeps([]))),"v-63077cb6":h(()=>s(()=>import("./shadowsocks.html-nM24MAPY.js"),__vite__mapDeps([]))),"v-516476d4":h(()=>s(()=>import("./socks.html-Cf97X7VI.js"),__vite__mapDeps([]))),"v-7d61a872":h(()=>s(()=>import("./trojan.html-DekTkRrf.js"),__vite__mapDeps([]))),"v-6e50feb6":h(()=>s(()=>import("./vless.html-BCUjxVGw.js"),__vite__mapDeps([]))),"v-02956db7":h(()=>s(()=>import("./vmess.html-CDBIkJMN.js"),__vite__mapDeps([]))),"v-797f8d25":h(()=>s(()=>import("./wireguard.html-B6z9zn0C.js"),__vite__mapDeps([]))),"v-2c6058d4":h(()=>s(()=>import("./grpc.html-C-k3ZkUy.js"),__vite__mapDeps([]))),"v-1c38292a":h(()=>s(()=>import("./h2.html-DfcDyfAy.js"),__vite__mapDeps([]))),"v-17ff144a":h(()=>s(()=>import("./httpupgrade.html-BD23lJKx.js"),__vite__mapDeps([]))),"v-1a7f9d6e":h(()=>s(()=>import("./mkcp.html-C779sbex.js"),__vite__mapDeps([]))),"v-4df52c3c":h(()=>s(()=>import("./splithttp.html-BE0bqGcK.js"),__vite__mapDeps([]))),"v-5254cbc6":h(()=>s(()=>import("./tcp.html-HofSOy7q.js"),__vite__mapDeps([]))),"v-9520f392":h(()=>s(()=>import("./websocket.html-2zGXYi2c.js"),__vite__mapDeps([]))),"v-b7760e2c":h(()=>s(()=>import("./compile.html-sA6hddT4.js"),__vite__mapDeps([]))),"v-fb774212":h(()=>s(()=>import("./design.html-CPqW5c51.js"),__vite__mapDeps([]))),"v-38c376c1":h(()=>s(()=>import("./guide.html-CumYazlz.js"),__vite__mapDeps([]))),"v-21bccd79":h(()=>s(()=>import("./mkcp.html-JU6IuAPN.js"),__vite__mapDeps([]))),"v-27001935":h(()=>s(()=>import("./muxcool.html-DTO-WOrE.js"),__vite__mapDeps([]))),"v-21b30c3f":h(()=>s(()=>import("./vless.html-CeF81Ekr.js"),__vite__mapDeps([]))),"v-94110980":h(()=>s(()=>import("./vmess.html-B3TZl91-.js"),__vite__mapDeps([]))),"v-789ba7ef":h(()=>s(()=>import("./index.html-CoQcU5ho.js"),__vite__mapDeps([]))),"v-d3712ade":h(()=>s(()=>import("./ch01-preface.html-DOL1zdys.js"),__vite__mapDeps([]))),"v-41f9c00e":h(()=>s(()=>import("./ch02-preparation.html-D2OoAhSr.js"),__vite__mapDeps([]))),"v-4c013f47":h(()=>s(()=>import("./ch03-ssh.html-DYiYMrsa.js"),__vite__mapDeps([]))),"v-a75683b8":h(()=>s(()=>import("./ch04-security.html-DF1Uapzz.js"),__vite__mapDeps([]))),"v-f5341aec":h(()=>s(()=>import("./ch05-webpage.html-BX0vFLsv.js"),__vite__mapDeps([]))),"v-4458f72a":h(()=>s(()=>import("./ch06-certificates.html-B4kZdJAn.js"),__vite__mapDeps([]))),"v-f1802e66":h(()=>s(()=>import("./ch07-xray-server.html-DacKAZFX.js"),__vite__mapDeps([]))),"v-4ca6f1ca":h(()=>s(()=>import("./ch08-xray-clients.html-djwoDk-t.js"),__vite__mapDeps([]))),"v-b0030f00":h(()=>s(()=>import("./ch09-appendix.html-CAGkKWfM.js"),__vite__mapDeps([]))),"v-789ba80e":h(()=>s(()=>import("./index.html-C7UV3jAp.js"),__vite__mapDeps([]))),"v-103b3e5c":h(()=>s(()=>import("./fallbacks-lv1.html-D3I9arTU.js"),__vite__mapDeps([]))),"v-110dd688":h(()=>s(()=>import("./fallbacks-with-sni.html-DtIkqYxV.js"),__vite__mapDeps([]))),"v-c425a7d4":h(()=>s(()=>import("./routing-lv1-part1.html-nqov9OAV.js"),__vite__mapDeps([]))),"v-c0bbf696":h(()=>s(()=>import("./routing-lv1-part2.html-DlBr3dUB.js"),__vite__mapDeps([]))),"v-5b6477cc":h(()=>s(()=>import("./work.html-BzVygHoH.js"),__vite__mapDeps([]))),"v-789ba82d":h(()=>s(()=>import("./index.html-D8JovJUC.js"),__vite__mapDeps([]))),"v-05ddc65d":h(()=>s(()=>import("./iptables_gid.html-CA7RPeCB.js"),__vite__mapDeps([]))),"v-474afe99":h(()=>s(()=>import("./nginx_or_haproxy_tls_tunnel.html-DR7z7Hc7.js"),__vite__mapDeps([]))),"v-930ac920":h(()=>s(()=>import("./redirect.html-VwFhzSui.js"),__vite__mapDeps([]))),"v-c579975c":h(()=>s(()=>import("./tproxy.html-CR4rpIqz.js"),__vite__mapDeps([]))),"v-7efb7c68":h(()=>s(()=>import("./tproxy_ipv4_and_ipv6.html-D1QYhYGk.js"),__vite__mapDeps([]))),"v-12a33bee":h(()=>s(()=>import("./traffic_stats.html-B_7LVx9s.js"),__vite__mapDeps([]))),"v-7d2b8478":h(()=>s(()=>import("./warp.html-CqXxUSeb.js"),__vite__mapDeps([]))),"v-1cfb44e6":h(()=>s(()=>import("./browser_dialer.html-ClnZpsOW.js"),__vite__mapDeps([]))),"v-6a3f8078":h(()=>s(()=>import("./env.html-BJIm3TxY.js"),__vite__mapDeps([]))),"v-74f22e7f":h(()=>s(()=>import("./fallback.html-DhKkR0oG.js"),__vite__mapDeps([]))),"v-2c9f7c11":h(()=>s(()=>import("./multiple.html-D1DFWDpc.js"),__vite__mapDeps([]))),"v-630c687e":h(()=>s(()=>import("./xtls.html-CX-lgDou.js"),__vite__mapDeps([]))),"v-20ff0a28":h(()=>s(()=>import("./dokodemo.html-DEix7lbM.js"),__vite__mapDeps([]))),"v-43124836":h(()=>s(()=>import("./http.html-BV-A6WLZ.js"),__vite__mapDeps([]))),"v-6a351ba5":h(()=>s(()=>import("./shadowsocks.html-B_N0lWJn.js"),__vite__mapDeps([]))),"v-3d1d02c5":h(()=>s(()=>import("./socks.html-CXgansFd.js"),__vite__mapDeps([]))),"v-1567b378":h(()=>s(()=>import("./trojan.html-DwB8yBqZ.js"),__vite__mapDeps([]))),"v-57bf8636":h(()=>s(()=>import("./vless.html-zQehtVf0.js"),__vite__mapDeps([]))),"v-6864abe6":h(()=>s(()=>import("./vmess.html-CktEh3JK.js"),__vite__mapDeps([]))),"v-67d3c858":h(()=>s(()=>import("./wireguard.html-CAQPxeg-.js"),__vite__mapDeps([]))),"v-5910da20":h(()=>s(()=>import("./blackhole.html-B1ejrmD3.js"),__vite__mapDeps([]))),"v-5717f8f6":h(()=>s(()=>import("./dns.html-aOkEAe83.js"),__vite__mapDeps([]))),"v-4360702e":h(()=>s(()=>import("./freedom.html-DxvEh0kc.js"),__vite__mapDeps([]))),"v-22e1532a":h(()=>s(()=>import("./http.html-CwukuwGj.js"),__vite__mapDeps([]))),"v-38c69248":h(()=>s(()=>import("./loopback.html-DKif3g9A.js"),__vite__mapDeps([]))),"v-1a2a97d0":h(()=>s(()=>import("./shadowsocks.html-BFqzUOKa.js"),__vite__mapDeps([]))),"v-0141bb30":h(()=>s(()=>import("./socks.html-D_fUXvUa.js"),__vite__mapDeps([]))),"v-544bef26":h(()=>s(()=>import("./trojan.html-xViDkd9I.js"),__vite__mapDeps([]))),"v-cf761560":h(()=>s(()=>import("./vless.html-oiH3sQfV.js"),__vite__mapDeps([]))),"v-2c896451":h(()=>s(()=>import("./vmess.html-DUx4NlE2.js"),__vite__mapDeps([]))),"v-0502a6bf":h(()=>s(()=>import("./wireguard.html-CtnQlY0W.js"),__vite__mapDeps([]))),"v-13c3ca30":h(()=>s(()=>import("./grpc.html-D7RhLn8X.js"),__vite__mapDeps([]))),"v-2fe60378":h(()=>s(()=>import("./h2.html-BBDDvcJa.js"),__vite__mapDeps([]))),"v-453f5c70":h(()=>s(()=>import("./httpupgrade.html-BlNHRqh5.js"),__vite__mapDeps([]))),"v-1cb427e3":h(()=>s(()=>import("./mkcp.html-DkNOr0bl.js"),__vite__mapDeps([]))),"v-32d545e2":h(()=>s(()=>import("./splithttp.html-Cs2Z785s.js"),__vite__mapDeps([]))),"v-f4c92f7a":h(()=>s(()=>import("./tcp.html-CwUsir3D.js"),__vite__mapDeps([]))),"v-cb60c046":h(()=>s(()=>import("./websocket.html-XpyUndOJ.js"),__vite__mapDeps([]))),"v-7ce977e0":h(()=>s(()=>import("./compile.html-B_SG4Rjg.js"),__vite__mapDeps([]))),"v-01d5d1de":h(()=>s(()=>import("./design.html-B_2qYX1J.js"),__vite__mapDeps([]))),"v-4d4e5367":h(()=>s(()=>import("./guide.html-BFvmPsJG.js"),__vite__mapDeps([]))),"v-a58031da":h(()=>s(()=>import("./mkcp.html-uDvBjn0p.js"),__vite__mapDeps([]))),"v-5440615b":h(()=>s(()=>import("./muxcool.html-C8vY0L1H.js"),__vite__mapDeps([]))),"v-069325e5":h(()=>s(()=>import("./vless.html-syxK1TrS.js"),__vite__mapDeps([]))),"v-ca50d634":h(()=>s(()=>import("./vmess.html-3nJoWs8G.js"),__vite__mapDeps([]))),"v-490791ee":h(()=>s(()=>import("./index.html-SiiWkWVt.js"),__vite__mapDeps([]))),"v-78f09a92":h(()=>s(()=>import("./ch01-preface.html-CTOjY6Js.js"),__vite__mapDeps([]))),"v-64f6e51f":h(()=>s(()=>import("./ch02-preparation.html-CBvgJlzh.js"),__vite__mapDeps([]))),"v-69478a6d":h(()=>s(()=>import("./ch03-ssh.html-Dm-1-GXk.js"),__vite__mapDeps([]))),"v-271d7abe":h(()=>s(()=>import("./ch04-security.html-Odh5MrhM.js"),__vite__mapDeps([]))),"v-9ab38aa0":h(()=>s(()=>import("./ch05-webpage.html-yQkzjvqw.js"),__vite__mapDeps([]))),"v-7cddd6c4":h(()=>s(()=>import("./ch06-certificates.html-DPu9Gv70.js"),__vite__mapDeps([]))),"v-0d33adf3":h(()=>s(()=>import("./ch07-xray-server.html-C8Y2-LpN.js"),__vite__mapDeps([]))),"v-123166b5":h(()=>s(()=>import("./ch08-xray-clients.html-CXbOJkkz.js"),__vite__mapDeps([]))),"v-22c7351a":h(()=>s(()=>import("./ch09-appendix.html-BLhf4FLL.js"),__vite__mapDeps([]))),"v-490791b0":h(()=>s(()=>import("./index.html-BWRtCA19.js"),__vite__mapDeps([]))),"v-e9f80a14":h(()=>s(()=>import("./fallbacks-lv1.html-djmxllKD.js"),__vite__mapDeps([]))),"v-2db62ba4":h(()=>s(()=>import("./fallbacks-with-sni.html-CV6F-_Vm.js"),__vite__mapDeps([]))),"v-531be8a0":h(()=>s(()=>import("./routing-lv1-part1.html-Byn2h66N.js"),__vite__mapDeps([]))),"v-4fb23762":h(()=>s(()=>import("./routing-lv1-part2.html-DfZ-Hwqj.js"),__vite__mapDeps([]))),"v-fdd8db80":h(()=>s(()=>import("./work.html-C4aNtZOg.js"),__vite__mapDeps([]))),"v-49079172":h(()=>s(()=>import("./index.html-BWQkkF3k.js"),__vite__mapDeps([]))),"v-331e0e83":h(()=>s(()=>import("./iptables_gid.html-DHq3P8hi.js"),__vite__mapDeps([]))),"v-7418a5b3":h(()=>s(()=>import("./nginx_or_haproxy_tls_tunnel.html-CYGy05Cb.js"),__vite__mapDeps([]))),"v-587e32d4":h(()=>s(()=>import("./redirect.html-C82dlL2o.js"),__vite__mapDeps([]))),"v-9c63de10":h(()=>s(()=>import("./tproxy.html-BuzTQD_L.js"),__vite__mapDeps([]))),"v-a4c782e4":h(()=>s(()=>import("./tproxy_ipv4_and_ipv6.html-BDAlrSaS.js"),__vite__mapDeps([]))),"v-71771ea3":h(()=>s(()=>import("./traffic_stats.html-BVpwRqGM.js"),__vite__mapDeps([]))),"v-70300bea":h(()=>s(()=>import("./warp.html-Ck2P9Tg0.js"),__vite__mapDeps([]))),"v-7689d7f3":h(()=>s(()=>import("./transparent_proxy.html-BjCgSdfC.js"),__vite__mapDeps([]))),"v-39b3c50d":h(()=>s(()=>import("./transparent_proxy.html-Dbpkmzp6.js"),__vite__mapDeps([]))),"v-3706649a":h(()=>s(()=>import("./404.html-B0Jvu-JI.js"),__vite__mapDeps([])))};var Hu=Symbol(""),ms=Symbol(""),Mu=Ri({key:"",path:"",title:"",lang:"",frontmatter:{},headers:[]}),Gt=()=>{const e=Te(ms);if(!e)throw new Error("pageData() is called without provider.");return e},bs=Symbol(""),pt=()=>{const e=Te(bs);if(!e)throw new Error("usePageFrontmatter() is called without provider.");return e},ks=Symbol(""),$u=()=>{const e=Te(ks);if(!e)throw new Error("usePageHead() is called without provider.");return e},Bu=Symbol(""),Es=Symbol(""),Wu=()=>{const e=Te(Es);if(!e)throw new Error("usePageLang() is called without provider.");return e},ys=Symbol(""),zu=()=>{const e=Te(ys);if(!e)throw new Error("usePageLayout() is called without provider.");return e},Uu=ge(Iu),Mn=Symbol(""),Jl=()=>{const e=Te(Mn);if(!e)throw new Error("useRouteLocale() is called without provider.");return e},ll=ge(Du),xs=()=>ll,Ls=Symbol(""),$n=()=>{const e=Te(Ls);if(!e)throw new Error("useSiteLocaleData() is called without provider.");return e},Xu=Symbol(""),Ku="Layout",qu="NotFound",vt=zl({resolveLayouts:e=>e.reduce((t,l)=>({...t,...l.layouts}),{}),resolvePageData:async e=>{const t=Uu.value[e];return await(t==null?void 0:t())??Mu},resolvePageFrontmatter:e=>e.frontmatter,resolvePageHead:(e,t,l)=>{const i=nt(t.description)?t.description:l.description,n=[...Array.isArray(t.head)?t.head:[],...l.head,["title",{},e],["meta",{name:"description",content:i}]];return Vu(n)},resolvePageHeadTitle:(e,t)=>[e.title,t.title].filter(l=>!!l).join(" | "),resolvePageLang:(e,t)=>e.lang||t.lang||"en-US",resolvePageLayout:(e,t)=>{let l;if(e.path){const i=e.frontmatter.layout;nt(i)?l=i:l=Ku}else l=qu;return t[l]},resolveRouteLocale:(e,t)=>gs(e,t),resolveSiteLocaleData:(e,t)=>{var l;return{...e,...e.locales[t],head:[...((l=e.locales[t])==null?void 0:l.head)??[],...e.head??[]]}}}),Bn=_e({name:"ClientOnly",setup(e,t){const l=ge(!1);return We(()=>{l.value=!0}),()=>{var i,n;return l.value?(n=(i=t.slots).default)==null?void 0:n.call(i):null}}}),Gu=_e({name:"Content",props:{pageKey:{type:String,required:!1,default:""}},setup(e){const t=Gt(),l=C(()=>ps[e.pageKey||t.value.key]);return()=>l.value?he(l.value):he("div","404 Not Found")}}),Et=(e={})=>e,Wn=e=>Yl(e)?e:`/${fs(e)}`;function Ts(e,t,l){var i,n,r;t===void 0&&(t=50),l===void 0&&(l={});var o=(i=l.isImmediate)!=null&&i,c=(n=l.callback)!=null&&n,a=l.maxWait,u=Date.now(),d=[];function v(){if(a!==void 0){var p=Date.now()-u;if(p+t>=a)return a-p}return t}var _=function(){var p=[].slice.call(arguments),m=this;return new Promise(function(x,A){var D=o&&r===void 0;if(r!==void 0&&clearTimeout(r),r=setTimeout(function(){if(r=void 0,u=Date.now(),!o){var b=e.apply(m,p);c&&c(b),d.forEach(function(y){return(0,y.resolve)(b)}),d=[]}},v()),D){var O=e.apply(m,p);return c&&c(O),x(O)}d.push({resolve:x,reject:A})})};return _.cancel=function(p){r!==void 0&&clearTimeout(r),d.forEach(function(m){return(0,m.reject)(p)}),d=[]},_}/*!
   * vue-router v4.3.2
   * (c) 2024 Eduardo San Martin Morote
   * @license MIT
@@ -7,7 +7,7 @@ Expects a CSS selector, a Node element, a NodeList or an array.
 See: https://github.com/francoischalifour/medium-zoom`)}},vh=function(t){var l=document.createElement("div");return l.classList.add("medium-zoom-overlay"),l.style.background=t,l},_h=function(t){var l=t.getBoundingClientRect(),i=l.top,n=l.left,r=l.width,o=l.height,c=t.cloneNode(),a=window.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop||0,u=window.pageXOffset||document.documentElement.scrollLeft||document.body.scrollLeft||0;return c.removeAttribute("id"),c.style.position="absolute",c.style.top=i+a+"px",c.style.left=n+u+"px",c.style.width=r+"px",c.style.height=o+"px",c.style.transform="",c},el=function(t,l){var i=Mt({bubbles:!1,cancelable:!1,detail:void 0},l);if(typeof window.CustomEvent=="function")return new CustomEvent(t,i);var n=document.createEvent("CustomEvent");return n.initCustomEvent(t,i.bubbles,i.cancelable,i.detail),n},fh=function e(t){var l=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{},i=window.Promise||function(L){function V(){}L(V,V)},n=function(L){var V=L.target;if(V===K){m();return}b.indexOf(V)!==-1&&x({target:V})},r=function(){if(!(H||!E.original)){var L=window.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop||0;Math.abs(G-L)>N.scrollOffset&&setTimeout(m,150)}},o=function(L){var V=L.key||L.keyCode;(V==="Escape"||V==="Esc"||V===27)&&m()},c=function(){var L=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},V=L;if(L.background&&(K.style.background=L.background),L.container&&L.container instanceof Object&&(V.container=Mt({},N.container,L.container)),L.template){var le=vi(L.template)?L.template:document.querySelector(L.template);V.template=le}return N=Mt({},N,V),b.forEach(function(ie){ie.dispatchEvent(el("medium-zoom:update",{detail:{zoom:w}}))}),w},a=function(){var L=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{};return e(Mt({},N,L))},u=function(){for(var L=arguments.length,V=Array(L),le=0;le0?V.reduce(function(S,J){return[].concat(S,no(J))},[]):b;return ie.forEach(function(S){S.classList.remove("medium-zoom-image"),S.dispatchEvent(el("medium-zoom:detach",{detail:{zoom:w}}))}),b=b.filter(function(S){return ie.indexOf(S)===-1}),w},v=function(L,V){var le=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{};return b.forEach(function(ie){ie.addEventListener("medium-zoom:"+L,V,le)}),y.push({type:"medium-zoom:"+L,listener:V,options:le}),w},_=function(L,V){var le=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{};return b.forEach(function(ie){ie.removeEventListener("medium-zoom:"+L,V,le)}),y=y.filter(function(ie){return!(ie.type==="medium-zoom:"+L&&ie.listener.toString()===V.toString())}),w},p=function(){var L=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},V=L.target,le=function(){var S={width:document.documentElement.clientWidth,height:document.documentElement.clientHeight,left:0,top:0,right:0,bottom:0},J=void 0,X=void 0;if(N.container)if(N.container instanceof Object)S=Mt({},S,N.container),J=S.width-S.left-S.right-N.margin*2,X=S.height-S.top-S.bottom-N.margin*2;else{var De=vi(N.container)?N.container:document.querySelector(N.container),Se=De.getBoundingClientRect(),ze=Se.width,He=Se.height,yt=Se.left,xt=Se.top;S=Mt({},S,{width:ze,height:He,left:yt,top:xt})}J=J||S.width-N.margin*2,X=X||S.height-N.margin*2;var ot=E.zoomedHd||E.original,je=io(ot)?J:ot.naturalWidth||J,P=io(ot)?X:ot.naturalHeight||X,z=ot.getBoundingClientRect(),M=z.top,Y=z.left,ae=z.width,f=z.height,g=Math.min(Math.max(ae,je),J)/ae,k=Math.min(Math.max(f,P),X)/f,T=Math.min(g,k),R=(-Y+(J-ae)/2+N.margin+S.left)/T,I=(-M+(X-f)/2+N.margin+S.top)/T,B="scale("+T+") translate3d("+R+"px, "+I+"px, 0)";E.zoomed.style.transform=B,E.zoomedHd&&(E.zoomedHd.style.transform=B)};return new i(function(ie){if(V&&b.indexOf(V)===-1){ie(w);return}var S=function ze(){H=!1,E.zoomed.removeEventListener("transitionend",ze),E.original.dispatchEvent(el("medium-zoom:opened",{detail:{zoom:w}})),ie(w)};if(E.zoomed){ie(w);return}if(V)E.original=V;else if(b.length>0){var J=b;E.original=J[0]}else{ie(w);return}if(E.original.dispatchEvent(el("medium-zoom:open",{detail:{zoom:w}})),G=window.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop||0,H=!0,E.zoomed=_h(E.original),document.body.appendChild(K),N.template){var X=vi(N.template)?N.template:document.querySelector(N.template);E.template=document.createElement("div"),E.template.appendChild(X.content.cloneNode(!0)),document.body.appendChild(E.template)}if(E.original.parentElement&&E.original.parentElement.tagName==="PICTURE"&&E.original.currentSrc&&(E.zoomed.src=E.original.currentSrc),document.body.appendChild(E.zoomed),window.requestAnimationFrame(function(){document.body.classList.add("medium-zoom--opened")}),E.original.classList.add("medium-zoom-image--hidden"),E.zoomed.classList.add("medium-zoom-image--opened"),E.zoomed.addEventListener("click",m),E.zoomed.addEventListener("transitionend",S),E.original.getAttribute("data-zoom-src")){E.zoomedHd=E.zoomed.cloneNode(),E.zoomedHd.removeAttribute("srcset"),E.zoomedHd.removeAttribute("sizes"),E.zoomedHd.removeAttribute("loading"),E.zoomedHd.src=E.zoomed.getAttribute("data-zoom-src"),E.zoomedHd.onerror=function(){clearInterval(De),console.warn("Unable to reach the zoom image target "+E.zoomedHd.src),E.zoomedHd=null,le()};var De=setInterval(function(){E.zoomedHd.complete&&(clearInterval(De),E.zoomedHd.classList.add("medium-zoom-image--opened"),E.zoomedHd.addEventListener("click",m),document.body.appendChild(E.zoomedHd),le())},10)}else if(E.original.hasAttribute("srcset")){E.zoomedHd=E.zoomed.cloneNode(),E.zoomedHd.removeAttribute("sizes"),E.zoomedHd.removeAttribute("loading");var Se=E.zoomedHd.addEventListener("load",function(){E.zoomedHd.removeEventListener("load",Se),E.zoomedHd.classList.add("medium-zoom-image--opened"),E.zoomedHd.addEventListener("click",m),document.body.appendChild(E.zoomedHd),le()})}else le()})},m=function(){return new i(function(L){if(H||!E.original){L(w);return}var V=function le(){E.original.classList.remove("medium-zoom-image--hidden"),document.body.removeChild(E.zoomed),E.zoomedHd&&document.body.removeChild(E.zoomedHd),document.body.removeChild(K),E.zoomed.classList.remove("medium-zoom-image--opened"),E.template&&document.body.removeChild(E.template),H=!1,E.zoomed.removeEventListener("transitionend",le),E.original.dispatchEvent(el("medium-zoom:closed",{detail:{zoom:w}})),E.original=null,E.zoomed=null,E.zoomedHd=null,E.template=null,L(w)};H=!0,document.body.classList.remove("medium-zoom--opened"),E.zoomed.style.transform="",E.zoomedHd&&(E.zoomedHd.style.transform=""),E.template&&(E.template.style.transition="opacity 150ms",E.template.style.opacity=0),E.original.dispatchEvent(el("medium-zoom:close",{detail:{zoom:w}})),E.zoomed.addEventListener("transitionend",V)})},x=function(){var L=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},V=L.target;return E.original?m():p({target:V})},A=function(){return N},D=function(){return b},O=function(){return E.original},b=[],y=[],H=!1,G=0,N=l,E={original:null,zoomed:null,zoomedHd:null,template:null};Object.prototype.toString.call(t)==="[object Object]"?N=t:(t||typeof t=="string")&&u(t),N=Mt({margin:0,background:"#fff",scrollOffset:40,container:null,template:null},N);var K=vh(N.background);document.addEventListener("click",n),document.addEventListener("keyup",o),document.addEventListener("scroll",r),window.addEventListener("resize",m);var w={open:p,close:m,toggle:x,update:c,clone:a,attach:u,detach:d,on:v,off:_,getOptions:A,getImages:D,getZoomedImage:O};return w};function gh(e,t){t===void 0&&(t={});var l=t.insertAt;if(!(typeof document>"u")){var i=document.head||document.getElementsByTagName("head")[0],n=document.createElement("style");n.type="text/css",l==="top"&&i.firstChild?i.insertBefore(n,i.firstChild):i.appendChild(n),n.styleSheet?n.styleSheet.cssText=e:n.appendChild(document.createTextNode(e))}}var ph=".medium-zoom-overlay{position:fixed;top:0;right:0;bottom:0;left:0;opacity:0;transition:opacity .3s;will-change:opacity}.medium-zoom--opened .medium-zoom-overlay{cursor:pointer;cursor:zoom-out;opacity:1}.medium-zoom-image{cursor:pointer;cursor:zoom-in;transition:transform .3s cubic-bezier(.2,0,.2,1)!important}.medium-zoom-image--hidden{visibility:hidden}.medium-zoom-image--opened{position:relative;cursor:pointer;cursor:zoom-out;will-change:transform}";gh(ph);const mh=Symbol("mediumZoom");var bh={};const kh=".theme-default-content > img, .theme-default-content :not(a) > img",Eh=bh,yh=300,xh=Et({enhance({app:e,router:t}){const l=fh(Eh);l.refresh=(i=kh)=>{l.detach(),l.attach(i)},e.provide(mh,l),t.afterEach(()=>{setTimeout(()=>l.refresh(),yh)})}});/**
  * NProgress, (c) 2013, 2014 Rico Sta. Cruz - http://ricostacruz.com/nprogress
  * @license MIT
- */const ue={settings:{minimum:.08,easing:"ease",speed:200,trickle:!0,trickleRate:.02,trickleSpeed:800,barSelector:'[role="bar"]',parent:"body",template:'
'},status:null,set:e=>{const t=ue.isStarted();e=en(e,ue.settings.minimum,1),ue.status=e===1?null:e;const l=ue.render(!t),i=l.querySelector(ue.settings.barSelector),n=ue.settings.speed,r=ue.settings.easing;return l.offsetWidth,Lh(o=>{ci(i,{transform:"translate3d("+ro(e)+"%,0,0)",transition:"all "+n+"ms "+r}),e===1?(ci(l,{transition:"none",opacity:"1"}),l.offsetWidth,setTimeout(function(){ci(l,{transition:"all "+n+"ms linear",opacity:"0"}),setTimeout(function(){ue.remove(),o()},n)},n)):setTimeout(()=>o(),n)}),ue},isStarted:()=>typeof ue.status=="number",start:()=>{ue.status||ue.set(0);const e=()=>{setTimeout(()=>{ue.status&&(ue.trickle(),e())},ue.settings.trickleSpeed)};return ue.settings.trickle&&e(),ue},done:e=>!e&&!ue.status?ue:ue.inc(.3+.5*Math.random()).set(1),inc:e=>{let t=ue.status;return t?(typeof e!="number"&&(e=(1-t)*en(Math.random()*t,.1,.95)),t=en(t+e,0,.994),ue.set(t)):ue.start()},trickle:()=>ue.inc(Math.random()*ue.settings.trickleRate),render:e=>{if(ue.isRendered())return document.getElementById("nprogress");oo(document.documentElement,"nprogress-busy");const t=document.createElement("div");t.id="nprogress",t.innerHTML=ue.settings.template;const l=t.querySelector(ue.settings.barSelector),i=e?"-100":ro(ue.status||0),n=document.querySelector(ue.settings.parent);return ci(l,{transition:"all 0 linear",transform:"translate3d("+i+"%,0,0)"}),n!==document.body&&oo(n,"nprogress-custom-parent"),n==null||n.appendChild(t),t},remove:()=>{so(document.documentElement,"nprogress-busy"),so(document.querySelector(ue.settings.parent),"nprogress-custom-parent");const e=document.getElementById("nprogress");e&&Th(e)},isRendered:()=>!!document.getElementById("nprogress")},en=(e,t,l)=>el?l:e,ro=e=>(-1+e)*100,Lh=function(){const e=[];function t(){const l=e.shift();l&&l(t)}return function(l){e.push(l),e.length===1&&t()}}(),ci=function(){const e=["Webkit","O","Moz","ms"],t={};function l(o){return o.replace(/^-ms-/,"ms-").replace(/-([\da-z])/gi,function(c,a){return a.toUpperCase()})}function i(o){const c=document.body.style;if(o in c)return o;let a=e.length;const u=o.charAt(0).toUpperCase()+o.slice(1);let d;for(;a--;)if(d=e[a]+u,d in c)return d;return o}function n(o){return o=l(o),t[o]??(t[o]=i(o))}function r(o,c,a){c=n(c),o.style[c]=a}return function(o,c){for(const a in c){const u=c[a];u!==void 0&&Object.prototype.hasOwnProperty.call(c,a)&&r(o,a,u)}}}(),Fs=(e,t)=>(typeof e=="string"?e:Xn(e)).indexOf(" "+t+" ")>=0,oo=(e,t)=>{const l=Xn(e),i=l+t;Fs(l,t)||(e.className=i.substring(1))},so=(e,t)=>{const l=Xn(e);if(!Fs(e,t))return;const i=l.replace(" "+t+" "," ");e.className=i.substring(1,i.length-1)},Xn=e=>(" "+(e.className||"")+" ").replace(/\s+/gi," "),Th=e=>{e&&e.parentNode&&e.parentNode.removeChild(e)},Oh=()=>{We(()=>{const e=bt(),t=new Set;t.add(e.currentRoute.value.path),e.beforeEach(l=>{t.has(l.path)||ue.start()}),e.afterEach(l=>{t.add(l.path),ue.done()})})},Ph=Et({setup(){Oh()}}),Ah=JSON.parse(`{"name":"vuepress-theme-xray","smoothScroll":true,"repo":"xtls/xray-core","docsDir":"docs","docsRepo":"xtls/Xray-docs-next","docsBranch":"main","editLinks":true,"enableToggle":true,"locales":{"/":{"navbar":[{"text":"首页","link":"/"},{"text":"大史记","link":"/about/news.md"},{"text":"配置指南","link":"/config/"},{"text":"开发指南","link":"/development/"},{"text":"使用指南","link":"/document/"}],"sidebar":{"/config/":[{"text":"特性详解","children":["/config/features/xtls.md","/config/features/fallback.md","/config/features/browser_dialer.md","/config/features/env.md","/config/features/multiple.md"]},{"text":"基础配置","children":["/config/README.md","/config/log.md","/config/api.md","/config/dns.md","/config/fakedns.md","/config/inbound.md","/config/outbound.md","/config/policy.md","/config/reverse.md","/config/routing.md","/config/stats.md","/config/transport.md","/config/metrics.md","/config/observatory.md"]},{"text":"入站代理","children":["/config/inbounds/dokodemo.md","/config/inbounds/http.md","/config/inbounds/shadowsocks.md","/config/inbounds/socks.md","/config/inbounds/trojan.md","/config/inbounds/vless.md","/config/inbounds/vmess.md","/config/inbounds/wireguard.md"]},{"text":"出站代理","children":["/config/outbounds/blackhole.md","/config/outbounds/dns.md","/config/outbounds/freedom.md","/config/outbounds/http.md","/config/outbounds/loopback.md","/config/outbounds/shadowsocks.md","/config/outbounds/socks.md","/config/outbounds/trojan.md","/config/outbounds/vless.md","/config/outbounds/vmess.md","/config/outbounds/wireguard.md"]},{"text":"底层传输","children":["/config/transports/grpc.md","/config/transports/h2.md","/config/transports/mkcp.md","/config/transports/tcp.md","/config/transports/websocket.md","/config/transports/httpupgrade.md","/config/transports/splithttp.md"]}],"/document/":[{"text":"快速入门文档","children":["/document/README.md","/document/install.md","/document/config.md","/document/command.md","/document/document.md"]},{"text":"小小白白话文","children":["/document/level-0/README.md","/document/level-0/ch01-preface.md","/document/level-0/ch02-preparation.md","/document/level-0/ch03-ssh.md","/document/level-0/ch04-security.md","/document/level-0/ch05-webpage.md","/document/level-0/ch06-certificates.md","/document/level-0/ch07-xray-server.md","/document/level-0/ch08-xray-clients.md","/document/level-0/ch09-appendix.md"]},{"text":"入门技巧","children":["/document/level-1/README.md","/document/level-1/fallbacks-lv1.md","/document/level-1/routing-lv1-part1.md","/document/level-1/routing-lv1-part2.md","/document/level-1/work.md","/document/level-1/fallbacks-with-sni.md"]},{"text":"进阶技巧","children":["/document/level-2/README.md","/document/level-2/transparent_proxy/transparent_proxy.md","/document/level-2/tproxy.md","/document/level-2/tproxy_ipv4_and_ipv6.md","/document/level-2/nginx_or_haproxy_tls_tunnel.md","/document/level-2/iptables_gid.md","/document/level-2/redirect.md","/document/level-2/warp.md","/document/level-2/traffic_stats.md"]}],"/development/":[{"text":"开发指南","children":["/development/README.md","/development/intro/compile.md","/development/intro/design.md","/development/intro/guide.md"]},{"text":"协议详解","children":["/development/protocols/vless.md","/development/protocols/vmess.md","/development/protocols/muxcool.md","/development/protocols/mkcp.md"]}]},"repoLabel":"查看源码","editLinkText":"帮助我们改善此页面!","tip":"提示","warning":"注意","danger":"警告","lastUpdatedText":"最近更改","selectLanguageName":"简体中文","selectLanguageText":"🌏 简体中文 / Change language","selectLanguageAriaLabel":"简体中文 / Change language","docsDir":"docs","backToHome":"back to home","openInNewWindow":"open in new tag","toggleColorMode":"toggle color mode","toggleSidebar":"toggle side bar"},"/en/":{"sidebar":{"/en/config/":[{"text":"feature","children":["/en/config/features/xtls.md","/en/config/features/fallback.md","/en/config/features/browser_dialer.md","/en/config/features/env.md","/en/config/features/multiple.md"]},{"text":"config","children":["/en/config/README.md","/en/config/log.md","/en/config/api.md","/en/config/dns.md","/en/config/fakedns.md","/en/config/inbound.md","/en/config/outbound.md","/en/config/policy.md","/en/config/reverse.md","/en/config/routing.md","/en/config/stats.md","/en/config/transport.md","/en/config/metrics.md","/en/config/observatory.md"]},{"text":"inbound","children":["/en/config/inbounds/dokodemo.md","/en/config/inbounds/http.md","/en/config/inbounds/shadowsocks.md","/en/config/inbounds/socks.md","/en/config/inbounds/trojan.md","/en/config/inbounds/vless.md","/en/config/inbounds/vmess.md","/en/config/inbounds/wireguard.md"]},{"text":"outbound","children":["/en/config/outbounds/blackhole.md","/en/config/outbounds/dns.md","/en/config/outbounds/freedom.md","/en/config/outbounds/http.md","/en/config/outbounds/loopback.md","/en/config/outbounds/shadowsocks.md","/en/config/outbounds/socks.md","/en/config/outbounds/trojan.md","/en/config/outbounds/vless.md","/en/config/outbounds/vmess.md","/en/config/outbounds/wireguard.md"]},{"text":"transport","children":["/en/config/transports/grpc.md","/en/config/transports/h2.md","/en/config/transports/mkcp.md","/en/config/transports/tcp.md","/en/config/transports/websocket.md","/en/config/transports/httpupgrade.md","/en/config/transports/splithttp.md"]}],"/en/document/":[{"text":"Quick Start","children":["/en/document/README.md","/en/document/install.md","/en/document/config.md","/en/document/command.md","/en/document/document.md"]},{"text":"Beginner Tutorial","children":["/en/document/level-0/README.md","/en/document/level-0/ch01-preface.md","/en/document/level-0/ch02-preparation.md","/en/document/level-0/ch03-ssh.md","/en/document/level-0/ch04-security.md","/en/document/level-0/ch05-webpage.md","/en/document/level-0/ch06-certificates.md","/en/document/level-0/ch07-xray-server.md","/en/document/level-0/ch08-xray-clients.md","/en/document/level-0/ch09-appendix.md"]},{"text":"Getting Started Tips","children":["/en/document/level-1/README.md","/en/document/level-1/fallbacks-lv1.md","/en/document/level-1/routing-lv1-part1.md","/en/document/level-1/routing-lv1-part2.md","/en/document/level-1/work.md","/en/document/level-1/fallbacks-with-sni.md"]},{"text":"Advanced Documentation","children":["/en/document/level-2/README.md","/en/document/level-2/transparent_proxy/transparent_proxy.md","/en/document/level-2/tproxy.md","/en/document/level-2/tproxy_ipv4_and_ipv6.md","/en/document/level-2/nginx_or_haproxy_tls_tunnel.md","/en/document/level-2/iptables_gid.md","/en/document/level-2/redirect.md","/en/document/level-2/warp.md","/en/document/level-2/traffic_stats.md"]}],"/en/development/":[{"text":"Developer Guide","children":["/en/development/README.md","/en/development/intro/compile.md","/en/development/intro/design.md","/en/development/intro/guide.md"]},{"text":"Protocol Details","children":["/en/development/protocols/vless.md","/en/development/protocols/vmess.md","/en/development/protocols/muxcool.md","/en/development/protocols/mkcp.md"]}]},"navbar":[{"text":"Homepage","link":"/en"},{"text":"Website History","link":"/en/about/news.md"},{"text":"Config Reference","link":"/en/config/"},{"text":"Developer Guide","link":"/en/development/"},{"text":"Quick Start","link":"/en/document/"}],"selectLanguageName":"English (WIP)","selectLanguageText":"🌎 English / Change language","selectLanguageAriaLabel":"English / Change language","editLinkText":"Help us improve this page on GitHub!","lastUpdatedText":"Last Updated","contributorsText":"contributors","tip":"Tip","warning":"Warning","danger":"Danger","notFound":["这里什么都没有","我们怎么到这来了?","这是一个 404 页面","看起来我们进入了错误的链接"],"backToHome":"back to home","openInNewWindow":"open in new tag","toggleColorMode":"toggle color mode","toggleSidebar":"toggle side bar"},"/ru/":{"navbar":[{"text":"Главная","link":"/ru"},{"text":"История сайта","link":"/ru/about/news.md"},{"text":"Справочник по конфигурации","link":"/ru/config/"},{"text":"Руководство разработчика","link":"/ru/development/"},{"text":"Быстрый старт","link":"/ru/document/"}],"sidebar":{"/ru/config/":[{"text":"Описание функций","children":["/ru/config/features/xtls.md","/ru/config/features/fallback.md","/ru/config/features/browser_dialer.md","/ru/config/features/env.md","/ru/config/features/multiple.md"]},{"text":"Базовая конфигурация","children":["/ru/config/README.md","/ru/config/log.md","/ru/config/api.md","/ru/config/dns.md","/ru/config/fakedns.md","/ru/config/inbound.md","/ru/config/outbound.md","/ru/config/policy.md","/ru/config/reverse.md","/ru/config/routing.md","/ru/config/stats.md","/ru/config/transport.md","/ru/config/metrics.md","/ru/config/observatory.md"]},{"text":"Входящие подключения","children":["/ru/config/inbounds/dokodemo.md","/ru/config/inbounds/http.md","/ru/config/inbounds/shadowsocks.md","/ru/config/inbounds/socks.md","/ru/config/inbounds/trojan.md","/ru/config/inbounds/vless.md","/ru/config/inbounds/vmess.md","/ru/config/inbounds/wireguard.md"]},{"text":"Исходящие подключения","children":["/ru/config/outbounds/blackhole.md","/ru/config/outbounds/dns.md","/ru/config/outbounds/freedom.md","/ru/config/outbounds/http.md","/ru/config/outbounds/loopback.md","/ru/config/outbounds/shadowsocks.md","/ru/config/outbounds/socks.md","/ru/config/outbounds/trojan.md","/ru/config/outbounds/vless.md","/ru/config/outbounds/vmess.md","/ru/config/outbounds/wireguard.md"]},{"text":"Транспортный уровень","children":["/ru/config/transports/grpc.md","/ru/config/transports/h2.md","/ru/config/transports/mkcp.md","/ru/config/transports/tcp.md","/ru/config/transports/websocket.md","/ru/config/transports/httpupgrade.md","/ru/config/transports/splithttp.md"]}],"/ru/document/":[{"text":"Быстрый старт","children":["/ru/document/README.md","/ru/document/install.md","/ru/document/config.md","/ru/document/command.md","/ru/document/document.md"]},{"text":"Простыми словами","children":["/ru/document/level-0/README.md","/ru/document/level-0/ch01-preface.md","/ru/document/level-0/ch02-preparation.md","/ru/document/level-0/ch03-ssh.md","/ru/document/level-0/ch04-security.md","/ru/document/level-0/ch05-webpage.md","/ru/document/level-0/ch06-certificates.md","/ru/document/level-0/ch07-xray-server.md","/ru/document/level-0/ch08-xray-clients.md","/ru/document/level-0/ch09-appendix.md"]},{"text":"Базовые навыки","children":["/ru/document/level-1/README.md","/ru/document/level-1/fallbacks-lv1.md","/ru/document/level-1/routing-lv1-part1.md","/ru/document/level-1/routing-lv1-part2.md","/ru/document/level-1/work.md","/ru/document/level-1/fallbacks-with-sni.md"]},{"text":"Продвинутые навыки","children":["/ru/document/level-2/README.md","/ru/document/level-2/transparent_proxy/transparent_proxy.md","/ru/document/level-2/tproxy.md","/ru/document/level-2/tproxy_ipv4_and_ipv6.md","/ru/document/level-2/nginx_or_haproxy_tls_tunnel.md","/ru/document/level-2/iptables_gid.md","/ru/document/level-2/redirect.md","/ru/document/level-2/warp.md","/ru/document/level-2/traffic_stats.md"]}],"/ru/development/":[{"text":"Руководство разработчика","children":["/ru/development/README.md","/ru/development/intro/compile.md","/ru/development/intro/design.md","/ru/development/intro/guide.md"]},{"text":"Описание протоколов","children":["/ru/development/protocols/vless.md","/ru/development/protocols/vmess.md","/ru/development/protocols/muxcool.md","/ru/development/protocols/mkcp.md"]}]},"repoLabel":"Посмотреть исходный код","editLinkText":"Помогите нам улучшить эту страницу!","tip":"Подсказка","warning":"Внимание","danger":"Предупреждение","lastUpdatedText":"Последние изменения","selectLanguageName":"Русский (WIP)","selectLanguageText":"🌍 Русский / Change language","selectLanguageAriaLabel":"Русский / Change language","docsDir":"docs","backToHome":"На главную","openInNewWindow":"Открыть в новой вкладке","toggleColorMode":"Переключить цветовую схему","toggleSidebar":"Переключить боковую панель"},"themePlugins":{"git":true}},"colorMode":"auto","colorModeSwitch":true,"navbar":[],"logo":null,"selectLanguageText":"Languages","selectLanguageAriaLabel":"Select language","sidebar":"auto","sidebarDepth":2,"editLink":true,"editLinkText":"Edit this page","lastUpdated":true,"lastUpdatedText":"Last Updated","contributors":true,"contributorsText":"Contributors","notFound":["There's nothing here.","How did we get here?","That's a Four-Oh-Four.","Looks like we've got some broken links."],"backToHome":"Take me home","openInNewWindow":"open in new window","toggleColorMode":"toggle color mode","toggleSidebar":"toggle sidebar"}`),wh=ge(Ah),Ns=()=>wh,Hs=Symbol(""),Rh=()=>{const e=Te(Hs);if(!e)throw new Error("useThemeLocaleData() is called without provider.");return e},Ih=(e,t)=>{const{locales:l,...i}=e;return{...i,...l==null?void 0:l[t]}},Dh=Et({enhance({app:e}){const t=Ns(),l=e._context.provides[Mn],i=C(()=>Ih(t.value,l.value));e.provide(Hs,i),Object.defineProperties(e.config.globalProperties,{$theme:{get(){return t.value}},$themeLocale:{get(){return i.value}}})}}),jh=_e({__name:"Badge",props:{type:{type:String,required:!1,default:"tip"},text:{type:String,required:!1,default:""},vertical:{type:String,required:!1,default:void 0}},setup(e,{expose:t}){t();const l={};return Object.defineProperty(l,"__isScriptSetup",{enumerable:!1,value:!0}),l}}),xe=(e,t)=>{const l=e.__vccOpts||e;for(const[i,n]of t)l[i]=n;return l};function Sh(e,t,l,i,n,r){return W(),ee("span",{class:$e(["badge",l.type]),style:Wl({verticalAlign:l.vertical})},[be(e.$slots,"default",{},()=>[Vt(Pe(l.text),1)])],6)}const Ch=xe(jh,[["render",Sh],["__file","Badge.vue"]]);function Vh(e,t){let l,i,n;const r=ge(!0),o=()=>{r.value=!0,n()};Ge(e,o,{flush:"sync"});const c=typeof t=="function"?t:t.get,a=typeof t=="function"?void 0:t.set,u=Mc((d,v)=>(i=d,n=v,{get(){return r.value&&(l=c(),r.value=!1),i(),l},set(_){a==null||a(_)}}));return Object.isExtensible(u)&&(u.trigger=o),u}function Ms(e){return Lo()?(fc(e),!0):!1}function _l(e){return typeof e=="function"?e():Xt(e)}const Fh=typeof window<"u"&&typeof document<"u";typeof WorkerGlobalScope<"u"&&globalThis instanceof WorkerGlobalScope;const Nh=Object.prototype.toString,Hh=e=>Nh.call(e)==="[object Object]",Mh=()=>{};function $h(e,t){function l(...i){return new Promise((n,r)=>{Promise.resolve(e(()=>t.apply(this,i),{fn:t,thisArg:this,args:i})).then(n).catch(r)})}return l}const $s=e=>e();function Bh(e=$s){const t=ge(!0);function l(){t.value=!1}function i(){t.value=!0}const n=(...r)=>{t.value&&e(...r)};return{isActive:Ri(t),pause:l,resume:i,eventFilter:n}}function Wh(e){return Vn()}function zh(e,t,l={}){const{eventFilter:i=$s,...n}=l;return Ge(e,$h(i,t),n)}function Uh(e,t,l={}){const{eventFilter:i,...n}=l,{eventFilter:r,pause:o,resume:c,isActive:a}=Bh(i);return{stop:zh(e,t,{...n,eventFilter:r}),pause:o,resume:c,isActive:a}}function Xh(e,t=!0,l){Wh()?We(e,l):t?e():Xl(e)}function Kh(e=!1,t={}){const{truthyValue:l=!0,falsyValue:i=!1}=t,n=Ne(e),r=ge(e);function o(c){if(arguments.length)return r.value=c,r.value;{const a=_l(l);return r.value=r.value===a?_l(i):a,r.value}}return n?o:[r,o]}function qh(e){var t;const l=_l(e);return(t=l==null?void 0:l.$el)!=null?t:l}const Ti=Fh?window:void 0;function co(...e){let t,l,i,n;if(typeof e[0]=="string"||Array.isArray(e[0])?([l,i,n]=e,t=Ti):[t,l,i,n]=e,!t)return Mh;Array.isArray(l)||(l=[l]),Array.isArray(i)||(i=[i]);const r=[],o=()=>{r.forEach(d=>d()),r.length=0},c=(d,v,_,p)=>(d.addEventListener(v,_,p),()=>d.removeEventListener(v,_,p)),a=Ge(()=>[qh(t),_l(n)],([d,v])=>{if(o(),!d)return;const _=Hh(v)?{...v}:v;r.push(...l.flatMap(p=>i.map(m=>c(d,p,m,_))))},{immediate:!0,flush:"post"}),u=()=>{a(),o()};return Ms(u),u}function Gh(){const e=ge(!1),t=Vn();return t&&We(()=>{e.value=!0},t),e}function Yh(e){const t=Gh();return C(()=>(t.value,!!e()))}function Jh(e,t={}){const{window:l=Ti}=t,i=Yh(()=>l&&"matchMedia"in l&&typeof l.matchMedia=="function");let n;const r=ge(!1),o=u=>{r.value=u.matches},c=()=>{n&&("removeEventListener"in n?n.removeEventListener("change",o):n.removeListener(o))},a=ra(()=>{i.value&&(c(),n=l.matchMedia(_l(e)),"addEventListener"in n?n.addEventListener("change",o):n.addListener(o),r.value=n.matches)});return Ms(()=>{a(),c(),n=void 0}),r}const ai=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{},ui="__vueuse_ssr_handlers__",Qh=Zh();function Zh(){return ui in ai||(ai[ui]=ai[ui]||{}),ai[ui]}function ev(e,t){return Qh[e]||t}function tv(e){return e==null?"any":e instanceof Set?"set":e instanceof Map?"map":e instanceof Date?"date":typeof e=="boolean"?"boolean":typeof e=="string"?"string":typeof e=="object"?"object":Number.isNaN(e)?"any":"number"}const lv={boolean:{read:e=>e==="true",write:e=>String(e)},object:{read:e=>JSON.parse(e),write:e=>JSON.stringify(e)},number:{read:e=>Number.parseFloat(e),write:e=>String(e)},any:{read:e=>e,write:e=>String(e)},string:{read:e=>e,write:e=>String(e)},map:{read:e=>new Map(JSON.parse(e)),write:e=>JSON.stringify(Array.from(e.entries()))},set:{read:e=>new Set(JSON.parse(e)),write:e=>JSON.stringify(Array.from(e))},date:{read:e=>new Date(e),write:e=>e.toISOString()}},ao="vueuse-storage";function Bs(e,t,l,i={}){var n;const{flush:r="pre",deep:o=!0,listenToStorageChanges:c=!0,writeDefaults:a=!0,mergeDefaults:u=!1,shallow:d,window:v=Ti,eventFilter:_,onError:p=w=>{console.error(w)},initOnMounted:m}=i,x=(d?No:ge)(typeof t=="function"?t():t);if(!l)try{l=ev("getDefaultStorage",()=>{var w;return(w=Ti)==null?void 0:w.localStorage})()}catch(w){p(w)}if(!l)return x;const A=_l(t),D=tv(A),O=(n=i.serializer)!=null?n:lv[D],{pause:b,resume:y}=Uh(x,()=>G(x.value),{flush:r,deep:o,eventFilter:_});v&&c&&Xh(()=>{co(v,"storage",E),co(v,ao,K),m&&E()}),m||E();function H(w,U){v&&v.dispatchEvent(new CustomEvent(ao,{detail:{key:e,oldValue:w,newValue:U,storageArea:l}}))}function G(w){try{const U=l.getItem(e);if(w==null)H(U,null),l.removeItem(e);else{const L=O.write(w);U!==L&&(l.setItem(e,L),H(U,L))}}catch(U){p(U)}}function N(w){const U=w?w.newValue:l.getItem(e);if(U==null)return a&&A!=null&&l.setItem(e,O.write(A)),A;if(!w&&u){const L=O.read(U);return typeof u=="function"?u(L,A):D==="object"&&!Array.isArray(L)?{...A,...L}:L}else return typeof U!="string"?U:O.read(U)}function E(w){if(!(w&&w.storageArea!==l)){if(w&&w.key==null){x.value=A;return}if(!(w&&w.key!==e)){b();try{(w==null?void 0:w.newValue)!==O.write(x.value)&&(x.value=N(w))}catch(U){p(U)}finally{w?Xl(y):y()}}}}function K(w){E(w.detail)}return x}function iv(e){return Jh("(prefers-color-scheme: dark)",e)}const nv=_e({name:"CodeGroup",slots:Object,setup(e,{slots:t}){const l=ge([]),i=ge(-1),n=Bs("vuepress-code-group",{}),r=C(()=>l.value.map(u=>u.innerText).join(","));We(()=>{Ge(()=>n.value[r.value],(u=-1)=>{i.value!==u&&(i.value=u)},{immediate:!0}),Ge(i,u=>{n.value[r.value]!==u&&(n.value[r.value]=u)})});const o=(u=i.value)=>{u{u>0?i.value=u-1:i.value=l.value.length-1,l.value[i.value].focus()},a=(u,d)=>{u.key===" "||u.key==="Enter"?(u.preventDefault(),i.value=d):u.key==="ArrowRight"?(u.preventDefault(),o(d)):u.key==="ArrowLeft"&&(u.preventDefault(),c(d))};return()=>{var d;const u=(((d=t.default)==null?void 0:d.call(t))||[]).filter(v=>v.type.name==="CodeGroupItem").map(v=>(v.props===null&&(v.props={}),v));return u.length===0?null:(i.value<0||i.value>u.length-1?(i.value=u.findIndex(v=>v.props.active===""||v.props.active===!0),i.value===-1&&(i.value=0)):u.forEach((v,_)=>{v.props.active=_===i.value}),he("div",{class:"code-group"},[he("div",{class:"code-group__nav",role:"tablist"},u.map((v,_)=>{const p=_===i.value;return he("button",{ref:m=>{m&&(l.value[_]=m)},class:{"code-group__nav-tab":!0,"code-group__nav-tab-active":p},role:"tab",ariaSelected:p,onClick:()=>i.value=_,onKeydown:m=>a(m,_)},v.props.title)})),u]))}}}),rv=_e({name:"CodeGroupItem",__name:"CodeGroupItem",props:{title:{type:String,required:!0},active:{type:Boolean,required:!1,default:!1}},setup(e,{expose:t}){t();const l={};return Object.defineProperty(l,"__isScriptSetup",{enumerable:!1,value:!0}),l}});function ov(e,t,l,i,n,r){return W(),ee("div",{class:$e(["code-group-item",{"code-group-item__active":l.active}]),role:"tabpanel"},[be(e.$slots,"default")],2)}const sv=xe(rv,[["render",ov],["__file","CodeGroupItem.vue"]]),cv=()=>Ns(),Fe=()=>Rh(),Ws=Symbol(""),Kn=()=>{const e=Te(Ws);if(!e)throw new Error("useDarkMode() is called without provider.");return e},av=()=>{const e=Fe(),t=iv(),l=Bs("vuepress-color-scheme",e.value.colorMode),i=C({get(){return e.value.colorModeSwitch?l.value==="auto"?t.value:l.value==="dark":e.value.colorMode==="dark"},set(n){n===t.value?l.value="auto":l.value=n?"dark":"light"}});Kt(Ws,i),uv(i)},uv=e=>{const t=(l=e.value)=>{const i=window==null?void 0:window.document.querySelector("html");i==null||i.classList.toggle("dark",l)};We(()=>{Ge(e,t,{immediate:!0})}),Ci(()=>t())};let tn=null,Ll=null;const dv={wait:()=>tn,pending:()=>{tn=new Promise(e=>Ll=e)},resolve:()=>{Ll==null||Ll(),tn=null,Ll=null}},zs=()=>dv,Us=(e,...t)=>{const l=e.resolve(...t),i=l.matched[l.matched.length-1];if(!(i!=null&&i.redirect))return l;const{redirect:n}=i,r=Nu(n)?n(l):n,o=nt(r)?{path:r}:r;return Us(e,{hash:l.hash,query:l.query,params:l.params,...o})},qn=(e,t)=>{const l=Us(e,encodeURI(t));return{text:l.meta.title||t,link:l.name==="404"?t:l.fullPath}},uo=e=>decodeURI(e).replace(/#.*$/,"").replace(/(index)?\.(md|html)$/,""),hv=(e,t)=>{if(t.hash===e)return!0;const l=uo(t.path),i=uo(e);return l===i},Xs=(e,t)=>e.link&&hv(e.link,t)?!0:e.children?e.children.some(l=>Xs(l,t)):!1,Ks=e=>!Yl(e)||/github\.com/.test(e)?"GitHub":/bitbucket\.org/.test(e)?"Bitbucket":/gitlab\.com/.test(e)?"GitLab":/gitee\.com/.test(e)?"Gitee":null,vv={GitHub:":repo/edit/:branch/:path",GitLab:":repo/-/edit/:branch/:path",Gitee:":repo/edit/:branch/:path",Bitbucket:":repo/src/:branch/:path?mode=edit&spa=0&at=:branch&fileviewer=file-view-default"},_v=({docsRepo:e,editLinkPattern:t})=>{if(t)return t;const l=Ks(e);return l!==null?vv[l]:null},fv=({docsRepo:e,docsBranch:t,docsDir:l,filePathRelative:i,editLinkPattern:n})=>{if(!i)return null;const r=_v({docsRepo:e,editLinkPattern:n});return r?r.replace(/:repo/,Yl(e)?e:`https://github.com/${e}`).replace(/:branch/,t).replace(/:path/,fs(`${_s(l)}/${i}`)):null},qs=Symbol("sidebarItems"),Gn=()=>{const e=Te(qs);if(!e)throw new Error("useSidebarItems() is called without provider.");return e},gv=()=>{const e=Fe(),t=pt(),l=Gt(),i=ml(),n=bt(),r=C(()=>pv(t.value,e.value,l.value,n,i.path));Kt(qs,r)},pv=(e,t,l,i,n)=>{const r=e.sidebar??t.sidebar??"auto",o=e.sidebarDepth??t.sidebarDepth??2;return e.home||r===!1?[]:r==="auto"?Gs(l,o):Array.isArray(r)?Ys(l,i,n,r,o):Hn(r)?bv(l,i,n,r,o):[]},mv=(e,t)=>({text:e.title,link:e.link,children:Yn(e.children,t)}),Yn=(e,t)=>t>0?e.map(l=>mv(l,t-1)):[],Gs=(e,t)=>[{text:e.title,children:Yn(e.headers,t)}],Ys=(e,t,l,i,n)=>{const r=o=>{var a;let c;if(nt(o)?c=qn(t,o):c=o,c.children)return{...c,children:c.children.map(u=>r(u))};if(c.link===l){const u=((a=e.headers[0])==null?void 0:a.level)===1?e.headers[0].children:e.headers;return{...c,children:Yn(u,n)}}return c};return i.map(o=>r(o))},bv=(e,t,l,i,n)=>{const r=gs(i,l),o=i[r]??[];return o==="heading"?Gs(e,n):Ys(e,t,l,o,n)},kv="719px",Ev={mobile:kv};var $l;(function(e){e.MOBILE="mobile"})($l||($l={}));var po;const yv={[$l.MOBILE]:Number.parseInt((po=Ev.mobile)==null?void 0:po.replace("px",""),10)},Js=(e,t)=>{const l=yv[e];Number.isInteger(l)&&We(()=>{t(l),window.addEventListener("resize",()=>t(l),!1),window.addEventListener("orientationchange",()=>t(l),!1)})},xv={},Lv={class:"theme-default-content"};function Tv(e,t){const l=mt("Content");return W(),ee("div",Lv,[ne(l)])}const Ov=xe(xv,[["render",Tv],["__file","HomeContent.vue"]]),Pv=_e({__name:"HomeFeatures",setup(e,{expose:t}){t();const l=pt(),i=C(()=>Array.isArray(l.value.features)?l.value.features:[]),n={frontmatter:l,features:i};return Object.defineProperty(n,"__isScriptSetup",{enumerable:!1,value:!0}),n}}),Av={key:0,class:"features"};function wv(e,t,l,i,n,r){return i.features.length?(W(),ee("div",Av,[(W(!0),ee(ke,null,St(i.features,o=>(W(),ee("div",{key:o.title,class:"feature"},[ce("h2",null,Pe(o.title),1),ce("p",null,Pe(o.details),1)]))),128))])):Le("",!0)}const Rv=xe(Pv,[["render",wv],["__file","HomeFeatures.vue"]]),Iv=_e({__name:"HomeFooter",setup(e,{expose:t}){t();const l=pt(),i=C(()=>l.value.footer),n=C(()=>l.value.footerHtml),r={frontmatter:l,footer:i,footerHtml:n};return Object.defineProperty(r,"__isScriptSetup",{enumerable:!1,value:!0}),r}}),Dv=["innerHTML"],jv=["textContent"];function Sv(e,t,l,i,n,r){return i.footer?(W(),ee(ke,{key:0},[i.footerHtml?(W(),ee("div",{key:0,class:"footer",innerHTML:i.footer},null,8,Dv)):(W(),ee("div",{key:1,class:"footer",textContent:Pe(i.footer)},null,8,jv))],64)):Le("",!0)}const Cv=xe(Iv,[["render",Sv],["__file","HomeFooter.vue"]]),Vv=_e({inheritAttrs:!1,__name:"AutoLink",props:{item:{type:Object,required:!0}},setup(e,{expose:t}){t();const l=e,i=ml(),n=xs(),{item:r}=Ii(l),o=C(()=>Yl(r.value.link)),c=C(()=>!o.value&&Fu(r.value.link)),a=C(()=>{if(!c.value){if(r.value.target)return r.value.target;if(o.value)return"_blank"}}),u=C(()=>a.value==="_blank"),d=C(()=>!o.value&&!c.value&&!u.value),v=C(()=>{if(!c.value){if(r.value.rel)return r.value.rel;if(u.value)return"noopener noreferrer"}}),_=C(()=>r.value.ariaLabel||r.value.text),p=C(()=>{const D=Object.keys(n.value.locales);return D.length?!D.some(O=>O===r.value.link):r.value.link!=="/"}),m=C(()=>p.value?i.path.startsWith(r.value.link):!1),x=C(()=>d.value?r.value.activeMatch?new RegExp(r.value.activeMatch).test(i.path):m.value:!1),A={props:l,route:i,site:n,item:r,hasHttpProtocol:o,hasNonHttpProtocol:c,linkTarget:a,isBlankTarget:u,isRouterLink:d,linkRel:v,linkAriaLabel:_,shouldBeActiveInSubpath:p,isActiveInSubpath:m,isActive:x};return Object.defineProperty(A,"__isScriptSetup",{enumerable:!1,value:!0}),A}}),Fv=["href","rel","target","aria-label"];function Nv(e,t,l,i,n,r){const o=mt("RouterLink"),c=mt("AutoLinkExternalIcon");return i.isRouterLink?(W(),Ae(o,_n({key:0,class:{"router-link-active":i.isActive},to:i.item.link,"aria-label":i.linkAriaLabel},e.$attrs),{default:Ce(()=>[be(e.$slots,"before"),Vt(" "+Pe(i.item.text)+" ",1),be(e.$slots,"after")]),_:3},16,["class","to","aria-label"])):(W(),ee("a",_n({key:1,class:"external-link",href:i.item.link,rel:i.linkRel,target:i.linkTarget,"aria-label":i.linkAriaLabel},e.$attrs),[be(e.$slots,"before"),Vt(" "+Pe(i.item.text)+" ",1),i.isBlankTarget?(W(),Ae(c,{key:0})):Le("",!0),be(e.$slots,"after")],16,Fv))}const bl=xe(Vv,[["render",Nv],["__file","AutoLink.vue"]]),Hv=_e({__name:"HomeHero",setup(e,{expose:t}){t();const l=pt(),i=$n(),n=Kn(),r=C(()=>n.value&&l.value.heroImageDark!==void 0?l.value.heroImageDark:l.value.heroImage),o=C(()=>l.value.heroAlt||a.value||"hero"),c=C(()=>l.value.heroHeight||280),a=C(()=>l.value.heroText===null?null:l.value.heroText||i.value.title||"Hello"),u=C(()=>l.value.tagline===null?null:l.value.tagline||i.value.description||"Welcome to your VuePress site"),d=C(()=>Array.isArray(l.value.actions)?l.value.actions.map(({text:p,link:m,type:x="primary"})=>({text:p,link:m,type:x})):[]),_={frontmatter:l,siteLocale:i,isDarkMode:n,heroImage:r,heroAlt:o,heroHeight:c,heroText:a,tagline:u,actions:d,HomeHeroImage:()=>{if(!r.value)return null;const p=he("img",{src:Wn(r.value),alt:o.value,height:c.value});return l.value.heroImageDark===void 0?p:he(Bn,()=>p)},AutoLink:bl};return Object.defineProperty(_,"__isScriptSetup",{enumerable:!1,value:!0}),_}}),Mv={class:"hero"},$v={key:0,id:"main-title"},Bv={key:1,class:"description"},Wv={key:2,class:"actions"};function zv(e,t,l,i,n,r){return W(),ee("header",Mv,[ne(i.HomeHeroImage),i.heroText?(W(),ee("h1",$v,Pe(i.heroText),1)):Le("",!0),i.tagline?(W(),ee("p",Bv,Pe(i.tagline),1)):Le("",!0),i.actions.length?(W(),ee("p",Wv,[(W(!0),ee(ke,null,St(i.actions,o=>(W(),Ae(i.AutoLink,{key:o.text,class:$e(["action-button",[o.type]]),item:o},null,8,["class","item"]))),128))])):Le("",!0)])}const Uv=xe(Hv,[["render",zv],["__file","HomeHero.vue"]]),Xv=_e({__name:"Home",setup(e,{expose:t}){t();const l={HomeContent:Ov,HomeFeatures:Rv,HomeFooter:Cv,HomeHero:Uv};return Object.defineProperty(l,"__isScriptSetup",{enumerable:!1,value:!0}),l}}),Kv={class:"home"};function qv(e,t,l,i,n,r){return W(),ee("main",Kv,[ne(i.HomeHero),ne(i.HomeFeatures),ne(i.HomeContent),ne(i.HomeFooter)])}const Gv=xe(Xv,[["render",qv],["__file","Home.vue"]]),Yv=_e({__name:"NavbarBrand",setup(e,{expose:t}){t();const l=Jl(),i=$n(),n=Fe(),r=Kn(),o=C(()=>n.value.home||l.value),c=C(()=>i.value.title),a=C(()=>r.value&&n.value.logoDark!==void 0?n.value.logoDark:n.value.logo),u=C(()=>n.value.logoAlt??c.value),d=C(()=>c.value.toLocaleUpperCase().trim()===u.value.toLocaleUpperCase().trim()),_={routeLocale:l,siteLocale:i,themeLocale:n,isDarkMode:r,navbarBrandLink:o,navbarBrandTitle:c,navbarBrandLogo:a,navbarBrandLogoAlt:u,navBarLogoAltMatchesTitle:d,NavbarBrandLogo:()=>{if(!a.value)return null;const p=he("img",{class:"logo",src:Wn(a.value),alt:u.value});return n.value.logoDark===void 0?p:he(Bn,()=>p)}};return Object.defineProperty(_,"__isScriptSetup",{enumerable:!1,value:!0}),_}}),Jv=["aria-hidden"];function Qv(e,t,l,i,n,r){const o=mt("RouterLink");return W(),Ae(o,{to:i.navbarBrandLink},{default:Ce(()=>[ne(i.NavbarBrandLogo),i.navbarBrandTitle?(W(),ee("span",{key:0,class:$e(["site-name",{"can-hide":i.navbarBrandLogo}]),"aria-hidden":i.navBarLogoAltMatchesTitle},Pe(i.navbarBrandTitle),11,Jv)):Le("",!0)]),_:1},8,["to"])}const Zv=xe(Yv,[["render",Qv],["__file","NavbarBrand.vue"]]),e_=_e({__name:"DropdownTransition",setup(e,{expose:t}){t();const n={setHeight:r=>{r.style.height=r.scrollHeight+"px"},unsetHeight:r=>{r.style.height=""}};return Object.defineProperty(n,"__isScriptSetup",{enumerable:!1,value:!0}),n}});function t_(e,t,l,i,n,r){return W(),Ae(Gl,{name:"dropdown",onEnter:i.setHeight,onAfterEnter:i.unsetHeight,onBeforeLeave:i.setHeight},{default:Ce(()=>[be(e.$slots,"default")]),_:3})}const Qs=xe(e_,[["render",t_],["__file","DropdownTransition.vue"]]),l_=_e({__name:"NavbarDropdown",props:{item:{type:Object,required:!0}},setup(e,{expose:t}){t();const l=e,{item:i}=Ii(l),n=C(()=>i.value.ariaLabel||i.value.text),r=ge(!1),o=ml();Ge(()=>o.path,()=>{r.value=!1});const u={props:l,item:i,dropdownAriaLabel:n,open:r,route:o,handleDropdown:d=>{d.detail===0?r.value=!r.value:r.value=!1},isLastItemOfArray:(d,v)=>v[v.length-1]===d,AutoLink:bl,DropdownTransition:Qs};return Object.defineProperty(u,"__isScriptSetup",{enumerable:!1,value:!0}),u}}),i_=["aria-label"],n_={class:"title"},r_=ce("span",{class:"arrow down"},null,-1),o_=["aria-label"],s_={class:"title"},c_={class:"navbar-dropdown"},a_={class:"navbar-dropdown-subtitle"},u_={key:1},d_={class:"navbar-dropdown-subitem-wrapper"};function h_(e,t,l,i,n,r){return W(),ee("div",{class:$e(["navbar-dropdown-wrapper",{open:i.open}])},[ce("button",{class:"navbar-dropdown-title",type:"button","aria-label":i.dropdownAriaLabel,onClick:i.handleDropdown},[ce("span",n_,Pe(i.item.text),1),r_],8,i_),ce("button",{class:"navbar-dropdown-title-mobile",type:"button","aria-label":i.dropdownAriaLabel,onClick:t[0]||(t[0]=o=>i.open=!i.open)},[ce("span",s_,Pe(i.item.text),1),ce("span",{class:$e(["arrow",i.open?"down":"right"])},null,2)],8,o_),ne(i.DropdownTransition,null,{default:Ce(()=>[bi(ce("ul",c_,[(W(!0),ee(ke,null,St(i.item.children,o=>(W(),ee("li",{key:o.text,class:"navbar-dropdown-item"},[o.children?(W(),ee(ke,{key:0},[ce("h4",a_,[o.link?(W(),Ae(i.AutoLink,{key:0,item:o,onFocusout:c=>i.isLastItemOfArray(o,i.item.children)&&o.children.length===0&&(i.open=!1)},null,8,["item","onFocusout"])):(W(),ee("span",u_,Pe(o.text),1))]),ce("ul",d_,[(W(!0),ee(ke,null,St(o.children,c=>(W(),ee("li",{key:c.link,class:"navbar-dropdown-subitem"},[ne(i.AutoLink,{item:c,onFocusout:a=>i.isLastItemOfArray(c,o.children)&&i.isLastItemOfArray(o,i.item.children)&&(i.open=!1)},null,8,["item","onFocusout"])]))),128))])],64)):(W(),Ae(i.AutoLink,{key:1,item:o,onFocusout:c=>i.isLastItemOfArray(o,i.item.children)&&(i.open=!1)},null,8,["item","onFocusout"]))]))),128))],512),[[Li,i.open]])]),_:1})],2)}const v_=xe(l_,[["render",h_],["__file","NavbarDropdown.vue"]]),__=_e({__name:"NavbarItems",setup(e,{expose:t}){t();const l=()=>{const p=bt(),m=Jl(),x=xs(),A=$n(),D=cv(),O=Fe();return C(()=>{const b=Object.keys(x.value.locales);if(b.length<2)return[];const y=p.currentRoute.value.path,H=p.currentRoute.value.fullPath;return[{text:`${O.value.selectLanguageText}`,ariaLabel:`${O.value.selectLanguageAriaLabel??O.value.selectLanguageText}`,children:b.map(N=>{var V,le;const E=((V=x.value.locales)==null?void 0:V[N])??{},K=((le=D.value.locales)==null?void 0:le[N])??{},w=`${E.lang}`,U=K.selectLanguageName??w;let L;if(w===A.value.lang)L=H;else{const ie=y.replace(m.value,N);p.getRoutes().some(S=>S.path===ie)?L=H.replace(y,ie):L=K.home??N}return{text:U,link:L}})}]})},i=()=>{const p=Fe(),m=C(()=>p.value.repo),x=C(()=>m.value?Ks(m.value):null),A=C(()=>m.value&&!Yl(m.value)?`https://github.com/${m.value}`:m.value),D=C(()=>A.value?p.value.repoLabel?p.value.repoLabel:x.value===null?"Source":x.value:null);return C(()=>!A.value||!D.value?[]:[{text:D.value,link:A.value}])},n=(p,m)=>nt(m)?qn(p,m):m.children?{...m,children:m.children.map(x=>n(p,x))}:m,r=()=>{const p=bt(),m=Fe();return C(()=>(m.value.navbar||[]).map(x=>n(p,x)))},o=ge(!1),c=r(),a=l(),u=i(),d=C(()=>[...c.value,...a.value,...u.value]);Js($l.MOBILE,p=>{window.innerWidthFe().value.navbarLabel??"site navigation"),_={useNavbarSelectLanguage:l,useNavbarRepo:i,resolveNavbarItem:n,useNavbarConfig:r,isMobile:o,navbarConfig:c,navbarSelectLanguage:a,navbarRepo:u,navbarLinks:d,navbarLabel:v,AutoLink:bl,NavbarDropdown:v_};return Object.defineProperty(_,"__isScriptSetup",{enumerable:!1,value:!0}),_}}),f_=["aria-label"];function g_(e,t,l,i,n,r){return i.navbarLinks.length?(W(),ee("nav",{key:0,class:"navbar-items","aria-label":i.navbarLabel},[(W(!0),ee(ke,null,St(i.navbarLinks,o=>(W(),ee("div",{key:o.text,class:"navbar-item"},[o.children?(W(),Ae(i.NavbarDropdown,{key:0,item:o,class:$e(i.isMobile?"mobile":"")},null,8,["item","class"])):(W(),Ae(i.AutoLink,{key:1,item:o},null,8,["item"]))]))),128))],8,f_)):Le("",!0)}const Zs=xe(__,[["render",g_],["__file","NavbarItems.vue"]]),p_=_e({__name:"ToggleColorModeButton",setup(e,{expose:t}){t();const l=Fe(),i=Kn(),r={themeLocale:l,isDarkMode:i,toggleColorMode:()=>{i.value=!i.value}};return Object.defineProperty(r,"__isScriptSetup",{enumerable:!1,value:!0}),r}}),m_=["title"],b_={class:"icon",focusable:"false",viewBox:"0 0 32 32"},k_=$a('',9),E_=[k_],y_={class:"icon",focusable:"false",viewBox:"0 0 32 32"},x_=ce("path",{d:"M13.502 5.414a15.075 15.075 0 0 0 11.594 18.194a11.113 11.113 0 0 1-7.975 3.39c-.138 0-.278.005-.418 0a11.094 11.094 0 0 1-3.2-21.584M14.98 3a1.002 1.002 0 0 0-.175.016a13.096 13.096 0 0 0 1.825 25.981c.164.006.328 0 .49 0a13.072 13.072 0 0 0 10.703-5.555a1.01 1.01 0 0 0-.783-1.565A13.08 13.08 0 0 1 15.89 4.38A1.015 1.015 0 0 0 14.98 3z",fill:"currentColor"},null,-1),L_=[x_];function T_(e,t,l,i,n,r){return W(),ee("button",{class:"toggle-color-mode-button",title:i.themeLocale.toggleColorMode,onClick:i.toggleColorMode},[bi((W(),ee("svg",b_,E_,512)),[[Li,!i.isDarkMode]]),bi((W(),ee("svg",y_,L_,512)),[[Li,i.isDarkMode]])],8,m_)}const O_=xe(p_,[["render",T_],["__file","ToggleColorModeButton.vue"]]),P_=_e({__name:"ToggleSidebarButton",emits:["toggle"],setup(e,{expose:t}){t();const i={themeLocale:Fe()};return Object.defineProperty(i,"__isScriptSetup",{enumerable:!1,value:!0}),i}}),A_=["title"],w_=ce("div",{class:"icon","aria-hidden":"true"},[ce("span"),ce("span"),ce("span")],-1),R_=[w_];function I_(e,t,l,i,n,r){return W(),ee("div",{class:"toggle-sidebar-button",title:i.themeLocale.toggleSidebar,"aria-expanded":"false",role:"button",tabindex:"0",onClick:t[0]||(t[0]=o=>e.$emit("toggle"))},R_,8,A_)}const D_=xe(P_,[["render",I_],["__file","ToggleSidebarButton.vue"]]),j_=_e({__name:"Navbar",emits:["toggle-sidebar"],setup(e,{expose:t}){t();const l=Fe(),i=ge(null),n=ge(null),r=ge(0),o=C(()=>r.value?{maxWidth:r.value+"px"}:{});Js($l.MOBILE,u=>{var v;const d=c(i.value,"paddingLeft")+c(i.value,"paddingRight");window.innerWidthe.$emit("toggle-sidebar"))}),ce("span",C_,[ne(i.NavbarBrand)],512),ce("div",{class:"navbar-items-wrapper",style:Wl(i.linksWrapperStyle)},[be(e.$slots,"before"),ne(i.NavbarItems,{class:"can-hide"}),be(e.$slots,"after"),i.themeLocale.colorModeSwitch?(W(),Ae(i.ToggleColorModeButton,{key:0})):Le("",!0),ne(o)],4)],512)}const F_=xe(j_,[["render",V_],["__file","Navbar.vue"]]),N_=_e({__name:"PageMeta",setup(e,{expose:t}){t();const l=()=>{const d=Fe(),v=Gt(),_=pt();return C(()=>{if(!(_.value.editLink??d.value.editLink??!0))return null;const{repo:m,docsRepo:x=m,docsBranch:A="main",docsDir:D="",editLinkText:O}=d.value;if(!x)return null;const b=fv({docsRepo:x,docsBranch:A,docsDir:D,filePathRelative:v.value.filePathRelative,editLinkPattern:_.value.editLinkPattern??d.value.editLinkPattern});return b?{text:O??"Edit this page",link:b}:null})},i=()=>{const d=Fe(),v=Gt(),_=pt();return C(()=>{var x,A;return!(_.value.lastUpdated??d.value.lastUpdated??!0)||!((x=v.value.git)!=null&&x.updatedTime)?null:new Date((A=v.value.git)==null?void 0:A.updatedTime).toLocaleString()})},n=()=>{const d=Fe(),v=Gt(),_=pt();return C(()=>{var m;return _.value.contributors??d.value.contributors??!0?((m=v.value.git)==null?void 0:m.contributors)??null:null})},r=Fe(),o=l(),c=i(),a=n(),u={useEditNavLink:l,useLastUpdated:i,useContributors:n,themeLocale:r,editNavLink:o,lastUpdated:c,contributors:a,AutoLink:bl};return Object.defineProperty(u,"__isScriptSetup",{enumerable:!1,value:!0}),u}}),H_={class:"page-meta"},M_={key:0,class:"meta-item edit-link"},$_={key:1,class:"meta-item last-updated"},B_={class:"meta-item-label"},W_={class:"meta-item-info"},z_={key:2,class:"meta-item contributors"},U_={class:"meta-item-label"},X_={class:"meta-item-info"},K_=["title"];function q_(e,t,l,i,n,r){const o=mt("ClientOnly");return W(),ee("footer",H_,[i.editNavLink?(W(),ee("div",M_,[ne(i.AutoLink,{class:"meta-item-label",item:i.editNavLink},null,8,["item"])])):Le("",!0),i.lastUpdated?(W(),ee("div",$_,[ce("span",B_,Pe(i.themeLocale.lastUpdatedText)+": ",1),ne(o,null,{default:Ce(()=>[ce("span",W_,Pe(i.lastUpdated),1)]),_:1})])):Le("",!0),i.contributors&&i.contributors.length?(W(),ee("div",z_,[ce("span",U_,Pe(i.themeLocale.contributorsText)+": ",1),ce("span",X_,[(W(!0),ee(ke,null,St(i.contributors,(c,a)=>(W(),ee(ke,{key:a},[ce("span",{class:"contributor",title:`email: ${c.email}`},Pe(c.name),9,K_),a!==i.contributors.length-1?(W(),ee(ke,{key:0},[Vt(", ")],64)):Le("",!0)],64))),128))])])):Le("",!0)])}const G_=xe(N_,[["render",q_],["__file","PageMeta.vue"]]),Y_=_e({__name:"PageNav",setup(e,{expose:t}){t();const l=(_,p)=>p===!1?null:nt(p)?qn(_,p):Hn(p)?p:!1,i=(_,p,m)=>{const x=_.findIndex(A=>A.link===p);if(x!==-1){const A=_[x+m];return A!=null&&A.link?A:null}for(const A of _)if(A.children){const D=i(A.children,p,m);if(D)return D}return null},n=pt(),r=Gn(),o=ml(),c=bt(),a=C(()=>{const _=l(c,n.value.prev);return _!==!1?_:i(r.value,o.path,-1)}),u=C(()=>{const _=l(c,n.value.next);return _!==!1?_:i(r.value,o.path,1)}),d=C(()=>Fe().value.pageNavbarLabel??"page navigation"),v={resolveFromFrontmatterConfig:l,resolveFromSidebarItems:i,frontmatter:n,sidebarItems:r,route:o,router:c,prevNavLink:a,nextNavLink:u,navbarLabel:d,AutoLink:bl};return Object.defineProperty(v,"__isScriptSetup",{enumerable:!1,value:!0}),v}}),J_=["aria-label"],Q_={class:"inner"},Z_={key:0,class:"prev"},e2={key:1,class:"next"};function t2(e,t,l,i,n,r){return i.prevNavLink||i.nextNavLink?(W(),ee("nav",{key:0,class:"page-nav","aria-label":i.navbarLabel},[ce("p",Q_,[i.prevNavLink?(W(),ee("span",Z_,[ne(i.AutoLink,{item:i.prevNavLink},null,8,["item"])])):Le("",!0),i.nextNavLink?(W(),ee("span",e2,[ne(i.AutoLink,{item:i.nextNavLink},null,8,["item"])])):Le("",!0)])],8,J_)):Le("",!0)}const l2=xe(Y_,[["render",t2],["__file","PageNav.vue"]]),i2=_e({__name:"Page",setup(e,{expose:t}){t();const l={PageMeta:G_,PageNav:l2};return Object.defineProperty(l,"__isScriptSetup",{enumerable:!1,value:!0}),l}}),n2={class:"page"},r2={class:"theme-default-content"};function o2(e,t,l,i,n,r){const o=mt("Content");return W(),ee("main",n2,[be(e.$slots,"top"),ce("div",r2,[be(e.$slots,"content-top"),ne(o),be(e.$slots,"content-bottom")]),ne(i.PageMeta),ne(i.PageNav),be(e.$slots,"bottom")])}const s2=xe(i2,[["render",o2],["__file","Page.vue"]]),c2=_e({__name:"SidebarItem",props:{item:{type:Object,required:!0},depth:{type:Number,required:!1,default:0}},setup(e,{expose:t}){t();const l=e,{item:i,depth:n}=Ii(l),r=ml(),o=bt(),c=C(()=>Xs(i.value,r)),a=C(()=>({"sidebar-item":!0,"sidebar-heading":n.value===0,active:c.value,collapsible:i.value.collapsible})),u=C(()=>i.value.collapsible?c.value:!0),[d,v]=Kh(u.value),_=x=>{i.value.collapsible&&(x.preventDefault(),v())},p=o.afterEach(x=>{Xl(()=>{d.value=u.value})});ql(()=>{p()});const m={props:l,item:i,depth:n,route:r,router:o,isActive:c,itemClass:a,isOpenDefault:u,isOpen:d,toggleIsOpen:v,onClick:_,unregisterRouterHook:p,AutoLink:bl,DropdownTransition:Qs};return Object.defineProperty(m,"__isScriptSetup",{enumerable:!1,value:!0}),m}}),a2={class:"sidebar-item-children"};function u2(e,t,l,i,n,r){var c;const o=mt("SidebarItem",!0);return W(),ee("li",null,[i.item.link?(W(),Ae(i.AutoLink,{key:0,class:$e(i.itemClass),item:i.item},null,8,["class","item"])):(W(),ee("p",{key:1,tabindex:"0",class:$e(i.itemClass),onClick:i.onClick,onKeydown:Lu(i.onClick,["enter"])},[Vt(Pe(i.item.text)+" ",1),i.item.collapsible?(W(),ee("span",{key:0,class:$e(["arrow",i.isOpen?"down":"right"])},null,2)):Le("",!0)],34)),(c=i.item.children)!=null&&c.length?(W(),Ae(i.DropdownTransition,{key:2},{default:Ce(()=>[bi(ce("ul",a2,[(W(!0),ee(ke,null,St(i.item.children,a=>(W(),Ae(o,{key:`${i.depth}${a.text}${a.link}`,item:a,depth:i.depth+1},null,8,["item","depth"]))),128))],512),[[Li,i.isOpen]])]),_:1})):Le("",!0)])}const d2=xe(c2,[["render",u2],["__file","SidebarItem.vue"]]),h2=_e({__name:"SidebarItems",setup(e,{expose:t}){t();const l=ml(),i=Gn();We(()=>{Ge(()=>l.hash,r=>{const o=document.querySelector(".sidebar");if(!o)return;const c=document.querySelector(`.sidebar a.sidebar-item[href="${l.path}${r}"]`);if(!c)return;const{top:a,height:u}=o.getBoundingClientRect(),{top:d,height:v}=c.getBoundingClientRect();da+u&&c.scrollIntoView(!1)})});const n={route:l,sidebarItems:i,SidebarItem:d2};return Object.defineProperty(n,"__isScriptSetup",{enumerable:!1,value:!0}),n}}),v2={key:0,class:"sidebar-items"};function _2(e,t,l,i,n,r){return i.sidebarItems.length?(W(),ee("ul",v2,[(W(!0),ee(ke,null,St(i.sidebarItems,o=>(W(),Ae(i.SidebarItem,{key:`${o.text}${o.link}`,item:o},null,8,["item"]))),128))])):Le("",!0)}const f2=xe(h2,[["render",_2],["__file","SidebarItems.vue"]]),g2=_e({__name:"Sidebar",setup(e,{expose:t}){t();const l={NavbarItems:Zs,SidebarItems:f2};return Object.defineProperty(l,"__isScriptSetup",{enumerable:!1,value:!0}),l}}),p2={class:"sidebar"};function m2(e,t,l,i,n,r){return W(),ee("aside",p2,[ne(i.NavbarItems),be(e.$slots,"top"),ne(i.SidebarItems),be(e.$slots,"bottom")])}const b2=xe(g2,[["render",m2],["__file","Sidebar.vue"]]),k2=_e({__name:"Layout",setup(e,{expose:t}){t();const l=Gt(),i=pt(),n=Fe(),r=C(()=>i.value.navbar!==!1&&n.value.navbar!==!1),o=Gn(),c=ge(!1),a=O=>{c.value=typeof O=="boolean"?O:!c.value},u={x:0,y:0},d=O=>{u.x=O.changedTouches[0].clientX,u.y=O.changedTouches[0].clientY},v=O=>{const b=O.changedTouches[0].clientX-u.x,y=O.changedTouches[0].clientY-u.y;Math.abs(b)>Math.abs(y)&&Math.abs(b)>40&&(b>0&&u.x<=80?a(!0):a(!1))},_=C(()=>[{"no-navbar":!r.value,"no-sidebar":!o.value.length,"sidebar-open":c.value},i.value.pageClass]);let p;We(()=>{p=bt().afterEach(()=>{a(!1)})}),Ci(()=>{p()});const m=zs(),x=m.resolve,A=m.pending,D={page:l,frontmatter:i,themeLocale:n,shouldShowNavbar:r,sidebarItems:o,isSidebarOpen:c,toggleSidebar:a,touchStart:u,onTouchStart:d,onTouchEnd:v,containerClass:_,get unregisterRouterHook(){return p},set unregisterRouterHook(O){p=O},scrollPromise:m,onBeforeEnter:x,onBeforeLeave:A,Home:Gv,Navbar:F_,Page:s2,Sidebar:b2};return Object.defineProperty(D,"__isScriptSetup",{enumerable:!1,value:!0}),D}});function E2(e,t,l,i,n,r){return W(),ee("div",{class:$e(["theme-container",i.containerClass]),onTouchstart:i.onTouchStart,onTouchend:i.onTouchEnd},[be(e.$slots,"navbar",{},()=>[i.shouldShowNavbar?(W(),Ae(i.Navbar,{key:0,onToggleSidebar:i.toggleSidebar},{before:Ce(()=>[be(e.$slots,"navbar-before")]),after:Ce(()=>[be(e.$slots,"navbar-after")]),_:3})):Le("",!0)]),ce("div",{class:"sidebar-mask",onClick:t[0]||(t[0]=o=>i.toggleSidebar(!1))}),be(e.$slots,"sidebar",{},()=>[ne(i.Sidebar,null,{top:Ce(()=>[be(e.$slots,"sidebar-top")]),bottom:Ce(()=>[be(e.$slots,"sidebar-bottom")]),_:3})]),be(e.$slots,"page",{},()=>[i.frontmatter.home?(W(),Ae(i.Home,{key:0})):(W(),Ae(Gl,{key:1,name:"fade-slide-y",mode:"out-in",onBeforeEnter:i.onBeforeEnter,onBeforeLeave:i.onBeforeLeave},{default:Ce(()=>[(W(),Ae(i.Page,{key:i.page.path},{top:Ce(()=>[be(e.$slots,"page-top")]),"content-top":Ce(()=>[be(e.$slots,"page-content-top")]),"content-bottom":Ce(()=>[be(e.$slots,"page-content-bottom")]),bottom:Ce(()=>[be(e.$slots,"page-bottom")]),_:3}))]),_:3},8,["onBeforeEnter","onBeforeLeave"]))])],34)}const y2=xe(k2,[["render",E2],["__file","Layout.vue"]]),x2=_e({__name:"NotFound",setup(e,{expose:t}){t();const l=Jl(),i=Fe(),n=i.value.notFound??["Not Found"],r=()=>n[Math.floor(Math.random()*n.length)],o=i.value.home??l.value,c=i.value.backToHome??"Back to home",a={routeLocale:l,themeLocale:i,messages:n,getMsg:r,homeLink:o,homeText:c};return Object.defineProperty(a,"__isScriptSetup",{enumerable:!1,value:!0}),a}}),L2={class:"theme-container"},T2={class:"page"},O2={class:"theme-default-content"},P2=ce("h1",null,"404",-1);function A2(e,t,l,i,n,r){const o=mt("RouterLink");return W(),ee("div",L2,[ce("main",T2,[ce("div",O2,[P2,ce("blockquote",null,Pe(i.getMsg()),1),ne(o,{to:i.homeLink},{default:Ce(()=>[Vt(Pe(i.homeText),1)]),_:1},8,["to"])])])])}const w2=xe(x2,[["render",A2],["__file","NotFound.vue"]]),R2=Et({enhance({app:e,router:t}){e.component("Badge",Ch),e.component("CodeGroup",nv),e.component("CodeGroupItem",sv),e.component("AutoLinkExternalIcon",()=>{const i=e.component("ExternalLinkIcon");return i?he(i):null}),e.component("NavbarSearch",()=>{const i=e.component("Docsearch")||e.component("SearchBox");return i?he(i):null});const l=t.options.scrollBehavior;t.options.scrollBehavior=async(...i)=>(await zs().wait(),l(...i))},setup(){av(),gv()},layouts:{Layout:y2,NotFound:w2}}),I2=e=>typeof e=="string",D2=(e,t)=>I2(e)&&e.startsWith(t),j2=e=>D2(e,"/"),S2={"/":"https://github.com/XTLS/Xray-docs-next"},C2={"/":{lang:"zh-CN",untranslated:{title:"提示",content:(e,t)=>`此页面尚未翻译${t?`,在${e("此处",t)}了解如何帮我们翻译`:""}。`},outdated:{title:"警告",content:(e,t,l,i)=>{const n=r=>{const o=new Date(r);return`${o.getFullYear()}年${o.getMonth()}月${o.getDate()}日`};return`本页面最后修改于${n(l)},原文已在${n(t)}更新。${e("查看原文",i)}`}}},"/en/":{lang:"en-US",untranslated:{title:"Notice",content:(e,t)=>`This page has not yet been translated${t?`, see how you can help ${e("here",t)}`:""}.`},outdated:{title:"Warning",content:(e,t,l,i)=>{const n=["January","February","March","April","May","June","July","August","September","October","November","December"],r=o=>{const c=new Date(o);return`${c.getDate()} ${n[c.getMonth()]} ${c.getFullYear()}`};return`This translation was modified on ${r(l)} and an updated version (${r(t)}) is available on the source page. ${e("View the original page",i)}`}}},"/ru/":{lang:"en-US",untranslated:{title:"Notice",content:(e,t)=>`This page has not yet been translated${t?`, see how you can help ${e("here",t)}`:""}.`},outdated:{title:"Warning",content:(e,t,l,i)=>{const n=["January","February","March","April","May","June","July","August","September","October","November","December"],r=o=>{const c=new Date(o);return`${c.getDate()} ${n[c.getMonth()]} ${c.getFullYear()}`};return`This translation was modified on ${r(l)} and an updated version (${r(t)}) is available on the source page. ${e("View the original page",i)}`}}}};var V2=["custom-container","hint-container"],F2=["custom-container-title","hint-container-title"],N2=V2,Tl="/",H2=F2,ho=S2,vo=C2,M2=()=>C(()=>{const{outdated:e=!1,pathLocale:t=Tl,sourceLink:l,sourceUpdatedTime:i,untranslated:n=!1,updatedTime:r}=Gt().value.i18n??{},o=vo[t??Tl]??vo[Tl],c=ho[t]??ho[Tl];return{isOutdated:e,isUntranslated:n,locale:o,options:{baseLocalePath:Tl,containerClass:N2,titleClass:H2},pathLocale:t,sourceLink:l,sourceUpdatedTime:i,translationGuide:c,updatedTime:r}}),Jn=_e({__name:"I18nTip",setup(e,{expose:t}){t();const l=(m,x)=>`${m}`,i=(m,x,A)=>{switch(m){case"untranslated":return x.untranslated.content(l,A.translationGuide);case"outdated":return!A.updatedTime||!A.sourceUpdatedTime||!A.sourceLink?null:x.outdated.content(l,A.sourceUpdatedTime,A.updatedTime,A.sourceLink);default:return null}},n=M2(),{containerClass:r,titleClass:o}=n.value.options,c=C(()=>n.value.locale),a=C(()=>n.value.isUntranslated||n.value.isOutdated),u=C(()=>n.value.isUntranslated?"untranslated":"outdated"),d=C(()=>u.value==="untranslated"?"tip":"warning"),v=C(()=>c.value[u.value].title),_=C(()=>a.value?i(u.value,c.value,n.value):null),p={linkRenderer:l,getContent:i,i18nData:n,containerClass:r,titleClass:o,locale:c,showTips:a,tipType:u,containerType:d,containerTitle:v,containerContent:_};return Object.defineProperty(p,"__isScriptSetup",{enumerable:!1,value:!0}),p}}),$2=["innerHTML"];function B2(e,t,l,i,n,r){return i.showTips&&i.containerContent?(W(),ee("div",{key:0,class:$e([...i.containerClass,i.containerType])},[ce("p",{class:$e(i.titleClass)},Pe(i.containerTitle),3),Le("eslint-disable-next-line vue/no-v-html "),ce("p",{innerHTML:i.containerContent},null,8,$2)],2)):Le("v-if",!0)}Jn.render=B2;Jn.__file="src/client/components/I18nTip.vue";var W2=Jn,z2=Et({enhance({app:e}){e.component("I18nTip",W2)}});const U2=e=>e instanceof Element?document.activeElement===e&&(["TEXTAREA","SELECT","INPUT"].includes(e.tagName)||e.hasAttribute("contenteditable")):!1,X2=(e,t)=>t.some(l=>{if(nt(l))return l===e.key;const{key:i,ctrl:n=!1,shift:r=!1,alt:o=!1}=l;return i===e.key&&n===e.ctrlKey&&r===e.shiftKey&&o===e.altKey}),K2=/[^\x00-\x7F]/,q2=e=>e.split(/\s+/g).map(t=>t.trim()).filter(t=>!!t),_o=e=>e.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&"),fo=(e,t)=>{const l=t.join(" "),i=q2(e);if(K2.test(e))return i.some(o=>l.toLowerCase().indexOf(o)>-1);const n=e.endsWith(" ");return new RegExp(i.map((o,c)=>i.length===c+1&&!n?`(?=.*\\b${_o(o)})`:`(?=.*\\b${_o(o)}\\b)`).join("")+".+","gi").test(l)},G2=({input:e,hotKeys:t})=>{if(t.value.length===0)return;const l=i=>{e.value&&X2(i,t.value)&&!U2(i.target)&&(i.preventDefault(),e.value.focus())};We(()=>{document.addEventListener("keydown",l)}),ql(()=>{document.removeEventListener("keydown",l)})},Y2=[{title:"",headers:[{level:2,title:"XTLS ? Xray ? V2Ray ?",slug:"xtls-xray-v2ray",link:"#xtls-xray-v2ray",children:[{level:3,title:"我们是谁?",slug:"我们是谁",link:"#我们是谁",children:[]},{level:3,title:"帮助 Xray 变得更强",slug:"帮助-xray-变得更强",link:"#帮助-xray-变得更强",children:[]},{level:3,title:"Telegram",slug:"telegram",link:"#telegram",children:[]},{level:3,title:"致谢",slug:"致谢",link:"#致谢",children:[]},{level:3,title:"更多关于 Project X",slug:"更多关于-project-x",link:"#更多关于-project-x",children:[]},{level:3,title:"License",slug:"license",link:"#license",children:[]},{level:3,title:"Stargazers over time",slug:"stargazers-over-time",link:"#stargazers-over-time",children:[]}]}],path:"/",pathLocale:"/",extraFields:[]},{title:"大史记",headers:[{level:2,title:"2024.9.12",slug:"_2024-9-12",link:"#_2024-9-12",children:[]},{level:2,title:"2024.9.7 v24.9.7",slug:"_2024-9-7-v24-9-7",link:"#_2024-9-7-v24-9-7",children:[]},{level:2,title:"2024.8.30 v1.8.24",slug:"_2024-8-30-v1-8-24",link:"#_2024-8-30-v1-8-24",children:[]},{level:2,title:"2024.8.26",slug:"_2024-8-26",link:"#_2024-8-26",children:[]},{level:2,title:"2024.8.3",slug:"_2024-8-3",link:"#_2024-8-3",children:[]},{level:2,title:"2024.7.29 v1.8.23",slug:"_2024-7-29-v1-8-23",link:"#_2024-7-29-v1-8-23",children:[]},{level:2,title:"2024.7.22 v1.8.21",slug:"_2024-7-22-v1-8-21",link:"#_2024-7-22-v1-8-21",children:[]},{level:2,title:"2024.7.16",slug:"_2024-7-16",link:"#_2024-7-16",children:[]},{level:2,title:"2024.7.15",slug:"_2024-7-15",link:"#_2024-7-15",children:[]},{level:2,title:"2024.6.18 v1.8.16",slug:"_2024-6-18-v1-8-16",link:"#_2024-6-18-v1-8-16",children:[]},{level:2,title:"2024.6.2",slug:"_2024-6-2",link:"#_2024-6-2",children:[]},{level:2,title:"2024.4.26 v1.8.11",slug:"_2024-4-26-v1-8-11",link:"#_2024-4-26-v1-8-11",children:[]},{level:2,title:"2024.4.20",slug:"_2024-4-20",link:"#_2024-4-20",children:[]},{level:2,title:"2024.4.13",slug:"_2024-4-13",link:"#_2024-4-13",children:[]},{level:2,title:"2024.3.18 v1.8.10",slug:"_2024-3-18-v1-8-10",link:"#_2024-3-18-v1-8-10",children:[]},{level:2,title:"2024.3.11 v1.8.9",slug:"_2024-3-11-v1-8-9",link:"#_2024-3-11-v1-8-9",children:[]},{level:2,title:"2024.2.29",slug:"_2024-2-29",link:"#_2024-2-29",children:[]},{level:2,title:"2024.2.25 v1.8.8",slug:"_2024-2-25-v1-8-8",link:"#_2024-2-25-v1-8-8",children:[]},{level:2,title:"2024.1.9",slug:"_2024-1-9",link:"#_2024-1-9",children:[]},{level:2,title:"2023.11.21",slug:"_2023-11-21",link:"#_2023-11-21",children:[]},{level:2,title:"2023.11.18 v1.8.6",slug:"_2023-11-18-v1-8-6",link:"#_2023-11-18-v1-8-6",children:[]},{level:2,title:"2023.9.30",slug:"_2023-9-30",link:"#_2023-9-30",children:[]},{level:2,title:"2023.8.29 v1.8.4",slug:"_2023-8-29-v1-8-4",link:"#_2023-8-29-v1-8-4",children:[]},{level:2,title:"2023.7.22",slug:"_2023-7-22",link:"#_2023-7-22",children:[]},{level:2,title:"2023.7.7",slug:"_2023-7-7",link:"#_2023-7-7",children:[]},{level:2,title:"2023.6.30",slug:"_2023-6-30",link:"#_2023-6-30",children:[]},{level:2,title:"2023.6.27",slug:"_2023-6-27",link:"#_2023-6-27",children:[]},{level:2,title:"2023.6.19 v1.8.3",slug:"_2023-6-19-v1-8-3",link:"#_2023-6-19-v1-8-3",children:[]},{level:2,title:"2023.6.6",slug:"_2023-6-6",link:"#_2023-6-6",children:[]},{level:2,title:"2023.4.21",slug:"_2023-4-21",link:"#_2023-4-21",children:[]},{level:2,title:"2023.4.20",slug:"_2023-4-20",link:"#_2023-4-20",children:[]},{level:2,title:"2023.4.19",slug:"_2023-4-19",link:"#_2023-4-19",children:[]},{level:2,title:"2023.4.18 v1.8.1",slug:"_2023-4-18-v1-8-1",link:"#_2023-4-18-v1-8-1",children:[]},{level:2,title:"2023.4.6",slug:"_2023-4-6",link:"#_2023-4-6",children:[]},{level:2,title:"2023.3.29",slug:"_2023-3-29",link:"#_2023-3-29",children:[]},{level:2,title:"2023.3.19",slug:"_2023-3-19",link:"#_2023-3-19",children:[]},{level:2,title:"2023.3.9 v1.8.0",slug:"_2023-3-9-v1-8-0",link:"#_2023-3-9-v1-8-0",children:[]},{level:2,title:"2023.3.4",slug:"_2023-3-4",link:"#_2023-3-4",children:[]},{level:2,title:"2023.3.2",slug:"_2023-3-2",link:"#_2023-3-2",children:[]},{level:2,title:"2023.2.16",slug:"_2023-2-16",link:"#_2023-2-16",children:[]},{level:2,title:"2023.2.9",slug:"_2023-2-9",link:"#_2023-2-9",children:[]},{level:2,title:"2023.2.8 v1.7.5",slug:"_2023-2-8-v1-7-5",link:"#_2023-2-8-v1-7-5",children:[]},{level:2,title:"2023.1.29",slug:"_2023-1-29",link:"#_2023-1-29",children:[]},{level:2,title:"2022.12.26 v1.7.0",slug:"_2022-12-26-v1-7-0",link:"#_2022-12-26-v1-7-0",children:[]},{level:2,title:"2022.11.28 v1.6.5",slug:"_2022-11-28-v1-6-5",link:"#_2022-11-28-v1-6-5",children:[]},{level:2,title:"2022.11.7 v1.6.3",slug:"_2022-11-7-v1-6-3",link:"#_2022-11-7-v1-6-3",children:[]},{level:2,title:"2022.10.29 v1.6.2",slug:"_2022-10-29-v1-6-2",link:"#_2022-10-29-v1-6-2",children:[]},{level:2,title:"2022.10.22 v1.6.1",slug:"_2022-10-22-v1-6-1",link:"#_2022-10-22-v1-6-1",children:[]},{level:2,title:"2022.10.3",slug:"_2022-10-3",link:"#_2022-10-3",children:[]},{level:2,title:"2022.8.28 v1.5.10",slug:"_2022-8-28-v1-5-10",link:"#_2022-8-28-v1-5-10",children:[]},{level:2,title:"2022.6.20 v1.5.8",slug:"_2022-6-20-v1-5-8",link:"#_2022-6-20-v1-5-8",children:[]},{level:2,title:"2022.5.29 v1.5.6",slug:"_2022-5-29-v1-5-6",link:"#_2022-5-29-v1-5-6",children:[]},{level:2,title:"2022.4.24 v1.5.5",slug:"_2022-4-24-v1-5-5",link:"#_2022-4-24-v1-5-5",children:[]},{level:2,title:"2022.3.13 v1.5.4",slug:"_2022-3-13-v1-5-4",link:"#_2022-3-13-v1-5-4",children:[]},{level:2,title:"2022.1.29 v1.5.3",slug:"_2022-1-29-v1-5-3",link:"#_2022-1-29-v1-5-3",children:[]},{level:2,title:"2021.12.24 v1.5.2",slug:"_2021-12-24-v1-5-2",link:"#_2021-12-24-v1-5-2",children:[]},{level:2,title:"2021.12.15 v1.5.1",slug:"_2021-12-15-v1-5-1",link:"#_2021-12-15-v1-5-1",children:[]},{level:2,title:"2021.10.20 v1.5.0",slug:"_2021-10-20-v1-5-0",link:"#_2021-10-20-v1-5-0",children:[]},{level:2,title:"2021.9.23 v1.4.5",slug:"_2021-9-23-v1-4-5",link:"#_2021-9-23-v1-4-5",children:[]},{level:2,title:"2021.9.16",slug:"_2021-9-16",link:"#_2021-9-16",children:[]},{level:2,title:"2021.9.8 v1.4.3",slug:"_2021-9-8-v1-4-3",link:"#_2021-9-8-v1-4-3",children:[]},{level:2,title:"2021.7.14",slug:"_2021-7-14",link:"#_2021-7-14",children:[]},{level:2,title:"2021.6.21",slug:"_2021-6-21",link:"#_2021-6-21",children:[]},{level:2,title:"2021.5.1",slug:"_2021-5-1",link:"#_2021-5-1",children:[]},{level:2,title:"2021.4.26",slug:"_2021-4-26",link:"#_2021-4-26",children:[]},{level:2,title:"2021.4.12",slug:"_2021-4-12",link:"#_2021-4-12",children:[]},{level:2,title:"2021.4.6",slug:"_2021-4-6",link:"#_2021-4-6",children:[]},{level:2,title:"2021.4.4",slug:"_2021-4-4",link:"#_2021-4-4",children:[]},{level:2,title:"2021.4.1 v1.4.2",slug:"_2021-4-1-v1-4-2",link:"#_2021-4-1-v1-4-2",children:[]},{level:2,title:"2021.3.25",slug:"_2021-3-25",link:"#_2021-3-25",children:[]},{level:2,title:"2021.3.15",slug:"_2021-3-15",link:"#_2021-3-15",children:[]},{level:2,title:"2021.3.14 v1.4.0",slug:"_2021-3-14-v1-4-0",link:"#_2021-3-14-v1-4-0",children:[]},{level:2,title:"2021.3.3 1.3.1",slug:"_2021-3-3-1-3-1",link:"#_2021-3-3-1-3-1",children:[]},{level:2,title:"2021.2.14 1.3.0",slug:"_2021-2-14-1-3-0",link:"#_2021-2-14-1-3-0",children:[]},{level:2,title:"2021.01.31 1.2.4",slug:"_2021-01-31-1-2-4",link:"#_2021-01-31-1-2-4",children:[]},{level:2,title:"2021.01.25",slug:"_2021-01-25",link:"#_2021-01-25",children:[]},{level:2,title:"2021.01.22 1.2.3",slug:"_2021-01-22-1-2-3",link:"#_2021-01-22-1-2-3",children:[]},{level:2,title:"2021.01.19",slug:"_2021-01-19",link:"#_2021-01-19",children:[]},{level:2,title:"2021.01.17",slug:"_2021-01-17",link:"#_2021-01-17",children:[]},{level:2,title:"2021.01.15 1.2.2",slug:"_2021-01-15-1-2-2",link:"#_2021-01-15-1-2-2",children:[]},{level:2,title:"2021.01.12",slug:"_2021-01-12",link:"#_2021-01-12",children:[]},{level:2,title:"2021.01.10 1.2.1",slug:"_2021-01-10-1-2-1",link:"#_2021-01-10-1-2-1",children:[]},{level:2,title:"2021.01.07",slug:"_2021-01-07",link:"#_2021-01-07",children:[]},{level:2,title:"2021.01.05",slug:"_2021-01-05",link:"#_2021-01-05",children:[]},{level:2,title:"2021.01.03",slug:"_2021-01-03",link:"#_2021-01-03",children:[]},{level:2,title:"2021.01.01",slug:"_2021-01-01",link:"#_2021-01-01",children:[]},{level:2,title:"2020.12.29",slug:"_2020-12-29",link:"#_2020-12-29",children:[]},{level:2,title:"2020.12.25 1.1.5",slug:"_2020-12-25-1-1-5",link:"#_2020-12-25-1-1-5",children:[]},{level:2,title:"2020.12.24",slug:"_2020-12-24",link:"#_2020-12-24",children:[]},{level:2,title:"2020.12.23",slug:"_2020-12-23",link:"#_2020-12-23",children:[]},{level:2,title:"2020.12.21",slug:"_2020-12-21",link:"#_2020-12-21",children:[]},{level:2,title:"2020.12.18 1.1.4",slug:"_2020-12-18-1-1-4",link:"#_2020-12-18-1-1-4",children:[]},{level:2,title:"2020.12.17",slug:"_2020-12-17",link:"#_2020-12-17",children:[]},{level:2,title:"2020.12.15",slug:"_2020-12-15",link:"#_2020-12-15",children:[]},{level:2,title:"2020.12.11 1.1.3",slug:"_2020-12-11-1-1-3",link:"#_2020-12-11-1-1-3",children:[]},{level:2,title:"2020.12.06 1.1.2",slug:"_2020-12-06-1-1-2",link:"#_2020-12-06-1-1-2",children:[]},{level:2,title:"2020.12.04",slug:"_2020-12-04",link:"#_2020-12-04",children:[]},{level:2,title:"2020.11.27",slug:"_2020-11-27",link:"#_2020-11-27",children:[]},{level:2,title:"2020.11.25 1.0.0",slug:"_2020-11-25-1-0-0",link:"#_2020-11-25-1-0-0",children:[]},{level:2,title:"2020.11.23",slug:"_2020-11-23",link:"#_2020-11-23",children:[]}],path:"/about/news.html",pathLocale:"/",extraFields:[]},{title:"开发指南",headers:[{level:2,title:"编译文档",slug:"编译文档",link:"#编译文档",children:[]},{level:2,title:"设计思路",slug:"设计思路",link:"#设计思路",children:[]},{level:2,title:"开发规范",slug:"开发规范",link:"#开发规范",children:[]},{level:2,title:"协议详解",slug:"协议详解",link:"#协议详解",children:[{level:3,title:"VLESS 协议",slug:"vless-协议",link:"#vless-协议",children:[]},{level:3,title:"VMess 协议",slug:"vmess-协议",link:"#vmess-协议",children:[]},{level:3,title:"Mux.Cool 协议",slug:"mux-cool-协议",link:"#mux-cool-协议",children:[]},{level:3,title:"mKCP 协议",slug:"mkcp-协议",link:"#mkcp-协议",children:[]}]}],path:"/development/",pathLocale:"/",extraFields:[]},{title:"配置文件",headers:[{level:2,title:"概述",slug:"概述",link:"#概述",children:[]},{level:2,title:"基础配置模块",slug:"基础配置模块",link:"#基础配置模块",children:[]}],path:"/config/",pathLocale:"/",extraFields:[]},{title:"API 接口",headers:[{level:2,title:"ApiObject",slug:"apiobject",link:"#apiobject",children:[]},{level:2,title:"相关配置",slug:"相关配置",link:"#相关配置",children:[]},{level:2,title:"支持的 API 列表",slug:"支持的-api-列表",link:"#支持的-api-列表",children:[{level:3,title:"HandlerService",slug:"handlerservice",link:"#handlerservice",children:[]},{level:3,title:"RoutingService",slug:"routingservice",link:"#routingservice",children:[]},{level:3,title:"LoggerService",slug:"loggerservice",link:"#loggerservice",children:[]},{level:3,title:"StatsService",slug:"statsservice",link:"#statsservice",children:[]},{level:3,title:"ReflectionService",slug:"reflectionservice",link:"#reflectionservice",children:[]}]},{level:2,title:"API 调用示例",slug:"api-调用示例",link:"#api-调用示例",children:[]}],path:"/config/api.html",pathLocale:"/",extraFields:[]},{title:"内置 DNS 服务器",headers:[{level:2,title:"DNS 服务器",slug:"dns-服务器",link:"#dns-服务器",children:[]},{level:2,title:"DNS 处理流程",slug:"dns-处理流程",link:"#dns-处理流程",children:[]},{level:2,title:"DnsObject",slug:"dnsobject",link:"#dnsobject",children:[{level:3,title:"ServerObject",slug:"serverobject",link:"#serverobject",children:[]}]}],path:"/config/dns.html",pathLocale:"/",extraFields:[]},{title:"FakeDNS",headers:[{level:2,title:"FakeDNSObject",slug:"fakednsobject",link:"#fakednsobject",children:[{level:3,title:"如何使用?",slug:"如何使用",link:"#如何使用",children:[]},{level:3,title:"与其它类型 DNS 搭配使用",slug:"与其它类型-dns-搭配使用",link:"#与其它类型-dns-搭配使用",children:[]}]}],path:"/config/fakedns.html",pathLocale:"/",extraFields:[]},{title:"入站代理",headers:[{level:2,title:"InboundObject",slug:"inboundobject",link:"#inboundobject",children:[{level:3,title:"SniffingObject",slug:"sniffingobject",link:"#sniffingobject",children:[]},{level:3,title:"AllocateObject",slug:"allocateobject",link:"#allocateobject",children:[]}]}],path:"/config/inbound.html",pathLocale:"/",extraFields:[]},{title:"日志配置",headers:[{level:2,title:"LogObject",slug:"logobject",link:"#logobject",children:[]}],path:"/config/log.html",pathLocale:"/",extraFields:[]},{title:"Metrics",headers:[{level:2,title:"相关配置",slug:"相关配置",link:"#相关配置",children:[]},{level:2,title:"使用方法",slug:"使用方法",link:"#使用方法",children:[{level:3,title:"pprof",slug:"pprof",link:"#pprof",children:[]},{level:3,title:"expvars",slug:"expvars",link:"#expvars",children:[]},{level:3,title:"Additional",slug:"additional",link:"#additional",children:[]}]}],path:"/config/metrics.html",pathLocale:"/",extraFields:[]},{title:"连接观测",headers:[{level:2,title:"ObservatoryObject",slug:"observatoryobject",link:"#observatoryobject",children:[]},{level:2,title:"BurstObservatoryObject",slug:"burstobservatoryobject",link:"#burstobservatoryobject",children:[{level:3,title:"PingConfigObject",slug:"pingconfigobject",link:"#pingconfigobject",children:[]}]}],path:"/config/observatory.html",pathLocale:"/",extraFields:[]},{title:"出站代理(Mux、XUDP)",headers:[{level:2,title:"OutboundObject",slug:"outboundobject",link:"#outboundobject",children:[{level:3,title:"ProxySettingsObject",slug:"proxysettingsobject",link:"#proxysettingsobject",children:[]},{level:3,title:"MuxObject",slug:"muxobject",link:"#muxobject",children:[]}]}],path:"/config/outbound.html",pathLocale:"/",extraFields:[]},{title:"本地策略",headers:[{level:2,title:"PolicyObject",slug:"policyobject",link:"#policyobject",children:[{level:3,title:"LevelPolicyObject",slug:"levelpolicyobject",link:"#levelpolicyobject",children:[]},{level:3,title:"SystemPolicyObject",slug:"systempolicyobject",link:"#systempolicyobject",children:[]}]}],path:"/config/policy.html",pathLocale:"/",extraFields:[]},{title:"反向代理",headers:[{level:2,title:"ReverseObject",slug:"reverseobject",link:"#reverseobject",children:[{level:3,title:"BridgeObject",slug:"bridgeobject",link:"#bridgeobject",children:[]},{level:3,title:"PortalObject",slug:"portalobject",link:"#portalobject",children:[]}]},{level:2,title:"完整配置样例",slug:"完整配置样例",link:"#完整配置样例",children:[{level:3,title:"bridge 配置",slug:"bridge-配置",link:"#bridge-配置",children:[]},{level:3,title:"portal 配置",slug:"portal-配置",link:"#portal-配置",children:[]}]}],path:"/config/reverse.html",pathLocale:"/",extraFields:[]},{title:"路由",headers:[{level:2,title:"RoutingObject",slug:"routingobject",link:"#routingobject",children:[{level:3,title:"RuleObject",slug:"ruleobject",link:"#ruleobject",children:[]},{level:3,title:"BalancerObject",slug:"balancerobject",link:"#balancerobject",children:[]},{level:3,title:"负载均衡配置示例",slug:"负载均衡配置示例",link:"#负载均衡配置示例",children:[]},{level:3,title:"预定义域名列表",slug:"预定义域名列表",link:"#预定义域名列表",children:[]}]}],path:"/config/routing.html",pathLocale:"/",extraFields:[]},{title:"统计信息",headers:[{level:2,title:"StatsObject",slug:"statsobject",link:"#statsobject",children:[]},{level:2,title:"获取统计信息",slug:"获取统计信息",link:"#获取统计信息",children:[]}],path:"/config/stats.html",pathLocale:"/",extraFields:[]},{title:"传输方式(uTLS、REALITY)",headers:[{level:2,title:"StreamSettingsObject",slug:"streamsettingsobject",link:"#streamsettingsobject",children:[{level:3,title:"TLSObject",slug:"tlsobject",link:"#tlsobject",children:[]},{level:3,title:"RealityObject",slug:"realityobject",link:"#realityobject",children:[]},{level:3,title:"SockoptObject",slug:"sockoptobject",link:"#sockoptobject",children:[]}]}],path:"/config/transport.html",pathLocale:"/",extraFields:[]},{title:"快速入门",headers:[{level:2,title:"下载安装",slug:"下载安装",link:"#下载安装",children:[]},{level:2,title:"配置运行",slug:"配置运行",link:"#配置运行",children:[]},{level:2,title:"命令参数",slug:"命令参数",link:"#命令参数",children:[]},{level:2,title:"改进文档",slug:"改进文档",link:"#改进文档",children:[]},{level:2,title:"小小白白话文",slug:"小小白白话文",link:"#小小白白话文",children:[]},{level:2,title:"入门技巧",slug:"入门技巧",link:"#入门技巧",children:[]},{level:2,title:"进阶文档",slug:"进阶文档",link:"#进阶文档",children:[]}],path:"/document/",pathLocale:"/",extraFields:[]},{title:"命令参数",headers:[{level:2,title:"获取基本命令",slug:"获取基本命令",link:"#获取基本命令",children:[{level:3,title:"xray run",slug:"xray-run",link:"#xray-run",children:[]},{level:3,title:"xray version",slug:"xray-version",link:"#xray-version",children:[]},{level:3,title:"xray api",slug:"xray-api",link:"#xray-api",children:[]},{level:3,title:"xray convert",slug:"xray-convert",link:"#xray-convert",children:[]},{level:3,title:"xray tls",slug:"xray-tls",link:"#xray-tls",children:[]},{level:3,title:"xray uuid",slug:"xray-uuid",link:"#xray-uuid",children:[]},{level:3,title:"xray x25519",slug:"xray-x25519",link:"#xray-x25519",children:[]},{level:3,title:"xray wg",slug:"xray-wg",link:"#xray-wg",children:[]}]}],path:"/document/command.html",pathLocale:"/",extraFields:[]},{title:"配置运行",headers:[{level:2,title:"服务端配置",slug:"服务端配置",link:"#服务端配置",children:[]},{level:2,title:"客户端配置",slug:"客户端配置",link:"#客户端配置",children:[]},{level:2,title:"运行",slug:"运行",link:"#运行",children:[]}],path:"/document/config.html",pathLocale:"/",extraFields:[]},{title:"为 Project X 的文档贡献",headers:[{level:2,title:"改进文档",slug:"改进文档",link:"#改进文档",children:[]},{level:2,title:"发现问题?",slug:"发现问题",link:"#发现问题",children:[]}],path:"/document/document.html",pathLocale:"/",extraFields:[]},{title:"下载安装",headers:[{level:2,title:"平台支持",slug:"平台支持",link:"#平台支持",children:[]},{level:2,title:"下载 Xray",slug:"下载-xray",link:"#下载-xray",children:[]},{level:2,title:"验证安装包",slug:"验证安装包",link:"#验证安装包",children:[]},{level:2,title:"Windows 安装方式",slug:"windows-安装方式",link:"#windows-安装方式",children:[]},{level:2,title:"macOS 安装方式",slug:"macos-安装方式",link:"#macos-安装方式",children:[]},{level:2,title:"Linux 安装方式",slug:"linux-安装方式",link:"#linux-安装方式",children:[{level:3,title:"安装脚本",slug:"安装脚本",link:"#安装脚本",children:[]},{level:3,title:"Arch Linux",slug:"arch-linux",link:"#arch-linux",children:[]},{level:3,title:"Linuxbrew",slug:"linuxbrew",link:"#linuxbrew",children:[]},{level:3,title:"Debian",slug:"debian",link:"#debian",children:[]},{level:3,title:"Gentoo",slug:"gentoo",link:"#gentoo",children:[]}]},{level:2,title:"Docker 安装方式",slug:"docker-安装方式",link:"#docker-安装方式",children:[{level:3,title:"Docker image 的文件结构",slug:"docker-image-的文件结构",link:"#docker-image-的文件结构",children:[]}]}],path:"/document/install.html",pathLocale:"/",extraFields:[]},{title:"",headers:[{level:2,title:"XTLS? Xray? V2Ray?",slug:"xtls-xray-v2ray",link:"#xtls-xray-v2ray",children:[{level:3,title:"Who are we?",slug:"who-are-we",link:"#who-are-we",children:[]},{level:3,title:"Help Xray become stronger",slug:"help-xray-become-stronger",link:"#help-xray-become-stronger",children:[]},{level:3,title:"Telegram",slug:"telegram",link:"#telegram",children:[]},{level:3,title:"Thanks",slug:"thanks",link:"#thanks",children:[]},{level:3,title:"More about project X",slug:"more-about-project-x",link:"#more-about-project-x",children:[]},{level:3,title:"License",slug:"license",link:"#license",children:[]},{level:3,title:"Stargazers over time",slug:"stargazers-over-time",link:"#stargazers-over-time",children:[]}]}],path:"/en/",pathLocale:"/en/",extraFields:[]},{title:"",headers:[{level:2,title:"XTLS? Xray? V2Ray?",slug:"xtls-xray-v2ray",link:"#xtls-xray-v2ray",children:[{level:3,title:"Кто мы?",slug:"кто-мы",link:"#кто-мы",children:[]},{level:3,title:"Помогите Xray стать сильнее",slug:"помогите-xray-стать-сильнее",link:"#помогите-xray-стать-сильнее",children:[]},{level:3,title:"Telegram",slug:"telegram",link:"#telegram",children:[]},{level:3,title:"Благодарности",slug:"благодарности",link:"#благодарности",children:[]},{level:3,title:"Подробнее о Project X",slug:"подробнее-о-project-x",link:"#подробнее-о-project-x",children:[]},{level:3,title:"Лицензия",slug:"лицензия",link:"#лицензия",children:[]},{level:3,title:"Динамика звезд на GitHub",slug:"динамика-звезд-на-github",link:"#динамика-звезд-на-github",children:[]}]}],path:"/ru/",pathLocale:"/ru/",extraFields:[]},{title:"编译文档",headers:[{level:2,title:"前序工作",slug:"前序工作",link:"#前序工作",children:[]},{level:2,title:"拉取 Xray 源代码",slug:"拉取-xray-源代码",link:"#拉取-xray-源代码",children:[]},{level:2,title:"构建二进制",slug:"构建二进制",link:"#构建二进制",children:[{level:3,title:"Windows(Powershell):",slug:"windows-powershell",link:"#windows-powershell",children:[]},{level:3,title:"macOS, Linux:",slug:"macos-linux",link:"#macos-linux",children:[]}]},{level:2,title:"交叉编译:",slug:"交叉编译",link:"#交叉编译",children:[]},{level:2,title:"可复现构建:",slug:"可复现构建",link:"#可复现构建",children:[]}],path:"/development/intro/compile.html",pathLocale:"/",extraFields:[]},{title:"设计目标",headers:[{level:2,title:"架构",slug:"架构",link:"#架构",children:[{level:3,title:"应用层",slug:"应用层",link:"#应用层",children:[]},{level:3,title:"代理层",slug:"代理层",link:"#代理层",children:[]},{level:3,title:"传输层",slug:"传输层",link:"#传输层",children:[]}]}],path:"/development/intro/design.html",pathLocale:"/",extraFields:[]},{title:"开发规范",headers:[{level:2,title:"基本",slug:"基本",link:"#基本",children:[{level:3,title:"版本控制",slug:"版本控制",link:"#版本控制",children:[]},{level:3,title:"分支(Branch)",slug:"分支-branch",link:"#分支-branch",children:[]},{level:3,title:"发布(Release)",slug:"发布-release",link:"#发布-release",children:[]},{level:3,title:"引用其它项目",slug:"引用其它项目",link:"#引用其它项目",children:[]}]},{level:2,title:"开发流程",slug:"开发流程",link:"#开发流程",children:[{level:3,title:"写代码之前",slug:"写代码之前",link:"#写代码之前",children:[]},{level:3,title:"修改代码",slug:"修改代码",link:"#修改代码",children:[]},{level:3,title:"Pull Request",slug:"pull-request",link:"#pull-request",children:[]},{level:3,title:"对代码的修改",slug:"对代码的修改",link:"#对代码的修改",children:[]}]},{level:2,title:"Xray 编码规范",slug:"xray-编码规范",link:"#xray-编码规范",children:[{level:3,title:"代码结构",slug:"代码结构",link:"#代码结构",children:[]},{level:3,title:"编码规范",slug:"编码规范",link:"#编码规范",children:[]}]}],path:"/development/intro/guide.html",pathLocale:"/",extraFields:[]},{title:"mKCP 协议",headers:[{level:2,title:"版本",slug:"版本",link:"#版本",children:[]},{level:2,title:"依赖",slug:"依赖",link:"#依赖",children:[{level:3,title:"底层协议",slug:"底层协议",link:"#底层协议",children:[]},{level:3,title:"函数",slug:"函数",link:"#函数",children:[]}]},{level:2,title:"通讯过程",slug:"通讯过程",link:"#通讯过程",children:[]},{level:2,title:"数据格式",slug:"数据格式",link:"#数据格式",children:[{level:3,title:"数据包",slug:"数据包",link:"#数据包",children:[]},{level:3,title:"数据片段",slug:"数据片段",link:"#数据片段",children:[]},{level:3,title:"确认片段",slug:"确认片段",link:"#确认片段",children:[]},{level:3,title:"心跳片段",slug:"心跳片段",link:"#心跳片段",children:[]}]}],path:"/development/protocols/mkcp.html",pathLocale:"/",extraFields:[]},{title:"Mux.Cool 协议",headers:[{level:2,title:"版本",slug:"版本",link:"#版本",children:[]},{level:2,title:"依赖",slug:"依赖",link:"#依赖",children:[{level:3,title:"底层协议",slug:"底层协议",link:"#底层协议",children:[]}]},{level:2,title:"通讯过程",slug:"通讯过程",link:"#通讯过程",children:[{level:3,title:"客户端行为",slug:"客户端行为",link:"#客户端行为",children:[]},{level:3,title:"服务器端行为",slug:"服务器端行为",link:"#服务器端行为",children:[]}]},{level:2,title:"传输格式",slug:"传输格式",link:"#传输格式",children:[{level:3,title:"帧格式",slug:"帧格式",link:"#帧格式",children:[]},{level:3,title:"元数据",slug:"元数据",link:"#元数据",children:[]},{level:3,title:"新建子连接 (New)",slug:"新建子连接-new",link:"#新建子连接-new",children:[]},{level:3,title:"保持子连接 (Keep)",slug:"保持子连接-keep",link:"#保持子连接-keep",children:[]},{level:3,title:"关闭子连接 (End)",slug:"关闭子连接-end",link:"#关闭子连接-end",children:[]},{level:3,title:"保持连接 (KeepAlive)",slug:"保持连接-keepalive",link:"#保持连接-keepalive",children:[]}]},{level:2,title:"应用",slug:"应用",link:"#应用",children:[]}],path:"/development/protocols/muxcool.html",pathLocale:"/",extraFields:[]},{title:"VLESS 协议",headers:[{level:2,title:"Request & Response",slug:"request-response",link:"#request-response",children:[]},{level:2,title:"ProtoBuf",slug:"protobuf",link:"#protobuf",children:[]},{level:2,title:"Schedulers Flow",slug:"schedulers-flow",link:"#schedulers-flow",children:[]},{level:2,title:"Encryption",slug:"encryption",link:"#encryption",children:[]},{level:2,title:"UDP issues",slug:"udp-issues",link:"#udp-issues",children:[]},{level:2,title:"客户端开发指引",slug:"客户端开发指引",link:"#客户端开发指引",children:[]},{level:2,title:"VLESS 分享链接标准",slug:"vless-分享链接标准",link:"#vless-分享链接标准",children:[]}],path:"/development/protocols/vless.html",pathLocale:"/",extraFields:[]},{title:"VMess 协议",headers:[{level:2,title:"版本",slug:"版本",link:"#版本",children:[]},{level:2,title:"依赖",slug:"依赖",link:"#依赖",children:[{level:3,title:"底层协议",slug:"底层协议",link:"#底层协议",children:[]},{level:3,title:"用户 ID",slug:"用户-id",link:"#用户-id",children:[]},{level:3,title:"函数",slug:"函数",link:"#函数",children:[]}]},{level:2,title:"通讯过程",slug:"通讯过程",link:"#通讯过程",children:[]},{level:2,title:"客户端请求",slug:"客户端请求",link:"#客户端请求",children:[{level:3,title:"认证信息",slug:"认证信息",link:"#认证信息",children:[]},{level:3,title:"指令部分",slug:"指令部分",link:"#指令部分",children:[]},{level:3,title:"数据部分",slug:"数据部分",link:"#数据部分",children:[]}]},{level:2,title:"服务器应答",slug:"服务器应答",link:"#服务器应答",children:[{level:3,title:"动态端口指令",slug:"动态端口指令",link:"#动态端口指令",children:[]}]},{level:2,title:"注释",slug:"注释",link:"#注释",children:[]}],path:"/development/protocols/vmess.html",pathLocale:"/",extraFields:[]},{title:"Browser Dialer",headers:[{level:2,title:"背景",slug:"背景",link:"#背景",children:[]},{level:2,title:"配置方法",slug:"配置方法",link:"#配置方法",children:[]},{level:2,title:"内部通信机制",slug:"内部通信机制",link:"#内部通信机制",children:[]},{level:2,title:"WebSocket",slug:"websocket",link:"#websocket",children:[]},{level:2,title:"SplitHTTP",slug:"splithttp",link:"#splithttp",children:[]}],path:"/config/features/browser_dialer.html",pathLocale:"/",extraFields:[]},{title:"环境变量",headers:[{level:2,title:"资源文件路径",slug:"资源文件路径",link:"#资源文件路径",children:[]},{level:2,title:"配置文件位置",slug:"配置文件位置",link:"#配置文件位置",children:[]},{level:2,title:"多配置目录",slug:"多配置目录",link:"#多配置目录",children:[]}],path:"/config/features/env.html",pathLocale:"/",extraFields:[]},{title:"Fallback 回落",headers:[{level:2,title:"fallbacks 配置",slug:"fallbacks-配置",link:"#fallbacks-配置",children:[{level:3,title:"FallbackObject",slug:"fallbackobject",link:"#fallbackobject",children:[]},{level:3,title:"补充说明",slug:"补充说明",link:"#补充说明",children:[]}]},{level:2,title:"Fallbacks 设计理论",slug:"fallbacks-设计理论",link:"#fallbacks-设计理论",children:[]}],path:"/config/features/fallback.html",pathLocale:"/",extraFields:[]},{title:"多文件配置",headers:[{level:2,title:"多文件启动",slug:"多文件启动",link:"#多文件启动",children:[]},{level:2,title:"规则说明",slug:"规则说明",link:"#规则说明",children:[{level:3,title:"普通对象({})",slug:"普通对象",link:"#普通对象",children:[]},{level:3,title:"数组([])",slug:"数组",link:"#数组",children:[]}]},{level:2,title:"配置例子",slug:"配置例子",link:"#配置例子",children:[]}],path:"/config/features/multiple.html",pathLocale:"/",extraFields:[]},{title:"XTLS 深度剖析",headers:[],path:"/config/features/xtls.html",pathLocale:"/",extraFields:[]},{title:"Dokodemo-Door",headers:[{level:2,title:"InboundConfigurationObject",slug:"inboundconfigurationobject",link:"#inboundconfigurationobject",children:[]},{level:2,title:"用处",slug:"用处",link:"#用处",children:[]},{level:2,title:"透明代理配置样例",slug:"透明代理配置样例",link:"#透明代理配置样例",children:[]}],path:"/config/inbounds/dokodemo.html",pathLocale:"/",extraFields:[]},{title:"HTTP",headers:[{level:2,title:"InboundConfigurationObject",slug:"inboundconfigurationobject",link:"#inboundconfigurationobject",children:[{level:3,title:"AccountObject",slug:"accountobject",link:"#accountobject",children:[]}]}],path:"/config/inbounds/http.html",pathLocale:"/",extraFields:[]},{title:"Shadowsocks",headers:[{level:2,title:"InboundConfigurationObject",slug:"inboundconfigurationobject",link:"#inboundconfigurationobject",children:[]},{level:2,title:"ClientObject",slug:"clientobject",link:"#clientobject",children:[]}],path:"/config/inbounds/shadowsocks.html",pathLocale:"/",extraFields:[]},{title:"Socks",headers:[{level:2,title:"InboundConfigurationObject",slug:"inboundconfigurationobject",link:"#inboundconfigurationobject",children:[{level:3,title:"AccountObject",slug:"accountobject",link:"#accountobject",children:[]}]}],path:"/config/inbounds/socks.html",pathLocale:"/",extraFields:[]},{title:"Trojan",headers:[{level:2,title:"InboundConfigurationObject",slug:"inboundconfigurationobject",link:"#inboundconfigurationobject",children:[{level:3,title:"ClientObject",slug:"clientobject",link:"#clientobject",children:[]}]}],path:"/config/inbounds/trojan.html",pathLocale:"/",extraFields:[]},{title:"VLESS(XTLS Vision Seed)",headers:[{level:2,title:"InboundConfigurationObject",slug:"inboundconfigurationobject",link:"#inboundconfigurationobject",children:[{level:3,title:"ClientObject",slug:"clientobject",link:"#clientobject",children:[]}]}],path:"/config/inbounds/vless.html",pathLocale:"/",extraFields:[]},{title:"VMess",headers:[{level:2,title:"InboundConfigurationObject",slug:"inboundconfigurationobject",link:"#inboundconfigurationobject",children:[{level:3,title:"ClientObject",slug:"clientobject",link:"#clientobject",children:[]},{level:3,title:"DetourObject",slug:"detourobject",link:"#detourobject",children:[]},{level:3,title:"DefaultObject",slug:"defaultobject",link:"#defaultobject",children:[]}]}],path:"/config/inbounds/vmess.html",pathLocale:"/",extraFields:[]},{title:"Wireguard",headers:[{level:2,title:"InboundConfigurationObject",slug:"inboundconfigurationobject",link:"#inboundconfigurationobject",children:[{level:3,title:"Peers",slug:"peers",link:"#peers",children:[]}]}],path:"/config/inbounds/wireguard.html",pathLocale:"/",extraFields:[]},{title:"Blackhole",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[{level:3,title:"ResponseObject",slug:"responseobject",link:"#responseobject",children:[]}]}],path:"/config/outbounds/blackhole.html",pathLocale:"/",extraFields:[]},{title:"DNS",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[]},{level:2,title:"DNS 配置实例",slug:"dns-配置实例",link:"#dns-配置实例",children:[]}],path:"/config/outbounds/dns.html",pathLocale:"/",extraFields:[]},{title:"Freedom(fragment、noises)",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[]}],path:"/config/outbounds/freedom.html",pathLocale:"/",extraFields:[]},{title:"HTTP",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[{level:3,title:"ServerObject",slug:"serverobject",link:"#serverobject",children:[]}]}],path:"/config/outbounds/http.html",pathLocale:"/",extraFields:[]},{title:"Loopback",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[{level:3,title:"如何使用?",slug:"如何使用",link:"#如何使用",children:[]}]}],path:"/config/outbounds/loopback.html",pathLocale:"/",extraFields:[]},{title:"Shadowsocks",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[{level:3,title:"ServerObject",slug:"serverobject",link:"#serverobject",children:[]}]}],path:"/config/outbounds/shadowsocks.html",pathLocale:"/",extraFields:[]},{title:"Socks",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[{level:3,title:"ServerObject",slug:"serverobject",link:"#serverobject",children:[]}]}],path:"/config/outbounds/socks.html",pathLocale:"/",extraFields:[]},{title:"Trojan",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[{level:3,title:"ServerObject",slug:"serverobject",link:"#serverobject",children:[]}]}],path:"/config/outbounds/trojan.html",pathLocale:"/",extraFields:[]},{title:"VLESS(XTLS Vision Seed)",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[{level:3,title:"ServerObject",slug:"serverobject",link:"#serverobject",children:[]},{level:3,title:"UserObject",slug:"userobject",link:"#userobject",children:[]}]}],path:"/config/outbounds/vless.html",pathLocale:"/",extraFields:[]},{title:"VMess",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[{level:3,title:"ServerObject",slug:"serverobject",link:"#serverobject",children:[]}]}],path:"/config/outbounds/vmess.html",pathLocale:"/",extraFields:[]},{title:"Wireguard",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[{level:3,title:"Peers",slug:"peers",link:"#peers",children:[]}]}],path:"/config/outbounds/wireguard.html",pathLocale:"/",extraFields:[]},{title:"gRPC",headers:[{level:2,title:"GRPCObject",slug:"grpcobject",link:"#grpcobject",children:[]}],path:"/config/transports/grpc.html",pathLocale:"/",extraFields:[]},{title:"HTTP/2",headers:[{level:2,title:"HttpObject",slug:"httpobject",link:"#httpobject",children:[]}],path:"/config/transports/h2.html",pathLocale:"/",extraFields:[]},{title:"HTTPUpgrade",headers:[{level:2,title:"HttpUpgradeObject",slug:"httpupgradeobject",link:"#httpupgradeobject",children:[]}],path:"/config/transports/httpupgrade.html",pathLocale:"/",extraFields:[]},{title:"mKCP",headers:[{level:2,title:"KcpObject",slug:"kcpobject",link:"#kcpobject",children:[{level:3,title:"HeaderObject",slug:"headerobject",link:"#headerobject",children:[]}]},{level:2,title:"鸣谢",slug:"鸣谢",link:"#鸣谢",children:[]},{level:2,title:"对 KCP 协议的改进",slug:"对-kcp-协议的改进",link:"#对-kcp-协议的改进",children:[{level:3,title:"更小的协议头",slug:"更小的协议头",link:"#更小的协议头",children:[]},{level:3,title:"确认包重传",slug:"确认包重传",link:"#确认包重传",children:[]},{level:3,title:"连接状态控制",slug:"连接状态控制",link:"#连接状态控制",children:[]}]}],path:"/config/transports/mkcp.html",pathLocale:"/",extraFields:[]},{title:"SplitHTTP(H2、QUIC H3)",headers:[{level:2,title:"SplitHttpObject",slug:"splithttpobject",link:"#splithttpobject",children:[]},{level:2,title:"HTTP 版本",slug:"http-版本",link:"#http-版本",children:[{level:3,title:"客户端行为",slug:"客户端行为",link:"#客户端行为",children:[]},{level:3,title:"服务端行为",slug:"服务端行为",link:"#服务端行为",children:[]},{level:3,title:"小提示",slug:"小提示",link:"#小提示",children:[]}]},{level:2,title:"Browser Dialer",slug:"browser-dialer",link:"#browser-dialer",children:[]},{level:2,title:"协议细节",slug:"协议细节",link:"#协议细节",children:[]}],path:"/config/transports/splithttp.html",pathLocale:"/",extraFields:[]},{title:"TCP",headers:[{level:2,title:"TcpObject",slug:"tcpobject",link:"#tcpobject",children:[{level:3,title:"NoneHeaderObject",slug:"noneheaderobject",link:"#noneheaderobject",children:[]},{level:3,title:"HttpHeaderObject",slug:"httpheaderobject",link:"#httpheaderobject",children:[]}]}],path:"/config/transports/tcp.html",pathLocale:"/",extraFields:[]},{title:"WebSocket",headers:[{level:2,title:"WebSocketObject",slug:"websocketobject",link:"#websocketobject",children:[]},{level:2,title:"Browser Dialer",slug:"browser-dialer",link:"#browser-dialer",children:[]}],path:"/config/transports/websocket.html",pathLocale:"/",extraFields:[]},{title:"小小白白话文",headers:[],path:"/document/level-0/",pathLocale:"/",extraFields:[]},{title:"【第 1 章】 小小白白话文",headers:[{level:2,title:"1.1 这篇文档是写给谁的?",slug:"_1-1-这篇文档是写给谁的",link:"#_1-1-这篇文档是写给谁的",children:[]},{level:2,title:"1.2 这篇文档不是写给谁的?",slug:"_1-2-这篇文档不是写给谁的",link:"#_1-2-这篇文档不是写给谁的",children:[]},{level:2,title:"1.3 郑重声明及其他声明",slug:"_1-3-郑重声明及其他声明",link:"#_1-3-郑重声明及其他声明",children:[]},{level:2,title:"1.4 为什么自建是个难题?",slug:"_1-4-为什么自建是个难题",link:"#_1-4-为什么自建是个难题",children:[]},{level:2,title:"1.5 “用机场不就行了?”",slug:"_1-5-用机场不就行了",link:"#_1-5-用机场不就行了",children:[]},{level:2,title:"1.6 那么你到底要不要自建呢?",slug:"_1-6-那么你到底要不要自建呢",link:"#_1-6-那么你到底要不要自建呢",children:[]},{level:2,title:"1.7 题外啰嗦几句",slug:"_1-7-题外啰嗦几句",link:"#_1-7-题外啰嗦几句",children:[]},{level:2,title:"1.8 你的进度",slug:"_1-8-你的进度",link:"#_1-8-你的进度",children:[]}],path:"/document/level-0/ch01-preface.html",pathLocale:"/",extraFields:[]},{title:"【第 2 章】原料准备篇",headers:[{level:2,title:"2.1 获取一台 VPS",slug:"_2-1-获取一台-vps",link:"#_2-1-获取一台-vps",children:[]},{level:2,title:"2.2 获取一个心仪的域名",slug:"_2-2-获取一个心仪的域名",link:"#_2-2-获取一个心仪的域名",children:[]},{level:2,title:"2.3 你本地电脑上需要安装的软件",slug:"_2-3-你本地电脑上需要安装的软件",link:"#_2-3-你本地电脑上需要安装的软件",children:[]},{level:2,title:"2.4 你的进度",slug:"_2-4-你的进度",link:"#_2-4-你的进度",children:[]}],path:"/document/level-0/ch02-preparation.html",pathLocale:"/",extraFields:[]},{title:"【第 3 章】远程登录篇",headers:[{level:2,title:"3.1 远程登录 VPS (PuTTY)",slug:"_3-1-远程登录-vps-putty",link:"#_3-1-远程登录-vps-putty",children:[]},{level:2,title:"3.2 成功登录 SSH!初识命令行界面!",slug:"_3-2-成功登录-ssh-初识命令行界面",link:"#_3-2-成功登录-ssh-初识命令行界面",children:[]},{level:2,title:"3.3 第一次更新 Linux 的软件!",slug:"_3-3-第一次更新-linux-的软件",link:"#_3-3-第一次更新-linux-的软件",children:[]},{level:2,title:"3.4 你的进度",slug:"_3-4-你的进度",link:"#_3-4-你的进度",children:[]}],path:"/document/level-0/ch03-ssh.html",pathLocale:"/",extraFields:[]},{title:"【第 4 章】安全防护篇",headers:[{level:2,title:"4.1 为什么要做安全防护",slug:"_4-1-为什么要做安全防护",link:"#_4-1-为什么要做安全防护",children:[]},{level:2,title:"4.2 具体的风险到底是什么",slug:"_4-2-具体的风险到底是什么",link:"#_4-2-具体的风险到底是什么",children:[]},{level:2,title:"4.3 我们要做的安全防护有哪些",slug:"_4-3-我们要做的安全防护有哪些",link:"#_4-3-我们要做的安全防护有哪些",children:[]},{level:2,title:"4.4 将 SSH 远程登录端口修改为非 22 端口",slug:"_4-4-将-ssh-远程登录端口修改为非-22-端口",link:"#_4-4-将-ssh-远程登录端口修改为非-22-端口",children:[]},{level:2,title:"4.5 建立非 root 的新用户",slug:"_4-5-建立非-root-的新用户",link:"#_4-5-建立非-root-的新用户",children:[]},{level:2,title:"4.6 禁用 root 用户 SSH 远程登录",slug:"_4-6-禁用-root-用户-ssh-远程登录",link:"#_4-6-禁用-root-用户-ssh-远程登录",children:[]},{level:2,title:"4.7 使用 RSA 密钥登录并禁用密码登录",slug:"_4-7-使用-rsa-密钥登录并禁用密码登录",link:"#_4-7-使用-rsa-密钥登录并禁用密码登录",children:[]},{level:2,title:"4.8 你的进度",slug:"_4-8-你的进度",link:"#_4-8-你的进度",children:[]}],path:"/document/level-0/ch04-security.html",pathLocale:"/",extraFields:[]},{title:"【第 5 章】网站建设篇",headers:[{level:2,title:"5.1 为什么要做一个网站?",slug:"_5-1-为什么要做一个网站",link:"#_5-1-为什么要做一个网站",children:[]},{level:2,title:"5.2 登录 VPS、安装运行 Nginx",slug:"_5-2-登录-vps、安装运行-nginx",link:"#_5-2-登录-vps、安装运行-nginx",children:[]},{level:2,title:"5.3 创建一个最简单的网页",slug:"_5-3-创建一个最简单的网页",link:"#_5-3-创建一个最简单的网页",children:[]},{level:2,title:"5.4 常见错误的说明",slug:"_5-4-常见错误的说明",link:"#_5-4-常见错误的说明",children:[]},{level:2,title:"5.5 你的进度",slug:"_5-5-你的进度",link:"#_5-5-你的进度",children:[]}],path:"/document/level-0/ch05-webpage.html",pathLocale:"/",extraFields:[]},{title:"【第 6 章】证书管理篇",headers:[{level:2,title:"6.1 申请 TLS 证书",slug:"_6-1-申请-tls-证书",link:"#_6-1-申请-tls-证书",children:[]},{level:2,title:"6.2 安装 acme.sh",slug:"_6-2-安装-acme-sh",link:"#_6-2-安装-acme-sh",children:[]},{level:2,title:"6.3 测试证书申请",slug:"_6-3-测试证书申请",link:"#_6-3-测试证书申请",children:[]},{level:2,title:"6.4 正式证书申请",slug:"_6-4-正式证书申请",link:"#_6-4-正式证书申请",children:[]},{level:2,title:"6.5 证书安装",slug:"_6-5-证书安装",link:"#_6-5-证书安装",children:[]},{level:2,title:"6.6 你的进度",slug:"_6-6-你的进度",link:"#_6-6-你的进度",children:[]}],path:"/document/level-0/ch06-certificates.html",pathLocale:"/",extraFields:[]},{title:"【第 7 章】Xray 服务器篇",headers:[{level:2,title:"7.1 博观而约取,厚积而薄发",slug:"_7-1-博观而约取-厚积而薄发",link:"#_7-1-博观而约取-厚积而薄发",children:[]},{level:2,title:"7.2 安装 Xray",slug:"_7-2-安装-xray",link:"#_7-2-安装-xray",children:[]},{level:2,title:"7.3 给 Xray 配置 TLS 证书",slug:"_7-3-给-xray-配置-tls-证书",link:"#_7-3-给-xray-配置-tls-证书",children:[]},{level:2,title:"7.4 配置 Xray",slug:"_7-4-配置-xray",link:"#_7-4-配置-xray",children:[]},{level:2,title:"7.5 启动 Xray 服务!!(并查看服务状态)",slug:"_7-5-启动-xray-服务-并查看服务状态",link:"#_7-5-启动-xray-服务-并查看服务状态",children:[]},{level:2,title:"7.6 回顾 systemd 进行基本的服务管理",slug:"_7-6-回顾-systemd-进行基本的服务管理",link:"#_7-6-回顾-systemd-进行基本的服务管理",children:[]},{level:2,title:"7.7 服务器优化之一:开启 BBR",slug:"_7-7-服务器优化之一-开启-bbr",link:"#_7-7-服务器优化之一-开启-bbr",children:[]},{level:2,title:"7.8 服务器优化之二:开启 HTTP 自动跳转 HTTPS",slug:"_7-8-服务器优化之二-开启-http-自动跳转-https",link:"#_7-8-服务器优化之二-开启-http-自动跳转-https",children:[]},{level:2,title:"7.9 服务器优化之三:更丰富的回落",slug:"_7-9-服务器优化之三-更丰富的回落",link:"#_7-9-服务器优化之三-更丰富的回落",children:[]},{level:2,title:"7.10 你的进度",slug:"_7-10-你的进度",link:"#_7-10-你的进度",children:[]},{level:2,title:"7.11 重要勘误",slug:"_7-11-重要勘误",link:"#_7-11-重要勘误",children:[]}],path:"/document/level-0/ch07-xray-server.html",pathLocale:"/",extraFields:[]},{title:"【第 8 章】Xray 客户端篇",headers:[{level:2,title:"8.1 Xray 的工作原理简述",slug:"_8-1-xray-的工作原理简述",link:"#_8-1-xray-的工作原理简述",children:[]},{level:2,title:"8.2 客户端与服务器端正确连接",slug:"_8-2-客户端与服务器端正确连接",link:"#_8-2-客户端与服务器端正确连接",children:[]},{level:2,title:"8.3 附加题 1:在 PC 端手工配置 xray-core",slug:"_8-3-附加题-1-在-pc-端手工配置-xray-core",link:"#_8-3-附加题-1-在-pc-端手工配置-xray-core",children:[]},{level:2,title:"8.4 附加题 2:在 PC 端手工运行 xray-core",slug:"_8-4-附加题-2-在-pc-端手工运行-xray-core",link:"#_8-4-附加题-2-在-pc-端手工运行-xray-core",children:[]},{level:2,title:"8.5 附加题 3:在 PC 端开机自动运行 xray-core",slug:"_8-5-附加题-3-在-pc-端开机自动运行-xray-core",link:"#_8-5-附加题-3-在-pc-端开机自动运行-xray-core",children:[]},{level:2,title:"8.6 圆满完成!",slug:"_8-6-圆满完成",link:"#_8-6-圆满完成",children:[]},{level:2,title:"8.7 TO INFINITY AND BEYOND!",slug:"_8-7-to-infinity-and-beyond",link:"#_8-7-to-infinity-and-beyond",children:[]}],path:"/document/level-0/ch08-xray-clients.html",pathLocale:"/",extraFields:[]},{title:"【第 9 章】附录",headers:[{level:2,title:"1. 小小白白 Linux 基础命令索引",slug:"_1-小小白白-linux-基础命令索引",link:"#_1-小小白白-linux-基础命令索引",children:[]},{level:2,title:"2. 小小白白 Linux 重要配置文件索引",slug:"_2-小小白白-linux-重要配置文件索引",link:"#_2-小小白白-linux-重要配置文件索引",children:[]},{level:2,title:"3. 小小白白 Xray 重要文件索引",slug:"_3-小小白白-xray-重要文件索引",link:"#_3-小小白白-xray-重要文件索引",children:[]}],path:"/document/level-0/ch09-appendix.html",pathLocale:"/",extraFields:[]},{title:"入门技巧",headers:[],path:"/document/level-1/",pathLocale:"/",extraFields:[]},{title:"回落 (fallbacks) 功能简析",headers:[{level:2,title:"1. 回顾《小小白白话文》中的回落",slug:"_1-回顾《小小白白话文》中的回落",link:"#_1-回顾《小小白白话文》中的回落",children:[]},{level:2,title:"2. 重新认识回落 (WHAT, HOW v1)",slug:"_2-重新认识回落-what-how-v1",link:"#_2-重新认识回落-what-how-v1",children:[]},{level:2,title:"3. 为什么要回落 (WHY v1)",slug:"_3-为什么要回落-why-v1",link:"#_3-为什么要回落-why-v1",children:[]},{level:2,title:"4. 重新认识【回落の完全体】 (WHAT, WHY, HOW v2)",slug:"_4-重新认识【回落の完全体】-what-why-how-v2",link:"#_4-重新认识【回落の完全体】-what-why-how-v2",children:[]},{level:2,title:"5. 多层回落示例及解读",slug:"_5-多层回落示例及解读",link:"#_5-多层回落示例及解读",children:[{level:3,title:"5.1 首先,我将服务器端配置的 443 监听段摘抄如下:",slug:"_5-1-首先-我将服务器端配置的-443-监听段摘抄如下",link:"#_5-1-首先-我将服务器端配置的-443-监听段摘抄如下",children:[]},{level:3,title:"5.2 后续监听处理的配置段摘抄如下:",slug:"_5-2-后续监听处理的配置段摘抄如下",link:"#_5-2-后续监听处理的配置段摘抄如下",children:[]}]},{level:2,title:"6. 结语",slug:"_6-结语",link:"#_6-结语",children:[]},{level:2,title:"7. 附加题",slug:"_7-附加题",link:"#_7-附加题",children:[]}],path:"/document/level-1/fallbacks-lv1.html",pathLocale:"/",extraFields:[]},{title:"SNI 回落",headers:[{level:2,title:"应用情景",slug:"应用情景",link:"#应用情景",children:[]},{level:2,title:"SNI 简介",slug:"sni-简介",link:"#sni-简介",children:[]},{level:2,title:"思路",slug:"思路",link:"#思路",children:[]},{level:2,title:"添加 DNS 记录",slug:"添加-dns-记录",link:"#添加-dns-记录",children:[]},{level:2,title:"申请 TLS 证书",slug:"申请-tls-证书",link:"#申请-tls-证书",children:[]},{level:2,title:"Xray 配置",slug:"xray-配置",link:"#xray-配置",children:[]},{level:2,title:"Nginx 配置",slug:"nginx-配置",link:"#nginx-配置",children:[]},{level:2,title:"Caddy 配置",slug:"caddy-配置",link:"#caddy-配置",children:[]},{level:2,title:"参考",slug:"参考",link:"#参考",children:[]},{level:2,title:"引用",slug:"引用",link:"#引用",children:[]}],path:"/document/level-1/fallbacks-with-sni.html",pathLocale:"/",extraFields:[]},{title:"路由 (routing) 功能简析(上)",headers:[{level:2,title:"1. 初识【路由】三兄弟",slug:"_1-初识【路由】三兄弟",link:"#_1-初识【路由】三兄弟",children:[]},{level:2,title:"2. 基本功: “兄弟一条心”",slug:"_2-基本功-兄弟一条心",link:"#_2-基本功-兄弟一条心",children:[{level:3,title:"2.1 入站",slug:"_2-1-入站",link:"#_2-1-入站",children:[]},{level:3,title:"2.3 路由",slug:"_2-3-路由",link:"#_2-3-路由",children:[]},{level:3,title:"2.4 路由配置项解析之一:流量筛选的依据",slug:"_2-4-路由配置项解析之一-流量筛选的依据",link:"#_2-4-路由配置项解析之一-流量筛选的依据",children:[]}]},{level:2,title:"3. 小试牛刀: “三分天下” 之 “域名分流”",slug:"_3-小试牛刀-三分天下-之-域名分流",link:"#_3-小试牛刀-三分天下-之-域名分流",children:[{level:3,title:"3.1 入站",slug:"_3-1-入站",link:"#_3-1-入站",children:[]},{level:3,title:"3.2 出站",slug:"_3-2-出站",link:"#_3-2-出站",children:[]},{level:3,title:"3.3 路由",slug:"_3-3-路由",link:"#_3-3-路由",children:[]},{level:3,title:"3.4 简析域名文件: geosite.dat",slug:"_3-4-简析域名文件-geosite-dat",link:"#_3-4-简析域名文件-geosite-dat",children:[]},{level:3,title:"3.5 所以 geosite.dat 到底是什么?不是有个 GFWList 吗?",slug:"_3-5-所以-geosite-dat-到底是什么-不是有个-gfwlist-吗",link:"#_3-5-所以-geosite-dat-到底是什么-不是有个-gfwlist-吗",children:[]},{level:3,title:"3.6 军师锦囊藏奇兵:一条隐藏的路由规则",slug:"_3-6-军师锦囊藏奇兵-一条隐藏的路由规则",link:"#_3-6-军师锦囊藏奇兵-一条隐藏的路由规则",children:[]},{level:3,title:"3.7 再看“三分天下”的大地图",slug:"_3-7-再看-三分天下-的大地图",link:"#_3-7-再看-三分天下-的大地图",children:[]}]},{level:2,title:"4. “三分天下” 之 “蜀魏争雄”",slug:"_4-三分天下-之-蜀魏争雄",link:"#_4-三分天下-之-蜀魏争雄",children:[]},{level:2,title:"5. 攻城略池 - 多种路由匹配条件",slug:"_5-攻城略池-多种路由匹配条件",link:"#_5-攻城略池-多种路由匹配条件",children:[]}],path:"/document/level-1/routing-lv1-part1.html",pathLocale:"/",extraFields:[]},{title:"路由 (routing) 功能简析(下)",headers:[{level:2,title:"5. 攻城略池 - 多种路由匹配条件",slug:"_5-攻城略池-多种路由匹配条件",link:"#_5-攻城略池-多种路由匹配条件",children:[{level:3,title:"5.1 基于指定域名分流:[domain], [full] 等",slug:"_5-1-基于指定域名分流-domain-full-等",link:"#_5-1-基于指定域名分流-domain-full-等",children:[]},{level:3,title:"5.2 基于 IP 文件分流:geoip.dat",slug:"_5-2-基于-ip-文件分流-geoip-dat",link:"#_5-2-基于-ip-文件分流-geoip-dat",children:[]},{level:3,title:"5.3 基于指定 IP 地址分流",slug:"_5-3-基于指定-ip-地址分流",link:"#_5-3-基于指定-ip-地址分流",children:[]},{level:3,title:"5.4 基于协议类型分流:[protocol] 等",slug:"_5-4-基于协议类型分流-protocol-等",link:"#_5-4-基于协议类型分流-protocol-等",children:[]},{level:3,title:"5.5 基于更多条件的分流",slug:"_5-5-基于更多条件的分流",link:"#_5-5-基于更多条件的分流",children:[]}]},{level:2,title:"6. “霸业初定”:路由规则整体回顾",slug:"_6-霸业初定-路由规则整体回顾",link:"#_6-霸业初定-路由规则整体回顾",children:[]},{level:2,title:"7. 路由配置常见错误",slug:"_7-路由配置常见错误",link:"#_7-路由配置常见错误",children:[{level:3,title:"7.1 错误示范",slug:"_7-1-错误示范",link:"#_7-1-错误示范",children:[]},{level:3,title:"7.2 正确示范",slug:"_7-2-正确示范",link:"#_7-2-正确示范",children:[]}]},{level:2,title:"8. 明修栈道、暗渡陈仓",slug:"_8-明修栈道、暗渡陈仓",link:"#_8-明修栈道、暗渡陈仓",children:[{level:3,title:'8.1 域名策略: "AsIs"',slug:"_8-1-域名策略-asis",link:"#_8-1-域名策略-asis",children:[]},{level:3,title:'8.2 域名策略: "IPIfNonMatch"',slug:"_8-2-域名策略-ipifnonmatch",link:"#_8-2-域名策略-ipifnonmatch",children:[]},{level:3,title:'8.3 域名策略: "IPOnDemand"',slug:"_8-3-域名策略-ipondemand",link:"#_8-3-域名策略-ipondemand",children:[]}]},{level:2,title:"9. 思考题",slug:"_9-思考题",link:"#_9-思考题",children:[]},{level:2,title:"10. 结语",slug:"_10-结语",link:"#_10-结语",children:[]},{level:2,title:"11. 尾注",slug:"_11-尾注",link:"#_11-尾注",children:[]}],path:"/document/level-1/routing-lv1-part2.html",pathLocale:"/",extraFields:[]},{title:"Xray 的工作模式",headers:[{level:2,title:"单服务器模式",slug:"单服务器模式",link:"#单服务器模式",children:[]},{level:2,title:"桥接模式",slug:"桥接模式",link:"#桥接模式",children:[]},{level:2,title:"工作原理",slug:"工作原理",link:"#工作原理",children:[]}],path:"/document/level-1/work.html",pathLocale:"/",extraFields:[]},{title:"进阶文档",headers:[],path:"/document/level-2/",pathLocale:"/",extraFields:[]},{title:"GID 透明代理",headers:[{level:2,title:"思路",slug:"思路",link:"#思路",children:[]},{level:2,title:"配置过程",slug:"配置过程",link:"#配置过程",children:[{level:3,title:"1. 前期准备",slug:"_1-前期准备",link:"#_1-前期准备",children:[]},{level:3,title:"2. 添加用户(安卓用户请忽略)",slug:"_2-添加用户-安卓用户请忽略",link:"#_2-添加用户-安卓用户请忽略",children:[]},{level:3,title:"3. 配置运行 Xray,配置 iptables 规则",slug:"_3-配置运行-xray-配置-iptables-规则",link:"#_3-配置运行-xray-配置-iptables-规则",children:[]}]},{level:2,title:"下面提供一个实现 tproxy 全局代理的完整配置过程",slug:"下面提供一个实现-tproxy-全局代理的完整配置过程",link:"#下面提供一个实现-tproxy-全局代理的完整配置过程",children:[{level:3,title:"1. 完成 前期准备 和 添加用户",slug:"_1-完成-前期准备-和-添加用户",link:"#_1-完成-前期准备-和-添加用户",children:[]},{level:3,title:"2. 准备 Xray 配置文件",slug:"_2-准备-xray-配置文件",link:"#_2-准备-xray-配置文件",children:[]},{level:3,title:"3. 配置最大文件打开数&运行 Xray 客户端",slug:"_3-配置最大文件打开数-运行-xray-客户端",link:"#_3-配置最大文件打开数-运行-xray-客户端",children:[]},{level:3,title:"4. 设置 iptables 规则",slug:"_4-设置-iptables-规则",link:"#_4-设置-iptables-规则",children:[]}]}],path:"/document/level-2/iptables_gid.html",pathLocale:"/",extraFields:[]},{title:"Nginx 或 Haproxy 搭建 TLS 隧道隐藏指纹",headers:[{level:2,title:"编译 nginx --with-stream",slug:"编译-nginx-with-stream",link:"#编译-nginx-with-stream",children:[]},{level:2,title:"配置 nginx",slug:"配置-nginx",link:"#配置-nginx",children:[]},{level:2,title:"xray 配置",slug:"xray-配置",link:"#xray-配置",children:[]},{level:2,title:"客户端及服务端启动服务",slug:"客户端及服务端启动服务",link:"#客户端及服务端启动服务",children:[]},{level:2,title:"结束",slug:"结束",link:"#结束",children:[]},{level:2,title:"HTTPS 隧道",slug:"https-隧道",link:"#https-隧道",children:[{level:3,title:"haproxy_client 配置 (运行前去掉注释)",slug:"haproxy-client-配置-运行前去掉注释",link:"#haproxy-client-配置-运行前去掉注释",children:[]},{level:3,title:"haproxy_server 配置 (运行前去掉注释)",slug:"haproxy-server-配置-运行前去掉注释",link:"#haproxy-server-配置-运行前去掉注释",children:[]},{level:3,title:"xray 配置",slug:"xray-配置-1",link:"#xray-配置-1",children:[]}]},{level:2,title:"WebSocket over HTTP/2",slug:"websocket-over-http-2",link:"#websocket-over-http-2",children:[{level:3,title:"haproxy_client 配置",slug:"haproxy-client-配置",link:"#haproxy-client-配置",children:[]},{level:3,title:"haproxy_server 配置",slug:"haproxy-server-配置",link:"#haproxy-server-配置",children:[]},{level:3,title:"xray 配置",slug:"xray-配置-2",link:"#xray-配置-2",children:[]}]},{level:2,title:"gRPC over HTTP/2",slug:"grpc-over-http-2",link:"#grpc-over-http-2",children:[{level:3,title:"haproxy_client 配置",slug:"haproxy-client-配置-1",link:"#haproxy-client-配置-1",children:[]},{level:3,title:"haproxy_server 配置",slug:"haproxy-server-配置-1",link:"#haproxy-server-配置-1",children:[]},{level:3,title:"xray 配置",slug:"xray-配置-3",link:"#xray-配置-3",children:[]},{level:3,title:"haproxy_client 配置",slug:"haproxy-client-配置-2",link:"#haproxy-client-配置-2",children:[]},{level:3,title:"haproxy_server 配置",slug:"haproxy-server-配置-2",link:"#haproxy-server-配置-2",children:[]},{level:3,title:"xray 配置",slug:"xray-配置-4",link:"#xray-配置-4",children:[]}]}],path:"/document/level-2/nginx_or_haproxy_tls_tunnel.html",pathLocale:"/",extraFields:[]},{title:"出站流量重定向",headers:[{level:2,title:"前言",slug:"前言",link:"#前言",children:[]},{level:2,title:"1、安装代理或者 VPN 软件(例如 Wireguard、IPsec 等)",slug:"_1、安装代理或者-vpn-软件-例如-wireguard、ipsec-等",link:"#_1、安装代理或者-vpn-软件-例如-wireguard、ipsec-等",children:[]},{level:2,title:"2、编辑 VPN 配置文件(以 WireGuard 为例)",slug:"_2、编辑-vpn-配置文件-以-wireguard-为例",link:"#_2、编辑-vpn-配置文件-以-wireguard-为例",children:[]},{level:2,title:"3、启用 WireGuard 网络接口",slug:"_3、启用-wireguard-网络接口",link:"#_3、启用-wireguard-网络接口",children:[]},{level:2,title:"4、Xray-core 配置文件修改",slug:"_4、xray-core-配置文件修改",link:"#_4、xray-core-配置文件修改",children:[]},{level:2,title:"5、系统设置配置",slug:"_5、系统设置配置",link:"#_5、系统设置配置",children:[]},{level:2,title:"6、完成 WireGuard 相关设置",slug:"_6、完成-wireguard-相关设置",link:"#_6、完成-wireguard-相关设置",children:[]},{level:2,title:"后记",slug:"后记",link:"#后记",children:[]},{level:2,title:"感谢",slug:"感谢",link:"#感谢",children:[]}],path:"/document/level-2/redirect.html",pathLocale:"/",extraFields:[]},{title:"TProxy 透明代理",headers:[{level:2,title:"开始之前",slug:"开始之前",link:"#开始之前",children:[]},{level:2,title:"Xray 配置",slug:"xray-配置",link:"#xray-配置",children:[]},{level:2,title:"策略路由配置",slug:"策略路由配置",link:"#策略路由配置",children:[]},{level:2,title:"Netfilter 配置",slug:"netfilter-配置",link:"#netfilter-配置",children:[]},{level:2,title:"配置永久化与开机自启",slug:"配置永久化与开机自启",link:"#配置永久化与开机自启",children:[]}],path:"/document/level-2/tproxy.html",pathLocale:"/",extraFields:[]},{title:"TProxy 透明代理 (ipv4 and ipv6)",headers:[{level:2,title:"Xray 配置",slug:"xray-配置",link:"#xray-配置",children:[{level:3,title:"客户端配置",slug:"客户端配置",link:"#客户端配置",children:[]},{level:3,title:"服务端配置",slug:"服务端配置",link:"#服务端配置",children:[]}]},{level:2,title:"Netfilter 配置",slug:"netfilter-配置",link:"#netfilter-配置",children:[{level:3,title:"首先设置策略路由",slug:"首先设置策略路由",link:"#首先设置策略路由",children:[]},{level:3,title:"使用 iptables",slug:"使用-iptables",link:"#使用-iptables",children:[]},{level:3,title:"使用 nftables",slug:"使用-nftables",link:"#使用-nftables",children:[]},{level:3,title:"开机自动运行 Netfilter 配置",slug:"开机自动运行-netfilter-配置",link:"#开机自动运行-netfilter-配置",children:[]}]},{level:2,title:"局域网设备上网设置",slug:"局域网设备上网设置",link:"#局域网设备上网设置",children:[{level:3,title:"方法一",slug:"方法一",link:"#方法一",children:[]},{level:3,title:"方法二",slug:"方法二",link:"#方法二",children:[]}]},{level:2,title:"Finally",slug:"finally",link:"#finally",children:[]},{level:2,title:"写在最后",slug:"写在最后",link:"#写在最后",children:[]}],path:"/document/level-2/tproxy_ipv4_and_ipv6.html",pathLocale:"/",extraFields:[]},{title:"流量统计",headers:[{level:2,title:"查看流量信息",slug:"查看流量信息",link:"#查看流量信息",children:[]},{level:2,title:"流量信息的处理",slug:"流量信息的处理",link:"#流量信息的处理",children:[]}],path:"/document/level-2/traffic_stats.html",pathLocale:"/",extraFields:[]},{title:"通过 Cloudflare Warp 增强代理安全性",headers:[{level:2,title:"申请 Warp 账户",slug:"申请-warp-账户",link:"#申请-warp-账户",children:[{level:3,title:"感谢 Cloudflare 推动自由的互联网,现在你可以免费使用 Warp 服务,连接的时候会根据出口自动选择最近的服务器",slug:"感谢-cloudflare-推动自由的互联网-现在你可以免费使用-warp-服务-连接的时候会根据出口自动选择最近的服务器",link:"#感谢-cloudflare-推动自由的互联网-现在你可以免费使用-warp-服务-连接的时候会根据出口自动选择最近的服务器",children:[]}]},{level:2,title:"在服务端分流回国流量至 warp",slug:"在服务端分流回国流量至-warp",link:"#在服务端分流回国流量至-warp",children:[]},{level:2,title:"客户端使用 warp 链式代理",slug:"客户端使用-warp-链式代理",link:"#客户端使用-warp-链式代理",children:[]}],path:"/document/level-2/warp.html",pathLocale:"/",extraFields:[]},{title:"The Great Chronicles",headers:[{level:2,title:"2024.9.12",slug:"_2024-9-12",link:"#_2024-9-12",children:[]},{level:2,title:"2024.9.7 v24.9.7",slug:"_2024-9-7-v24-9-7",link:"#_2024-9-7-v24-9-7",children:[]},{level:2,title:"2024.8.30 v1.8.24",slug:"_2024-8-30-v1-8-24",link:"#_2024-8-30-v1-8-24",children:[]},{level:2,title:"2024.8.26",slug:"_2024-8-26",link:"#_2024-8-26",children:[]},{level:2,title:"2024.8.3",slug:"_2024-8-3",link:"#_2024-8-3",children:[]},{level:2,title:"2024.7.29 v1.8.23",slug:"_2024-7-29-v1-8-23",link:"#_2024-7-29-v1-8-23",children:[]},{level:2,title:"2024.7.22 v1.8.21",slug:"_2024-7-22-v1-8-21",link:"#_2024-7-22-v1-8-21",children:[]},{level:2,title:"2024.7.16",slug:"_2024-7-16",link:"#_2024-7-16",children:[]},{level:2,title:"2024.7.15",slug:"_2024-7-15",link:"#_2024-7-15",children:[]},{level:2,title:"2024.6.18 v1.8.16",slug:"_2024-6-18-v1-8-16",link:"#_2024-6-18-v1-8-16",children:[]},{level:2,title:"2024.6.2",slug:"_2024-6-2",link:"#_2024-6-2",children:[]},{level:2,title:"2024.4.26 v1.8.11",slug:"_2024-4-26-v1-8-11",link:"#_2024-4-26-v1-8-11",children:[]},{level:2,title:"2024.4.20",slug:"_2024-4-20",link:"#_2024-4-20",children:[]},{level:2,title:"2024.4.13",slug:"_2024-4-13",link:"#_2024-4-13",children:[]},{level:2,title:"2024.3.18 v1.8.10",slug:"_2024-3-18-v1-8-10",link:"#_2024-3-18-v1-8-10",children:[]},{level:2,title:"2024.3.11 v1.8.9",slug:"_2024-3-11-v1-8-9",link:"#_2024-3-11-v1-8-9",children:[]},{level:2,title:"2024.2.29",slug:"_2024-2-29",link:"#_2024-2-29",children:[]},{level:2,title:"2024.2.25 v1.8.8",slug:"_2024-2-25-v1-8-8",link:"#_2024-2-25-v1-8-8",children:[]},{level:2,title:"2024.1.9",slug:"_2024-1-9",link:"#_2024-1-9",children:[]},{level:2,title:"2023.11.21",slug:"_2023-11-21",link:"#_2023-11-21",children:[]},{level:2,title:"2023.11.18 v1.8.6",slug:"_2023-11-18-v1-8-6",link:"#_2023-11-18-v1-8-6",children:[]},{level:2,title:"2023.9.30",slug:"_2023-9-30",link:"#_2023-9-30",children:[]},{level:2,title:"2023.8.29 v1.8.4",slug:"_2023-8-29-v1-8-4",link:"#_2023-8-29-v1-8-4",children:[]},{level:2,title:"2023.7.22",slug:"_2023-7-22",link:"#_2023-7-22",children:[]},{level:2,title:"2023.7.7",slug:"_2023-7-7",link:"#_2023-7-7",children:[]},{level:2,title:"2023.6.30",slug:"_2023-6-30",link:"#_2023-6-30",children:[]},{level:2,title:"2023.6.27",slug:"_2023-6-27",link:"#_2023-6-27",children:[]},{level:2,title:"2023.6.19 v1.8.3",slug:"_2023-6-19-v1-8-3",link:"#_2023-6-19-v1-8-3",children:[]},{level:2,title:"2023.6.6",slug:"_2023-6-6",link:"#_2023-6-6",children:[]},{level:2,title:"2023.4.21",slug:"_2023-4-21",link:"#_2023-4-21",children:[]},{level:2,title:"2023.4.20",slug:"_2023-4-20",link:"#_2023-4-20",children:[]},{level:2,title:"2023.4.19",slug:"_2023-4-19",link:"#_2023-4-19",children:[]},{level:2,title:"2023.4.18 v1.8.1",slug:"_2023-4-18-v1-8-1",link:"#_2023-4-18-v1-8-1",children:[]},{level:2,title:"2023.4.6",slug:"_2023-4-6",link:"#_2023-4-6",children:[]},{level:2,title:"2023.3.29",slug:"_2023-3-29",link:"#_2023-3-29",children:[]},{level:2,title:"2023.3.19",slug:"_2023-3-19",link:"#_2023-3-19",children:[]},{level:2,title:"2023.3.9 v1.8.0",slug:"_2023-3-9-v1-8-0",link:"#_2023-3-9-v1-8-0",children:[]},{level:2,title:"2023.3.4",slug:"_2023-3-4",link:"#_2023-3-4",children:[]},{level:2,title:"2023.3.2",slug:"_2023-3-2",link:"#_2023-3-2",children:[]},{level:2,title:"2023.2.16",slug:"_2023-2-16",link:"#_2023-2-16",children:[]},{level:2,title:"2023.2.9",slug:"_2023-2-9",link:"#_2023-2-9",children:[]},{level:2,title:"2023.2.8 v1.7.5",slug:"_2023-2-8-v1-7-5",link:"#_2023-2-8-v1-7-5",children:[]},{level:2,title:"2023.1.29",slug:"_2023-1-29",link:"#_2023-1-29",children:[]},{level:2,title:"2022.12.26 v1.7.0",slug:"_2022-12-26-v1-7-0",link:"#_2022-12-26-v1-7-0",children:[]},{level:2,title:"2022.11.28 v1.6.5",slug:"_2022-11-28-v1-6-5",link:"#_2022-11-28-v1-6-5",children:[]},{level:2,title:"2022.11.7 v1.6.3",slug:"_2022-11-7-v1-6-3",link:"#_2022-11-7-v1-6-3",children:[]},{level:2,title:"2022.10.29 v1.6.2",slug:"_2022-10-29-v1-6-2",link:"#_2022-10-29-v1-6-2",children:[]},{level:2,title:"2022.10.22 v1.6.1",slug:"_2022-10-22-v1-6-1",link:"#_2022-10-22-v1-6-1",children:[]},{level:2,title:"2022.10.3",slug:"_2022-10-3",link:"#_2022-10-3",children:[]},{level:2,title:"2022.8.28 v1.5.10",slug:"_2022-8-28-v1-5-10",link:"#_2022-8-28-v1-5-10",children:[]},{level:2,title:"2022.6.20 v1.5.8",slug:"_2022-6-20-v1-5-8",link:"#_2022-6-20-v1-5-8",children:[]},{level:2,title:"2022.5.29 v1.5.6",slug:"_2022-5-29-v1-5-6",link:"#_2022-5-29-v1-5-6",children:[]},{level:2,title:"2022.4.24 v1.5.5",slug:"_2022-4-24-v1-5-5",link:"#_2022-4-24-v1-5-5",children:[]},{level:2,title:"2022.3.13 v1.5.4",slug:"_2022-3-13-v1-5-4",link:"#_2022-3-13-v1-5-4",children:[]},{level:2,title:"2022.1.29 v1.5.3",slug:"_2022-1-29-v1-5-3",link:"#_2022-1-29-v1-5-3",children:[]},{level:2,title:"2021.12.24 v1.5.2",slug:"_2021-12-24-v1-5-2",link:"#_2021-12-24-v1-5-2",children:[]},{level:2,title:"2021.12.15 v1.5.1",slug:"_2021-12-15-v1-5-1",link:"#_2021-12-15-v1-5-1",children:[]},{level:2,title:"2021.10.20 v1.5.0",slug:"_2021-10-20-v1-5-0",link:"#_2021-10-20-v1-5-0",children:[]},{level:2,title:"2021.9.23 v1.4.5",slug:"_2021-9-23-v1-4-5",link:"#_2021-9-23-v1-4-5",children:[]},{level:2,title:"2021.9.16",slug:"_2021-9-16",link:"#_2021-9-16",children:[]},{level:2,title:"2021.9.8 v1.4.3",slug:"_2021-9-8-v1-4-3",link:"#_2021-9-8-v1-4-3",children:[]},{level:2,title:"2021.7.14",slug:"_2021-7-14",link:"#_2021-7-14",children:[]},{level:2,title:"2021.6.21",slug:"_2021-6-21",link:"#_2021-6-21",children:[]},{level:2,title:"2021.5.1",slug:"_2021-5-1",link:"#_2021-5-1",children:[]},{level:2,title:"2021.4.26",slug:"_2021-4-26",link:"#_2021-4-26",children:[]},{level:2,title:"2021.4.12",slug:"_2021-4-12",link:"#_2021-4-12",children:[]},{level:2,title:"2021.4.6",slug:"_2021-4-6",link:"#_2021-4-6",children:[]},{level:2,title:"2021.4.4",slug:"_2021-4-4",link:"#_2021-4-4",children:[]},{level:2,title:"2021.4.1 v1.4.2",slug:"_2021-4-1-v1-4-2",link:"#_2021-4-1-v1-4-2",children:[]},{level:2,title:"2021.3.25",slug:"_2021-3-25",link:"#_2021-3-25",children:[]},{level:2,title:"2021.3.15",slug:"_2021-3-15",link:"#_2021-3-15",children:[]},{level:2,title:"2021.3.14 v1.4.0",slug:"_2021-3-14-v1-4-0",link:"#_2021-3-14-v1-4-0",children:[]},{level:2,title:"2021.3.3 1.3.1",slug:"_2021-3-3-1-3-1",link:"#_2021-3-3-1-3-1",children:[]},{level:2,title:"2021.2.14 1.3.0",slug:"_2021-2-14-1-3-0",link:"#_2021-2-14-1-3-0",children:[]},{level:2,title:"2021.01.31 1.2.4",slug:"_2021-01-31-1-2-4",link:"#_2021-01-31-1-2-4",children:[]},{level:2,title:"2021.01.25",slug:"_2021-01-25",link:"#_2021-01-25",children:[]},{level:2,title:"2021.01.22 1.2.3",slug:"_2021-01-22-1-2-3",link:"#_2021-01-22-1-2-3",children:[]},{level:2,title:"2021.01.19",slug:"_2021-01-19",link:"#_2021-01-19",children:[]},{level:2,title:"2021.01.17",slug:"_2021-01-17",link:"#_2021-01-17",children:[]},{level:2,title:"2021.01.15 1.2.2",slug:"_2021-01-15-1-2-2",link:"#_2021-01-15-1-2-2",children:[]},{level:2,title:"2021.01.12",slug:"_2021-01-12",link:"#_2021-01-12",children:[]},{level:2,title:"2021.01.10 1.2.1",slug:"_2021-01-10-1-2-1",link:"#_2021-01-10-1-2-1",children:[]},{level:2,title:"2021.01.07",slug:"_2021-01-07",link:"#_2021-01-07",children:[]},{level:2,title:"2021.01.05",slug:"_2021-01-05",link:"#_2021-01-05",children:[]},{level:2,title:"2021.01.03",slug:"_2021-01-03",link:"#_2021-01-03",children:[]},{level:2,title:"2021.01.01",slug:"_2021-01-01",link:"#_2021-01-01",children:[]},{level:2,title:"2020.12.29",slug:"_2020-12-29",link:"#_2020-12-29",children:[]},{level:2,title:"2020.12.25 1.1.5",slug:"_2020-12-25-1-1-5",link:"#_2020-12-25-1-1-5",children:[]},{level:2,title:"2020.12.24",slug:"_2020-12-24",link:"#_2020-12-24",children:[]},{level:2,title:"2020.12.23",slug:"_2020-12-23",link:"#_2020-12-23",children:[]},{level:2,title:"2020.12.21",slug:"_2020-12-21",link:"#_2020-12-21",children:[]},{level:2,title:"2020.12.18 1.1.4",slug:"_2020-12-18-1-1-4",link:"#_2020-12-18-1-1-4",children:[]},{level:2,title:"2020.12.17",slug:"_2020-12-17",link:"#_2020-12-17",children:[]},{level:2,title:"2020.12.15",slug:"_2020-12-15",link:"#_2020-12-15",children:[]},{level:2,title:"2020.12.11 1.1.3",slug:"_2020-12-11-1-1-3",link:"#_2020-12-11-1-1-3",children:[]},{level:2,title:"2020.12.06 1.1.2",slug:"_2020-12-06-1-1-2",link:"#_2020-12-06-1-1-2",children:[]},{level:2,title:"2020.12.04",slug:"_2020-12-04",link:"#_2020-12-04",children:[]},{level:2,title:"2020.11.27",slug:"_2020-11-27",link:"#_2020-11-27",children:[]},{level:2,title:"2020.11.25 1.0.0",slug:"_2020-11-25-1-0-0",link:"#_2020-11-25-1-0-0",children:[]},{level:2,title:"2020.11.23",slug:"_2020-11-23",link:"#_2020-11-23",children:[]}],path:"/en/about/news.html",pathLocale:"/en/",extraFields:[]},{title:"Configurations",headers:[{level:2,title:"Overview",slug:"overview",link:"#overview",children:[]},{level:2,title:"Basic Configuration Modules",slug:"basic-configuration-modules",link:"#basic-configuration-modules",children:[]}],path:"/en/config/",pathLocale:"/en/",extraFields:[]},{title:"API Interface",headers:[{level:2,title:"ApiObject",slug:"apiobject",link:"#apiobject",children:[]},{level:2,title:"Related Configuration",slug:"related-configuration",link:"#related-configuration",children:[]},{level:2,title:"Supported API List",slug:"supported-api-list",link:"#supported-api-list",children:[{level:3,title:"HandlerService",slug:"handlerservice",link:"#handlerservice",children:[]}]},{level:2,title:"RoutingService",slug:"routingservice",link:"#routingservice",children:[{level:3,title:"LoggerService",slug:"loggerservice",link:"#loggerservice",children:[]},{level:3,title:"StatsService",slug:"statsservice",link:"#statsservice",children:[]},{level:3,title:"ReflectionService",slug:"reflectionservice",link:"#reflectionservice",children:[]}]},{level:2,title:"API Calling Example",slug:"api-calling-example",link:"#api-calling-example",children:[]}],path:"/en/config/api.html",pathLocale:"/en/",extraFields:[]},{title:"Built-in DNS Server",headers:[{level:2,title:"DNS Server",slug:"dns-server",link:"#dns-server",children:[]},{level:2,title:"DNS Processing Flow",slug:"dns-processing-flow",link:"#dns-processing-flow",children:[]},{level:2,title:"DnsObject",slug:"dnsobject",link:"#dnsobject",children:[{level:3,title:"ServerObject",slug:"serverobject",link:"#serverobject",children:[]}]}],path:"/en/config/dns.html",pathLocale:"/en/",extraFields:[]},{title:"FakeDNS",headers:[{level:2,title:"FakeDNSObject",slug:"fakednsobject",link:"#fakednsobject",children:[{level:3,title:"How to use?",slug:"how-to-use",link:"#how-to-use",children:[]},{level:3,title:"Using with other types of DNS",slug:"using-with-other-types-of-dns",link:"#using-with-other-types-of-dns",children:[]}]}],path:"/en/config/fakedns.html",pathLocale:"/en/",extraFields:[]},{title:"Inbound Proxy",headers:[{level:2,title:"InboundObject",slug:"inboundobject",link:"#inboundobject",children:[{level:3,title:"SniffingObject",slug:"sniffingobject",link:"#sniffingobject",children:[]},{level:3,title:"AllocateObject",slug:"allocateobject",link:"#allocateobject",children:[]}]}],path:"/en/config/inbound.html",pathLocale:"/en/",extraFields:[]},{title:"Log Configuration",headers:[{level:2,title:"LogObject",slug:"logobject",link:"#logobject",children:[]}],path:"/en/config/log.html",pathLocale:"/en/",extraFields:[]},{title:"Metrics",headers:[{level:2,title:"Related configurations",slug:"related-configurations",link:"#related-configurations",children:[]},{level:2,title:"Usage",slug:"usage",link:"#usage",children:[{level:3,title:"pprof",slug:"pprof",link:"#pprof",children:[]},{level:3,title:"expvars",slug:"expvars",link:"#expvars",children:[]},{level:3,title:"Additional",slug:"additional",link:"#additional",children:[]}]}],path:"/en/config/metrics.html",pathLocale:"/en/",extraFields:[]},{title:"Connection Monitoring",headers:[{level:2,title:"ObservatoryObject",slug:"observatoryobject",link:"#observatoryobject",children:[]},{level:2,title:"BurstObservatoryObject",slug:"burstobservatoryobject",link:"#burstobservatoryobject",children:[{level:3,title:"PingConfigObject",slug:"pingconfigobject",link:"#pingconfigobject",children:[]}]}],path:"/en/config/observatory.html",pathLocale:"/en/",extraFields:[]},{title:"Outbound Proxies",headers:[{level:2,title:"OutboundObject",slug:"outboundobject",link:"#outboundobject",children:[{level:3,title:"ProxySettingsObject",slug:"proxysettingsobject",link:"#proxysettingsobject",children:[]},{level:3,title:"MuxObject",slug:"muxobject",link:"#muxobject",children:[]}]}],path:"/en/config/outbound.html",pathLocale:"/en/",extraFields:[]},{title:"Local Policy",headers:[{level:2,title:"PolicyObject",slug:"policyobject",link:"#policyobject",children:[{level:3,title:"LevelPolicyObject",slug:"levelpolicyobject",link:"#levelpolicyobject",children:[]},{level:3,title:"SystemPolicyObject",slug:"systempolicyobject",link:"#systempolicyobject",children:[]}]}],path:"/en/config/policy.html",pathLocale:"/en/",extraFields:[]},{title:"Reverse Proxy",headers:[{level:2,title:"ReverseObject",slug:"reverseobject",link:"#reverseobject",children:[{level:3,title:"BridgeObject",slug:"bridgeobject",link:"#bridgeobject",children:[]},{level:3,title:"PortalObject",slug:"portalobject",link:"#portalobject",children:[]}]},{level:2,title:"Complete Configuration Example",slug:"complete-configuration-example",link:"#complete-configuration-example",children:[{level:3,title:"Bridge Configuration",slug:"bridge-configuration",link:"#bridge-configuration",children:[]},{level:3,title:"Portal Configuration",slug:"portal-configuration",link:"#portal-configuration",children:[]}]}],path:"/en/config/reverse.html",pathLocale:"/en/",extraFields:[]},{title:"Routing",headers:[{level:2,title:"RoutingObject",slug:"routingobject",link:"#routingobject",children:[{level:3,title:"RuleObject",slug:"ruleobject",link:"#ruleobject",children:[]},{level:3,title:"BalancerObject",slug:"balancerobject",link:"#balancerobject",children:[]},{level:3,title:"Predefined Domain Lists",slug:"predefined-domain-lists",link:"#predefined-domain-lists",children:[]}]}],path:"/en/config/routing.html",pathLocale:"/en/",extraFields:[]},{title:"Traffic Statistics",headers:[{level:2,title:"StatsObject",slug:"statsobject",link:"#statsobject",children:[]},{level:2,title:"Retrieving Traffic Statistics",slug:"retrieving-traffic-statistics",link:"#retrieving-traffic-statistics",children:[]}],path:"/en/config/stats.html",pathLocale:"/en/",extraFields:[]},{title:"Transport",headers:[{level:2,title:"StreamSettingsObject",slug:"streamsettingsobject",link:"#streamsettingsobject",children:[{level:3,title:"TLSObject",slug:"tlsobject",link:"#tlsobject",children:[]},{level:3,title:"SockoptObject",slug:"sockoptobject",link:"#sockoptobject",children:[]}]}],path:"/en/config/transport.html",pathLocale:"/en/",extraFields:[]},{title:"Development Guide",headers:[{level:2,title:"Compile Documentation",slug:"compile-documentation",link:"#compile-documentation",children:[]},{level:2,title:"Design Concept",slug:"design-concept",link:"#design-concept",children:[]},{level:2,title:"Development Standards",slug:"development-standards",link:"#development-standards",children:[]},{level:2,title:"Protocol Details",slug:"protocol-details",link:"#protocol-details",children:[{level:3,title:"VLESS Protocol",slug:"vless-protocol",link:"#vless-protocol",children:[]},{level:3,title:"VMess Protocol",slug:"vmess-protocol",link:"#vmess-protocol",children:[]},{level:3,title:"Mux.Cool Protocol",slug:"mux-cool-protocol",link:"#mux-cool-protocol",children:[]},{level:3,title:"mKCP Protocol",slug:"mkcp-protocol",link:"#mkcp-protocol",children:[]}]}],path:"/en/development/",pathLocale:"/en/",extraFields:[]},{title:"Quick Start",headers:[{level:2,title:"Download and Install",slug:"download-and-install",link:"#download-and-install",children:[]},{level:2,title:"Configure and Run",slug:"configure-and-run",link:"#configure-and-run",children:[]},{level:2,title:"Command Parameters",slug:"command-parameters",link:"#command-parameters",children:[]},{level:2,title:"Improve Documents",slug:"improve-documents",link:"#improve-documents",children:[]},{level:2,title:"Beginner Tutorial",slug:"beginner-tutorial",link:"#beginner-tutorial",children:[]},{level:2,title:"Getting Started Tips",slug:"getting-started-tips",link:"#getting-started-tips",children:[]},{level:2,title:"Advanced Documentation",slug:"advanced-documentation",link:"#advanced-documentation",children:[]}],path:"/en/document/",pathLocale:"/en/",extraFields:[]},{title:"Command Parameters",headers:[{level:2,title:"Get Basic Commands",slug:"get-basic-commands",link:"#get-basic-commands",children:[{level:3,title:"xray run",slug:"xray-run",link:"#xray-run",children:[]},{level:3,title:"xray version",slug:"xray-version",link:"#xray-version",children:[]},{level:3,title:"xray api",slug:"xray-api",link:"#xray-api",children:[]},{level:3,title:"xray convert",slug:"xray-convert",link:"#xray-convert",children:[]},{level:3,title:"xray tls",slug:"xray-tls",link:"#xray-tls",children:[]},{level:3,title:"xray uuid",slug:"xray-uuid",link:"#xray-uuid",children:[]},{level:3,title:"xray x25519",slug:"xray-x25519",link:"#xray-x25519",children:[]},{level:3,title:"xray wg",slug:"xray-wg",link:"#xray-wg",children:[]}]}],path:"/en/document/command.html",pathLocale:"/en/",extraFields:[]},{title:"Configure and Run",headers:[{level:2,title:"Server Configuration",slug:"server-configuration",link:"#server-configuration",children:[]},{level:2,title:"Client Configuration",slug:"client-configuration",link:"#client-configuration",children:[]},{level:2,title:"Run",slug:"run",link:"#run",children:[]}],path:"/en/document/config.html",pathLocale:"/en/",extraFields:[]},{title:"Contribute to Project X's Document",headers:[{level:2,title:"Improve Document",slug:"improve-document",link:"#improve-document",children:[]},{level:2,title:"Found Problems?",slug:"found-problems",link:"#found-problems",children:[]}],path:"/en/document/document.html",pathLocale:"/en/",extraFields:[]},{title:"Download and Install",headers:[{level:2,title:"Platform Support",slug:"platform-support",link:"#platform-support",children:[]},{level:2,title:"Download Xray",slug:"download-xray",link:"#download-xray",children:[]},{level:2,title:"Verify the Installation Package",slug:"verify-the-installation-package",link:"#verify-the-installation-package",children:[]},{level:2,title:"Install on Windows",slug:"install-on-windows",link:"#install-on-windows",children:[]},{level:2,title:"Install on macOS",slug:"install-on-macos",link:"#install-on-macos",children:[]},{level:2,title:"Install on Linux",slug:"install-on-linux",link:"#install-on-linux",children:[{level:3,title:"Install Script",slug:"install-script",link:"#install-script",children:[]},{level:3,title:"Arch Linux",slug:"arch-linux",link:"#arch-linux",children:[]},{level:3,title:"Linuxbrew",slug:"linuxbrew",link:"#linuxbrew",children:[]},{level:3,title:"Debian",slug:"debian",link:"#debian",children:[]}]},{level:2,title:"Install via Docker",slug:"install-via-docker",link:"#install-via-docker",children:[{level:3,title:"The File Structure of the Docker Image",slug:"the-file-structure-of-the-docker-image",link:"#the-file-structure-of-the-docker-image",children:[]}]}],path:"/en/document/install.html",pathLocale:"/en/",extraFields:[]},{title:"大史记",headers:[{level:2,title:"2024.9.12",slug:"_2024-9-12",link:"#_2024-9-12",children:[]},{level:2,title:"2024.9.7 v24.9.7",slug:"_2024-9-7-v24-9-7",link:"#_2024-9-7-v24-9-7",children:[]},{level:2,title:"2024.8.30 v1.8.24",slug:"_2024-8-30-v1-8-24",link:"#_2024-8-30-v1-8-24",children:[]},{level:2,title:"2024.8.26",slug:"_2024-8-26",link:"#_2024-8-26",children:[]},{level:2,title:"2024.8.3",slug:"_2024-8-3",link:"#_2024-8-3",children:[]},{level:2,title:"2024.7.29 v1.8.23",slug:"_2024-7-29-v1-8-23",link:"#_2024-7-29-v1-8-23",children:[]},{level:2,title:"2024.7.22 v1.8.21",slug:"_2024-7-22-v1-8-21",link:"#_2024-7-22-v1-8-21",children:[]},{level:2,title:"2024.7.16",slug:"_2024-7-16",link:"#_2024-7-16",children:[]},{level:2,title:"2024.7.15",slug:"_2024-7-15",link:"#_2024-7-15",children:[]},{level:2,title:"2024.6.18 v1.8.16",slug:"_2024-6-18-v1-8-16",link:"#_2024-6-18-v1-8-16",children:[]},{level:2,title:"2024.6.2",slug:"_2024-6-2",link:"#_2024-6-2",children:[]},{level:2,title:"2024.4.26 v1.8.11",slug:"_2024-4-26-v1-8-11",link:"#_2024-4-26-v1-8-11",children:[]},{level:2,title:"2024.4.20",slug:"_2024-4-20",link:"#_2024-4-20",children:[]},{level:2,title:"2024.4.13",slug:"_2024-4-13",link:"#_2024-4-13",children:[]},{level:2,title:"2024.3.18 v1.8.10",slug:"_2024-3-18-v1-8-10",link:"#_2024-3-18-v1-8-10",children:[]},{level:2,title:"2024.3.11 v1.8.9",slug:"_2024-3-11-v1-8-9",link:"#_2024-3-11-v1-8-9",children:[]},{level:2,title:"2024.2.29",slug:"_2024-2-29",link:"#_2024-2-29",children:[]},{level:2,title:"2024.2.25 v1.8.8",slug:"_2024-2-25-v1-8-8",link:"#_2024-2-25-v1-8-8",children:[]},{level:2,title:"2024.1.9",slug:"_2024-1-9",link:"#_2024-1-9",children:[]},{level:2,title:"2023.11.21",slug:"_2023-11-21",link:"#_2023-11-21",children:[]},{level:2,title:"2023.11.18 v1.8.6",slug:"_2023-11-18-v1-8-6",link:"#_2023-11-18-v1-8-6",children:[]},{level:2,title:"2023.9.30",slug:"_2023-9-30",link:"#_2023-9-30",children:[]},{level:2,title:"2023.8.29 v1.8.4",slug:"_2023-8-29-v1-8-4",link:"#_2023-8-29-v1-8-4",children:[]},{level:2,title:"2023.7.22",slug:"_2023-7-22",link:"#_2023-7-22",children:[]},{level:2,title:"2023.7.7",slug:"_2023-7-7",link:"#_2023-7-7",children:[]},{level:2,title:"2023.6.30",slug:"_2023-6-30",link:"#_2023-6-30",children:[]},{level:2,title:"2023.6.27",slug:"_2023-6-27",link:"#_2023-6-27",children:[]},{level:2,title:"2023.6.19 v1.8.3",slug:"_2023-6-19-v1-8-3",link:"#_2023-6-19-v1-8-3",children:[]},{level:2,title:"2023.6.6",slug:"_2023-6-6",link:"#_2023-6-6",children:[]},{level:2,title:"2023.4.21",slug:"_2023-4-21",link:"#_2023-4-21",children:[]},{level:2,title:"2023.4.20",slug:"_2023-4-20",link:"#_2023-4-20",children:[]},{level:2,title:"2023.4.19",slug:"_2023-4-19",link:"#_2023-4-19",children:[]},{level:2,title:"2023.4.18 v1.8.1",slug:"_2023-4-18-v1-8-1",link:"#_2023-4-18-v1-8-1",children:[]},{level:2,title:"2023.4.6",slug:"_2023-4-6",link:"#_2023-4-6",children:[]},{level:2,title:"2023.3.29",slug:"_2023-3-29",link:"#_2023-3-29",children:[]},{level:2,title:"2023.3.19",slug:"_2023-3-19",link:"#_2023-3-19",children:[]},{level:2,title:"2023.3.9 v1.8.0",slug:"_2023-3-9-v1-8-0",link:"#_2023-3-9-v1-8-0",children:[]},{level:2,title:"2023.3.4",slug:"_2023-3-4",link:"#_2023-3-4",children:[]},{level:2,title:"2023.3.2",slug:"_2023-3-2",link:"#_2023-3-2",children:[]},{level:2,title:"2023.2.16",slug:"_2023-2-16",link:"#_2023-2-16",children:[]},{level:2,title:"2023.2.9",slug:"_2023-2-9",link:"#_2023-2-9",children:[]},{level:2,title:"2023.2.8 v1.7.5",slug:"_2023-2-8-v1-7-5",link:"#_2023-2-8-v1-7-5",children:[]},{level:2,title:"2023.1.29",slug:"_2023-1-29",link:"#_2023-1-29",children:[]},{level:2,title:"2022.12.26 v1.7.0",slug:"_2022-12-26-v1-7-0",link:"#_2022-12-26-v1-7-0",children:[]},{level:2,title:"2022.11.28 v1.6.5",slug:"_2022-11-28-v1-6-5",link:"#_2022-11-28-v1-6-5",children:[]},{level:2,title:"2022.11.7 v1.6.3",slug:"_2022-11-7-v1-6-3",link:"#_2022-11-7-v1-6-3",children:[]},{level:2,title:"2022.10.29 v1.6.2",slug:"_2022-10-29-v1-6-2",link:"#_2022-10-29-v1-6-2",children:[]},{level:2,title:"2022.10.22 v1.6.1",slug:"_2022-10-22-v1-6-1",link:"#_2022-10-22-v1-6-1",children:[]},{level:2,title:"2022.10.3",slug:"_2022-10-3",link:"#_2022-10-3",children:[]},{level:2,title:"2022.8.28 v1.5.10",slug:"_2022-8-28-v1-5-10",link:"#_2022-8-28-v1-5-10",children:[]},{level:2,title:"2022.6.20 v1.5.8",slug:"_2022-6-20-v1-5-8",link:"#_2022-6-20-v1-5-8",children:[]},{level:2,title:"2022.5.29 v1.5.6",slug:"_2022-5-29-v1-5-6",link:"#_2022-5-29-v1-5-6",children:[]},{level:2,title:"2022.4.24 v1.5.5",slug:"_2022-4-24-v1-5-5",link:"#_2022-4-24-v1-5-5",children:[]},{level:2,title:"2022.3.13 v1.5.4",slug:"_2022-3-13-v1-5-4",link:"#_2022-3-13-v1-5-4",children:[]},{level:2,title:"2022.1.29 v1.5.3",slug:"_2022-1-29-v1-5-3",link:"#_2022-1-29-v1-5-3",children:[]},{level:2,title:"2021.12.24 v1.5.2",slug:"_2021-12-24-v1-5-2",link:"#_2021-12-24-v1-5-2",children:[]},{level:2,title:"2021.12.15 v1.5.1",slug:"_2021-12-15-v1-5-1",link:"#_2021-12-15-v1-5-1",children:[]},{level:2,title:"2021.10.20 v1.5.0",slug:"_2021-10-20-v1-5-0",link:"#_2021-10-20-v1-5-0",children:[]},{level:2,title:"2021.9.23 v1.4.5",slug:"_2021-9-23-v1-4-5",link:"#_2021-9-23-v1-4-5",children:[]},{level:2,title:"2021.9.16",slug:"_2021-9-16",link:"#_2021-9-16",children:[]},{level:2,title:"2021.9.8 v1.4.3",slug:"_2021-9-8-v1-4-3",link:"#_2021-9-8-v1-4-3",children:[]},{level:2,title:"2021.7.14",slug:"_2021-7-14",link:"#_2021-7-14",children:[]},{level:2,title:"2021.6.21",slug:"_2021-6-21",link:"#_2021-6-21",children:[]},{level:2,title:"2021.5.1",slug:"_2021-5-1",link:"#_2021-5-1",children:[]},{level:2,title:"2021.4.26",slug:"_2021-4-26",link:"#_2021-4-26",children:[]},{level:2,title:"2021.4.12",slug:"_2021-4-12",link:"#_2021-4-12",children:[]},{level:2,title:"2021.4.6",slug:"_2021-4-6",link:"#_2021-4-6",children:[]},{level:2,title:"2021.4.4",slug:"_2021-4-4",link:"#_2021-4-4",children:[]},{level:2,title:"2021.4.1 v1.4.2",slug:"_2021-4-1-v1-4-2",link:"#_2021-4-1-v1-4-2",children:[]},{level:2,title:"2021.3.25",slug:"_2021-3-25",link:"#_2021-3-25",children:[]},{level:2,title:"2021.3.15",slug:"_2021-3-15",link:"#_2021-3-15",children:[]},{level:2,title:"2021.3.14 v1.4.0",slug:"_2021-3-14-v1-4-0",link:"#_2021-3-14-v1-4-0",children:[]},{level:2,title:"2021.3.3 1.3.1",slug:"_2021-3-3-1-3-1",link:"#_2021-3-3-1-3-1",children:[]},{level:2,title:"2021.2.14 1.3.0",slug:"_2021-2-14-1-3-0",link:"#_2021-2-14-1-3-0",children:[]},{level:2,title:"2021.01.31 1.2.4",slug:"_2021-01-31-1-2-4",link:"#_2021-01-31-1-2-4",children:[]},{level:2,title:"2021.01.25",slug:"_2021-01-25",link:"#_2021-01-25",children:[]},{level:2,title:"2021.01.22 1.2.3",slug:"_2021-01-22-1-2-3",link:"#_2021-01-22-1-2-3",children:[]},{level:2,title:"2021.01.19",slug:"_2021-01-19",link:"#_2021-01-19",children:[]},{level:2,title:"2021.01.17",slug:"_2021-01-17",link:"#_2021-01-17",children:[]},{level:2,title:"2021.01.15 1.2.2",slug:"_2021-01-15-1-2-2",link:"#_2021-01-15-1-2-2",children:[]},{level:2,title:"2021.01.12",slug:"_2021-01-12",link:"#_2021-01-12",children:[]},{level:2,title:"2021.01.10 1.2.1",slug:"_2021-01-10-1-2-1",link:"#_2021-01-10-1-2-1",children:[]},{level:2,title:"2021.01.07",slug:"_2021-01-07",link:"#_2021-01-07",children:[]},{level:2,title:"2021.01.05",slug:"_2021-01-05",link:"#_2021-01-05",children:[]},{level:2,title:"2021.01.03",slug:"_2021-01-03",link:"#_2021-01-03",children:[]},{level:2,title:"2021.01.01",slug:"_2021-01-01",link:"#_2021-01-01",children:[]},{level:2,title:"2020.12.29",slug:"_2020-12-29",link:"#_2020-12-29",children:[]},{level:2,title:"2020.12.25 1.1.5",slug:"_2020-12-25-1-1-5",link:"#_2020-12-25-1-1-5",children:[]},{level:2,title:"2020.12.24",slug:"_2020-12-24",link:"#_2020-12-24",children:[]},{level:2,title:"2020.12.23",slug:"_2020-12-23",link:"#_2020-12-23",children:[]},{level:2,title:"2020.12.21",slug:"_2020-12-21",link:"#_2020-12-21",children:[]},{level:2,title:"2020.12.18 1.1.4",slug:"_2020-12-18-1-1-4",link:"#_2020-12-18-1-1-4",children:[]},{level:2,title:"2020.12.17",slug:"_2020-12-17",link:"#_2020-12-17",children:[]},{level:2,title:"2020.12.15",slug:"_2020-12-15",link:"#_2020-12-15",children:[]},{level:2,title:"2020.12.11 1.1.3",slug:"_2020-12-11-1-1-3",link:"#_2020-12-11-1-1-3",children:[]},{level:2,title:"2020.12.06 1.1.2",slug:"_2020-12-06-1-1-2",link:"#_2020-12-06-1-1-2",children:[]},{level:2,title:"2020.12.04",slug:"_2020-12-04",link:"#_2020-12-04",children:[]},{level:2,title:"2020.11.27",slug:"_2020-11-27",link:"#_2020-11-27",children:[]},{level:2,title:"2020.11.25 1.0.0",slug:"_2020-11-25-1-0-0",link:"#_2020-11-25-1-0-0",children:[]},{level:2,title:"2020.11.23",slug:"_2020-11-23",link:"#_2020-11-23",children:[]}],path:"/ru/about/news.html",pathLocale:"/ru/",extraFields:[]},{title:"Конфигурационный файл",headers:[{level:2,title:"Обзор",slug:"обзор",link:"#обзор",children:[]},{level:2,title:"Основные модули конфигурации",slug:"основные-модули-конфигурации",link:"#основные-модули-конфигурации",children:[]}],path:"/ru/config/",pathLocale:"/ru/",extraFields:[]},{title:"API",headers:[{level:2,title:"ApiObject",slug:"apiobject",link:"#apiobject",children:[]},{level:2,title:"Связанные настройки",slug:"связанные-настроики",link:"#связанные-настроики",children:[]},{level:2,title:"Список поддерживаемых API",slug:"список-поддерживаемых-api",link:"#список-поддерживаемых-api",children:[{level:3,title:"HandlerService",slug:"handlerservice",link:"#handlerservice",children:[]},{level:3,title:"RoutingService",slug:"routingservice",link:"#routingservice",children:[]},{level:3,title:"LoggerService",slug:"loggerservice",link:"#loggerservice",children:[]},{level:3,title:"StatsService",slug:"statsservice",link:"#statsservice",children:[]},{level:3,title:"ReflectionService",slug:"reflectionservice",link:"#reflectionservice",children:[]}]},{level:2,title:"Примеры вызова API",slug:"примеры-вызова-api",link:"#примеры-вызова-api",children:[]}],path:"/ru/config/api.html",pathLocale:"/ru/",extraFields:[]},{title:"Встроенный DNS-сервер",headers:[{level:2,title:"DNS-сервер",slug:"dns-сервер",link:"#dns-сервер",children:[]},{level:2,title:"Процесс обработки DNS-запросов",slug:"процесс-обработки-dns-запросов",link:"#процесс-обработки-dns-запросов",children:[]},{level:2,title:"DnsObject",slug:"dnsobject",link:"#dnsobject",children:[{level:3,title:"ServerObject",slug:"serverobject",link:"#serverobject",children:[]}]}],path:"/ru/config/dns.html",pathLocale:"/ru/",extraFields:[]},{title:"FakeDNS",headers:[{level:2,title:"FakeDNSObject",slug:"fakednsobject",link:"#fakednsobject",children:[{level:3,title:"Как использовать FakeDNS?",slug:"как-использовать-fakedns",link:"#как-использовать-fakedns",children:[]},{level:3,title:"Использование FakeDNS с другими типами DNS",slug:"использование-fakedns-с-другими-типами-dns",link:"#использование-fakedns-с-другими-типами-dns",children:[]}]}],path:"/ru/config/fakedns.html",pathLocale:"/ru/",extraFields:[]},{title:"Входящие подключения",headers:[{level:2,title:"InboundObject",slug:"inboundobject",link:"#inboundobject",children:[{level:3,title:"SniffingObject",slug:"sniffingobject",link:"#sniffingobject",children:[]},{level:3,title:"AllocateObject",slug:"allocateobject",link:"#allocateobject",children:[]}]}],path:"/ru/config/inbound.html",pathLocale:"/ru/",extraFields:[]},{title:"Настройка журнала",headers:[{level:2,title:"LogObject",slug:"logobject",link:"#logobject",children:[]}],path:"/ru/config/log.html",pathLocale:"/ru/",extraFields:[]},{title:"Метрики",headers:[{level:2,title:"Связанные настройки",slug:"связанные-настроики",link:"#связанные-настроики",children:[]},{level:2,title:"Использование",slug:"использование",link:"#использование",children:[{level:3,title:"pprof",slug:"pprof",link:"#pprof",children:[]},{level:3,title:"expvars",slug:"expvars",link:"#expvars",children:[]},{level:3,title:"Дополнительно",slug:"дополнительно",link:"#дополнительно",children:[]}]}],path:"/ru/config/metrics.html",pathLocale:"/ru/",extraFields:[]},{title:"Мониторинг подключений",headers:[{level:2,title:"ObservatoryObject",slug:"observatoryobject",link:"#observatoryobject",children:[]},{level:2,title:"BurstObservatoryObject",slug:"burstobservatoryobject",link:"#burstobservatoryobject",children:[{level:3,title:"PingConfigObject",slug:"pingconfigobject",link:"#pingconfigobject",children:[]}]}],path:"/ru/config/observatory.html",pathLocale:"/ru/",extraFields:[]},{title:"Исходящие подключения",headers:[{level:2,title:"OutboundObject",slug:"outboundobject",link:"#outboundobject",children:[{level:3,title:"ProxySettingsObject",slug:"proxysettingsobject",link:"#proxysettingsobject",children:[]},{level:3,title:"MuxObject",slug:"muxobject",link:"#muxobject",children:[]}]}],path:"/ru/config/outbound.html",pathLocale:"/ru/",extraFields:[]},{title:"Локальные политики",headers:[{level:2,title:"PolicyObject",slug:"policyobject",link:"#policyobject",children:[{level:3,title:"LevelPolicyObject",slug:"levelpolicyobject",link:"#levelpolicyobject",children:[]},{level:3,title:"SystemPolicyObject",slug:"systempolicyobject",link:"#systempolicyobject",children:[]}]}],path:"/ru/config/policy.html",pathLocale:"/ru/",extraFields:[]},{title:"Обратный прокси",headers:[{level:2,title:"ReverseObject",slug:"reverseobject",link:"#reverseobject",children:[{level:3,title:"BridgeObject",slug:"bridgeobject",link:"#bridgeobject",children:[]},{level:3,title:"PortalObject",slug:"portalobject",link:"#portalobject",children:[]}]},{level:2,title:"Примеры полных конфигураций",slug:"примеры-полных-конфигурации",link:"#примеры-полных-конфигурации",children:[{level:3,title:"Настройка bridge",slug:"настроика-bridge",link:"#настроика-bridge",children:[]},{level:3,title:"Настройка portal",slug:"настроика-portal",link:"#настроика-portal",children:[]}]}],path:"/ru/config/reverse.html",pathLocale:"/ru/",extraFields:[]},{title:"Маршрутизация",headers:[{level:2,title:"RoutingObject",slug:"routingobject",link:"#routingobject",children:[{level:3,title:"RuleObject",slug:"ruleobject",link:"#ruleobject",children:[]},{level:3,title:"BalancerObject",slug:"balancerobject",link:"#balancerobject",children:[]},{level:3,title:"Пример конфигурации балансировщика нагрузки",slug:"пример-конфигурации-балансировщика-нагрузки",link:"#пример-конфигурации-балансировщика-нагрузки",children:[]},{level:3,title:"Предопределенные списки доменов",slug:"предопределенные-списки-доменов",link:"#предопределенные-списки-доменов",children:[]}]}],path:"/ru/config/routing.html",pathLocale:"/ru/",extraFields:[]},{title:"Статистика",headers:[{level:2,title:"StatsObject",slug:"statsobject",link:"#statsobject",children:[]},{level:2,title:"Получение статистики",slug:"получение-статистики",link:"#получение-статистики",children:[]}],path:"/ru/config/stats.html",pathLocale:"/ru/",extraFields:[]},{title:"Транспорт",headers:[{level:2,title:"StreamSettingsObject",slug:"streamsettingsobject",link:"#streamsettingsobject",children:[{level:3,title:"TLSObject",slug:"tlsobject",link:"#tlsobject",children:[]},{level:3,title:"RealityObject",slug:"realityobject",link:"#realityobject",children:[]},{level:3,title:"SockoptObject",slug:"sockoptobject",link:"#sockoptobject",children:[]}]}],path:"/ru/config/transport.html",pathLocale:"/ru/",extraFields:[]},{title:"开发指南",headers:[{level:2,title:"编译文档",slug:"编译文档",link:"#编译文档",children:[]},{level:2,title:"设计思路",slug:"设计思路",link:"#设计思路",children:[]},{level:2,title:"开发规范",slug:"开发规范",link:"#开发规范",children:[]},{level:2,title:"协议详解",slug:"协议详解",link:"#协议详解",children:[{level:3,title:"VLESS 协议",slug:"vless-协议",link:"#vless-协议",children:[]},{level:3,title:"VMess 协议",slug:"vmess-协议",link:"#vmess-协议",children:[]},{level:3,title:"Mux.Cool 协议",slug:"mux-cool-协议",link:"#mux-cool-协议",children:[]},{level:3,title:"mKCP 协议",slug:"mkcp-协议",link:"#mkcp-协议",children:[]}]}],path:"/ru/development/",pathLocale:"/ru/",extraFields:[]},{title:"Быстрый старт",headers:[{level:2,title:"Загрузка и установка",slug:"загрузка-и-установка",link:"#загрузка-и-установка",children:[]},{level:2,title:"Настройка и запуск",slug:"настроика-и-запуск",link:"#настроика-и-запуск",children:[]},{level:2,title:"Команды и аргументы",slug:"команды-и-аргументы",link:"#команды-и-аргументы",children:[]},{level:2,title:"Улучшение документации",slug:"улучшение-документации",link:"#улучшение-документации",children:[]},{level:2,title:"Простыми словами",slug:"простыми-словами",link:"#простыми-словами",children:[]},{level:2,title:"Базовые навыки",slug:"базовые-навыки",link:"#базовые-навыки",children:[]},{level:2,title:"Продвинутая документация",slug:"продвинутая-документация",link:"#продвинутая-документация",children:[]}],path:"/ru/document/",pathLocale:"/ru/",extraFields:[]},{title:"Командные аргументы",headers:[{level:2,title:"Базовые команды",slug:"базовые-команды",link:"#базовые-команды",children:[{level:3,title:"xray run",slug:"xray-run",link:"#xray-run",children:[]},{level:3,title:"xray version",slug:"xray-version",link:"#xray-version",children:[]},{level:3,title:"xray api",slug:"xray-api",link:"#xray-api",children:[]},{level:3,title:"xray convert",slug:"xray-convert",link:"#xray-convert",children:[]},{level:3,title:"xray tls",slug:"xray-tls",link:"#xray-tls",children:[]},{level:3,title:"xray uuid",slug:"xray-uuid",link:"#xray-uuid",children:[]},{level:3,title:"xray x25519",slug:"xray-x25519",link:"#xray-x25519",children:[]},{level:3,title:"xray wg",slug:"xray-wg",link:"#xray-wg",children:[]}]}],path:"/ru/document/command.html",pathLocale:"/ru/",extraFields:[]},{title:"Настройка и запуск",headers:[{level:2,title:"Настройка сервера",slug:"настроика-сервера",link:"#настроика-сервера",children:[]},{level:2,title:"Настройка клиента",slug:"настроика-клиента",link:"#настроика-клиента",children:[]},{level:2,title:"Запуск",slug:"запуск",link:"#запуск",children:[]}],path:"/ru/document/config.html",pathLocale:"/ru/",extraFields:[]},{title:"Вклад в документацию Project X",headers:[{level:2,title:"Улучшение документации",slug:"улучшение-документации",link:"#улучшение-документации",children:[]},{level:2,title:"Нашли ошибку?",slug:"нашли-ошибку",link:"#нашли-ошибку",children:[]}],path:"/ru/document/document.html",pathLocale:"/ru/",extraFields:[]},{title:"Загрузка и установка",headers:[{level:2,title:"Поддерживаемые платформы",slug:"поддерживаемые-платформы",link:"#поддерживаемые-платформы",children:[]},{level:2,title:"Загрузка Xray",slug:"загрузка-xray",link:"#загрузка-xray",children:[]},{level:2,title:"Проверка установочного пакета",slug:"проверка-установочного-пакета",link:"#проверка-установочного-пакета",children:[]},{level:2,title:"Установка на Windows",slug:"установка-на-windows",link:"#установка-на-windows",children:[]},{level:2,title:"Установка на macOS",slug:"установка-на-macos",link:"#установка-на-macos",children:[]},{level:2,title:"Установка на Linux",slug:"установка-на-linux",link:"#установка-на-linux",children:[{level:3,title:"Установочные скрипты",slug:"установочные-скрипты",link:"#установочные-скрипты",children:[]},{level:3,title:"Arch Linux",slug:"arch-linux",link:"#arch-linux",children:[]},{level:3,title:"Linuxbrew",slug:"linuxbrew",link:"#linuxbrew",children:[]},{level:3,title:"Debian",slug:"debian",link:"#debian",children:[]},{level:3,title:"Gentoo",slug:"gentoo",link:"#gentoo",children:[]}]},{level:2,title:"Установка с помощью Docker",slug:"установка-с-помощью-docker",link:"#установка-с-помощью-docker",children:[{level:3,title:"Файловая структура образа Docker",slug:"фаиловая-структура-образа-docker",link:"#фаиловая-структура-образа-docker",children:[]}]}],path:"/ru/document/install.html",pathLocale:"/ru/",extraFields:[]},{title:"透明代理入门",headers:[{level:2,title:"什么是透明代理",slug:"什么是透明代理",link:"#什么是透明代理",children:[]},{level:2,title:"透明代理的实现",slug:"透明代理的实现",link:"#透明代理的实现",children:[{level:3,title:"tun2socks",slug:"tun2socks",link:"#tun2socks",children:[]},{level:3,title:"iptables/nftables",slug:"iptables-nftables",link:"#iptables-nftables",children:[]}]},{level:2,title:"iptables 实现透明代理原理",slug:"iptables-实现透明代理原理",link:"#iptables-实现透明代理原理",children:[]},{level:2,title:"透明代理难在哪里",slug:"透明代理难在哪里",link:"#透明代理难在哪里",children:[]},{level:2,title:"从零开始一步步实现基于 iptables-tproxy 的透明代理",slug:"从零开始一步步实现基于-iptables-tproxy-的透明代理",link:"#从零开始一步步实现基于-iptables-tproxy-的透明代理",children:[{level:3,title:"在开始之前,你需要有一定的基础知识:",slug:"在开始之前-你需要有一定的基础知识",link:"#在开始之前-你需要有一定的基础知识",children:[]},{level:3,title:"前期准备工作",slug:"前期准备工作",link:"#前期准备工作",children:[]},{level:3,title:"首先,我们先试试做到第一阶段",slug:"首先-我们先试试做到第一阶段",link:"#首先-我们先试试做到第一阶段",children:[]},{level:3,title:"第二阶段",slug:"第二阶段",link:"#第二阶段",children:[]},{level:3,title:"第三阶段",slug:"第三阶段",link:"#第三阶段",children:[]},{level:3,title:"第四阶段",slug:"第四阶段",link:"#第四阶段",children:[]},{level:3,title:"代理 ipv6",slug:"代理-ipv6",link:"#代理-ipv6",children:[]}]}],path:"/document/level-2/transparent_proxy/transparent_proxy.html",pathLocale:"/",extraFields:[]},{title:"Browser Dialer",headers:[{level:2,title:"Background",slug:"background",link:"#background",children:[]},{level:2,title:"Configuration",slug:"configuration",link:"#configuration",children:[]},{level:2,title:"Inner workings",slug:"inner-workings",link:"#inner-workings",children:[]},{level:2,title:"WebSocket",slug:"websocket",link:"#websocket",children:[]},{level:2,title:"SplitHTTP",slug:"splithttp",link:"#splithttp",children:[]}],path:"/en/config/features/browser_dialer.html",pathLocale:"/en/",extraFields:[]},{title:"Environment Variables",headers:[{level:2,title:"Xray Asset Location",slug:"xray-asset-location",link:"#xray-asset-location",children:[]},{level:2,title:"Configuration File Location",slug:"configuration-file-location",link:"#configuration-file-location",children:[]},{level:2,title:"Multiple Configuration Directories",slug:"multiple-configuration-directories",link:"#multiple-configuration-directories",children:[]}],path:"/en/config/features/env.html",pathLocale:"/en/",extraFields:[]},{title:"Fallback",headers:[{level:2,title:"fallbacks configuration",slug:"fallbacks-configuration",link:"#fallbacks-configuration",children:[{level:3,title:"FallbackObject",slug:"fallbackobject",link:"#fallbackobject",children:[]},{level:3,title:"Additional Information",slug:"additional-information",link:"#additional-information",children:[]}]},{level:2,title:"Fallbacks design theory",slug:"fallbacks-design-theory",link:"#fallbacks-design-theory",children:[]}],path:"/en/config/features/fallback.html",pathLocale:"/en/",extraFields:[]},{title:"Multi-file configuration",headers:[{level:2,title:"Multi-file startup",slug:"multi-file-startup",link:"#multi-file-startup",children:[]},{level:2,title:"Rule Explanation",slug:"rule-explanation",link:"#rule-explanation",children:[{level:3,title:"Normal Objects({})",slug:"normal-objects",link:"#normal-objects",children:[]},{level:3,title:"Arrays([])",slug:"arrays",link:"#arrays",children:[]}]},{level:2,title:"Recommended Multi-file List",slug:"recommended-multi-file-list",link:"#recommended-multi-file-list",children:[]}],path:"/en/config/features/multiple.html",pathLocale:"/en/",extraFields:[]},{title:"Deep analysis of XTLS",headers:[],path:"/en/config/features/xtls.html",pathLocale:"/en/",extraFields:[]},{title:"Dokodemo-Door",headers:[{level:2,title:"InboundConfigurationObject",slug:"inboundconfigurationobject",link:"#inboundconfigurationobject",children:[]},{level:2,title:"Usage",slug:"usage",link:"#usage",children:[]},{level:2,title:"Transparent Proxy Configuration Example",slug:"transparent-proxy-configuration-example",link:"#transparent-proxy-configuration-example",children:[]}],path:"/en/config/inbounds/dokodemo.html",pathLocale:"/en/",extraFields:[]},{title:"HTTP",headers:[{level:3,title:"AccountObject",slug:"accountobject",link:"#accountobject",children:[]}],path:"/en/config/inbounds/http.html",pathLocale:"/en/",extraFields:[]},{title:"Shadowsocks",headers:[{level:3,title:"Supported Encryption Methods",slug:"supported-encryption-methods",link:"#supported-encryption-methods",children:[]},{level:2,title:"InboundConfigurationObject",slug:"inboundconfigurationobject",link:"#inboundconfigurationobject",children:[]},{level:2,title:"ClientObject",slug:"clientobject",link:"#clientobject",children:[]}],path:"/en/config/inbounds/shadowsocks.html",pathLocale:"/en/",extraFields:[]},{title:"SOCKS",headers:[{level:2,title:"InboundConfigurationObject",slug:"inboundconfigurationobject",link:"#inboundconfigurationobject",children:[{level:3,title:"AccountObject",slug:"accountobject",link:"#accountobject",children:[]}]}],path:"/en/config/inbounds/socks.html",pathLocale:"/en/",extraFields:[]},{title:"Trojan",headers:[{level:2,title:"InboundConfigurationObject",slug:"inboundconfigurationobject",link:"#inboundconfigurationobject",children:[{level:3,title:"ClientObject",slug:"clientobject",link:"#clientobject",children:[]}]}],path:"/en/config/inbounds/trojan.html",pathLocale:"/en/",extraFields:[]},{title:"VLESS",headers:[{level:2,title:"InboundConfigurationObject",slug:"inboundconfigurationobject",link:"#inboundconfigurationobject",children:[{level:3,title:"ClientObject",slug:"clientobject",link:"#clientobject",children:[]}]}],path:"/en/config/inbounds/vless.html",pathLocale:"/en/",extraFields:[]},{title:"VMess",headers:[{level:2,title:"InboundConfigurationObject",slug:"inboundconfigurationobject",link:"#inboundconfigurationobject",children:[{level:3,title:"ClientObject",slug:"clientobject",link:"#clientobject",children:[]}]}],path:"/en/config/inbounds/vmess.html",pathLocale:"/en/",extraFields:[]},{title:"Wireguard",headers:[{level:2,title:"InboundConfigurationObject",slug:"inboundconfigurationobject",link:"#inboundconfigurationobject",children:[{level:3,title:"Peers",slug:"peers",link:"#peers",children:[]}]}],path:"/en/config/inbounds/wireguard.html",pathLocale:"/en/",extraFields:[]},{title:"Blackhole",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[{level:3,title:"ResponseObject",slug:"responseobject",link:"#responseobject",children:[]}]}],path:"/en/config/outbounds/blackhole.html",pathLocale:"/en/",extraFields:[]},{title:"DNS",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[]},{level:2,title:"DNS Configuration Example",slug:"dns-configuration-example",link:"#dns-configuration-example",children:[]}],path:"/en/config/outbounds/dns.html",pathLocale:"/en/",extraFields:[]},{title:"Freedom",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[]}],path:"/en/config/outbounds/freedom.html",pathLocale:"/en/",extraFields:[]},{title:"HTTP",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[{level:3,title:"ServerObject",slug:"serverobject",link:"#serverobject",children:[]}]}],path:"/en/config/outbounds/http.html",pathLocale:"/en/",extraFields:[]},{title:"Loopback",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[{level:3,title:"How to use?",slug:"how-to-use",link:"#how-to-use",children:[]}]}],path:"/en/config/outbounds/loopback.html",pathLocale:"/en/",extraFields:[]},{title:"Shadowsocks",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[{level:3,title:"ServerObject",slug:"serverobject",link:"#serverobject",children:[]}]}],path:"/en/config/outbounds/shadowsocks.html",pathLocale:"/en/",extraFields:[]},{title:"Socks",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[{level:3,title:"ServerObject",slug:"serverobject",link:"#serverobject",children:[]}]}],path:"/en/config/outbounds/socks.html",pathLocale:"/en/",extraFields:[]},{title:"Trojan",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[{level:3,title:"ServerObject",slug:"serverobject",link:"#serverobject",children:[]}]}],path:"/en/config/outbounds/trojan.html",pathLocale:"/en/",extraFields:[]},{title:"VLESS",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[{level:3,title:"ServerObject",slug:"serverobject",link:"#serverobject",children:[]},{level:3,title:"UserObject",slug:"userobject",link:"#userobject",children:[]}]}],path:"/en/config/outbounds/vless.html",pathLocale:"/en/",extraFields:[]},{title:"VMess",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[{level:3,title:"ServerObject",slug:"serverobject",link:"#serverobject",children:[]}]}],path:"/en/config/outbounds/vmess.html",pathLocale:"/en/",extraFields:[]},{title:"Wireguard",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[{level:3,title:"Peers",slug:"peers",link:"#peers",children:[]}]}],path:"/en/config/outbounds/wireguard.html",pathLocale:"/en/",extraFields:[]},{title:"gRPC",headers:[{level:2,title:"GRPCObject",slug:"grpcobject",link:"#grpcobject",children:[]}],path:"/en/config/transports/grpc.html",pathLocale:"/en/",extraFields:[]},{title:"HTTP/2",headers:[{level:2,title:"HttpObject",slug:"httpobject",link:"#httpobject",children:[]}],path:"/en/config/transports/h2.html",pathLocale:"/en/",extraFields:[]},{title:"HTTPUpgrade",headers:[{level:2,title:"HttpUpgradeObject",slug:"httpupgradeobject",link:"#httpupgradeobject",children:[]}],path:"/en/config/transports/httpupgrade.html",pathLocale:"/en/",extraFields:[]},{title:"mKCP",headers:[{level:2,title:"KcpObject",slug:"kcpobject",link:"#kcpobject",children:[{level:3,title:"HeaderObject",slug:"headerobject",link:"#headerobject",children:[]}]},{level:2,title:"Special Thanks",slug:"special-thanks",link:"#special-thanks",children:[]},{level:2,title:"Improvements to the KCP protocol",slug:"improvements-to-the-kcp-protocol",link:"#improvements-to-the-kcp-protocol",children:[{level:3,title:"smaller protocol header",slug:"smaller-protocol-header",link:"#smaller-protocol-header",children:[]},{level:3,title:"ACK packet retransmission",slug:"ack-packet-retransmission",link:"#ack-packet-retransmission",children:[]},{level:3,title:"Connection state control",slug:"connection-state-control",link:"#connection-state-control",children:[]}]}],path:"/en/config/transports/mkcp.html",pathLocale:"/en/",extraFields:[]},{title:"SplitHTTP",headers:[{level:2,title:"SplitHttpObject",slug:"splithttpobject",link:"#splithttpobject",children:[]},{level:2,title:"HTTP versions",slug:"http-versions",link:"#http-versions",children:[]},{level:2,title:"Troubleshooting",slug:"troubleshooting",link:"#troubleshooting",children:[]},{level:2,title:"Browser Dialer",slug:"browser-dialer",link:"#browser-dialer",children:[]},{level:2,title:"Protocol details",slug:"protocol-details",link:"#protocol-details",children:[]}],path:"/en/config/transports/splithttp.html",pathLocale:"/en/",extraFields:[]},{title:"TCP",headers:[{level:2,title:"TcpObject",slug:"tcpobject",link:"#tcpobject",children:[{level:3,title:"NoneHeaderObject",slug:"noneheaderobject",link:"#noneheaderobject",children:[]},{level:3,title:"HttpHeaderObject",slug:"httpheaderobject",link:"#httpheaderobject",children:[]}]}],path:"/en/config/transports/tcp.html",pathLocale:"/en/",extraFields:[]},{title:"WebSocket",headers:[{level:2,title:"WebSocketObject",slug:"websocketobject",link:"#websocketobject",children:[]},{level:2,title:"Browser Dialer",slug:"browser-dialer",link:"#browser-dialer",children:[]}],path:"/en/config/transports/websocket.html",pathLocale:"/en/",extraFields:[]},{title:"Compile the document",headers:[{level:2,title:"Preparatory Work",slug:"preparatory-work",link:"#preparatory-work",children:[]},{level:2,title:"Pull Xray source code",slug:"pull-xray-source-code",link:"#pull-xray-source-code",children:[]},{level:2,title:"Build Binary",slug:"build-binary",link:"#build-binary",children:[{level:3,title:"Windows(Powershell):",slug:"windows-powershell",link:"#windows-powershell",children:[]},{level:3,title:"macOS, Linux:",slug:"macos-linux",link:"#macos-linux",children:[]}]},{level:2,title:"Reproducible Build:",slug:"reproducible-build",link:"#reproducible-build",children:[]}],path:"/en/development/intro/compile.html",pathLocale:"/en/",extraFields:[]},{title:"Design Objectives",headers:[{level:2,title:"Architecture",slug:"architecture",link:"#architecture",children:[{level:3,title:"Application Layer",slug:"application-layer",link:"#application-layer",children:[]},{level:3,title:"Proxy Layer",slug:"proxy-layer",link:"#proxy-layer",children:[]},{level:3,title:"Transport Layer",slug:"transport-layer",link:"#transport-layer",children:[]}]}],path:"/en/development/intro/design.html",pathLocale:"/en/",extraFields:[]},{title:"Development Standards",headers:[{level:2,title:"Basic",slug:"basic",link:"#basic",children:[{level:3,title:"Version Control",slug:"version-control",link:"#version-control",children:[]},{level:3,title:"Branch",slug:"branch",link:"#branch",children:[]},{level:3,title:"Release",slug:"release",link:"#release",children:[]},{level:3,title:"Citing other projects",slug:"citing-other-projects",link:"#citing-other-projects",children:[]}]},{level:2,title:"Development Process",slug:"development-process",link:"#development-process",children:[{level:3,title:"Before Writing Code",slug:"before-writing-code",link:"#before-writing-code",children:[]},{level:3,title:"Modify the code",slug:"modify-the-code",link:"#modify-the-code",children:[]},{level:3,title:"Pull Request",slug:"pull-request",link:"#pull-request",children:[]},{level:3,title:"Modifying Code",slug:"modifying-code",link:"#modifying-code",children:[]}]},{level:2,title:"Xray Coding Guidelines",slug:"xray-coding-guidelines",link:"#xray-coding-guidelines",children:[{level:3,title:"Code Structure",slug:"code-structure",link:"#code-structure",children:[]},{level:3,title:"Coding Standards",slug:"coding-standards",link:"#coding-standards",children:[]}]}],path:"/en/development/intro/guide.html",pathLocale:"/en/",extraFields:[]},{title:"mKCP Protocol",headers:[{level:2,title:"Version",slug:"version",link:"#version",children:[]},{level:2,title:"Dependencies",slug:"dependencies",link:"#dependencies",children:[{level:3,title:"Underlying Protocol",slug:"underlying-protocol",link:"#underlying-protocol",children:[]},{level:3,title:"Functions",slug:"functions",link:"#functions",children:[]}]},{level:2,title:"Communication Process",slug:"communication-process",link:"#communication-process",children:[]},{level:2,title:"Data Format",slug:"data-format",link:"#data-format",children:[{level:3,title:"Data Packet",slug:"data-packet",link:"#data-packet",children:[]},{level:3,title:"Data snippet",slug:"data-snippet",link:"#data-snippet",children:[]},{level:3,title:"Confirmation snippet",slug:"confirmation-snippet",link:"#confirmation-snippet",children:[]},{level:3,title:"Heartbeat Fragments",slug:"heartbeat-fragments",link:"#heartbeat-fragments",children:[]}]}],path:"/en/development/protocols/mkcp.html",pathLocale:"/en/",extraFields:[]},{title:"Mux.Cool Protocol",headers:[{level:2,title:"Version",slug:"version",link:"#version",children:[]},{level:2,title:"Dependencies",slug:"dependencies",link:"#dependencies",children:[{level:3,title:"Underlying Protocol",slug:"underlying-protocol",link:"#underlying-protocol",children:[]}]},{level:2,title:"Communication Process",slug:"communication-process",link:"#communication-process",children:[{level:3,title:"Client behavior",slug:"client-behavior",link:"#client-behavior",children:[]},{level:3,title:"Server-side behavior",slug:"server-side-behavior",link:"#server-side-behavior",children:[]}]},{level:2,title:"Data Format",slug:"data-format",link:"#data-format",children:[{level:3,title:"Frame Format",slug:"frame-format",link:"#frame-format",children:[]},{level:3,title:"Metadata",slug:"metadata",link:"#metadata",children:[]},{level:3,title:"New Sublink (New)",slug:"new-sublink-new",link:"#new-sublink-new",children:[]},{level:3,title:"Keep sub-connections",slug:"keep-sub-connections",link:"#keep-sub-connections",children:[]},{level:3,title:"End",slug:"end",link:"#end",children:[]},{level:3,title:"KeepAlive",slug:"keepalive",link:"#keepalive",children:[]}]},{level:2,title:"Application",slug:"application",link:"#application",children:[]}],path:"/en/development/protocols/muxcool.html",pathLocale:"/en/",extraFields:[]},{title:"VLESS Protocol",headers:[{level:2,title:"Request & Response",slug:"request-response",link:"#request-response",children:[]},{level:2,title:"ProtoBuf",slug:"protobuf",link:"#protobuf",children:[]},{level:2,title:"Flow",slug:"flow",link:"#flow",children:[{level:3,title:"Flow Control (Formerly Traffic Scheduler)",slug:"flow-control-formerly-traffic-scheduler",link:"#flow-control-formerly-traffic-scheduler",children:[]}]},{level:2,title:"Encryption",slug:"encryption",link:"#encryption",children:[]},{level:2,title:"UDP issues",slug:"udp-issues",link:"#udp-issues",children:[]},{level:2,title:"Client Development Guide",slug:"client-development-guide",link:"#client-development-guide",children:[]},{level:2,title:"VLESS Sharing Link Standard",slug:"vless-sharing-link-standard",link:"#vless-sharing-link-standard",children:[]}],path:"/en/development/protocols/vless.html",pathLocale:"/en/",extraFields:[]},{title:"VMess Protocol",headers:[{level:2,title:"Version",slug:"version",link:"#version",children:[]},{level:2,title:"Dependencies",slug:"dependencies",link:"#dependencies",children:[{level:3,title:"Underlying Protocol",slug:"underlying-protocol",link:"#underlying-protocol",children:[]},{level:3,title:"User ID",slug:"user-id",link:"#user-id",children:[]},{level:3,title:"Functions",slug:"functions",link:"#functions",children:[]}]},{level:2,title:"Communication Process",slug:"communication-process",link:"#communication-process",children:[]},{level:2,title:"Client Request",slug:"client-request",link:"#client-request",children:[{level:3,title:"Authentication Information",slug:"authentication-information",link:"#authentication-information",children:[]},{level:3,title:"Command Section",slug:"command-section",link:"#command-section",children:[]},{level:3,title:"Data Section",slug:"data-section",link:"#data-section",children:[]}]},{level:2,title:"Server Response",slug:"server-response",link:"#server-response",children:[{level:3,title:"Dynamic Port Instructions",slug:"dynamic-port-instructions",link:"#dynamic-port-instructions",children:[]}]},{level:2,title:"Comment",slug:"comment",link:"#comment",children:[]}],path:"/en/development/protocols/vmess.html",pathLocale:"/en/",extraFields:[]},{title:"Plain and Simple Language",headers:[],path:"/en/document/level-0/",pathLocale:"/en/",extraFields:[]},{title:"[Chapter 1] Simple and Plain Language",headers:[{level:2,title:"1.1 Who is this document written for?",slug:"_1-1-who-is-this-document-written-for",link:"#_1-1-who-is-this-document-written-for",children:[]},{level:2,title:"1.2 Who is this document not written for?",slug:"_1-2-who-is-this-document-not-written-for",link:"#_1-2-who-is-this-document-not-written-for",children:[]},{level:2,title:"1.3 Declaration and Other Statements",slug:"_1-3-declaration-and-other-statements",link:"#_1-3-declaration-and-other-statements",children:[]},{level:2,title:"1.4 Why is self-hosting a challenge?",slug:"_1-4-why-is-self-hosting-a-challenge",link:"#_1-4-why-is-self-hosting-a-challenge",children:[]},{level:2,title:'1.5 "Why not just use the airport?"',slug:"_1-5-why-not-just-use-the-airport",link:"#_1-5-why-not-just-use-the-airport",children:[]},{level:2,title:"1.6 So should you build your own website?",slug:"_1-6-so-should-you-build-your-own-website",link:"#_1-6-so-should-you-build-your-own-website",children:[]},{level:2,title:"1.7 Some digressions",slug:"_1-7-some-digressions",link:"#_1-7-some-digressions",children:[]},{level:2,title:"1.8 Your Progress",slug:"_1-8-your-progress",link:"#_1-8-your-progress",children:[]}],path:"/en/document/level-0/ch01-preface.html",pathLocale:"/en/",extraFields:[]},{title:"[Chapter 2] Preparation of Raw Materials",headers:[{level:2,title:"2.1 Acquiring a VPS",slug:"_2-1-acquiring-a-vps",link:"#_2-1-acquiring-a-vps",children:[]},{level:2,title:"2.2 Obtaining a Desired Domain Name",slug:"_2-2-obtaining-a-desired-domain-name",link:"#_2-2-obtaining-a-desired-domain-name",children:[]},{level:2,title:"2.3 Software you need to install on your local computer",slug:"_2-3-software-you-need-to-install-on-your-local-computer",link:"#_2-3-software-you-need-to-install-on-your-local-computer",children:[]},{level:2,title:"2.4 Your Progress",slug:"_2-4-your-progress",link:"#_2-4-your-progress",children:[]}],path:"/en/document/level-0/ch02-preparation.html",pathLocale:"/en/",extraFields:[]},{title:"[Chapter 3] Remote Login",headers:[{level:2,title:"3.1 Remote Login to VPS (PuTTY)",slug:"_3-1-remote-login-to-vps-putty",link:"#_3-1-remote-login-to-vps-putty",children:[]},{level:2,title:"3.2 Successfully Logging in SSH! Introduction to Command Line Interface!",slug:"_3-2-successfully-logging-in-ssh-introduction-to-command-line-interface",link:"#_3-2-successfully-logging-in-ssh-introduction-to-command-line-interface",children:[]},{level:2,title:"3.3 Updating software on Linux for the first time!",slug:"_3-3-updating-software-on-linux-for-the-first-time",link:"#_3-3-updating-software-on-linux-for-the-first-time",children:[]},{level:2,title:"3.4 Your Progress",slug:"_3-4-your-progress",link:"#_3-4-your-progress",children:[]}],path:"/en/document/level-0/ch03-ssh.html",pathLocale:"/en/",extraFields:[]},{title:"[Chapter 4] Security and Protection",headers:[{level:2,title:"4.1 Why Do We Need Security Protection?",slug:"_4-1-why-do-we-need-security-protection",link:"#_4-1-why-do-we-need-security-protection",children:[]},{level:2,title:"4.2 What are the specific risks",slug:"_4-2-what-are-the-specific-risks",link:"#_4-2-what-are-the-specific-risks",children:[]},{level:2,title:"4.3 What security measures do we need to take",slug:"_4-3-what-security-measures-do-we-need-to-take",link:"#_4-3-what-security-measures-do-we-need-to-take",children:[]},{level:2,title:"4.4 Change the SSH Remote Login Port to a Non-22 Port",slug:"_4-4-change-the-ssh-remote-login-port-to-a-non-22-port",link:"#_4-4-change-the-ssh-remote-login-port-to-a-non-22-port",children:[]},{level:2,title:"4.5 Creating a New User Without Root Access",slug:"_4-5-creating-a-new-user-without-root-access",link:"#_4-5-creating-a-new-user-without-root-access",children:[]},{level:2,title:"4.8 Your Progress",slug:"_4-8-your-progress",link:"#_4-8-your-progress",children:[]}],path:"/en/document/level-0/ch04-security.html",pathLocale:"/en/",extraFields:[]},{title:"Chapter 5: Website Building",headers:[{level:2,title:"5.1 Why should you create a website?",slug:"_5-1-why-should-you-create-a-website",link:"#_5-1-why-should-you-create-a-website",children:[]},{level:2,title:"5.2 Log in to VPS, install and run Nginx",slug:"_5-2-log-in-to-vps-install-and-run-nginx",link:"#_5-2-log-in-to-vps-install-and-run-nginx",children:[]},{level:2,title:"5.3 Create the simplest web page",slug:"_5-3-create-the-simplest-web-page",link:"#_5-3-create-the-simplest-web-page",children:[]},{level:2,title:"5.4 Common error explanations",slug:"_5-4-common-error-explanations",link:"#_5-4-common-error-explanations",children:[]}],path:"/en/document/level-0/ch05-webpage.html",pathLocale:"/en/",extraFields:[]},{title:"[Chapter 6] Certificate Management",headers:[{level:2,title:"6.1 Applying for a TLS Certificate",slug:"_6-1-applying-for-a-tls-certificate",link:"#_6-1-applying-for-a-tls-certificate",children:[]},{level:2,title:"6.2 Install acme.sh",slug:"_6-2-install-acme-sh",link:"#_6-2-install-acme-sh",children:[]},{level:2,title:"6.3 Testing Certificate Application",slug:"_6-3-testing-certificate-application",link:"#_6-3-testing-certificate-application",children:[]},{level:2,title:"6.5 Certificate Installation",slug:"_6-5-certificate-installation",link:"#_6-5-certificate-installation",children:[]},{level:2,title:"6.6 Your Progress",slug:"_6-6-your-progress",link:"#_6-6-your-progress",children:[]}],path:"/en/document/level-0/ch06-certificates.html",pathLocale:"/en/",extraFields:[]},{title:"[Chapter 7]Xray Server",headers:[{level:2,title:"7.1 Study broadly, Act decisively.",slug:"_7-1-study-broadly-act-decisively",link:"#_7-1-study-broadly-act-decisively",children:[]},{level:2,title:"7.2 Install Xray",slug:"_7-2-install-xray",link:"#_7-2-install-xray",children:[]},{level:2,title:"7.3 Configure TLS certificate for Xray",slug:"_7-3-configure-tls-certificate-for-xray",link:"#_7-3-configure-tls-certificate-for-xray",children:[]},{level:2,title:"7.4 Configure Xray",slug:"_7-4-configure-xray",link:"#_7-4-configure-xray",children:[]},{level:2,title:"7.5 Start Xray service! ! (and check the service status)",slug:"_7-5-start-xray-service-and-check-the-service-status",link:"#_7-5-start-xray-service-and-check-the-service-status",children:[]},{level:2,title:"7.6 Review systemd for basic service management",slug:"_7-6-review-systemd-for-basic-service-management",link:"#_7-6-review-systemd-for-basic-service-management",children:[]},{level:2,title:"7.7 Server Optimization 1: Enable BBR",slug:"_7-7-server-optimization-1-enable-bbr",link:"#_7-7-server-optimization-1-enable-bbr",children:[]},{level:2,title:"7.8 Server Optimization 2: Enable HTTP to automatically redirect to HTTPS",slug:"_7-8-server-optimization-2-enable-http-to-automatically-redirect-to-https",link:"#_7-8-server-optimization-2-enable-http-to-automatically-redirect-to-https",children:[]},{level:2,title:"7.9 Server Optimization 3: More Fallbacks",slug:"_7-9-server-optimization-3-more-fallbacks",link:"#_7-9-server-optimization-3-more-fallbacks",children:[]},{level:2,title:"7.10 Your progress",slug:"_7-10-your-progress",link:"#_7-10-your-progress",children:[]},{level:2,title:"7.11 Important errata",slug:"_7-11-important-errata",link:"#_7-11-important-errata",children:[]}],path:"/en/document/level-0/ch07-xray-server.html",pathLocale:"/en/",extraFields:[]},{title:"【第 8 章】Xray 客户端篇",headers:[{level:2,title:"8.1 Xray 的工作原理简述",slug:"_8-1-xray-的工作原理简述",link:"#_8-1-xray-的工作原理简述",children:[]},{level:2,title:"8.2 客户端与服务器端正确连接",slug:"_8-2-客户端与服务器端正确连接",link:"#_8-2-客户端与服务器端正确连接",children:[]},{level:2,title:"8.3 附加题 1:在 PC 端手工配置 xray-core",slug:"_8-3-附加题-1-在-pc-端手工配置-xray-core",link:"#_8-3-附加题-1-在-pc-端手工配置-xray-core",children:[]},{level:2,title:"8.4 附加题 2:在 PC 端手工运行 xray-core",slug:"_8-4-附加题-2-在-pc-端手工运行-xray-core",link:"#_8-4-附加题-2-在-pc-端手工运行-xray-core",children:[]},{level:2,title:"8.5 附加题 3:在 PC 端开机自动运行 xray-core",slug:"_8-5-附加题-3-在-pc-端开机自动运行-xray-core",link:"#_8-5-附加题-3-在-pc-端开机自动运行-xray-core",children:[]},{level:2,title:"8.6 圆满完成!",slug:"_8-6-圆满完成",link:"#_8-6-圆满完成",children:[]},{level:2,title:"8.7 TO INFINITY AND BEYOND!",slug:"_8-7-to-infinity-and-beyond",link:"#_8-7-to-infinity-and-beyond",children:[]}],path:"/en/document/level-0/ch08-xray-clients.html",pathLocale:"/en/",extraFields:[]},{title:"【第 9 章】附录",headers:[{level:2,title:"1. 小小白白 Linux 基础命令索引",slug:"_1-小小白白-linux-基础命令索引",link:"#_1-小小白白-linux-基础命令索引",children:[]},{level:2,title:"2. 小小白白 Linux 重要配置文件索引",slug:"_2-小小白白-linux-重要配置文件索引",link:"#_2-小小白白-linux-重要配置文件索引",children:[]},{level:2,title:"3. 小小白白 Xray 重要文件索引",slug:"_3-小小白白-xray-重要文件索引",link:"#_3-小小白白-xray-重要文件索引",children:[]}],path:"/en/document/level-0/ch09-appendix.html",pathLocale:"/en/",extraFields:[]},{title:"Beginner's Tips",headers:[],path:"/en/document/level-1/",pathLocale:"/en/",extraFields:[]},{title:"回落 (fallbacks) 功能简析",headers:[{level:2,title:"1. 回顾《小小白白话文》中的回落",slug:"_1-回顾《小小白白话文》中的回落",link:"#_1-回顾《小小白白话文》中的回落",children:[]},{level:2,title:"2. 重新认识回落 (WHAT, HOW v1)",slug:"_2-重新认识回落-what-how-v1",link:"#_2-重新认识回落-what-how-v1",children:[]},{level:2,title:"3. 为什么要回落 (WHY v1)",slug:"_3-为什么要回落-why-v1",link:"#_3-为什么要回落-why-v1",children:[]},{level:2,title:"4. 重新认识【回落の完全体】 (WHAT, WHY, HOW v2)",slug:"_4-重新认识【回落の完全体】-what-why-how-v2",link:"#_4-重新认识【回落の完全体】-what-why-how-v2",children:[]},{level:2,title:"5. 多层回落示例及解读",slug:"_5-多层回落示例及解读",link:"#_5-多层回落示例及解读",children:[{level:3,title:"5.1 首先,我将服务器端配置的 443 监听段摘抄如下:",slug:"_5-1-首先-我将服务器端配置的-443-监听段摘抄如下",link:"#_5-1-首先-我将服务器端配置的-443-监听段摘抄如下",children:[]},{level:3,title:"5.2 后续监听处理的配置段摘抄如下:",slug:"_5-2-后续监听处理的配置段摘抄如下",link:"#_5-2-后续监听处理的配置段摘抄如下",children:[]}]},{level:2,title:"6. 结语",slug:"_6-结语",link:"#_6-结语",children:[]},{level:2,title:"7. 附加题",slug:"_7-附加题",link:"#_7-附加题",children:[]}],path:"/en/document/level-1/fallbacks-lv1.html",pathLocale:"/en/",extraFields:[]},{title:"SNI fallback",headers:[{level:2,title:"Application Scenarios",slug:"application-scenarios",link:"#application-scenarios",children:[]},{level:2,title:"Introduction to SNI",slug:"introduction-to-sni",link:"#introduction-to-sni",children:[]},{level:2,title:"Idea",slug:"idea",link:"#idea",children:[]},{level:2,title:"Adding DNS Records",slug:"adding-dns-records",link:"#adding-dns-records",children:[]},{level:2,title:"Applying for TLS Certificate",slug:"applying-for-tls-certificate",link:"#applying-for-tls-certificate",children:[]},{level:2,title:"Xray Configuration",slug:"xray-configuration",link:"#xray-configuration",children:[]},{level:2,title:"Nginx Configuration",slug:"nginx-configuration",link:"#nginx-configuration",children:[]},{level:2,title:"Caddy Configuration",slug:"caddy-configuration",link:"#caddy-configuration",children:[]},{level:2,title:"Reference",slug:"reference",link:"#reference",children:[]},{level:2,title:"Quotation",slug:"quotation",link:"#quotation",children:[]}],path:"/en/document/level-1/fallbacks-with-sni.html",pathLocale:"/en/",extraFields:[]},{title:"路由 (routing) 功能简析(上)",headers:[{level:2,title:"1. 初识【路由】三兄弟",slug:"_1-初识【路由】三兄弟",link:"#_1-初识【路由】三兄弟",children:[]},{level:2,title:"2. 基本功: “兄弟一条心”",slug:"_2-基本功-兄弟一条心",link:"#_2-基本功-兄弟一条心",children:[{level:3,title:"2.1 入站",slug:"_2-1-入站",link:"#_2-1-入站",children:[]},{level:3,title:"2.3 路由",slug:"_2-3-路由",link:"#_2-3-路由",children:[]},{level:3,title:"2.4 路由配置项解析之一:流量筛选的依据",slug:"_2-4-路由配置项解析之一-流量筛选的依据",link:"#_2-4-路由配置项解析之一-流量筛选的依据",children:[]}]},{level:2,title:"3. 小试牛刀: “三分天下” 之 “域名分流”",slug:"_3-小试牛刀-三分天下-之-域名分流",link:"#_3-小试牛刀-三分天下-之-域名分流",children:[{level:3,title:"3.1 入站",slug:"_3-1-入站",link:"#_3-1-入站",children:[]},{level:3,title:"3.2 出站",slug:"_3-2-出站",link:"#_3-2-出站",children:[]},{level:3,title:"3.3 路由",slug:"_3-3-路由",link:"#_3-3-路由",children:[]},{level:3,title:"3.4 简析域名文件: geosite.dat",slug:"_3-4-简析域名文件-geosite-dat",link:"#_3-4-简析域名文件-geosite-dat",children:[]},{level:3,title:"3.5 所以 geosite.dat 到底是什么?不是有个 GFWList 吗?",slug:"_3-5-所以-geosite-dat-到底是什么-不是有个-gfwlist-吗",link:"#_3-5-所以-geosite-dat-到底是什么-不是有个-gfwlist-吗",children:[]},{level:3,title:"3.6 军师锦囊藏奇兵:一条隐藏的路由规则",slug:"_3-6-军师锦囊藏奇兵-一条隐藏的路由规则",link:"#_3-6-军师锦囊藏奇兵-一条隐藏的路由规则",children:[]},{level:3,title:"3.7 再看“三分天下”的大地图",slug:"_3-7-再看-三分天下-的大地图",link:"#_3-7-再看-三分天下-的大地图",children:[]}]},{level:2,title:"4. “三分天下” 之 “蜀魏争雄”",slug:"_4-三分天下-之-蜀魏争雄",link:"#_4-三分天下-之-蜀魏争雄",children:[]},{level:2,title:"5. 攻城略池 - 多种路由匹配条件",slug:"_5-攻城略池-多种路由匹配条件",link:"#_5-攻城略池-多种路由匹配条件",children:[]}],path:"/en/document/level-1/routing-lv1-part1.html",pathLocale:"/en/",extraFields:[]},{title:"路由 (routing) 功能简析(下)",headers:[{level:2,title:"5. 攻城略池 - 多种路由匹配条件",slug:"_5-攻城略池-多种路由匹配条件",link:"#_5-攻城略池-多种路由匹配条件",children:[{level:3,title:"5.1 基于指定域名分流:[domain], [full] 等",slug:"_5-1-基于指定域名分流-domain-full-等",link:"#_5-1-基于指定域名分流-domain-full-等",children:[]},{level:3,title:"5.2 基于 IP 文件分流:geoip.dat",slug:"_5-2-基于-ip-文件分流-geoip-dat",link:"#_5-2-基于-ip-文件分流-geoip-dat",children:[]},{level:3,title:"5.3 基于指定 IP 地址分流",slug:"_5-3-基于指定-ip-地址分流",link:"#_5-3-基于指定-ip-地址分流",children:[]},{level:3,title:"5.4 基于协议类型分流:[protocol] 等",slug:"_5-4-基于协议类型分流-protocol-等",link:"#_5-4-基于协议类型分流-protocol-等",children:[]},{level:3,title:"5.5 基于更多条件的分流",slug:"_5-5-基于更多条件的分流",link:"#_5-5-基于更多条件的分流",children:[]}]},{level:2,title:"6. “霸业初定”:路由规则整体回顾",slug:"_6-霸业初定-路由规则整体回顾",link:"#_6-霸业初定-路由规则整体回顾",children:[]},{level:2,title:"7. 路由配置常见错误",slug:"_7-路由配置常见错误",link:"#_7-路由配置常见错误",children:[{level:3,title:"7.1 错误示范",slug:"_7-1-错误示范",link:"#_7-1-错误示范",children:[]},{level:3,title:"7.2 正确示范",slug:"_7-2-正确示范",link:"#_7-2-正确示范",children:[]}]},{level:2,title:"8. 明修栈道、暗渡陈仓",slug:"_8-明修栈道、暗渡陈仓",link:"#_8-明修栈道、暗渡陈仓",children:[{level:3,title:'8.1 域名策略: "AsIs"',slug:"_8-1-域名策略-asis",link:"#_8-1-域名策略-asis",children:[]},{level:3,title:'8.2 域名策略: "IPIfNonMatch"',slug:"_8-2-域名策略-ipifnonmatch",link:"#_8-2-域名策略-ipifnonmatch",children:[]},{level:3,title:'8.3 域名策略: "IPOnDemand"',slug:"_8-3-域名策略-ipondemand",link:"#_8-3-域名策略-ipondemand",children:[]}]},{level:2,title:"9. 思考题",slug:"_9-思考题",link:"#_9-思考题",children:[]},{level:2,title:"10. 结语",slug:"_10-结语",link:"#_10-结语",children:[]},{level:2,title:"11. 尾注",slug:"_11-尾注",link:"#_11-尾注",children:[]}],path:"/en/document/level-1/routing-lv1-part2.html",pathLocale:"/en/",extraFields:[]},{title:"Xray 的工作模式",headers:[{level:2,title:"单服务器模式",slug:"单服务器模式",link:"#单服务器模式",children:[]},{level:2,title:"桥接模式",slug:"桥接模式",link:"#桥接模式",children:[]},{level:2,title:"工作原理",slug:"工作原理",link:"#工作原理",children:[]}],path:"/en/document/level-1/work.html",pathLocale:"/en/",extraFields:[]},{title:"Advanced Documentation",headers:[],path:"/en/document/level-2/",pathLocale:"/en/",extraFields:[]},{title:"Transparent proxy via GID",headers:[{level:2,title:"Ideas",slug:"ideas",link:"#ideas",children:[]},{level:2,title:"Configuration Procedure",slug:"configuration-procedure",link:"#configuration-procedure",children:[{level:3,title:"1. Preliminary preparation",slug:"_1-preliminary-preparation",link:"#_1-preliminary-preparation",children:[]},{level:3,title:"2. Add user (Android users please ignore this section)",slug:"_2-add-user-android-users-please-ignore-this-section",link:"#_2-add-user-android-users-please-ignore-this-section",children:[]},{level:3,title:"3. Configure and run Xray, and configure iptables rules",slug:"_3-configure-and-run-xray-and-configure-iptables-rules",link:"#_3-configure-and-run-xray-and-configure-iptables-rules",children:[]}]},{level:2,title:"Steps",slug:"steps",link:"#steps",children:[{level:3,title:"1. Finish Preliminary preparation and Add user",slug:"_1-finish-preliminary-preparation-and-add-user",link:"#_1-finish-preliminary-preparation-and-add-user",children:[]},{level:3,title:"2. Preparing Xray profiles",slug:"_2-preparing-xray-profiles",link:"#_2-preparing-xray-profiles",children:[]},{level:3,title:"3. Configuring the maximum number of open files and run the Xray client",slug:"_3-configuring-the-maximum-number-of-open-files-and-run-the-xray-client",link:"#_3-configuring-the-maximum-number-of-open-files-and-run-the-xray-client",children:[]},{level:3,title:"4. Setting up iptables rules",slug:"_4-setting-up-iptables-rules",link:"#_4-setting-up-iptables-rules",children:[]}]}],path:"/en/document/level-2/iptables_gid.html",pathLocale:"/en/",extraFields:[]},{title:"Nginx 或 Haproxy 搭建 TLS 隧道隐藏指纹",headers:[{level:2,title:"编译 nginx --with-stream",slug:"编译-nginx-with-stream",link:"#编译-nginx-with-stream",children:[]},{level:2,title:"配置 nginx",slug:"配置-nginx",link:"#配置-nginx",children:[]},{level:2,title:"xray 配置",slug:"xray-配置",link:"#xray-配置",children:[]},{level:2,title:"客户端及服务端启动服务",slug:"客户端及服务端启动服务",link:"#客户端及服务端启动服务",children:[]},{level:2,title:"结束",slug:"结束",link:"#结束",children:[]},{level:2,title:"HTTPS 隧道",slug:"https-隧道",link:"#https-隧道",children:[{level:3,title:"haproxy_client 配置 (运行前去掉注释)",slug:"haproxy-client-配置-运行前去掉注释",link:"#haproxy-client-配置-运行前去掉注释",children:[]},{level:3,title:"haproxy_server 配置 (运行前去掉注释)",slug:"haproxy-server-配置-运行前去掉注释",link:"#haproxy-server-配置-运行前去掉注释",children:[]},{level:3,title:"xray 配置",slug:"xray-配置-1",link:"#xray-配置-1",children:[]}]},{level:2,title:"WebSocket over HTTP/2",slug:"websocket-over-http-2",link:"#websocket-over-http-2",children:[{level:3,title:"haproxy_client 配置",slug:"haproxy-client-配置",link:"#haproxy-client-配置",children:[]},{level:3,title:"haproxy_server 配置",slug:"haproxy-server-配置",link:"#haproxy-server-配置",children:[]},{level:3,title:"xray 配置",slug:"xray-配置-2",link:"#xray-配置-2",children:[]}]},{level:2,title:"gRPC over HTTP/2",slug:"grpc-over-http-2",link:"#grpc-over-http-2",children:[{level:3,title:"haproxy_client 配置",slug:"haproxy-client-配置-1",link:"#haproxy-client-配置-1",children:[]},{level:3,title:"haproxy_server 配置",slug:"haproxy-server-配置-1",link:"#haproxy-server-配置-1",children:[]},{level:3,title:"xray 配置",slug:"xray-配置-3",link:"#xray-配置-3",children:[]},{level:3,title:"haproxy_client 配置",slug:"haproxy-client-配置-2",link:"#haproxy-client-配置-2",children:[]},{level:3,title:"haproxy_server 配置",slug:"haproxy-server-配置-2",link:"#haproxy-server-配置-2",children:[]},{level:3,title:"xray 配置",slug:"xray-配置-4",link:"#xray-配置-4",children:[]}]}],path:"/en/document/level-2/nginx_or_haproxy_tls_tunnel.html",pathLocale:"/en/",extraFields:[]},{title:"出站流量重定向",headers:[{level:2,title:"前言",slug:"前言",link:"#前言",children:[]},{level:2,title:"1、安装代理或者 VPN 软件(例如 Wireguard、IPsec 等)",slug:"_1、安装代理或者-vpn-软件-例如-wireguard、ipsec-等",link:"#_1、安装代理或者-vpn-软件-例如-wireguard、ipsec-等",children:[]},{level:2,title:"2、编辑 VPN 配置文件(以 WireGuard 为例)",slug:"_2、编辑-vpn-配置文件-以-wireguard-为例",link:"#_2、编辑-vpn-配置文件-以-wireguard-为例",children:[]},{level:2,title:"3、启用 WireGuard 网络接口",slug:"_3、启用-wireguard-网络接口",link:"#_3、启用-wireguard-网络接口",children:[]},{level:2,title:"4、Xray-core 配置文件修改",slug:"_4、xray-core-配置文件修改",link:"#_4、xray-core-配置文件修改",children:[]},{level:2,title:"5、系统设置配置",slug:"_5、系统设置配置",link:"#_5、系统设置配置",children:[]},{level:2,title:"6、完成 WireGuard 相关设置",slug:"_6、完成-wireguard-相关设置",link:"#_6、完成-wireguard-相关设置",children:[]},{level:2,title:"后记",slug:"后记",link:"#后记",children:[]},{level:2,title:"感谢",slug:"感谢",link:"#感谢",children:[]}],path:"/en/document/level-2/redirect.html",pathLocale:"/en/",extraFields:[]},{title:"TProxy 透明代理",headers:[{level:2,title:"开始之前",slug:"开始之前",link:"#开始之前",children:[]},{level:2,title:"Xray 配置",slug:"xray-配置",link:"#xray-配置",children:[]},{level:2,title:"策略路由配置",slug:"策略路由配置",link:"#策略路由配置",children:[]},{level:2,title:"Netfilter 配置",slug:"netfilter-配置",link:"#netfilter-配置",children:[]},{level:2,title:"配置永久化与开机自启",slug:"配置永久化与开机自启",link:"#配置永久化与开机自启",children:[]}],path:"/en/document/level-2/tproxy.html",pathLocale:"/en/",extraFields:[]},{title:"TProxy 透明代理 (ipv4 and ipv6)",headers:[{level:2,title:"Xray 配置",slug:"xray-配置",link:"#xray-配置",children:[{level:3,title:"客户端配置",slug:"客户端配置",link:"#客户端配置",children:[]},{level:3,title:"服务端配置",slug:"服务端配置",link:"#服务端配置",children:[]}]},{level:2,title:"Netfilter 配置",slug:"netfilter-配置",link:"#netfilter-配置",children:[{level:3,title:"首先设置策略路由",slug:"首先设置策略路由",link:"#首先设置策略路由",children:[]},{level:3,title:"使用 iptables",slug:"使用-iptables",link:"#使用-iptables",children:[]},{level:3,title:"使用 nftables",slug:"使用-nftables",link:"#使用-nftables",children:[]},{level:3,title:"开机自动运行 Netfilter 配置",slug:"开机自动运行-netfilter-配置",link:"#开机自动运行-netfilter-配置",children:[]}]},{level:2,title:"局域网设备上网设置",slug:"局域网设备上网设置",link:"#局域网设备上网设置",children:[{level:3,title:"方法一",slug:"方法一",link:"#方法一",children:[]},{level:3,title:"方法二",slug:"方法二",link:"#方法二",children:[]}]},{level:2,title:"Finally",slug:"finally",link:"#finally",children:[]},{level:2,title:"写在最后",slug:"写在最后",link:"#写在最后",children:[]}],path:"/en/document/level-2/tproxy_ipv4_and_ipv6.html",pathLocale:"/en/",extraFields:[]},{title:"流量统计",headers:[{level:2,title:"查看流量信息",slug:"查看流量信息",link:"#查看流量信息",children:[]},{level:2,title:"流量信息的处理",slug:"流量信息的处理",link:"#流量信息的处理",children:[]}],path:"/en/document/level-2/traffic_stats.html",pathLocale:"/en/",extraFields:[]},{title:"Enhancing Proxy Security with Cloudflare Warp",headers:[{level:2,title:"Applying for a Warp Account",slug:"applying-for-a-warp-account",link:"#applying-for-a-warp-account",children:[]},{level:2,title:"Diverting inbound traffic to warp on the server side",slug:"diverting-inbound-traffic-to-warp-on-the-server-side",link:"#diverting-inbound-traffic-to-warp-on-the-server-side",children:[]},{level:2,title:"Using Warp Chain Proxy on the Client Side",slug:"using-warp-chain-proxy-on-the-client-side",link:"#using-warp-chain-proxy-on-the-client-side",children:[]}],path:"/en/document/level-2/warp.html",pathLocale:"/en/",extraFields:[]},{title:"Browser Dialer",headers:[{level:2,title:"Предыстория",slug:"предыстория",link:"#предыстория",children:[]},{level:2,title:"Конфигурация",slug:"конфигурация",link:"#конфигурация",children:[]},{level:2,title:"Внутренняя работа",slug:"внутренняя-работа",link:"#внутренняя-работа",children:[]},{level:2,title:"WebSocket",slug:"websocket",link:"#websocket",children:[]},{level:2,title:"SplitHTTP",slug:"splithttp",link:"#splithttp",children:[]}],path:"/ru/config/features/browser_dialer.html",pathLocale:"/ru/",extraFields:[]},{title:"Переменные среды",headers:[{level:2,title:"Путь к файлам ресурсов",slug:"путь-к-фаилам-ресурсов",link:"#путь-к-фаилам-ресурсов",children:[]},{level:2,title:"Расположение файла конфигурации",slug:"расположение-фаила-конфигурации",link:"#расположение-фаила-конфигурации",children:[]},{level:2,title:"Каталог с несколькими конфигурациями",slug:"каталог-с-несколькими-конфигурациями",link:"#каталог-с-несколькими-конфигурациями",children:[]}],path:"/ru/config/features/env.html",pathLocale:"/ru/",extraFields:[]},{title:"Fallback",headers:[{level:2,title:"Настройка fallbacks",slug:"настроика-fallbacks",link:"#настроика-fallbacks",children:[{level:3,title:"FallbackObject",slug:"fallbackobject",link:"#fallbackobject",children:[]},{level:3,title:"Дополнительные замечания",slug:"дополнительные-замечания",link:"#дополнительные-замечания",children:[]}]},{level:2,title:"Теория Fallbacks",slug:"теория-fallbacks",link:"#теория-fallbacks",children:[]}],path:"/ru/config/features/fallback.html",pathLocale:"/ru/",extraFields:[]},{title:"Настройка с помощью нескольких файлов",headers:[{level:2,title:"Запуск с несколькими файлами",slug:"запуск-с-несколькими-фаилами",link:"#запуск-с-несколькими-фаилами",children:[]},{level:2,title:"Правила",slug:"правила",link:"#правила",children:[{level:3,title:"Обычные объекты ({})",slug:"обычные-объекты",link:"#обычные-объекты",children:[]},{level:3,title:"Массивы ([])",slug:"массивы",link:"#массивы",children:[]}]},{level:2,title:"Пример конфигурации",slug:"пример-конфигурации",link:"#пример-конфигурации",children:[]}],path:"/ru/config/features/multiple.html",pathLocale:"/ru/",extraFields:[]},{title:"Глубокое погружение в XTLS",headers:[],path:"/ru/config/features/xtls.html",pathLocale:"/ru/",extraFields:[]},{title:"Dokodemo-Door",headers:[{level:2,title:"InboundConfigurationObject",slug:"inboundconfigurationobject",link:"#inboundconfigurationobject",children:[]},{level:2,title:"Использование",slug:"использование",link:"#использование",children:[]},{level:2,title:"Пример настройки прозрачного прокси",slug:"пример-настроики-прозрачного-прокси",link:"#пример-настроики-прозрачного-прокси",children:[]}],path:"/ru/config/inbounds/dokodemo.html",pathLocale:"/ru/",extraFields:[]},{title:"HTTP",headers:[{level:2,title:"InboundConfigurationObject",slug:"inboundconfigurationobject",link:"#inboundconfigurationobject",children:[{level:3,title:"AccountObject",slug:"accountobject",link:"#accountobject",children:[]}]}],path:"/ru/config/inbounds/http.html",pathLocale:"/ru/",extraFields:[]},{title:"Shadowsocks",headers:[{level:2,title:"InboundConfigurationObject",slug:"inboundconfigurationobject",link:"#inboundconfigurationobject",children:[]},{level:2,title:"ClientObject",slug:"clientobject",link:"#clientobject",children:[]}],path:"/ru/config/inbounds/shadowsocks.html",pathLocale:"/ru/",extraFields:[]},{title:"Socks",headers:[{level:2,title:"InboundConfigurationObject",slug:"inboundconfigurationobject",link:"#inboundconfigurationobject",children:[{level:3,title:"AccountObject",slug:"accountobject",link:"#accountobject",children:[]}]}],path:"/ru/config/inbounds/socks.html",pathLocale:"/ru/",extraFields:[]},{title:"Trojan",headers:[{level:2,title:"InboundConfigurationObject",slug:"inboundconfigurationobject",link:"#inboundconfigurationobject",children:[{level:3,title:"ClientObject",slug:"clientobject",link:"#clientobject",children:[]}]}],path:"/ru/config/inbounds/trojan.html",pathLocale:"/ru/",extraFields:[]},{title:"VLESS",headers:[{level:2,title:"InboundConfigurationObject",slug:"inboundconfigurationobject",link:"#inboundconfigurationobject",children:[{level:3,title:"ClientObject",slug:"clientobject",link:"#clientobject",children:[]}]}],path:"/ru/config/inbounds/vless.html",pathLocale:"/ru/",extraFields:[]},{title:"VMess",headers:[{level:2,title:"InboundConfigurationObject",slug:"inboundconfigurationobject",link:"#inboundconfigurationobject",children:[{level:3,title:"ClientObject",slug:"clientobject",link:"#clientobject",children:[]}]}],path:"/ru/config/inbounds/vmess.html",pathLocale:"/ru/",extraFields:[]},{title:"Wireguard",headers:[{level:2,title:"InboundConfigurationObject",slug:"inboundconfigurationobject",link:"#inboundconfigurationobject",children:[{level:3,title:"Peers",slug:"peers",link:"#peers",children:[]}]}],path:"/ru/config/inbounds/wireguard.html",pathLocale:"/ru/",extraFields:[]},{title:"Blackhole",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[{level:3,title:"ResponseObject",slug:"responseobject",link:"#responseobject",children:[]}]}],path:"/ru/config/outbounds/blackhole.html",pathLocale:"/ru/",extraFields:[]},{title:"DNS",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[]},{level:2,title:"Пример настройки DNS",slug:"пример-настроики-dns",link:"#пример-настроики-dns",children:[]}],path:"/ru/config/outbounds/dns.html",pathLocale:"/ru/",extraFields:[]},{title:"Freedom",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[]}],path:"/ru/config/outbounds/freedom.html",pathLocale:"/ru/",extraFields:[]},{title:"HTTP",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[{level:3,title:"ServerObject",slug:"serverobject",link:"#serverobject",children:[]}]}],path:"/ru/config/outbounds/http.html",pathLocale:"/ru/",extraFields:[]},{title:"Loopback",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[{level:3,title:"Как использовать?",slug:"как-использовать",link:"#как-использовать",children:[]}]}],path:"/ru/config/outbounds/loopback.html",pathLocale:"/ru/",extraFields:[]},{title:"Shadowsocks",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[{level:3,title:"ServerObject",slug:"serverobject",link:"#serverobject",children:[]}]}],path:"/ru/config/outbounds/shadowsocks.html",pathLocale:"/ru/",extraFields:[]},{title:"Socks",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[{level:3,title:"ServerObject",slug:"serverobject",link:"#serverobject",children:[]}]}],path:"/ru/config/outbounds/socks.html",pathLocale:"/ru/",extraFields:[]},{title:"Trojan",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[{level:3,title:"ServerObject",slug:"serverobject",link:"#serverobject",children:[]}]}],path:"/ru/config/outbounds/trojan.html",pathLocale:"/ru/",extraFields:[]},{title:"VLESS",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[{level:3,title:"ServerObject",slug:"serverobject",link:"#serverobject",children:[]},{level:3,title:"UserObject",slug:"userobject",link:"#userobject",children:[]}]}],path:"/ru/config/outbounds/vless.html",pathLocale:"/ru/",extraFields:[]},{title:"VMess",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[{level:3,title:"ServerObject",slug:"serverobject",link:"#serverobject",children:[]}]}],path:"/ru/config/outbounds/vmess.html",pathLocale:"/ru/",extraFields:[]},{title:"WireGuard",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[{level:3,title:"Peers",slug:"peers",link:"#peers",children:[]}]}],path:"/ru/config/outbounds/wireguard.html",pathLocale:"/ru/",extraFields:[]},{title:"gRPC",headers:[{level:2,title:"GRPCObject",slug:"grpcobject",link:"#grpcobject",children:[]}],path:"/ru/config/transports/grpc.html",pathLocale:"/ru/",extraFields:[]},{title:"HTTP/2",headers:[{level:2,title:"HttpObject",slug:"httpobject",link:"#httpobject",children:[]}],path:"/ru/config/transports/h2.html",pathLocale:"/ru/",extraFields:[]},{title:"HTTPUpgrade",headers:[{level:2,title:"HttpUpgradeObject",slug:"httpupgradeobject",link:"#httpupgradeobject",children:[]}],path:"/ru/config/transports/httpupgrade.html",pathLocale:"/ru/",extraFields:[]},{title:"mKCP",headers:[{level:2,title:"KcpObject",slug:"kcpobject",link:"#kcpobject",children:[{level:3,title:"HeaderObject",slug:"headerobject",link:"#headerobject",children:[]}]},{level:2,title:"Благодарности",slug:"благодарности",link:"#благодарности",children:[]},{level:2,title:"Улучшения протокола KCP",slug:"улучшения-протокола-kcp",link:"#улучшения-протокола-kcp",children:[{level:3,title:"Более компактный заголовок протокола",slug:"более-компактныи-заголовок-протокола",link:"#более-компактныи-заголовок-протокола",children:[]},{level:3,title:"Передача пакетов подтверждения",slug:"передача-пакетов-подтверждения",link:"#передача-пакетов-подтверждения",children:[]},{level:3,title:"Управление состоянием соединения",slug:"управление-состоянием-соединения",link:"#управление-состоянием-соединения",children:[]}]}],path:"/ru/config/transports/mkcp.html",pathLocale:"/ru/",extraFields:[]},{title:"SplitHTTP",headers:[{level:2,title:"SplitHttpObject",slug:"splithttpobject",link:"#splithttpobject",children:[]},{level:2,title:"Детали протокола",slug:"детали-протокола",link:"#детали-протокола",children:[]},{level:2,title:"BrowserDialer",slug:"browserdialer",link:"#browserdialer",children:[]}],path:"/ru/config/transports/splithttp.html",pathLocale:"/ru/",extraFields:[]},{title:"TCP",headers:[{level:2,title:"TcpObject",slug:"tcpobject",link:"#tcpobject",children:[{level:3,title:"NoneHeaderObject",slug:"noneheaderobject",link:"#noneheaderobject",children:[]},{level:3,title:"HttpHeaderObject",slug:"httpheaderobject",link:"#httpheaderobject",children:[]}]}],path:"/ru/config/transports/tcp.html",pathLocale:"/ru/",extraFields:[]},{title:"WebSocket",headers:[{level:2,title:"WebSocketObject",slug:"websocketobject",link:"#websocketobject",children:[]},{level:2,title:"Browser Dialer",slug:"browser-dialer",link:"#browser-dialer",children:[]}],path:"/ru/config/transports/websocket.html",pathLocale:"/ru/",extraFields:[]},{title:"编译文档",headers:[{level:2,title:"前序工作",slug:"前序工作",link:"#前序工作",children:[]},{level:2,title:"拉取 Xray 源代码",slug:"拉取-xray-源代码",link:"#拉取-xray-源代码",children:[]},{level:2,title:"构建二进制",slug:"构建二进制",link:"#构建二进制",children:[{level:3,title:"Windows(Powershell):",slug:"windows-powershell",link:"#windows-powershell",children:[]},{level:3,title:"macOS, Linux:",slug:"macos-linux",link:"#macos-linux",children:[]}]},{level:2,title:"交叉编译:",slug:"交叉编译",link:"#交叉编译",children:[]},{level:2,title:"可复现构建:",slug:"可复现构建",link:"#可复现构建",children:[]}],path:"/ru/development/intro/compile.html",pathLocale:"/ru/",extraFields:[]},{title:"设计目标",headers:[{level:2,title:"架构",slug:"架构",link:"#架构",children:[{level:3,title:"应用层",slug:"应用层",link:"#应用层",children:[]},{level:3,title:"代理层",slug:"代理层",link:"#代理层",children:[]},{level:3,title:"传输层",slug:"传输层",link:"#传输层",children:[]}]}],path:"/ru/development/intro/design.html",pathLocale:"/ru/",extraFields:[]},{title:"开发规范",headers:[{level:2,title:"基本",slug:"基本",link:"#基本",children:[{level:3,title:"版本控制",slug:"版本控制",link:"#版本控制",children:[]},{level:3,title:"分支(Branch)",slug:"分支-branch",link:"#分支-branch",children:[]},{level:3,title:"发布(Release)",slug:"发布-release",link:"#发布-release",children:[]},{level:3,title:"引用其它项目",slug:"引用其它项目",link:"#引用其它项目",children:[]}]},{level:2,title:"开发流程",slug:"开发流程",link:"#开发流程",children:[{level:3,title:"写代码之前",slug:"写代码之前",link:"#写代码之前",children:[]},{level:3,title:"修改代码",slug:"修改代码",link:"#修改代码",children:[]},{level:3,title:"Pull Request",slug:"pull-request",link:"#pull-request",children:[]},{level:3,title:"对代码的修改",slug:"对代码的修改",link:"#对代码的修改",children:[]}]},{level:2,title:"Xray 编码规范",slug:"xray-编码规范",link:"#xray-编码规范",children:[{level:3,title:"代码结构",slug:"代码结构",link:"#代码结构",children:[]},{level:3,title:"编码规范",slug:"编码规范",link:"#编码规范",children:[]}]}],path:"/ru/development/intro/guide.html",pathLocale:"/ru/",extraFields:[]},{title:"mKCP 协议",headers:[{level:2,title:"版本",slug:"版本",link:"#版本",children:[]},{level:2,title:"依赖",slug:"依赖",link:"#依赖",children:[{level:3,title:"底层协议",slug:"底层协议",link:"#底层协议",children:[]},{level:3,title:"函数",slug:"函数",link:"#函数",children:[]}]},{level:2,title:"通讯过程",slug:"通讯过程",link:"#通讯过程",children:[]},{level:2,title:"数据格式",slug:"数据格式",link:"#数据格式",children:[{level:3,title:"数据包",slug:"数据包",link:"#数据包",children:[]},{level:3,title:"数据片段",slug:"数据片段",link:"#数据片段",children:[]},{level:3,title:"确认片段",slug:"确认片段",link:"#确认片段",children:[]},{level:3,title:"心跳片段",slug:"心跳片段",link:"#心跳片段",children:[]}]}],path:"/ru/development/protocols/mkcp.html",pathLocale:"/ru/",extraFields:[]},{title:"Mux.Cool 协议",headers:[{level:2,title:"版本",slug:"版本",link:"#版本",children:[]},{level:2,title:"依赖",slug:"依赖",link:"#依赖",children:[{level:3,title:"底层协议",slug:"底层协议",link:"#底层协议",children:[]}]},{level:2,title:"通讯过程",slug:"通讯过程",link:"#通讯过程",children:[{level:3,title:"客户端行为",slug:"客户端行为",link:"#客户端行为",children:[]},{level:3,title:"服务器端行为",slug:"服务器端行为",link:"#服务器端行为",children:[]}]},{level:2,title:"传输格式",slug:"传输格式",link:"#传输格式",children:[{level:3,title:"帧格式",slug:"帧格式",link:"#帧格式",children:[]},{level:3,title:"元数据",slug:"元数据",link:"#元数据",children:[]},{level:3,title:"新建子连接 (New)",slug:"新建子连接-new",link:"#新建子连接-new",children:[]},{level:3,title:"保持子连接 (Keep)",slug:"保持子连接-keep",link:"#保持子连接-keep",children:[]},{level:3,title:"关闭子连接 (End)",slug:"关闭子连接-end",link:"#关闭子连接-end",children:[]},{level:3,title:"保持连接 (KeepAlive)",slug:"保持连接-keepalive",link:"#保持连接-keepalive",children:[]}]},{level:2,title:"应用",slug:"应用",link:"#应用",children:[]}],path:"/ru/development/protocols/muxcool.html",pathLocale:"/ru/",extraFields:[]},{title:"VLESS 协议",headers:[{level:2,title:"Request & Response",slug:"request-response",link:"#request-response",children:[]},{level:2,title:"ProtoBuf",slug:"protobuf",link:"#protobuf",children:[]},{level:2,title:"Schedulers Flow",slug:"schedulers-flow",link:"#schedulers-flow",children:[]},{level:2,title:"Encryption",slug:"encryption",link:"#encryption",children:[]},{level:2,title:"UDP issues",slug:"udp-issues",link:"#udp-issues",children:[]},{level:2,title:"客户端开发指引",slug:"客户端开发指引",link:"#客户端开发指引",children:[]},{level:2,title:"VLESS 分享链接标准",slug:"vless-分享链接标准",link:"#vless-分享链接标准",children:[]}],path:"/ru/development/protocols/vless.html",pathLocale:"/ru/",extraFields:[]},{title:"VMess 协议",headers:[{level:2,title:"版本",slug:"版本",link:"#版本",children:[]},{level:2,title:"依赖",slug:"依赖",link:"#依赖",children:[{level:3,title:"底层协议",slug:"底层协议",link:"#底层协议",children:[]},{level:3,title:"用户 ID",slug:"用户-id",link:"#用户-id",children:[]},{level:3,title:"函数",slug:"函数",link:"#函数",children:[]}]},{level:2,title:"通讯过程",slug:"通讯过程",link:"#通讯过程",children:[]},{level:2,title:"客户端请求",slug:"客户端请求",link:"#客户端请求",children:[{level:3,title:"认证信息",slug:"认证信息",link:"#认证信息",children:[]},{level:3,title:"指令部分",slug:"指令部分",link:"#指令部分",children:[]},{level:3,title:"数据部分",slug:"数据部分",link:"#数据部分",children:[]}]},{level:2,title:"服务器应答",slug:"服务器应答",link:"#服务器应答",children:[{level:3,title:"动态端口指令",slug:"动态端口指令",link:"#动态端口指令",children:[]}]},{level:2,title:"注释",slug:"注释",link:"#注释",children:[]}],path:"/ru/development/protocols/vmess.html",pathLocale:"/ru/",extraFields:[]},{title:"Простые разговоры о сложном",headers:[],path:"/ru/document/level-0/",pathLocale:"/ru/",extraFields:[]},{title:"【Глава 1】 Простыми словами",headers:[{level:2,title:"1.1 Для кого эта документация?",slug:"_1-1-для-кого-эта-документация",link:"#_1-1-для-кого-эта-документация",children:[]},{level:2,title:"1.2 Для кого эта документация не предназначена?",slug:"_1-2-для-кого-эта-документация-не-предназначена",link:"#_1-2-для-кого-эта-документация-не-предназначена",children:[]},{level:2,title:"1.3 Важное замечание и другие примечания",slug:"_1-3-важное-замечание-и-другие-примечания",link:"#_1-3-важное-замечание-и-другие-примечания",children:[]},{level:2,title:"1.4 Почему самостоятельная настройка — это сложно?",slug:"_1-4-почему-самостоятельная-настроика-—-это-сложно",link:"#_1-4-почему-самостоятельная-настроика-—-это-сложно",children:[]},{level:2,title:"1.5 «Почему бы просто не пользоваться платным VPN?»",slug:"_1-5-«почему-бы-просто-не-пользоваться-платным-vpn-»",link:"#_1-5-«почему-бы-просто-не-пользоваться-платным-vpn-»",children:[]},{level:2,title:"1.6 Так стоит ли настраивать VPN самостоятельно?",slug:"_1-6-так-стоит-ли-настраивать-vpn-самостоятельно",link:"#_1-6-так-стоит-ли-настраивать-vpn-самостоятельно",children:[]},{level:2,title:"1.7 Немного лирики",slug:"_1-7-немного-лирики",link:"#_1-7-немного-лирики",children:[]},{level:2,title:"1.8 Ваш прогресс",slug:"_1-8-ваш-прогресс",link:"#_1-8-ваш-прогресс",children:[]}],path:"/ru/document/level-0/ch01-preface.html",pathLocale:"/ru/",extraFields:[]},{title:"【Глава 2】 Подготовка",headers:[{level:2,title:"2.1 Приобретение VPS",slug:"_2-1-приобретение-vps",link:"#_2-1-приобретение-vps",children:[]},{level:2,title:"2.2 Выбор доменного имени",slug:"_2-2-выбор-доменного-имени",link:"#_2-2-выбор-доменного-имени",children:[]},{level:2,title:"2.3 Необходимое программное обеспечение",slug:"_2-3-необходимое-программное-обеспечение",link:"#_2-3-необходимое-программное-обеспечение",children:[]},{level:2,title:"2.4 Ваш прогресс",slug:"_2-4-ваш-прогресс",link:"#_2-4-ваш-прогресс",children:[]}],path:"/ru/document/level-0/ch02-preparation.html",pathLocale:"/ru/",extraFields:[]},{title:"【Глава 3】 Удалённое подключение",headers:[{level:2,title:"3.1 Удалённое подключение к VPS (PuTTY)",slug:"_3-1-удаленное-подключение-к-vps-putty",link:"#_3-1-удаленное-подключение-к-vps-putty",children:[]},{level:2,title:"3.2 Успешное подключение по SSH! Знакомство с командной строкой!",slug:"_3-2-успешное-подключение-по-ssh-знакомство-с-команднои-строкои",link:"#_3-2-успешное-подключение-по-ssh-знакомство-с-команднои-строкои",children:[]},{level:2,title:"3.3 Первое обновление программного обеспечения Linux!",slug:"_3-3-первое-обновление-программного-обеспечения-linux",link:"#_3-3-первое-обновление-программного-обеспечения-linux",children:[]},{level:2,title:"3.4 Ваш прогресс",slug:"_3-4-ваш-прогресс",link:"#_3-4-ваш-прогресс",children:[]}],path:"/ru/document/level-0/ch03-ssh.html",pathLocale:"/ru/",extraFields:[]},{title:"【Глава 4】 Обеспечение безопасности",headers:[{level:2,title:"4.1 Зачем нужна безопасность?",slug:"_4-1-зачем-нужна-безопасность",link:"#_4-1-зачем-нужна-безопасность",children:[]},{level:2,title:"4.2 Какие именно риски существуют?",slug:"_4-2-какие-именно-риски-существуют",link:"#_4-2-какие-именно-риски-существуют",children:[]},{level:2,title:"4.3 Какие меры безопасности нужно предпринять?",slug:"_4-3-какие-меры-безопасности-нужно-предпринять",link:"#_4-3-какие-меры-безопасности-нужно-предпринять",children:[]},{level:2,title:"4.4 Изменение порта SSH",slug:"_4-4-изменение-порта-ssh",link:"#_4-4-изменение-порта-ssh",children:[]},{level:2,title:"4.5 Создание нового пользователя",slug:"_4-5-создание-нового-пользователя",link:"#_4-5-создание-нового-пользователя",children:[]},{level:2,title:"4.6 Запрет удалённого подключения по SSH для пользователя root",slug:"_4-6-запрет-удаленного-подключения-по-ssh-для-пользователя-root",link:"#_4-6-запрет-удаленного-подключения-по-ssh-для-пользователя-root",children:[]},{level:2,title:"4.7 Настройка аутентификации по SSH-ключам и запрет аутентификации по паролю",slug:"_4-7-настроика-аутентификации-по-ssh-ключам-и-запрет-аутентификации-по-паролю",link:"#_4-7-настроика-аутентификации-по-ssh-ключам-и-запрет-аутентификации-по-паролю",children:[]},{level:2,title:"4.8 Ваш прогресс",slug:"_4-8-ваш-прогресс",link:"#_4-8-ваш-прогресс",children:[]}],path:"/ru/document/level-0/ch04-security.html",pathLocale:"/ru/",extraFields:[]},{title:"【Глава 5】 Создание веб-сайта",headers:[{level:2,title:"5.1 Зачем нужен веб-сайт?",slug:"_5-1-зачем-нужен-веб-саит",link:"#_5-1-зачем-нужен-веб-саит",children:[]},{level:2,title:"5.2 Подключение к VPS и установка Nginx",slug:"_5-2-подключение-к-vps-и-установка-nginx",link:"#_5-2-подключение-к-vps-и-установка-nginx",children:[]},{level:2,title:"5.3 Создание простой веб-страницы",slug:"_5-3-создание-простои-веб-страницы",link:"#_5-3-создание-простои-веб-страницы",children:[]},{level:2,title:"5.4 Распространённые ошибки",slug:"_5-4-распространенные-ошибки",link:"#_5-4-распространенные-ошибки",children:[]},{level:2,title:"5.5 Ваш прогресс",slug:"_5-5-ваш-прогресс",link:"#_5-5-ваш-прогресс",children:[]}],path:"/ru/document/level-0/ch05-webpage.html",pathLocale:"/ru/",extraFields:[]},{title:"【Глава 6】 Управление сертификатами",headers:[{level:2,title:"6.1 Получение SSL-сертификата",slug:"_6-1-получение-ssl-сертификата",link:"#_6-1-получение-ssl-сертификата",children:[]},{level:2,title:"6.2 Установка acme.sh",slug:"_6-2-установка-acme-sh",link:"#_6-2-установка-acme-sh",children:[]},{level:2,title:"6.3 Тестовый запрос сертификата",slug:"_6-3-тестовыи-запрос-сертификата",link:"#_6-3-тестовыи-запрос-сертификата",children:[]},{level:2,title:"6.4 Запрос настоящего сертификата",slug:"_6-4-запрос-настоящего-сертификата",link:"#_6-4-запрос-настоящего-сертификата",children:[]},{level:2,title:"6.5 Установка сертификата",slug:"_6-5-установка-сертификата",link:"#_6-5-установка-сертификата",children:[]},{level:2,title:"6.6 Ваш прогресс",slug:"_6-6-ваш-прогресс",link:"#_6-6-ваш-прогресс",children:[]}],path:"/ru/document/level-0/ch06-certificates.html",pathLocale:"/ru/",extraFields:[]},{title:"【Глава 7】Настройка Xray на сервере",headers:[{level:2,title:"7.1 Познать многое, усвоить нужное; копить постепенно, тратить осмотрительно",slug:"_7-1-познать-многое-усвоить-нужное-копить-постепенно-тратить-осмотрительно",link:"#_7-1-познать-многое-усвоить-нужное-копить-постепенно-тратить-осмотрительно",children:[]},{level:2,title:"7.2 Установка Xray",slug:"_7-2-установка-xray",link:"#_7-2-установка-xray",children:[]},{level:2,title:"7.3 Установка TLS-сертификата для Xray",slug:"_7-3-установка-tls-сертификата-для-xray",link:"#_7-3-установка-tls-сертификата-для-xray",children:[]},{level:2,title:"7.4 Настройка Xray",slug:"_7-4-настроика-xray",link:"#_7-4-настроика-xray",children:[]},{level:2,title:"7.5 Запуск Xray! (и проверка состояния сервиса)",slug:"_7-5-запуск-xray-и-проверка-состояния-сервиса",link:"#_7-5-запуск-xray-и-проверка-состояния-сервиса",children:[]},{level:2,title:"7.6 Базовое управление сервисами с помощью systemd",slug:"_7-6-базовое-управление-сервисами-с-помощью-systemd",link:"#_7-6-базовое-управление-сервисами-с-помощью-systemd",children:[]},{level:2,title:"7.7 Оптимизация сервера: включение BBR",slug:"_7-7-оптимизация-сервера-включение-bbr",link:"#_7-7-оптимизация-сервера-включение-bbr",children:[]},{level:2,title:"7.8 Оптимизация сервера: автоматическое перенаправление HTTP на HTTPS",slug:"_7-8-оптимизация-сервера-автоматическое-перенаправление-http-на-https",link:"#_7-8-оптимизация-сервера-автоматическое-перенаправление-http-на-https",children:[]},{level:2,title:"7.9 Оптимизация сервера: более гибкая настройка перенаправления",slug:"_7-9-оптимизация-сервера-более-гибкая-настроика-перенаправления",link:"#_7-9-оптимизация-сервера-более-гибкая-настроика-перенаправления",children:[]},{level:2,title:"7.10 Ваши успехи",slug:"_7-10-ваши-успехи",link:"#_7-10-ваши-успехи",children:[]},{level:2,title:"7.11 Важные исправления",slug:"_7-11-важные-исправления",link:"#_7-11-важные-исправления",children:[]}],path:"/ru/document/level-0/ch07-xray-server.html",pathLocale:"/ru/",extraFields:[]},{title:"【Глава 8】Настройка Xray на клиенте",headers:[{level:2,title:"8.1 Как работает Xray: краткое описание",slug:"_8-1-как-работает-xray-краткое-описание",link:"#_8-1-как-работает-xray-краткое-описание",children:[]},{level:2,title:"8.2 Подключение клиента к серверу",slug:"_8-2-подключение-клиента-к-серверу",link:"#_8-2-подключение-клиента-к-серверу",children:[]},{level:2,title:"8.3 Дополнительное задание 1: настройка xray-core на ПК вручную",slug:"_8-3-дополнительное-задание-1-настроика-xray-core-на-пк-вручную",link:"#_8-3-дополнительное-задание-1-настроика-xray-core-на-пк-вручную",children:[]},{level:2,title:"8.4 Дополнительное задание 2: запуск xray-core на ПК",slug:"_8-4-дополнительное-задание-2-запуск-xray-core-на-пк",link:"#_8-4-дополнительное-задание-2-запуск-xray-core-на-пк",children:[]},{level:2,title:"8.5 Дополнительное задание 3: автозапуск xray-core на ПК",slug:"_8-5-дополнительное-задание-3-автозапуск-xray-core-на-пк",link:"#_8-5-дополнительное-задание-3-автозапуск-xray-core-на-пк",children:[]},{level:2,title:"8.6 Финишная прямая!",slug:"_8-6-финишная-прямая",link:"#_8-6-финишная-прямая",children:[]},{level:2,title:"8.7 В бесконечность и далее!",slug:"_8-7-в-бесконечность-и-далее",link:"#_8-7-в-бесконечность-и-далее",children:[]}],path:"/ru/document/level-0/ch08-xray-clients.html",pathLocale:"/ru/",extraFields:[]},{title:"[Глава 9] Приложение",headers:[{level:2,title:"1. Индекс основных команд Linux для начинающих",slug:"_1-индекс-основных-команд-linux-для-начинающих",link:"#_1-индекс-основных-команд-linux-для-начинающих",children:[]},{level:2,title:"2. Индекс важных конфигурационных файлов Linux",slug:"_2-индекс-важных-конфигурационных-фаилов-linux",link:"#_2-индекс-важных-конфигурационных-фаилов-linux",children:[]},{level:2,title:"3. Индекс важных файлов Xray",slug:"_3-индекс-важных-фаилов-xray",link:"#_3-индекс-важных-фаилов-xray",children:[]}],path:"/ru/document/level-0/ch09-appendix.html",pathLocale:"/ru/",extraFields:[]},{title:"Советы для начинающих",headers:[],path:"/ru/document/level-1/",pathLocale:"/ru/",extraFields:[]},{title:"Обзор функции Fallback",headers:[{level:2,title:"1. Что такое Fallback в простых словах",slug:"_1-что-такое-fallback-в-простых-словах",link:"#_1-что-такое-fallback-в-простых-словах",children:[]},{level:2,title:"2. Что такое Fallback (ЧТО, КАК v1)",slug:"_2-что-такое-fallback-что-как-v1",link:"#_2-что-такое-fallback-что-как-v1",children:[]},{level:2,title:"3. Зачем нужен Fallback (ЗАЧЕМ v1)",slug:"_3-зачем-нужен-fallback-зачем-v1",link:"#_3-зачем-нужен-fallback-зачем-v1",children:[]},{level:2,title:"4. Полное понимание Fallback (ЧТО, ЗАЧЕМ, КАК v2)",slug:"_4-полное-понимание-fallback-что-зачем-как-v2",link:"#_4-полное-понимание-fallback-что-зачем-как-v2",children:[]},{level:2,title:"5. Пример и описание многоуровневого fallback",slug:"_5-пример-и-описание-многоуровневого-fallback",link:"#_5-пример-и-описание-многоуровневого-fallback",children:[{level:3,title:"5.1 Сначала скопируем фрагмент конфигурации прослушивания порта 443 на стороне сервера:",slug:"_5-1-сначала-скопируем-фрагмент-конфигурации-прослушивания-порта-443-на-стороне-сервера",link:"#_5-1-сначала-скопируем-фрагмент-конфигурации-прослушивания-порта-443-на-стороне-сервера",children:[]},{level:3,title:"5.2 Фрагмент конфигурации, отвечающий за обработку fallback:",slug:"_5-2-фрагмент-конфигурации-отвечающии-за-обработку-fallback",link:"#_5-2-фрагмент-конфигурации-отвечающии-за-обработку-fallback",children:[]}]},{level:2,title:"6. Заключение",slug:"_6-заключение",link:"#_6-заключение",children:[]},{level:2,title:"7. Дополнительное задание",slug:"_7-дополнительное-задание",link:"#_7-дополнительное-задание",children:[]}],path:"/ru/document/level-1/fallbacks-lv1.html",pathLocale:"/ru/",extraFields:[]},{title:"SNI Fallback",headers:[{level:2,title:"Сценарии использования",slug:"сценарии-использования",link:"#сценарии-использования",children:[]},{level:2,title:"Что такое SNI",slug:"что-такое-sni",link:"#что-такое-sni",children:[]},{level:2,title:"Идея",slug:"идея",link:"#идея",children:[]},{level:2,title:"Добавление DNS-записей",slug:"добавление-dns-записеи",link:"#добавление-dns-записеи",children:[]},{level:2,title:"Запрос TLS-сертификата",slug:"запрос-tls-сертификата",link:"#запрос-tls-сертификата",children:[]},{level:2,title:"Конфигурация Xray",slug:"конфигурация-xray",link:"#конфигурация-xray",children:[]},{level:2,title:"Конфигурация Nginx",slug:"конфигурация-nginx",link:"#конфигурация-nginx",children:[]},{level:2,title:"Конфигурация Caddy",slug:"конфигурация-caddy",link:"#конфигурация-caddy",children:[]},{level:2,title:"Ссылки",slug:"ссылки",link:"#ссылки",children:[]},{level:2,title:"Примечания",slug:"примечания",link:"#примечания",children:[]}],path:"/ru/document/level-1/fallbacks-with-sni.html",pathLocale:"/ru/",extraFields:[]},{title:"Краткий обзор функции маршрутизации (routing) (часть 1)",headers:[{level:2,title:"1. Знакомство с тремя братьями-маршрутизаторами",slug:"_1-знакомство-с-тремя-братьями-маршрутизаторами",link:"#_1-знакомство-с-тремя-братьями-маршрутизаторами",children:[]},{level:2,title:'2. Основы: "Братья едины"',slug:"_2-основы-братья-едины",link:"#_2-основы-братья-едины",children:[{level:3,title:"2.1 Входящий трафик",slug:"_2-1-входящии-трафик",link:"#_2-1-входящии-трафик",children:[]},{level:3,title:"2.2 Исходящий трафик",slug:"_2-2-исходящии-трафик",link:"#_2-2-исходящии-трафик",children:[]},{level:3,title:"2.3 Маршрутизация",slug:"_2-3-маршрутизация",link:"#_2-3-маршрутизация",children:[]},{level:3,title:"2.4 Анализ параметров конфигурации маршрутизации: критерии фильтрации трафика",slug:"_2-4-анализ-параметров-конфигурации-маршрутизации-критерии-фильтрации-трафика",link:"#_2-4-анализ-параметров-конфигурации-маршрутизации-критерии-фильтрации-трафика",children:[]}]},{level:2,title:'3. Первые шаги: "Разделение мира на три части" - "Разделение по домену"',slug:"_3-первые-шаги-разделение-мира-на-три-части-разделение-по-домену",link:"#_3-первые-шаги-разделение-мира-на-три-части-разделение-по-домену",children:[{level:3,title:"3.1 Входящий трафик",slug:"_3-1-входящии-трафик",link:"#_3-1-входящии-трафик",children:[]},{level:3,title:"3.2 Исходящий трафик",slug:"_3-2-исходящии-трафик",link:"#_3-2-исходящии-трафик",children:[]},{level:3,title:"3.3 Маршрутизация",slug:"_3-3-маршрутизация",link:"#_3-3-маршрутизация",children:[]},{level:3,title:"3.4 Краткий обзор файла доменов: geosite.dat",slug:"_3-4-краткии-обзор-фаила-доменов-geosite-dat",link:"#_3-4-краткии-обзор-фаила-доменов-geosite-dat",children:[]},{level:3,title:"3.5 Так что же такое geosite.dat? Разве у нас нет GFWList?",slug:"_3-5-так-что-же-такое-geosite-dat-разве-у-нас-нет-gfwlist",link:"#_3-5-так-что-же-такое-geosite-dat-разве-у-нас-нет-gfwlist",children:[]},{level:3,title:"3.6 Секретное оружие: скрытое правило маршрутизации",slug:"_3-6-секретное-оружие-скрытое-правило-маршрутизации",link:"#_3-6-секретное-оружие-скрытое-правило-маршрутизации",children:[]},{level:3,title:'3.7 Снова смотрим на карту "трех царств"',slug:"_3-7-снова-смотрим-на-карту-трех-царств",link:"#_3-7-снова-смотрим-на-карту-трех-царств",children:[]}]},{level:2,title:'4. "Разделение мира на три части" - "Битва Вэй и Шу"',slug:"_4-разделение-мира-на-три-части-битва-вэи-и-шу",link:"#_4-разделение-мира-на-три-части-битва-вэи-и-шу",children:[]},{level:2,title:"5. Покорение новых высот - Различные условия сопоставления маршрутов",slug:"_5-покорение-новых-высот-различные-условия-сопоставления-маршрутов",link:"#_5-покорение-новых-высот-различные-условия-сопоставления-маршрутов",children:[]}],path:"/ru/document/level-1/routing-lv1-part1.html",pathLocale:"/ru/",extraFields:[]},{title:"Краткий обзор функции маршрутизации (routing) (часть 2)",headers:[{level:2,title:"5. Покорение новых высот - Различные условия сопоставления маршрутов",slug:"_5-покорение-новых-высот-различные-условия-сопоставления-маршрутов",link:"#_5-покорение-новых-высот-различные-условия-сопоставления-маршрутов",children:[{level:3,title:"5.1 Разделение по определенному домену: [domain], [full] и т. д.",slug:"_5-1-разделение-по-определенному-домену-domain-full-и-т-д",link:"#_5-1-разделение-по-определенному-домену-domain-full-и-т-д",children:[]},{level:3,title:"5.2 Разделение по IP-адресам из файла: geoip.dat",slug:"_5-2-разделение-по-ip-адресам-из-фаила-geoip-dat",link:"#_5-2-разделение-по-ip-адресам-из-фаила-geoip-dat",children:[]},{level:3,title:"5.3 Разделение по определенному IP-адресу",slug:"_5-3-разделение-по-определенному-ip-адресу",link:"#_5-3-разделение-по-определенному-ip-адресу",children:[]},{level:3,title:"5.4 Разделение по типу протокола: [protocol] и т. д.",slug:"_5-4-разделение-по-типу-протокола-protocol-и-т-д",link:"#_5-4-разделение-по-типу-протокола-protocol-и-т-д",children:[]},{level:3,title:"5.5 Разделение по другим критериям",slug:"_5-5-разделение-по-другим-критериям",link:"#_5-5-разделение-по-другим-критериям",children:[]}]},{level:2,title:'6. "Начало новой эры": обзор правил маршрутизации',slug:"_6-начало-новои-эры-обзор-правил-маршрутизации",link:"#_6-начало-новои-эры-обзор-правил-маршрутизации",children:[]},{level:2,title:"7. Распространенные ошибки в конфигурации маршрутизации",slug:"_7-распространенные-ошибки-в-конфигурации-маршрутизации",link:"#_7-распространенные-ошибки-в-конфигурации-маршрутизации",children:[{level:3,title:"7.1 Неправильный пример",slug:"_7-1-неправильныи-пример",link:"#_7-1-неправильныи-пример",children:[]},{level:3,title:"7.2 Правильный пример",slug:"_7-2-правильныи-пример",link:"#_7-2-правильныи-пример",children:[]}]},{level:2,title:"8. Скрытые пути",slug:"_8-скрытые-пути",link:"#_8-скрытые-пути",children:[{level:3,title:'8.1 Стратегия домена: "AsIs"',slug:"_8-1-стратегия-домена-asis",link:"#_8-1-стратегия-домена-asis",children:[]},{level:3,title:'8.2 Стратегия домена: "IPIfNonMatch"',slug:"_8-2-стратегия-домена-ipifnonmatch",link:"#_8-2-стратегия-домена-ipifnonmatch",children:[]},{level:3,title:'8.3 Стратегия домена: "IPOnDemand"',slug:"_8-3-стратегия-домена-ipondemand",link:"#_8-3-стратегия-домена-ipondemand",children:[]}]},{level:2,title:"9. Задание для размышления",slug:"_9-задание-для-размышления",link:"#_9-задание-для-размышления",children:[]},{level:2,title:"10. Заключение",slug:"_10-заключение",link:"#_10-заключение",children:[]},{level:2,title:"11. Примечания",slug:"_11-примечания",link:"#_11-примечания",children:[]}],path:"/ru/document/level-1/routing-lv1-part2.html",pathLocale:"/ru/",extraFields:[]},{title:"Режимы работы Xray",headers:[{level:2,title:"Режим одного сервера",slug:"режим-одного-сервера",link:"#режим-одного-сервера",children:[]},{level:2,title:"Режим моста",slug:"режим-моста",link:"#режим-моста",children:[]},{level:2,title:"Принцип работы",slug:"принцип-работы",link:"#принцип-работы",children:[]}],path:"/ru/document/level-1/work.html",pathLocale:"/ru/",extraFields:[]},{title:"Продвинутая документация",headers:[],path:"/ru/document/level-2/",pathLocale:"/ru/",extraFields:[]},{title:"GID Прозрачное проксирование",headers:[{level:2,title:"Идея",slug:"идея",link:"#идея",children:[]},{level:2,title:"Настройка",slug:"настроика",link:"#настроика",children:[{level:3,title:"1. Предварительная подготовка",slug:"_1-предварительная-подготовка",link:"#_1-предварительная-подготовка",children:[]},{level:3,title:"2. Добавление пользователя (пропустите для Android)",slug:"_2-добавление-пользователя-пропустите-для-android",link:"#_2-добавление-пользователя-пропустите-для-android",children:[]},{level:3,title:"3. Настройка запуска Xray и правил iptables",slug:"_3-настроика-запуска-xray-и-правил-iptables",link:"#_3-настроика-запуска-xray-и-правил-iptables",children:[]}]},{level:2,title:"Ниже приведен пример полной настройки глобального проксирования с использованием TPROXY",slug:"ниже-приведен-пример-полнои-настроики-глобального-проксирования-с-использованием-tproxy",link:"#ниже-приведен-пример-полнои-настроики-глобального-проксирования-с-использованием-tproxy",children:[{level:3,title:"1. Выполните предварительную подготовку и добавление пользователя.",slug:"_1-выполните-предварительную-подготовку-и-добавление-пользователя",link:"#_1-выполните-предварительную-подготовку-и-добавление-пользователя",children:[]},{level:3,title:"2. Подготовьте конфигурационный файл Xray.",slug:"_2-подготовьте-конфигурационныи-фаил-xray",link:"#_2-подготовьте-конфигурационныи-фаил-xray",children:[]},{level:3,title:"3. Настройка максимального количества открытых файлов и запуск клиента Xray",slug:"_3-настроика-максимального-количества-открытых-фаилов-и-запуск-клиента-xray",link:"#_3-настроика-максимального-количества-открытых-фаилов-и-запуск-клиента-xray",children:[]},{level:3,title:"4. Настройка правил iptables",slug:"_4-настроика-правил-iptables",link:"#_4-настроика-правил-iptables",children:[]}]}],path:"/ru/document/level-2/iptables_gid.html",pathLocale:"/ru/",extraFields:[]},{title:"Создание TLS-туннеля с помощью Nginx или Haproxy для скрытия отпечатков",headers:[{level:2,title:"Компиляция nginx с поддержкой --with-stream",slug:"компиляция-nginx-с-поддержкои-with-stream",link:"#компиляция-nginx-с-поддержкои-with-stream",children:[]},{level:2,title:"Настройка nginx",slug:"настроика-nginx",link:"#настроика-nginx",children:[]},{level:2,title:"Настройка Xray",slug:"настроика-xray",link:"#настроика-xray",children:[]},{level:2,title:"Запуск сервисов на клиенте и сервере",slug:"запуск-сервисов-на-клиенте-и-сервере",link:"#запуск-сервисов-на-клиенте-и-сервере",children:[]},{level:2,title:"Завершение",slug:"завершение",link:"#завершение",children:[]},{level:2,title:"HTTPS-туннель",slug:"https-туннель",link:"#https-туннель",children:[{level:3,title:"Конфигурация haproxy_client (удалите комментарии перед запуском):",slug:"конфигурация-haproxy-client-удалите-комментарии-перед-запуском",link:"#конфигурация-haproxy-client-удалите-комментарии-перед-запуском",children:[]},{level:3,title:"Конфигурация haproxy_server (удалите комментарии перед запуском):",slug:"конфигурация-haproxy-server-удалите-комментарии-перед-запуском",link:"#конфигурация-haproxy-server-удалите-комментарии-перед-запуском",children:[]},{level:3,title:"Настройка Xray",slug:"настроика-xray-1",link:"#настроика-xray-1",children:[]}]},{level:2,title:"WebSocket over HTTP/2",slug:"websocket-over-http-2",link:"#websocket-over-http-2",children:[{level:3,title:"Конфигурация haproxy_client:",slug:"конфигурация-haproxy-client",link:"#конфигурация-haproxy-client",children:[]},{level:3,title:"Конфигурация haproxy_server:",slug:"конфигурация-haproxy-server",link:"#конфигурация-haproxy-server",children:[]},{level:3,title:"Настройка Xray",slug:"настроика-xray-2",link:"#настроика-xray-2",children:[]}]},{level:2,title:"gRPC over HTTP/2",slug:"grpc-over-http-2",link:"#grpc-over-http-2",children:[{level:3,title:"Конфигурация haproxy_client:",slug:"конфигурация-haproxy-client-1",link:"#конфигурация-haproxy-client-1",children:[]},{level:3,title:"Конфигурация haproxy_server:",slug:"конфигурация-haproxy-server-1",link:"#конфигурация-haproxy-server-1",children:[]},{level:3,title:"Настройка Xray",slug:"настроика-xray-3",link:"#настроика-xray-3",children:[]},{level:3,title:"Конфигурация haproxy_client:",slug:"конфигурация-haproxy-client-2",link:"#конфигурация-haproxy-client-2",children:[]},{level:3,title:"Конфигурация haproxy_server:",slug:"конфигурация-haproxy-server-2",link:"#конфигурация-haproxy-server-2",children:[]},{level:3,title:"Настройка Xray",slug:"настроика-xray-4",link:"#настроика-xray-4",children:[]}]}],path:"/ru/document/level-2/nginx_or_haproxy_tls_tunnel.html",pathLocale:"/ru/",extraFields:[]},{title:"Перенаправление исходящего трафика",headers:[{level:2,title:"Введение",slug:"введение",link:"#введение",children:[]},{level:2,title:"1. Установите прокси-сервер или VPN-клиент (например, Wireguard, IPsec и т.д.)",slug:"_1-установите-прокси-сервер-или-vpn-клиент-например-wireguard-ipsec-и-т-д",link:"#_1-установите-прокси-сервер-или-vpn-клиент-например-wireguard-ipsec-и-т-д",children:[]},{level:2,title:"2. Отредактируйте конфигурационный файл VPN (на примере WireGuard)",slug:"_2-отредактируите-конфигурационныи-фаил-vpn-на-примере-wireguard",link:"#_2-отредактируите-конфигурационныи-фаил-vpn-на-примере-wireguard",children:[]},{level:2,title:"3. Активируйте сетевой интерфейс WireGuard.",slug:"_3-активируите-сетевои-интерфеис-wireguard",link:"#_3-активируите-сетевои-интерфеис-wireguard",children:[]},{level:2,title:"4. Измените конфигурационный файл Xray-core.",slug:"_4-измените-конфигурационныи-фаил-xray-core",link:"#_4-измените-конфигурационныи-фаил-xray-core",children:[]},{level:2,title:"5. Настройка системы",slug:"_5-настроика-системы",link:"#_5-настроика-системы",children:[]},{level:2,title:"6. Завершение настройки WireGuard",slug:"_6-завершение-настроики-wireguard",link:"#_6-завершение-настроики-wireguard",children:[]},{level:2,title:"Послесловие",slug:"послесловие",link:"#послесловие",children:[]},{level:2,title:"Благодарности",slug:"благодарности",link:"#благодарности",children:[]}],path:"/ru/document/level-2/redirect.html",pathLocale:"/ru/",extraFields:[]},{title:"Прозрачное проксирование TProxy",headers:[{level:2,title:"Перед началом работы",slug:"перед-началом-работы",link:"#перед-началом-работы",children:[]},{level:2,title:"Настройка Xray",slug:"настроика-xray",link:"#настроика-xray",children:[]},{level:2,title:"Настройка маршрутизации по политике",slug:"настроика-маршрутизации-по-политике",link:"#настроика-маршрутизации-по-политике",children:[]},{level:2,title:"Настройка Netfilter",slug:"настроика-netfilter",link:"#настроика-netfilter",children:[]},{level:2,title:"Настройка автозагрузки и сохранения конфигурации",slug:"настроика-автозагрузки-и-сохранения-конфигурации",link:"#настроика-автозагрузки-и-сохранения-конфигурации",children:[]}],path:"/ru/document/level-2/tproxy.html",pathLocale:"/ru/",extraFields:[]},{title:"Прозрачное проксирование TProxy (ipv4 и ipv6)",headers:[{level:2,title:"Настройка Xray",slug:"настроика-xray",link:"#настроика-xray",children:[{level:3,title:"Конфигурация клиента",slug:"конфигурация-клиента",link:"#конфигурация-клиента",children:[]},{level:3,title:"Конфигурация сервера",slug:"конфигурация-сервера",link:"#конфигурация-сервера",children:[]}]},{level:2,title:"Настройка Netfilter",slug:"настроика-netfilter",link:"#настроика-netfilter",children:[{level:3,title:"Настройка маршрутизации по политике",slug:"настроика-маршрутизации-по-политике",link:"#настроика-маршрутизации-по-политике",children:[]},{level:3,title:"Использование iptables",slug:"использование-iptables",link:"#использование-iptables",children:[]},{level:3,title:"Использование nftables",slug:"использование-nftables",link:"#использование-nftables",children:[]},{level:3,title:"Автоматический запуск конфигурации Netfilter при загрузке",slug:"автоматическии-запуск-конфигурации-netfilter-при-загрузке",link:"#автоматическии-запуск-конфигурации-netfilter-при-загрузке",children:[]}]},{level:2,title:"Настройка доступа к интернету на устройствах локальной сети",slug:"настроика-доступа-к-интернету-на-устроиствах-локальнои-сети",link:"#настроика-доступа-к-интернету-на-устроиствах-локальнои-сети",children:[{level:3,title:"Метод 1",slug:"метод-1",link:"#метод-1",children:[]},{level:3,title:"Метод 2",slug:"метод-2",link:"#метод-2",children:[]}]},{level:2,title:"Результаты",slug:"результаты",link:"#результаты",children:[]},{level:2,title:"Заключение",slug:"заключение",link:"#заключение",children:[]}],path:"/ru/document/level-2/tproxy_ipv4_and_ipv6.html",pathLocale:"/ru/",extraFields:[]},{title:"Статистика трафика",headers:[{level:2,title:"Просмотр статистики трафика",slug:"просмотр-статистики-трафика",link:"#просмотр-статистики-трафика",children:[]},{level:2,title:"Обработка статистики трафика",slug:"обработка-статистики-трафика",link:"#обработка-статистики-трафика",children:[]}],path:"/ru/document/level-2/traffic_stats.html",pathLocale:"/ru/",extraFields:[]},{title:"Повышение безопасности проксирования с помощью Cloudflare Warp",headers:[{level:2,title:"Создание аккаунта Warp",slug:"создание-аккаунта-warp",link:"#создание-аккаунта-warp",children:[{level:3,title:"Спасибо Cloudflare за содействие свободному интернету! Теперь вы можете бесплатно пользоваться услугами Warp. При подключении автоматически выбирается ближайший сервер.",slug:"спасибо-cloudflare-за-содеиствие-свободному-интернету-теперь-вы-можете-бесплатно-пользоваться-услугами-warp-при-подключении-автоматически-выбирается-ближаишии-сервер",link:"#спасибо-cloudflare-за-содеиствие-свободному-интернету-теперь-вы-можете-бесплатно-пользоваться-услугами-warp-при-подключении-автоматически-выбирается-ближаишии-сервер",children:[]}]},{level:2,title:"Перенаправление трафика в Китай через Warp на сервере",slug:"перенаправление-трафика-в-китаи-через-warp-на-сервере",link:"#перенаправление-трафика-в-китаи-через-warp-на-сервере",children:[]},{level:2,title:"Использование Warp в качестве прокси-сервера в цепочке на клиенте",slug:"использование-warp-в-качестве-прокси-сервера-в-цепочке-на-клиенте",link:"#использование-warp-в-качестве-прокси-сервера-в-цепочке-на-клиенте",children:[]}],path:"/ru/document/level-2/warp.html",pathLocale:"/ru/",extraFields:[]},{title:"透明代理入门",headers:[{level:2,title:"什么是透明代理",slug:"什么是透明代理",link:"#什么是透明代理",children:[]},{level:2,title:"透明代理的实现",slug:"透明代理的实现",link:"#透明代理的实现",children:[{level:3,title:"tun2socks",slug:"tun2socks",link:"#tun2socks",children:[]},{level:3,title:"iptables/nftables",slug:"iptables-nftables",link:"#iptables-nftables",children:[]}]},{level:2,title:"iptables 实现透明代理原理",slug:"iptables-实现透明代理原理",link:"#iptables-实现透明代理原理",children:[]},{level:2,title:"透明代理难在哪里",slug:"透明代理难在哪里",link:"#透明代理难在哪里",children:[]},{level:2,title:"从零开始一步步实现基于 iptables-tproxy 的透明代理",slug:"从零开始一步步实现基于-iptables-tproxy-的透明代理",link:"#从零开始一步步实现基于-iptables-tproxy-的透明代理",children:[{level:3,title:"在开始之前,你需要有一定的基础知识:",slug:"在开始之前-你需要有一定的基础知识",link:"#在开始之前-你需要有一定的基础知识",children:[]},{level:3,title:"前期准备工作",slug:"前期准备工作",link:"#前期准备工作",children:[]},{level:3,title:"首先,我们先试试做到第一阶段",slug:"首先-我们先试试做到第一阶段",link:"#首先-我们先试试做到第一阶段",children:[]},{level:3,title:"第二阶段",slug:"第二阶段",link:"#第二阶段",children:[]},{level:3,title:"第三阶段",slug:"第三阶段",link:"#第三阶段",children:[]},{level:3,title:"第四阶段",slug:"第四阶段",link:"#第四阶段",children:[]},{level:3,title:"代理 ipv6",slug:"代理-ipv6",link:"#代理-ipv6",children:[]}]}],path:"/en/document/level-2/transparent_proxy/transparent_proxy.html",pathLocale:"/en/",extraFields:[]},{title:"Другие замечания по прозрачному проксированию с помощью iptables",headers:[{level:2,title:"Погружение в прозрачное проксирование",slug:"погружение-в-прозрачное-проксирование",link:"#погружение-в-прозрачное-проксирование",children:[{level:3,title:"Что такое прозрачное проксирование?",slug:"что-такое-прозрачное-проксирование",link:"#что-такое-прозрачное-проксирование",children:[]},{level:3,title:"Реализация прозрачного проксирования",slug:"реализация-прозрачного-проксирования",link:"#реализация-прозрачного-проксирования",children:[]},{level:3,title:"tun2socks",slug:"tun2socks",link:"#tun2socks",children:[]},{level:3,title:"iptables/nftables",slug:"iptables-nftables",link:"#iptables-nftables",children:[]}]},{level:2,title:"Принцип реализации прозрачного проксирования с помощью iptables",slug:"принцип-реализации-прозрачного-проксирования-с-помощью-iptables",link:"#принцип-реализации-прозрачного-проксирования-с-помощью-iptables",children:[]},{level:2,title:"В чем сложность прозрачного проксирования?",slug:"в-чем-сложность-прозрачного-проксирования",link:"#в-чем-сложность-прозрачного-проксирования",children:[]},{level:2,title:"Пошаговая реализация прозрачного проксирования на основе iptables-tproxy с нуля",slug:"пошаговая-реализация-прозрачного-проксирования-на-основе-iptables-tproxy-с-нуля",link:"#пошаговая-реализация-прозрачного-проксирования-на-основе-iptables-tproxy-с-нуля",children:[{level:3,title:"Прежде чем начать, вам необходимо иметь базовые знания:",slug:"прежде-чем-начать-вам-необходимо-иметь-базовые-знания",link:"#прежде-чем-начать-вам-необходимо-иметь-базовые-знания",children:[]},{level:3,title:"Предварительная подготовка",slug:"предварительная-подготовка",link:"#предварительная-подготовка",children:[]},{level:3,title:"Сначала давайте попробуем достичь первого этапа",slug:"сначала-даваите-попробуем-достичь-первого-этапа",link:"#сначала-даваите-попробуем-достичь-первого-этапа",children:[]},{level:3,title:"Второй этап",slug:"второи-этап",link:"#второи-этап",children:[]},{level:3,title:"Третий этап",slug:"третии-этап",link:"#третии-этап",children:[]},{level:3,title:"Четвертый этап",slug:"четвертыи-этап",link:"#четвертыи-этап",children:[]},{level:3,title:"Проксирование IPv6",slug:"проксирование-ipv6",link:"#проксирование-ipv6",children:[]}]}],path:"/ru/document/level-2/transparent_proxy/transparent_proxy.html",pathLocale:"/ru/",extraFields:[]},{title:"",headers:[],path:"/404.html",pathLocale:"/",extraFields:[]}],J2=ge(Y2),Q2=()=>J2,Z2=({searchIndex:e,routeLocale:t,query:l,maxSuggestions:i})=>{const n=C(()=>e.value.filter(r=>r.pathLocale===t.value));return C(()=>{const r=l.value.trim().toLowerCase();if(!r)return[];const o=[],c=(a,u)=>{fo(r,[u.title])&&o.push({link:`${a.path}#${u.slug}`,title:a.title,header:u.title});for(const d of u.children){if(o.length>=i.value)return;c(a,d)}};for(const a of n.value){if(o.length>=i.value)break;if(fo(r,[a.title,...a.extraFields])){o.push({link:a.path,title:a.title});continue}for(const u of a.headers){if(o.length>=i.value)break;c(a,u)}}return o})},ef=e=>{const t=ge(0);return{focusIndex:t,focusNext:()=>{t.value{t.value>0?t.value-=1:t.value=e.value.length-1}}},tf=_e({name:"SearchBox",props:{locales:{type:Object,required:!1,default:()=>({})},hotKeys:{type:Array,required:!1,default:()=>[]},maxSuggestions:{type:Number,required:!1,default:5}},setup(e){const{locales:t,hotKeys:l,maxSuggestions:i}=Ii(e),n=bt(),r=Jl(),o=Q2(),c=ge(null),a=ge(!1),u=ge(""),d=C(()=>t.value[r.value]??{}),v=Z2({searchIndex:o,routeLocale:r,query:u,maxSuggestions:i}),{focusIndex:_,focusNext:p,focusPrev:m}=ef(v);G2({input:c,hotKeys:l});const x=C(()=>a.value&&!!v.value.length),A=()=>{x.value&&m()},D=()=>{x.value&&p()},O=b=>{if(!x.value)return;const y=v.value[b];y&&n.push(y.link).then(()=>{u.value="",_.value=0})};return()=>he("form",{class:"search-box",role:"search"},[he("input",{ref:c,type:"search",placeholder:d.value.placeholder,autocomplete:"off",spellcheck:!1,value:u.value,onFocus:()=>a.value=!0,onBlur:()=>a.value=!1,onInput:b=>u.value=b.target.value,onKeydown:b=>{switch(b.key){case"ArrowUp":{A();break}case"ArrowDown":{D();break}case"Enter":{b.preventDefault(),O(_.value);break}}}}),x.value&&he("ul",{class:"suggestions",onMouseleave:()=>_.value=-1},v.value.map(({link:b,title:y,header:H},G)=>he("li",{class:["suggestion",{focus:_.value===G}],onMouseenter:()=>_.value=G,onMousedown:()=>O(G)},he("a",{href:b,onClick:N=>N.preventDefault()},[he("span",{class:"page-title"},y),H&&he("span",{class:"page-header"},`> ${H}`)]))))])}});var lf=["s","/"],nf={"/":{placeholder:"搜索"}};const rf=nf,of=lf,sf=5,cf=Et({enhance({app:e}){e.component("SearchBox",t=>he(tf,{locales:rf,hotKeys:of,maxSuggestions:sf,...t}))}}),af={enhance:({app:e})=>{e.component("Mermaid",h(()=>s(()=>import("./Mermaid-D_ImV7ws.js"),__vite__mapDeps([])))),e.component("Tab",h(()=>s(()=>import("./Tab-BFTIeLDp.js"),__vite__mapDeps([])))),e.component("Tabs",h(()=>s(()=>import("./Tabs-2T1W4IpS.js"),__vite__mapDeps([]))))}},di=[ih,oh,dh,xh,Ph,Dh,R2,z2,cf,af],uf=[["v-8daa1a0e","/",{title:""},["/README.md"]],["v-aad48c6a","/about/news.html",{title:"大史记"},[":md"]],["v-f7496066","/development/",{title:"开发指南"},["/development/README.md"]],["v-ba934fd8","/config/",{title:"配置文件"},["/config/README.md"]],["v-41ade9da","/config/api.html",{title:"API 接口"},[":md"]],["v-83dedd38","/config/dns.html",{title:"内置 DNS 服务器"},[":md"]],["v-192a19b9","/config/fakedns.html",{title:"FakeDNS"},[":md"]],["v-7f6279d8","/config/inbound.html",{title:"入站代理"},[":md"]],["v-1d860c29","/config/log.html",{title:"日志配置"},[":md"]],["v-fbaf47ec","/config/metrics.html",{title:"Metrics"},[":md"]],["v-24956213","/config/observatory.html",{title:"连接观测"},[":md"]],["v-2367d756","/config/outbound.html",{title:"出站代理(Mux、XUDP)"},[":md"]],["v-4ebec35a","/config/policy.html",{title:"本地策略"},[":md"]],["v-31b7756a","/config/reverse.html",{title:"反向代理"},[":md"]],["v-70677432","/config/routing.html",{title:"路由"},[":md"]],["v-7e21d6ae","/config/stats.html",{title:"统计信息"},[":md"]],["v-e3dfff38","/config/transport.html",{title:"传输方式(uTLS、REALITY)"},[":md"]],["v-36b1a79b","/document/",{title:"快速入门"},["/document/README.md"]],["v-09a64f89","/document/command.html",{title:"命令参数"},[":md"]],["v-2b1adf48","/document/config.html",{title:"配置运行"},[":md"]],["v-86ee963a","/document/document.html",{title:"为 Project X 的文档贡献"},[":md"]],["v-0e5d7b39","/document/install.html",{title:"下载安装"},[":md"]],["v-2d0a870d","/en/",{title:""},["/en/README.md"]],["v-2d0ab8b3","/ru/",{title:""},["/ru/README.md"]],["v-6a9e8054","/development/intro/compile.html",{title:"编译文档"},[":md"]],["v-95e3eaea","/development/intro/design.html",{title:"设计目标"},[":md"]],["v-61e7eea6","/development/intro/guide.html",{title:"开发规范"},[":md"]],["v-6e6c37e6","/development/protocols/mkcp.html",{title:"mKCP 协议"},[":md"]],["v-13168a21","/development/protocols/muxcool.html",{title:"Mux.Cool 协议"},[":md"]],["v-5c48c82b","/development/protocols/vless.html",{title:"VLESS 协议"},[":md"]],["v-1ee591a8","/development/protocols/vmess.html",{title:"VMess 协议"},[":md"]],["v-0d714d87","/config/features/browser_dialer.html",{title:"Browser Dialer"},[":md"]],["v-0da7880a","/config/features/env.html",{title:"环境变量"},[":md"]],["v-2aeb21f9","/config/features/fallback.html",{title:"Fallback 回落"},[":md"]],["v-3acf20ea","/config/features/multiple.html",{title:"多文件配置"},[":md"]],["v-792e28f8","/config/features/xtls.html",{title:"XTLS 深度剖析"},[":md"]],["v-b50d2334","/config/inbounds/dokodemo.html",{title:"Dokodemo-Door"},[":md"]],["v-593408b0","/config/inbounds/http.html",{title:"HTTP"},[":md"]],["v-802a842a","/config/inbounds/shadowsocks.html",{title:"Shadowsocks"},[":md"]],["v-29995cea","/config/inbounds/socks.html",{title:"Socks"},[":md"]],["v-2a1b3d72","/config/inbounds/trojan.html",{title:"Trojan"},[":md"]],["v-fb92e8aa","/config/inbounds/vless.html",{title:"VLESS(XTLS Vision Seed)"},[":md"]],["v-167afaac","/config/inbounds/vmess.html",{title:"VMess"},[":md"]],["v-5588d0cc","/config/inbounds/wireguard.html",{title:"Wireguard"},[":md"]],["v-749ad71a","/config/outbounds/blackhole.html",{title:"Blackhole"},[":md"]],["v-6d39b970","/config/outbounds/dns.html",{title:"DNS"},[":md"]],["v-d76e893a","/config/outbounds/freedom.html",{title:"Freedom(fragment、noises)"},[":md"]],["v-c6b4b59e","/config/outbounds/http.html",{title:"HTTP"},[":md"]],["v-41ec0e0e","/config/outbounds/loopback.html",{title:"Loopback"},[":md"]],["v-7b293e4a","/config/outbounds/shadowsocks.html",{title:"Shadowsocks"},[":md"]],["v-15f5452a","/config/outbounds/socks.html",{title:"Socks"},[":md"]],["v-5797bdb3","/config/outbounds/trojan.html",{title:"Trojan"},[":md"]],["v-a60f016c","/config/outbounds/vless.html",{title:"VLESS(XTLS Vision Seed)"},[":md"]],["v-413cee4b","/config/outbounds/vmess.html",{title:"VMess"},[":md"]],["v-208ca3b9","/config/outbounds/wireguard.html",{title:"Wireguard"},[":md"]],["v-2877542a","/config/transports/grpc.html",{title:"gRPC"},[":md"]],["v-03a28284","/config/transports/h2.html",{title:"HTTP/2"},[":md"]],["v-04158536","/config/transports/httpupgrade.html",{title:"HTTPUpgrade"},[":md"]],["v-3167b1dd","/config/transports/mkcp.html",{title:"mKCP"},[":md"]],["v-eeea2fb0","/config/transports/splithttp.html",{title:"SplitHTTP(H2、QUIC H3)"},[":md"]],["v-33b1b709","/config/transports/tcp.html",{title:"TCP"},[":md"]],["v-1ff57bba","/config/transports/websocket.html",{title:"WebSocket"},[":md"]],["v-3f09dcfa","/document/level-0/",{title:"小小白白话文"},["/document/level-0/README.md"]],["v-fb444906","/document/level-0/ch01-preface.html",{title:"【第 1 章】 小小白白话文"},[":md"]],["v-075f3ae5","/document/level-0/ch02-preparation.html",{title:"【第 2 章】原料准备篇"},[":md"]],["v-726d0633","/document/level-0/ch03-ssh.html",{title:"【第 3 章】远程登录篇"},[":md"]],["v-430c6ab8","/document/level-0/ch04-security.html",{title:"【第 4 章】安全防护篇"},[":md"]],["v-717c6376","/document/level-0/ch05-webpage.html",{title:"【第 5 章】网站建设篇"},[":md"]],["v-278039be","/document/level-0/ch06-certificates.html",{title:"【第 6 章】证书管理篇"},[":md"]],["v-a0c7f88e","/document/level-0/ch07-xray-server.html",{title:"【第 7 章】Xray 服务器篇"},[":md"]],["v-86586ca2","/document/level-0/ch08-xray-clients.html",{title:"【第 8 章】Xray 客户端篇"},[":md"]],["v-3eb62514","/document/level-0/ch09-appendix.html",{title:"【第 9 章】附录"},[":md"]],["v-3f09dcbc","/document/level-1/",{title:"入门技巧"},["/document/level-1/README.md"]],["v-b21a2a20","/document/level-1/fallbacks-lv1.html",{title:"回落 (fallbacks) 功能简析"},[":md"]],["v-da623318","/document/level-1/fallbacks-with-sni.html",{title:"SNI 回落"},[":md"]],["v-fdd722ac","/document/level-1/routing-lv1-part1.html",{title:"路由 (routing) 功能简析(上)"},[":md"]],["v-fa6d716e","/document/level-1/routing-lv1-part2.html",{title:"路由 (routing) 功能简析(下)"},[":md"]],["v-2f29e106","/document/level-1/work.html",{title:"Xray 的工作模式"},[":md"]],["v-3f09dc7e","/document/level-2/",{title:"进阶文档"},["/document/level-2/README.md"]],["v-1c17916e","/document/level-2/iptables_gid.html",{title:"GID 透明代理"},[":md"]],["v-a001cfa6","/document/level-2/nginx_or_haproxy_tls_tunnel.html",{title:"Nginx 或 Haproxy 搭建 TLS 隧道隐藏指纹"},[":md"]],["v-46333b48","/document/level-2/redirect.html",{title:"出站流量重定向"},[":md"]],["v-338bc63e","/document/level-2/tproxy.html",{title:"TProxy 透明代理"},[":md"]],["v-d68f7d58","/document/level-2/tproxy_ipv4_and_ipv6.html",{title:"TProxy 透明代理 (ipv4 and ipv6)"},[":md"]],["v-e533e2c6","/document/level-2/traffic_stats.html",{title:"流量统计"},[":md"]],["v-1e465ab0","/document/level-2/warp.html",{title:"通过 Cloudflare Warp 增强代理安全性"},[":md"]],["v-1080fb37","/en/about/news.html",{title:"The Great Chronicles"},[":md"]],["v-317fc580","/en/config/",{title:"Configurations"},["/en/config/README.md"]],["v-45144c7f","/en/config/api.html",{title:"API Interface"},[":md"]],["v-23fbd2d0","/en/config/dns.html",{title:"Built-in DNS Server"},[":md"]],["v-2b7ec525","/en/config/fakedns.html",{title:"FakeDNS"},[":md"]],["v-5ab92300","/en/config/inbound.html",{title:"Inbound Proxy"},[":md"]],["v-f91d64d6","/en/config/log.html",{title:"Log Configuration"},[":md"]],["v-d705f114","/en/config/metrics.html",{title:"Metrics"},[":md"]],["v-5c8e777f","/en/config/observatory.html",{title:"Connection Monitoring"},[":md"]],["v-268cd669","/en/config/outbound.html",{title:"Outbound Proxies"},[":md"]],["v-4492d567","/en/config/policy.html",{title:"Local Policy"},[":md"]],["v-0d0e1e92","/en/config/reverse.html",{title:"Reverse Proxy"},[":md"]],["v-4bbe1d5a","/en/config/routing.html",{title:"Routing"},[":md"]],["v-16426d1a","/en/config/stats.html",{title:"Traffic Statistics"},[":md"]],["v-5de780d0","/en/config/transport.html",{title:"Transport"},[":md"]],["v-f88d343e","/en/development/",{title:"Development Guide"},["/en/development/README.md"]],["v-38d56a07","/en/document/",{title:"Quick Start"},["/en/document/README.md"]],["v-4d046016","/en/document/command.html",{title:"Command Parameters"},[":md"]],["v-22b35270","/en/document/config.html",{title:"Configure and Run"},[":md"]],["v-30bd7c12","/en/document/document.html",{title:"Contribute to Project X's Document"},[":md"]],["v-439608b6","/en/document/install.html",{title:"Download and Install"},[":md"]],["v-408e88d1","/ru/about/news.html",{title:"大史记"},[":md"]],["v-b1cce5cc","/ru/config/",{title:"Конфигурационный файл"},["/ru/config/README.md"]],["v-7521da19","/ru/config/api.html",{title:"API"},[":md"]],["v-5409606a","/ru/config/dns.html",{title:"Встроенный DNS-сервер"},[":md"]],["v-5877f5bf","/ru/config/fakedns.html",{title:"FakeDNS"},[":md"]],["v-00c6c1cc","/ru/config/inbound.html",{title:"Входящие подключения"},[":md"]],["v-990249a2","/ru/config/log.html",{title:"Настройка журнала"},[":md"]],["v-7d138fe0","/ru/config/metrics.html",{title:"Метрики"},[":md"]],["v-11e9cb19","/ru/config/observatory.html",{title:"Мониторинг подключений"},[":md"]],["v-ce8c8de2","/ru/config/outbound.html",{title:"Исходящие подключения"},[":md"]],["v-3dc4298d","/ru/config/policy.html",{title:"Локальные политики"},[":md"]],["v-26722151","/ru/config/reverse.html",{title:"Обратный прокси"},[":md"]],["v-071a21ed","/ru/config/routing.html",{title:"Маршрутизация"},[":md"]],["v-7922fc34","/ru/config/stats.html",{title:"Статистика"},[":md"]],["v-3156f2ea","/ru/config/transport.html",{title:"Транспорт"},[":md"]],["v-40ee4e87","/ru/development/",{title:"开发指南"},["/ru/development/README.md"]],["v-a1c899be","/ru/document/",{title:"Быстрый старт"},["/ru/document/README.md"]],["v-a6257be2","/ru/document/command.html",{title:"Командные аргументы"},[":md"]],["v-d63f95d4","/ru/document/config.html",{title:"Настройка и запуск"},[":md"]],["v-fbbfd9c6","/ru/document/document.html",{title:"Вклад в документацию Project X"},[":md"]],["v-9cb72482","/ru/document/install.html",{title:"Загрузка и установка"},[":md"]],["v-51a51d87","/document/level-2/transparent_proxy/transparent_proxy.html",{title:"透明代理入门"},[":md"]],["v-76b9a0f3","/en/config/features/browser_dialer.html",{title:"Browser Dialer"},[":md"]],["v-565dbfc4","/en/config/features/env.html",{title:"Environment Variables"},[":md"]],["v-0fbd1336","/en/config/features/fallback.html",{title:"Fallback"},[":md"]],["v-a0627812","/en/config/features/multiple.html",{title:"Multi-file configuration"},[":md"]],["v-d190d938","/en/config/features/xtls.html",{title:"Deep analysis of XTLS"},[":md"]],["v-72afc2d2","/en/config/inbounds/dokodemo.html",{title:"Dokodemo-Door"},[":md"]],["v-773d731c","/en/config/inbounds/http.html",{title:"HTTP"},[":md"]],["v-f555fc02","/en/config/inbounds/shadowsocks.html",{title:"Shadowsocks"},[":md"]],["v-e35196c2","/en/config/inbounds/socks.html",{title:"SOCKS"},[":md"]],["v-29188644","/en/config/inbounds/trojan.html",{title:"Trojan"},[":md"]],["v-255a6ebf","/en/config/inbounds/vless.html",{title:"VLESS"},[":md"]],["v-8cc24480","/en/config/inbounds/vmess.html",{title:"VMess"},[":md"]],["v-a2605ea4","/en/config/inbounds/wireguard.html",{title:"Wireguard"},[":md"]],["v-64e47ef4","/en/config/outbounds/blackhole.html",{title:"Blackhole"},[":md"]],["v-e979b848","/en/config/outbounds/dns.html",{title:"DNS"},[":md"]],["v-617f0fcf","/en/config/outbounds/freedom.html",{title:"Freedom"},[":md"]],["v-3fc98845","/en/config/outbounds/http.html",{title:"HTTP"},[":md"]],["v-1b804722","/en/config/outbounds/loopback.html",{title:"Loopback"},[":md"]],["v-63077cb6","/en/config/outbounds/shadowsocks.html",{title:"Shadowsocks"},[":md"]],["v-516476d4","/en/config/outbounds/socks.html",{title:"Socks"},[":md"]],["v-7d61a872","/en/config/outbounds/trojan.html",{title:"Trojan"},[":md"]],["v-6e50feb6","/en/config/outbounds/vless.html",{title:"VLESS"},[":md"]],["v-02956db7","/en/config/outbounds/vmess.html",{title:"VMess"},[":md"]],["v-797f8d25","/en/config/outbounds/wireguard.html",{title:"Wireguard"},[":md"]],["v-2c6058d4","/en/config/transports/grpc.html",{title:"gRPC"},[":md"]],["v-1c38292a","/en/config/transports/h2.html",{title:"HTTP/2"},[":md"]],["v-17ff144a","/en/config/transports/httpupgrade.html",{title:"HTTPUpgrade"},[":md"]],["v-1a7f9d6e","/en/config/transports/mkcp.html",{title:"mKCP"},[":md"]],["v-4df52c3c","/en/config/transports/splithttp.html",{title:"SplitHTTP"},[":md"]],["v-5254cbc6","/en/config/transports/tcp.html",{title:"TCP"},[":md"]],["v-9520f392","/en/config/transports/websocket.html",{title:"WebSocket"},[":md"]],["v-b7760e2c","/en/development/intro/compile.html",{title:"Compile the document"},[":md"]],["v-fb774212","/en/development/intro/design.html",{title:"Design Objectives"},[":md"]],["v-38c376c1","/en/development/intro/guide.html",{title:"Development Standards"},[":md"]],["v-21bccd79","/en/development/protocols/mkcp.html",{title:"mKCP Protocol"},[":md"]],["v-27001935","/en/development/protocols/muxcool.html",{title:"Mux.Cool Protocol"},[":md"]],["v-21b30c3f","/en/development/protocols/vless.html",{title:"VLESS Protocol"},[":md"]],["v-94110980","/en/development/protocols/vmess.html",{title:"VMess Protocol"},[":md"]],["v-789ba7ef","/en/document/level-0/",{title:"Plain and Simple Language"},["/en/document/level-0/README.md"]],["v-d3712ade","/en/document/level-0/ch01-preface.html",{title:"[Chapter 1] Simple and Plain Language"},[":md"]],["v-41f9c00e","/en/document/level-0/ch02-preparation.html",{title:"[Chapter 2] Preparation of Raw Materials"},[":md"]],["v-4c013f47","/en/document/level-0/ch03-ssh.html",{title:"[Chapter 3] Remote Login"},[":md"]],["v-a75683b8","/en/document/level-0/ch04-security.html",{title:"[Chapter 4] Security and Protection"},[":md"]],["v-f5341aec","/en/document/level-0/ch05-webpage.html",{title:"Chapter 5: Website Building"},[":md"]],["v-4458f72a","/en/document/level-0/ch06-certificates.html",{title:"[Chapter 6] Certificate Management"},[":md"]],["v-f1802e66","/en/document/level-0/ch07-xray-server.html",{title:"[Chapter 7]Xray Server"},[":md"]],["v-4ca6f1ca","/en/document/level-0/ch08-xray-clients.html",{title:"【第 8 章】Xray 客户端篇"},[":md"]],["v-b0030f00","/en/document/level-0/ch09-appendix.html",{title:"【第 9 章】附录"},[":md"]],["v-789ba80e","/en/document/level-1/",{title:"Beginner's Tips"},["/en/document/level-1/README.md"]],["v-103b3e5c","/en/document/level-1/fallbacks-lv1.html",{title:"回落 (fallbacks) 功能简析"},[":md"]],["v-110dd688","/en/document/level-1/fallbacks-with-sni.html",{title:"SNI fallback"},[":md"]],["v-c425a7d4","/en/document/level-1/routing-lv1-part1.html",{title:"路由 (routing) 功能简析(上)"},[":md"]],["v-c0bbf696","/en/document/level-1/routing-lv1-part2.html",{title:"路由 (routing) 功能简析(下)"},[":md"]],["v-5b6477cc","/en/document/level-1/work.html",{title:"Xray 的工作模式"},[":md"]],["v-789ba82d","/en/document/level-2/",{title:"Advanced Documentation"},["/en/document/level-2/README.md"]],["v-05ddc65d","/en/document/level-2/iptables_gid.html",{title:"Transparent proxy via GID"},[":md"]],["v-474afe99","/en/document/level-2/nginx_or_haproxy_tls_tunnel.html",{title:"Nginx 或 Haproxy 搭建 TLS 隧道隐藏指纹"},[":md"]],["v-930ac920","/en/document/level-2/redirect.html",{title:"出站流量重定向"},[":md"]],["v-c579975c","/en/document/level-2/tproxy.html",{title:"TProxy 透明代理"},[":md"]],["v-7efb7c68","/en/document/level-2/tproxy_ipv4_and_ipv6.html",{title:"TProxy 透明代理 (ipv4 and ipv6)"},[":md"]],["v-12a33bee","/en/document/level-2/traffic_stats.html",{title:"流量统计"},[":md"]],["v-7d2b8478","/en/document/level-2/warp.html",{title:"Enhancing Proxy Security with Cloudflare Warp"},[":md"]],["v-1cfb44e6","/ru/config/features/browser_dialer.html",{title:"Browser Dialer"},[":md"]],["v-6a3f8078","/ru/config/features/env.html",{title:"Переменные среды"},[":md"]],["v-74f22e7f","/ru/config/features/fallback.html",{title:"Fallback"},[":md"]],["v-2c9f7c11","/ru/config/features/multiple.html",{title:"Настройка с помощью нескольких файлов"},[":md"]],["v-630c687e","/ru/config/features/xtls.html",{title:"Глубокое погружение в XTLS"},[":md"]],["v-20ff0a28","/ru/config/inbounds/dokodemo.html",{title:"Dokodemo-Door"},[":md"]],["v-43124836","/ru/config/inbounds/http.html",{title:"HTTP"},[":md"]],["v-6a351ba5","/ru/config/inbounds/shadowsocks.html",{title:"Shadowsocks"},[":md"]],["v-3d1d02c5","/ru/config/inbounds/socks.html",{title:"Socks"},[":md"]],["v-1567b378","/ru/config/inbounds/trojan.html",{title:"Trojan"},[":md"]],["v-57bf8636","/ru/config/inbounds/vless.html",{title:"VLESS"},[":md"]],["v-6864abe6","/ru/config/inbounds/vmess.html",{title:"VMess"},[":md"]],["v-67d3c858","/ru/config/inbounds/wireguard.html",{title:"Wireguard"},[":md"]],["v-5910da20","/ru/config/outbounds/blackhole.html",{title:"Blackhole"},[":md"]],["v-5717f8f6","/ru/config/outbounds/dns.html",{title:"DNS"},[":md"]],["v-4360702e","/ru/config/outbounds/freedom.html",{title:"Freedom"},[":md"]],["v-22e1532a","/ru/config/outbounds/http.html",{title:"HTTP"},[":md"]],["v-38c69248","/ru/config/outbounds/loopback.html",{title:"Loopback"},[":md"]],["v-1a2a97d0","/ru/config/outbounds/shadowsocks.html",{title:"Shadowsocks"},[":md"]],["v-0141bb30","/ru/config/outbounds/socks.html",{title:"Socks"},[":md"]],["v-544bef26","/ru/config/outbounds/trojan.html",{title:"Trojan"},[":md"]],["v-cf761560","/ru/config/outbounds/vless.html",{title:"VLESS"},[":md"]],["v-2c896451","/ru/config/outbounds/vmess.html",{title:"VMess"},[":md"]],["v-0502a6bf","/ru/config/outbounds/wireguard.html",{title:"WireGuard"},[":md"]],["v-13c3ca30","/ru/config/transports/grpc.html",{title:"gRPC"},[":md"]],["v-2fe60378","/ru/config/transports/h2.html",{title:"HTTP/2"},[":md"]],["v-453f5c70","/ru/config/transports/httpupgrade.html",{title:"HTTPUpgrade"},[":md"]],["v-1cb427e3","/ru/config/transports/mkcp.html",{title:"mKCP"},[":md"]],["v-32d545e2","/ru/config/transports/splithttp.html",{title:"SplitHTTP"},[":md"]],["v-f4c92f7a","/ru/config/transports/tcp.html",{title:"TCP"},[":md"]],["v-cb60c046","/ru/config/transports/websocket.html",{title:"WebSocket"},[":md"]],["v-7ce977e0","/ru/development/intro/compile.html",{title:"编译文档"},[":md"]],["v-01d5d1de","/ru/development/intro/design.html",{title:"设计目标"},[":md"]],["v-4d4e5367","/ru/development/intro/guide.html",{title:"开发规范"},[":md"]],["v-a58031da","/ru/development/protocols/mkcp.html",{title:"mKCP 协议"},[":md"]],["v-5440615b","/ru/development/protocols/muxcool.html",{title:"Mux.Cool 协议"},[":md"]],["v-069325e5","/ru/development/protocols/vless.html",{title:"VLESS 协议"},[":md"]],["v-ca50d634","/ru/development/protocols/vmess.html",{title:"VMess 协议"},[":md"]],["v-490791ee","/ru/document/level-0/",{title:"Простые разговоры о сложном"},["/ru/document/level-0/README.md"]],["v-78f09a92","/ru/document/level-0/ch01-preface.html",{title:"【Глава 1】 Простыми словами"},[":md"]],["v-64f6e51f","/ru/document/level-0/ch02-preparation.html",{title:"【Глава 2】 Подготовка"},[":md"]],["v-69478a6d","/ru/document/level-0/ch03-ssh.html",{title:"【Глава 3】 Удалённое подключение"},[":md"]],["v-271d7abe","/ru/document/level-0/ch04-security.html",{title:"【Глава 4】 Обеспечение безопасности"},[":md"]],["v-9ab38aa0","/ru/document/level-0/ch05-webpage.html",{title:"【Глава 5】 Создание веб-сайта"},[":md"]],["v-7cddd6c4","/ru/document/level-0/ch06-certificates.html",{title:"【Глава 6】 Управление сертификатами"},[":md"]],["v-0d33adf3","/ru/document/level-0/ch07-xray-server.html",{title:"【Глава 7】Настройка Xray на сервере"},[":md"]],["v-123166b5","/ru/document/level-0/ch08-xray-clients.html",{title:"【Глава 8】Настройка Xray на клиенте"},[":md"]],["v-22c7351a","/ru/document/level-0/ch09-appendix.html",{title:"[Глава 9] Приложение"},[":md"]],["v-490791b0","/ru/document/level-1/",{title:"Советы для начинающих"},["/ru/document/level-1/README.md"]],["v-e9f80a14","/ru/document/level-1/fallbacks-lv1.html",{title:"Обзор функции Fallback"},[":md"]],["v-2db62ba4","/ru/document/level-1/fallbacks-with-sni.html",{title:"SNI Fallback"},[":md"]],["v-531be8a0","/ru/document/level-1/routing-lv1-part1.html",{title:"Краткий обзор функции маршрутизации (routing) (часть 1)"},[":md"]],["v-4fb23762","/ru/document/level-1/routing-lv1-part2.html",{title:"Краткий обзор функции маршрутизации (routing) (часть 2)"},[":md"]],["v-fdd8db80","/ru/document/level-1/work.html",{title:"Режимы работы Xray"},[":md"]],["v-49079172","/ru/document/level-2/",{title:"Продвинутая документация"},["/ru/document/level-2/README.md"]],["v-331e0e83","/ru/document/level-2/iptables_gid.html",{title:"GID Прозрачное проксирование"},[":md"]],["v-7418a5b3","/ru/document/level-2/nginx_or_haproxy_tls_tunnel.html",{title:"Создание TLS-туннеля с помощью Nginx или Haproxy для скрытия отпечатков"},[":md"]],["v-587e32d4","/ru/document/level-2/redirect.html",{title:"Перенаправление исходящего трафика"},[":md"]],["v-9c63de10","/ru/document/level-2/tproxy.html",{title:"Прозрачное проксирование TProxy"},[":md"]],["v-a4c782e4","/ru/document/level-2/tproxy_ipv4_and_ipv6.html",{title:"Прозрачное проксирование TProxy (ipv4 и ipv6)"},[":md"]],["v-71771ea3","/ru/document/level-2/traffic_stats.html",{title:"Статистика трафика"},[":md"]],["v-70300bea","/ru/document/level-2/warp.html",{title:"Повышение безопасности проксирования с помощью Cloudflare Warp"},[":md"]],["v-7689d7f3","/en/document/level-2/transparent_proxy/transparent_proxy.html",{title:"透明代理入门"},[":md"]],["v-39b3c50d","/ru/document/level-2/transparent_proxy/transparent_proxy.html",{title:"Другие замечания по прозрачному проксированию с помощью iptables"},[":md"]],["v-3706649a","/404.html",{title:""},[]]];var go=_e({name:"Vuepress",setup(){const e=zu();return()=>he(e.value)}}),df=()=>uf.reduce((e,[t,l,i,n])=>(e.push({name:t,path:l,component:go,meta:i},{path:l.endsWith("/")?l+"index.html":l.substring(0,l.length-5),redirect:l},...n.map(r=>({path:r===":md"?l.substring(0,l.length-5)+".md":r,redirect:l}))),e),[{name:"404",path:"/:catchAll(.*)",component:go}]),hf=Od,vf=()=>{const e=Yd({history:hf(_s("/")),routes:df(),scrollBehavior:(t,l,i)=>i||(t.hash?{el:t.hash}:{top:0})});return e.beforeResolve(async(t,l)=>{var i;(t.path!==l.path||l===_t)&&([t.meta._data]=await Promise.all([vt.resolvePageData(t.name),(i=ps[t.name])==null?void 0:i.__asyncLoader()]))}),e},_f=e=>{e.component("ClientOnly",Bn),e.component("Content",Gu)},ff=(e,t,l)=>{const i=C(()=>t.currentRoute.value.path),n=Vh(i,()=>t.currentRoute.value.meta._data),r=C(()=>vt.resolveLayouts(l)),o=C(()=>vt.resolveRouteLocale(ll.value.locales,i.value)),c=C(()=>vt.resolveSiteLocaleData(ll.value,o.value)),a=C(()=>vt.resolvePageFrontmatter(n.value)),u=C(()=>vt.resolvePageHeadTitle(n.value,c.value)),d=C(()=>vt.resolvePageHead(u.value,a.value,c.value)),v=C(()=>vt.resolvePageLang(n.value,c.value)),_=C(()=>vt.resolvePageLayout(n.value,r.value));return e.provide(Hu,r),e.provide(ms,n),e.provide(bs,a),e.provide(Bu,u),e.provide(ks,d),e.provide(Es,v),e.provide(ys,_),e.provide(Mn,o),e.provide(Ls,c),Object.defineProperties(e.config.globalProperties,{$frontmatter:{get:()=>a.value},$head:{get:()=>d.value},$headTitle:{get:()=>u.value},$lang:{get:()=>v.value},$page:{get:()=>n.value},$routeLocale:{get:()=>o.value},$site:{get:()=>ll.value},$siteLocale:{get:()=>c.value},$withBase:{get:()=>Wn}}),{layouts:r,pageData:n,pageFrontmatter:a,pageHead:d,pageHeadTitle:u,pageLang:v,pageLayout:_,routeLocale:o,siteData:ll,siteLocaleData:c}},gf=()=>{const e=$u(),t=Wu();let l=[];const i=()=>{e.value.forEach(o=>{const c=pf(o);c&&l.push(c)})},n=()=>{const o=[];return e.value.forEach(c=>{const a=mf(c);a&&o.push(a)}),o},r=()=>{document.documentElement.lang=t.value;const o=n();l.forEach((c,a)=>{const u=o.findIndex(d=>c.isEqualNode(d));u===-1?(c.remove(),delete l[a]):o.splice(u,1)}),o.forEach(c=>document.head.appendChild(c)),l=[...l.filter(c=>!!c),...o]};Kt(Xu,r),We(()=>{i(),Ge(e,r,{immediate:!1})})},pf=([e,t,l=""])=>{const i=Object.entries(t).map(([c,a])=>nt(a)?`[${c}=${JSON.stringify(a)}]`:a===!0?`[${c}]`:"").join(""),n=`head > ${e}${i}`;return Array.from(document.querySelectorAll(n)).find(c=>c.innerText===l)||null},mf=([e,t,l])=>{if(!nt(e))return null;const i=document.createElement(e);return Hn(t)&&Object.entries(t).forEach(([n,r])=>{nt(r)?i.setAttribute(n,r):r===!0&&i.setAttribute(n,"")}),nt(l)&&i.appendChild(document.createTextNode(l)),i},bf=Pu,kf=async()=>{var l;const e=bf({name:"VuepressApp",setup(){var i;gf();for(const n of di)(i=n.setup)==null||i.call(n);return()=>[he(Vs),...di.flatMap(({rootComponents:n=[]})=>n.map(r=>he(r)))]}}),t=vf();_f(e),ff(e,t,di);for(const i of di)await((l=i.enhance)==null?void 0:l.call(i,{app:e,router:t,siteData:ll}));return e.use(t),{app:e,router:t}};kf().then(({app:e,router:t})=>{t.isReady().then(()=>{e.mount("#app")})});export{ke as F,xe as _,ne as a,ce as b,ee as c,kf as createVueApp,Vt as d,$a as e,_e as f,be as g,s as h,St as i,Lo as j,fc as k,C as l,Ge as m,ge as n,W as o,We as p,Vn as q,mt as r,zl as s,Pe as t,Xt as u,Ef as v,Ce as w,Xl as x}; + */const ue={settings:{minimum:.08,easing:"ease",speed:200,trickle:!0,trickleRate:.02,trickleSpeed:800,barSelector:'[role="bar"]',parent:"body",template:'
'},status:null,set:e=>{const t=ue.isStarted();e=en(e,ue.settings.minimum,1),ue.status=e===1?null:e;const l=ue.render(!t),i=l.querySelector(ue.settings.barSelector),n=ue.settings.speed,r=ue.settings.easing;return l.offsetWidth,Lh(o=>{ci(i,{transform:"translate3d("+ro(e)+"%,0,0)",transition:"all "+n+"ms "+r}),e===1?(ci(l,{transition:"none",opacity:"1"}),l.offsetWidth,setTimeout(function(){ci(l,{transition:"all "+n+"ms linear",opacity:"0"}),setTimeout(function(){ue.remove(),o()},n)},n)):setTimeout(()=>o(),n)}),ue},isStarted:()=>typeof ue.status=="number",start:()=>{ue.status||ue.set(0);const e=()=>{setTimeout(()=>{ue.status&&(ue.trickle(),e())},ue.settings.trickleSpeed)};return ue.settings.trickle&&e(),ue},done:e=>!e&&!ue.status?ue:ue.inc(.3+.5*Math.random()).set(1),inc:e=>{let t=ue.status;return t?(typeof e!="number"&&(e=(1-t)*en(Math.random()*t,.1,.95)),t=en(t+e,0,.994),ue.set(t)):ue.start()},trickle:()=>ue.inc(Math.random()*ue.settings.trickleRate),render:e=>{if(ue.isRendered())return document.getElementById("nprogress");oo(document.documentElement,"nprogress-busy");const t=document.createElement("div");t.id="nprogress",t.innerHTML=ue.settings.template;const l=t.querySelector(ue.settings.barSelector),i=e?"-100":ro(ue.status||0),n=document.querySelector(ue.settings.parent);return ci(l,{transition:"all 0 linear",transform:"translate3d("+i+"%,0,0)"}),n!==document.body&&oo(n,"nprogress-custom-parent"),n==null||n.appendChild(t),t},remove:()=>{so(document.documentElement,"nprogress-busy"),so(document.querySelector(ue.settings.parent),"nprogress-custom-parent");const e=document.getElementById("nprogress");e&&Th(e)},isRendered:()=>!!document.getElementById("nprogress")},en=(e,t,l)=>el?l:e,ro=e=>(-1+e)*100,Lh=function(){const e=[];function t(){const l=e.shift();l&&l(t)}return function(l){e.push(l),e.length===1&&t()}}(),ci=function(){const e=["Webkit","O","Moz","ms"],t={};function l(o){return o.replace(/^-ms-/,"ms-").replace(/-([\da-z])/gi,function(c,a){return a.toUpperCase()})}function i(o){const c=document.body.style;if(o in c)return o;let a=e.length;const u=o.charAt(0).toUpperCase()+o.slice(1);let d;for(;a--;)if(d=e[a]+u,d in c)return d;return o}function n(o){return o=l(o),t[o]??(t[o]=i(o))}function r(o,c,a){c=n(c),o.style[c]=a}return function(o,c){for(const a in c){const u=c[a];u!==void 0&&Object.prototype.hasOwnProperty.call(c,a)&&r(o,a,u)}}}(),Fs=(e,t)=>(typeof e=="string"?e:Xn(e)).indexOf(" "+t+" ")>=0,oo=(e,t)=>{const l=Xn(e),i=l+t;Fs(l,t)||(e.className=i.substring(1))},so=(e,t)=>{const l=Xn(e);if(!Fs(e,t))return;const i=l.replace(" "+t+" "," ");e.className=i.substring(1,i.length-1)},Xn=e=>(" "+(e.className||"")+" ").replace(/\s+/gi," "),Th=e=>{e&&e.parentNode&&e.parentNode.removeChild(e)},Oh=()=>{We(()=>{const e=bt(),t=new Set;t.add(e.currentRoute.value.path),e.beforeEach(l=>{t.has(l.path)||ue.start()}),e.afterEach(l=>{t.add(l.path),ue.done()})})},Ph=Et({setup(){Oh()}}),Ah=JSON.parse(`{"name":"vuepress-theme-xray","smoothScroll":true,"repo":"xtls/xray-core","docsDir":"docs","docsRepo":"xtls/Xray-docs-next","docsBranch":"main","editLinks":true,"enableToggle":true,"locales":{"/":{"navbar":[{"text":"首页","link":"/"},{"text":"大史记","link":"/about/news.md"},{"text":"配置指南","link":"/config/"},{"text":"开发指南","link":"/development/"},{"text":"使用指南","link":"/document/"}],"sidebar":{"/config/":[{"text":"特性详解","children":["/config/features/xtls.md","/config/features/fallback.md","/config/features/browser_dialer.md","/config/features/env.md","/config/features/multiple.md"]},{"text":"基础配置","children":["/config/README.md","/config/log.md","/config/api.md","/config/dns.md","/config/fakedns.md","/config/inbound.md","/config/outbound.md","/config/policy.md","/config/reverse.md","/config/routing.md","/config/stats.md","/config/transport.md","/config/metrics.md","/config/observatory.md"]},{"text":"入站代理","children":["/config/inbounds/dokodemo.md","/config/inbounds/http.md","/config/inbounds/shadowsocks.md","/config/inbounds/socks.md","/config/inbounds/trojan.md","/config/inbounds/vless.md","/config/inbounds/vmess.md","/config/inbounds/wireguard.md"]},{"text":"出站代理","children":["/config/outbounds/blackhole.md","/config/outbounds/dns.md","/config/outbounds/freedom.md","/config/outbounds/http.md","/config/outbounds/loopback.md","/config/outbounds/shadowsocks.md","/config/outbounds/socks.md","/config/outbounds/trojan.md","/config/outbounds/vless.md","/config/outbounds/vmess.md","/config/outbounds/wireguard.md"]},{"text":"底层传输","children":["/config/transports/grpc.md","/config/transports/h2.md","/config/transports/mkcp.md","/config/transports/tcp.md","/config/transports/websocket.md","/config/transports/httpupgrade.md","/config/transports/splithttp.md"]}],"/document/":[{"text":"快速入门文档","children":["/document/README.md","/document/install.md","/document/config.md","/document/command.md","/document/document.md"]},{"text":"小小白白话文","children":["/document/level-0/README.md","/document/level-0/ch01-preface.md","/document/level-0/ch02-preparation.md","/document/level-0/ch03-ssh.md","/document/level-0/ch04-security.md","/document/level-0/ch05-webpage.md","/document/level-0/ch06-certificates.md","/document/level-0/ch07-xray-server.md","/document/level-0/ch08-xray-clients.md","/document/level-0/ch09-appendix.md"]},{"text":"入门技巧","children":["/document/level-1/README.md","/document/level-1/fallbacks-lv1.md","/document/level-1/routing-lv1-part1.md","/document/level-1/routing-lv1-part2.md","/document/level-1/work.md","/document/level-1/fallbacks-with-sni.md"]},{"text":"进阶技巧","children":["/document/level-2/README.md","/document/level-2/transparent_proxy/transparent_proxy.md","/document/level-2/tproxy.md","/document/level-2/tproxy_ipv4_and_ipv6.md","/document/level-2/nginx_or_haproxy_tls_tunnel.md","/document/level-2/iptables_gid.md","/document/level-2/redirect.md","/document/level-2/warp.md","/document/level-2/traffic_stats.md"]}],"/development/":[{"text":"开发指南","children":["/development/README.md","/development/intro/compile.md","/development/intro/design.md","/development/intro/guide.md"]},{"text":"协议详解","children":["/development/protocols/vless.md","/development/protocols/vmess.md","/development/protocols/muxcool.md","/development/protocols/mkcp.md"]}]},"repoLabel":"查看源码","editLinkText":"帮助我们改善此页面!","tip":"提示","warning":"注意","danger":"警告","lastUpdatedText":"最近更改","selectLanguageName":"简体中文","selectLanguageText":"🌏 简体中文 / Change language","selectLanguageAriaLabel":"简体中文 / Change language","docsDir":"docs","backToHome":"back to home","openInNewWindow":"open in new tag","toggleColorMode":"toggle color mode","toggleSidebar":"toggle side bar"},"/en/":{"sidebar":{"/en/config/":[{"text":"feature","children":["/en/config/features/xtls.md","/en/config/features/fallback.md","/en/config/features/browser_dialer.md","/en/config/features/env.md","/en/config/features/multiple.md"]},{"text":"config","children":["/en/config/README.md","/en/config/log.md","/en/config/api.md","/en/config/dns.md","/en/config/fakedns.md","/en/config/inbound.md","/en/config/outbound.md","/en/config/policy.md","/en/config/reverse.md","/en/config/routing.md","/en/config/stats.md","/en/config/transport.md","/en/config/metrics.md","/en/config/observatory.md"]},{"text":"inbound","children":["/en/config/inbounds/dokodemo.md","/en/config/inbounds/http.md","/en/config/inbounds/shadowsocks.md","/en/config/inbounds/socks.md","/en/config/inbounds/trojan.md","/en/config/inbounds/vless.md","/en/config/inbounds/vmess.md","/en/config/inbounds/wireguard.md"]},{"text":"outbound","children":["/en/config/outbounds/blackhole.md","/en/config/outbounds/dns.md","/en/config/outbounds/freedom.md","/en/config/outbounds/http.md","/en/config/outbounds/loopback.md","/en/config/outbounds/shadowsocks.md","/en/config/outbounds/socks.md","/en/config/outbounds/trojan.md","/en/config/outbounds/vless.md","/en/config/outbounds/vmess.md","/en/config/outbounds/wireguard.md"]},{"text":"transport","children":["/en/config/transports/grpc.md","/en/config/transports/h2.md","/en/config/transports/mkcp.md","/en/config/transports/tcp.md","/en/config/transports/websocket.md","/en/config/transports/httpupgrade.md","/en/config/transports/splithttp.md"]}],"/en/document/":[{"text":"Quick Start","children":["/en/document/README.md","/en/document/install.md","/en/document/config.md","/en/document/command.md","/en/document/document.md"]},{"text":"Beginner Tutorial","children":["/en/document/level-0/README.md","/en/document/level-0/ch01-preface.md","/en/document/level-0/ch02-preparation.md","/en/document/level-0/ch03-ssh.md","/en/document/level-0/ch04-security.md","/en/document/level-0/ch05-webpage.md","/en/document/level-0/ch06-certificates.md","/en/document/level-0/ch07-xray-server.md","/en/document/level-0/ch08-xray-clients.md","/en/document/level-0/ch09-appendix.md"]},{"text":"Getting Started Tips","children":["/en/document/level-1/README.md","/en/document/level-1/fallbacks-lv1.md","/en/document/level-1/routing-lv1-part1.md","/en/document/level-1/routing-lv1-part2.md","/en/document/level-1/work.md","/en/document/level-1/fallbacks-with-sni.md"]},{"text":"Advanced Documentation","children":["/en/document/level-2/README.md","/en/document/level-2/transparent_proxy/transparent_proxy.md","/en/document/level-2/tproxy.md","/en/document/level-2/tproxy_ipv4_and_ipv6.md","/en/document/level-2/nginx_or_haproxy_tls_tunnel.md","/en/document/level-2/iptables_gid.md","/en/document/level-2/redirect.md","/en/document/level-2/warp.md","/en/document/level-2/traffic_stats.md"]}],"/en/development/":[{"text":"Developer Guide","children":["/en/development/README.md","/en/development/intro/compile.md","/en/development/intro/design.md","/en/development/intro/guide.md"]},{"text":"Protocol Details","children":["/en/development/protocols/vless.md","/en/development/protocols/vmess.md","/en/development/protocols/muxcool.md","/en/development/protocols/mkcp.md"]}]},"navbar":[{"text":"Homepage","link":"/en"},{"text":"Website History","link":"/en/about/news.md"},{"text":"Config Reference","link":"/en/config/"},{"text":"Developer Guide","link":"/en/development/"},{"text":"Quick Start","link":"/en/document/"}],"selectLanguageName":"English (WIP)","selectLanguageText":"🌎 English / Change language","selectLanguageAriaLabel":"English / Change language","editLinkText":"Help us improve this page on GitHub!","lastUpdatedText":"Last Updated","contributorsText":"contributors","tip":"Tip","warning":"Warning","danger":"Danger","notFound":["这里什么都没有","我们怎么到这来了?","这是一个 404 页面","看起来我们进入了错误的链接"],"backToHome":"back to home","openInNewWindow":"open in new tag","toggleColorMode":"toggle color mode","toggleSidebar":"toggle side bar"},"/ru/":{"navbar":[{"text":"Главная","link":"/ru"},{"text":"История сайта","link":"/ru/about/news.md"},{"text":"Справочник по конфигурации","link":"/ru/config/"},{"text":"Руководство разработчика","link":"/ru/development/"},{"text":"Быстрый старт","link":"/ru/document/"}],"sidebar":{"/ru/config/":[{"text":"Описание функций","children":["/ru/config/features/xtls.md","/ru/config/features/fallback.md","/ru/config/features/browser_dialer.md","/ru/config/features/env.md","/ru/config/features/multiple.md"]},{"text":"Базовая конфигурация","children":["/ru/config/README.md","/ru/config/log.md","/ru/config/api.md","/ru/config/dns.md","/ru/config/fakedns.md","/ru/config/inbound.md","/ru/config/outbound.md","/ru/config/policy.md","/ru/config/reverse.md","/ru/config/routing.md","/ru/config/stats.md","/ru/config/transport.md","/ru/config/metrics.md","/ru/config/observatory.md"]},{"text":"Входящие подключения","children":["/ru/config/inbounds/dokodemo.md","/ru/config/inbounds/http.md","/ru/config/inbounds/shadowsocks.md","/ru/config/inbounds/socks.md","/ru/config/inbounds/trojan.md","/ru/config/inbounds/vless.md","/ru/config/inbounds/vmess.md","/ru/config/inbounds/wireguard.md"]},{"text":"Исходящие подключения","children":["/ru/config/outbounds/blackhole.md","/ru/config/outbounds/dns.md","/ru/config/outbounds/freedom.md","/ru/config/outbounds/http.md","/ru/config/outbounds/loopback.md","/ru/config/outbounds/shadowsocks.md","/ru/config/outbounds/socks.md","/ru/config/outbounds/trojan.md","/ru/config/outbounds/vless.md","/ru/config/outbounds/vmess.md","/ru/config/outbounds/wireguard.md"]},{"text":"Транспортный уровень","children":["/ru/config/transports/grpc.md","/ru/config/transports/h2.md","/ru/config/transports/mkcp.md","/ru/config/transports/tcp.md","/ru/config/transports/websocket.md","/ru/config/transports/httpupgrade.md","/ru/config/transports/splithttp.md"]}],"/ru/document/":[{"text":"Быстрый старт","children":["/ru/document/README.md","/ru/document/install.md","/ru/document/config.md","/ru/document/command.md","/ru/document/document.md"]},{"text":"Простыми словами","children":["/ru/document/level-0/README.md","/ru/document/level-0/ch01-preface.md","/ru/document/level-0/ch02-preparation.md","/ru/document/level-0/ch03-ssh.md","/ru/document/level-0/ch04-security.md","/ru/document/level-0/ch05-webpage.md","/ru/document/level-0/ch06-certificates.md","/ru/document/level-0/ch07-xray-server.md","/ru/document/level-0/ch08-xray-clients.md","/ru/document/level-0/ch09-appendix.md"]},{"text":"Базовые навыки","children":["/ru/document/level-1/README.md","/ru/document/level-1/fallbacks-lv1.md","/ru/document/level-1/routing-lv1-part1.md","/ru/document/level-1/routing-lv1-part2.md","/ru/document/level-1/work.md","/ru/document/level-1/fallbacks-with-sni.md"]},{"text":"Продвинутые навыки","children":["/ru/document/level-2/README.md","/ru/document/level-2/transparent_proxy/transparent_proxy.md","/ru/document/level-2/tproxy.md","/ru/document/level-2/tproxy_ipv4_and_ipv6.md","/ru/document/level-2/nginx_or_haproxy_tls_tunnel.md","/ru/document/level-2/iptables_gid.md","/ru/document/level-2/redirect.md","/ru/document/level-2/warp.md","/ru/document/level-2/traffic_stats.md"]}],"/ru/development/":[{"text":"Руководство разработчика","children":["/ru/development/README.md","/ru/development/intro/compile.md","/ru/development/intro/design.md","/ru/development/intro/guide.md"]},{"text":"Описание протоколов","children":["/ru/development/protocols/vless.md","/ru/development/protocols/vmess.md","/ru/development/protocols/muxcool.md","/ru/development/protocols/mkcp.md"]}]},"repoLabel":"Посмотреть исходный код","editLinkText":"Помогите нам улучшить эту страницу!","tip":"Подсказка","warning":"Внимание","danger":"Предупреждение","lastUpdatedText":"Последние изменения","selectLanguageName":"Русский (WIP)","selectLanguageText":"🌍 Русский / Change language","selectLanguageAriaLabel":"Русский / Change language","docsDir":"docs","backToHome":"На главную","openInNewWindow":"Открыть в новой вкладке","toggleColorMode":"Переключить цветовую схему","toggleSidebar":"Переключить боковую панель"},"themePlugins":{"git":true}},"colorMode":"auto","colorModeSwitch":true,"navbar":[],"logo":null,"selectLanguageText":"Languages","selectLanguageAriaLabel":"Select language","sidebar":"auto","sidebarDepth":2,"editLink":true,"editLinkText":"Edit this page","lastUpdated":true,"lastUpdatedText":"Last Updated","contributors":true,"contributorsText":"Contributors","notFound":["There's nothing here.","How did we get here?","That's a Four-Oh-Four.","Looks like we've got some broken links."],"backToHome":"Take me home","openInNewWindow":"open in new window","toggleColorMode":"toggle color mode","toggleSidebar":"toggle sidebar"}`),wh=ge(Ah),Ns=()=>wh,Hs=Symbol(""),Rh=()=>{const e=Te(Hs);if(!e)throw new Error("useThemeLocaleData() is called without provider.");return e},Ih=(e,t)=>{const{locales:l,...i}=e;return{...i,...l==null?void 0:l[t]}},Dh=Et({enhance({app:e}){const t=Ns(),l=e._context.provides[Mn],i=C(()=>Ih(t.value,l.value));e.provide(Hs,i),Object.defineProperties(e.config.globalProperties,{$theme:{get(){return t.value}},$themeLocale:{get(){return i.value}}})}}),jh=_e({__name:"Badge",props:{type:{type:String,required:!1,default:"tip"},text:{type:String,required:!1,default:""},vertical:{type:String,required:!1,default:void 0}},setup(e,{expose:t}){t();const l={};return Object.defineProperty(l,"__isScriptSetup",{enumerable:!1,value:!0}),l}}),xe=(e,t)=>{const l=e.__vccOpts||e;for(const[i,n]of t)l[i]=n;return l};function Sh(e,t,l,i,n,r){return W(),ee("span",{class:$e(["badge",l.type]),style:Wl({verticalAlign:l.vertical})},[be(e.$slots,"default",{},()=>[Vt(Pe(l.text),1)])],6)}const Ch=xe(jh,[["render",Sh],["__file","Badge.vue"]]);function Vh(e,t){let l,i,n;const r=ge(!0),o=()=>{r.value=!0,n()};Ge(e,o,{flush:"sync"});const c=typeof t=="function"?t:t.get,a=typeof t=="function"?void 0:t.set,u=Mc((d,v)=>(i=d,n=v,{get(){return r.value&&(l=c(),r.value=!1),i(),l},set(_){a==null||a(_)}}));return Object.isExtensible(u)&&(u.trigger=o),u}function Ms(e){return Lo()?(fc(e),!0):!1}function _l(e){return typeof e=="function"?e():Xt(e)}const Fh=typeof window<"u"&&typeof document<"u";typeof WorkerGlobalScope<"u"&&globalThis instanceof WorkerGlobalScope;const Nh=Object.prototype.toString,Hh=e=>Nh.call(e)==="[object Object]",Mh=()=>{};function $h(e,t){function l(...i){return new Promise((n,r)=>{Promise.resolve(e(()=>t.apply(this,i),{fn:t,thisArg:this,args:i})).then(n).catch(r)})}return l}const $s=e=>e();function Bh(e=$s){const t=ge(!0);function l(){t.value=!1}function i(){t.value=!0}const n=(...r)=>{t.value&&e(...r)};return{isActive:Ri(t),pause:l,resume:i,eventFilter:n}}function Wh(e){return Vn()}function zh(e,t,l={}){const{eventFilter:i=$s,...n}=l;return Ge(e,$h(i,t),n)}function Uh(e,t,l={}){const{eventFilter:i,...n}=l,{eventFilter:r,pause:o,resume:c,isActive:a}=Bh(i);return{stop:zh(e,t,{...n,eventFilter:r}),pause:o,resume:c,isActive:a}}function Xh(e,t=!0,l){Wh()?We(e,l):t?e():Xl(e)}function Kh(e=!1,t={}){const{truthyValue:l=!0,falsyValue:i=!1}=t,n=Ne(e),r=ge(e);function o(c){if(arguments.length)return r.value=c,r.value;{const a=_l(l);return r.value=r.value===a?_l(i):a,r.value}}return n?o:[r,o]}function qh(e){var t;const l=_l(e);return(t=l==null?void 0:l.$el)!=null?t:l}const Ti=Fh?window:void 0;function co(...e){let t,l,i,n;if(typeof e[0]=="string"||Array.isArray(e[0])?([l,i,n]=e,t=Ti):[t,l,i,n]=e,!t)return Mh;Array.isArray(l)||(l=[l]),Array.isArray(i)||(i=[i]);const r=[],o=()=>{r.forEach(d=>d()),r.length=0},c=(d,v,_,p)=>(d.addEventListener(v,_,p),()=>d.removeEventListener(v,_,p)),a=Ge(()=>[qh(t),_l(n)],([d,v])=>{if(o(),!d)return;const _=Hh(v)?{...v}:v;r.push(...l.flatMap(p=>i.map(m=>c(d,p,m,_))))},{immediate:!0,flush:"post"}),u=()=>{a(),o()};return Ms(u),u}function Gh(){const e=ge(!1),t=Vn();return t&&We(()=>{e.value=!0},t),e}function Yh(e){const t=Gh();return C(()=>(t.value,!!e()))}function Jh(e,t={}){const{window:l=Ti}=t,i=Yh(()=>l&&"matchMedia"in l&&typeof l.matchMedia=="function");let n;const r=ge(!1),o=u=>{r.value=u.matches},c=()=>{n&&("removeEventListener"in n?n.removeEventListener("change",o):n.removeListener(o))},a=ra(()=>{i.value&&(c(),n=l.matchMedia(_l(e)),"addEventListener"in n?n.addEventListener("change",o):n.addListener(o),r.value=n.matches)});return Ms(()=>{a(),c(),n=void 0}),r}const ai=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{},ui="__vueuse_ssr_handlers__",Qh=Zh();function Zh(){return ui in ai||(ai[ui]=ai[ui]||{}),ai[ui]}function ev(e,t){return Qh[e]||t}function tv(e){return e==null?"any":e instanceof Set?"set":e instanceof Map?"map":e instanceof Date?"date":typeof e=="boolean"?"boolean":typeof e=="string"?"string":typeof e=="object"?"object":Number.isNaN(e)?"any":"number"}const lv={boolean:{read:e=>e==="true",write:e=>String(e)},object:{read:e=>JSON.parse(e),write:e=>JSON.stringify(e)},number:{read:e=>Number.parseFloat(e),write:e=>String(e)},any:{read:e=>e,write:e=>String(e)},string:{read:e=>e,write:e=>String(e)},map:{read:e=>new Map(JSON.parse(e)),write:e=>JSON.stringify(Array.from(e.entries()))},set:{read:e=>new Set(JSON.parse(e)),write:e=>JSON.stringify(Array.from(e))},date:{read:e=>new Date(e),write:e=>e.toISOString()}},ao="vueuse-storage";function Bs(e,t,l,i={}){var n;const{flush:r="pre",deep:o=!0,listenToStorageChanges:c=!0,writeDefaults:a=!0,mergeDefaults:u=!1,shallow:d,window:v=Ti,eventFilter:_,onError:p=w=>{console.error(w)},initOnMounted:m}=i,x=(d?No:ge)(typeof t=="function"?t():t);if(!l)try{l=ev("getDefaultStorage",()=>{var w;return(w=Ti)==null?void 0:w.localStorage})()}catch(w){p(w)}if(!l)return x;const A=_l(t),D=tv(A),O=(n=i.serializer)!=null?n:lv[D],{pause:b,resume:y}=Uh(x,()=>G(x.value),{flush:r,deep:o,eventFilter:_});v&&c&&Xh(()=>{co(v,"storage",E),co(v,ao,K),m&&E()}),m||E();function H(w,U){v&&v.dispatchEvent(new CustomEvent(ao,{detail:{key:e,oldValue:w,newValue:U,storageArea:l}}))}function G(w){try{const U=l.getItem(e);if(w==null)H(U,null),l.removeItem(e);else{const L=O.write(w);U!==L&&(l.setItem(e,L),H(U,L))}}catch(U){p(U)}}function N(w){const U=w?w.newValue:l.getItem(e);if(U==null)return a&&A!=null&&l.setItem(e,O.write(A)),A;if(!w&&u){const L=O.read(U);return typeof u=="function"?u(L,A):D==="object"&&!Array.isArray(L)?{...A,...L}:L}else return typeof U!="string"?U:O.read(U)}function E(w){if(!(w&&w.storageArea!==l)){if(w&&w.key==null){x.value=A;return}if(!(w&&w.key!==e)){b();try{(w==null?void 0:w.newValue)!==O.write(x.value)&&(x.value=N(w))}catch(U){p(U)}finally{w?Xl(y):y()}}}}function K(w){E(w.detail)}return x}function iv(e){return Jh("(prefers-color-scheme: dark)",e)}const nv=_e({name:"CodeGroup",slots:Object,setup(e,{slots:t}){const l=ge([]),i=ge(-1),n=Bs("vuepress-code-group",{}),r=C(()=>l.value.map(u=>u.innerText).join(","));We(()=>{Ge(()=>n.value[r.value],(u=-1)=>{i.value!==u&&(i.value=u)},{immediate:!0}),Ge(i,u=>{n.value[r.value]!==u&&(n.value[r.value]=u)})});const o=(u=i.value)=>{u{u>0?i.value=u-1:i.value=l.value.length-1,l.value[i.value].focus()},a=(u,d)=>{u.key===" "||u.key==="Enter"?(u.preventDefault(),i.value=d):u.key==="ArrowRight"?(u.preventDefault(),o(d)):u.key==="ArrowLeft"&&(u.preventDefault(),c(d))};return()=>{var d;const u=(((d=t.default)==null?void 0:d.call(t))||[]).filter(v=>v.type.name==="CodeGroupItem").map(v=>(v.props===null&&(v.props={}),v));return u.length===0?null:(i.value<0||i.value>u.length-1?(i.value=u.findIndex(v=>v.props.active===""||v.props.active===!0),i.value===-1&&(i.value=0)):u.forEach((v,_)=>{v.props.active=_===i.value}),he("div",{class:"code-group"},[he("div",{class:"code-group__nav",role:"tablist"},u.map((v,_)=>{const p=_===i.value;return he("button",{ref:m=>{m&&(l.value[_]=m)},class:{"code-group__nav-tab":!0,"code-group__nav-tab-active":p},role:"tab",ariaSelected:p,onClick:()=>i.value=_,onKeydown:m=>a(m,_)},v.props.title)})),u]))}}}),rv=_e({name:"CodeGroupItem",__name:"CodeGroupItem",props:{title:{type:String,required:!0},active:{type:Boolean,required:!1,default:!1}},setup(e,{expose:t}){t();const l={};return Object.defineProperty(l,"__isScriptSetup",{enumerable:!1,value:!0}),l}});function ov(e,t,l,i,n,r){return W(),ee("div",{class:$e(["code-group-item",{"code-group-item__active":l.active}]),role:"tabpanel"},[be(e.$slots,"default")],2)}const sv=xe(rv,[["render",ov],["__file","CodeGroupItem.vue"]]),cv=()=>Ns(),Fe=()=>Rh(),Ws=Symbol(""),Kn=()=>{const e=Te(Ws);if(!e)throw new Error("useDarkMode() is called without provider.");return e},av=()=>{const e=Fe(),t=iv(),l=Bs("vuepress-color-scheme",e.value.colorMode),i=C({get(){return e.value.colorModeSwitch?l.value==="auto"?t.value:l.value==="dark":e.value.colorMode==="dark"},set(n){n===t.value?l.value="auto":l.value=n?"dark":"light"}});Kt(Ws,i),uv(i)},uv=e=>{const t=(l=e.value)=>{const i=window==null?void 0:window.document.querySelector("html");i==null||i.classList.toggle("dark",l)};We(()=>{Ge(e,t,{immediate:!0})}),Ci(()=>t())};let tn=null,Ll=null;const dv={wait:()=>tn,pending:()=>{tn=new Promise(e=>Ll=e)},resolve:()=>{Ll==null||Ll(),tn=null,Ll=null}},zs=()=>dv,Us=(e,...t)=>{const l=e.resolve(...t),i=l.matched[l.matched.length-1];if(!(i!=null&&i.redirect))return l;const{redirect:n}=i,r=Nu(n)?n(l):n,o=nt(r)?{path:r}:r;return Us(e,{hash:l.hash,query:l.query,params:l.params,...o})},qn=(e,t)=>{const l=Us(e,encodeURI(t));return{text:l.meta.title||t,link:l.name==="404"?t:l.fullPath}},uo=e=>decodeURI(e).replace(/#.*$/,"").replace(/(index)?\.(md|html)$/,""),hv=(e,t)=>{if(t.hash===e)return!0;const l=uo(t.path),i=uo(e);return l===i},Xs=(e,t)=>e.link&&hv(e.link,t)?!0:e.children?e.children.some(l=>Xs(l,t)):!1,Ks=e=>!Yl(e)||/github\.com/.test(e)?"GitHub":/bitbucket\.org/.test(e)?"Bitbucket":/gitlab\.com/.test(e)?"GitLab":/gitee\.com/.test(e)?"Gitee":null,vv={GitHub:":repo/edit/:branch/:path",GitLab:":repo/-/edit/:branch/:path",Gitee:":repo/edit/:branch/:path",Bitbucket:":repo/src/:branch/:path?mode=edit&spa=0&at=:branch&fileviewer=file-view-default"},_v=({docsRepo:e,editLinkPattern:t})=>{if(t)return t;const l=Ks(e);return l!==null?vv[l]:null},fv=({docsRepo:e,docsBranch:t,docsDir:l,filePathRelative:i,editLinkPattern:n})=>{if(!i)return null;const r=_v({docsRepo:e,editLinkPattern:n});return r?r.replace(/:repo/,Yl(e)?e:`https://github.com/${e}`).replace(/:branch/,t).replace(/:path/,fs(`${_s(l)}/${i}`)):null},qs=Symbol("sidebarItems"),Gn=()=>{const e=Te(qs);if(!e)throw new Error("useSidebarItems() is called without provider.");return e},gv=()=>{const e=Fe(),t=pt(),l=Gt(),i=ml(),n=bt(),r=C(()=>pv(t.value,e.value,l.value,n,i.path));Kt(qs,r)},pv=(e,t,l,i,n)=>{const r=e.sidebar??t.sidebar??"auto",o=e.sidebarDepth??t.sidebarDepth??2;return e.home||r===!1?[]:r==="auto"?Gs(l,o):Array.isArray(r)?Ys(l,i,n,r,o):Hn(r)?bv(l,i,n,r,o):[]},mv=(e,t)=>({text:e.title,link:e.link,children:Yn(e.children,t)}),Yn=(e,t)=>t>0?e.map(l=>mv(l,t-1)):[],Gs=(e,t)=>[{text:e.title,children:Yn(e.headers,t)}],Ys=(e,t,l,i,n)=>{const r=o=>{var a;let c;if(nt(o)?c=qn(t,o):c=o,c.children)return{...c,children:c.children.map(u=>r(u))};if(c.link===l){const u=((a=e.headers[0])==null?void 0:a.level)===1?e.headers[0].children:e.headers;return{...c,children:Yn(u,n)}}return c};return i.map(o=>r(o))},bv=(e,t,l,i,n)=>{const r=gs(i,l),o=i[r]??[];return o==="heading"?Gs(e,n):Ys(e,t,l,o,n)},kv="719px",Ev={mobile:kv};var $l;(function(e){e.MOBILE="mobile"})($l||($l={}));var po;const yv={[$l.MOBILE]:Number.parseInt((po=Ev.mobile)==null?void 0:po.replace("px",""),10)},Js=(e,t)=>{const l=yv[e];Number.isInteger(l)&&We(()=>{t(l),window.addEventListener("resize",()=>t(l),!1),window.addEventListener("orientationchange",()=>t(l),!1)})},xv={},Lv={class:"theme-default-content"};function Tv(e,t){const l=mt("Content");return W(),ee("div",Lv,[ne(l)])}const Ov=xe(xv,[["render",Tv],["__file","HomeContent.vue"]]),Pv=_e({__name:"HomeFeatures",setup(e,{expose:t}){t();const l=pt(),i=C(()=>Array.isArray(l.value.features)?l.value.features:[]),n={frontmatter:l,features:i};return Object.defineProperty(n,"__isScriptSetup",{enumerable:!1,value:!0}),n}}),Av={key:0,class:"features"};function wv(e,t,l,i,n,r){return i.features.length?(W(),ee("div",Av,[(W(!0),ee(ke,null,St(i.features,o=>(W(),ee("div",{key:o.title,class:"feature"},[ce("h2",null,Pe(o.title),1),ce("p",null,Pe(o.details),1)]))),128))])):Le("",!0)}const Rv=xe(Pv,[["render",wv],["__file","HomeFeatures.vue"]]),Iv=_e({__name:"HomeFooter",setup(e,{expose:t}){t();const l=pt(),i=C(()=>l.value.footer),n=C(()=>l.value.footerHtml),r={frontmatter:l,footer:i,footerHtml:n};return Object.defineProperty(r,"__isScriptSetup",{enumerable:!1,value:!0}),r}}),Dv=["innerHTML"],jv=["textContent"];function Sv(e,t,l,i,n,r){return i.footer?(W(),ee(ke,{key:0},[i.footerHtml?(W(),ee("div",{key:0,class:"footer",innerHTML:i.footer},null,8,Dv)):(W(),ee("div",{key:1,class:"footer",textContent:Pe(i.footer)},null,8,jv))],64)):Le("",!0)}const Cv=xe(Iv,[["render",Sv],["__file","HomeFooter.vue"]]),Vv=_e({inheritAttrs:!1,__name:"AutoLink",props:{item:{type:Object,required:!0}},setup(e,{expose:t}){t();const l=e,i=ml(),n=xs(),{item:r}=Ii(l),o=C(()=>Yl(r.value.link)),c=C(()=>!o.value&&Fu(r.value.link)),a=C(()=>{if(!c.value){if(r.value.target)return r.value.target;if(o.value)return"_blank"}}),u=C(()=>a.value==="_blank"),d=C(()=>!o.value&&!c.value&&!u.value),v=C(()=>{if(!c.value){if(r.value.rel)return r.value.rel;if(u.value)return"noopener noreferrer"}}),_=C(()=>r.value.ariaLabel||r.value.text),p=C(()=>{const D=Object.keys(n.value.locales);return D.length?!D.some(O=>O===r.value.link):r.value.link!=="/"}),m=C(()=>p.value?i.path.startsWith(r.value.link):!1),x=C(()=>d.value?r.value.activeMatch?new RegExp(r.value.activeMatch).test(i.path):m.value:!1),A={props:l,route:i,site:n,item:r,hasHttpProtocol:o,hasNonHttpProtocol:c,linkTarget:a,isBlankTarget:u,isRouterLink:d,linkRel:v,linkAriaLabel:_,shouldBeActiveInSubpath:p,isActiveInSubpath:m,isActive:x};return Object.defineProperty(A,"__isScriptSetup",{enumerable:!1,value:!0}),A}}),Fv=["href","rel","target","aria-label"];function Nv(e,t,l,i,n,r){const o=mt("RouterLink"),c=mt("AutoLinkExternalIcon");return i.isRouterLink?(W(),Ae(o,_n({key:0,class:{"router-link-active":i.isActive},to:i.item.link,"aria-label":i.linkAriaLabel},e.$attrs),{default:Ce(()=>[be(e.$slots,"before"),Vt(" "+Pe(i.item.text)+" ",1),be(e.$slots,"after")]),_:3},16,["class","to","aria-label"])):(W(),ee("a",_n({key:1,class:"external-link",href:i.item.link,rel:i.linkRel,target:i.linkTarget,"aria-label":i.linkAriaLabel},e.$attrs),[be(e.$slots,"before"),Vt(" "+Pe(i.item.text)+" ",1),i.isBlankTarget?(W(),Ae(c,{key:0})):Le("",!0),be(e.$slots,"after")],16,Fv))}const bl=xe(Vv,[["render",Nv],["__file","AutoLink.vue"]]),Hv=_e({__name:"HomeHero",setup(e,{expose:t}){t();const l=pt(),i=$n(),n=Kn(),r=C(()=>n.value&&l.value.heroImageDark!==void 0?l.value.heroImageDark:l.value.heroImage),o=C(()=>l.value.heroAlt||a.value||"hero"),c=C(()=>l.value.heroHeight||280),a=C(()=>l.value.heroText===null?null:l.value.heroText||i.value.title||"Hello"),u=C(()=>l.value.tagline===null?null:l.value.tagline||i.value.description||"Welcome to your VuePress site"),d=C(()=>Array.isArray(l.value.actions)?l.value.actions.map(({text:p,link:m,type:x="primary"})=>({text:p,link:m,type:x})):[]),_={frontmatter:l,siteLocale:i,isDarkMode:n,heroImage:r,heroAlt:o,heroHeight:c,heroText:a,tagline:u,actions:d,HomeHeroImage:()=>{if(!r.value)return null;const p=he("img",{src:Wn(r.value),alt:o.value,height:c.value});return l.value.heroImageDark===void 0?p:he(Bn,()=>p)},AutoLink:bl};return Object.defineProperty(_,"__isScriptSetup",{enumerable:!1,value:!0}),_}}),Mv={class:"hero"},$v={key:0,id:"main-title"},Bv={key:1,class:"description"},Wv={key:2,class:"actions"};function zv(e,t,l,i,n,r){return W(),ee("header",Mv,[ne(i.HomeHeroImage),i.heroText?(W(),ee("h1",$v,Pe(i.heroText),1)):Le("",!0),i.tagline?(W(),ee("p",Bv,Pe(i.tagline),1)):Le("",!0),i.actions.length?(W(),ee("p",Wv,[(W(!0),ee(ke,null,St(i.actions,o=>(W(),Ae(i.AutoLink,{key:o.text,class:$e(["action-button",[o.type]]),item:o},null,8,["class","item"]))),128))])):Le("",!0)])}const Uv=xe(Hv,[["render",zv],["__file","HomeHero.vue"]]),Xv=_e({__name:"Home",setup(e,{expose:t}){t();const l={HomeContent:Ov,HomeFeatures:Rv,HomeFooter:Cv,HomeHero:Uv};return Object.defineProperty(l,"__isScriptSetup",{enumerable:!1,value:!0}),l}}),Kv={class:"home"};function qv(e,t,l,i,n,r){return W(),ee("main",Kv,[ne(i.HomeHero),ne(i.HomeFeatures),ne(i.HomeContent),ne(i.HomeFooter)])}const Gv=xe(Xv,[["render",qv],["__file","Home.vue"]]),Yv=_e({__name:"NavbarBrand",setup(e,{expose:t}){t();const l=Jl(),i=$n(),n=Fe(),r=Kn(),o=C(()=>n.value.home||l.value),c=C(()=>i.value.title),a=C(()=>r.value&&n.value.logoDark!==void 0?n.value.logoDark:n.value.logo),u=C(()=>n.value.logoAlt??c.value),d=C(()=>c.value.toLocaleUpperCase().trim()===u.value.toLocaleUpperCase().trim()),_={routeLocale:l,siteLocale:i,themeLocale:n,isDarkMode:r,navbarBrandLink:o,navbarBrandTitle:c,navbarBrandLogo:a,navbarBrandLogoAlt:u,navBarLogoAltMatchesTitle:d,NavbarBrandLogo:()=>{if(!a.value)return null;const p=he("img",{class:"logo",src:Wn(a.value),alt:u.value});return n.value.logoDark===void 0?p:he(Bn,()=>p)}};return Object.defineProperty(_,"__isScriptSetup",{enumerable:!1,value:!0}),_}}),Jv=["aria-hidden"];function Qv(e,t,l,i,n,r){const o=mt("RouterLink");return W(),Ae(o,{to:i.navbarBrandLink},{default:Ce(()=>[ne(i.NavbarBrandLogo),i.navbarBrandTitle?(W(),ee("span",{key:0,class:$e(["site-name",{"can-hide":i.navbarBrandLogo}]),"aria-hidden":i.navBarLogoAltMatchesTitle},Pe(i.navbarBrandTitle),11,Jv)):Le("",!0)]),_:1},8,["to"])}const Zv=xe(Yv,[["render",Qv],["__file","NavbarBrand.vue"]]),e_=_e({__name:"DropdownTransition",setup(e,{expose:t}){t();const n={setHeight:r=>{r.style.height=r.scrollHeight+"px"},unsetHeight:r=>{r.style.height=""}};return Object.defineProperty(n,"__isScriptSetup",{enumerable:!1,value:!0}),n}});function t_(e,t,l,i,n,r){return W(),Ae(Gl,{name:"dropdown",onEnter:i.setHeight,onAfterEnter:i.unsetHeight,onBeforeLeave:i.setHeight},{default:Ce(()=>[be(e.$slots,"default")]),_:3})}const Qs=xe(e_,[["render",t_],["__file","DropdownTransition.vue"]]),l_=_e({__name:"NavbarDropdown",props:{item:{type:Object,required:!0}},setup(e,{expose:t}){t();const l=e,{item:i}=Ii(l),n=C(()=>i.value.ariaLabel||i.value.text),r=ge(!1),o=ml();Ge(()=>o.path,()=>{r.value=!1});const u={props:l,item:i,dropdownAriaLabel:n,open:r,route:o,handleDropdown:d=>{d.detail===0?r.value=!r.value:r.value=!1},isLastItemOfArray:(d,v)=>v[v.length-1]===d,AutoLink:bl,DropdownTransition:Qs};return Object.defineProperty(u,"__isScriptSetup",{enumerable:!1,value:!0}),u}}),i_=["aria-label"],n_={class:"title"},r_=ce("span",{class:"arrow down"},null,-1),o_=["aria-label"],s_={class:"title"},c_={class:"navbar-dropdown"},a_={class:"navbar-dropdown-subtitle"},u_={key:1},d_={class:"navbar-dropdown-subitem-wrapper"};function h_(e,t,l,i,n,r){return W(),ee("div",{class:$e(["navbar-dropdown-wrapper",{open:i.open}])},[ce("button",{class:"navbar-dropdown-title",type:"button","aria-label":i.dropdownAriaLabel,onClick:i.handleDropdown},[ce("span",n_,Pe(i.item.text),1),r_],8,i_),ce("button",{class:"navbar-dropdown-title-mobile",type:"button","aria-label":i.dropdownAriaLabel,onClick:t[0]||(t[0]=o=>i.open=!i.open)},[ce("span",s_,Pe(i.item.text),1),ce("span",{class:$e(["arrow",i.open?"down":"right"])},null,2)],8,o_),ne(i.DropdownTransition,null,{default:Ce(()=>[bi(ce("ul",c_,[(W(!0),ee(ke,null,St(i.item.children,o=>(W(),ee("li",{key:o.text,class:"navbar-dropdown-item"},[o.children?(W(),ee(ke,{key:0},[ce("h4",a_,[o.link?(W(),Ae(i.AutoLink,{key:0,item:o,onFocusout:c=>i.isLastItemOfArray(o,i.item.children)&&o.children.length===0&&(i.open=!1)},null,8,["item","onFocusout"])):(W(),ee("span",u_,Pe(o.text),1))]),ce("ul",d_,[(W(!0),ee(ke,null,St(o.children,c=>(W(),ee("li",{key:c.link,class:"navbar-dropdown-subitem"},[ne(i.AutoLink,{item:c,onFocusout:a=>i.isLastItemOfArray(c,o.children)&&i.isLastItemOfArray(o,i.item.children)&&(i.open=!1)},null,8,["item","onFocusout"])]))),128))])],64)):(W(),Ae(i.AutoLink,{key:1,item:o,onFocusout:c=>i.isLastItemOfArray(o,i.item.children)&&(i.open=!1)},null,8,["item","onFocusout"]))]))),128))],512),[[Li,i.open]])]),_:1})],2)}const v_=xe(l_,[["render",h_],["__file","NavbarDropdown.vue"]]),__=_e({__name:"NavbarItems",setup(e,{expose:t}){t();const l=()=>{const p=bt(),m=Jl(),x=xs(),A=$n(),D=cv(),O=Fe();return C(()=>{const b=Object.keys(x.value.locales);if(b.length<2)return[];const y=p.currentRoute.value.path,H=p.currentRoute.value.fullPath;return[{text:`${O.value.selectLanguageText}`,ariaLabel:`${O.value.selectLanguageAriaLabel??O.value.selectLanguageText}`,children:b.map(N=>{var V,le;const E=((V=x.value.locales)==null?void 0:V[N])??{},K=((le=D.value.locales)==null?void 0:le[N])??{},w=`${E.lang}`,U=K.selectLanguageName??w;let L;if(w===A.value.lang)L=H;else{const ie=y.replace(m.value,N);p.getRoutes().some(S=>S.path===ie)?L=H.replace(y,ie):L=K.home??N}return{text:U,link:L}})}]})},i=()=>{const p=Fe(),m=C(()=>p.value.repo),x=C(()=>m.value?Ks(m.value):null),A=C(()=>m.value&&!Yl(m.value)?`https://github.com/${m.value}`:m.value),D=C(()=>A.value?p.value.repoLabel?p.value.repoLabel:x.value===null?"Source":x.value:null);return C(()=>!A.value||!D.value?[]:[{text:D.value,link:A.value}])},n=(p,m)=>nt(m)?qn(p,m):m.children?{...m,children:m.children.map(x=>n(p,x))}:m,r=()=>{const p=bt(),m=Fe();return C(()=>(m.value.navbar||[]).map(x=>n(p,x)))},o=ge(!1),c=r(),a=l(),u=i(),d=C(()=>[...c.value,...a.value,...u.value]);Js($l.MOBILE,p=>{window.innerWidthFe().value.navbarLabel??"site navigation"),_={useNavbarSelectLanguage:l,useNavbarRepo:i,resolveNavbarItem:n,useNavbarConfig:r,isMobile:o,navbarConfig:c,navbarSelectLanguage:a,navbarRepo:u,navbarLinks:d,navbarLabel:v,AutoLink:bl,NavbarDropdown:v_};return Object.defineProperty(_,"__isScriptSetup",{enumerable:!1,value:!0}),_}}),f_=["aria-label"];function g_(e,t,l,i,n,r){return i.navbarLinks.length?(W(),ee("nav",{key:0,class:"navbar-items","aria-label":i.navbarLabel},[(W(!0),ee(ke,null,St(i.navbarLinks,o=>(W(),ee("div",{key:o.text,class:"navbar-item"},[o.children?(W(),Ae(i.NavbarDropdown,{key:0,item:o,class:$e(i.isMobile?"mobile":"")},null,8,["item","class"])):(W(),Ae(i.AutoLink,{key:1,item:o},null,8,["item"]))]))),128))],8,f_)):Le("",!0)}const Zs=xe(__,[["render",g_],["__file","NavbarItems.vue"]]),p_=_e({__name:"ToggleColorModeButton",setup(e,{expose:t}){t();const l=Fe(),i=Kn(),r={themeLocale:l,isDarkMode:i,toggleColorMode:()=>{i.value=!i.value}};return Object.defineProperty(r,"__isScriptSetup",{enumerable:!1,value:!0}),r}}),m_=["title"],b_={class:"icon",focusable:"false",viewBox:"0 0 32 32"},k_=$a('',9),E_=[k_],y_={class:"icon",focusable:"false",viewBox:"0 0 32 32"},x_=ce("path",{d:"M13.502 5.414a15.075 15.075 0 0 0 11.594 18.194a11.113 11.113 0 0 1-7.975 3.39c-.138 0-.278.005-.418 0a11.094 11.094 0 0 1-3.2-21.584M14.98 3a1.002 1.002 0 0 0-.175.016a13.096 13.096 0 0 0 1.825 25.981c.164.006.328 0 .49 0a13.072 13.072 0 0 0 10.703-5.555a1.01 1.01 0 0 0-.783-1.565A13.08 13.08 0 0 1 15.89 4.38A1.015 1.015 0 0 0 14.98 3z",fill:"currentColor"},null,-1),L_=[x_];function T_(e,t,l,i,n,r){return W(),ee("button",{class:"toggle-color-mode-button",title:i.themeLocale.toggleColorMode,onClick:i.toggleColorMode},[bi((W(),ee("svg",b_,E_,512)),[[Li,!i.isDarkMode]]),bi((W(),ee("svg",y_,L_,512)),[[Li,i.isDarkMode]])],8,m_)}const O_=xe(p_,[["render",T_],["__file","ToggleColorModeButton.vue"]]),P_=_e({__name:"ToggleSidebarButton",emits:["toggle"],setup(e,{expose:t}){t();const i={themeLocale:Fe()};return Object.defineProperty(i,"__isScriptSetup",{enumerable:!1,value:!0}),i}}),A_=["title"],w_=ce("div",{class:"icon","aria-hidden":"true"},[ce("span"),ce("span"),ce("span")],-1),R_=[w_];function I_(e,t,l,i,n,r){return W(),ee("div",{class:"toggle-sidebar-button",title:i.themeLocale.toggleSidebar,"aria-expanded":"false",role:"button",tabindex:"0",onClick:t[0]||(t[0]=o=>e.$emit("toggle"))},R_,8,A_)}const D_=xe(P_,[["render",I_],["__file","ToggleSidebarButton.vue"]]),j_=_e({__name:"Navbar",emits:["toggle-sidebar"],setup(e,{expose:t}){t();const l=Fe(),i=ge(null),n=ge(null),r=ge(0),o=C(()=>r.value?{maxWidth:r.value+"px"}:{});Js($l.MOBILE,u=>{var v;const d=c(i.value,"paddingLeft")+c(i.value,"paddingRight");window.innerWidthe.$emit("toggle-sidebar"))}),ce("span",C_,[ne(i.NavbarBrand)],512),ce("div",{class:"navbar-items-wrapper",style:Wl(i.linksWrapperStyle)},[be(e.$slots,"before"),ne(i.NavbarItems,{class:"can-hide"}),be(e.$slots,"after"),i.themeLocale.colorModeSwitch?(W(),Ae(i.ToggleColorModeButton,{key:0})):Le("",!0),ne(o)],4)],512)}const F_=xe(j_,[["render",V_],["__file","Navbar.vue"]]),N_=_e({__name:"PageMeta",setup(e,{expose:t}){t();const l=()=>{const d=Fe(),v=Gt(),_=pt();return C(()=>{if(!(_.value.editLink??d.value.editLink??!0))return null;const{repo:m,docsRepo:x=m,docsBranch:A="main",docsDir:D="",editLinkText:O}=d.value;if(!x)return null;const b=fv({docsRepo:x,docsBranch:A,docsDir:D,filePathRelative:v.value.filePathRelative,editLinkPattern:_.value.editLinkPattern??d.value.editLinkPattern});return b?{text:O??"Edit this page",link:b}:null})},i=()=>{const d=Fe(),v=Gt(),_=pt();return C(()=>{var x,A;return!(_.value.lastUpdated??d.value.lastUpdated??!0)||!((x=v.value.git)!=null&&x.updatedTime)?null:new Date((A=v.value.git)==null?void 0:A.updatedTime).toLocaleString()})},n=()=>{const d=Fe(),v=Gt(),_=pt();return C(()=>{var m;return _.value.contributors??d.value.contributors??!0?((m=v.value.git)==null?void 0:m.contributors)??null:null})},r=Fe(),o=l(),c=i(),a=n(),u={useEditNavLink:l,useLastUpdated:i,useContributors:n,themeLocale:r,editNavLink:o,lastUpdated:c,contributors:a,AutoLink:bl};return Object.defineProperty(u,"__isScriptSetup",{enumerable:!1,value:!0}),u}}),H_={class:"page-meta"},M_={key:0,class:"meta-item edit-link"},$_={key:1,class:"meta-item last-updated"},B_={class:"meta-item-label"},W_={class:"meta-item-info"},z_={key:2,class:"meta-item contributors"},U_={class:"meta-item-label"},X_={class:"meta-item-info"},K_=["title"];function q_(e,t,l,i,n,r){const o=mt("ClientOnly");return W(),ee("footer",H_,[i.editNavLink?(W(),ee("div",M_,[ne(i.AutoLink,{class:"meta-item-label",item:i.editNavLink},null,8,["item"])])):Le("",!0),i.lastUpdated?(W(),ee("div",$_,[ce("span",B_,Pe(i.themeLocale.lastUpdatedText)+": ",1),ne(o,null,{default:Ce(()=>[ce("span",W_,Pe(i.lastUpdated),1)]),_:1})])):Le("",!0),i.contributors&&i.contributors.length?(W(),ee("div",z_,[ce("span",U_,Pe(i.themeLocale.contributorsText)+": ",1),ce("span",X_,[(W(!0),ee(ke,null,St(i.contributors,(c,a)=>(W(),ee(ke,{key:a},[ce("span",{class:"contributor",title:`email: ${c.email}`},Pe(c.name),9,K_),a!==i.contributors.length-1?(W(),ee(ke,{key:0},[Vt(", ")],64)):Le("",!0)],64))),128))])])):Le("",!0)])}const G_=xe(N_,[["render",q_],["__file","PageMeta.vue"]]),Y_=_e({__name:"PageNav",setup(e,{expose:t}){t();const l=(_,p)=>p===!1?null:nt(p)?qn(_,p):Hn(p)?p:!1,i=(_,p,m)=>{const x=_.findIndex(A=>A.link===p);if(x!==-1){const A=_[x+m];return A!=null&&A.link?A:null}for(const A of _)if(A.children){const D=i(A.children,p,m);if(D)return D}return null},n=pt(),r=Gn(),o=ml(),c=bt(),a=C(()=>{const _=l(c,n.value.prev);return _!==!1?_:i(r.value,o.path,-1)}),u=C(()=>{const _=l(c,n.value.next);return _!==!1?_:i(r.value,o.path,1)}),d=C(()=>Fe().value.pageNavbarLabel??"page navigation"),v={resolveFromFrontmatterConfig:l,resolveFromSidebarItems:i,frontmatter:n,sidebarItems:r,route:o,router:c,prevNavLink:a,nextNavLink:u,navbarLabel:d,AutoLink:bl};return Object.defineProperty(v,"__isScriptSetup",{enumerable:!1,value:!0}),v}}),J_=["aria-label"],Q_={class:"inner"},Z_={key:0,class:"prev"},e2={key:1,class:"next"};function t2(e,t,l,i,n,r){return i.prevNavLink||i.nextNavLink?(W(),ee("nav",{key:0,class:"page-nav","aria-label":i.navbarLabel},[ce("p",Q_,[i.prevNavLink?(W(),ee("span",Z_,[ne(i.AutoLink,{item:i.prevNavLink},null,8,["item"])])):Le("",!0),i.nextNavLink?(W(),ee("span",e2,[ne(i.AutoLink,{item:i.nextNavLink},null,8,["item"])])):Le("",!0)])],8,J_)):Le("",!0)}const l2=xe(Y_,[["render",t2],["__file","PageNav.vue"]]),i2=_e({__name:"Page",setup(e,{expose:t}){t();const l={PageMeta:G_,PageNav:l2};return Object.defineProperty(l,"__isScriptSetup",{enumerable:!1,value:!0}),l}}),n2={class:"page"},r2={class:"theme-default-content"};function o2(e,t,l,i,n,r){const o=mt("Content");return W(),ee("main",n2,[be(e.$slots,"top"),ce("div",r2,[be(e.$slots,"content-top"),ne(o),be(e.$slots,"content-bottom")]),ne(i.PageMeta),ne(i.PageNav),be(e.$slots,"bottom")])}const s2=xe(i2,[["render",o2],["__file","Page.vue"]]),c2=_e({__name:"SidebarItem",props:{item:{type:Object,required:!0},depth:{type:Number,required:!1,default:0}},setup(e,{expose:t}){t();const l=e,{item:i,depth:n}=Ii(l),r=ml(),o=bt(),c=C(()=>Xs(i.value,r)),a=C(()=>({"sidebar-item":!0,"sidebar-heading":n.value===0,active:c.value,collapsible:i.value.collapsible})),u=C(()=>i.value.collapsible?c.value:!0),[d,v]=Kh(u.value),_=x=>{i.value.collapsible&&(x.preventDefault(),v())},p=o.afterEach(x=>{Xl(()=>{d.value=u.value})});ql(()=>{p()});const m={props:l,item:i,depth:n,route:r,router:o,isActive:c,itemClass:a,isOpenDefault:u,isOpen:d,toggleIsOpen:v,onClick:_,unregisterRouterHook:p,AutoLink:bl,DropdownTransition:Qs};return Object.defineProperty(m,"__isScriptSetup",{enumerable:!1,value:!0}),m}}),a2={class:"sidebar-item-children"};function u2(e,t,l,i,n,r){var c;const o=mt("SidebarItem",!0);return W(),ee("li",null,[i.item.link?(W(),Ae(i.AutoLink,{key:0,class:$e(i.itemClass),item:i.item},null,8,["class","item"])):(W(),ee("p",{key:1,tabindex:"0",class:$e(i.itemClass),onClick:i.onClick,onKeydown:Lu(i.onClick,["enter"])},[Vt(Pe(i.item.text)+" ",1),i.item.collapsible?(W(),ee("span",{key:0,class:$e(["arrow",i.isOpen?"down":"right"])},null,2)):Le("",!0)],34)),(c=i.item.children)!=null&&c.length?(W(),Ae(i.DropdownTransition,{key:2},{default:Ce(()=>[bi(ce("ul",a2,[(W(!0),ee(ke,null,St(i.item.children,a=>(W(),Ae(o,{key:`${i.depth}${a.text}${a.link}`,item:a,depth:i.depth+1},null,8,["item","depth"]))),128))],512),[[Li,i.isOpen]])]),_:1})):Le("",!0)])}const d2=xe(c2,[["render",u2],["__file","SidebarItem.vue"]]),h2=_e({__name:"SidebarItems",setup(e,{expose:t}){t();const l=ml(),i=Gn();We(()=>{Ge(()=>l.hash,r=>{const o=document.querySelector(".sidebar");if(!o)return;const c=document.querySelector(`.sidebar a.sidebar-item[href="${l.path}${r}"]`);if(!c)return;const{top:a,height:u}=o.getBoundingClientRect(),{top:d,height:v}=c.getBoundingClientRect();da+u&&c.scrollIntoView(!1)})});const n={route:l,sidebarItems:i,SidebarItem:d2};return Object.defineProperty(n,"__isScriptSetup",{enumerable:!1,value:!0}),n}}),v2={key:0,class:"sidebar-items"};function _2(e,t,l,i,n,r){return i.sidebarItems.length?(W(),ee("ul",v2,[(W(!0),ee(ke,null,St(i.sidebarItems,o=>(W(),Ae(i.SidebarItem,{key:`${o.text}${o.link}`,item:o},null,8,["item"]))),128))])):Le("",!0)}const f2=xe(h2,[["render",_2],["__file","SidebarItems.vue"]]),g2=_e({__name:"Sidebar",setup(e,{expose:t}){t();const l={NavbarItems:Zs,SidebarItems:f2};return Object.defineProperty(l,"__isScriptSetup",{enumerable:!1,value:!0}),l}}),p2={class:"sidebar"};function m2(e,t,l,i,n,r){return W(),ee("aside",p2,[ne(i.NavbarItems),be(e.$slots,"top"),ne(i.SidebarItems),be(e.$slots,"bottom")])}const b2=xe(g2,[["render",m2],["__file","Sidebar.vue"]]),k2=_e({__name:"Layout",setup(e,{expose:t}){t();const l=Gt(),i=pt(),n=Fe(),r=C(()=>i.value.navbar!==!1&&n.value.navbar!==!1),o=Gn(),c=ge(!1),a=O=>{c.value=typeof O=="boolean"?O:!c.value},u={x:0,y:0},d=O=>{u.x=O.changedTouches[0].clientX,u.y=O.changedTouches[0].clientY},v=O=>{const b=O.changedTouches[0].clientX-u.x,y=O.changedTouches[0].clientY-u.y;Math.abs(b)>Math.abs(y)&&Math.abs(b)>40&&(b>0&&u.x<=80?a(!0):a(!1))},_=C(()=>[{"no-navbar":!r.value,"no-sidebar":!o.value.length,"sidebar-open":c.value},i.value.pageClass]);let p;We(()=>{p=bt().afterEach(()=>{a(!1)})}),Ci(()=>{p()});const m=zs(),x=m.resolve,A=m.pending,D={page:l,frontmatter:i,themeLocale:n,shouldShowNavbar:r,sidebarItems:o,isSidebarOpen:c,toggleSidebar:a,touchStart:u,onTouchStart:d,onTouchEnd:v,containerClass:_,get unregisterRouterHook(){return p},set unregisterRouterHook(O){p=O},scrollPromise:m,onBeforeEnter:x,onBeforeLeave:A,Home:Gv,Navbar:F_,Page:s2,Sidebar:b2};return Object.defineProperty(D,"__isScriptSetup",{enumerable:!1,value:!0}),D}});function E2(e,t,l,i,n,r){return W(),ee("div",{class:$e(["theme-container",i.containerClass]),onTouchstart:i.onTouchStart,onTouchend:i.onTouchEnd},[be(e.$slots,"navbar",{},()=>[i.shouldShowNavbar?(W(),Ae(i.Navbar,{key:0,onToggleSidebar:i.toggleSidebar},{before:Ce(()=>[be(e.$slots,"navbar-before")]),after:Ce(()=>[be(e.$slots,"navbar-after")]),_:3})):Le("",!0)]),ce("div",{class:"sidebar-mask",onClick:t[0]||(t[0]=o=>i.toggleSidebar(!1))}),be(e.$slots,"sidebar",{},()=>[ne(i.Sidebar,null,{top:Ce(()=>[be(e.$slots,"sidebar-top")]),bottom:Ce(()=>[be(e.$slots,"sidebar-bottom")]),_:3})]),be(e.$slots,"page",{},()=>[i.frontmatter.home?(W(),Ae(i.Home,{key:0})):(W(),Ae(Gl,{key:1,name:"fade-slide-y",mode:"out-in",onBeforeEnter:i.onBeforeEnter,onBeforeLeave:i.onBeforeLeave},{default:Ce(()=>[(W(),Ae(i.Page,{key:i.page.path},{top:Ce(()=>[be(e.$slots,"page-top")]),"content-top":Ce(()=>[be(e.$slots,"page-content-top")]),"content-bottom":Ce(()=>[be(e.$slots,"page-content-bottom")]),bottom:Ce(()=>[be(e.$slots,"page-bottom")]),_:3}))]),_:3},8,["onBeforeEnter","onBeforeLeave"]))])],34)}const y2=xe(k2,[["render",E2],["__file","Layout.vue"]]),x2=_e({__name:"NotFound",setup(e,{expose:t}){t();const l=Jl(),i=Fe(),n=i.value.notFound??["Not Found"],r=()=>n[Math.floor(Math.random()*n.length)],o=i.value.home??l.value,c=i.value.backToHome??"Back to home",a={routeLocale:l,themeLocale:i,messages:n,getMsg:r,homeLink:o,homeText:c};return Object.defineProperty(a,"__isScriptSetup",{enumerable:!1,value:!0}),a}}),L2={class:"theme-container"},T2={class:"page"},O2={class:"theme-default-content"},P2=ce("h1",null,"404",-1);function A2(e,t,l,i,n,r){const o=mt("RouterLink");return W(),ee("div",L2,[ce("main",T2,[ce("div",O2,[P2,ce("blockquote",null,Pe(i.getMsg()),1),ne(o,{to:i.homeLink},{default:Ce(()=>[Vt(Pe(i.homeText),1)]),_:1},8,["to"])])])])}const w2=xe(x2,[["render",A2],["__file","NotFound.vue"]]),R2=Et({enhance({app:e,router:t}){e.component("Badge",Ch),e.component("CodeGroup",nv),e.component("CodeGroupItem",sv),e.component("AutoLinkExternalIcon",()=>{const i=e.component("ExternalLinkIcon");return i?he(i):null}),e.component("NavbarSearch",()=>{const i=e.component("Docsearch")||e.component("SearchBox");return i?he(i):null});const l=t.options.scrollBehavior;t.options.scrollBehavior=async(...i)=>(await zs().wait(),l(...i))},setup(){av(),gv()},layouts:{Layout:y2,NotFound:w2}}),I2=e=>typeof e=="string",D2=(e,t)=>I2(e)&&e.startsWith(t),j2=e=>D2(e,"/"),S2={"/":"https://github.com/XTLS/Xray-docs-next"},C2={"/":{lang:"zh-CN",untranslated:{title:"提示",content:(e,t)=>`此页面尚未翻译${t?`,在${e("此处",t)}了解如何帮我们翻译`:""}。`},outdated:{title:"警告",content:(e,t,l,i)=>{const n=r=>{const o=new Date(r);return`${o.getFullYear()}年${o.getMonth()}月${o.getDate()}日`};return`本页面最后修改于${n(l)},原文已在${n(t)}更新。${e("查看原文",i)}`}}},"/en/":{lang:"en-US",untranslated:{title:"Notice",content:(e,t)=>`This page has not yet been translated${t?`, see how you can help ${e("here",t)}`:""}.`},outdated:{title:"Warning",content:(e,t,l,i)=>{const n=["January","February","March","April","May","June","July","August","September","October","November","December"],r=o=>{const c=new Date(o);return`${c.getDate()} ${n[c.getMonth()]} ${c.getFullYear()}`};return`This translation was modified on ${r(l)} and an updated version (${r(t)}) is available on the source page. ${e("View the original page",i)}`}}},"/ru/":{lang:"en-US",untranslated:{title:"Notice",content:(e,t)=>`This page has not yet been translated${t?`, see how you can help ${e("here",t)}`:""}.`},outdated:{title:"Warning",content:(e,t,l,i)=>{const n=["January","February","March","April","May","June","July","August","September","October","November","December"],r=o=>{const c=new Date(o);return`${c.getDate()} ${n[c.getMonth()]} ${c.getFullYear()}`};return`This translation was modified on ${r(l)} and an updated version (${r(t)}) is available on the source page. ${e("View the original page",i)}`}}}};var V2=["custom-container","hint-container"],F2=["custom-container-title","hint-container-title"],N2=V2,Tl="/",H2=F2,ho=S2,vo=C2,M2=()=>C(()=>{const{outdated:e=!1,pathLocale:t=Tl,sourceLink:l,sourceUpdatedTime:i,untranslated:n=!1,updatedTime:r}=Gt().value.i18n??{},o=vo[t??Tl]??vo[Tl],c=ho[t]??ho[Tl];return{isOutdated:e,isUntranslated:n,locale:o,options:{baseLocalePath:Tl,containerClass:N2,titleClass:H2},pathLocale:t,sourceLink:l,sourceUpdatedTime:i,translationGuide:c,updatedTime:r}}),Jn=_e({__name:"I18nTip",setup(e,{expose:t}){t();const l=(m,x)=>`${m}`,i=(m,x,A)=>{switch(m){case"untranslated":return x.untranslated.content(l,A.translationGuide);case"outdated":return!A.updatedTime||!A.sourceUpdatedTime||!A.sourceLink?null:x.outdated.content(l,A.sourceUpdatedTime,A.updatedTime,A.sourceLink);default:return null}},n=M2(),{containerClass:r,titleClass:o}=n.value.options,c=C(()=>n.value.locale),a=C(()=>n.value.isUntranslated||n.value.isOutdated),u=C(()=>n.value.isUntranslated?"untranslated":"outdated"),d=C(()=>u.value==="untranslated"?"tip":"warning"),v=C(()=>c.value[u.value].title),_=C(()=>a.value?i(u.value,c.value,n.value):null),p={linkRenderer:l,getContent:i,i18nData:n,containerClass:r,titleClass:o,locale:c,showTips:a,tipType:u,containerType:d,containerTitle:v,containerContent:_};return Object.defineProperty(p,"__isScriptSetup",{enumerable:!1,value:!0}),p}}),$2=["innerHTML"];function B2(e,t,l,i,n,r){return i.showTips&&i.containerContent?(W(),ee("div",{key:0,class:$e([...i.containerClass,i.containerType])},[ce("p",{class:$e(i.titleClass)},Pe(i.containerTitle),3),Le("eslint-disable-next-line vue/no-v-html "),ce("p",{innerHTML:i.containerContent},null,8,$2)],2)):Le("v-if",!0)}Jn.render=B2;Jn.__file="src/client/components/I18nTip.vue";var W2=Jn,z2=Et({enhance({app:e}){e.component("I18nTip",W2)}});const U2=e=>e instanceof Element?document.activeElement===e&&(["TEXTAREA","SELECT","INPUT"].includes(e.tagName)||e.hasAttribute("contenteditable")):!1,X2=(e,t)=>t.some(l=>{if(nt(l))return l===e.key;const{key:i,ctrl:n=!1,shift:r=!1,alt:o=!1}=l;return i===e.key&&n===e.ctrlKey&&r===e.shiftKey&&o===e.altKey}),K2=/[^\x00-\x7F]/,q2=e=>e.split(/\s+/g).map(t=>t.trim()).filter(t=>!!t),_o=e=>e.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&"),fo=(e,t)=>{const l=t.join(" "),i=q2(e);if(K2.test(e))return i.some(o=>l.toLowerCase().indexOf(o)>-1);const n=e.endsWith(" ");return new RegExp(i.map((o,c)=>i.length===c+1&&!n?`(?=.*\\b${_o(o)})`:`(?=.*\\b${_o(o)}\\b)`).join("")+".+","gi").test(l)},G2=({input:e,hotKeys:t})=>{if(t.value.length===0)return;const l=i=>{e.value&&X2(i,t.value)&&!U2(i.target)&&(i.preventDefault(),e.value.focus())};We(()=>{document.addEventListener("keydown",l)}),ql(()=>{document.removeEventListener("keydown",l)})},Y2=[{title:"",headers:[{level:2,title:"XTLS ? Xray ? V2Ray ?",slug:"xtls-xray-v2ray",link:"#xtls-xray-v2ray",children:[{level:3,title:"我们是谁?",slug:"我们是谁",link:"#我们是谁",children:[]},{level:3,title:"帮助 Xray 变得更强",slug:"帮助-xray-变得更强",link:"#帮助-xray-变得更强",children:[]},{level:3,title:"Telegram",slug:"telegram",link:"#telegram",children:[]},{level:3,title:"致谢",slug:"致谢",link:"#致谢",children:[]},{level:3,title:"更多关于 Project X",slug:"更多关于-project-x",link:"#更多关于-project-x",children:[]},{level:3,title:"License",slug:"license",link:"#license",children:[]},{level:3,title:"Stargazers over time",slug:"stargazers-over-time",link:"#stargazers-over-time",children:[]}]}],path:"/",pathLocale:"/",extraFields:[]},{title:"大史记",headers:[{level:2,title:"2024.9.12",slug:"_2024-9-12",link:"#_2024-9-12",children:[]},{level:2,title:"2024.9.7 v24.9.7",slug:"_2024-9-7-v24-9-7",link:"#_2024-9-7-v24-9-7",children:[]},{level:2,title:"2024.8.30 v1.8.24",slug:"_2024-8-30-v1-8-24",link:"#_2024-8-30-v1-8-24",children:[]},{level:2,title:"2024.8.26",slug:"_2024-8-26",link:"#_2024-8-26",children:[]},{level:2,title:"2024.8.3",slug:"_2024-8-3",link:"#_2024-8-3",children:[]},{level:2,title:"2024.7.29 v1.8.23",slug:"_2024-7-29-v1-8-23",link:"#_2024-7-29-v1-8-23",children:[]},{level:2,title:"2024.7.22 v1.8.21",slug:"_2024-7-22-v1-8-21",link:"#_2024-7-22-v1-8-21",children:[]},{level:2,title:"2024.7.16",slug:"_2024-7-16",link:"#_2024-7-16",children:[]},{level:2,title:"2024.7.15",slug:"_2024-7-15",link:"#_2024-7-15",children:[]},{level:2,title:"2024.6.18 v1.8.16",slug:"_2024-6-18-v1-8-16",link:"#_2024-6-18-v1-8-16",children:[]},{level:2,title:"2024.6.2",slug:"_2024-6-2",link:"#_2024-6-2",children:[]},{level:2,title:"2024.4.26 v1.8.11",slug:"_2024-4-26-v1-8-11",link:"#_2024-4-26-v1-8-11",children:[]},{level:2,title:"2024.4.20",slug:"_2024-4-20",link:"#_2024-4-20",children:[]},{level:2,title:"2024.4.13",slug:"_2024-4-13",link:"#_2024-4-13",children:[]},{level:2,title:"2024.3.18 v1.8.10",slug:"_2024-3-18-v1-8-10",link:"#_2024-3-18-v1-8-10",children:[]},{level:2,title:"2024.3.11 v1.8.9",slug:"_2024-3-11-v1-8-9",link:"#_2024-3-11-v1-8-9",children:[]},{level:2,title:"2024.2.29",slug:"_2024-2-29",link:"#_2024-2-29",children:[]},{level:2,title:"2024.2.25 v1.8.8",slug:"_2024-2-25-v1-8-8",link:"#_2024-2-25-v1-8-8",children:[]},{level:2,title:"2024.1.9",slug:"_2024-1-9",link:"#_2024-1-9",children:[]},{level:2,title:"2023.11.21",slug:"_2023-11-21",link:"#_2023-11-21",children:[]},{level:2,title:"2023.11.18 v1.8.6",slug:"_2023-11-18-v1-8-6",link:"#_2023-11-18-v1-8-6",children:[]},{level:2,title:"2023.9.30",slug:"_2023-9-30",link:"#_2023-9-30",children:[]},{level:2,title:"2023.8.29 v1.8.4",slug:"_2023-8-29-v1-8-4",link:"#_2023-8-29-v1-8-4",children:[]},{level:2,title:"2023.7.22",slug:"_2023-7-22",link:"#_2023-7-22",children:[]},{level:2,title:"2023.7.7",slug:"_2023-7-7",link:"#_2023-7-7",children:[]},{level:2,title:"2023.6.30",slug:"_2023-6-30",link:"#_2023-6-30",children:[]},{level:2,title:"2023.6.27",slug:"_2023-6-27",link:"#_2023-6-27",children:[]},{level:2,title:"2023.6.19 v1.8.3",slug:"_2023-6-19-v1-8-3",link:"#_2023-6-19-v1-8-3",children:[]},{level:2,title:"2023.6.6",slug:"_2023-6-6",link:"#_2023-6-6",children:[]},{level:2,title:"2023.4.21",slug:"_2023-4-21",link:"#_2023-4-21",children:[]},{level:2,title:"2023.4.20",slug:"_2023-4-20",link:"#_2023-4-20",children:[]},{level:2,title:"2023.4.19",slug:"_2023-4-19",link:"#_2023-4-19",children:[]},{level:2,title:"2023.4.18 v1.8.1",slug:"_2023-4-18-v1-8-1",link:"#_2023-4-18-v1-8-1",children:[]},{level:2,title:"2023.4.6",slug:"_2023-4-6",link:"#_2023-4-6",children:[]},{level:2,title:"2023.3.29",slug:"_2023-3-29",link:"#_2023-3-29",children:[]},{level:2,title:"2023.3.19",slug:"_2023-3-19",link:"#_2023-3-19",children:[]},{level:2,title:"2023.3.9 v1.8.0",slug:"_2023-3-9-v1-8-0",link:"#_2023-3-9-v1-8-0",children:[]},{level:2,title:"2023.3.4",slug:"_2023-3-4",link:"#_2023-3-4",children:[]},{level:2,title:"2023.3.2",slug:"_2023-3-2",link:"#_2023-3-2",children:[]},{level:2,title:"2023.2.16",slug:"_2023-2-16",link:"#_2023-2-16",children:[]},{level:2,title:"2023.2.9",slug:"_2023-2-9",link:"#_2023-2-9",children:[]},{level:2,title:"2023.2.8 v1.7.5",slug:"_2023-2-8-v1-7-5",link:"#_2023-2-8-v1-7-5",children:[]},{level:2,title:"2023.1.29",slug:"_2023-1-29",link:"#_2023-1-29",children:[]},{level:2,title:"2022.12.26 v1.7.0",slug:"_2022-12-26-v1-7-0",link:"#_2022-12-26-v1-7-0",children:[]},{level:2,title:"2022.11.28 v1.6.5",slug:"_2022-11-28-v1-6-5",link:"#_2022-11-28-v1-6-5",children:[]},{level:2,title:"2022.11.7 v1.6.3",slug:"_2022-11-7-v1-6-3",link:"#_2022-11-7-v1-6-3",children:[]},{level:2,title:"2022.10.29 v1.6.2",slug:"_2022-10-29-v1-6-2",link:"#_2022-10-29-v1-6-2",children:[]},{level:2,title:"2022.10.22 v1.6.1",slug:"_2022-10-22-v1-6-1",link:"#_2022-10-22-v1-6-1",children:[]},{level:2,title:"2022.10.3",slug:"_2022-10-3",link:"#_2022-10-3",children:[]},{level:2,title:"2022.8.28 v1.5.10",slug:"_2022-8-28-v1-5-10",link:"#_2022-8-28-v1-5-10",children:[]},{level:2,title:"2022.6.20 v1.5.8",slug:"_2022-6-20-v1-5-8",link:"#_2022-6-20-v1-5-8",children:[]},{level:2,title:"2022.5.29 v1.5.6",slug:"_2022-5-29-v1-5-6",link:"#_2022-5-29-v1-5-6",children:[]},{level:2,title:"2022.4.24 v1.5.5",slug:"_2022-4-24-v1-5-5",link:"#_2022-4-24-v1-5-5",children:[]},{level:2,title:"2022.3.13 v1.5.4",slug:"_2022-3-13-v1-5-4",link:"#_2022-3-13-v1-5-4",children:[]},{level:2,title:"2022.1.29 v1.5.3",slug:"_2022-1-29-v1-5-3",link:"#_2022-1-29-v1-5-3",children:[]},{level:2,title:"2021.12.24 v1.5.2",slug:"_2021-12-24-v1-5-2",link:"#_2021-12-24-v1-5-2",children:[]},{level:2,title:"2021.12.15 v1.5.1",slug:"_2021-12-15-v1-5-1",link:"#_2021-12-15-v1-5-1",children:[]},{level:2,title:"2021.10.20 v1.5.0",slug:"_2021-10-20-v1-5-0",link:"#_2021-10-20-v1-5-0",children:[]},{level:2,title:"2021.9.23 v1.4.5",slug:"_2021-9-23-v1-4-5",link:"#_2021-9-23-v1-4-5",children:[]},{level:2,title:"2021.9.16",slug:"_2021-9-16",link:"#_2021-9-16",children:[]},{level:2,title:"2021.9.8 v1.4.3",slug:"_2021-9-8-v1-4-3",link:"#_2021-9-8-v1-4-3",children:[]},{level:2,title:"2021.7.14",slug:"_2021-7-14",link:"#_2021-7-14",children:[]},{level:2,title:"2021.6.21",slug:"_2021-6-21",link:"#_2021-6-21",children:[]},{level:2,title:"2021.5.1",slug:"_2021-5-1",link:"#_2021-5-1",children:[]},{level:2,title:"2021.4.26",slug:"_2021-4-26",link:"#_2021-4-26",children:[]},{level:2,title:"2021.4.12",slug:"_2021-4-12",link:"#_2021-4-12",children:[]},{level:2,title:"2021.4.6",slug:"_2021-4-6",link:"#_2021-4-6",children:[]},{level:2,title:"2021.4.4",slug:"_2021-4-4",link:"#_2021-4-4",children:[]},{level:2,title:"2021.4.1 v1.4.2",slug:"_2021-4-1-v1-4-2",link:"#_2021-4-1-v1-4-2",children:[]},{level:2,title:"2021.3.25",slug:"_2021-3-25",link:"#_2021-3-25",children:[]},{level:2,title:"2021.3.15",slug:"_2021-3-15",link:"#_2021-3-15",children:[]},{level:2,title:"2021.3.14 v1.4.0",slug:"_2021-3-14-v1-4-0",link:"#_2021-3-14-v1-4-0",children:[]},{level:2,title:"2021.3.3 1.3.1",slug:"_2021-3-3-1-3-1",link:"#_2021-3-3-1-3-1",children:[]},{level:2,title:"2021.2.14 1.3.0",slug:"_2021-2-14-1-3-0",link:"#_2021-2-14-1-3-0",children:[]},{level:2,title:"2021.01.31 1.2.4",slug:"_2021-01-31-1-2-4",link:"#_2021-01-31-1-2-4",children:[]},{level:2,title:"2021.01.25",slug:"_2021-01-25",link:"#_2021-01-25",children:[]},{level:2,title:"2021.01.22 1.2.3",slug:"_2021-01-22-1-2-3",link:"#_2021-01-22-1-2-3",children:[]},{level:2,title:"2021.01.19",slug:"_2021-01-19",link:"#_2021-01-19",children:[]},{level:2,title:"2021.01.17",slug:"_2021-01-17",link:"#_2021-01-17",children:[]},{level:2,title:"2021.01.15 1.2.2",slug:"_2021-01-15-1-2-2",link:"#_2021-01-15-1-2-2",children:[]},{level:2,title:"2021.01.12",slug:"_2021-01-12",link:"#_2021-01-12",children:[]},{level:2,title:"2021.01.10 1.2.1",slug:"_2021-01-10-1-2-1",link:"#_2021-01-10-1-2-1",children:[]},{level:2,title:"2021.01.07",slug:"_2021-01-07",link:"#_2021-01-07",children:[]},{level:2,title:"2021.01.05",slug:"_2021-01-05",link:"#_2021-01-05",children:[]},{level:2,title:"2021.01.03",slug:"_2021-01-03",link:"#_2021-01-03",children:[]},{level:2,title:"2021.01.01",slug:"_2021-01-01",link:"#_2021-01-01",children:[]},{level:2,title:"2020.12.29",slug:"_2020-12-29",link:"#_2020-12-29",children:[]},{level:2,title:"2020.12.25 1.1.5",slug:"_2020-12-25-1-1-5",link:"#_2020-12-25-1-1-5",children:[]},{level:2,title:"2020.12.24",slug:"_2020-12-24",link:"#_2020-12-24",children:[]},{level:2,title:"2020.12.23",slug:"_2020-12-23",link:"#_2020-12-23",children:[]},{level:2,title:"2020.12.21",slug:"_2020-12-21",link:"#_2020-12-21",children:[]},{level:2,title:"2020.12.18 1.1.4",slug:"_2020-12-18-1-1-4",link:"#_2020-12-18-1-1-4",children:[]},{level:2,title:"2020.12.17",slug:"_2020-12-17",link:"#_2020-12-17",children:[]},{level:2,title:"2020.12.15",slug:"_2020-12-15",link:"#_2020-12-15",children:[]},{level:2,title:"2020.12.11 1.1.3",slug:"_2020-12-11-1-1-3",link:"#_2020-12-11-1-1-3",children:[]},{level:2,title:"2020.12.06 1.1.2",slug:"_2020-12-06-1-1-2",link:"#_2020-12-06-1-1-2",children:[]},{level:2,title:"2020.12.04",slug:"_2020-12-04",link:"#_2020-12-04",children:[]},{level:2,title:"2020.11.27",slug:"_2020-11-27",link:"#_2020-11-27",children:[]},{level:2,title:"2020.11.25 1.0.0",slug:"_2020-11-25-1-0-0",link:"#_2020-11-25-1-0-0",children:[]},{level:2,title:"2020.11.23",slug:"_2020-11-23",link:"#_2020-11-23",children:[]}],path:"/about/news.html",pathLocale:"/",extraFields:[]},{title:"配置文件",headers:[{level:2,title:"概述",slug:"概述",link:"#概述",children:[]},{level:2,title:"基础配置模块",slug:"基础配置模块",link:"#基础配置模块",children:[]}],path:"/config/",pathLocale:"/",extraFields:[]},{title:"API 接口",headers:[{level:2,title:"ApiObject",slug:"apiobject",link:"#apiobject",children:[]},{level:2,title:"相关配置",slug:"相关配置",link:"#相关配置",children:[]},{level:2,title:"支持的 API 列表",slug:"支持的-api-列表",link:"#支持的-api-列表",children:[{level:3,title:"HandlerService",slug:"handlerservice",link:"#handlerservice",children:[]},{level:3,title:"RoutingService",slug:"routingservice",link:"#routingservice",children:[]},{level:3,title:"LoggerService",slug:"loggerservice",link:"#loggerservice",children:[]},{level:3,title:"StatsService",slug:"statsservice",link:"#statsservice",children:[]},{level:3,title:"ReflectionService",slug:"reflectionservice",link:"#reflectionservice",children:[]}]},{level:2,title:"API 调用示例",slug:"api-调用示例",link:"#api-调用示例",children:[]}],path:"/config/api.html",pathLocale:"/",extraFields:[]},{title:"内置 DNS 服务器",headers:[{level:2,title:"DNS 服务器",slug:"dns-服务器",link:"#dns-服务器",children:[]},{level:2,title:"DNS 处理流程",slug:"dns-处理流程",link:"#dns-处理流程",children:[]},{level:2,title:"DnsObject",slug:"dnsobject",link:"#dnsobject",children:[{level:3,title:"ServerObject",slug:"serverobject",link:"#serverobject",children:[]}]}],path:"/config/dns.html",pathLocale:"/",extraFields:[]},{title:"FakeDNS",headers:[{level:2,title:"FakeDNSObject",slug:"fakednsobject",link:"#fakednsobject",children:[{level:3,title:"如何使用?",slug:"如何使用",link:"#如何使用",children:[]},{level:3,title:"与其它类型 DNS 搭配使用",slug:"与其它类型-dns-搭配使用",link:"#与其它类型-dns-搭配使用",children:[]}]}],path:"/config/fakedns.html",pathLocale:"/",extraFields:[]},{title:"入站代理",headers:[{level:2,title:"InboundObject",slug:"inboundobject",link:"#inboundobject",children:[{level:3,title:"SniffingObject",slug:"sniffingobject",link:"#sniffingobject",children:[]},{level:3,title:"AllocateObject",slug:"allocateobject",link:"#allocateobject",children:[]}]}],path:"/config/inbound.html",pathLocale:"/",extraFields:[]},{title:"日志配置",headers:[{level:2,title:"LogObject",slug:"logobject",link:"#logobject",children:[]}],path:"/config/log.html",pathLocale:"/",extraFields:[]},{title:"Metrics",headers:[{level:2,title:"相关配置",slug:"相关配置",link:"#相关配置",children:[]},{level:2,title:"使用方法",slug:"使用方法",link:"#使用方法",children:[{level:3,title:"pprof",slug:"pprof",link:"#pprof",children:[]},{level:3,title:"expvars",slug:"expvars",link:"#expvars",children:[]},{level:3,title:"Additional",slug:"additional",link:"#additional",children:[]}]}],path:"/config/metrics.html",pathLocale:"/",extraFields:[]},{title:"连接观测",headers:[{level:2,title:"ObservatoryObject",slug:"observatoryobject",link:"#observatoryobject",children:[]},{level:2,title:"BurstObservatoryObject",slug:"burstobservatoryobject",link:"#burstobservatoryobject",children:[{level:3,title:"PingConfigObject",slug:"pingconfigobject",link:"#pingconfigobject",children:[]}]}],path:"/config/observatory.html",pathLocale:"/",extraFields:[]},{title:"出站代理(Mux、XUDP)",headers:[{level:2,title:"OutboundObject",slug:"outboundobject",link:"#outboundobject",children:[{level:3,title:"ProxySettingsObject",slug:"proxysettingsobject",link:"#proxysettingsobject",children:[]},{level:3,title:"MuxObject",slug:"muxobject",link:"#muxobject",children:[]}]}],path:"/config/outbound.html",pathLocale:"/",extraFields:[]},{title:"本地策略",headers:[{level:2,title:"PolicyObject",slug:"policyobject",link:"#policyobject",children:[{level:3,title:"LevelPolicyObject",slug:"levelpolicyobject",link:"#levelpolicyobject",children:[]},{level:3,title:"SystemPolicyObject",slug:"systempolicyobject",link:"#systempolicyobject",children:[]}]}],path:"/config/policy.html",pathLocale:"/",extraFields:[]},{title:"反向代理",headers:[{level:2,title:"ReverseObject",slug:"reverseobject",link:"#reverseobject",children:[{level:3,title:"BridgeObject",slug:"bridgeobject",link:"#bridgeobject",children:[]},{level:3,title:"PortalObject",slug:"portalobject",link:"#portalobject",children:[]}]},{level:2,title:"完整配置样例",slug:"完整配置样例",link:"#完整配置样例",children:[{level:3,title:"bridge 配置",slug:"bridge-配置",link:"#bridge-配置",children:[]},{level:3,title:"portal 配置",slug:"portal-配置",link:"#portal-配置",children:[]}]}],path:"/config/reverse.html",pathLocale:"/",extraFields:[]},{title:"路由",headers:[{level:2,title:"RoutingObject",slug:"routingobject",link:"#routingobject",children:[{level:3,title:"RuleObject",slug:"ruleobject",link:"#ruleobject",children:[]},{level:3,title:"BalancerObject",slug:"balancerobject",link:"#balancerobject",children:[]},{level:3,title:"负载均衡配置示例",slug:"负载均衡配置示例",link:"#负载均衡配置示例",children:[]},{level:3,title:"预定义域名列表",slug:"预定义域名列表",link:"#预定义域名列表",children:[]}]}],path:"/config/routing.html",pathLocale:"/",extraFields:[]},{title:"统计信息",headers:[{level:2,title:"StatsObject",slug:"statsobject",link:"#statsobject",children:[]},{level:2,title:"获取统计信息",slug:"获取统计信息",link:"#获取统计信息",children:[]}],path:"/config/stats.html",pathLocale:"/",extraFields:[]},{title:"传输方式(uTLS、REALITY)",headers:[{level:2,title:"StreamSettingsObject",slug:"streamsettingsobject",link:"#streamsettingsobject",children:[{level:3,title:"TLSObject",slug:"tlsobject",link:"#tlsobject",children:[]},{level:3,title:"RealityObject",slug:"realityobject",link:"#realityobject",children:[]},{level:3,title:"SockoptObject",slug:"sockoptobject",link:"#sockoptobject",children:[]}]}],path:"/config/transport.html",pathLocale:"/",extraFields:[]},{title:"开发指南",headers:[{level:2,title:"编译文档",slug:"编译文档",link:"#编译文档",children:[]},{level:2,title:"设计思路",slug:"设计思路",link:"#设计思路",children:[]},{level:2,title:"开发规范",slug:"开发规范",link:"#开发规范",children:[]},{level:2,title:"协议详解",slug:"协议详解",link:"#协议详解",children:[{level:3,title:"VLESS 协议",slug:"vless-协议",link:"#vless-协议",children:[]},{level:3,title:"VMess 协议",slug:"vmess-协议",link:"#vmess-协议",children:[]},{level:3,title:"Mux.Cool 协议",slug:"mux-cool-协议",link:"#mux-cool-协议",children:[]},{level:3,title:"mKCP 协议",slug:"mkcp-协议",link:"#mkcp-协议",children:[]}]}],path:"/development/",pathLocale:"/",extraFields:[]},{title:"快速入门",headers:[{level:2,title:"下载安装",slug:"下载安装",link:"#下载安装",children:[]},{level:2,title:"配置运行",slug:"配置运行",link:"#配置运行",children:[]},{level:2,title:"命令参数",slug:"命令参数",link:"#命令参数",children:[]},{level:2,title:"改进文档",slug:"改进文档",link:"#改进文档",children:[]},{level:2,title:"小小白白话文",slug:"小小白白话文",link:"#小小白白话文",children:[]},{level:2,title:"入门技巧",slug:"入门技巧",link:"#入门技巧",children:[]},{level:2,title:"进阶文档",slug:"进阶文档",link:"#进阶文档",children:[]}],path:"/document/",pathLocale:"/",extraFields:[]},{title:"命令参数",headers:[{level:2,title:"获取基本命令",slug:"获取基本命令",link:"#获取基本命令",children:[{level:3,title:"xray run",slug:"xray-run",link:"#xray-run",children:[]},{level:3,title:"xray version",slug:"xray-version",link:"#xray-version",children:[]},{level:3,title:"xray api",slug:"xray-api",link:"#xray-api",children:[]},{level:3,title:"xray convert",slug:"xray-convert",link:"#xray-convert",children:[]},{level:3,title:"xray tls",slug:"xray-tls",link:"#xray-tls",children:[]},{level:3,title:"xray uuid",slug:"xray-uuid",link:"#xray-uuid",children:[]},{level:3,title:"xray x25519",slug:"xray-x25519",link:"#xray-x25519",children:[]},{level:3,title:"xray wg",slug:"xray-wg",link:"#xray-wg",children:[]}]}],path:"/document/command.html",pathLocale:"/",extraFields:[]},{title:"配置运行",headers:[{level:2,title:"服务端配置",slug:"服务端配置",link:"#服务端配置",children:[]},{level:2,title:"客户端配置",slug:"客户端配置",link:"#客户端配置",children:[]},{level:2,title:"运行",slug:"运行",link:"#运行",children:[]}],path:"/document/config.html",pathLocale:"/",extraFields:[]},{title:"为 Project X 的文档贡献",headers:[{level:2,title:"改进文档",slug:"改进文档",link:"#改进文档",children:[]},{level:2,title:"发现问题?",slug:"发现问题",link:"#发现问题",children:[]}],path:"/document/document.html",pathLocale:"/",extraFields:[]},{title:"下载安装",headers:[{level:2,title:"平台支持",slug:"平台支持",link:"#平台支持",children:[]},{level:2,title:"下载 Xray",slug:"下载-xray",link:"#下载-xray",children:[]},{level:2,title:"验证安装包",slug:"验证安装包",link:"#验证安装包",children:[]},{level:2,title:"Windows 安装方式",slug:"windows-安装方式",link:"#windows-安装方式",children:[]},{level:2,title:"macOS 安装方式",slug:"macos-安装方式",link:"#macos-安装方式",children:[]},{level:2,title:"Linux 安装方式",slug:"linux-安装方式",link:"#linux-安装方式",children:[{level:3,title:"安装脚本",slug:"安装脚本",link:"#安装脚本",children:[]},{level:3,title:"Arch Linux",slug:"arch-linux",link:"#arch-linux",children:[]},{level:3,title:"Linuxbrew",slug:"linuxbrew",link:"#linuxbrew",children:[]},{level:3,title:"Debian",slug:"debian",link:"#debian",children:[]},{level:3,title:"Gentoo",slug:"gentoo",link:"#gentoo",children:[]}]},{level:2,title:"Docker 安装方式",slug:"docker-安装方式",link:"#docker-安装方式",children:[{level:3,title:"Docker image 的文件结构",slug:"docker-image-的文件结构",link:"#docker-image-的文件结构",children:[]}]}],path:"/document/install.html",pathLocale:"/",extraFields:[]},{title:"",headers:[{level:2,title:"XTLS? Xray? V2Ray?",slug:"xtls-xray-v2ray",link:"#xtls-xray-v2ray",children:[{level:3,title:"Who are we?",slug:"who-are-we",link:"#who-are-we",children:[]},{level:3,title:"Help Xray become stronger",slug:"help-xray-become-stronger",link:"#help-xray-become-stronger",children:[]},{level:3,title:"Telegram",slug:"telegram",link:"#telegram",children:[]},{level:3,title:"Thanks",slug:"thanks",link:"#thanks",children:[]},{level:3,title:"More about project X",slug:"more-about-project-x",link:"#more-about-project-x",children:[]},{level:3,title:"License",slug:"license",link:"#license",children:[]},{level:3,title:"Stargazers over time",slug:"stargazers-over-time",link:"#stargazers-over-time",children:[]}]}],path:"/en/",pathLocale:"/en/",extraFields:[]},{title:"",headers:[{level:2,title:"XTLS? Xray? V2Ray?",slug:"xtls-xray-v2ray",link:"#xtls-xray-v2ray",children:[{level:3,title:"Кто мы?",slug:"кто-мы",link:"#кто-мы",children:[]},{level:3,title:"Помогите Xray стать сильнее",slug:"помогите-xray-стать-сильнее",link:"#помогите-xray-стать-сильнее",children:[]},{level:3,title:"Telegram",slug:"telegram",link:"#telegram",children:[]},{level:3,title:"Благодарности",slug:"благодарности",link:"#благодарности",children:[]},{level:3,title:"Подробнее о Project X",slug:"подробнее-о-project-x",link:"#подробнее-о-project-x",children:[]},{level:3,title:"Лицензия",slug:"лицензия",link:"#лицензия",children:[]},{level:3,title:"Динамика звезд на GitHub",slug:"динамика-звезд-на-github",link:"#динамика-звезд-на-github",children:[]}]}],path:"/ru/",pathLocale:"/ru/",extraFields:[]},{title:"Browser Dialer",headers:[{level:2,title:"背景",slug:"背景",link:"#背景",children:[]},{level:2,title:"配置方法",slug:"配置方法",link:"#配置方法",children:[]},{level:2,title:"内部通信机制",slug:"内部通信机制",link:"#内部通信机制",children:[]},{level:2,title:"WebSocket",slug:"websocket",link:"#websocket",children:[]},{level:2,title:"SplitHTTP",slug:"splithttp",link:"#splithttp",children:[]}],path:"/config/features/browser_dialer.html",pathLocale:"/",extraFields:[]},{title:"环境变量",headers:[{level:2,title:"资源文件路径",slug:"资源文件路径",link:"#资源文件路径",children:[]},{level:2,title:"配置文件位置",slug:"配置文件位置",link:"#配置文件位置",children:[]},{level:2,title:"多配置目录",slug:"多配置目录",link:"#多配置目录",children:[]}],path:"/config/features/env.html",pathLocale:"/",extraFields:[]},{title:"Fallback 回落",headers:[{level:2,title:"fallbacks 配置",slug:"fallbacks-配置",link:"#fallbacks-配置",children:[{level:3,title:"FallbackObject",slug:"fallbackobject",link:"#fallbackobject",children:[]},{level:3,title:"补充说明",slug:"补充说明",link:"#补充说明",children:[]}]},{level:2,title:"Fallbacks 设计理论",slug:"fallbacks-设计理论",link:"#fallbacks-设计理论",children:[]}],path:"/config/features/fallback.html",pathLocale:"/",extraFields:[]},{title:"多文件配置",headers:[{level:2,title:"多文件启动",slug:"多文件启动",link:"#多文件启动",children:[]},{level:2,title:"规则说明",slug:"规则说明",link:"#规则说明",children:[{level:3,title:"普通对象({})",slug:"普通对象",link:"#普通对象",children:[]},{level:3,title:"数组([])",slug:"数组",link:"#数组",children:[]}]},{level:2,title:"配置例子",slug:"配置例子",link:"#配置例子",children:[]}],path:"/config/features/multiple.html",pathLocale:"/",extraFields:[]},{title:"XTLS 深度剖析",headers:[],path:"/config/features/xtls.html",pathLocale:"/",extraFields:[]},{title:"Dokodemo-Door",headers:[{level:2,title:"InboundConfigurationObject",slug:"inboundconfigurationobject",link:"#inboundconfigurationobject",children:[]},{level:2,title:"用处",slug:"用处",link:"#用处",children:[]},{level:2,title:"透明代理配置样例",slug:"透明代理配置样例",link:"#透明代理配置样例",children:[]}],path:"/config/inbounds/dokodemo.html",pathLocale:"/",extraFields:[]},{title:"HTTP",headers:[{level:2,title:"InboundConfigurationObject",slug:"inboundconfigurationobject",link:"#inboundconfigurationobject",children:[{level:3,title:"AccountObject",slug:"accountobject",link:"#accountobject",children:[]}]}],path:"/config/inbounds/http.html",pathLocale:"/",extraFields:[]},{title:"Shadowsocks",headers:[{level:2,title:"InboundConfigurationObject",slug:"inboundconfigurationobject",link:"#inboundconfigurationobject",children:[]},{level:2,title:"ClientObject",slug:"clientobject",link:"#clientobject",children:[]}],path:"/config/inbounds/shadowsocks.html",pathLocale:"/",extraFields:[]},{title:"Socks",headers:[{level:2,title:"InboundConfigurationObject",slug:"inboundconfigurationobject",link:"#inboundconfigurationobject",children:[{level:3,title:"AccountObject",slug:"accountobject",link:"#accountobject",children:[]}]}],path:"/config/inbounds/socks.html",pathLocale:"/",extraFields:[]},{title:"Trojan",headers:[{level:2,title:"InboundConfigurationObject",slug:"inboundconfigurationobject",link:"#inboundconfigurationobject",children:[{level:3,title:"ClientObject",slug:"clientobject",link:"#clientobject",children:[]}]}],path:"/config/inbounds/trojan.html",pathLocale:"/",extraFields:[]},{title:"VLESS(XTLS Vision Seed)",headers:[{level:2,title:"InboundConfigurationObject",slug:"inboundconfigurationobject",link:"#inboundconfigurationobject",children:[{level:3,title:"ClientObject",slug:"clientobject",link:"#clientobject",children:[]}]}],path:"/config/inbounds/vless.html",pathLocale:"/",extraFields:[]},{title:"VMess",headers:[{level:2,title:"InboundConfigurationObject",slug:"inboundconfigurationobject",link:"#inboundconfigurationobject",children:[{level:3,title:"ClientObject",slug:"clientobject",link:"#clientobject",children:[]},{level:3,title:"DetourObject",slug:"detourobject",link:"#detourobject",children:[]},{level:3,title:"DefaultObject",slug:"defaultobject",link:"#defaultobject",children:[]}]}],path:"/config/inbounds/vmess.html",pathLocale:"/",extraFields:[]},{title:"Wireguard",headers:[{level:2,title:"InboundConfigurationObject",slug:"inboundconfigurationobject",link:"#inboundconfigurationobject",children:[{level:3,title:"Peers",slug:"peers",link:"#peers",children:[]}]}],path:"/config/inbounds/wireguard.html",pathLocale:"/",extraFields:[]},{title:"Blackhole",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[{level:3,title:"ResponseObject",slug:"responseobject",link:"#responseobject",children:[]}]}],path:"/config/outbounds/blackhole.html",pathLocale:"/",extraFields:[]},{title:"DNS",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[]},{level:2,title:"DNS 配置实例",slug:"dns-配置实例",link:"#dns-配置实例",children:[]}],path:"/config/outbounds/dns.html",pathLocale:"/",extraFields:[]},{title:"Freedom(fragment、noises)",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[]}],path:"/config/outbounds/freedom.html",pathLocale:"/",extraFields:[]},{title:"HTTP",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[{level:3,title:"ServerObject",slug:"serverobject",link:"#serverobject",children:[]}]}],path:"/config/outbounds/http.html",pathLocale:"/",extraFields:[]},{title:"Loopback",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[{level:3,title:"如何使用?",slug:"如何使用",link:"#如何使用",children:[]}]}],path:"/config/outbounds/loopback.html",pathLocale:"/",extraFields:[]},{title:"Shadowsocks",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[{level:3,title:"ServerObject",slug:"serverobject",link:"#serverobject",children:[]}]}],path:"/config/outbounds/shadowsocks.html",pathLocale:"/",extraFields:[]},{title:"Socks",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[{level:3,title:"ServerObject",slug:"serverobject",link:"#serverobject",children:[]}]}],path:"/config/outbounds/socks.html",pathLocale:"/",extraFields:[]},{title:"Trojan",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[{level:3,title:"ServerObject",slug:"serverobject",link:"#serverobject",children:[]}]}],path:"/config/outbounds/trojan.html",pathLocale:"/",extraFields:[]},{title:"VLESS(XTLS Vision Seed)",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[{level:3,title:"ServerObject",slug:"serverobject",link:"#serverobject",children:[]},{level:3,title:"UserObject",slug:"userobject",link:"#userobject",children:[]}]}],path:"/config/outbounds/vless.html",pathLocale:"/",extraFields:[]},{title:"VMess",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[{level:3,title:"ServerObject",slug:"serverobject",link:"#serverobject",children:[]}]}],path:"/config/outbounds/vmess.html",pathLocale:"/",extraFields:[]},{title:"Wireguard",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[{level:3,title:"Peers",slug:"peers",link:"#peers",children:[]}]}],path:"/config/outbounds/wireguard.html",pathLocale:"/",extraFields:[]},{title:"gRPC",headers:[{level:2,title:"GRPCObject",slug:"grpcobject",link:"#grpcobject",children:[]}],path:"/config/transports/grpc.html",pathLocale:"/",extraFields:[]},{title:"HTTP/2",headers:[{level:2,title:"HttpObject",slug:"httpobject",link:"#httpobject",children:[]}],path:"/config/transports/h2.html",pathLocale:"/",extraFields:[]},{title:"HTTPUpgrade",headers:[{level:2,title:"HttpUpgradeObject",slug:"httpupgradeobject",link:"#httpupgradeobject",children:[]}],path:"/config/transports/httpupgrade.html",pathLocale:"/",extraFields:[]},{title:"mKCP",headers:[{level:2,title:"KcpObject",slug:"kcpobject",link:"#kcpobject",children:[{level:3,title:"HeaderObject",slug:"headerobject",link:"#headerobject",children:[]}]},{level:2,title:"鸣谢",slug:"鸣谢",link:"#鸣谢",children:[]},{level:2,title:"对 KCP 协议的改进",slug:"对-kcp-协议的改进",link:"#对-kcp-协议的改进",children:[{level:3,title:"更小的协议头",slug:"更小的协议头",link:"#更小的协议头",children:[]},{level:3,title:"确认包重传",slug:"确认包重传",link:"#确认包重传",children:[]},{level:3,title:"连接状态控制",slug:"连接状态控制",link:"#连接状态控制",children:[]}]}],path:"/config/transports/mkcp.html",pathLocale:"/",extraFields:[]},{title:"SplitHTTP(H2、QUIC H3)",headers:[{level:2,title:"SplitHttpObject",slug:"splithttpobject",link:"#splithttpobject",children:[]},{level:2,title:"HTTP 版本",slug:"http-版本",link:"#http-版本",children:[{level:3,title:"客户端行为",slug:"客户端行为",link:"#客户端行为",children:[]},{level:3,title:"服务端行为",slug:"服务端行为",link:"#服务端行为",children:[]},{level:3,title:"小提示",slug:"小提示",link:"#小提示",children:[]}]},{level:2,title:"Browser Dialer",slug:"browser-dialer",link:"#browser-dialer",children:[]},{level:2,title:"协议细节",slug:"协议细节",link:"#协议细节",children:[]}],path:"/config/transports/splithttp.html",pathLocale:"/",extraFields:[]},{title:"TCP",headers:[{level:2,title:"TcpObject",slug:"tcpobject",link:"#tcpobject",children:[{level:3,title:"NoneHeaderObject",slug:"noneheaderobject",link:"#noneheaderobject",children:[]},{level:3,title:"HttpHeaderObject",slug:"httpheaderobject",link:"#httpheaderobject",children:[]}]}],path:"/config/transports/tcp.html",pathLocale:"/",extraFields:[]},{title:"WebSocket",headers:[{level:2,title:"WebSocketObject",slug:"websocketobject",link:"#websocketobject",children:[]},{level:2,title:"Browser Dialer",slug:"browser-dialer",link:"#browser-dialer",children:[]}],path:"/config/transports/websocket.html",pathLocale:"/",extraFields:[]},{title:"编译文档",headers:[{level:2,title:"前序工作",slug:"前序工作",link:"#前序工作",children:[]},{level:2,title:"拉取 Xray 源代码",slug:"拉取-xray-源代码",link:"#拉取-xray-源代码",children:[]},{level:2,title:"构建二进制",slug:"构建二进制",link:"#构建二进制",children:[{level:3,title:"Windows(Powershell):",slug:"windows-powershell",link:"#windows-powershell",children:[]},{level:3,title:"macOS, Linux:",slug:"macos-linux",link:"#macos-linux",children:[]}]},{level:2,title:"交叉编译:",slug:"交叉编译",link:"#交叉编译",children:[]},{level:2,title:"可复现构建:",slug:"可复现构建",link:"#可复现构建",children:[]}],path:"/development/intro/compile.html",pathLocale:"/",extraFields:[]},{title:"设计目标",headers:[{level:2,title:"架构",slug:"架构",link:"#架构",children:[{level:3,title:"应用层",slug:"应用层",link:"#应用层",children:[]},{level:3,title:"代理层",slug:"代理层",link:"#代理层",children:[]},{level:3,title:"传输层",slug:"传输层",link:"#传输层",children:[]}]}],path:"/development/intro/design.html",pathLocale:"/",extraFields:[]},{title:"开发规范",headers:[{level:2,title:"基本",slug:"基本",link:"#基本",children:[{level:3,title:"版本控制",slug:"版本控制",link:"#版本控制",children:[]},{level:3,title:"分支(Branch)",slug:"分支-branch",link:"#分支-branch",children:[]},{level:3,title:"发布(Release)",slug:"发布-release",link:"#发布-release",children:[]},{level:3,title:"引用其它项目",slug:"引用其它项目",link:"#引用其它项目",children:[]}]},{level:2,title:"开发流程",slug:"开发流程",link:"#开发流程",children:[{level:3,title:"写代码之前",slug:"写代码之前",link:"#写代码之前",children:[]},{level:3,title:"修改代码",slug:"修改代码",link:"#修改代码",children:[]},{level:3,title:"Pull Request",slug:"pull-request",link:"#pull-request",children:[]},{level:3,title:"对代码的修改",slug:"对代码的修改",link:"#对代码的修改",children:[]}]},{level:2,title:"Xray 编码规范",slug:"xray-编码规范",link:"#xray-编码规范",children:[{level:3,title:"代码结构",slug:"代码结构",link:"#代码结构",children:[]},{level:3,title:"编码规范",slug:"编码规范",link:"#编码规范",children:[]}]}],path:"/development/intro/guide.html",pathLocale:"/",extraFields:[]},{title:"mKCP 协议",headers:[{level:2,title:"版本",slug:"版本",link:"#版本",children:[]},{level:2,title:"依赖",slug:"依赖",link:"#依赖",children:[{level:3,title:"底层协议",slug:"底层协议",link:"#底层协议",children:[]},{level:3,title:"函数",slug:"函数",link:"#函数",children:[]}]},{level:2,title:"通讯过程",slug:"通讯过程",link:"#通讯过程",children:[]},{level:2,title:"数据格式",slug:"数据格式",link:"#数据格式",children:[{level:3,title:"数据包",slug:"数据包",link:"#数据包",children:[]},{level:3,title:"数据片段",slug:"数据片段",link:"#数据片段",children:[]},{level:3,title:"确认片段",slug:"确认片段",link:"#确认片段",children:[]},{level:3,title:"心跳片段",slug:"心跳片段",link:"#心跳片段",children:[]}]}],path:"/development/protocols/mkcp.html",pathLocale:"/",extraFields:[]},{title:"Mux.Cool 协议",headers:[{level:2,title:"版本",slug:"版本",link:"#版本",children:[]},{level:2,title:"依赖",slug:"依赖",link:"#依赖",children:[{level:3,title:"底层协议",slug:"底层协议",link:"#底层协议",children:[]}]},{level:2,title:"通讯过程",slug:"通讯过程",link:"#通讯过程",children:[{level:3,title:"客户端行为",slug:"客户端行为",link:"#客户端行为",children:[]},{level:3,title:"服务器端行为",slug:"服务器端行为",link:"#服务器端行为",children:[]}]},{level:2,title:"传输格式",slug:"传输格式",link:"#传输格式",children:[{level:3,title:"帧格式",slug:"帧格式",link:"#帧格式",children:[]},{level:3,title:"元数据",slug:"元数据",link:"#元数据",children:[]},{level:3,title:"新建子连接 (New)",slug:"新建子连接-new",link:"#新建子连接-new",children:[]},{level:3,title:"保持子连接 (Keep)",slug:"保持子连接-keep",link:"#保持子连接-keep",children:[]},{level:3,title:"关闭子连接 (End)",slug:"关闭子连接-end",link:"#关闭子连接-end",children:[]},{level:3,title:"保持连接 (KeepAlive)",slug:"保持连接-keepalive",link:"#保持连接-keepalive",children:[]}]},{level:2,title:"应用",slug:"应用",link:"#应用",children:[]}],path:"/development/protocols/muxcool.html",pathLocale:"/",extraFields:[]},{title:"VLESS 协议",headers:[{level:2,title:"Request & Response",slug:"request-response",link:"#request-response",children:[]},{level:2,title:"ProtoBuf",slug:"protobuf",link:"#protobuf",children:[]},{level:2,title:"Schedulers Flow",slug:"schedulers-flow",link:"#schedulers-flow",children:[]},{level:2,title:"Encryption",slug:"encryption",link:"#encryption",children:[]},{level:2,title:"UDP issues",slug:"udp-issues",link:"#udp-issues",children:[]},{level:2,title:"客户端开发指引",slug:"客户端开发指引",link:"#客户端开发指引",children:[]},{level:2,title:"VLESS 分享链接标准",slug:"vless-分享链接标准",link:"#vless-分享链接标准",children:[]}],path:"/development/protocols/vless.html",pathLocale:"/",extraFields:[]},{title:"VMess 协议",headers:[{level:2,title:"版本",slug:"版本",link:"#版本",children:[]},{level:2,title:"依赖",slug:"依赖",link:"#依赖",children:[{level:3,title:"底层协议",slug:"底层协议",link:"#底层协议",children:[]},{level:3,title:"用户 ID",slug:"用户-id",link:"#用户-id",children:[]},{level:3,title:"函数",slug:"函数",link:"#函数",children:[]}]},{level:2,title:"通讯过程",slug:"通讯过程",link:"#通讯过程",children:[]},{level:2,title:"客户端请求",slug:"客户端请求",link:"#客户端请求",children:[{level:3,title:"认证信息",slug:"认证信息",link:"#认证信息",children:[]},{level:3,title:"指令部分",slug:"指令部分",link:"#指令部分",children:[]},{level:3,title:"数据部分",slug:"数据部分",link:"#数据部分",children:[]}]},{level:2,title:"服务器应答",slug:"服务器应答",link:"#服务器应答",children:[{level:3,title:"动态端口指令",slug:"动态端口指令",link:"#动态端口指令",children:[]}]},{level:2,title:"注释",slug:"注释",link:"#注释",children:[]}],path:"/development/protocols/vmess.html",pathLocale:"/",extraFields:[]},{title:"小小白白话文",headers:[],path:"/document/level-0/",pathLocale:"/",extraFields:[]},{title:"【第 1 章】 小小白白话文",headers:[{level:2,title:"1.1 这篇文档是写给谁的?",slug:"_1-1-这篇文档是写给谁的",link:"#_1-1-这篇文档是写给谁的",children:[]},{level:2,title:"1.2 这篇文档不是写给谁的?",slug:"_1-2-这篇文档不是写给谁的",link:"#_1-2-这篇文档不是写给谁的",children:[]},{level:2,title:"1.3 郑重声明及其他声明",slug:"_1-3-郑重声明及其他声明",link:"#_1-3-郑重声明及其他声明",children:[]},{level:2,title:"1.4 为什么自建是个难题?",slug:"_1-4-为什么自建是个难题",link:"#_1-4-为什么自建是个难题",children:[]},{level:2,title:"1.5 “用机场不就行了?”",slug:"_1-5-用机场不就行了",link:"#_1-5-用机场不就行了",children:[]},{level:2,title:"1.6 那么你到底要不要自建呢?",slug:"_1-6-那么你到底要不要自建呢",link:"#_1-6-那么你到底要不要自建呢",children:[]},{level:2,title:"1.7 题外啰嗦几句",slug:"_1-7-题外啰嗦几句",link:"#_1-7-题外啰嗦几句",children:[]},{level:2,title:"1.8 你的进度",slug:"_1-8-你的进度",link:"#_1-8-你的进度",children:[]}],path:"/document/level-0/ch01-preface.html",pathLocale:"/",extraFields:[]},{title:"【第 2 章】原料准备篇",headers:[{level:2,title:"2.1 获取一台 VPS",slug:"_2-1-获取一台-vps",link:"#_2-1-获取一台-vps",children:[]},{level:2,title:"2.2 获取一个心仪的域名",slug:"_2-2-获取一个心仪的域名",link:"#_2-2-获取一个心仪的域名",children:[]},{level:2,title:"2.3 你本地电脑上需要安装的软件",slug:"_2-3-你本地电脑上需要安装的软件",link:"#_2-3-你本地电脑上需要安装的软件",children:[]},{level:2,title:"2.4 你的进度",slug:"_2-4-你的进度",link:"#_2-4-你的进度",children:[]}],path:"/document/level-0/ch02-preparation.html",pathLocale:"/",extraFields:[]},{title:"【第 3 章】远程登录篇",headers:[{level:2,title:"3.1 远程登录 VPS (PuTTY)",slug:"_3-1-远程登录-vps-putty",link:"#_3-1-远程登录-vps-putty",children:[]},{level:2,title:"3.2 成功登录 SSH!初识命令行界面!",slug:"_3-2-成功登录-ssh-初识命令行界面",link:"#_3-2-成功登录-ssh-初识命令行界面",children:[]},{level:2,title:"3.3 第一次更新 Linux 的软件!",slug:"_3-3-第一次更新-linux-的软件",link:"#_3-3-第一次更新-linux-的软件",children:[]},{level:2,title:"3.4 你的进度",slug:"_3-4-你的进度",link:"#_3-4-你的进度",children:[]}],path:"/document/level-0/ch03-ssh.html",pathLocale:"/",extraFields:[]},{title:"【第 4 章】安全防护篇",headers:[{level:2,title:"4.1 为什么要做安全防护",slug:"_4-1-为什么要做安全防护",link:"#_4-1-为什么要做安全防护",children:[]},{level:2,title:"4.2 具体的风险到底是什么",slug:"_4-2-具体的风险到底是什么",link:"#_4-2-具体的风险到底是什么",children:[]},{level:2,title:"4.3 我们要做的安全防护有哪些",slug:"_4-3-我们要做的安全防护有哪些",link:"#_4-3-我们要做的安全防护有哪些",children:[]},{level:2,title:"4.4 将 SSH 远程登录端口修改为非 22 端口",slug:"_4-4-将-ssh-远程登录端口修改为非-22-端口",link:"#_4-4-将-ssh-远程登录端口修改为非-22-端口",children:[]},{level:2,title:"4.5 建立非 root 的新用户",slug:"_4-5-建立非-root-的新用户",link:"#_4-5-建立非-root-的新用户",children:[]},{level:2,title:"4.6 禁用 root 用户 SSH 远程登录",slug:"_4-6-禁用-root-用户-ssh-远程登录",link:"#_4-6-禁用-root-用户-ssh-远程登录",children:[]},{level:2,title:"4.7 使用 RSA 密钥登录并禁用密码登录",slug:"_4-7-使用-rsa-密钥登录并禁用密码登录",link:"#_4-7-使用-rsa-密钥登录并禁用密码登录",children:[]},{level:2,title:"4.8 你的进度",slug:"_4-8-你的进度",link:"#_4-8-你的进度",children:[]}],path:"/document/level-0/ch04-security.html",pathLocale:"/",extraFields:[]},{title:"【第 5 章】网站建设篇",headers:[{level:2,title:"5.1 为什么要做一个网站?",slug:"_5-1-为什么要做一个网站",link:"#_5-1-为什么要做一个网站",children:[]},{level:2,title:"5.2 登录 VPS、安装运行 Nginx",slug:"_5-2-登录-vps、安装运行-nginx",link:"#_5-2-登录-vps、安装运行-nginx",children:[]},{level:2,title:"5.3 创建一个最简单的网页",slug:"_5-3-创建一个最简单的网页",link:"#_5-3-创建一个最简单的网页",children:[]},{level:2,title:"5.4 常见错误的说明",slug:"_5-4-常见错误的说明",link:"#_5-4-常见错误的说明",children:[]},{level:2,title:"5.5 你的进度",slug:"_5-5-你的进度",link:"#_5-5-你的进度",children:[]}],path:"/document/level-0/ch05-webpage.html",pathLocale:"/",extraFields:[]},{title:"【第 6 章】证书管理篇",headers:[{level:2,title:"6.1 申请 TLS 证书",slug:"_6-1-申请-tls-证书",link:"#_6-1-申请-tls-证书",children:[]},{level:2,title:"6.2 安装 acme.sh",slug:"_6-2-安装-acme-sh",link:"#_6-2-安装-acme-sh",children:[]},{level:2,title:"6.3 测试证书申请",slug:"_6-3-测试证书申请",link:"#_6-3-测试证书申请",children:[]},{level:2,title:"6.4 正式证书申请",slug:"_6-4-正式证书申请",link:"#_6-4-正式证书申请",children:[]},{level:2,title:"6.5 证书安装",slug:"_6-5-证书安装",link:"#_6-5-证书安装",children:[]},{level:2,title:"6.6 你的进度",slug:"_6-6-你的进度",link:"#_6-6-你的进度",children:[]}],path:"/document/level-0/ch06-certificates.html",pathLocale:"/",extraFields:[]},{title:"【第 7 章】Xray 服务器篇",headers:[{level:2,title:"7.1 博观而约取,厚积而薄发",slug:"_7-1-博观而约取-厚积而薄发",link:"#_7-1-博观而约取-厚积而薄发",children:[]},{level:2,title:"7.2 安装 Xray",slug:"_7-2-安装-xray",link:"#_7-2-安装-xray",children:[]},{level:2,title:"7.3 给 Xray 配置 TLS 证书",slug:"_7-3-给-xray-配置-tls-证书",link:"#_7-3-给-xray-配置-tls-证书",children:[]},{level:2,title:"7.4 配置 Xray",slug:"_7-4-配置-xray",link:"#_7-4-配置-xray",children:[]},{level:2,title:"7.5 启动 Xray 服务!!(并查看服务状态)",slug:"_7-5-启动-xray-服务-并查看服务状态",link:"#_7-5-启动-xray-服务-并查看服务状态",children:[]},{level:2,title:"7.6 回顾 systemd 进行基本的服务管理",slug:"_7-6-回顾-systemd-进行基本的服务管理",link:"#_7-6-回顾-systemd-进行基本的服务管理",children:[]},{level:2,title:"7.7 服务器优化之一:开启 BBR",slug:"_7-7-服务器优化之一-开启-bbr",link:"#_7-7-服务器优化之一-开启-bbr",children:[]},{level:2,title:"7.8 服务器优化之二:开启 HTTP 自动跳转 HTTPS",slug:"_7-8-服务器优化之二-开启-http-自动跳转-https",link:"#_7-8-服务器优化之二-开启-http-自动跳转-https",children:[]},{level:2,title:"7.9 服务器优化之三:更丰富的回落",slug:"_7-9-服务器优化之三-更丰富的回落",link:"#_7-9-服务器优化之三-更丰富的回落",children:[]},{level:2,title:"7.10 你的进度",slug:"_7-10-你的进度",link:"#_7-10-你的进度",children:[]},{level:2,title:"7.11 重要勘误",slug:"_7-11-重要勘误",link:"#_7-11-重要勘误",children:[]}],path:"/document/level-0/ch07-xray-server.html",pathLocale:"/",extraFields:[]},{title:"【第 8 章】Xray 客户端篇",headers:[{level:2,title:"8.1 Xray 的工作原理简述",slug:"_8-1-xray-的工作原理简述",link:"#_8-1-xray-的工作原理简述",children:[]},{level:2,title:"8.2 客户端与服务器端正确连接",slug:"_8-2-客户端与服务器端正确连接",link:"#_8-2-客户端与服务器端正确连接",children:[]},{level:2,title:"8.3 附加题 1:在 PC 端手工配置 xray-core",slug:"_8-3-附加题-1-在-pc-端手工配置-xray-core",link:"#_8-3-附加题-1-在-pc-端手工配置-xray-core",children:[]},{level:2,title:"8.4 附加题 2:在 PC 端手工运行 xray-core",slug:"_8-4-附加题-2-在-pc-端手工运行-xray-core",link:"#_8-4-附加题-2-在-pc-端手工运行-xray-core",children:[]},{level:2,title:"8.5 附加题 3:在 PC 端开机自动运行 xray-core",slug:"_8-5-附加题-3-在-pc-端开机自动运行-xray-core",link:"#_8-5-附加题-3-在-pc-端开机自动运行-xray-core",children:[]},{level:2,title:"8.6 圆满完成!",slug:"_8-6-圆满完成",link:"#_8-6-圆满完成",children:[]},{level:2,title:"8.7 TO INFINITY AND BEYOND!",slug:"_8-7-to-infinity-and-beyond",link:"#_8-7-to-infinity-and-beyond",children:[]}],path:"/document/level-0/ch08-xray-clients.html",pathLocale:"/",extraFields:[]},{title:"【第 9 章】附录",headers:[{level:2,title:"1. 小小白白 Linux 基础命令索引",slug:"_1-小小白白-linux-基础命令索引",link:"#_1-小小白白-linux-基础命令索引",children:[]},{level:2,title:"2. 小小白白 Linux 重要配置文件索引",slug:"_2-小小白白-linux-重要配置文件索引",link:"#_2-小小白白-linux-重要配置文件索引",children:[]},{level:2,title:"3. 小小白白 Xray 重要文件索引",slug:"_3-小小白白-xray-重要文件索引",link:"#_3-小小白白-xray-重要文件索引",children:[]}],path:"/document/level-0/ch09-appendix.html",pathLocale:"/",extraFields:[]},{title:"入门技巧",headers:[],path:"/document/level-1/",pathLocale:"/",extraFields:[]},{title:"回落 (fallbacks) 功能简析",headers:[{level:2,title:"1. 回顾《小小白白话文》中的回落",slug:"_1-回顾《小小白白话文》中的回落",link:"#_1-回顾《小小白白话文》中的回落",children:[]},{level:2,title:"2. 重新认识回落 (WHAT, HOW v1)",slug:"_2-重新认识回落-what-how-v1",link:"#_2-重新认识回落-what-how-v1",children:[]},{level:2,title:"3. 为什么要回落 (WHY v1)",slug:"_3-为什么要回落-why-v1",link:"#_3-为什么要回落-why-v1",children:[]},{level:2,title:"4. 重新认识【回落の完全体】 (WHAT, WHY, HOW v2)",slug:"_4-重新认识【回落の完全体】-what-why-how-v2",link:"#_4-重新认识【回落の完全体】-what-why-how-v2",children:[]},{level:2,title:"5. 多层回落示例及解读",slug:"_5-多层回落示例及解读",link:"#_5-多层回落示例及解读",children:[{level:3,title:"5.1 首先,我将服务器端配置的 443 监听段摘抄如下:",slug:"_5-1-首先-我将服务器端配置的-443-监听段摘抄如下",link:"#_5-1-首先-我将服务器端配置的-443-监听段摘抄如下",children:[]},{level:3,title:"5.2 后续监听处理的配置段摘抄如下:",slug:"_5-2-后续监听处理的配置段摘抄如下",link:"#_5-2-后续监听处理的配置段摘抄如下",children:[]}]},{level:2,title:"6. 结语",slug:"_6-结语",link:"#_6-结语",children:[]},{level:2,title:"7. 附加题",slug:"_7-附加题",link:"#_7-附加题",children:[]}],path:"/document/level-1/fallbacks-lv1.html",pathLocale:"/",extraFields:[]},{title:"SNI 回落",headers:[{level:2,title:"应用情景",slug:"应用情景",link:"#应用情景",children:[]},{level:2,title:"SNI 简介",slug:"sni-简介",link:"#sni-简介",children:[]},{level:2,title:"思路",slug:"思路",link:"#思路",children:[]},{level:2,title:"添加 DNS 记录",slug:"添加-dns-记录",link:"#添加-dns-记录",children:[]},{level:2,title:"申请 TLS 证书",slug:"申请-tls-证书",link:"#申请-tls-证书",children:[]},{level:2,title:"Xray 配置",slug:"xray-配置",link:"#xray-配置",children:[]},{level:2,title:"Nginx 配置",slug:"nginx-配置",link:"#nginx-配置",children:[]},{level:2,title:"Caddy 配置",slug:"caddy-配置",link:"#caddy-配置",children:[]},{level:2,title:"参考",slug:"参考",link:"#参考",children:[]},{level:2,title:"引用",slug:"引用",link:"#引用",children:[]}],path:"/document/level-1/fallbacks-with-sni.html",pathLocale:"/",extraFields:[]},{title:"路由 (routing) 功能简析(上)",headers:[{level:2,title:"1. 初识【路由】三兄弟",slug:"_1-初识【路由】三兄弟",link:"#_1-初识【路由】三兄弟",children:[]},{level:2,title:"2. 基本功: “兄弟一条心”",slug:"_2-基本功-兄弟一条心",link:"#_2-基本功-兄弟一条心",children:[{level:3,title:"2.1 入站",slug:"_2-1-入站",link:"#_2-1-入站",children:[]},{level:3,title:"2.3 路由",slug:"_2-3-路由",link:"#_2-3-路由",children:[]},{level:3,title:"2.4 路由配置项解析之一:流量筛选的依据",slug:"_2-4-路由配置项解析之一-流量筛选的依据",link:"#_2-4-路由配置项解析之一-流量筛选的依据",children:[]}]},{level:2,title:"3. 小试牛刀: “三分天下” 之 “域名分流”",slug:"_3-小试牛刀-三分天下-之-域名分流",link:"#_3-小试牛刀-三分天下-之-域名分流",children:[{level:3,title:"3.1 入站",slug:"_3-1-入站",link:"#_3-1-入站",children:[]},{level:3,title:"3.2 出站",slug:"_3-2-出站",link:"#_3-2-出站",children:[]},{level:3,title:"3.3 路由",slug:"_3-3-路由",link:"#_3-3-路由",children:[]},{level:3,title:"3.4 简析域名文件: geosite.dat",slug:"_3-4-简析域名文件-geosite-dat",link:"#_3-4-简析域名文件-geosite-dat",children:[]},{level:3,title:"3.5 所以 geosite.dat 到底是什么?不是有个 GFWList 吗?",slug:"_3-5-所以-geosite-dat-到底是什么-不是有个-gfwlist-吗",link:"#_3-5-所以-geosite-dat-到底是什么-不是有个-gfwlist-吗",children:[]},{level:3,title:"3.6 军师锦囊藏奇兵:一条隐藏的路由规则",slug:"_3-6-军师锦囊藏奇兵-一条隐藏的路由规则",link:"#_3-6-军师锦囊藏奇兵-一条隐藏的路由规则",children:[]},{level:3,title:"3.7 再看“三分天下”的大地图",slug:"_3-7-再看-三分天下-的大地图",link:"#_3-7-再看-三分天下-的大地图",children:[]}]},{level:2,title:"4. “三分天下” 之 “蜀魏争雄”",slug:"_4-三分天下-之-蜀魏争雄",link:"#_4-三分天下-之-蜀魏争雄",children:[]},{level:2,title:"5. 攻城略池 - 多种路由匹配条件",slug:"_5-攻城略池-多种路由匹配条件",link:"#_5-攻城略池-多种路由匹配条件",children:[]}],path:"/document/level-1/routing-lv1-part1.html",pathLocale:"/",extraFields:[]},{title:"路由 (routing) 功能简析(下)",headers:[{level:2,title:"5. 攻城略池 - 多种路由匹配条件",slug:"_5-攻城略池-多种路由匹配条件",link:"#_5-攻城略池-多种路由匹配条件",children:[{level:3,title:"5.1 基于指定域名分流:[domain], [full] 等",slug:"_5-1-基于指定域名分流-domain-full-等",link:"#_5-1-基于指定域名分流-domain-full-等",children:[]},{level:3,title:"5.2 基于 IP 文件分流:geoip.dat",slug:"_5-2-基于-ip-文件分流-geoip-dat",link:"#_5-2-基于-ip-文件分流-geoip-dat",children:[]},{level:3,title:"5.3 基于指定 IP 地址分流",slug:"_5-3-基于指定-ip-地址分流",link:"#_5-3-基于指定-ip-地址分流",children:[]},{level:3,title:"5.4 基于协议类型分流:[protocol] 等",slug:"_5-4-基于协议类型分流-protocol-等",link:"#_5-4-基于协议类型分流-protocol-等",children:[]},{level:3,title:"5.5 基于更多条件的分流",slug:"_5-5-基于更多条件的分流",link:"#_5-5-基于更多条件的分流",children:[]}]},{level:2,title:"6. “霸业初定”:路由规则整体回顾",slug:"_6-霸业初定-路由规则整体回顾",link:"#_6-霸业初定-路由规则整体回顾",children:[]},{level:2,title:"7. 路由配置常见错误",slug:"_7-路由配置常见错误",link:"#_7-路由配置常见错误",children:[{level:3,title:"7.1 错误示范",slug:"_7-1-错误示范",link:"#_7-1-错误示范",children:[]},{level:3,title:"7.2 正确示范",slug:"_7-2-正确示范",link:"#_7-2-正确示范",children:[]}]},{level:2,title:"8. 明修栈道、暗渡陈仓",slug:"_8-明修栈道、暗渡陈仓",link:"#_8-明修栈道、暗渡陈仓",children:[{level:3,title:'8.1 域名策略: "AsIs"',slug:"_8-1-域名策略-asis",link:"#_8-1-域名策略-asis",children:[]},{level:3,title:'8.2 域名策略: "IPIfNonMatch"',slug:"_8-2-域名策略-ipifnonmatch",link:"#_8-2-域名策略-ipifnonmatch",children:[]},{level:3,title:'8.3 域名策略: "IPOnDemand"',slug:"_8-3-域名策略-ipondemand",link:"#_8-3-域名策略-ipondemand",children:[]}]},{level:2,title:"9. 思考题",slug:"_9-思考题",link:"#_9-思考题",children:[]},{level:2,title:"10. 结语",slug:"_10-结语",link:"#_10-结语",children:[]},{level:2,title:"11. 尾注",slug:"_11-尾注",link:"#_11-尾注",children:[]}],path:"/document/level-1/routing-lv1-part2.html",pathLocale:"/",extraFields:[]},{title:"Xray 的工作模式",headers:[{level:2,title:"单服务器模式",slug:"单服务器模式",link:"#单服务器模式",children:[]},{level:2,title:"桥接模式",slug:"桥接模式",link:"#桥接模式",children:[]},{level:2,title:"工作原理",slug:"工作原理",link:"#工作原理",children:[]}],path:"/document/level-1/work.html",pathLocale:"/",extraFields:[]},{title:"进阶文档",headers:[],path:"/document/level-2/",pathLocale:"/",extraFields:[]},{title:"GID 透明代理",headers:[{level:2,title:"思路",slug:"思路",link:"#思路",children:[]},{level:2,title:"配置过程",slug:"配置过程",link:"#配置过程",children:[{level:3,title:"1. 前期准备",slug:"_1-前期准备",link:"#_1-前期准备",children:[]},{level:3,title:"2. 添加用户(安卓用户请忽略)",slug:"_2-添加用户-安卓用户请忽略",link:"#_2-添加用户-安卓用户请忽略",children:[]},{level:3,title:"3. 配置运行 Xray,配置 iptables 规则",slug:"_3-配置运行-xray-配置-iptables-规则",link:"#_3-配置运行-xray-配置-iptables-规则",children:[]}]},{level:2,title:"下面提供一个实现 tproxy 全局代理的完整配置过程",slug:"下面提供一个实现-tproxy-全局代理的完整配置过程",link:"#下面提供一个实现-tproxy-全局代理的完整配置过程",children:[{level:3,title:"1. 完成 前期准备 和 添加用户",slug:"_1-完成-前期准备-和-添加用户",link:"#_1-完成-前期准备-和-添加用户",children:[]},{level:3,title:"2. 准备 Xray 配置文件",slug:"_2-准备-xray-配置文件",link:"#_2-准备-xray-配置文件",children:[]},{level:3,title:"3. 配置最大文件打开数&运行 Xray 客户端",slug:"_3-配置最大文件打开数-运行-xray-客户端",link:"#_3-配置最大文件打开数-运行-xray-客户端",children:[]},{level:3,title:"4. 设置 iptables 规则",slug:"_4-设置-iptables-规则",link:"#_4-设置-iptables-规则",children:[]}]}],path:"/document/level-2/iptables_gid.html",pathLocale:"/",extraFields:[]},{title:"Nginx 或 Haproxy 搭建 TLS 隧道隐藏指纹",headers:[{level:2,title:"编译 nginx --with-stream",slug:"编译-nginx-with-stream",link:"#编译-nginx-with-stream",children:[]},{level:2,title:"配置 nginx",slug:"配置-nginx",link:"#配置-nginx",children:[]},{level:2,title:"xray 配置",slug:"xray-配置",link:"#xray-配置",children:[]},{level:2,title:"客户端及服务端启动服务",slug:"客户端及服务端启动服务",link:"#客户端及服务端启动服务",children:[]},{level:2,title:"结束",slug:"结束",link:"#结束",children:[]},{level:2,title:"HTTPS 隧道",slug:"https-隧道",link:"#https-隧道",children:[{level:3,title:"haproxy_client 配置 (运行前去掉注释)",slug:"haproxy-client-配置-运行前去掉注释",link:"#haproxy-client-配置-运行前去掉注释",children:[]},{level:3,title:"haproxy_server 配置 (运行前去掉注释)",slug:"haproxy-server-配置-运行前去掉注释",link:"#haproxy-server-配置-运行前去掉注释",children:[]},{level:3,title:"xray 配置",slug:"xray-配置-1",link:"#xray-配置-1",children:[]}]},{level:2,title:"WebSocket over HTTP/2",slug:"websocket-over-http-2",link:"#websocket-over-http-2",children:[{level:3,title:"haproxy_client 配置",slug:"haproxy-client-配置",link:"#haproxy-client-配置",children:[]},{level:3,title:"haproxy_server 配置",slug:"haproxy-server-配置",link:"#haproxy-server-配置",children:[]},{level:3,title:"xray 配置",slug:"xray-配置-2",link:"#xray-配置-2",children:[]}]},{level:2,title:"gRPC over HTTP/2",slug:"grpc-over-http-2",link:"#grpc-over-http-2",children:[{level:3,title:"haproxy_client 配置",slug:"haproxy-client-配置-1",link:"#haproxy-client-配置-1",children:[]},{level:3,title:"haproxy_server 配置",slug:"haproxy-server-配置-1",link:"#haproxy-server-配置-1",children:[]},{level:3,title:"xray 配置",slug:"xray-配置-3",link:"#xray-配置-3",children:[]},{level:3,title:"haproxy_client 配置",slug:"haproxy-client-配置-2",link:"#haproxy-client-配置-2",children:[]},{level:3,title:"haproxy_server 配置",slug:"haproxy-server-配置-2",link:"#haproxy-server-配置-2",children:[]},{level:3,title:"xray 配置",slug:"xray-配置-4",link:"#xray-配置-4",children:[]}]}],path:"/document/level-2/nginx_or_haproxy_tls_tunnel.html",pathLocale:"/",extraFields:[]},{title:"出站流量重定向",headers:[{level:2,title:"前言",slug:"前言",link:"#前言",children:[]},{level:2,title:"1、安装代理或者 VPN 软件(例如 Wireguard、IPsec 等)",slug:"_1、安装代理或者-vpn-软件-例如-wireguard、ipsec-等",link:"#_1、安装代理或者-vpn-软件-例如-wireguard、ipsec-等",children:[]},{level:2,title:"2、编辑 VPN 配置文件(以 WireGuard 为例)",slug:"_2、编辑-vpn-配置文件-以-wireguard-为例",link:"#_2、编辑-vpn-配置文件-以-wireguard-为例",children:[]},{level:2,title:"3、启用 WireGuard 网络接口",slug:"_3、启用-wireguard-网络接口",link:"#_3、启用-wireguard-网络接口",children:[]},{level:2,title:"4、Xray-core 配置文件修改",slug:"_4、xray-core-配置文件修改",link:"#_4、xray-core-配置文件修改",children:[]},{level:2,title:"5、系统设置配置",slug:"_5、系统设置配置",link:"#_5、系统设置配置",children:[]},{level:2,title:"6、完成 WireGuard 相关设置",slug:"_6、完成-wireguard-相关设置",link:"#_6、完成-wireguard-相关设置",children:[]},{level:2,title:"后记",slug:"后记",link:"#后记",children:[]},{level:2,title:"感谢",slug:"感谢",link:"#感谢",children:[]}],path:"/document/level-2/redirect.html",pathLocale:"/",extraFields:[]},{title:"TProxy 透明代理",headers:[{level:2,title:"开始之前",slug:"开始之前",link:"#开始之前",children:[]},{level:2,title:"Xray 配置",slug:"xray-配置",link:"#xray-配置",children:[]},{level:2,title:"策略路由配置",slug:"策略路由配置",link:"#策略路由配置",children:[]},{level:2,title:"Netfilter 配置",slug:"netfilter-配置",link:"#netfilter-配置",children:[]},{level:2,title:"配置永久化与开机自启",slug:"配置永久化与开机自启",link:"#配置永久化与开机自启",children:[]}],path:"/document/level-2/tproxy.html",pathLocale:"/",extraFields:[]},{title:"TProxy 透明代理 (ipv4 and ipv6)",headers:[{level:2,title:"Xray 配置",slug:"xray-配置",link:"#xray-配置",children:[{level:3,title:"客户端配置",slug:"客户端配置",link:"#客户端配置",children:[]},{level:3,title:"服务端配置",slug:"服务端配置",link:"#服务端配置",children:[]}]},{level:2,title:"Netfilter 配置",slug:"netfilter-配置",link:"#netfilter-配置",children:[{level:3,title:"首先设置策略路由",slug:"首先设置策略路由",link:"#首先设置策略路由",children:[]},{level:3,title:"使用 iptables",slug:"使用-iptables",link:"#使用-iptables",children:[]},{level:3,title:"使用 nftables",slug:"使用-nftables",link:"#使用-nftables",children:[]},{level:3,title:"开机自动运行 Netfilter 配置",slug:"开机自动运行-netfilter-配置",link:"#开机自动运行-netfilter-配置",children:[]}]},{level:2,title:"局域网设备上网设置",slug:"局域网设备上网设置",link:"#局域网设备上网设置",children:[{level:3,title:"方法一",slug:"方法一",link:"#方法一",children:[]},{level:3,title:"方法二",slug:"方法二",link:"#方法二",children:[]}]},{level:2,title:"Finally",slug:"finally",link:"#finally",children:[]},{level:2,title:"写在最后",slug:"写在最后",link:"#写在最后",children:[]}],path:"/document/level-2/tproxy_ipv4_and_ipv6.html",pathLocale:"/",extraFields:[]},{title:"流量统计",headers:[{level:2,title:"查看流量信息",slug:"查看流量信息",link:"#查看流量信息",children:[]},{level:2,title:"流量信息的处理",slug:"流量信息的处理",link:"#流量信息的处理",children:[]}],path:"/document/level-2/traffic_stats.html",pathLocale:"/",extraFields:[]},{title:"通过 Cloudflare Warp 增强代理安全性",headers:[{level:2,title:"申请 Warp 账户",slug:"申请-warp-账户",link:"#申请-warp-账户",children:[{level:3,title:"感谢 Cloudflare 推动自由的互联网,现在你可以免费使用 Warp 服务,连接的时候会根据出口自动选择最近的服务器",slug:"感谢-cloudflare-推动自由的互联网-现在你可以免费使用-warp-服务-连接的时候会根据出口自动选择最近的服务器",link:"#感谢-cloudflare-推动自由的互联网-现在你可以免费使用-warp-服务-连接的时候会根据出口自动选择最近的服务器",children:[]}]},{level:2,title:"在服务端分流回国流量至 warp",slug:"在服务端分流回国流量至-warp",link:"#在服务端分流回国流量至-warp",children:[]},{level:2,title:"客户端使用 warp 链式代理",slug:"客户端使用-warp-链式代理",link:"#客户端使用-warp-链式代理",children:[]}],path:"/document/level-2/warp.html",pathLocale:"/",extraFields:[]},{title:"The Great Chronicles",headers:[{level:2,title:"2024.9.12",slug:"_2024-9-12",link:"#_2024-9-12",children:[]},{level:2,title:"2024.9.7 v24.9.7",slug:"_2024-9-7-v24-9-7",link:"#_2024-9-7-v24-9-7",children:[]},{level:2,title:"2024.8.30 v1.8.24",slug:"_2024-8-30-v1-8-24",link:"#_2024-8-30-v1-8-24",children:[]},{level:2,title:"2024.8.26",slug:"_2024-8-26",link:"#_2024-8-26",children:[]},{level:2,title:"2024.8.3",slug:"_2024-8-3",link:"#_2024-8-3",children:[]},{level:2,title:"2024.7.29 v1.8.23",slug:"_2024-7-29-v1-8-23",link:"#_2024-7-29-v1-8-23",children:[]},{level:2,title:"2024.7.22 v1.8.21",slug:"_2024-7-22-v1-8-21",link:"#_2024-7-22-v1-8-21",children:[]},{level:2,title:"2024.7.16",slug:"_2024-7-16",link:"#_2024-7-16",children:[]},{level:2,title:"2024.7.15",slug:"_2024-7-15",link:"#_2024-7-15",children:[]},{level:2,title:"2024.6.18 v1.8.16",slug:"_2024-6-18-v1-8-16",link:"#_2024-6-18-v1-8-16",children:[]},{level:2,title:"2024.6.2",slug:"_2024-6-2",link:"#_2024-6-2",children:[]},{level:2,title:"2024.4.26 v1.8.11",slug:"_2024-4-26-v1-8-11",link:"#_2024-4-26-v1-8-11",children:[]},{level:2,title:"2024.4.20",slug:"_2024-4-20",link:"#_2024-4-20",children:[]},{level:2,title:"2024.4.13",slug:"_2024-4-13",link:"#_2024-4-13",children:[]},{level:2,title:"2024.3.18 v1.8.10",slug:"_2024-3-18-v1-8-10",link:"#_2024-3-18-v1-8-10",children:[]},{level:2,title:"2024.3.11 v1.8.9",slug:"_2024-3-11-v1-8-9",link:"#_2024-3-11-v1-8-9",children:[]},{level:2,title:"2024.2.29",slug:"_2024-2-29",link:"#_2024-2-29",children:[]},{level:2,title:"2024.2.25 v1.8.8",slug:"_2024-2-25-v1-8-8",link:"#_2024-2-25-v1-8-8",children:[]},{level:2,title:"2024.1.9",slug:"_2024-1-9",link:"#_2024-1-9",children:[]},{level:2,title:"2023.11.21",slug:"_2023-11-21",link:"#_2023-11-21",children:[]},{level:2,title:"2023.11.18 v1.8.6",slug:"_2023-11-18-v1-8-6",link:"#_2023-11-18-v1-8-6",children:[]},{level:2,title:"2023.9.30",slug:"_2023-9-30",link:"#_2023-9-30",children:[]},{level:2,title:"2023.8.29 v1.8.4",slug:"_2023-8-29-v1-8-4",link:"#_2023-8-29-v1-8-4",children:[]},{level:2,title:"2023.7.22",slug:"_2023-7-22",link:"#_2023-7-22",children:[]},{level:2,title:"2023.7.7",slug:"_2023-7-7",link:"#_2023-7-7",children:[]},{level:2,title:"2023.6.30",slug:"_2023-6-30",link:"#_2023-6-30",children:[]},{level:2,title:"2023.6.27",slug:"_2023-6-27",link:"#_2023-6-27",children:[]},{level:2,title:"2023.6.19 v1.8.3",slug:"_2023-6-19-v1-8-3",link:"#_2023-6-19-v1-8-3",children:[]},{level:2,title:"2023.6.6",slug:"_2023-6-6",link:"#_2023-6-6",children:[]},{level:2,title:"2023.4.21",slug:"_2023-4-21",link:"#_2023-4-21",children:[]},{level:2,title:"2023.4.20",slug:"_2023-4-20",link:"#_2023-4-20",children:[]},{level:2,title:"2023.4.19",slug:"_2023-4-19",link:"#_2023-4-19",children:[]},{level:2,title:"2023.4.18 v1.8.1",slug:"_2023-4-18-v1-8-1",link:"#_2023-4-18-v1-8-1",children:[]},{level:2,title:"2023.4.6",slug:"_2023-4-6",link:"#_2023-4-6",children:[]},{level:2,title:"2023.3.29",slug:"_2023-3-29",link:"#_2023-3-29",children:[]},{level:2,title:"2023.3.19",slug:"_2023-3-19",link:"#_2023-3-19",children:[]},{level:2,title:"2023.3.9 v1.8.0",slug:"_2023-3-9-v1-8-0",link:"#_2023-3-9-v1-8-0",children:[]},{level:2,title:"2023.3.4",slug:"_2023-3-4",link:"#_2023-3-4",children:[]},{level:2,title:"2023.3.2",slug:"_2023-3-2",link:"#_2023-3-2",children:[]},{level:2,title:"2023.2.16",slug:"_2023-2-16",link:"#_2023-2-16",children:[]},{level:2,title:"2023.2.9",slug:"_2023-2-9",link:"#_2023-2-9",children:[]},{level:2,title:"2023.2.8 v1.7.5",slug:"_2023-2-8-v1-7-5",link:"#_2023-2-8-v1-7-5",children:[]},{level:2,title:"2023.1.29",slug:"_2023-1-29",link:"#_2023-1-29",children:[]},{level:2,title:"2022.12.26 v1.7.0",slug:"_2022-12-26-v1-7-0",link:"#_2022-12-26-v1-7-0",children:[]},{level:2,title:"2022.11.28 v1.6.5",slug:"_2022-11-28-v1-6-5",link:"#_2022-11-28-v1-6-5",children:[]},{level:2,title:"2022.11.7 v1.6.3",slug:"_2022-11-7-v1-6-3",link:"#_2022-11-7-v1-6-3",children:[]},{level:2,title:"2022.10.29 v1.6.2",slug:"_2022-10-29-v1-6-2",link:"#_2022-10-29-v1-6-2",children:[]},{level:2,title:"2022.10.22 v1.6.1",slug:"_2022-10-22-v1-6-1",link:"#_2022-10-22-v1-6-1",children:[]},{level:2,title:"2022.10.3",slug:"_2022-10-3",link:"#_2022-10-3",children:[]},{level:2,title:"2022.8.28 v1.5.10",slug:"_2022-8-28-v1-5-10",link:"#_2022-8-28-v1-5-10",children:[]},{level:2,title:"2022.6.20 v1.5.8",slug:"_2022-6-20-v1-5-8",link:"#_2022-6-20-v1-5-8",children:[]},{level:2,title:"2022.5.29 v1.5.6",slug:"_2022-5-29-v1-5-6",link:"#_2022-5-29-v1-5-6",children:[]},{level:2,title:"2022.4.24 v1.5.5",slug:"_2022-4-24-v1-5-5",link:"#_2022-4-24-v1-5-5",children:[]},{level:2,title:"2022.3.13 v1.5.4",slug:"_2022-3-13-v1-5-4",link:"#_2022-3-13-v1-5-4",children:[]},{level:2,title:"2022.1.29 v1.5.3",slug:"_2022-1-29-v1-5-3",link:"#_2022-1-29-v1-5-3",children:[]},{level:2,title:"2021.12.24 v1.5.2",slug:"_2021-12-24-v1-5-2",link:"#_2021-12-24-v1-5-2",children:[]},{level:2,title:"2021.12.15 v1.5.1",slug:"_2021-12-15-v1-5-1",link:"#_2021-12-15-v1-5-1",children:[]},{level:2,title:"2021.10.20 v1.5.0",slug:"_2021-10-20-v1-5-0",link:"#_2021-10-20-v1-5-0",children:[]},{level:2,title:"2021.9.23 v1.4.5",slug:"_2021-9-23-v1-4-5",link:"#_2021-9-23-v1-4-5",children:[]},{level:2,title:"2021.9.16",slug:"_2021-9-16",link:"#_2021-9-16",children:[]},{level:2,title:"2021.9.8 v1.4.3",slug:"_2021-9-8-v1-4-3",link:"#_2021-9-8-v1-4-3",children:[]},{level:2,title:"2021.7.14",slug:"_2021-7-14",link:"#_2021-7-14",children:[]},{level:2,title:"2021.6.21",slug:"_2021-6-21",link:"#_2021-6-21",children:[]},{level:2,title:"2021.5.1",slug:"_2021-5-1",link:"#_2021-5-1",children:[]},{level:2,title:"2021.4.26",slug:"_2021-4-26",link:"#_2021-4-26",children:[]},{level:2,title:"2021.4.12",slug:"_2021-4-12",link:"#_2021-4-12",children:[]},{level:2,title:"2021.4.6",slug:"_2021-4-6",link:"#_2021-4-6",children:[]},{level:2,title:"2021.4.4",slug:"_2021-4-4",link:"#_2021-4-4",children:[]},{level:2,title:"2021.4.1 v1.4.2",slug:"_2021-4-1-v1-4-2",link:"#_2021-4-1-v1-4-2",children:[]},{level:2,title:"2021.3.25",slug:"_2021-3-25",link:"#_2021-3-25",children:[]},{level:2,title:"2021.3.15",slug:"_2021-3-15",link:"#_2021-3-15",children:[]},{level:2,title:"2021.3.14 v1.4.0",slug:"_2021-3-14-v1-4-0",link:"#_2021-3-14-v1-4-0",children:[]},{level:2,title:"2021.3.3 1.3.1",slug:"_2021-3-3-1-3-1",link:"#_2021-3-3-1-3-1",children:[]},{level:2,title:"2021.2.14 1.3.0",slug:"_2021-2-14-1-3-0",link:"#_2021-2-14-1-3-0",children:[]},{level:2,title:"2021.01.31 1.2.4",slug:"_2021-01-31-1-2-4",link:"#_2021-01-31-1-2-4",children:[]},{level:2,title:"2021.01.25",slug:"_2021-01-25",link:"#_2021-01-25",children:[]},{level:2,title:"2021.01.22 1.2.3",slug:"_2021-01-22-1-2-3",link:"#_2021-01-22-1-2-3",children:[]},{level:2,title:"2021.01.19",slug:"_2021-01-19",link:"#_2021-01-19",children:[]},{level:2,title:"2021.01.17",slug:"_2021-01-17",link:"#_2021-01-17",children:[]},{level:2,title:"2021.01.15 1.2.2",slug:"_2021-01-15-1-2-2",link:"#_2021-01-15-1-2-2",children:[]},{level:2,title:"2021.01.12",slug:"_2021-01-12",link:"#_2021-01-12",children:[]},{level:2,title:"2021.01.10 1.2.1",slug:"_2021-01-10-1-2-1",link:"#_2021-01-10-1-2-1",children:[]},{level:2,title:"2021.01.07",slug:"_2021-01-07",link:"#_2021-01-07",children:[]},{level:2,title:"2021.01.05",slug:"_2021-01-05",link:"#_2021-01-05",children:[]},{level:2,title:"2021.01.03",slug:"_2021-01-03",link:"#_2021-01-03",children:[]},{level:2,title:"2021.01.01",slug:"_2021-01-01",link:"#_2021-01-01",children:[]},{level:2,title:"2020.12.29",slug:"_2020-12-29",link:"#_2020-12-29",children:[]},{level:2,title:"2020.12.25 1.1.5",slug:"_2020-12-25-1-1-5",link:"#_2020-12-25-1-1-5",children:[]},{level:2,title:"2020.12.24",slug:"_2020-12-24",link:"#_2020-12-24",children:[]},{level:2,title:"2020.12.23",slug:"_2020-12-23",link:"#_2020-12-23",children:[]},{level:2,title:"2020.12.21",slug:"_2020-12-21",link:"#_2020-12-21",children:[]},{level:2,title:"2020.12.18 1.1.4",slug:"_2020-12-18-1-1-4",link:"#_2020-12-18-1-1-4",children:[]},{level:2,title:"2020.12.17",slug:"_2020-12-17",link:"#_2020-12-17",children:[]},{level:2,title:"2020.12.15",slug:"_2020-12-15",link:"#_2020-12-15",children:[]},{level:2,title:"2020.12.11 1.1.3",slug:"_2020-12-11-1-1-3",link:"#_2020-12-11-1-1-3",children:[]},{level:2,title:"2020.12.06 1.1.2",slug:"_2020-12-06-1-1-2",link:"#_2020-12-06-1-1-2",children:[]},{level:2,title:"2020.12.04",slug:"_2020-12-04",link:"#_2020-12-04",children:[]},{level:2,title:"2020.11.27",slug:"_2020-11-27",link:"#_2020-11-27",children:[]},{level:2,title:"2020.11.25 1.0.0",slug:"_2020-11-25-1-0-0",link:"#_2020-11-25-1-0-0",children:[]},{level:2,title:"2020.11.23",slug:"_2020-11-23",link:"#_2020-11-23",children:[]}],path:"/en/about/news.html",pathLocale:"/en/",extraFields:[]},{title:"Configurations",headers:[{level:2,title:"Overview",slug:"overview",link:"#overview",children:[]},{level:2,title:"Basic Configuration Modules",slug:"basic-configuration-modules",link:"#basic-configuration-modules",children:[]}],path:"/en/config/",pathLocale:"/en/",extraFields:[]},{title:"API Interface",headers:[{level:2,title:"ApiObject",slug:"apiobject",link:"#apiobject",children:[]},{level:2,title:"Related Configuration",slug:"related-configuration",link:"#related-configuration",children:[]},{level:2,title:"Supported API List",slug:"supported-api-list",link:"#supported-api-list",children:[{level:3,title:"HandlerService",slug:"handlerservice",link:"#handlerservice",children:[]}]},{level:2,title:"RoutingService",slug:"routingservice",link:"#routingservice",children:[{level:3,title:"LoggerService",slug:"loggerservice",link:"#loggerservice",children:[]},{level:3,title:"StatsService",slug:"statsservice",link:"#statsservice",children:[]},{level:3,title:"ReflectionService",slug:"reflectionservice",link:"#reflectionservice",children:[]}]},{level:2,title:"API Calling Example",slug:"api-calling-example",link:"#api-calling-example",children:[]}],path:"/en/config/api.html",pathLocale:"/en/",extraFields:[]},{title:"Built-in DNS Server",headers:[{level:2,title:"DNS Server",slug:"dns-server",link:"#dns-server",children:[]},{level:2,title:"DNS Processing Flow",slug:"dns-processing-flow",link:"#dns-processing-flow",children:[]},{level:2,title:"DnsObject",slug:"dnsobject",link:"#dnsobject",children:[{level:3,title:"ServerObject",slug:"serverobject",link:"#serverobject",children:[]}]}],path:"/en/config/dns.html",pathLocale:"/en/",extraFields:[]},{title:"FakeDNS",headers:[{level:2,title:"FakeDNSObject",slug:"fakednsobject",link:"#fakednsobject",children:[{level:3,title:"How to use?",slug:"how-to-use",link:"#how-to-use",children:[]},{level:3,title:"Using with other types of DNS",slug:"using-with-other-types-of-dns",link:"#using-with-other-types-of-dns",children:[]}]}],path:"/en/config/fakedns.html",pathLocale:"/en/",extraFields:[]},{title:"Inbound Proxy",headers:[{level:2,title:"InboundObject",slug:"inboundobject",link:"#inboundobject",children:[{level:3,title:"SniffingObject",slug:"sniffingobject",link:"#sniffingobject",children:[]},{level:3,title:"AllocateObject",slug:"allocateobject",link:"#allocateobject",children:[]}]}],path:"/en/config/inbound.html",pathLocale:"/en/",extraFields:[]},{title:"Log Configuration",headers:[{level:2,title:"LogObject",slug:"logobject",link:"#logobject",children:[]}],path:"/en/config/log.html",pathLocale:"/en/",extraFields:[]},{title:"Metrics",headers:[{level:2,title:"Related configurations",slug:"related-configurations",link:"#related-configurations",children:[]},{level:2,title:"Usage",slug:"usage",link:"#usage",children:[{level:3,title:"pprof",slug:"pprof",link:"#pprof",children:[]},{level:3,title:"expvars",slug:"expvars",link:"#expvars",children:[]},{level:3,title:"Additional",slug:"additional",link:"#additional",children:[]}]}],path:"/en/config/metrics.html",pathLocale:"/en/",extraFields:[]},{title:"Connection Monitoring",headers:[{level:2,title:"ObservatoryObject",slug:"observatoryobject",link:"#observatoryobject",children:[]},{level:2,title:"BurstObservatoryObject",slug:"burstobservatoryobject",link:"#burstobservatoryobject",children:[{level:3,title:"PingConfigObject",slug:"pingconfigobject",link:"#pingconfigobject",children:[]}]}],path:"/en/config/observatory.html",pathLocale:"/en/",extraFields:[]},{title:"Outbound Proxies",headers:[{level:2,title:"OutboundObject",slug:"outboundobject",link:"#outboundobject",children:[{level:3,title:"ProxySettingsObject",slug:"proxysettingsobject",link:"#proxysettingsobject",children:[]},{level:3,title:"MuxObject",slug:"muxobject",link:"#muxobject",children:[]}]}],path:"/en/config/outbound.html",pathLocale:"/en/",extraFields:[]},{title:"Local Policy",headers:[{level:2,title:"PolicyObject",slug:"policyobject",link:"#policyobject",children:[{level:3,title:"LevelPolicyObject",slug:"levelpolicyobject",link:"#levelpolicyobject",children:[]},{level:3,title:"SystemPolicyObject",slug:"systempolicyobject",link:"#systempolicyobject",children:[]}]}],path:"/en/config/policy.html",pathLocale:"/en/",extraFields:[]},{title:"Reverse Proxy",headers:[{level:2,title:"ReverseObject",slug:"reverseobject",link:"#reverseobject",children:[{level:3,title:"BridgeObject",slug:"bridgeobject",link:"#bridgeobject",children:[]},{level:3,title:"PortalObject",slug:"portalobject",link:"#portalobject",children:[]}]},{level:2,title:"Complete Configuration Example",slug:"complete-configuration-example",link:"#complete-configuration-example",children:[{level:3,title:"Bridge Configuration",slug:"bridge-configuration",link:"#bridge-configuration",children:[]},{level:3,title:"Portal Configuration",slug:"portal-configuration",link:"#portal-configuration",children:[]}]}],path:"/en/config/reverse.html",pathLocale:"/en/",extraFields:[]},{title:"Routing",headers:[{level:2,title:"RoutingObject",slug:"routingobject",link:"#routingobject",children:[{level:3,title:"RuleObject",slug:"ruleobject",link:"#ruleobject",children:[]},{level:3,title:"BalancerObject",slug:"balancerobject",link:"#balancerobject",children:[]},{level:3,title:"Predefined Domain Lists",slug:"predefined-domain-lists",link:"#predefined-domain-lists",children:[]}]}],path:"/en/config/routing.html",pathLocale:"/en/",extraFields:[]},{title:"Traffic Statistics",headers:[{level:2,title:"StatsObject",slug:"statsobject",link:"#statsobject",children:[]},{level:2,title:"Retrieving Traffic Statistics",slug:"retrieving-traffic-statistics",link:"#retrieving-traffic-statistics",children:[]}],path:"/en/config/stats.html",pathLocale:"/en/",extraFields:[]},{title:"Transport",headers:[{level:2,title:"StreamSettingsObject",slug:"streamsettingsobject",link:"#streamsettingsobject",children:[{level:3,title:"TLSObject",slug:"tlsobject",link:"#tlsobject",children:[]},{level:3,title:"SockoptObject",slug:"sockoptobject",link:"#sockoptobject",children:[]}]}],path:"/en/config/transport.html",pathLocale:"/en/",extraFields:[]},{title:"Development Guide",headers:[{level:2,title:"Compile Documentation",slug:"compile-documentation",link:"#compile-documentation",children:[]},{level:2,title:"Design Concept",slug:"design-concept",link:"#design-concept",children:[]},{level:2,title:"Development Standards",slug:"development-standards",link:"#development-standards",children:[]},{level:2,title:"Protocol Details",slug:"protocol-details",link:"#protocol-details",children:[{level:3,title:"VLESS Protocol",slug:"vless-protocol",link:"#vless-protocol",children:[]},{level:3,title:"VMess Protocol",slug:"vmess-protocol",link:"#vmess-protocol",children:[]},{level:3,title:"Mux.Cool Protocol",slug:"mux-cool-protocol",link:"#mux-cool-protocol",children:[]},{level:3,title:"mKCP Protocol",slug:"mkcp-protocol",link:"#mkcp-protocol",children:[]}]}],path:"/en/development/",pathLocale:"/en/",extraFields:[]},{title:"Quick Start",headers:[{level:2,title:"Download and Install",slug:"download-and-install",link:"#download-and-install",children:[]},{level:2,title:"Configure and Run",slug:"configure-and-run",link:"#configure-and-run",children:[]},{level:2,title:"Command Parameters",slug:"command-parameters",link:"#command-parameters",children:[]},{level:2,title:"Improve Documents",slug:"improve-documents",link:"#improve-documents",children:[]},{level:2,title:"Beginner Tutorial",slug:"beginner-tutorial",link:"#beginner-tutorial",children:[]},{level:2,title:"Getting Started Tips",slug:"getting-started-tips",link:"#getting-started-tips",children:[]},{level:2,title:"Advanced Documentation",slug:"advanced-documentation",link:"#advanced-documentation",children:[]}],path:"/en/document/",pathLocale:"/en/",extraFields:[]},{title:"Command Parameters",headers:[{level:2,title:"Get Basic Commands",slug:"get-basic-commands",link:"#get-basic-commands",children:[{level:3,title:"xray run",slug:"xray-run",link:"#xray-run",children:[]},{level:3,title:"xray version",slug:"xray-version",link:"#xray-version",children:[]},{level:3,title:"xray api",slug:"xray-api",link:"#xray-api",children:[]},{level:3,title:"xray convert",slug:"xray-convert",link:"#xray-convert",children:[]},{level:3,title:"xray tls",slug:"xray-tls",link:"#xray-tls",children:[]},{level:3,title:"xray uuid",slug:"xray-uuid",link:"#xray-uuid",children:[]},{level:3,title:"xray x25519",slug:"xray-x25519",link:"#xray-x25519",children:[]},{level:3,title:"xray wg",slug:"xray-wg",link:"#xray-wg",children:[]}]}],path:"/en/document/command.html",pathLocale:"/en/",extraFields:[]},{title:"Configure and Run",headers:[{level:2,title:"Server Configuration",slug:"server-configuration",link:"#server-configuration",children:[]},{level:2,title:"Client Configuration",slug:"client-configuration",link:"#client-configuration",children:[]},{level:2,title:"Run",slug:"run",link:"#run",children:[]}],path:"/en/document/config.html",pathLocale:"/en/",extraFields:[]},{title:"Contribute to Project X's Document",headers:[{level:2,title:"Improve Document",slug:"improve-document",link:"#improve-document",children:[]},{level:2,title:"Found Problems?",slug:"found-problems",link:"#found-problems",children:[]}],path:"/en/document/document.html",pathLocale:"/en/",extraFields:[]},{title:"Download and Install",headers:[{level:2,title:"Platform Support",slug:"platform-support",link:"#platform-support",children:[]},{level:2,title:"Download Xray",slug:"download-xray",link:"#download-xray",children:[]},{level:2,title:"Verify the Installation Package",slug:"verify-the-installation-package",link:"#verify-the-installation-package",children:[]},{level:2,title:"Install on Windows",slug:"install-on-windows",link:"#install-on-windows",children:[]},{level:2,title:"Install on macOS",slug:"install-on-macos",link:"#install-on-macos",children:[]},{level:2,title:"Install on Linux",slug:"install-on-linux",link:"#install-on-linux",children:[{level:3,title:"Install Script",slug:"install-script",link:"#install-script",children:[]},{level:3,title:"Arch Linux",slug:"arch-linux",link:"#arch-linux",children:[]},{level:3,title:"Linuxbrew",slug:"linuxbrew",link:"#linuxbrew",children:[]},{level:3,title:"Debian",slug:"debian",link:"#debian",children:[]}]},{level:2,title:"Install via Docker",slug:"install-via-docker",link:"#install-via-docker",children:[{level:3,title:"The File Structure of the Docker Image",slug:"the-file-structure-of-the-docker-image",link:"#the-file-structure-of-the-docker-image",children:[]}]}],path:"/en/document/install.html",pathLocale:"/en/",extraFields:[]},{title:"大史记",headers:[{level:2,title:"2024.9.12",slug:"_2024-9-12",link:"#_2024-9-12",children:[]},{level:2,title:"2024.9.7 v24.9.7",slug:"_2024-9-7-v24-9-7",link:"#_2024-9-7-v24-9-7",children:[]},{level:2,title:"2024.8.30 v1.8.24",slug:"_2024-8-30-v1-8-24",link:"#_2024-8-30-v1-8-24",children:[]},{level:2,title:"2024.8.26",slug:"_2024-8-26",link:"#_2024-8-26",children:[]},{level:2,title:"2024.8.3",slug:"_2024-8-3",link:"#_2024-8-3",children:[]},{level:2,title:"2024.7.29 v1.8.23",slug:"_2024-7-29-v1-8-23",link:"#_2024-7-29-v1-8-23",children:[]},{level:2,title:"2024.7.22 v1.8.21",slug:"_2024-7-22-v1-8-21",link:"#_2024-7-22-v1-8-21",children:[]},{level:2,title:"2024.7.16",slug:"_2024-7-16",link:"#_2024-7-16",children:[]},{level:2,title:"2024.7.15",slug:"_2024-7-15",link:"#_2024-7-15",children:[]},{level:2,title:"2024.6.18 v1.8.16",slug:"_2024-6-18-v1-8-16",link:"#_2024-6-18-v1-8-16",children:[]},{level:2,title:"2024.6.2",slug:"_2024-6-2",link:"#_2024-6-2",children:[]},{level:2,title:"2024.4.26 v1.8.11",slug:"_2024-4-26-v1-8-11",link:"#_2024-4-26-v1-8-11",children:[]},{level:2,title:"2024.4.20",slug:"_2024-4-20",link:"#_2024-4-20",children:[]},{level:2,title:"2024.4.13",slug:"_2024-4-13",link:"#_2024-4-13",children:[]},{level:2,title:"2024.3.18 v1.8.10",slug:"_2024-3-18-v1-8-10",link:"#_2024-3-18-v1-8-10",children:[]},{level:2,title:"2024.3.11 v1.8.9",slug:"_2024-3-11-v1-8-9",link:"#_2024-3-11-v1-8-9",children:[]},{level:2,title:"2024.2.29",slug:"_2024-2-29",link:"#_2024-2-29",children:[]},{level:2,title:"2024.2.25 v1.8.8",slug:"_2024-2-25-v1-8-8",link:"#_2024-2-25-v1-8-8",children:[]},{level:2,title:"2024.1.9",slug:"_2024-1-9",link:"#_2024-1-9",children:[]},{level:2,title:"2023.11.21",slug:"_2023-11-21",link:"#_2023-11-21",children:[]},{level:2,title:"2023.11.18 v1.8.6",slug:"_2023-11-18-v1-8-6",link:"#_2023-11-18-v1-8-6",children:[]},{level:2,title:"2023.9.30",slug:"_2023-9-30",link:"#_2023-9-30",children:[]},{level:2,title:"2023.8.29 v1.8.4",slug:"_2023-8-29-v1-8-4",link:"#_2023-8-29-v1-8-4",children:[]},{level:2,title:"2023.7.22",slug:"_2023-7-22",link:"#_2023-7-22",children:[]},{level:2,title:"2023.7.7",slug:"_2023-7-7",link:"#_2023-7-7",children:[]},{level:2,title:"2023.6.30",slug:"_2023-6-30",link:"#_2023-6-30",children:[]},{level:2,title:"2023.6.27",slug:"_2023-6-27",link:"#_2023-6-27",children:[]},{level:2,title:"2023.6.19 v1.8.3",slug:"_2023-6-19-v1-8-3",link:"#_2023-6-19-v1-8-3",children:[]},{level:2,title:"2023.6.6",slug:"_2023-6-6",link:"#_2023-6-6",children:[]},{level:2,title:"2023.4.21",slug:"_2023-4-21",link:"#_2023-4-21",children:[]},{level:2,title:"2023.4.20",slug:"_2023-4-20",link:"#_2023-4-20",children:[]},{level:2,title:"2023.4.19",slug:"_2023-4-19",link:"#_2023-4-19",children:[]},{level:2,title:"2023.4.18 v1.8.1",slug:"_2023-4-18-v1-8-1",link:"#_2023-4-18-v1-8-1",children:[]},{level:2,title:"2023.4.6",slug:"_2023-4-6",link:"#_2023-4-6",children:[]},{level:2,title:"2023.3.29",slug:"_2023-3-29",link:"#_2023-3-29",children:[]},{level:2,title:"2023.3.19",slug:"_2023-3-19",link:"#_2023-3-19",children:[]},{level:2,title:"2023.3.9 v1.8.0",slug:"_2023-3-9-v1-8-0",link:"#_2023-3-9-v1-8-0",children:[]},{level:2,title:"2023.3.4",slug:"_2023-3-4",link:"#_2023-3-4",children:[]},{level:2,title:"2023.3.2",slug:"_2023-3-2",link:"#_2023-3-2",children:[]},{level:2,title:"2023.2.16",slug:"_2023-2-16",link:"#_2023-2-16",children:[]},{level:2,title:"2023.2.9",slug:"_2023-2-9",link:"#_2023-2-9",children:[]},{level:2,title:"2023.2.8 v1.7.5",slug:"_2023-2-8-v1-7-5",link:"#_2023-2-8-v1-7-5",children:[]},{level:2,title:"2023.1.29",slug:"_2023-1-29",link:"#_2023-1-29",children:[]},{level:2,title:"2022.12.26 v1.7.0",slug:"_2022-12-26-v1-7-0",link:"#_2022-12-26-v1-7-0",children:[]},{level:2,title:"2022.11.28 v1.6.5",slug:"_2022-11-28-v1-6-5",link:"#_2022-11-28-v1-6-5",children:[]},{level:2,title:"2022.11.7 v1.6.3",slug:"_2022-11-7-v1-6-3",link:"#_2022-11-7-v1-6-3",children:[]},{level:2,title:"2022.10.29 v1.6.2",slug:"_2022-10-29-v1-6-2",link:"#_2022-10-29-v1-6-2",children:[]},{level:2,title:"2022.10.22 v1.6.1",slug:"_2022-10-22-v1-6-1",link:"#_2022-10-22-v1-6-1",children:[]},{level:2,title:"2022.10.3",slug:"_2022-10-3",link:"#_2022-10-3",children:[]},{level:2,title:"2022.8.28 v1.5.10",slug:"_2022-8-28-v1-5-10",link:"#_2022-8-28-v1-5-10",children:[]},{level:2,title:"2022.6.20 v1.5.8",slug:"_2022-6-20-v1-5-8",link:"#_2022-6-20-v1-5-8",children:[]},{level:2,title:"2022.5.29 v1.5.6",slug:"_2022-5-29-v1-5-6",link:"#_2022-5-29-v1-5-6",children:[]},{level:2,title:"2022.4.24 v1.5.5",slug:"_2022-4-24-v1-5-5",link:"#_2022-4-24-v1-5-5",children:[]},{level:2,title:"2022.3.13 v1.5.4",slug:"_2022-3-13-v1-5-4",link:"#_2022-3-13-v1-5-4",children:[]},{level:2,title:"2022.1.29 v1.5.3",slug:"_2022-1-29-v1-5-3",link:"#_2022-1-29-v1-5-3",children:[]},{level:2,title:"2021.12.24 v1.5.2",slug:"_2021-12-24-v1-5-2",link:"#_2021-12-24-v1-5-2",children:[]},{level:2,title:"2021.12.15 v1.5.1",slug:"_2021-12-15-v1-5-1",link:"#_2021-12-15-v1-5-1",children:[]},{level:2,title:"2021.10.20 v1.5.0",slug:"_2021-10-20-v1-5-0",link:"#_2021-10-20-v1-5-0",children:[]},{level:2,title:"2021.9.23 v1.4.5",slug:"_2021-9-23-v1-4-5",link:"#_2021-9-23-v1-4-5",children:[]},{level:2,title:"2021.9.16",slug:"_2021-9-16",link:"#_2021-9-16",children:[]},{level:2,title:"2021.9.8 v1.4.3",slug:"_2021-9-8-v1-4-3",link:"#_2021-9-8-v1-4-3",children:[]},{level:2,title:"2021.7.14",slug:"_2021-7-14",link:"#_2021-7-14",children:[]},{level:2,title:"2021.6.21",slug:"_2021-6-21",link:"#_2021-6-21",children:[]},{level:2,title:"2021.5.1",slug:"_2021-5-1",link:"#_2021-5-1",children:[]},{level:2,title:"2021.4.26",slug:"_2021-4-26",link:"#_2021-4-26",children:[]},{level:2,title:"2021.4.12",slug:"_2021-4-12",link:"#_2021-4-12",children:[]},{level:2,title:"2021.4.6",slug:"_2021-4-6",link:"#_2021-4-6",children:[]},{level:2,title:"2021.4.4",slug:"_2021-4-4",link:"#_2021-4-4",children:[]},{level:2,title:"2021.4.1 v1.4.2",slug:"_2021-4-1-v1-4-2",link:"#_2021-4-1-v1-4-2",children:[]},{level:2,title:"2021.3.25",slug:"_2021-3-25",link:"#_2021-3-25",children:[]},{level:2,title:"2021.3.15",slug:"_2021-3-15",link:"#_2021-3-15",children:[]},{level:2,title:"2021.3.14 v1.4.0",slug:"_2021-3-14-v1-4-0",link:"#_2021-3-14-v1-4-0",children:[]},{level:2,title:"2021.3.3 1.3.1",slug:"_2021-3-3-1-3-1",link:"#_2021-3-3-1-3-1",children:[]},{level:2,title:"2021.2.14 1.3.0",slug:"_2021-2-14-1-3-0",link:"#_2021-2-14-1-3-0",children:[]},{level:2,title:"2021.01.31 1.2.4",slug:"_2021-01-31-1-2-4",link:"#_2021-01-31-1-2-4",children:[]},{level:2,title:"2021.01.25",slug:"_2021-01-25",link:"#_2021-01-25",children:[]},{level:2,title:"2021.01.22 1.2.3",slug:"_2021-01-22-1-2-3",link:"#_2021-01-22-1-2-3",children:[]},{level:2,title:"2021.01.19",slug:"_2021-01-19",link:"#_2021-01-19",children:[]},{level:2,title:"2021.01.17",slug:"_2021-01-17",link:"#_2021-01-17",children:[]},{level:2,title:"2021.01.15 1.2.2",slug:"_2021-01-15-1-2-2",link:"#_2021-01-15-1-2-2",children:[]},{level:2,title:"2021.01.12",slug:"_2021-01-12",link:"#_2021-01-12",children:[]},{level:2,title:"2021.01.10 1.2.1",slug:"_2021-01-10-1-2-1",link:"#_2021-01-10-1-2-1",children:[]},{level:2,title:"2021.01.07",slug:"_2021-01-07",link:"#_2021-01-07",children:[]},{level:2,title:"2021.01.05",slug:"_2021-01-05",link:"#_2021-01-05",children:[]},{level:2,title:"2021.01.03",slug:"_2021-01-03",link:"#_2021-01-03",children:[]},{level:2,title:"2021.01.01",slug:"_2021-01-01",link:"#_2021-01-01",children:[]},{level:2,title:"2020.12.29",slug:"_2020-12-29",link:"#_2020-12-29",children:[]},{level:2,title:"2020.12.25 1.1.5",slug:"_2020-12-25-1-1-5",link:"#_2020-12-25-1-1-5",children:[]},{level:2,title:"2020.12.24",slug:"_2020-12-24",link:"#_2020-12-24",children:[]},{level:2,title:"2020.12.23",slug:"_2020-12-23",link:"#_2020-12-23",children:[]},{level:2,title:"2020.12.21",slug:"_2020-12-21",link:"#_2020-12-21",children:[]},{level:2,title:"2020.12.18 1.1.4",slug:"_2020-12-18-1-1-4",link:"#_2020-12-18-1-1-4",children:[]},{level:2,title:"2020.12.17",slug:"_2020-12-17",link:"#_2020-12-17",children:[]},{level:2,title:"2020.12.15",slug:"_2020-12-15",link:"#_2020-12-15",children:[]},{level:2,title:"2020.12.11 1.1.3",slug:"_2020-12-11-1-1-3",link:"#_2020-12-11-1-1-3",children:[]},{level:2,title:"2020.12.06 1.1.2",slug:"_2020-12-06-1-1-2",link:"#_2020-12-06-1-1-2",children:[]},{level:2,title:"2020.12.04",slug:"_2020-12-04",link:"#_2020-12-04",children:[]},{level:2,title:"2020.11.27",slug:"_2020-11-27",link:"#_2020-11-27",children:[]},{level:2,title:"2020.11.25 1.0.0",slug:"_2020-11-25-1-0-0",link:"#_2020-11-25-1-0-0",children:[]},{level:2,title:"2020.11.23",slug:"_2020-11-23",link:"#_2020-11-23",children:[]}],path:"/ru/about/news.html",pathLocale:"/ru/",extraFields:[]},{title:"Конфигурационный файл",headers:[{level:2,title:"Обзор",slug:"обзор",link:"#обзор",children:[]},{level:2,title:"Основные модули конфигурации",slug:"основные-модули-конфигурации",link:"#основные-модули-конфигурации",children:[]}],path:"/ru/config/",pathLocale:"/ru/",extraFields:[]},{title:"API",headers:[{level:2,title:"ApiObject",slug:"apiobject",link:"#apiobject",children:[]},{level:2,title:"Связанные настройки",slug:"связанные-настроики",link:"#связанные-настроики",children:[]},{level:2,title:"Список поддерживаемых API",slug:"список-поддерживаемых-api",link:"#список-поддерживаемых-api",children:[{level:3,title:"HandlerService",slug:"handlerservice",link:"#handlerservice",children:[]},{level:3,title:"RoutingService",slug:"routingservice",link:"#routingservice",children:[]},{level:3,title:"LoggerService",slug:"loggerservice",link:"#loggerservice",children:[]},{level:3,title:"StatsService",slug:"statsservice",link:"#statsservice",children:[]},{level:3,title:"ReflectionService",slug:"reflectionservice",link:"#reflectionservice",children:[]}]},{level:2,title:"Примеры вызова API",slug:"примеры-вызова-api",link:"#примеры-вызова-api",children:[]}],path:"/ru/config/api.html",pathLocale:"/ru/",extraFields:[]},{title:"Встроенный DNS-сервер",headers:[{level:2,title:"DNS-сервер",slug:"dns-сервер",link:"#dns-сервер",children:[]},{level:2,title:"Процесс обработки DNS-запросов",slug:"процесс-обработки-dns-запросов",link:"#процесс-обработки-dns-запросов",children:[]},{level:2,title:"DnsObject",slug:"dnsobject",link:"#dnsobject",children:[{level:3,title:"ServerObject",slug:"serverobject",link:"#serverobject",children:[]}]}],path:"/ru/config/dns.html",pathLocale:"/ru/",extraFields:[]},{title:"FakeDNS",headers:[{level:2,title:"FakeDNSObject",slug:"fakednsobject",link:"#fakednsobject",children:[{level:3,title:"Как использовать FakeDNS?",slug:"как-использовать-fakedns",link:"#как-использовать-fakedns",children:[]},{level:3,title:"Использование FakeDNS с другими типами DNS",slug:"использование-fakedns-с-другими-типами-dns",link:"#использование-fakedns-с-другими-типами-dns",children:[]}]}],path:"/ru/config/fakedns.html",pathLocale:"/ru/",extraFields:[]},{title:"Входящие подключения",headers:[{level:2,title:"InboundObject",slug:"inboundobject",link:"#inboundobject",children:[{level:3,title:"SniffingObject",slug:"sniffingobject",link:"#sniffingobject",children:[]},{level:3,title:"AllocateObject",slug:"allocateobject",link:"#allocateobject",children:[]}]}],path:"/ru/config/inbound.html",pathLocale:"/ru/",extraFields:[]},{title:"Настройка журнала",headers:[{level:2,title:"LogObject",slug:"logobject",link:"#logobject",children:[]}],path:"/ru/config/log.html",pathLocale:"/ru/",extraFields:[]},{title:"Метрики",headers:[{level:2,title:"Связанные настройки",slug:"связанные-настроики",link:"#связанные-настроики",children:[]},{level:2,title:"Использование",slug:"использование",link:"#использование",children:[{level:3,title:"pprof",slug:"pprof",link:"#pprof",children:[]},{level:3,title:"expvars",slug:"expvars",link:"#expvars",children:[]},{level:3,title:"Дополнительно",slug:"дополнительно",link:"#дополнительно",children:[]}]}],path:"/ru/config/metrics.html",pathLocale:"/ru/",extraFields:[]},{title:"Мониторинг подключений",headers:[{level:2,title:"ObservatoryObject",slug:"observatoryobject",link:"#observatoryobject",children:[]},{level:2,title:"BurstObservatoryObject",slug:"burstobservatoryobject",link:"#burstobservatoryobject",children:[{level:3,title:"PingConfigObject",slug:"pingconfigobject",link:"#pingconfigobject",children:[]}]}],path:"/ru/config/observatory.html",pathLocale:"/ru/",extraFields:[]},{title:"Исходящие подключения",headers:[{level:2,title:"OutboundObject",slug:"outboundobject",link:"#outboundobject",children:[{level:3,title:"ProxySettingsObject",slug:"proxysettingsobject",link:"#proxysettingsobject",children:[]},{level:3,title:"MuxObject",slug:"muxobject",link:"#muxobject",children:[]}]}],path:"/ru/config/outbound.html",pathLocale:"/ru/",extraFields:[]},{title:"Локальные политики",headers:[{level:2,title:"PolicyObject",slug:"policyobject",link:"#policyobject",children:[{level:3,title:"LevelPolicyObject",slug:"levelpolicyobject",link:"#levelpolicyobject",children:[]},{level:3,title:"SystemPolicyObject",slug:"systempolicyobject",link:"#systempolicyobject",children:[]}]}],path:"/ru/config/policy.html",pathLocale:"/ru/",extraFields:[]},{title:"Обратный прокси",headers:[{level:2,title:"ReverseObject",slug:"reverseobject",link:"#reverseobject",children:[{level:3,title:"BridgeObject",slug:"bridgeobject",link:"#bridgeobject",children:[]},{level:3,title:"PortalObject",slug:"portalobject",link:"#portalobject",children:[]}]},{level:2,title:"Примеры полных конфигураций",slug:"примеры-полных-конфигурации",link:"#примеры-полных-конфигурации",children:[{level:3,title:"Настройка bridge",slug:"настроика-bridge",link:"#настроика-bridge",children:[]},{level:3,title:"Настройка portal",slug:"настроика-portal",link:"#настроика-portal",children:[]}]}],path:"/ru/config/reverse.html",pathLocale:"/ru/",extraFields:[]},{title:"Маршрутизация",headers:[{level:2,title:"RoutingObject",slug:"routingobject",link:"#routingobject",children:[{level:3,title:"RuleObject",slug:"ruleobject",link:"#ruleobject",children:[]},{level:3,title:"BalancerObject",slug:"balancerobject",link:"#balancerobject",children:[]},{level:3,title:"Пример конфигурации балансировщика нагрузки",slug:"пример-конфигурации-балансировщика-нагрузки",link:"#пример-конфигурации-балансировщика-нагрузки",children:[]},{level:3,title:"Предопределенные списки доменов",slug:"предопределенные-списки-доменов",link:"#предопределенные-списки-доменов",children:[]}]}],path:"/ru/config/routing.html",pathLocale:"/ru/",extraFields:[]},{title:"Статистика",headers:[{level:2,title:"StatsObject",slug:"statsobject",link:"#statsobject",children:[]},{level:2,title:"Получение статистики",slug:"получение-статистики",link:"#получение-статистики",children:[]}],path:"/ru/config/stats.html",pathLocale:"/ru/",extraFields:[]},{title:"Транспорт",headers:[{level:2,title:"StreamSettingsObject",slug:"streamsettingsobject",link:"#streamsettingsobject",children:[{level:3,title:"TLSObject",slug:"tlsobject",link:"#tlsobject",children:[]},{level:3,title:"RealityObject",slug:"realityobject",link:"#realityobject",children:[]},{level:3,title:"SockoptObject",slug:"sockoptobject",link:"#sockoptobject",children:[]}]}],path:"/ru/config/transport.html",pathLocale:"/ru/",extraFields:[]},{title:"开发指南",headers:[{level:2,title:"编译文档",slug:"编译文档",link:"#编译文档",children:[]},{level:2,title:"设计思路",slug:"设计思路",link:"#设计思路",children:[]},{level:2,title:"开发规范",slug:"开发规范",link:"#开发规范",children:[]},{level:2,title:"协议详解",slug:"协议详解",link:"#协议详解",children:[{level:3,title:"VLESS 协议",slug:"vless-协议",link:"#vless-协议",children:[]},{level:3,title:"VMess 协议",slug:"vmess-协议",link:"#vmess-协议",children:[]},{level:3,title:"Mux.Cool 协议",slug:"mux-cool-协议",link:"#mux-cool-协议",children:[]},{level:3,title:"mKCP 协议",slug:"mkcp-协议",link:"#mkcp-协议",children:[]}]}],path:"/ru/development/",pathLocale:"/ru/",extraFields:[]},{title:"Быстрый старт",headers:[{level:2,title:"Загрузка и установка",slug:"загрузка-и-установка",link:"#загрузка-и-установка",children:[]},{level:2,title:"Настройка и запуск",slug:"настроика-и-запуск",link:"#настроика-и-запуск",children:[]},{level:2,title:"Команды и аргументы",slug:"команды-и-аргументы",link:"#команды-и-аргументы",children:[]},{level:2,title:"Улучшение документации",slug:"улучшение-документации",link:"#улучшение-документации",children:[]},{level:2,title:"Простыми словами",slug:"простыми-словами",link:"#простыми-словами",children:[]},{level:2,title:"Базовые навыки",slug:"базовые-навыки",link:"#базовые-навыки",children:[]},{level:2,title:"Продвинутая документация",slug:"продвинутая-документация",link:"#продвинутая-документация",children:[]}],path:"/ru/document/",pathLocale:"/ru/",extraFields:[]},{title:"Командные аргументы",headers:[{level:2,title:"Базовые команды",slug:"базовые-команды",link:"#базовые-команды",children:[{level:3,title:"xray run",slug:"xray-run",link:"#xray-run",children:[]},{level:3,title:"xray version",slug:"xray-version",link:"#xray-version",children:[]},{level:3,title:"xray api",slug:"xray-api",link:"#xray-api",children:[]},{level:3,title:"xray convert",slug:"xray-convert",link:"#xray-convert",children:[]},{level:3,title:"xray tls",slug:"xray-tls",link:"#xray-tls",children:[]},{level:3,title:"xray uuid",slug:"xray-uuid",link:"#xray-uuid",children:[]},{level:3,title:"xray x25519",slug:"xray-x25519",link:"#xray-x25519",children:[]},{level:3,title:"xray wg",slug:"xray-wg",link:"#xray-wg",children:[]}]}],path:"/ru/document/command.html",pathLocale:"/ru/",extraFields:[]},{title:"Настройка и запуск",headers:[{level:2,title:"Настройка сервера",slug:"настроика-сервера",link:"#настроика-сервера",children:[]},{level:2,title:"Настройка клиента",slug:"настроика-клиента",link:"#настроика-клиента",children:[]},{level:2,title:"Запуск",slug:"запуск",link:"#запуск",children:[]}],path:"/ru/document/config.html",pathLocale:"/ru/",extraFields:[]},{title:"Вклад в документацию Project X",headers:[{level:2,title:"Улучшение документации",slug:"улучшение-документации",link:"#улучшение-документации",children:[]},{level:2,title:"Нашли ошибку?",slug:"нашли-ошибку",link:"#нашли-ошибку",children:[]}],path:"/ru/document/document.html",pathLocale:"/ru/",extraFields:[]},{title:"Загрузка и установка",headers:[{level:2,title:"Поддерживаемые платформы",slug:"поддерживаемые-платформы",link:"#поддерживаемые-платформы",children:[]},{level:2,title:"Загрузка Xray",slug:"загрузка-xray",link:"#загрузка-xray",children:[]},{level:2,title:"Проверка установочного пакета",slug:"проверка-установочного-пакета",link:"#проверка-установочного-пакета",children:[]},{level:2,title:"Установка на Windows",slug:"установка-на-windows",link:"#установка-на-windows",children:[]},{level:2,title:"Установка на macOS",slug:"установка-на-macos",link:"#установка-на-macos",children:[]},{level:2,title:"Установка на Linux",slug:"установка-на-linux",link:"#установка-на-linux",children:[{level:3,title:"Установочные скрипты",slug:"установочные-скрипты",link:"#установочные-скрипты",children:[]},{level:3,title:"Arch Linux",slug:"arch-linux",link:"#arch-linux",children:[]},{level:3,title:"Linuxbrew",slug:"linuxbrew",link:"#linuxbrew",children:[]},{level:3,title:"Debian",slug:"debian",link:"#debian",children:[]},{level:3,title:"Gentoo",slug:"gentoo",link:"#gentoo",children:[]}]},{level:2,title:"Установка с помощью Docker",slug:"установка-с-помощью-docker",link:"#установка-с-помощью-docker",children:[{level:3,title:"Файловая структура образа Docker",slug:"фаиловая-структура-образа-docker",link:"#фаиловая-структура-образа-docker",children:[]}]}],path:"/ru/document/install.html",pathLocale:"/ru/",extraFields:[]},{title:"透明代理入门",headers:[{level:2,title:"什么是透明代理",slug:"什么是透明代理",link:"#什么是透明代理",children:[]},{level:2,title:"透明代理的实现",slug:"透明代理的实现",link:"#透明代理的实现",children:[{level:3,title:"tun2socks",slug:"tun2socks",link:"#tun2socks",children:[]},{level:3,title:"iptables/nftables",slug:"iptables-nftables",link:"#iptables-nftables",children:[]}]},{level:2,title:"iptables 实现透明代理原理",slug:"iptables-实现透明代理原理",link:"#iptables-实现透明代理原理",children:[]},{level:2,title:"透明代理难在哪里",slug:"透明代理难在哪里",link:"#透明代理难在哪里",children:[]},{level:2,title:"从零开始一步步实现基于 iptables-tproxy 的透明代理",slug:"从零开始一步步实现基于-iptables-tproxy-的透明代理",link:"#从零开始一步步实现基于-iptables-tproxy-的透明代理",children:[{level:3,title:"在开始之前,你需要有一定的基础知识:",slug:"在开始之前-你需要有一定的基础知识",link:"#在开始之前-你需要有一定的基础知识",children:[]},{level:3,title:"前期准备工作",slug:"前期准备工作",link:"#前期准备工作",children:[]},{level:3,title:"首先,我们先试试做到第一阶段",slug:"首先-我们先试试做到第一阶段",link:"#首先-我们先试试做到第一阶段",children:[]},{level:3,title:"第二阶段",slug:"第二阶段",link:"#第二阶段",children:[]},{level:3,title:"第三阶段",slug:"第三阶段",link:"#第三阶段",children:[]},{level:3,title:"第四阶段",slug:"第四阶段",link:"#第四阶段",children:[]},{level:3,title:"代理 ipv6",slug:"代理-ipv6",link:"#代理-ipv6",children:[]}]}],path:"/document/level-2/transparent_proxy/transparent_proxy.html",pathLocale:"/",extraFields:[]},{title:"Browser Dialer",headers:[{level:2,title:"Background",slug:"background",link:"#background",children:[]},{level:2,title:"Configuration",slug:"configuration",link:"#configuration",children:[]},{level:2,title:"Inner workings",slug:"inner-workings",link:"#inner-workings",children:[]},{level:2,title:"WebSocket",slug:"websocket",link:"#websocket",children:[]},{level:2,title:"SplitHTTP",slug:"splithttp",link:"#splithttp",children:[]}],path:"/en/config/features/browser_dialer.html",pathLocale:"/en/",extraFields:[]},{title:"Environment Variables",headers:[{level:2,title:"Xray Asset Location",slug:"xray-asset-location",link:"#xray-asset-location",children:[]},{level:2,title:"Configuration File Location",slug:"configuration-file-location",link:"#configuration-file-location",children:[]},{level:2,title:"Multiple Configuration Directories",slug:"multiple-configuration-directories",link:"#multiple-configuration-directories",children:[]}],path:"/en/config/features/env.html",pathLocale:"/en/",extraFields:[]},{title:"Fallback",headers:[{level:2,title:"fallbacks configuration",slug:"fallbacks-configuration",link:"#fallbacks-configuration",children:[{level:3,title:"FallbackObject",slug:"fallbackobject",link:"#fallbackobject",children:[]},{level:3,title:"Additional Information",slug:"additional-information",link:"#additional-information",children:[]}]},{level:2,title:"Fallbacks design theory",slug:"fallbacks-design-theory",link:"#fallbacks-design-theory",children:[]}],path:"/en/config/features/fallback.html",pathLocale:"/en/",extraFields:[]},{title:"Multi-file configuration",headers:[{level:2,title:"Multi-file startup",slug:"multi-file-startup",link:"#multi-file-startup",children:[]},{level:2,title:"Rule Explanation",slug:"rule-explanation",link:"#rule-explanation",children:[{level:3,title:"Normal Objects({})",slug:"normal-objects",link:"#normal-objects",children:[]},{level:3,title:"Arrays([])",slug:"arrays",link:"#arrays",children:[]}]},{level:2,title:"Recommended Multi-file List",slug:"recommended-multi-file-list",link:"#recommended-multi-file-list",children:[]}],path:"/en/config/features/multiple.html",pathLocale:"/en/",extraFields:[]},{title:"Deep analysis of XTLS",headers:[],path:"/en/config/features/xtls.html",pathLocale:"/en/",extraFields:[]},{title:"Dokodemo-Door",headers:[{level:2,title:"InboundConfigurationObject",slug:"inboundconfigurationobject",link:"#inboundconfigurationobject",children:[]},{level:2,title:"Usage",slug:"usage",link:"#usage",children:[]},{level:2,title:"Transparent Proxy Configuration Example",slug:"transparent-proxy-configuration-example",link:"#transparent-proxy-configuration-example",children:[]}],path:"/en/config/inbounds/dokodemo.html",pathLocale:"/en/",extraFields:[]},{title:"HTTP",headers:[{level:3,title:"AccountObject",slug:"accountobject",link:"#accountobject",children:[]}],path:"/en/config/inbounds/http.html",pathLocale:"/en/",extraFields:[]},{title:"Shadowsocks",headers:[{level:3,title:"Supported Encryption Methods",slug:"supported-encryption-methods",link:"#supported-encryption-methods",children:[]},{level:2,title:"InboundConfigurationObject",slug:"inboundconfigurationobject",link:"#inboundconfigurationobject",children:[]},{level:2,title:"ClientObject",slug:"clientobject",link:"#clientobject",children:[]}],path:"/en/config/inbounds/shadowsocks.html",pathLocale:"/en/",extraFields:[]},{title:"SOCKS",headers:[{level:2,title:"InboundConfigurationObject",slug:"inboundconfigurationobject",link:"#inboundconfigurationobject",children:[{level:3,title:"AccountObject",slug:"accountobject",link:"#accountobject",children:[]}]}],path:"/en/config/inbounds/socks.html",pathLocale:"/en/",extraFields:[]},{title:"Trojan",headers:[{level:2,title:"InboundConfigurationObject",slug:"inboundconfigurationobject",link:"#inboundconfigurationobject",children:[{level:3,title:"ClientObject",slug:"clientobject",link:"#clientobject",children:[]}]}],path:"/en/config/inbounds/trojan.html",pathLocale:"/en/",extraFields:[]},{title:"VLESS",headers:[{level:2,title:"InboundConfigurationObject",slug:"inboundconfigurationobject",link:"#inboundconfigurationobject",children:[{level:3,title:"ClientObject",slug:"clientobject",link:"#clientobject",children:[]}]}],path:"/en/config/inbounds/vless.html",pathLocale:"/en/",extraFields:[]},{title:"VMess",headers:[{level:2,title:"InboundConfigurationObject",slug:"inboundconfigurationobject",link:"#inboundconfigurationobject",children:[{level:3,title:"ClientObject",slug:"clientobject",link:"#clientobject",children:[]}]}],path:"/en/config/inbounds/vmess.html",pathLocale:"/en/",extraFields:[]},{title:"Wireguard",headers:[{level:2,title:"InboundConfigurationObject",slug:"inboundconfigurationobject",link:"#inboundconfigurationobject",children:[{level:3,title:"Peers",slug:"peers",link:"#peers",children:[]}]}],path:"/en/config/inbounds/wireguard.html",pathLocale:"/en/",extraFields:[]},{title:"Blackhole",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[{level:3,title:"ResponseObject",slug:"responseobject",link:"#responseobject",children:[]}]}],path:"/en/config/outbounds/blackhole.html",pathLocale:"/en/",extraFields:[]},{title:"DNS",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[]},{level:2,title:"DNS Configuration Example",slug:"dns-configuration-example",link:"#dns-configuration-example",children:[]}],path:"/en/config/outbounds/dns.html",pathLocale:"/en/",extraFields:[]},{title:"Freedom",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[]}],path:"/en/config/outbounds/freedom.html",pathLocale:"/en/",extraFields:[]},{title:"HTTP",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[{level:3,title:"ServerObject",slug:"serverobject",link:"#serverobject",children:[]}]}],path:"/en/config/outbounds/http.html",pathLocale:"/en/",extraFields:[]},{title:"Loopback",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[{level:3,title:"How to use?",slug:"how-to-use",link:"#how-to-use",children:[]}]}],path:"/en/config/outbounds/loopback.html",pathLocale:"/en/",extraFields:[]},{title:"Shadowsocks",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[{level:3,title:"ServerObject",slug:"serverobject",link:"#serverobject",children:[]}]}],path:"/en/config/outbounds/shadowsocks.html",pathLocale:"/en/",extraFields:[]},{title:"Socks",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[{level:3,title:"ServerObject",slug:"serverobject",link:"#serverobject",children:[]}]}],path:"/en/config/outbounds/socks.html",pathLocale:"/en/",extraFields:[]},{title:"Trojan",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[{level:3,title:"ServerObject",slug:"serverobject",link:"#serverobject",children:[]}]}],path:"/en/config/outbounds/trojan.html",pathLocale:"/en/",extraFields:[]},{title:"VLESS",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[{level:3,title:"ServerObject",slug:"serverobject",link:"#serverobject",children:[]},{level:3,title:"UserObject",slug:"userobject",link:"#userobject",children:[]}]}],path:"/en/config/outbounds/vless.html",pathLocale:"/en/",extraFields:[]},{title:"VMess",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[{level:3,title:"ServerObject",slug:"serverobject",link:"#serverobject",children:[]}]}],path:"/en/config/outbounds/vmess.html",pathLocale:"/en/",extraFields:[]},{title:"Wireguard",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[{level:3,title:"Peers",slug:"peers",link:"#peers",children:[]}]}],path:"/en/config/outbounds/wireguard.html",pathLocale:"/en/",extraFields:[]},{title:"gRPC",headers:[{level:2,title:"GRPCObject",slug:"grpcobject",link:"#grpcobject",children:[]}],path:"/en/config/transports/grpc.html",pathLocale:"/en/",extraFields:[]},{title:"HTTP/2",headers:[{level:2,title:"HttpObject",slug:"httpobject",link:"#httpobject",children:[]}],path:"/en/config/transports/h2.html",pathLocale:"/en/",extraFields:[]},{title:"HTTPUpgrade",headers:[{level:2,title:"HttpUpgradeObject",slug:"httpupgradeobject",link:"#httpupgradeobject",children:[]}],path:"/en/config/transports/httpupgrade.html",pathLocale:"/en/",extraFields:[]},{title:"mKCP",headers:[{level:2,title:"KcpObject",slug:"kcpobject",link:"#kcpobject",children:[{level:3,title:"HeaderObject",slug:"headerobject",link:"#headerobject",children:[]}]},{level:2,title:"Special Thanks",slug:"special-thanks",link:"#special-thanks",children:[]},{level:2,title:"Improvements to the KCP protocol",slug:"improvements-to-the-kcp-protocol",link:"#improvements-to-the-kcp-protocol",children:[{level:3,title:"smaller protocol header",slug:"smaller-protocol-header",link:"#smaller-protocol-header",children:[]},{level:3,title:"ACK packet retransmission",slug:"ack-packet-retransmission",link:"#ack-packet-retransmission",children:[]},{level:3,title:"Connection state control",slug:"connection-state-control",link:"#connection-state-control",children:[]}]}],path:"/en/config/transports/mkcp.html",pathLocale:"/en/",extraFields:[]},{title:"SplitHTTP",headers:[{level:2,title:"SplitHttpObject",slug:"splithttpobject",link:"#splithttpobject",children:[]},{level:2,title:"HTTP versions",slug:"http-versions",link:"#http-versions",children:[]},{level:2,title:"Troubleshooting",slug:"troubleshooting",link:"#troubleshooting",children:[]},{level:2,title:"Browser Dialer",slug:"browser-dialer",link:"#browser-dialer",children:[]},{level:2,title:"Protocol details",slug:"protocol-details",link:"#protocol-details",children:[]}],path:"/en/config/transports/splithttp.html",pathLocale:"/en/",extraFields:[]},{title:"TCP",headers:[{level:2,title:"TcpObject",slug:"tcpobject",link:"#tcpobject",children:[{level:3,title:"NoneHeaderObject",slug:"noneheaderobject",link:"#noneheaderobject",children:[]},{level:3,title:"HttpHeaderObject",slug:"httpheaderobject",link:"#httpheaderobject",children:[]}]}],path:"/en/config/transports/tcp.html",pathLocale:"/en/",extraFields:[]},{title:"WebSocket",headers:[{level:2,title:"WebSocketObject",slug:"websocketobject",link:"#websocketobject",children:[]},{level:2,title:"Browser Dialer",slug:"browser-dialer",link:"#browser-dialer",children:[]}],path:"/en/config/transports/websocket.html",pathLocale:"/en/",extraFields:[]},{title:"Compile the document",headers:[{level:2,title:"Preparatory Work",slug:"preparatory-work",link:"#preparatory-work",children:[]},{level:2,title:"Pull Xray source code",slug:"pull-xray-source-code",link:"#pull-xray-source-code",children:[]},{level:2,title:"Build Binary",slug:"build-binary",link:"#build-binary",children:[{level:3,title:"Windows(Powershell):",slug:"windows-powershell",link:"#windows-powershell",children:[]},{level:3,title:"macOS, Linux:",slug:"macos-linux",link:"#macos-linux",children:[]}]},{level:2,title:"Reproducible Build:",slug:"reproducible-build",link:"#reproducible-build",children:[]}],path:"/en/development/intro/compile.html",pathLocale:"/en/",extraFields:[]},{title:"Design Objectives",headers:[{level:2,title:"Architecture",slug:"architecture",link:"#architecture",children:[{level:3,title:"Application Layer",slug:"application-layer",link:"#application-layer",children:[]},{level:3,title:"Proxy Layer",slug:"proxy-layer",link:"#proxy-layer",children:[]},{level:3,title:"Transport Layer",slug:"transport-layer",link:"#transport-layer",children:[]}]}],path:"/en/development/intro/design.html",pathLocale:"/en/",extraFields:[]},{title:"Development Standards",headers:[{level:2,title:"Basic",slug:"basic",link:"#basic",children:[{level:3,title:"Version Control",slug:"version-control",link:"#version-control",children:[]},{level:3,title:"Branch",slug:"branch",link:"#branch",children:[]},{level:3,title:"Release",slug:"release",link:"#release",children:[]},{level:3,title:"Citing other projects",slug:"citing-other-projects",link:"#citing-other-projects",children:[]}]},{level:2,title:"Development Process",slug:"development-process",link:"#development-process",children:[{level:3,title:"Before Writing Code",slug:"before-writing-code",link:"#before-writing-code",children:[]},{level:3,title:"Modify the code",slug:"modify-the-code",link:"#modify-the-code",children:[]},{level:3,title:"Pull Request",slug:"pull-request",link:"#pull-request",children:[]},{level:3,title:"Modifying Code",slug:"modifying-code",link:"#modifying-code",children:[]}]},{level:2,title:"Xray Coding Guidelines",slug:"xray-coding-guidelines",link:"#xray-coding-guidelines",children:[{level:3,title:"Code Structure",slug:"code-structure",link:"#code-structure",children:[]},{level:3,title:"Coding Standards",slug:"coding-standards",link:"#coding-standards",children:[]}]}],path:"/en/development/intro/guide.html",pathLocale:"/en/",extraFields:[]},{title:"mKCP Protocol",headers:[{level:2,title:"Version",slug:"version",link:"#version",children:[]},{level:2,title:"Dependencies",slug:"dependencies",link:"#dependencies",children:[{level:3,title:"Underlying Protocol",slug:"underlying-protocol",link:"#underlying-protocol",children:[]},{level:3,title:"Functions",slug:"functions",link:"#functions",children:[]}]},{level:2,title:"Communication Process",slug:"communication-process",link:"#communication-process",children:[]},{level:2,title:"Data Format",slug:"data-format",link:"#data-format",children:[{level:3,title:"Data Packet",slug:"data-packet",link:"#data-packet",children:[]},{level:3,title:"Data snippet",slug:"data-snippet",link:"#data-snippet",children:[]},{level:3,title:"Confirmation snippet",slug:"confirmation-snippet",link:"#confirmation-snippet",children:[]},{level:3,title:"Heartbeat Fragments",slug:"heartbeat-fragments",link:"#heartbeat-fragments",children:[]}]}],path:"/en/development/protocols/mkcp.html",pathLocale:"/en/",extraFields:[]},{title:"Mux.Cool Protocol",headers:[{level:2,title:"Version",slug:"version",link:"#version",children:[]},{level:2,title:"Dependencies",slug:"dependencies",link:"#dependencies",children:[{level:3,title:"Underlying Protocol",slug:"underlying-protocol",link:"#underlying-protocol",children:[]}]},{level:2,title:"Communication Process",slug:"communication-process",link:"#communication-process",children:[{level:3,title:"Client behavior",slug:"client-behavior",link:"#client-behavior",children:[]},{level:3,title:"Server-side behavior",slug:"server-side-behavior",link:"#server-side-behavior",children:[]}]},{level:2,title:"Data Format",slug:"data-format",link:"#data-format",children:[{level:3,title:"Frame Format",slug:"frame-format",link:"#frame-format",children:[]},{level:3,title:"Metadata",slug:"metadata",link:"#metadata",children:[]},{level:3,title:"New Sublink (New)",slug:"new-sublink-new",link:"#new-sublink-new",children:[]},{level:3,title:"Keep sub-connections",slug:"keep-sub-connections",link:"#keep-sub-connections",children:[]},{level:3,title:"End",slug:"end",link:"#end",children:[]},{level:3,title:"KeepAlive",slug:"keepalive",link:"#keepalive",children:[]}]},{level:2,title:"Application",slug:"application",link:"#application",children:[]}],path:"/en/development/protocols/muxcool.html",pathLocale:"/en/",extraFields:[]},{title:"VLESS Protocol",headers:[{level:2,title:"Request & Response",slug:"request-response",link:"#request-response",children:[]},{level:2,title:"ProtoBuf",slug:"protobuf",link:"#protobuf",children:[]},{level:2,title:"Flow",slug:"flow",link:"#flow",children:[{level:3,title:"Flow Control (Formerly Traffic Scheduler)",slug:"flow-control-formerly-traffic-scheduler",link:"#flow-control-formerly-traffic-scheduler",children:[]}]},{level:2,title:"Encryption",slug:"encryption",link:"#encryption",children:[]},{level:2,title:"UDP issues",slug:"udp-issues",link:"#udp-issues",children:[]},{level:2,title:"Client Development Guide",slug:"client-development-guide",link:"#client-development-guide",children:[]},{level:2,title:"VLESS Sharing Link Standard",slug:"vless-sharing-link-standard",link:"#vless-sharing-link-standard",children:[]}],path:"/en/development/protocols/vless.html",pathLocale:"/en/",extraFields:[]},{title:"VMess Protocol",headers:[{level:2,title:"Version",slug:"version",link:"#version",children:[]},{level:2,title:"Dependencies",slug:"dependencies",link:"#dependencies",children:[{level:3,title:"Underlying Protocol",slug:"underlying-protocol",link:"#underlying-protocol",children:[]},{level:3,title:"User ID",slug:"user-id",link:"#user-id",children:[]},{level:3,title:"Functions",slug:"functions",link:"#functions",children:[]}]},{level:2,title:"Communication Process",slug:"communication-process",link:"#communication-process",children:[]},{level:2,title:"Client Request",slug:"client-request",link:"#client-request",children:[{level:3,title:"Authentication Information",slug:"authentication-information",link:"#authentication-information",children:[]},{level:3,title:"Command Section",slug:"command-section",link:"#command-section",children:[]},{level:3,title:"Data Section",slug:"data-section",link:"#data-section",children:[]}]},{level:2,title:"Server Response",slug:"server-response",link:"#server-response",children:[{level:3,title:"Dynamic Port Instructions",slug:"dynamic-port-instructions",link:"#dynamic-port-instructions",children:[]}]},{level:2,title:"Comment",slug:"comment",link:"#comment",children:[]}],path:"/en/development/protocols/vmess.html",pathLocale:"/en/",extraFields:[]},{title:"Plain and Simple Language",headers:[],path:"/en/document/level-0/",pathLocale:"/en/",extraFields:[]},{title:"[Chapter 1] Simple and Plain Language",headers:[{level:2,title:"1.1 Who is this document written for?",slug:"_1-1-who-is-this-document-written-for",link:"#_1-1-who-is-this-document-written-for",children:[]},{level:2,title:"1.2 Who is this document not written for?",slug:"_1-2-who-is-this-document-not-written-for",link:"#_1-2-who-is-this-document-not-written-for",children:[]},{level:2,title:"1.3 Declaration and Other Statements",slug:"_1-3-declaration-and-other-statements",link:"#_1-3-declaration-and-other-statements",children:[]},{level:2,title:"1.4 Why is self-hosting a challenge?",slug:"_1-4-why-is-self-hosting-a-challenge",link:"#_1-4-why-is-self-hosting-a-challenge",children:[]},{level:2,title:'1.5 "Why not just use the airport?"',slug:"_1-5-why-not-just-use-the-airport",link:"#_1-5-why-not-just-use-the-airport",children:[]},{level:2,title:"1.6 So should you build your own website?",slug:"_1-6-so-should-you-build-your-own-website",link:"#_1-6-so-should-you-build-your-own-website",children:[]},{level:2,title:"1.7 Some digressions",slug:"_1-7-some-digressions",link:"#_1-7-some-digressions",children:[]},{level:2,title:"1.8 Your Progress",slug:"_1-8-your-progress",link:"#_1-8-your-progress",children:[]}],path:"/en/document/level-0/ch01-preface.html",pathLocale:"/en/",extraFields:[]},{title:"[Chapter 2] Preparation of Raw Materials",headers:[{level:2,title:"2.1 Acquiring a VPS",slug:"_2-1-acquiring-a-vps",link:"#_2-1-acquiring-a-vps",children:[]},{level:2,title:"2.2 Obtaining a Desired Domain Name",slug:"_2-2-obtaining-a-desired-domain-name",link:"#_2-2-obtaining-a-desired-domain-name",children:[]},{level:2,title:"2.3 Software you need to install on your local computer",slug:"_2-3-software-you-need-to-install-on-your-local-computer",link:"#_2-3-software-you-need-to-install-on-your-local-computer",children:[]},{level:2,title:"2.4 Your Progress",slug:"_2-4-your-progress",link:"#_2-4-your-progress",children:[]}],path:"/en/document/level-0/ch02-preparation.html",pathLocale:"/en/",extraFields:[]},{title:"[Chapter 3] Remote Login",headers:[{level:2,title:"3.1 Remote Login to VPS (PuTTY)",slug:"_3-1-remote-login-to-vps-putty",link:"#_3-1-remote-login-to-vps-putty",children:[]},{level:2,title:"3.2 Successfully Logging in SSH! Introduction to Command Line Interface!",slug:"_3-2-successfully-logging-in-ssh-introduction-to-command-line-interface",link:"#_3-2-successfully-logging-in-ssh-introduction-to-command-line-interface",children:[]},{level:2,title:"3.3 Updating software on Linux for the first time!",slug:"_3-3-updating-software-on-linux-for-the-first-time",link:"#_3-3-updating-software-on-linux-for-the-first-time",children:[]},{level:2,title:"3.4 Your Progress",slug:"_3-4-your-progress",link:"#_3-4-your-progress",children:[]}],path:"/en/document/level-0/ch03-ssh.html",pathLocale:"/en/",extraFields:[]},{title:"[Chapter 4] Security and Protection",headers:[{level:2,title:"4.1 Why Do We Need Security Protection?",slug:"_4-1-why-do-we-need-security-protection",link:"#_4-1-why-do-we-need-security-protection",children:[]},{level:2,title:"4.2 What are the specific risks",slug:"_4-2-what-are-the-specific-risks",link:"#_4-2-what-are-the-specific-risks",children:[]},{level:2,title:"4.3 What security measures do we need to take",slug:"_4-3-what-security-measures-do-we-need-to-take",link:"#_4-3-what-security-measures-do-we-need-to-take",children:[]},{level:2,title:"4.4 Change the SSH Remote Login Port to a Non-22 Port",slug:"_4-4-change-the-ssh-remote-login-port-to-a-non-22-port",link:"#_4-4-change-the-ssh-remote-login-port-to-a-non-22-port",children:[]},{level:2,title:"4.5 Creating a New User Without Root Access",slug:"_4-5-creating-a-new-user-without-root-access",link:"#_4-5-creating-a-new-user-without-root-access",children:[]},{level:2,title:"4.8 Your Progress",slug:"_4-8-your-progress",link:"#_4-8-your-progress",children:[]}],path:"/en/document/level-0/ch04-security.html",pathLocale:"/en/",extraFields:[]},{title:"Chapter 5: Website Building",headers:[{level:2,title:"5.1 Why should you create a website?",slug:"_5-1-why-should-you-create-a-website",link:"#_5-1-why-should-you-create-a-website",children:[]},{level:2,title:"5.2 Log in to VPS, install and run Nginx",slug:"_5-2-log-in-to-vps-install-and-run-nginx",link:"#_5-2-log-in-to-vps-install-and-run-nginx",children:[]},{level:2,title:"5.3 Create the simplest web page",slug:"_5-3-create-the-simplest-web-page",link:"#_5-3-create-the-simplest-web-page",children:[]},{level:2,title:"5.4 Common error explanations",slug:"_5-4-common-error-explanations",link:"#_5-4-common-error-explanations",children:[]}],path:"/en/document/level-0/ch05-webpage.html",pathLocale:"/en/",extraFields:[]},{title:"[Chapter 6] Certificate Management",headers:[{level:2,title:"6.1 Applying for a TLS Certificate",slug:"_6-1-applying-for-a-tls-certificate",link:"#_6-1-applying-for-a-tls-certificate",children:[]},{level:2,title:"6.2 Install acme.sh",slug:"_6-2-install-acme-sh",link:"#_6-2-install-acme-sh",children:[]},{level:2,title:"6.3 Testing Certificate Application",slug:"_6-3-testing-certificate-application",link:"#_6-3-testing-certificate-application",children:[]},{level:2,title:"6.5 Certificate Installation",slug:"_6-5-certificate-installation",link:"#_6-5-certificate-installation",children:[]},{level:2,title:"6.6 Your Progress",slug:"_6-6-your-progress",link:"#_6-6-your-progress",children:[]}],path:"/en/document/level-0/ch06-certificates.html",pathLocale:"/en/",extraFields:[]},{title:"[Chapter 7]Xray Server",headers:[{level:2,title:"7.1 Study broadly, Act decisively.",slug:"_7-1-study-broadly-act-decisively",link:"#_7-1-study-broadly-act-decisively",children:[]},{level:2,title:"7.2 Install Xray",slug:"_7-2-install-xray",link:"#_7-2-install-xray",children:[]},{level:2,title:"7.3 Configure TLS certificate for Xray",slug:"_7-3-configure-tls-certificate-for-xray",link:"#_7-3-configure-tls-certificate-for-xray",children:[]},{level:2,title:"7.4 Configure Xray",slug:"_7-4-configure-xray",link:"#_7-4-configure-xray",children:[]},{level:2,title:"7.5 Start Xray service! ! (and check the service status)",slug:"_7-5-start-xray-service-and-check-the-service-status",link:"#_7-5-start-xray-service-and-check-the-service-status",children:[]},{level:2,title:"7.6 Review systemd for basic service management",slug:"_7-6-review-systemd-for-basic-service-management",link:"#_7-6-review-systemd-for-basic-service-management",children:[]},{level:2,title:"7.7 Server Optimization 1: Enable BBR",slug:"_7-7-server-optimization-1-enable-bbr",link:"#_7-7-server-optimization-1-enable-bbr",children:[]},{level:2,title:"7.8 Server Optimization 2: Enable HTTP to automatically redirect to HTTPS",slug:"_7-8-server-optimization-2-enable-http-to-automatically-redirect-to-https",link:"#_7-8-server-optimization-2-enable-http-to-automatically-redirect-to-https",children:[]},{level:2,title:"7.9 Server Optimization 3: More Fallbacks",slug:"_7-9-server-optimization-3-more-fallbacks",link:"#_7-9-server-optimization-3-more-fallbacks",children:[]},{level:2,title:"7.10 Your progress",slug:"_7-10-your-progress",link:"#_7-10-your-progress",children:[]},{level:2,title:"7.11 Important errata",slug:"_7-11-important-errata",link:"#_7-11-important-errata",children:[]}],path:"/en/document/level-0/ch07-xray-server.html",pathLocale:"/en/",extraFields:[]},{title:"【第 8 章】Xray 客户端篇",headers:[{level:2,title:"8.1 Xray 的工作原理简述",slug:"_8-1-xray-的工作原理简述",link:"#_8-1-xray-的工作原理简述",children:[]},{level:2,title:"8.2 客户端与服务器端正确连接",slug:"_8-2-客户端与服务器端正确连接",link:"#_8-2-客户端与服务器端正确连接",children:[]},{level:2,title:"8.3 附加题 1:在 PC 端手工配置 xray-core",slug:"_8-3-附加题-1-在-pc-端手工配置-xray-core",link:"#_8-3-附加题-1-在-pc-端手工配置-xray-core",children:[]},{level:2,title:"8.4 附加题 2:在 PC 端手工运行 xray-core",slug:"_8-4-附加题-2-在-pc-端手工运行-xray-core",link:"#_8-4-附加题-2-在-pc-端手工运行-xray-core",children:[]},{level:2,title:"8.5 附加题 3:在 PC 端开机自动运行 xray-core",slug:"_8-5-附加题-3-在-pc-端开机自动运行-xray-core",link:"#_8-5-附加题-3-在-pc-端开机自动运行-xray-core",children:[]},{level:2,title:"8.6 圆满完成!",slug:"_8-6-圆满完成",link:"#_8-6-圆满完成",children:[]},{level:2,title:"8.7 TO INFINITY AND BEYOND!",slug:"_8-7-to-infinity-and-beyond",link:"#_8-7-to-infinity-and-beyond",children:[]}],path:"/en/document/level-0/ch08-xray-clients.html",pathLocale:"/en/",extraFields:[]},{title:"【第 9 章】附录",headers:[{level:2,title:"1. 小小白白 Linux 基础命令索引",slug:"_1-小小白白-linux-基础命令索引",link:"#_1-小小白白-linux-基础命令索引",children:[]},{level:2,title:"2. 小小白白 Linux 重要配置文件索引",slug:"_2-小小白白-linux-重要配置文件索引",link:"#_2-小小白白-linux-重要配置文件索引",children:[]},{level:2,title:"3. 小小白白 Xray 重要文件索引",slug:"_3-小小白白-xray-重要文件索引",link:"#_3-小小白白-xray-重要文件索引",children:[]}],path:"/en/document/level-0/ch09-appendix.html",pathLocale:"/en/",extraFields:[]},{title:"Beginner's Tips",headers:[],path:"/en/document/level-1/",pathLocale:"/en/",extraFields:[]},{title:"回落 (fallbacks) 功能简析",headers:[{level:2,title:"1. 回顾《小小白白话文》中的回落",slug:"_1-回顾《小小白白话文》中的回落",link:"#_1-回顾《小小白白话文》中的回落",children:[]},{level:2,title:"2. 重新认识回落 (WHAT, HOW v1)",slug:"_2-重新认识回落-what-how-v1",link:"#_2-重新认识回落-what-how-v1",children:[]},{level:2,title:"3. 为什么要回落 (WHY v1)",slug:"_3-为什么要回落-why-v1",link:"#_3-为什么要回落-why-v1",children:[]},{level:2,title:"4. 重新认识【回落の完全体】 (WHAT, WHY, HOW v2)",slug:"_4-重新认识【回落の完全体】-what-why-how-v2",link:"#_4-重新认识【回落の完全体】-what-why-how-v2",children:[]},{level:2,title:"5. 多层回落示例及解读",slug:"_5-多层回落示例及解读",link:"#_5-多层回落示例及解读",children:[{level:3,title:"5.1 首先,我将服务器端配置的 443 监听段摘抄如下:",slug:"_5-1-首先-我将服务器端配置的-443-监听段摘抄如下",link:"#_5-1-首先-我将服务器端配置的-443-监听段摘抄如下",children:[]},{level:3,title:"5.2 后续监听处理的配置段摘抄如下:",slug:"_5-2-后续监听处理的配置段摘抄如下",link:"#_5-2-后续监听处理的配置段摘抄如下",children:[]}]},{level:2,title:"6. 结语",slug:"_6-结语",link:"#_6-结语",children:[]},{level:2,title:"7. 附加题",slug:"_7-附加题",link:"#_7-附加题",children:[]}],path:"/en/document/level-1/fallbacks-lv1.html",pathLocale:"/en/",extraFields:[]},{title:"SNI fallback",headers:[{level:2,title:"Application Scenarios",slug:"application-scenarios",link:"#application-scenarios",children:[]},{level:2,title:"Introduction to SNI",slug:"introduction-to-sni",link:"#introduction-to-sni",children:[]},{level:2,title:"Idea",slug:"idea",link:"#idea",children:[]},{level:2,title:"Adding DNS Records",slug:"adding-dns-records",link:"#adding-dns-records",children:[]},{level:2,title:"Applying for TLS Certificate",slug:"applying-for-tls-certificate",link:"#applying-for-tls-certificate",children:[]},{level:2,title:"Xray Configuration",slug:"xray-configuration",link:"#xray-configuration",children:[]},{level:2,title:"Nginx Configuration",slug:"nginx-configuration",link:"#nginx-configuration",children:[]},{level:2,title:"Caddy Configuration",slug:"caddy-configuration",link:"#caddy-configuration",children:[]},{level:2,title:"Reference",slug:"reference",link:"#reference",children:[]},{level:2,title:"Quotation",slug:"quotation",link:"#quotation",children:[]}],path:"/en/document/level-1/fallbacks-with-sni.html",pathLocale:"/en/",extraFields:[]},{title:"路由 (routing) 功能简析(上)",headers:[{level:2,title:"1. 初识【路由】三兄弟",slug:"_1-初识【路由】三兄弟",link:"#_1-初识【路由】三兄弟",children:[]},{level:2,title:"2. 基本功: “兄弟一条心”",slug:"_2-基本功-兄弟一条心",link:"#_2-基本功-兄弟一条心",children:[{level:3,title:"2.1 入站",slug:"_2-1-入站",link:"#_2-1-入站",children:[]},{level:3,title:"2.3 路由",slug:"_2-3-路由",link:"#_2-3-路由",children:[]},{level:3,title:"2.4 路由配置项解析之一:流量筛选的依据",slug:"_2-4-路由配置项解析之一-流量筛选的依据",link:"#_2-4-路由配置项解析之一-流量筛选的依据",children:[]}]},{level:2,title:"3. 小试牛刀: “三分天下” 之 “域名分流”",slug:"_3-小试牛刀-三分天下-之-域名分流",link:"#_3-小试牛刀-三分天下-之-域名分流",children:[{level:3,title:"3.1 入站",slug:"_3-1-入站",link:"#_3-1-入站",children:[]},{level:3,title:"3.2 出站",slug:"_3-2-出站",link:"#_3-2-出站",children:[]},{level:3,title:"3.3 路由",slug:"_3-3-路由",link:"#_3-3-路由",children:[]},{level:3,title:"3.4 简析域名文件: geosite.dat",slug:"_3-4-简析域名文件-geosite-dat",link:"#_3-4-简析域名文件-geosite-dat",children:[]},{level:3,title:"3.5 所以 geosite.dat 到底是什么?不是有个 GFWList 吗?",slug:"_3-5-所以-geosite-dat-到底是什么-不是有个-gfwlist-吗",link:"#_3-5-所以-geosite-dat-到底是什么-不是有个-gfwlist-吗",children:[]},{level:3,title:"3.6 军师锦囊藏奇兵:一条隐藏的路由规则",slug:"_3-6-军师锦囊藏奇兵-一条隐藏的路由规则",link:"#_3-6-军师锦囊藏奇兵-一条隐藏的路由规则",children:[]},{level:3,title:"3.7 再看“三分天下”的大地图",slug:"_3-7-再看-三分天下-的大地图",link:"#_3-7-再看-三分天下-的大地图",children:[]}]},{level:2,title:"4. “三分天下” 之 “蜀魏争雄”",slug:"_4-三分天下-之-蜀魏争雄",link:"#_4-三分天下-之-蜀魏争雄",children:[]},{level:2,title:"5. 攻城略池 - 多种路由匹配条件",slug:"_5-攻城略池-多种路由匹配条件",link:"#_5-攻城略池-多种路由匹配条件",children:[]}],path:"/en/document/level-1/routing-lv1-part1.html",pathLocale:"/en/",extraFields:[]},{title:"路由 (routing) 功能简析(下)",headers:[{level:2,title:"5. 攻城略池 - 多种路由匹配条件",slug:"_5-攻城略池-多种路由匹配条件",link:"#_5-攻城略池-多种路由匹配条件",children:[{level:3,title:"5.1 基于指定域名分流:[domain], [full] 等",slug:"_5-1-基于指定域名分流-domain-full-等",link:"#_5-1-基于指定域名分流-domain-full-等",children:[]},{level:3,title:"5.2 基于 IP 文件分流:geoip.dat",slug:"_5-2-基于-ip-文件分流-geoip-dat",link:"#_5-2-基于-ip-文件分流-geoip-dat",children:[]},{level:3,title:"5.3 基于指定 IP 地址分流",slug:"_5-3-基于指定-ip-地址分流",link:"#_5-3-基于指定-ip-地址分流",children:[]},{level:3,title:"5.4 基于协议类型分流:[protocol] 等",slug:"_5-4-基于协议类型分流-protocol-等",link:"#_5-4-基于协议类型分流-protocol-等",children:[]},{level:3,title:"5.5 基于更多条件的分流",slug:"_5-5-基于更多条件的分流",link:"#_5-5-基于更多条件的分流",children:[]}]},{level:2,title:"6. “霸业初定”:路由规则整体回顾",slug:"_6-霸业初定-路由规则整体回顾",link:"#_6-霸业初定-路由规则整体回顾",children:[]},{level:2,title:"7. 路由配置常见错误",slug:"_7-路由配置常见错误",link:"#_7-路由配置常见错误",children:[{level:3,title:"7.1 错误示范",slug:"_7-1-错误示范",link:"#_7-1-错误示范",children:[]},{level:3,title:"7.2 正确示范",slug:"_7-2-正确示范",link:"#_7-2-正确示范",children:[]}]},{level:2,title:"8. 明修栈道、暗渡陈仓",slug:"_8-明修栈道、暗渡陈仓",link:"#_8-明修栈道、暗渡陈仓",children:[{level:3,title:'8.1 域名策略: "AsIs"',slug:"_8-1-域名策略-asis",link:"#_8-1-域名策略-asis",children:[]},{level:3,title:'8.2 域名策略: "IPIfNonMatch"',slug:"_8-2-域名策略-ipifnonmatch",link:"#_8-2-域名策略-ipifnonmatch",children:[]},{level:3,title:'8.3 域名策略: "IPOnDemand"',slug:"_8-3-域名策略-ipondemand",link:"#_8-3-域名策略-ipondemand",children:[]}]},{level:2,title:"9. 思考题",slug:"_9-思考题",link:"#_9-思考题",children:[]},{level:2,title:"10. 结语",slug:"_10-结语",link:"#_10-结语",children:[]},{level:2,title:"11. 尾注",slug:"_11-尾注",link:"#_11-尾注",children:[]}],path:"/en/document/level-1/routing-lv1-part2.html",pathLocale:"/en/",extraFields:[]},{title:"Xray 的工作模式",headers:[{level:2,title:"单服务器模式",slug:"单服务器模式",link:"#单服务器模式",children:[]},{level:2,title:"桥接模式",slug:"桥接模式",link:"#桥接模式",children:[]},{level:2,title:"工作原理",slug:"工作原理",link:"#工作原理",children:[]}],path:"/en/document/level-1/work.html",pathLocale:"/en/",extraFields:[]},{title:"Advanced Documentation",headers:[],path:"/en/document/level-2/",pathLocale:"/en/",extraFields:[]},{title:"Transparent proxy via GID",headers:[{level:2,title:"Ideas",slug:"ideas",link:"#ideas",children:[]},{level:2,title:"Configuration Procedure",slug:"configuration-procedure",link:"#configuration-procedure",children:[{level:3,title:"1. Preliminary preparation",slug:"_1-preliminary-preparation",link:"#_1-preliminary-preparation",children:[]},{level:3,title:"2. Add user (Android users please ignore this section)",slug:"_2-add-user-android-users-please-ignore-this-section",link:"#_2-add-user-android-users-please-ignore-this-section",children:[]},{level:3,title:"3. Configure and run Xray, and configure iptables rules",slug:"_3-configure-and-run-xray-and-configure-iptables-rules",link:"#_3-configure-and-run-xray-and-configure-iptables-rules",children:[]}]},{level:2,title:"Steps",slug:"steps",link:"#steps",children:[{level:3,title:"1. Finish Preliminary preparation and Add user",slug:"_1-finish-preliminary-preparation-and-add-user",link:"#_1-finish-preliminary-preparation-and-add-user",children:[]},{level:3,title:"2. Preparing Xray profiles",slug:"_2-preparing-xray-profiles",link:"#_2-preparing-xray-profiles",children:[]},{level:3,title:"3. Configuring the maximum number of open files and run the Xray client",slug:"_3-configuring-the-maximum-number-of-open-files-and-run-the-xray-client",link:"#_3-configuring-the-maximum-number-of-open-files-and-run-the-xray-client",children:[]},{level:3,title:"4. Setting up iptables rules",slug:"_4-setting-up-iptables-rules",link:"#_4-setting-up-iptables-rules",children:[]}]}],path:"/en/document/level-2/iptables_gid.html",pathLocale:"/en/",extraFields:[]},{title:"Nginx 或 Haproxy 搭建 TLS 隧道隐藏指纹",headers:[{level:2,title:"编译 nginx --with-stream",slug:"编译-nginx-with-stream",link:"#编译-nginx-with-stream",children:[]},{level:2,title:"配置 nginx",slug:"配置-nginx",link:"#配置-nginx",children:[]},{level:2,title:"xray 配置",slug:"xray-配置",link:"#xray-配置",children:[]},{level:2,title:"客户端及服务端启动服务",slug:"客户端及服务端启动服务",link:"#客户端及服务端启动服务",children:[]},{level:2,title:"结束",slug:"结束",link:"#结束",children:[]},{level:2,title:"HTTPS 隧道",slug:"https-隧道",link:"#https-隧道",children:[{level:3,title:"haproxy_client 配置 (运行前去掉注释)",slug:"haproxy-client-配置-运行前去掉注释",link:"#haproxy-client-配置-运行前去掉注释",children:[]},{level:3,title:"haproxy_server 配置 (运行前去掉注释)",slug:"haproxy-server-配置-运行前去掉注释",link:"#haproxy-server-配置-运行前去掉注释",children:[]},{level:3,title:"xray 配置",slug:"xray-配置-1",link:"#xray-配置-1",children:[]}]},{level:2,title:"WebSocket over HTTP/2",slug:"websocket-over-http-2",link:"#websocket-over-http-2",children:[{level:3,title:"haproxy_client 配置",slug:"haproxy-client-配置",link:"#haproxy-client-配置",children:[]},{level:3,title:"haproxy_server 配置",slug:"haproxy-server-配置",link:"#haproxy-server-配置",children:[]},{level:3,title:"xray 配置",slug:"xray-配置-2",link:"#xray-配置-2",children:[]}]},{level:2,title:"gRPC over HTTP/2",slug:"grpc-over-http-2",link:"#grpc-over-http-2",children:[{level:3,title:"haproxy_client 配置",slug:"haproxy-client-配置-1",link:"#haproxy-client-配置-1",children:[]},{level:3,title:"haproxy_server 配置",slug:"haproxy-server-配置-1",link:"#haproxy-server-配置-1",children:[]},{level:3,title:"xray 配置",slug:"xray-配置-3",link:"#xray-配置-3",children:[]},{level:3,title:"haproxy_client 配置",slug:"haproxy-client-配置-2",link:"#haproxy-client-配置-2",children:[]},{level:3,title:"haproxy_server 配置",slug:"haproxy-server-配置-2",link:"#haproxy-server-配置-2",children:[]},{level:3,title:"xray 配置",slug:"xray-配置-4",link:"#xray-配置-4",children:[]}]}],path:"/en/document/level-2/nginx_or_haproxy_tls_tunnel.html",pathLocale:"/en/",extraFields:[]},{title:"出站流量重定向",headers:[{level:2,title:"前言",slug:"前言",link:"#前言",children:[]},{level:2,title:"1、安装代理或者 VPN 软件(例如 Wireguard、IPsec 等)",slug:"_1、安装代理或者-vpn-软件-例如-wireguard、ipsec-等",link:"#_1、安装代理或者-vpn-软件-例如-wireguard、ipsec-等",children:[]},{level:2,title:"2、编辑 VPN 配置文件(以 WireGuard 为例)",slug:"_2、编辑-vpn-配置文件-以-wireguard-为例",link:"#_2、编辑-vpn-配置文件-以-wireguard-为例",children:[]},{level:2,title:"3、启用 WireGuard 网络接口",slug:"_3、启用-wireguard-网络接口",link:"#_3、启用-wireguard-网络接口",children:[]},{level:2,title:"4、Xray-core 配置文件修改",slug:"_4、xray-core-配置文件修改",link:"#_4、xray-core-配置文件修改",children:[]},{level:2,title:"5、系统设置配置",slug:"_5、系统设置配置",link:"#_5、系统设置配置",children:[]},{level:2,title:"6、完成 WireGuard 相关设置",slug:"_6、完成-wireguard-相关设置",link:"#_6、完成-wireguard-相关设置",children:[]},{level:2,title:"后记",slug:"后记",link:"#后记",children:[]},{level:2,title:"感谢",slug:"感谢",link:"#感谢",children:[]}],path:"/en/document/level-2/redirect.html",pathLocale:"/en/",extraFields:[]},{title:"TProxy 透明代理",headers:[{level:2,title:"开始之前",slug:"开始之前",link:"#开始之前",children:[]},{level:2,title:"Xray 配置",slug:"xray-配置",link:"#xray-配置",children:[]},{level:2,title:"策略路由配置",slug:"策略路由配置",link:"#策略路由配置",children:[]},{level:2,title:"Netfilter 配置",slug:"netfilter-配置",link:"#netfilter-配置",children:[]},{level:2,title:"配置永久化与开机自启",slug:"配置永久化与开机自启",link:"#配置永久化与开机自启",children:[]}],path:"/en/document/level-2/tproxy.html",pathLocale:"/en/",extraFields:[]},{title:"TProxy 透明代理 (ipv4 and ipv6)",headers:[{level:2,title:"Xray 配置",slug:"xray-配置",link:"#xray-配置",children:[{level:3,title:"客户端配置",slug:"客户端配置",link:"#客户端配置",children:[]},{level:3,title:"服务端配置",slug:"服务端配置",link:"#服务端配置",children:[]}]},{level:2,title:"Netfilter 配置",slug:"netfilter-配置",link:"#netfilter-配置",children:[{level:3,title:"首先设置策略路由",slug:"首先设置策略路由",link:"#首先设置策略路由",children:[]},{level:3,title:"使用 iptables",slug:"使用-iptables",link:"#使用-iptables",children:[]},{level:3,title:"使用 nftables",slug:"使用-nftables",link:"#使用-nftables",children:[]},{level:3,title:"开机自动运行 Netfilter 配置",slug:"开机自动运行-netfilter-配置",link:"#开机自动运行-netfilter-配置",children:[]}]},{level:2,title:"局域网设备上网设置",slug:"局域网设备上网设置",link:"#局域网设备上网设置",children:[{level:3,title:"方法一",slug:"方法一",link:"#方法一",children:[]},{level:3,title:"方法二",slug:"方法二",link:"#方法二",children:[]}]},{level:2,title:"Finally",slug:"finally",link:"#finally",children:[]},{level:2,title:"写在最后",slug:"写在最后",link:"#写在最后",children:[]}],path:"/en/document/level-2/tproxy_ipv4_and_ipv6.html",pathLocale:"/en/",extraFields:[]},{title:"流量统计",headers:[{level:2,title:"查看流量信息",slug:"查看流量信息",link:"#查看流量信息",children:[]},{level:2,title:"流量信息的处理",slug:"流量信息的处理",link:"#流量信息的处理",children:[]}],path:"/en/document/level-2/traffic_stats.html",pathLocale:"/en/",extraFields:[]},{title:"Enhancing Proxy Security with Cloudflare Warp",headers:[{level:2,title:"Applying for a Warp Account",slug:"applying-for-a-warp-account",link:"#applying-for-a-warp-account",children:[]},{level:2,title:"Diverting inbound traffic to warp on the server side",slug:"diverting-inbound-traffic-to-warp-on-the-server-side",link:"#diverting-inbound-traffic-to-warp-on-the-server-side",children:[]},{level:2,title:"Using Warp Chain Proxy on the Client Side",slug:"using-warp-chain-proxy-on-the-client-side",link:"#using-warp-chain-proxy-on-the-client-side",children:[]}],path:"/en/document/level-2/warp.html",pathLocale:"/en/",extraFields:[]},{title:"Browser Dialer",headers:[{level:2,title:"Предыстория",slug:"предыстория",link:"#предыстория",children:[]},{level:2,title:"Конфигурация",slug:"конфигурация",link:"#конфигурация",children:[]},{level:2,title:"Внутренняя работа",slug:"внутренняя-работа",link:"#внутренняя-работа",children:[]},{level:2,title:"WebSocket",slug:"websocket",link:"#websocket",children:[]},{level:2,title:"SplitHTTP",slug:"splithttp",link:"#splithttp",children:[]}],path:"/ru/config/features/browser_dialer.html",pathLocale:"/ru/",extraFields:[]},{title:"Переменные среды",headers:[{level:2,title:"Путь к файлам ресурсов",slug:"путь-к-фаилам-ресурсов",link:"#путь-к-фаилам-ресурсов",children:[]},{level:2,title:"Расположение файла конфигурации",slug:"расположение-фаила-конфигурации",link:"#расположение-фаила-конфигурации",children:[]},{level:2,title:"Каталог с несколькими конфигурациями",slug:"каталог-с-несколькими-конфигурациями",link:"#каталог-с-несколькими-конфигурациями",children:[]}],path:"/ru/config/features/env.html",pathLocale:"/ru/",extraFields:[]},{title:"Fallback",headers:[{level:2,title:"Настройка fallbacks",slug:"настроика-fallbacks",link:"#настроика-fallbacks",children:[{level:3,title:"FallbackObject",slug:"fallbackobject",link:"#fallbackobject",children:[]},{level:3,title:"Дополнительные замечания",slug:"дополнительные-замечания",link:"#дополнительные-замечания",children:[]}]},{level:2,title:"Теория Fallbacks",slug:"теория-fallbacks",link:"#теория-fallbacks",children:[]}],path:"/ru/config/features/fallback.html",pathLocale:"/ru/",extraFields:[]},{title:"Настройка с помощью нескольких файлов",headers:[{level:2,title:"Запуск с несколькими файлами",slug:"запуск-с-несколькими-фаилами",link:"#запуск-с-несколькими-фаилами",children:[]},{level:2,title:"Правила",slug:"правила",link:"#правила",children:[{level:3,title:"Обычные объекты ({})",slug:"обычные-объекты",link:"#обычные-объекты",children:[]},{level:3,title:"Массивы ([])",slug:"массивы",link:"#массивы",children:[]}]},{level:2,title:"Пример конфигурации",slug:"пример-конфигурации",link:"#пример-конфигурации",children:[]}],path:"/ru/config/features/multiple.html",pathLocale:"/ru/",extraFields:[]},{title:"Глубокое погружение в XTLS",headers:[],path:"/ru/config/features/xtls.html",pathLocale:"/ru/",extraFields:[]},{title:"Dokodemo-Door",headers:[{level:2,title:"InboundConfigurationObject",slug:"inboundconfigurationobject",link:"#inboundconfigurationobject",children:[]},{level:2,title:"Использование",slug:"использование",link:"#использование",children:[]},{level:2,title:"Пример настройки прозрачного прокси",slug:"пример-настроики-прозрачного-прокси",link:"#пример-настроики-прозрачного-прокси",children:[]}],path:"/ru/config/inbounds/dokodemo.html",pathLocale:"/ru/",extraFields:[]},{title:"HTTP",headers:[{level:2,title:"InboundConfigurationObject",slug:"inboundconfigurationobject",link:"#inboundconfigurationobject",children:[{level:3,title:"AccountObject",slug:"accountobject",link:"#accountobject",children:[]}]}],path:"/ru/config/inbounds/http.html",pathLocale:"/ru/",extraFields:[]},{title:"Shadowsocks",headers:[{level:2,title:"InboundConfigurationObject",slug:"inboundconfigurationobject",link:"#inboundconfigurationobject",children:[]},{level:2,title:"ClientObject",slug:"clientobject",link:"#clientobject",children:[]}],path:"/ru/config/inbounds/shadowsocks.html",pathLocale:"/ru/",extraFields:[]},{title:"Socks",headers:[{level:2,title:"InboundConfigurationObject",slug:"inboundconfigurationobject",link:"#inboundconfigurationobject",children:[{level:3,title:"AccountObject",slug:"accountobject",link:"#accountobject",children:[]}]}],path:"/ru/config/inbounds/socks.html",pathLocale:"/ru/",extraFields:[]},{title:"Trojan",headers:[{level:2,title:"InboundConfigurationObject",slug:"inboundconfigurationobject",link:"#inboundconfigurationobject",children:[{level:3,title:"ClientObject",slug:"clientobject",link:"#clientobject",children:[]}]}],path:"/ru/config/inbounds/trojan.html",pathLocale:"/ru/",extraFields:[]},{title:"VLESS",headers:[{level:2,title:"InboundConfigurationObject",slug:"inboundconfigurationobject",link:"#inboundconfigurationobject",children:[{level:3,title:"ClientObject",slug:"clientobject",link:"#clientobject",children:[]}]}],path:"/ru/config/inbounds/vless.html",pathLocale:"/ru/",extraFields:[]},{title:"VMess",headers:[{level:2,title:"InboundConfigurationObject",slug:"inboundconfigurationobject",link:"#inboundconfigurationobject",children:[{level:3,title:"ClientObject",slug:"clientobject",link:"#clientobject",children:[]}]}],path:"/ru/config/inbounds/vmess.html",pathLocale:"/ru/",extraFields:[]},{title:"Wireguard",headers:[{level:2,title:"InboundConfigurationObject",slug:"inboundconfigurationobject",link:"#inboundconfigurationobject",children:[{level:3,title:"Peers",slug:"peers",link:"#peers",children:[]}]}],path:"/ru/config/inbounds/wireguard.html",pathLocale:"/ru/",extraFields:[]},{title:"Blackhole",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[{level:3,title:"ResponseObject",slug:"responseobject",link:"#responseobject",children:[]}]}],path:"/ru/config/outbounds/blackhole.html",pathLocale:"/ru/",extraFields:[]},{title:"DNS",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[]},{level:2,title:"Пример настройки DNS",slug:"пример-настроики-dns",link:"#пример-настроики-dns",children:[]}],path:"/ru/config/outbounds/dns.html",pathLocale:"/ru/",extraFields:[]},{title:"Freedom",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[]}],path:"/ru/config/outbounds/freedom.html",pathLocale:"/ru/",extraFields:[]},{title:"HTTP",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[{level:3,title:"ServerObject",slug:"serverobject",link:"#serverobject",children:[]}]}],path:"/ru/config/outbounds/http.html",pathLocale:"/ru/",extraFields:[]},{title:"Loopback",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[{level:3,title:"Как использовать?",slug:"как-использовать",link:"#как-использовать",children:[]}]}],path:"/ru/config/outbounds/loopback.html",pathLocale:"/ru/",extraFields:[]},{title:"Shadowsocks",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[{level:3,title:"ServerObject",slug:"serverobject",link:"#serverobject",children:[]}]}],path:"/ru/config/outbounds/shadowsocks.html",pathLocale:"/ru/",extraFields:[]},{title:"Socks",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[{level:3,title:"ServerObject",slug:"serverobject",link:"#serverobject",children:[]}]}],path:"/ru/config/outbounds/socks.html",pathLocale:"/ru/",extraFields:[]},{title:"Trojan",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[{level:3,title:"ServerObject",slug:"serverobject",link:"#serverobject",children:[]}]}],path:"/ru/config/outbounds/trojan.html",pathLocale:"/ru/",extraFields:[]},{title:"VLESS",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[{level:3,title:"ServerObject",slug:"serverobject",link:"#serverobject",children:[]},{level:3,title:"UserObject",slug:"userobject",link:"#userobject",children:[]}]}],path:"/ru/config/outbounds/vless.html",pathLocale:"/ru/",extraFields:[]},{title:"VMess",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[{level:3,title:"ServerObject",slug:"serverobject",link:"#serverobject",children:[]}]}],path:"/ru/config/outbounds/vmess.html",pathLocale:"/ru/",extraFields:[]},{title:"WireGuard",headers:[{level:2,title:"OutboundConfigurationObject",slug:"outboundconfigurationobject",link:"#outboundconfigurationobject",children:[{level:3,title:"Peers",slug:"peers",link:"#peers",children:[]}]}],path:"/ru/config/outbounds/wireguard.html",pathLocale:"/ru/",extraFields:[]},{title:"gRPC",headers:[{level:2,title:"GRPCObject",slug:"grpcobject",link:"#grpcobject",children:[]}],path:"/ru/config/transports/grpc.html",pathLocale:"/ru/",extraFields:[]},{title:"HTTP/2",headers:[{level:2,title:"HttpObject",slug:"httpobject",link:"#httpobject",children:[]}],path:"/ru/config/transports/h2.html",pathLocale:"/ru/",extraFields:[]},{title:"HTTPUpgrade",headers:[{level:2,title:"HttpUpgradeObject",slug:"httpupgradeobject",link:"#httpupgradeobject",children:[]}],path:"/ru/config/transports/httpupgrade.html",pathLocale:"/ru/",extraFields:[]},{title:"mKCP",headers:[{level:2,title:"KcpObject",slug:"kcpobject",link:"#kcpobject",children:[{level:3,title:"HeaderObject",slug:"headerobject",link:"#headerobject",children:[]}]},{level:2,title:"Благодарности",slug:"благодарности",link:"#благодарности",children:[]},{level:2,title:"Улучшения протокола KCP",slug:"улучшения-протокола-kcp",link:"#улучшения-протокола-kcp",children:[{level:3,title:"Более компактный заголовок протокола",slug:"более-компактныи-заголовок-протокола",link:"#более-компактныи-заголовок-протокола",children:[]},{level:3,title:"Передача пакетов подтверждения",slug:"передача-пакетов-подтверждения",link:"#передача-пакетов-подтверждения",children:[]},{level:3,title:"Управление состоянием соединения",slug:"управление-состоянием-соединения",link:"#управление-состоянием-соединения",children:[]}]}],path:"/ru/config/transports/mkcp.html",pathLocale:"/ru/",extraFields:[]},{title:"SplitHTTP",headers:[{level:2,title:"SplitHttpObject",slug:"splithttpobject",link:"#splithttpobject",children:[]},{level:2,title:"Детали протокола",slug:"детали-протокола",link:"#детали-протокола",children:[]},{level:2,title:"BrowserDialer",slug:"browserdialer",link:"#browserdialer",children:[]}],path:"/ru/config/transports/splithttp.html",pathLocale:"/ru/",extraFields:[]},{title:"TCP",headers:[{level:2,title:"TcpObject",slug:"tcpobject",link:"#tcpobject",children:[{level:3,title:"NoneHeaderObject",slug:"noneheaderobject",link:"#noneheaderobject",children:[]},{level:3,title:"HttpHeaderObject",slug:"httpheaderobject",link:"#httpheaderobject",children:[]}]}],path:"/ru/config/transports/tcp.html",pathLocale:"/ru/",extraFields:[]},{title:"WebSocket",headers:[{level:2,title:"WebSocketObject",slug:"websocketobject",link:"#websocketobject",children:[]},{level:2,title:"Browser Dialer",slug:"browser-dialer",link:"#browser-dialer",children:[]}],path:"/ru/config/transports/websocket.html",pathLocale:"/ru/",extraFields:[]},{title:"编译文档",headers:[{level:2,title:"前序工作",slug:"前序工作",link:"#前序工作",children:[]},{level:2,title:"拉取 Xray 源代码",slug:"拉取-xray-源代码",link:"#拉取-xray-源代码",children:[]},{level:2,title:"构建二进制",slug:"构建二进制",link:"#构建二进制",children:[{level:3,title:"Windows(Powershell):",slug:"windows-powershell",link:"#windows-powershell",children:[]},{level:3,title:"macOS, Linux:",slug:"macos-linux",link:"#macos-linux",children:[]}]},{level:2,title:"交叉编译:",slug:"交叉编译",link:"#交叉编译",children:[]},{level:2,title:"可复现构建:",slug:"可复现构建",link:"#可复现构建",children:[]}],path:"/ru/development/intro/compile.html",pathLocale:"/ru/",extraFields:[]},{title:"设计目标",headers:[{level:2,title:"架构",slug:"架构",link:"#架构",children:[{level:3,title:"应用层",slug:"应用层",link:"#应用层",children:[]},{level:3,title:"代理层",slug:"代理层",link:"#代理层",children:[]},{level:3,title:"传输层",slug:"传输层",link:"#传输层",children:[]}]}],path:"/ru/development/intro/design.html",pathLocale:"/ru/",extraFields:[]},{title:"开发规范",headers:[{level:2,title:"基本",slug:"基本",link:"#基本",children:[{level:3,title:"版本控制",slug:"版本控制",link:"#版本控制",children:[]},{level:3,title:"分支(Branch)",slug:"分支-branch",link:"#分支-branch",children:[]},{level:3,title:"发布(Release)",slug:"发布-release",link:"#发布-release",children:[]},{level:3,title:"引用其它项目",slug:"引用其它项目",link:"#引用其它项目",children:[]}]},{level:2,title:"开发流程",slug:"开发流程",link:"#开发流程",children:[{level:3,title:"写代码之前",slug:"写代码之前",link:"#写代码之前",children:[]},{level:3,title:"修改代码",slug:"修改代码",link:"#修改代码",children:[]},{level:3,title:"Pull Request",slug:"pull-request",link:"#pull-request",children:[]},{level:3,title:"对代码的修改",slug:"对代码的修改",link:"#对代码的修改",children:[]}]},{level:2,title:"Xray 编码规范",slug:"xray-编码规范",link:"#xray-编码规范",children:[{level:3,title:"代码结构",slug:"代码结构",link:"#代码结构",children:[]},{level:3,title:"编码规范",slug:"编码规范",link:"#编码规范",children:[]}]}],path:"/ru/development/intro/guide.html",pathLocale:"/ru/",extraFields:[]},{title:"mKCP 协议",headers:[{level:2,title:"版本",slug:"版本",link:"#版本",children:[]},{level:2,title:"依赖",slug:"依赖",link:"#依赖",children:[{level:3,title:"底层协议",slug:"底层协议",link:"#底层协议",children:[]},{level:3,title:"函数",slug:"函数",link:"#函数",children:[]}]},{level:2,title:"通讯过程",slug:"通讯过程",link:"#通讯过程",children:[]},{level:2,title:"数据格式",slug:"数据格式",link:"#数据格式",children:[{level:3,title:"数据包",slug:"数据包",link:"#数据包",children:[]},{level:3,title:"数据片段",slug:"数据片段",link:"#数据片段",children:[]},{level:3,title:"确认片段",slug:"确认片段",link:"#确认片段",children:[]},{level:3,title:"心跳片段",slug:"心跳片段",link:"#心跳片段",children:[]}]}],path:"/ru/development/protocols/mkcp.html",pathLocale:"/ru/",extraFields:[]},{title:"Mux.Cool 协议",headers:[{level:2,title:"版本",slug:"版本",link:"#版本",children:[]},{level:2,title:"依赖",slug:"依赖",link:"#依赖",children:[{level:3,title:"底层协议",slug:"底层协议",link:"#底层协议",children:[]}]},{level:2,title:"通讯过程",slug:"通讯过程",link:"#通讯过程",children:[{level:3,title:"客户端行为",slug:"客户端行为",link:"#客户端行为",children:[]},{level:3,title:"服务器端行为",slug:"服务器端行为",link:"#服务器端行为",children:[]}]},{level:2,title:"传输格式",slug:"传输格式",link:"#传输格式",children:[{level:3,title:"帧格式",slug:"帧格式",link:"#帧格式",children:[]},{level:3,title:"元数据",slug:"元数据",link:"#元数据",children:[]},{level:3,title:"新建子连接 (New)",slug:"新建子连接-new",link:"#新建子连接-new",children:[]},{level:3,title:"保持子连接 (Keep)",slug:"保持子连接-keep",link:"#保持子连接-keep",children:[]},{level:3,title:"关闭子连接 (End)",slug:"关闭子连接-end",link:"#关闭子连接-end",children:[]},{level:3,title:"保持连接 (KeepAlive)",slug:"保持连接-keepalive",link:"#保持连接-keepalive",children:[]}]},{level:2,title:"应用",slug:"应用",link:"#应用",children:[]}],path:"/ru/development/protocols/muxcool.html",pathLocale:"/ru/",extraFields:[]},{title:"VLESS 协议",headers:[{level:2,title:"Request & Response",slug:"request-response",link:"#request-response",children:[]},{level:2,title:"ProtoBuf",slug:"protobuf",link:"#protobuf",children:[]},{level:2,title:"Schedulers Flow",slug:"schedulers-flow",link:"#schedulers-flow",children:[]},{level:2,title:"Encryption",slug:"encryption",link:"#encryption",children:[]},{level:2,title:"UDP issues",slug:"udp-issues",link:"#udp-issues",children:[]},{level:2,title:"客户端开发指引",slug:"客户端开发指引",link:"#客户端开发指引",children:[]},{level:2,title:"VLESS 分享链接标准",slug:"vless-分享链接标准",link:"#vless-分享链接标准",children:[]}],path:"/ru/development/protocols/vless.html",pathLocale:"/ru/",extraFields:[]},{title:"VMess 协议",headers:[{level:2,title:"版本",slug:"版本",link:"#版本",children:[]},{level:2,title:"依赖",slug:"依赖",link:"#依赖",children:[{level:3,title:"底层协议",slug:"底层协议",link:"#底层协议",children:[]},{level:3,title:"用户 ID",slug:"用户-id",link:"#用户-id",children:[]},{level:3,title:"函数",slug:"函数",link:"#函数",children:[]}]},{level:2,title:"通讯过程",slug:"通讯过程",link:"#通讯过程",children:[]},{level:2,title:"客户端请求",slug:"客户端请求",link:"#客户端请求",children:[{level:3,title:"认证信息",slug:"认证信息",link:"#认证信息",children:[]},{level:3,title:"指令部分",slug:"指令部分",link:"#指令部分",children:[]},{level:3,title:"数据部分",slug:"数据部分",link:"#数据部分",children:[]}]},{level:2,title:"服务器应答",slug:"服务器应答",link:"#服务器应答",children:[{level:3,title:"动态端口指令",slug:"动态端口指令",link:"#动态端口指令",children:[]}]},{level:2,title:"注释",slug:"注释",link:"#注释",children:[]}],path:"/ru/development/protocols/vmess.html",pathLocale:"/ru/",extraFields:[]},{title:"Простые разговоры о сложном",headers:[],path:"/ru/document/level-0/",pathLocale:"/ru/",extraFields:[]},{title:"【Глава 1】 Простыми словами",headers:[{level:2,title:"1.1 Для кого эта документация?",slug:"_1-1-для-кого-эта-документация",link:"#_1-1-для-кого-эта-документация",children:[]},{level:2,title:"1.2 Для кого эта документация не предназначена?",slug:"_1-2-для-кого-эта-документация-не-предназначена",link:"#_1-2-для-кого-эта-документация-не-предназначена",children:[]},{level:2,title:"1.3 Важное замечание и другие примечания",slug:"_1-3-важное-замечание-и-другие-примечания",link:"#_1-3-важное-замечание-и-другие-примечания",children:[]},{level:2,title:"1.4 Почему самостоятельная настройка — это сложно?",slug:"_1-4-почему-самостоятельная-настроика-—-это-сложно",link:"#_1-4-почему-самостоятельная-настроика-—-это-сложно",children:[]},{level:2,title:"1.5 «Почему бы просто не пользоваться платным VPN?»",slug:"_1-5-«почему-бы-просто-не-пользоваться-платным-vpn-»",link:"#_1-5-«почему-бы-просто-не-пользоваться-платным-vpn-»",children:[]},{level:2,title:"1.6 Так стоит ли настраивать VPN самостоятельно?",slug:"_1-6-так-стоит-ли-настраивать-vpn-самостоятельно",link:"#_1-6-так-стоит-ли-настраивать-vpn-самостоятельно",children:[]},{level:2,title:"1.7 Немного лирики",slug:"_1-7-немного-лирики",link:"#_1-7-немного-лирики",children:[]},{level:2,title:"1.8 Ваш прогресс",slug:"_1-8-ваш-прогресс",link:"#_1-8-ваш-прогресс",children:[]}],path:"/ru/document/level-0/ch01-preface.html",pathLocale:"/ru/",extraFields:[]},{title:"【Глава 2】 Подготовка",headers:[{level:2,title:"2.1 Приобретение VPS",slug:"_2-1-приобретение-vps",link:"#_2-1-приобретение-vps",children:[]},{level:2,title:"2.2 Выбор доменного имени",slug:"_2-2-выбор-доменного-имени",link:"#_2-2-выбор-доменного-имени",children:[]},{level:2,title:"2.3 Необходимое программное обеспечение",slug:"_2-3-необходимое-программное-обеспечение",link:"#_2-3-необходимое-программное-обеспечение",children:[]},{level:2,title:"2.4 Ваш прогресс",slug:"_2-4-ваш-прогресс",link:"#_2-4-ваш-прогресс",children:[]}],path:"/ru/document/level-0/ch02-preparation.html",pathLocale:"/ru/",extraFields:[]},{title:"【Глава 3】 Удалённое подключение",headers:[{level:2,title:"3.1 Удалённое подключение к VPS (PuTTY)",slug:"_3-1-удаленное-подключение-к-vps-putty",link:"#_3-1-удаленное-подключение-к-vps-putty",children:[]},{level:2,title:"3.2 Успешное подключение по SSH! Знакомство с командной строкой!",slug:"_3-2-успешное-подключение-по-ssh-знакомство-с-команднои-строкои",link:"#_3-2-успешное-подключение-по-ssh-знакомство-с-команднои-строкои",children:[]},{level:2,title:"3.3 Первое обновление программного обеспечения Linux!",slug:"_3-3-первое-обновление-программного-обеспечения-linux",link:"#_3-3-первое-обновление-программного-обеспечения-linux",children:[]},{level:2,title:"3.4 Ваш прогресс",slug:"_3-4-ваш-прогресс",link:"#_3-4-ваш-прогресс",children:[]}],path:"/ru/document/level-0/ch03-ssh.html",pathLocale:"/ru/",extraFields:[]},{title:"【Глава 4】 Обеспечение безопасности",headers:[{level:2,title:"4.1 Зачем нужна безопасность?",slug:"_4-1-зачем-нужна-безопасность",link:"#_4-1-зачем-нужна-безопасность",children:[]},{level:2,title:"4.2 Какие именно риски существуют?",slug:"_4-2-какие-именно-риски-существуют",link:"#_4-2-какие-именно-риски-существуют",children:[]},{level:2,title:"4.3 Какие меры безопасности нужно предпринять?",slug:"_4-3-какие-меры-безопасности-нужно-предпринять",link:"#_4-3-какие-меры-безопасности-нужно-предпринять",children:[]},{level:2,title:"4.4 Изменение порта SSH",slug:"_4-4-изменение-порта-ssh",link:"#_4-4-изменение-порта-ssh",children:[]},{level:2,title:"4.5 Создание нового пользователя",slug:"_4-5-создание-нового-пользователя",link:"#_4-5-создание-нового-пользователя",children:[]},{level:2,title:"4.6 Запрет удалённого подключения по SSH для пользователя root",slug:"_4-6-запрет-удаленного-подключения-по-ssh-для-пользователя-root",link:"#_4-6-запрет-удаленного-подключения-по-ssh-для-пользователя-root",children:[]},{level:2,title:"4.7 Настройка аутентификации по SSH-ключам и запрет аутентификации по паролю",slug:"_4-7-настроика-аутентификации-по-ssh-ключам-и-запрет-аутентификации-по-паролю",link:"#_4-7-настроика-аутентификации-по-ssh-ключам-и-запрет-аутентификации-по-паролю",children:[]},{level:2,title:"4.8 Ваш прогресс",slug:"_4-8-ваш-прогресс",link:"#_4-8-ваш-прогресс",children:[]}],path:"/ru/document/level-0/ch04-security.html",pathLocale:"/ru/",extraFields:[]},{title:"【Глава 5】 Создание веб-сайта",headers:[{level:2,title:"5.1 Зачем нужен веб-сайт?",slug:"_5-1-зачем-нужен-веб-саит",link:"#_5-1-зачем-нужен-веб-саит",children:[]},{level:2,title:"5.2 Подключение к VPS и установка Nginx",slug:"_5-2-подключение-к-vps-и-установка-nginx",link:"#_5-2-подключение-к-vps-и-установка-nginx",children:[]},{level:2,title:"5.3 Создание простой веб-страницы",slug:"_5-3-создание-простои-веб-страницы",link:"#_5-3-создание-простои-веб-страницы",children:[]},{level:2,title:"5.4 Распространённые ошибки",slug:"_5-4-распространенные-ошибки",link:"#_5-4-распространенные-ошибки",children:[]},{level:2,title:"5.5 Ваш прогресс",slug:"_5-5-ваш-прогресс",link:"#_5-5-ваш-прогресс",children:[]}],path:"/ru/document/level-0/ch05-webpage.html",pathLocale:"/ru/",extraFields:[]},{title:"【Глава 6】 Управление сертификатами",headers:[{level:2,title:"6.1 Получение SSL-сертификата",slug:"_6-1-получение-ssl-сертификата",link:"#_6-1-получение-ssl-сертификата",children:[]},{level:2,title:"6.2 Установка acme.sh",slug:"_6-2-установка-acme-sh",link:"#_6-2-установка-acme-sh",children:[]},{level:2,title:"6.3 Тестовый запрос сертификата",slug:"_6-3-тестовыи-запрос-сертификата",link:"#_6-3-тестовыи-запрос-сертификата",children:[]},{level:2,title:"6.4 Запрос настоящего сертификата",slug:"_6-4-запрос-настоящего-сертификата",link:"#_6-4-запрос-настоящего-сертификата",children:[]},{level:2,title:"6.5 Установка сертификата",slug:"_6-5-установка-сертификата",link:"#_6-5-установка-сертификата",children:[]},{level:2,title:"6.6 Ваш прогресс",slug:"_6-6-ваш-прогресс",link:"#_6-6-ваш-прогресс",children:[]}],path:"/ru/document/level-0/ch06-certificates.html",pathLocale:"/ru/",extraFields:[]},{title:"【Глава 7】Настройка Xray на сервере",headers:[{level:2,title:"7.1 Познать многое, усвоить нужное; копить постепенно, тратить осмотрительно",slug:"_7-1-познать-многое-усвоить-нужное-копить-постепенно-тратить-осмотрительно",link:"#_7-1-познать-многое-усвоить-нужное-копить-постепенно-тратить-осмотрительно",children:[]},{level:2,title:"7.2 Установка Xray",slug:"_7-2-установка-xray",link:"#_7-2-установка-xray",children:[]},{level:2,title:"7.3 Установка TLS-сертификата для Xray",slug:"_7-3-установка-tls-сертификата-для-xray",link:"#_7-3-установка-tls-сертификата-для-xray",children:[]},{level:2,title:"7.4 Настройка Xray",slug:"_7-4-настроика-xray",link:"#_7-4-настроика-xray",children:[]},{level:2,title:"7.5 Запуск Xray! (и проверка состояния сервиса)",slug:"_7-5-запуск-xray-и-проверка-состояния-сервиса",link:"#_7-5-запуск-xray-и-проверка-состояния-сервиса",children:[]},{level:2,title:"7.6 Базовое управление сервисами с помощью systemd",slug:"_7-6-базовое-управление-сервисами-с-помощью-systemd",link:"#_7-6-базовое-управление-сервисами-с-помощью-systemd",children:[]},{level:2,title:"7.7 Оптимизация сервера: включение BBR",slug:"_7-7-оптимизация-сервера-включение-bbr",link:"#_7-7-оптимизация-сервера-включение-bbr",children:[]},{level:2,title:"7.8 Оптимизация сервера: автоматическое перенаправление HTTP на HTTPS",slug:"_7-8-оптимизация-сервера-автоматическое-перенаправление-http-на-https",link:"#_7-8-оптимизация-сервера-автоматическое-перенаправление-http-на-https",children:[]},{level:2,title:"7.9 Оптимизация сервера: более гибкая настройка перенаправления",slug:"_7-9-оптимизация-сервера-более-гибкая-настроика-перенаправления",link:"#_7-9-оптимизация-сервера-более-гибкая-настроика-перенаправления",children:[]},{level:2,title:"7.10 Ваши успехи",slug:"_7-10-ваши-успехи",link:"#_7-10-ваши-успехи",children:[]},{level:2,title:"7.11 Важные исправления",slug:"_7-11-важные-исправления",link:"#_7-11-важные-исправления",children:[]}],path:"/ru/document/level-0/ch07-xray-server.html",pathLocale:"/ru/",extraFields:[]},{title:"【Глава 8】Настройка Xray на клиенте",headers:[{level:2,title:"8.1 Как работает Xray: краткое описание",slug:"_8-1-как-работает-xray-краткое-описание",link:"#_8-1-как-работает-xray-краткое-описание",children:[]},{level:2,title:"8.2 Подключение клиента к серверу",slug:"_8-2-подключение-клиента-к-серверу",link:"#_8-2-подключение-клиента-к-серверу",children:[]},{level:2,title:"8.3 Дополнительное задание 1: настройка xray-core на ПК вручную",slug:"_8-3-дополнительное-задание-1-настроика-xray-core-на-пк-вручную",link:"#_8-3-дополнительное-задание-1-настроика-xray-core-на-пк-вручную",children:[]},{level:2,title:"8.4 Дополнительное задание 2: запуск xray-core на ПК",slug:"_8-4-дополнительное-задание-2-запуск-xray-core-на-пк",link:"#_8-4-дополнительное-задание-2-запуск-xray-core-на-пк",children:[]},{level:2,title:"8.5 Дополнительное задание 3: автозапуск xray-core на ПК",slug:"_8-5-дополнительное-задание-3-автозапуск-xray-core-на-пк",link:"#_8-5-дополнительное-задание-3-автозапуск-xray-core-на-пк",children:[]},{level:2,title:"8.6 Финишная прямая!",slug:"_8-6-финишная-прямая",link:"#_8-6-финишная-прямая",children:[]},{level:2,title:"8.7 В бесконечность и далее!",slug:"_8-7-в-бесконечность-и-далее",link:"#_8-7-в-бесконечность-и-далее",children:[]}],path:"/ru/document/level-0/ch08-xray-clients.html",pathLocale:"/ru/",extraFields:[]},{title:"[Глава 9] Приложение",headers:[{level:2,title:"1. Индекс основных команд Linux для начинающих",slug:"_1-индекс-основных-команд-linux-для-начинающих",link:"#_1-индекс-основных-команд-linux-для-начинающих",children:[]},{level:2,title:"2. Индекс важных конфигурационных файлов Linux",slug:"_2-индекс-важных-конфигурационных-фаилов-linux",link:"#_2-индекс-важных-конфигурационных-фаилов-linux",children:[]},{level:2,title:"3. Индекс важных файлов Xray",slug:"_3-индекс-важных-фаилов-xray",link:"#_3-индекс-важных-фаилов-xray",children:[]}],path:"/ru/document/level-0/ch09-appendix.html",pathLocale:"/ru/",extraFields:[]},{title:"Советы для начинающих",headers:[],path:"/ru/document/level-1/",pathLocale:"/ru/",extraFields:[]},{title:"Обзор функции Fallback",headers:[{level:2,title:"1. Что такое Fallback в простых словах",slug:"_1-что-такое-fallback-в-простых-словах",link:"#_1-что-такое-fallback-в-простых-словах",children:[]},{level:2,title:"2. Что такое Fallback (ЧТО, КАК v1)",slug:"_2-что-такое-fallback-что-как-v1",link:"#_2-что-такое-fallback-что-как-v1",children:[]},{level:2,title:"3. Зачем нужен Fallback (ЗАЧЕМ v1)",slug:"_3-зачем-нужен-fallback-зачем-v1",link:"#_3-зачем-нужен-fallback-зачем-v1",children:[]},{level:2,title:"4. Полное понимание Fallback (ЧТО, ЗАЧЕМ, КАК v2)",slug:"_4-полное-понимание-fallback-что-зачем-как-v2",link:"#_4-полное-понимание-fallback-что-зачем-как-v2",children:[]},{level:2,title:"5. Пример и описание многоуровневого fallback",slug:"_5-пример-и-описание-многоуровневого-fallback",link:"#_5-пример-и-описание-многоуровневого-fallback",children:[{level:3,title:"5.1 Сначала скопируем фрагмент конфигурации прослушивания порта 443 на стороне сервера:",slug:"_5-1-сначала-скопируем-фрагмент-конфигурации-прослушивания-порта-443-на-стороне-сервера",link:"#_5-1-сначала-скопируем-фрагмент-конфигурации-прослушивания-порта-443-на-стороне-сервера",children:[]},{level:3,title:"5.2 Фрагмент конфигурации, отвечающий за обработку fallback:",slug:"_5-2-фрагмент-конфигурации-отвечающии-за-обработку-fallback",link:"#_5-2-фрагмент-конфигурации-отвечающии-за-обработку-fallback",children:[]}]},{level:2,title:"6. Заключение",slug:"_6-заключение",link:"#_6-заключение",children:[]},{level:2,title:"7. Дополнительное задание",slug:"_7-дополнительное-задание",link:"#_7-дополнительное-задание",children:[]}],path:"/ru/document/level-1/fallbacks-lv1.html",pathLocale:"/ru/",extraFields:[]},{title:"SNI Fallback",headers:[{level:2,title:"Сценарии использования",slug:"сценарии-использования",link:"#сценарии-использования",children:[]},{level:2,title:"Что такое SNI",slug:"что-такое-sni",link:"#что-такое-sni",children:[]},{level:2,title:"Идея",slug:"идея",link:"#идея",children:[]},{level:2,title:"Добавление DNS-записей",slug:"добавление-dns-записеи",link:"#добавление-dns-записеи",children:[]},{level:2,title:"Запрос TLS-сертификата",slug:"запрос-tls-сертификата",link:"#запрос-tls-сертификата",children:[]},{level:2,title:"Конфигурация Xray",slug:"конфигурация-xray",link:"#конфигурация-xray",children:[]},{level:2,title:"Конфигурация Nginx",slug:"конфигурация-nginx",link:"#конфигурация-nginx",children:[]},{level:2,title:"Конфигурация Caddy",slug:"конфигурация-caddy",link:"#конфигурация-caddy",children:[]},{level:2,title:"Ссылки",slug:"ссылки",link:"#ссылки",children:[]},{level:2,title:"Примечания",slug:"примечания",link:"#примечания",children:[]}],path:"/ru/document/level-1/fallbacks-with-sni.html",pathLocale:"/ru/",extraFields:[]},{title:"Краткий обзор функции маршрутизации (routing) (часть 1)",headers:[{level:2,title:"1. Знакомство с тремя братьями-маршрутизаторами",slug:"_1-знакомство-с-тремя-братьями-маршрутизаторами",link:"#_1-знакомство-с-тремя-братьями-маршрутизаторами",children:[]},{level:2,title:'2. Основы: "Братья едины"',slug:"_2-основы-братья-едины",link:"#_2-основы-братья-едины",children:[{level:3,title:"2.1 Входящий трафик",slug:"_2-1-входящии-трафик",link:"#_2-1-входящии-трафик",children:[]},{level:3,title:"2.2 Исходящий трафик",slug:"_2-2-исходящии-трафик",link:"#_2-2-исходящии-трафик",children:[]},{level:3,title:"2.3 Маршрутизация",slug:"_2-3-маршрутизация",link:"#_2-3-маршрутизация",children:[]},{level:3,title:"2.4 Анализ параметров конфигурации маршрутизации: критерии фильтрации трафика",slug:"_2-4-анализ-параметров-конфигурации-маршрутизации-критерии-фильтрации-трафика",link:"#_2-4-анализ-параметров-конфигурации-маршрутизации-критерии-фильтрации-трафика",children:[]}]},{level:2,title:'3. Первые шаги: "Разделение мира на три части" - "Разделение по домену"',slug:"_3-первые-шаги-разделение-мира-на-три-части-разделение-по-домену",link:"#_3-первые-шаги-разделение-мира-на-три-части-разделение-по-домену",children:[{level:3,title:"3.1 Входящий трафик",slug:"_3-1-входящии-трафик",link:"#_3-1-входящии-трафик",children:[]},{level:3,title:"3.2 Исходящий трафик",slug:"_3-2-исходящии-трафик",link:"#_3-2-исходящии-трафик",children:[]},{level:3,title:"3.3 Маршрутизация",slug:"_3-3-маршрутизация",link:"#_3-3-маршрутизация",children:[]},{level:3,title:"3.4 Краткий обзор файла доменов: geosite.dat",slug:"_3-4-краткии-обзор-фаила-доменов-geosite-dat",link:"#_3-4-краткии-обзор-фаила-доменов-geosite-dat",children:[]},{level:3,title:"3.5 Так что же такое geosite.dat? Разве у нас нет GFWList?",slug:"_3-5-так-что-же-такое-geosite-dat-разве-у-нас-нет-gfwlist",link:"#_3-5-так-что-же-такое-geosite-dat-разве-у-нас-нет-gfwlist",children:[]},{level:3,title:"3.6 Секретное оружие: скрытое правило маршрутизации",slug:"_3-6-секретное-оружие-скрытое-правило-маршрутизации",link:"#_3-6-секретное-оружие-скрытое-правило-маршрутизации",children:[]},{level:3,title:'3.7 Снова смотрим на карту "трех царств"',slug:"_3-7-снова-смотрим-на-карту-трех-царств",link:"#_3-7-снова-смотрим-на-карту-трех-царств",children:[]}]},{level:2,title:'4. "Разделение мира на три части" - "Битва Вэй и Шу"',slug:"_4-разделение-мира-на-три-части-битва-вэи-и-шу",link:"#_4-разделение-мира-на-три-части-битва-вэи-и-шу",children:[]},{level:2,title:"5. Покорение новых высот - Различные условия сопоставления маршрутов",slug:"_5-покорение-новых-высот-различные-условия-сопоставления-маршрутов",link:"#_5-покорение-новых-высот-различные-условия-сопоставления-маршрутов",children:[]}],path:"/ru/document/level-1/routing-lv1-part1.html",pathLocale:"/ru/",extraFields:[]},{title:"Краткий обзор функции маршрутизации (routing) (часть 2)",headers:[{level:2,title:"5. Покорение новых высот - Различные условия сопоставления маршрутов",slug:"_5-покорение-новых-высот-различные-условия-сопоставления-маршрутов",link:"#_5-покорение-новых-высот-различные-условия-сопоставления-маршрутов",children:[{level:3,title:"5.1 Разделение по определенному домену: [domain], [full] и т. д.",slug:"_5-1-разделение-по-определенному-домену-domain-full-и-т-д",link:"#_5-1-разделение-по-определенному-домену-domain-full-и-т-д",children:[]},{level:3,title:"5.2 Разделение по IP-адресам из файла: geoip.dat",slug:"_5-2-разделение-по-ip-адресам-из-фаила-geoip-dat",link:"#_5-2-разделение-по-ip-адресам-из-фаила-geoip-dat",children:[]},{level:3,title:"5.3 Разделение по определенному IP-адресу",slug:"_5-3-разделение-по-определенному-ip-адресу",link:"#_5-3-разделение-по-определенному-ip-адресу",children:[]},{level:3,title:"5.4 Разделение по типу протокола: [protocol] и т. д.",slug:"_5-4-разделение-по-типу-протокола-protocol-и-т-д",link:"#_5-4-разделение-по-типу-протокола-protocol-и-т-д",children:[]},{level:3,title:"5.5 Разделение по другим критериям",slug:"_5-5-разделение-по-другим-критериям",link:"#_5-5-разделение-по-другим-критериям",children:[]}]},{level:2,title:'6. "Начало новой эры": обзор правил маршрутизации',slug:"_6-начало-новои-эры-обзор-правил-маршрутизации",link:"#_6-начало-новои-эры-обзор-правил-маршрутизации",children:[]},{level:2,title:"7. Распространенные ошибки в конфигурации маршрутизации",slug:"_7-распространенные-ошибки-в-конфигурации-маршрутизации",link:"#_7-распространенные-ошибки-в-конфигурации-маршрутизации",children:[{level:3,title:"7.1 Неправильный пример",slug:"_7-1-неправильныи-пример",link:"#_7-1-неправильныи-пример",children:[]},{level:3,title:"7.2 Правильный пример",slug:"_7-2-правильныи-пример",link:"#_7-2-правильныи-пример",children:[]}]},{level:2,title:"8. Скрытые пути",slug:"_8-скрытые-пути",link:"#_8-скрытые-пути",children:[{level:3,title:'8.1 Стратегия домена: "AsIs"',slug:"_8-1-стратегия-домена-asis",link:"#_8-1-стратегия-домена-asis",children:[]},{level:3,title:'8.2 Стратегия домена: "IPIfNonMatch"',slug:"_8-2-стратегия-домена-ipifnonmatch",link:"#_8-2-стратегия-домена-ipifnonmatch",children:[]},{level:3,title:'8.3 Стратегия домена: "IPOnDemand"',slug:"_8-3-стратегия-домена-ipondemand",link:"#_8-3-стратегия-домена-ipondemand",children:[]}]},{level:2,title:"9. Задание для размышления",slug:"_9-задание-для-размышления",link:"#_9-задание-для-размышления",children:[]},{level:2,title:"10. Заключение",slug:"_10-заключение",link:"#_10-заключение",children:[]},{level:2,title:"11. Примечания",slug:"_11-примечания",link:"#_11-примечания",children:[]}],path:"/ru/document/level-1/routing-lv1-part2.html",pathLocale:"/ru/",extraFields:[]},{title:"Режимы работы Xray",headers:[{level:2,title:"Режим одного сервера",slug:"режим-одного-сервера",link:"#режим-одного-сервера",children:[]},{level:2,title:"Режим моста",slug:"режим-моста",link:"#режим-моста",children:[]},{level:2,title:"Принцип работы",slug:"принцип-работы",link:"#принцип-работы",children:[]}],path:"/ru/document/level-1/work.html",pathLocale:"/ru/",extraFields:[]},{title:"Продвинутая документация",headers:[],path:"/ru/document/level-2/",pathLocale:"/ru/",extraFields:[]},{title:"GID Прозрачное проксирование",headers:[{level:2,title:"Идея",slug:"идея",link:"#идея",children:[]},{level:2,title:"Настройка",slug:"настроика",link:"#настроика",children:[{level:3,title:"1. Предварительная подготовка",slug:"_1-предварительная-подготовка",link:"#_1-предварительная-подготовка",children:[]},{level:3,title:"2. Добавление пользователя (пропустите для Android)",slug:"_2-добавление-пользователя-пропустите-для-android",link:"#_2-добавление-пользователя-пропустите-для-android",children:[]},{level:3,title:"3. Настройка запуска Xray и правил iptables",slug:"_3-настроика-запуска-xray-и-правил-iptables",link:"#_3-настроика-запуска-xray-и-правил-iptables",children:[]}]},{level:2,title:"Ниже приведен пример полной настройки глобального проксирования с использованием TPROXY",slug:"ниже-приведен-пример-полнои-настроики-глобального-проксирования-с-использованием-tproxy",link:"#ниже-приведен-пример-полнои-настроики-глобального-проксирования-с-использованием-tproxy",children:[{level:3,title:"1. Выполните предварительную подготовку и добавление пользователя.",slug:"_1-выполните-предварительную-подготовку-и-добавление-пользователя",link:"#_1-выполните-предварительную-подготовку-и-добавление-пользователя",children:[]},{level:3,title:"2. Подготовьте конфигурационный файл Xray.",slug:"_2-подготовьте-конфигурационныи-фаил-xray",link:"#_2-подготовьте-конфигурационныи-фаил-xray",children:[]},{level:3,title:"3. Настройка максимального количества открытых файлов и запуск клиента Xray",slug:"_3-настроика-максимального-количества-открытых-фаилов-и-запуск-клиента-xray",link:"#_3-настроика-максимального-количества-открытых-фаилов-и-запуск-клиента-xray",children:[]},{level:3,title:"4. Настройка правил iptables",slug:"_4-настроика-правил-iptables",link:"#_4-настроика-правил-iptables",children:[]}]}],path:"/ru/document/level-2/iptables_gid.html",pathLocale:"/ru/",extraFields:[]},{title:"Создание TLS-туннеля с помощью Nginx или Haproxy для скрытия отпечатков",headers:[{level:2,title:"Компиляция nginx с поддержкой --with-stream",slug:"компиляция-nginx-с-поддержкои-with-stream",link:"#компиляция-nginx-с-поддержкои-with-stream",children:[]},{level:2,title:"Настройка nginx",slug:"настроика-nginx",link:"#настроика-nginx",children:[]},{level:2,title:"Настройка Xray",slug:"настроика-xray",link:"#настроика-xray",children:[]},{level:2,title:"Запуск сервисов на клиенте и сервере",slug:"запуск-сервисов-на-клиенте-и-сервере",link:"#запуск-сервисов-на-клиенте-и-сервере",children:[]},{level:2,title:"Завершение",slug:"завершение",link:"#завершение",children:[]},{level:2,title:"HTTPS-туннель",slug:"https-туннель",link:"#https-туннель",children:[{level:3,title:"Конфигурация haproxy_client (удалите комментарии перед запуском):",slug:"конфигурация-haproxy-client-удалите-комментарии-перед-запуском",link:"#конфигурация-haproxy-client-удалите-комментарии-перед-запуском",children:[]},{level:3,title:"Конфигурация haproxy_server (удалите комментарии перед запуском):",slug:"конфигурация-haproxy-server-удалите-комментарии-перед-запуском",link:"#конфигурация-haproxy-server-удалите-комментарии-перед-запуском",children:[]},{level:3,title:"Настройка Xray",slug:"настроика-xray-1",link:"#настроика-xray-1",children:[]}]},{level:2,title:"WebSocket over HTTP/2",slug:"websocket-over-http-2",link:"#websocket-over-http-2",children:[{level:3,title:"Конфигурация haproxy_client:",slug:"конфигурация-haproxy-client",link:"#конфигурация-haproxy-client",children:[]},{level:3,title:"Конфигурация haproxy_server:",slug:"конфигурация-haproxy-server",link:"#конфигурация-haproxy-server",children:[]},{level:3,title:"Настройка Xray",slug:"настроика-xray-2",link:"#настроика-xray-2",children:[]}]},{level:2,title:"gRPC over HTTP/2",slug:"grpc-over-http-2",link:"#grpc-over-http-2",children:[{level:3,title:"Конфигурация haproxy_client:",slug:"конфигурация-haproxy-client-1",link:"#конфигурация-haproxy-client-1",children:[]},{level:3,title:"Конфигурация haproxy_server:",slug:"конфигурация-haproxy-server-1",link:"#конфигурация-haproxy-server-1",children:[]},{level:3,title:"Настройка Xray",slug:"настроика-xray-3",link:"#настроика-xray-3",children:[]},{level:3,title:"Конфигурация haproxy_client:",slug:"конфигурация-haproxy-client-2",link:"#конфигурация-haproxy-client-2",children:[]},{level:3,title:"Конфигурация haproxy_server:",slug:"конфигурация-haproxy-server-2",link:"#конфигурация-haproxy-server-2",children:[]},{level:3,title:"Настройка Xray",slug:"настроика-xray-4",link:"#настроика-xray-4",children:[]}]}],path:"/ru/document/level-2/nginx_or_haproxy_tls_tunnel.html",pathLocale:"/ru/",extraFields:[]},{title:"Перенаправление исходящего трафика",headers:[{level:2,title:"Введение",slug:"введение",link:"#введение",children:[]},{level:2,title:"1. Установите прокси-сервер или VPN-клиент (например, Wireguard, IPsec и т.д.)",slug:"_1-установите-прокси-сервер-или-vpn-клиент-например-wireguard-ipsec-и-т-д",link:"#_1-установите-прокси-сервер-или-vpn-клиент-например-wireguard-ipsec-и-т-д",children:[]},{level:2,title:"2. Отредактируйте конфигурационный файл VPN (на примере WireGuard)",slug:"_2-отредактируите-конфигурационныи-фаил-vpn-на-примере-wireguard",link:"#_2-отредактируите-конфигурационныи-фаил-vpn-на-примере-wireguard",children:[]},{level:2,title:"3. Активируйте сетевой интерфейс WireGuard.",slug:"_3-активируите-сетевои-интерфеис-wireguard",link:"#_3-активируите-сетевои-интерфеис-wireguard",children:[]},{level:2,title:"4. Измените конфигурационный файл Xray-core.",slug:"_4-измените-конфигурационныи-фаил-xray-core",link:"#_4-измените-конфигурационныи-фаил-xray-core",children:[]},{level:2,title:"5. Настройка системы",slug:"_5-настроика-системы",link:"#_5-настроика-системы",children:[]},{level:2,title:"6. Завершение настройки WireGuard",slug:"_6-завершение-настроики-wireguard",link:"#_6-завершение-настроики-wireguard",children:[]},{level:2,title:"Послесловие",slug:"послесловие",link:"#послесловие",children:[]},{level:2,title:"Благодарности",slug:"благодарности",link:"#благодарности",children:[]}],path:"/ru/document/level-2/redirect.html",pathLocale:"/ru/",extraFields:[]},{title:"Прозрачное проксирование TProxy",headers:[{level:2,title:"Перед началом работы",slug:"перед-началом-работы",link:"#перед-началом-работы",children:[]},{level:2,title:"Настройка Xray",slug:"настроика-xray",link:"#настроика-xray",children:[]},{level:2,title:"Настройка маршрутизации по политике",slug:"настроика-маршрутизации-по-политике",link:"#настроика-маршрутизации-по-политике",children:[]},{level:2,title:"Настройка Netfilter",slug:"настроика-netfilter",link:"#настроика-netfilter",children:[]},{level:2,title:"Настройка автозагрузки и сохранения конфигурации",slug:"настроика-автозагрузки-и-сохранения-конфигурации",link:"#настроика-автозагрузки-и-сохранения-конфигурации",children:[]}],path:"/ru/document/level-2/tproxy.html",pathLocale:"/ru/",extraFields:[]},{title:"Прозрачное проксирование TProxy (ipv4 и ipv6)",headers:[{level:2,title:"Настройка Xray",slug:"настроика-xray",link:"#настроика-xray",children:[{level:3,title:"Конфигурация клиента",slug:"конфигурация-клиента",link:"#конфигурация-клиента",children:[]},{level:3,title:"Конфигурация сервера",slug:"конфигурация-сервера",link:"#конфигурация-сервера",children:[]}]},{level:2,title:"Настройка Netfilter",slug:"настроика-netfilter",link:"#настроика-netfilter",children:[{level:3,title:"Настройка маршрутизации по политике",slug:"настроика-маршрутизации-по-политике",link:"#настроика-маршрутизации-по-политике",children:[]},{level:3,title:"Использование iptables",slug:"использование-iptables",link:"#использование-iptables",children:[]},{level:3,title:"Использование nftables",slug:"использование-nftables",link:"#использование-nftables",children:[]},{level:3,title:"Автоматический запуск конфигурации Netfilter при загрузке",slug:"автоматическии-запуск-конфигурации-netfilter-при-загрузке",link:"#автоматическии-запуск-конфигурации-netfilter-при-загрузке",children:[]}]},{level:2,title:"Настройка доступа к интернету на устройствах локальной сети",slug:"настроика-доступа-к-интернету-на-устроиствах-локальнои-сети",link:"#настроика-доступа-к-интернету-на-устроиствах-локальнои-сети",children:[{level:3,title:"Метод 1",slug:"метод-1",link:"#метод-1",children:[]},{level:3,title:"Метод 2",slug:"метод-2",link:"#метод-2",children:[]}]},{level:2,title:"Результаты",slug:"результаты",link:"#результаты",children:[]},{level:2,title:"Заключение",slug:"заключение",link:"#заключение",children:[]}],path:"/ru/document/level-2/tproxy_ipv4_and_ipv6.html",pathLocale:"/ru/",extraFields:[]},{title:"Статистика трафика",headers:[{level:2,title:"Просмотр статистики трафика",slug:"просмотр-статистики-трафика",link:"#просмотр-статистики-трафика",children:[]},{level:2,title:"Обработка статистики трафика",slug:"обработка-статистики-трафика",link:"#обработка-статистики-трафика",children:[]}],path:"/ru/document/level-2/traffic_stats.html",pathLocale:"/ru/",extraFields:[]},{title:"Повышение безопасности проксирования с помощью Cloudflare Warp",headers:[{level:2,title:"Создание аккаунта Warp",slug:"создание-аккаунта-warp",link:"#создание-аккаунта-warp",children:[{level:3,title:"Спасибо Cloudflare за содействие свободному интернету! Теперь вы можете бесплатно пользоваться услугами Warp. При подключении автоматически выбирается ближайший сервер.",slug:"спасибо-cloudflare-за-содеиствие-свободному-интернету-теперь-вы-можете-бесплатно-пользоваться-услугами-warp-при-подключении-автоматически-выбирается-ближаишии-сервер",link:"#спасибо-cloudflare-за-содеиствие-свободному-интернету-теперь-вы-можете-бесплатно-пользоваться-услугами-warp-при-подключении-автоматически-выбирается-ближаишии-сервер",children:[]}]},{level:2,title:"Перенаправление трафика в Китай через Warp на сервере",slug:"перенаправление-трафика-в-китаи-через-warp-на-сервере",link:"#перенаправление-трафика-в-китаи-через-warp-на-сервере",children:[]},{level:2,title:"Использование Warp в качестве прокси-сервера в цепочке на клиенте",slug:"использование-warp-в-качестве-прокси-сервера-в-цепочке-на-клиенте",link:"#использование-warp-в-качестве-прокси-сервера-в-цепочке-на-клиенте",children:[]}],path:"/ru/document/level-2/warp.html",pathLocale:"/ru/",extraFields:[]},{title:"透明代理入门",headers:[{level:2,title:"什么是透明代理",slug:"什么是透明代理",link:"#什么是透明代理",children:[]},{level:2,title:"透明代理的实现",slug:"透明代理的实现",link:"#透明代理的实现",children:[{level:3,title:"tun2socks",slug:"tun2socks",link:"#tun2socks",children:[]},{level:3,title:"iptables/nftables",slug:"iptables-nftables",link:"#iptables-nftables",children:[]}]},{level:2,title:"iptables 实现透明代理原理",slug:"iptables-实现透明代理原理",link:"#iptables-实现透明代理原理",children:[]},{level:2,title:"透明代理难在哪里",slug:"透明代理难在哪里",link:"#透明代理难在哪里",children:[]},{level:2,title:"从零开始一步步实现基于 iptables-tproxy 的透明代理",slug:"从零开始一步步实现基于-iptables-tproxy-的透明代理",link:"#从零开始一步步实现基于-iptables-tproxy-的透明代理",children:[{level:3,title:"在开始之前,你需要有一定的基础知识:",slug:"在开始之前-你需要有一定的基础知识",link:"#在开始之前-你需要有一定的基础知识",children:[]},{level:3,title:"前期准备工作",slug:"前期准备工作",link:"#前期准备工作",children:[]},{level:3,title:"首先,我们先试试做到第一阶段",slug:"首先-我们先试试做到第一阶段",link:"#首先-我们先试试做到第一阶段",children:[]},{level:3,title:"第二阶段",slug:"第二阶段",link:"#第二阶段",children:[]},{level:3,title:"第三阶段",slug:"第三阶段",link:"#第三阶段",children:[]},{level:3,title:"第四阶段",slug:"第四阶段",link:"#第四阶段",children:[]},{level:3,title:"代理 ipv6",slug:"代理-ipv6",link:"#代理-ipv6",children:[]}]}],path:"/en/document/level-2/transparent_proxy/transparent_proxy.html",pathLocale:"/en/",extraFields:[]},{title:"Другие замечания по прозрачному проксированию с помощью iptables",headers:[{level:2,title:"Погружение в прозрачное проксирование",slug:"погружение-в-прозрачное-проксирование",link:"#погружение-в-прозрачное-проксирование",children:[{level:3,title:"Что такое прозрачное проксирование?",slug:"что-такое-прозрачное-проксирование",link:"#что-такое-прозрачное-проксирование",children:[]},{level:3,title:"Реализация прозрачного проксирования",slug:"реализация-прозрачного-проксирования",link:"#реализация-прозрачного-проксирования",children:[]},{level:3,title:"tun2socks",slug:"tun2socks",link:"#tun2socks",children:[]},{level:3,title:"iptables/nftables",slug:"iptables-nftables",link:"#iptables-nftables",children:[]}]},{level:2,title:"Принцип реализации прозрачного проксирования с помощью iptables",slug:"принцип-реализации-прозрачного-проксирования-с-помощью-iptables",link:"#принцип-реализации-прозрачного-проксирования-с-помощью-iptables",children:[]},{level:2,title:"В чем сложность прозрачного проксирования?",slug:"в-чем-сложность-прозрачного-проксирования",link:"#в-чем-сложность-прозрачного-проксирования",children:[]},{level:2,title:"Пошаговая реализация прозрачного проксирования на основе iptables-tproxy с нуля",slug:"пошаговая-реализация-прозрачного-проксирования-на-основе-iptables-tproxy-с-нуля",link:"#пошаговая-реализация-прозрачного-проксирования-на-основе-iptables-tproxy-с-нуля",children:[{level:3,title:"Прежде чем начать, вам необходимо иметь базовые знания:",slug:"прежде-чем-начать-вам-необходимо-иметь-базовые-знания",link:"#прежде-чем-начать-вам-необходимо-иметь-базовые-знания",children:[]},{level:3,title:"Предварительная подготовка",slug:"предварительная-подготовка",link:"#предварительная-подготовка",children:[]},{level:3,title:"Сначала давайте попробуем достичь первого этапа",slug:"сначала-даваите-попробуем-достичь-первого-этапа",link:"#сначала-даваите-попробуем-достичь-первого-этапа",children:[]},{level:3,title:"Второй этап",slug:"второи-этап",link:"#второи-этап",children:[]},{level:3,title:"Третий этап",slug:"третии-этап",link:"#третии-этап",children:[]},{level:3,title:"Четвертый этап",slug:"четвертыи-этап",link:"#четвертыи-этап",children:[]},{level:3,title:"Проксирование IPv6",slug:"проксирование-ipv6",link:"#проксирование-ipv6",children:[]}]}],path:"/ru/document/level-2/transparent_proxy/transparent_proxy.html",pathLocale:"/ru/",extraFields:[]},{title:"",headers:[],path:"/404.html",pathLocale:"/",extraFields:[]}],J2=ge(Y2),Q2=()=>J2,Z2=({searchIndex:e,routeLocale:t,query:l,maxSuggestions:i})=>{const n=C(()=>e.value.filter(r=>r.pathLocale===t.value));return C(()=>{const r=l.value.trim().toLowerCase();if(!r)return[];const o=[],c=(a,u)=>{fo(r,[u.title])&&o.push({link:`${a.path}#${u.slug}`,title:a.title,header:u.title});for(const d of u.children){if(o.length>=i.value)return;c(a,d)}};for(const a of n.value){if(o.length>=i.value)break;if(fo(r,[a.title,...a.extraFields])){o.push({link:a.path,title:a.title});continue}for(const u of a.headers){if(o.length>=i.value)break;c(a,u)}}return o})},ef=e=>{const t=ge(0);return{focusIndex:t,focusNext:()=>{t.value{t.value>0?t.value-=1:t.value=e.value.length-1}}},tf=_e({name:"SearchBox",props:{locales:{type:Object,required:!1,default:()=>({})},hotKeys:{type:Array,required:!1,default:()=>[]},maxSuggestions:{type:Number,required:!1,default:5}},setup(e){const{locales:t,hotKeys:l,maxSuggestions:i}=Ii(e),n=bt(),r=Jl(),o=Q2(),c=ge(null),a=ge(!1),u=ge(""),d=C(()=>t.value[r.value]??{}),v=Z2({searchIndex:o,routeLocale:r,query:u,maxSuggestions:i}),{focusIndex:_,focusNext:p,focusPrev:m}=ef(v);G2({input:c,hotKeys:l});const x=C(()=>a.value&&!!v.value.length),A=()=>{x.value&&m()},D=()=>{x.value&&p()},O=b=>{if(!x.value)return;const y=v.value[b];y&&n.push(y.link).then(()=>{u.value="",_.value=0})};return()=>he("form",{class:"search-box",role:"search"},[he("input",{ref:c,type:"search",placeholder:d.value.placeholder,autocomplete:"off",spellcheck:!1,value:u.value,onFocus:()=>a.value=!0,onBlur:()=>a.value=!1,onInput:b=>u.value=b.target.value,onKeydown:b=>{switch(b.key){case"ArrowUp":{A();break}case"ArrowDown":{D();break}case"Enter":{b.preventDefault(),O(_.value);break}}}}),x.value&&he("ul",{class:"suggestions",onMouseleave:()=>_.value=-1},v.value.map(({link:b,title:y,header:H},G)=>he("li",{class:["suggestion",{focus:_.value===G}],onMouseenter:()=>_.value=G,onMousedown:()=>O(G)},he("a",{href:b,onClick:N=>N.preventDefault()},[he("span",{class:"page-title"},y),H&&he("span",{class:"page-header"},`> ${H}`)]))))])}});var lf=["s","/"],nf={"/":{placeholder:"搜索"}};const rf=nf,of=lf,sf=5,cf=Et({enhance({app:e}){e.component("SearchBox",t=>he(tf,{locales:rf,hotKeys:of,maxSuggestions:sf,...t}))}}),af={enhance:({app:e})=>{e.component("Mermaid",h(()=>s(()=>import("./Mermaid-wJbLESOb.js"),__vite__mapDeps([])))),e.component("Tab",h(()=>s(()=>import("./Tab-BCE01DFa.js"),__vite__mapDeps([])))),e.component("Tabs",h(()=>s(()=>import("./Tabs-CcpaQpRZ.js"),__vite__mapDeps([]))))}},di=[ih,oh,dh,xh,Ph,Dh,R2,z2,cf,af],uf=[["v-8daa1a0e","/",{title:""},["/README.md"]],["v-aad48c6a","/about/news.html",{title:"大史记"},[":md"]],["v-ba934fd8","/config/",{title:"配置文件"},["/config/README.md"]],["v-41ade9da","/config/api.html",{title:"API 接口"},[":md"]],["v-83dedd38","/config/dns.html",{title:"内置 DNS 服务器"},[":md"]],["v-192a19b9","/config/fakedns.html",{title:"FakeDNS"},[":md"]],["v-7f6279d8","/config/inbound.html",{title:"入站代理"},[":md"]],["v-1d860c29","/config/log.html",{title:"日志配置"},[":md"]],["v-fbaf47ec","/config/metrics.html",{title:"Metrics"},[":md"]],["v-24956213","/config/observatory.html",{title:"连接观测"},[":md"]],["v-2367d756","/config/outbound.html",{title:"出站代理(Mux、XUDP)"},[":md"]],["v-4ebec35a","/config/policy.html",{title:"本地策略"},[":md"]],["v-31b7756a","/config/reverse.html",{title:"反向代理"},[":md"]],["v-70677432","/config/routing.html",{title:"路由"},[":md"]],["v-7e21d6ae","/config/stats.html",{title:"统计信息"},[":md"]],["v-e3dfff38","/config/transport.html",{title:"传输方式(uTLS、REALITY)"},[":md"]],["v-f7496066","/development/",{title:"开发指南"},["/development/README.md"]],["v-36b1a79b","/document/",{title:"快速入门"},["/document/README.md"]],["v-09a64f89","/document/command.html",{title:"命令参数"},[":md"]],["v-2b1adf48","/document/config.html",{title:"配置运行"},[":md"]],["v-86ee963a","/document/document.html",{title:"为 Project X 的文档贡献"},[":md"]],["v-0e5d7b39","/document/install.html",{title:"下载安装"},[":md"]],["v-2d0a870d","/en/",{title:""},["/en/README.md"]],["v-2d0ab8b3","/ru/",{title:""},["/ru/README.md"]],["v-0d714d87","/config/features/browser_dialer.html",{title:"Browser Dialer"},[":md"]],["v-0da7880a","/config/features/env.html",{title:"环境变量"},[":md"]],["v-2aeb21f9","/config/features/fallback.html",{title:"Fallback 回落"},[":md"]],["v-3acf20ea","/config/features/multiple.html",{title:"多文件配置"},[":md"]],["v-792e28f8","/config/features/xtls.html",{title:"XTLS 深度剖析"},[":md"]],["v-b50d2334","/config/inbounds/dokodemo.html",{title:"Dokodemo-Door"},[":md"]],["v-593408b0","/config/inbounds/http.html",{title:"HTTP"},[":md"]],["v-802a842a","/config/inbounds/shadowsocks.html",{title:"Shadowsocks"},[":md"]],["v-29995cea","/config/inbounds/socks.html",{title:"Socks"},[":md"]],["v-2a1b3d72","/config/inbounds/trojan.html",{title:"Trojan"},[":md"]],["v-fb92e8aa","/config/inbounds/vless.html",{title:"VLESS(XTLS Vision Seed)"},[":md"]],["v-167afaac","/config/inbounds/vmess.html",{title:"VMess"},[":md"]],["v-5588d0cc","/config/inbounds/wireguard.html",{title:"Wireguard"},[":md"]],["v-749ad71a","/config/outbounds/blackhole.html",{title:"Blackhole"},[":md"]],["v-6d39b970","/config/outbounds/dns.html",{title:"DNS"},[":md"]],["v-d76e893a","/config/outbounds/freedom.html",{title:"Freedom(fragment、noises)"},[":md"]],["v-c6b4b59e","/config/outbounds/http.html",{title:"HTTP"},[":md"]],["v-41ec0e0e","/config/outbounds/loopback.html",{title:"Loopback"},[":md"]],["v-7b293e4a","/config/outbounds/shadowsocks.html",{title:"Shadowsocks"},[":md"]],["v-15f5452a","/config/outbounds/socks.html",{title:"Socks"},[":md"]],["v-5797bdb3","/config/outbounds/trojan.html",{title:"Trojan"},[":md"]],["v-a60f016c","/config/outbounds/vless.html",{title:"VLESS(XTLS Vision Seed)"},[":md"]],["v-413cee4b","/config/outbounds/vmess.html",{title:"VMess"},[":md"]],["v-208ca3b9","/config/outbounds/wireguard.html",{title:"Wireguard"},[":md"]],["v-2877542a","/config/transports/grpc.html",{title:"gRPC"},[":md"]],["v-03a28284","/config/transports/h2.html",{title:"HTTP/2"},[":md"]],["v-04158536","/config/transports/httpupgrade.html",{title:"HTTPUpgrade"},[":md"]],["v-3167b1dd","/config/transports/mkcp.html",{title:"mKCP"},[":md"]],["v-eeea2fb0","/config/transports/splithttp.html",{title:"SplitHTTP(H2、QUIC H3)"},[":md"]],["v-33b1b709","/config/transports/tcp.html",{title:"TCP"},[":md"]],["v-1ff57bba","/config/transports/websocket.html",{title:"WebSocket"},[":md"]],["v-6a9e8054","/development/intro/compile.html",{title:"编译文档"},[":md"]],["v-95e3eaea","/development/intro/design.html",{title:"设计目标"},[":md"]],["v-61e7eea6","/development/intro/guide.html",{title:"开发规范"},[":md"]],["v-6e6c37e6","/development/protocols/mkcp.html",{title:"mKCP 协议"},[":md"]],["v-13168a21","/development/protocols/muxcool.html",{title:"Mux.Cool 协议"},[":md"]],["v-5c48c82b","/development/protocols/vless.html",{title:"VLESS 协议"},[":md"]],["v-1ee591a8","/development/protocols/vmess.html",{title:"VMess 协议"},[":md"]],["v-3f09dcfa","/document/level-0/",{title:"小小白白话文"},["/document/level-0/README.md"]],["v-fb444906","/document/level-0/ch01-preface.html",{title:"【第 1 章】 小小白白话文"},[":md"]],["v-075f3ae5","/document/level-0/ch02-preparation.html",{title:"【第 2 章】原料准备篇"},[":md"]],["v-726d0633","/document/level-0/ch03-ssh.html",{title:"【第 3 章】远程登录篇"},[":md"]],["v-430c6ab8","/document/level-0/ch04-security.html",{title:"【第 4 章】安全防护篇"},[":md"]],["v-717c6376","/document/level-0/ch05-webpage.html",{title:"【第 5 章】网站建设篇"},[":md"]],["v-278039be","/document/level-0/ch06-certificates.html",{title:"【第 6 章】证书管理篇"},[":md"]],["v-a0c7f88e","/document/level-0/ch07-xray-server.html",{title:"【第 7 章】Xray 服务器篇"},[":md"]],["v-86586ca2","/document/level-0/ch08-xray-clients.html",{title:"【第 8 章】Xray 客户端篇"},[":md"]],["v-3eb62514","/document/level-0/ch09-appendix.html",{title:"【第 9 章】附录"},[":md"]],["v-3f09dcbc","/document/level-1/",{title:"入门技巧"},["/document/level-1/README.md"]],["v-b21a2a20","/document/level-1/fallbacks-lv1.html",{title:"回落 (fallbacks) 功能简析"},[":md"]],["v-da623318","/document/level-1/fallbacks-with-sni.html",{title:"SNI 回落"},[":md"]],["v-fdd722ac","/document/level-1/routing-lv1-part1.html",{title:"路由 (routing) 功能简析(上)"},[":md"]],["v-fa6d716e","/document/level-1/routing-lv1-part2.html",{title:"路由 (routing) 功能简析(下)"},[":md"]],["v-2f29e106","/document/level-1/work.html",{title:"Xray 的工作模式"},[":md"]],["v-3f09dc7e","/document/level-2/",{title:"进阶文档"},["/document/level-2/README.md"]],["v-1c17916e","/document/level-2/iptables_gid.html",{title:"GID 透明代理"},[":md"]],["v-a001cfa6","/document/level-2/nginx_or_haproxy_tls_tunnel.html",{title:"Nginx 或 Haproxy 搭建 TLS 隧道隐藏指纹"},[":md"]],["v-46333b48","/document/level-2/redirect.html",{title:"出站流量重定向"},[":md"]],["v-338bc63e","/document/level-2/tproxy.html",{title:"TProxy 透明代理"},[":md"]],["v-d68f7d58","/document/level-2/tproxy_ipv4_and_ipv6.html",{title:"TProxy 透明代理 (ipv4 and ipv6)"},[":md"]],["v-e533e2c6","/document/level-2/traffic_stats.html",{title:"流量统计"},[":md"]],["v-1e465ab0","/document/level-2/warp.html",{title:"通过 Cloudflare Warp 增强代理安全性"},[":md"]],["v-1080fb37","/en/about/news.html",{title:"The Great Chronicles"},[":md"]],["v-317fc580","/en/config/",{title:"Configurations"},["/en/config/README.md"]],["v-45144c7f","/en/config/api.html",{title:"API Interface"},[":md"]],["v-23fbd2d0","/en/config/dns.html",{title:"Built-in DNS Server"},[":md"]],["v-2b7ec525","/en/config/fakedns.html",{title:"FakeDNS"},[":md"]],["v-5ab92300","/en/config/inbound.html",{title:"Inbound Proxy"},[":md"]],["v-f91d64d6","/en/config/log.html",{title:"Log Configuration"},[":md"]],["v-d705f114","/en/config/metrics.html",{title:"Metrics"},[":md"]],["v-5c8e777f","/en/config/observatory.html",{title:"Connection Monitoring"},[":md"]],["v-268cd669","/en/config/outbound.html",{title:"Outbound Proxies"},[":md"]],["v-4492d567","/en/config/policy.html",{title:"Local Policy"},[":md"]],["v-0d0e1e92","/en/config/reverse.html",{title:"Reverse Proxy"},[":md"]],["v-4bbe1d5a","/en/config/routing.html",{title:"Routing"},[":md"]],["v-16426d1a","/en/config/stats.html",{title:"Traffic Statistics"},[":md"]],["v-5de780d0","/en/config/transport.html",{title:"Transport"},[":md"]],["v-f88d343e","/en/development/",{title:"Development Guide"},["/en/development/README.md"]],["v-38d56a07","/en/document/",{title:"Quick Start"},["/en/document/README.md"]],["v-4d046016","/en/document/command.html",{title:"Command Parameters"},[":md"]],["v-22b35270","/en/document/config.html",{title:"Configure and Run"},[":md"]],["v-30bd7c12","/en/document/document.html",{title:"Contribute to Project X's Document"},[":md"]],["v-439608b6","/en/document/install.html",{title:"Download and Install"},[":md"]],["v-408e88d1","/ru/about/news.html",{title:"大史记"},[":md"]],["v-b1cce5cc","/ru/config/",{title:"Конфигурационный файл"},["/ru/config/README.md"]],["v-7521da19","/ru/config/api.html",{title:"API"},[":md"]],["v-5409606a","/ru/config/dns.html",{title:"Встроенный DNS-сервер"},[":md"]],["v-5877f5bf","/ru/config/fakedns.html",{title:"FakeDNS"},[":md"]],["v-00c6c1cc","/ru/config/inbound.html",{title:"Входящие подключения"},[":md"]],["v-990249a2","/ru/config/log.html",{title:"Настройка журнала"},[":md"]],["v-7d138fe0","/ru/config/metrics.html",{title:"Метрики"},[":md"]],["v-11e9cb19","/ru/config/observatory.html",{title:"Мониторинг подключений"},[":md"]],["v-ce8c8de2","/ru/config/outbound.html",{title:"Исходящие подключения"},[":md"]],["v-3dc4298d","/ru/config/policy.html",{title:"Локальные политики"},[":md"]],["v-26722151","/ru/config/reverse.html",{title:"Обратный прокси"},[":md"]],["v-071a21ed","/ru/config/routing.html",{title:"Маршрутизация"},[":md"]],["v-7922fc34","/ru/config/stats.html",{title:"Статистика"},[":md"]],["v-3156f2ea","/ru/config/transport.html",{title:"Транспорт"},[":md"]],["v-40ee4e87","/ru/development/",{title:"开发指南"},["/ru/development/README.md"]],["v-a1c899be","/ru/document/",{title:"Быстрый старт"},["/ru/document/README.md"]],["v-a6257be2","/ru/document/command.html",{title:"Командные аргументы"},[":md"]],["v-d63f95d4","/ru/document/config.html",{title:"Настройка и запуск"},[":md"]],["v-fbbfd9c6","/ru/document/document.html",{title:"Вклад в документацию Project X"},[":md"]],["v-9cb72482","/ru/document/install.html",{title:"Загрузка и установка"},[":md"]],["v-51a51d87","/document/level-2/transparent_proxy/transparent_proxy.html",{title:"透明代理入门"},[":md"]],["v-76b9a0f3","/en/config/features/browser_dialer.html",{title:"Browser Dialer"},[":md"]],["v-565dbfc4","/en/config/features/env.html",{title:"Environment Variables"},[":md"]],["v-0fbd1336","/en/config/features/fallback.html",{title:"Fallback"},[":md"]],["v-a0627812","/en/config/features/multiple.html",{title:"Multi-file configuration"},[":md"]],["v-d190d938","/en/config/features/xtls.html",{title:"Deep analysis of XTLS"},[":md"]],["v-72afc2d2","/en/config/inbounds/dokodemo.html",{title:"Dokodemo-Door"},[":md"]],["v-773d731c","/en/config/inbounds/http.html",{title:"HTTP"},[":md"]],["v-f555fc02","/en/config/inbounds/shadowsocks.html",{title:"Shadowsocks"},[":md"]],["v-e35196c2","/en/config/inbounds/socks.html",{title:"SOCKS"},[":md"]],["v-29188644","/en/config/inbounds/trojan.html",{title:"Trojan"},[":md"]],["v-255a6ebf","/en/config/inbounds/vless.html",{title:"VLESS"},[":md"]],["v-8cc24480","/en/config/inbounds/vmess.html",{title:"VMess"},[":md"]],["v-a2605ea4","/en/config/inbounds/wireguard.html",{title:"Wireguard"},[":md"]],["v-64e47ef4","/en/config/outbounds/blackhole.html",{title:"Blackhole"},[":md"]],["v-e979b848","/en/config/outbounds/dns.html",{title:"DNS"},[":md"]],["v-617f0fcf","/en/config/outbounds/freedom.html",{title:"Freedom"},[":md"]],["v-3fc98845","/en/config/outbounds/http.html",{title:"HTTP"},[":md"]],["v-1b804722","/en/config/outbounds/loopback.html",{title:"Loopback"},[":md"]],["v-63077cb6","/en/config/outbounds/shadowsocks.html",{title:"Shadowsocks"},[":md"]],["v-516476d4","/en/config/outbounds/socks.html",{title:"Socks"},[":md"]],["v-7d61a872","/en/config/outbounds/trojan.html",{title:"Trojan"},[":md"]],["v-6e50feb6","/en/config/outbounds/vless.html",{title:"VLESS"},[":md"]],["v-02956db7","/en/config/outbounds/vmess.html",{title:"VMess"},[":md"]],["v-797f8d25","/en/config/outbounds/wireguard.html",{title:"Wireguard"},[":md"]],["v-2c6058d4","/en/config/transports/grpc.html",{title:"gRPC"},[":md"]],["v-1c38292a","/en/config/transports/h2.html",{title:"HTTP/2"},[":md"]],["v-17ff144a","/en/config/transports/httpupgrade.html",{title:"HTTPUpgrade"},[":md"]],["v-1a7f9d6e","/en/config/transports/mkcp.html",{title:"mKCP"},[":md"]],["v-4df52c3c","/en/config/transports/splithttp.html",{title:"SplitHTTP"},[":md"]],["v-5254cbc6","/en/config/transports/tcp.html",{title:"TCP"},[":md"]],["v-9520f392","/en/config/transports/websocket.html",{title:"WebSocket"},[":md"]],["v-b7760e2c","/en/development/intro/compile.html",{title:"Compile the document"},[":md"]],["v-fb774212","/en/development/intro/design.html",{title:"Design Objectives"},[":md"]],["v-38c376c1","/en/development/intro/guide.html",{title:"Development Standards"},[":md"]],["v-21bccd79","/en/development/protocols/mkcp.html",{title:"mKCP Protocol"},[":md"]],["v-27001935","/en/development/protocols/muxcool.html",{title:"Mux.Cool Protocol"},[":md"]],["v-21b30c3f","/en/development/protocols/vless.html",{title:"VLESS Protocol"},[":md"]],["v-94110980","/en/development/protocols/vmess.html",{title:"VMess Protocol"},[":md"]],["v-789ba7ef","/en/document/level-0/",{title:"Plain and Simple Language"},["/en/document/level-0/README.md"]],["v-d3712ade","/en/document/level-0/ch01-preface.html",{title:"[Chapter 1] Simple and Plain Language"},[":md"]],["v-41f9c00e","/en/document/level-0/ch02-preparation.html",{title:"[Chapter 2] Preparation of Raw Materials"},[":md"]],["v-4c013f47","/en/document/level-0/ch03-ssh.html",{title:"[Chapter 3] Remote Login"},[":md"]],["v-a75683b8","/en/document/level-0/ch04-security.html",{title:"[Chapter 4] Security and Protection"},[":md"]],["v-f5341aec","/en/document/level-0/ch05-webpage.html",{title:"Chapter 5: Website Building"},[":md"]],["v-4458f72a","/en/document/level-0/ch06-certificates.html",{title:"[Chapter 6] Certificate Management"},[":md"]],["v-f1802e66","/en/document/level-0/ch07-xray-server.html",{title:"[Chapter 7]Xray Server"},[":md"]],["v-4ca6f1ca","/en/document/level-0/ch08-xray-clients.html",{title:"【第 8 章】Xray 客户端篇"},[":md"]],["v-b0030f00","/en/document/level-0/ch09-appendix.html",{title:"【第 9 章】附录"},[":md"]],["v-789ba80e","/en/document/level-1/",{title:"Beginner's Tips"},["/en/document/level-1/README.md"]],["v-103b3e5c","/en/document/level-1/fallbacks-lv1.html",{title:"回落 (fallbacks) 功能简析"},[":md"]],["v-110dd688","/en/document/level-1/fallbacks-with-sni.html",{title:"SNI fallback"},[":md"]],["v-c425a7d4","/en/document/level-1/routing-lv1-part1.html",{title:"路由 (routing) 功能简析(上)"},[":md"]],["v-c0bbf696","/en/document/level-1/routing-lv1-part2.html",{title:"路由 (routing) 功能简析(下)"},[":md"]],["v-5b6477cc","/en/document/level-1/work.html",{title:"Xray 的工作模式"},[":md"]],["v-789ba82d","/en/document/level-2/",{title:"Advanced Documentation"},["/en/document/level-2/README.md"]],["v-05ddc65d","/en/document/level-2/iptables_gid.html",{title:"Transparent proxy via GID"},[":md"]],["v-474afe99","/en/document/level-2/nginx_or_haproxy_tls_tunnel.html",{title:"Nginx 或 Haproxy 搭建 TLS 隧道隐藏指纹"},[":md"]],["v-930ac920","/en/document/level-2/redirect.html",{title:"出站流量重定向"},[":md"]],["v-c579975c","/en/document/level-2/tproxy.html",{title:"TProxy 透明代理"},[":md"]],["v-7efb7c68","/en/document/level-2/tproxy_ipv4_and_ipv6.html",{title:"TProxy 透明代理 (ipv4 and ipv6)"},[":md"]],["v-12a33bee","/en/document/level-2/traffic_stats.html",{title:"流量统计"},[":md"]],["v-7d2b8478","/en/document/level-2/warp.html",{title:"Enhancing Proxy Security with Cloudflare Warp"},[":md"]],["v-1cfb44e6","/ru/config/features/browser_dialer.html",{title:"Browser Dialer"},[":md"]],["v-6a3f8078","/ru/config/features/env.html",{title:"Переменные среды"},[":md"]],["v-74f22e7f","/ru/config/features/fallback.html",{title:"Fallback"},[":md"]],["v-2c9f7c11","/ru/config/features/multiple.html",{title:"Настройка с помощью нескольких файлов"},[":md"]],["v-630c687e","/ru/config/features/xtls.html",{title:"Глубокое погружение в XTLS"},[":md"]],["v-20ff0a28","/ru/config/inbounds/dokodemo.html",{title:"Dokodemo-Door"},[":md"]],["v-43124836","/ru/config/inbounds/http.html",{title:"HTTP"},[":md"]],["v-6a351ba5","/ru/config/inbounds/shadowsocks.html",{title:"Shadowsocks"},[":md"]],["v-3d1d02c5","/ru/config/inbounds/socks.html",{title:"Socks"},[":md"]],["v-1567b378","/ru/config/inbounds/trojan.html",{title:"Trojan"},[":md"]],["v-57bf8636","/ru/config/inbounds/vless.html",{title:"VLESS"},[":md"]],["v-6864abe6","/ru/config/inbounds/vmess.html",{title:"VMess"},[":md"]],["v-67d3c858","/ru/config/inbounds/wireguard.html",{title:"Wireguard"},[":md"]],["v-5910da20","/ru/config/outbounds/blackhole.html",{title:"Blackhole"},[":md"]],["v-5717f8f6","/ru/config/outbounds/dns.html",{title:"DNS"},[":md"]],["v-4360702e","/ru/config/outbounds/freedom.html",{title:"Freedom"},[":md"]],["v-22e1532a","/ru/config/outbounds/http.html",{title:"HTTP"},[":md"]],["v-38c69248","/ru/config/outbounds/loopback.html",{title:"Loopback"},[":md"]],["v-1a2a97d0","/ru/config/outbounds/shadowsocks.html",{title:"Shadowsocks"},[":md"]],["v-0141bb30","/ru/config/outbounds/socks.html",{title:"Socks"},[":md"]],["v-544bef26","/ru/config/outbounds/trojan.html",{title:"Trojan"},[":md"]],["v-cf761560","/ru/config/outbounds/vless.html",{title:"VLESS"},[":md"]],["v-2c896451","/ru/config/outbounds/vmess.html",{title:"VMess"},[":md"]],["v-0502a6bf","/ru/config/outbounds/wireguard.html",{title:"WireGuard"},[":md"]],["v-13c3ca30","/ru/config/transports/grpc.html",{title:"gRPC"},[":md"]],["v-2fe60378","/ru/config/transports/h2.html",{title:"HTTP/2"},[":md"]],["v-453f5c70","/ru/config/transports/httpupgrade.html",{title:"HTTPUpgrade"},[":md"]],["v-1cb427e3","/ru/config/transports/mkcp.html",{title:"mKCP"},[":md"]],["v-32d545e2","/ru/config/transports/splithttp.html",{title:"SplitHTTP"},[":md"]],["v-f4c92f7a","/ru/config/transports/tcp.html",{title:"TCP"},[":md"]],["v-cb60c046","/ru/config/transports/websocket.html",{title:"WebSocket"},[":md"]],["v-7ce977e0","/ru/development/intro/compile.html",{title:"编译文档"},[":md"]],["v-01d5d1de","/ru/development/intro/design.html",{title:"设计目标"},[":md"]],["v-4d4e5367","/ru/development/intro/guide.html",{title:"开发规范"},[":md"]],["v-a58031da","/ru/development/protocols/mkcp.html",{title:"mKCP 协议"},[":md"]],["v-5440615b","/ru/development/protocols/muxcool.html",{title:"Mux.Cool 协议"},[":md"]],["v-069325e5","/ru/development/protocols/vless.html",{title:"VLESS 协议"},[":md"]],["v-ca50d634","/ru/development/protocols/vmess.html",{title:"VMess 协议"},[":md"]],["v-490791ee","/ru/document/level-0/",{title:"Простые разговоры о сложном"},["/ru/document/level-0/README.md"]],["v-78f09a92","/ru/document/level-0/ch01-preface.html",{title:"【Глава 1】 Простыми словами"},[":md"]],["v-64f6e51f","/ru/document/level-0/ch02-preparation.html",{title:"【Глава 2】 Подготовка"},[":md"]],["v-69478a6d","/ru/document/level-0/ch03-ssh.html",{title:"【Глава 3】 Удалённое подключение"},[":md"]],["v-271d7abe","/ru/document/level-0/ch04-security.html",{title:"【Глава 4】 Обеспечение безопасности"},[":md"]],["v-9ab38aa0","/ru/document/level-0/ch05-webpage.html",{title:"【Глава 5】 Создание веб-сайта"},[":md"]],["v-7cddd6c4","/ru/document/level-0/ch06-certificates.html",{title:"【Глава 6】 Управление сертификатами"},[":md"]],["v-0d33adf3","/ru/document/level-0/ch07-xray-server.html",{title:"【Глава 7】Настройка Xray на сервере"},[":md"]],["v-123166b5","/ru/document/level-0/ch08-xray-clients.html",{title:"【Глава 8】Настройка Xray на клиенте"},[":md"]],["v-22c7351a","/ru/document/level-0/ch09-appendix.html",{title:"[Глава 9] Приложение"},[":md"]],["v-490791b0","/ru/document/level-1/",{title:"Советы для начинающих"},["/ru/document/level-1/README.md"]],["v-e9f80a14","/ru/document/level-1/fallbacks-lv1.html",{title:"Обзор функции Fallback"},[":md"]],["v-2db62ba4","/ru/document/level-1/fallbacks-with-sni.html",{title:"SNI Fallback"},[":md"]],["v-531be8a0","/ru/document/level-1/routing-lv1-part1.html",{title:"Краткий обзор функции маршрутизации (routing) (часть 1)"},[":md"]],["v-4fb23762","/ru/document/level-1/routing-lv1-part2.html",{title:"Краткий обзор функции маршрутизации (routing) (часть 2)"},[":md"]],["v-fdd8db80","/ru/document/level-1/work.html",{title:"Режимы работы Xray"},[":md"]],["v-49079172","/ru/document/level-2/",{title:"Продвинутая документация"},["/ru/document/level-2/README.md"]],["v-331e0e83","/ru/document/level-2/iptables_gid.html",{title:"GID Прозрачное проксирование"},[":md"]],["v-7418a5b3","/ru/document/level-2/nginx_or_haproxy_tls_tunnel.html",{title:"Создание TLS-туннеля с помощью Nginx или Haproxy для скрытия отпечатков"},[":md"]],["v-587e32d4","/ru/document/level-2/redirect.html",{title:"Перенаправление исходящего трафика"},[":md"]],["v-9c63de10","/ru/document/level-2/tproxy.html",{title:"Прозрачное проксирование TProxy"},[":md"]],["v-a4c782e4","/ru/document/level-2/tproxy_ipv4_and_ipv6.html",{title:"Прозрачное проксирование TProxy (ipv4 и ipv6)"},[":md"]],["v-71771ea3","/ru/document/level-2/traffic_stats.html",{title:"Статистика трафика"},[":md"]],["v-70300bea","/ru/document/level-2/warp.html",{title:"Повышение безопасности проксирования с помощью Cloudflare Warp"},[":md"]],["v-7689d7f3","/en/document/level-2/transparent_proxy/transparent_proxy.html",{title:"透明代理入门"},[":md"]],["v-39b3c50d","/ru/document/level-2/transparent_proxy/transparent_proxy.html",{title:"Другие замечания по прозрачному проксированию с помощью iptables"},[":md"]],["v-3706649a","/404.html",{title:""},[]]];var go=_e({name:"Vuepress",setup(){const e=zu();return()=>he(e.value)}}),df=()=>uf.reduce((e,[t,l,i,n])=>(e.push({name:t,path:l,component:go,meta:i},{path:l.endsWith("/")?l+"index.html":l.substring(0,l.length-5),redirect:l},...n.map(r=>({path:r===":md"?l.substring(0,l.length-5)+".md":r,redirect:l}))),e),[{name:"404",path:"/:catchAll(.*)",component:go}]),hf=Od,vf=()=>{const e=Yd({history:hf(_s("/")),routes:df(),scrollBehavior:(t,l,i)=>i||(t.hash?{el:t.hash}:{top:0})});return e.beforeResolve(async(t,l)=>{var i;(t.path!==l.path||l===_t)&&([t.meta._data]=await Promise.all([vt.resolvePageData(t.name),(i=ps[t.name])==null?void 0:i.__asyncLoader()]))}),e},_f=e=>{e.component("ClientOnly",Bn),e.component("Content",Gu)},ff=(e,t,l)=>{const i=C(()=>t.currentRoute.value.path),n=Vh(i,()=>t.currentRoute.value.meta._data),r=C(()=>vt.resolveLayouts(l)),o=C(()=>vt.resolveRouteLocale(ll.value.locales,i.value)),c=C(()=>vt.resolveSiteLocaleData(ll.value,o.value)),a=C(()=>vt.resolvePageFrontmatter(n.value)),u=C(()=>vt.resolvePageHeadTitle(n.value,c.value)),d=C(()=>vt.resolvePageHead(u.value,a.value,c.value)),v=C(()=>vt.resolvePageLang(n.value,c.value)),_=C(()=>vt.resolvePageLayout(n.value,r.value));return e.provide(Hu,r),e.provide(ms,n),e.provide(bs,a),e.provide(Bu,u),e.provide(ks,d),e.provide(Es,v),e.provide(ys,_),e.provide(Mn,o),e.provide(Ls,c),Object.defineProperties(e.config.globalProperties,{$frontmatter:{get:()=>a.value},$head:{get:()=>d.value},$headTitle:{get:()=>u.value},$lang:{get:()=>v.value},$page:{get:()=>n.value},$routeLocale:{get:()=>o.value},$site:{get:()=>ll.value},$siteLocale:{get:()=>c.value},$withBase:{get:()=>Wn}}),{layouts:r,pageData:n,pageFrontmatter:a,pageHead:d,pageHeadTitle:u,pageLang:v,pageLayout:_,routeLocale:o,siteData:ll,siteLocaleData:c}},gf=()=>{const e=$u(),t=Wu();let l=[];const i=()=>{e.value.forEach(o=>{const c=pf(o);c&&l.push(c)})},n=()=>{const o=[];return e.value.forEach(c=>{const a=mf(c);a&&o.push(a)}),o},r=()=>{document.documentElement.lang=t.value;const o=n();l.forEach((c,a)=>{const u=o.findIndex(d=>c.isEqualNode(d));u===-1?(c.remove(),delete l[a]):o.splice(u,1)}),o.forEach(c=>document.head.appendChild(c)),l=[...l.filter(c=>!!c),...o]};Kt(Xu,r),We(()=>{i(),Ge(e,r,{immediate:!1})})},pf=([e,t,l=""])=>{const i=Object.entries(t).map(([c,a])=>nt(a)?`[${c}=${JSON.stringify(a)}]`:a===!0?`[${c}]`:"").join(""),n=`head > ${e}${i}`;return Array.from(document.querySelectorAll(n)).find(c=>c.innerText===l)||null},mf=([e,t,l])=>{if(!nt(e))return null;const i=document.createElement(e);return Hn(t)&&Object.entries(t).forEach(([n,r])=>{nt(r)?i.setAttribute(n,r):r===!0&&i.setAttribute(n,"")}),nt(l)&&i.appendChild(document.createTextNode(l)),i},bf=Pu,kf=async()=>{var l;const e=bf({name:"VuepressApp",setup(){var i;gf();for(const n of di)(i=n.setup)==null||i.call(n);return()=>[he(Vs),...di.flatMap(({rootComponents:n=[]})=>n.map(r=>he(r)))]}}),t=vf();_f(e),ff(e,t,di);for(const i of di)await((l=i.enhance)==null?void 0:l.call(i,{app:e,router:t,siteData:ll}));return e.use(t),{app:e,router:t}};kf().then(({app:e,router:t})=>{t.isReady().then(()=>{e.mount("#app")})});export{ke as F,xe as _,ne as a,ce as b,ee as c,kf as createVueApp,Vt as d,$a as e,_e as f,be as g,s as h,St as i,Lo as j,fc as k,C as l,Ge as m,ge as n,W as o,We as p,Vn as q,mt as r,zl as s,Pe as t,Xt as u,Ef as v,Ce as w,Xl as x}; function __vite__mapDeps(indexes) { if (!__vite__mapDeps.viteFileDeps) { __vite__mapDeps.viteFileDeps = [] diff --git a/assets/arc-CO2v8jBL.js b/assets/arc-9Itq1iXl.js similarity index 98% rename from assets/arc-CO2v8jBL.js rename to assets/arc-9Itq1iXl.js index ac40043b21..a7ea29574c 100644 --- a/assets/arc-CO2v8jBL.js +++ b/assets/arc-9Itq1iXl.js @@ -1 +1 @@ -import{M as ln,N as an,O as y,P as tn,Q as Y,R as O,S as _,T as un,V as rn,W as j,X as o,Y as Q,Z as sn,$ as on,a0 as fn}from"./mermaid.core-DapiNGBY.js";function cn(l){return l.innerRadius}function yn(l){return l.outerRadius}function gn(l){return l.startAngle}function dn(l){return l.endAngle}function mn(l){return l&&l.padAngle}function pn(l,h,D,S,v,R,V,a){var E=D-l,i=S-h,n=V-v,d=a-R,u=d*E-n*i;if(!(u*ur*r+X*X&&(M=w,N=p),{cx:M,cy:N,x01:-n,y01:-d,x11:M*(v/T-1),y11:N*(v/T-1)}}function hn(){var l=cn,h=yn,D=Q(0),S=null,v=gn,R=dn,V=mn,a=null,E=ln(i);function i(){var n,d,u=+l.apply(this,arguments),s=+h.apply(this,arguments),f=v.apply(this,arguments)-an,c=R.apply(this,arguments)-an,W=un(c-f),t=c>f;if(a||(a=n=E()),sy))a.moveTo(0,0);else if(W>tn-y)a.moveTo(s*Y(f),s*O(f)),a.arc(0,0,s,f,c,!t),u>y&&(a.moveTo(u*Y(c),u*O(c)),a.arc(0,0,u,c,f,t));else{var m=f,g=c,A=f,T=c,P=W,I=W,M=V.apply(this,arguments)/2,N=M>y&&(S?+S.apply(this,arguments):j(u*u+s*s)),w=_(un(s-u)/2,+D.apply(this,arguments)),p=w,x=w,e,r;if(N>y){var X=sn(N/u*O(M)),z=sn(N/s*O(M));(P-=X*2)>y?(X*=t?1:-1,A+=X,T-=X):(P=0,A=T=(f+c)/2),(I-=z*2)>y?(z*=t?1:-1,m+=z,g-=z):(I=0,m=g=(f+c)/2)}var Z=s*Y(m),$=s*O(m),B=u*Y(T),C=u*O(T);if(w>y){var F=s*Y(g),G=s*O(g),J=u*Y(A),K=u*O(A),q;if(Wy?x>y?(e=H(J,K,Z,$,s,x,t),r=H(F,G,B,C,s,x,t),a.moveTo(e.cx+e.x01,e.cy+e.y01),xy)||!(P>y)?a.lineTo(B,C):p>y?(e=H(B,C,F,G,u,-p,t),r=H(Z,$,J,K,u,-p,t),a.lineTo(e.cx+e.x01,e.cy+e.y01),pr*r+X*X&&(M=w,N=p),{cx:M,cy:N,x01:-n,y01:-d,x11:M*(v/T-1),y11:N*(v/T-1)}}function hn(){var l=cn,h=yn,D=Q(0),S=null,v=gn,R=dn,V=mn,a=null,E=ln(i);function i(){var n,d,u=+l.apply(this,arguments),s=+h.apply(this,arguments),f=v.apply(this,arguments)-an,c=R.apply(this,arguments)-an,W=un(c-f),t=c>f;if(a||(a=n=E()),sy))a.moveTo(0,0);else if(W>tn-y)a.moveTo(s*Y(f),s*O(f)),a.arc(0,0,s,f,c,!t),u>y&&(a.moveTo(u*Y(c),u*O(c)),a.arc(0,0,u,c,f,t));else{var m=f,g=c,A=f,T=c,P=W,I=W,M=V.apply(this,arguments)/2,N=M>y&&(S?+S.apply(this,arguments):j(u*u+s*s)),w=_(un(s-u)/2,+D.apply(this,arguments)),p=w,x=w,e,r;if(N>y){var X=sn(N/u*O(M)),z=sn(N/s*O(M));(P-=X*2)>y?(X*=t?1:-1,A+=X,T-=X):(P=0,A=T=(f+c)/2),(I-=z*2)>y?(z*=t?1:-1,m+=z,g-=z):(I=0,m=g=(f+c)/2)}var Z=s*Y(m),$=s*O(m),B=u*Y(T),C=u*O(T);if(w>y){var F=s*Y(g),G=s*O(g),J=u*Y(A),K=u*O(A),q;if(Wy?x>y?(e=H(J,K,Z,$,s,x,t),r=H(F,G,B,C,s,x,t),a.moveTo(e.cx+e.x01,e.cy+e.y01),xy)||!(P>y)?a.lineTo(B,C):p>y?(e=H(B,C,F,G,u,-p,t),r=H(Z,$,J,K,u,-p,t),a.lineTo(e.cx+e.x01,e.cy+e.y01),p2?r[2]:void 0;for(i&&F(r[0],r[1],i)&&(e=1);++t-1?i[f?r[a]:a]:void 0}}var Q=Math.max;function U(n,r,t){var e=n==null?0:n.length;if(!e)return-1;var i=t==null?0:X(t);return i<0&&(i=Q(e+i,0)),P(n,m(r),i)}var sn=D(U);function Z(n,r){var t=-1,e=o(n)?Array(n.length):[];return A(n,function(i,f,a){e[++t]=r(i,f,a)}),e}function fn(n,r){var t=T(n)?M:Z;return t(n,m(r))}function V(n,r){return n2?r[2]:void 0;for(i&&F(r[0],r[1],i)&&(e=1);++t-1?i[f?r[a]:a]:void 0}}var Q=Math.max;function U(n,r,t){var e=n==null?0:n.length;if(!e)return-1;var i=t==null?0:X(t);return i<0&&(i=Q(e+i,0)),P(n,m(r),i)}var sn=D(U);function Z(n,r){var t=-1,e=o(n)?Array(n.length):[];return A(n,function(i,f,a){e[++t]=r(i,f,a)}),e}function fn(n,r){var t=T(n)?M:Z;return t(n,m(r))}function V(n,r){return n-1}function $(n){return sn(n)?Mn(n):mn(n)}var rr=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,er=/^\w*$/;function B(n,r){if(T(n))return!1;var e=typeof n;return e=="number"||e=="symbol"||e=="boolean"||n==null||U(n)?!0:er.test(n)||!rr.test(n)||r!=null&&n in Object(r)}var tr=500;function ir(n){var r=Fn(n,function(t){return e.size===tr&&e.clear(),t}),e=r.cache;return r}var ar=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,fr=/\\(\\)?/g,sr=ir(function(n){var r=[];return n.charCodeAt(0)===46&&r.push(""),n.replace(ar,function(e,t,a,i){r.push(a?i.replace(fr,"$1"):t||e)}),r});function ur(n){return n==null?"":dn(n)}function An(n,r){return T(n)?n:B(n,r)?[n]:sr(ur(n))}var or=1/0;function M(n){if(typeof n=="string"||U(n))return n;var r=n+"";return r=="0"&&1/n==-or?"-0":r}function yn(n,r){r=An(r,n);for(var e=0,t=r.length;n!=null&&es))return!1;var b=i.get(n),l=i.get(r);if(b&&l)return b==r&&l==n;var o=-1,c=!0,h=e&xe?new S:void 0;for(i.set(n,r),i.set(r,n);++o=It){var b=r?null:_t(n);if(b)return j(b);f=!1,a=Pn,u=new S}else u=r?[]:s;n:for(;++t-1}function $(n){return sn(n)?Mn(n):mn(n)}var rr=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,er=/^\w*$/;function B(n,r){if(T(n))return!1;var e=typeof n;return e=="number"||e=="symbol"||e=="boolean"||n==null||U(n)?!0:er.test(n)||!rr.test(n)||r!=null&&n in Object(r)}var tr=500;function ir(n){var r=Fn(n,function(t){return e.size===tr&&e.clear(),t}),e=r.cache;return r}var ar=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,fr=/\\(\\)?/g,sr=ir(function(n){var r=[];return n.charCodeAt(0)===46&&r.push(""),n.replace(ar,function(e,t,a,i){r.push(a?i.replace(fr,"$1"):t||e)}),r});function ur(n){return n==null?"":dn(n)}function An(n,r){return T(n)?n:B(n,r)?[n]:sr(ur(n))}var or=1/0;function M(n){if(typeof n=="string"||U(n))return n;var r=n+"";return r=="0"&&1/n==-or?"-0":r}function yn(n,r){r=An(r,n);for(var e=0,t=r.length;n!=null&&es))return!1;var b=i.get(n),l=i.get(r);if(b&&l)return b==r&&l==n;var o=-1,c=!0,h=e&xe?new S:void 0;for(i.set(n,r),i.set(r,n);++o=It){var b=r?null:_t(n);if(b)return j(b);f=!1,a=Pn,u=new S}else u=r?[]:s;n:for(;++tOutboundConfigurationObject
{
+import{_ as c,r as o,o as l,c as p,a as s,b as e,d as n,w as i,e as d}from"./app-D7uBbsY3.js";const r={},u=e("h1",{id:"blackhole",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#blackhole"},[e("span",null,"Blackhole")])],-1),h=d(`

OutboundConfigurationObject

{
   "response": {
     "type": "none"
   }
diff --git a/assets/blackhole.html-BwT5tNQJ.js b/assets/blackhole.html-CguJu2fJ.js
similarity index 97%
rename from assets/blackhole.html-BwT5tNQJ.js
rename to assets/blackhole.html-CguJu2fJ.js
index 43ed784990..5c154626d4 100644
--- a/assets/blackhole.html-BwT5tNQJ.js
+++ b/assets/blackhole.html-CguJu2fJ.js
@@ -1,4 +1,4 @@
-import{_ as c,r as o,o as l,c as p,a as s,b as e,d as n,w as i,e as d}from"./app-DBM4OJyw.js";const r={},u=e("h1",{id:"blackhole",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#blackhole"},[e("span",null,"Blackhole")])],-1),h=d(`

OutboundConfigurationObject

{
+import{_ as c,r as o,o as l,c as p,a as s,b as e,d as n,w as i,e as d}from"./app-D7uBbsY3.js";const r={},u=e("h1",{id:"blackhole",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#blackhole"},[e("span",null,"Blackhole")])],-1),h=d(`

OutboundConfigurationObject

{
   "response": {
     "type": "none"
   }
diff --git a/assets/blackhole.html-Nc1ubt3S.js b/assets/blackhole.html-Cllw1jwu.js
similarity index 97%
rename from assets/blackhole.html-Nc1ubt3S.js
rename to assets/blackhole.html-Cllw1jwu.js
index c050b99842..dee4199d44 100644
--- a/assets/blackhole.html-Nc1ubt3S.js
+++ b/assets/blackhole.html-Cllw1jwu.js
@@ -1,4 +1,4 @@
-import{_ as c,r as o,o as l,c as i,a as s,b as e,d as n,w as d,e as p}from"./app-DBM4OJyw.js";const r={},u=e("h1",{id:"blackhole",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#blackhole"},[e("span",null,"Blackhole")])],-1),h=p(`

OutboundConfigurationObject

{
+import{_ as c,r as o,o as l,c as i,a as s,b as e,d as n,w as d,e as p}from"./app-D7uBbsY3.js";const r={},u=e("h1",{id:"blackhole",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#blackhole"},[e("span",null,"Blackhole")])],-1),h=p(`

OutboundConfigurationObject

{
   "response": {
     "type": "none"
   }
diff --git a/assets/blockDiagram-V6UOASA5-C4OVhM5p.js b/assets/blockDiagram-V6UOASA5-Dajk3X5E.js
similarity index 99%
rename from assets/blockDiagram-V6UOASA5-C4OVhM5p.js
rename to assets/blockDiagram-V6UOASA5-Dajk3X5E.js
index 68fdb7679b..8084dd2084 100644
--- a/assets/blockDiagram-V6UOASA5-C4OVhM5p.js
+++ b/assets/blockDiagram-V6UOASA5-Dajk3X5E.js
@@ -1,4 +1,4 @@
-import{a as Re,i as Be,p as ke,m as Pe}from"./chunk-PDCO53Z4-RQMWNvLJ.js";import{i as xe,p as Fe}from"./chunk-Z2VRG6XP-DsASRjJ5.js";import{_ as u,d as Le,l as L,ab as Ke,H as ie,j as H,k as Me,t as Ye,z as We,e as Ve}from"./mermaid.core-DapiNGBY.js";import{c as je}from"./clone-B3i2nD77.js";import{G as Ue}from"./graph-Oq3lz9SV.js";import{c as Xe}from"./channel-BHWICgEe.js";import"./app-DBM4OJyw.js";import"./baseUniq-ZJgB7efo.js";var se=function(){var e=u(function(N,c,s,r){for(s=s||{},r=N.length;r--;s[N[r]]=c);return s},"o"),l=[1,7],h=[1,13],n=[1,14],i=[1,15],d=[1,19],o=[1,16],f=[1,17],S=[1,18],m=[8,30],x=[8,21,28,29,30,31,32,40,44,47],_=[1,23],O=[1,24],I=[8,15,16,21,28,29,30,31,32,40,44,47],D=[8,15,16,21,27,28,29,30,31,32,40,44,47],C=[1,49],E={trace:u(function(){},"trace"),yy:{},symbols_:{error:2,spaceLines:3,SPACELINE:4,NL:5,separator:6,SPACE:7,EOF:8,start:9,BLOCK_DIAGRAM_KEY:10,document:11,stop:12,statement:13,link:14,LINK:15,START_LINK:16,LINK_LABEL:17,STR:18,nodeStatement:19,columnsStatement:20,SPACE_BLOCK:21,blockStatement:22,classDefStatement:23,cssClassStatement:24,styleStatement:25,node:26,SIZE:27,COLUMNS:28,"id-block":29,end:30,block:31,NODE_ID:32,nodeShapeNLabel:33,dirList:34,DIR:35,NODE_DSTART:36,NODE_DEND:37,BLOCK_ARROW_START:38,BLOCK_ARROW_END:39,classDef:40,CLASSDEF_ID:41,CLASSDEF_STYLEOPTS:42,DEFAULT:43,class:44,CLASSENTITY_IDS:45,STYLECLASS:46,style:47,STYLE_ENTITY_IDS:48,STYLE_DEFINITION_DATA:49,$accept:0,$end:1},terminals_:{2:"error",4:"SPACELINE",5:"NL",7:"SPACE",8:"EOF",10:"BLOCK_DIAGRAM_KEY",15:"LINK",16:"START_LINK",17:"LINK_LABEL",18:"STR",21:"SPACE_BLOCK",27:"SIZE",28:"COLUMNS",29:"id-block",30:"end",31:"block",32:"NODE_ID",35:"DIR",36:"NODE_DSTART",37:"NODE_DEND",38:"BLOCK_ARROW_START",39:"BLOCK_ARROW_END",40:"classDef",41:"CLASSDEF_ID",42:"CLASSDEF_STYLEOPTS",43:"DEFAULT",44:"class",45:"CLASSENTITY_IDS",46:"STYLECLASS",47:"style",48:"STYLE_ENTITY_IDS",49:"STYLE_DEFINITION_DATA"},productions_:[0,[3,1],[3,2],[3,2],[6,1],[6,1],[6,1],[9,3],[12,1],[12,1],[12,2],[12,2],[11,1],[11,2],[14,1],[14,4],[13,1],[13,1],[13,1],[13,1],[13,1],[13,1],[13,1],[19,3],[19,2],[19,1],[20,1],[22,4],[22,3],[26,1],[26,2],[34,1],[34,2],[33,3],[33,4],[23,3],[23,3],[24,3],[25,3]],performAction:u(function(c,s,r,g,p,t,b){var a=t.length-1;switch(p){case 4:g.getLogger().debug("Rule: separator (NL) ");break;case 5:g.getLogger().debug("Rule: separator (Space) ");break;case 6:g.getLogger().debug("Rule: separator (EOF) ");break;case 7:g.getLogger().debug("Rule: hierarchy: ",t[a-1]),g.setHierarchy(t[a-1]);break;case 8:g.getLogger().debug("Stop NL ");break;case 9:g.getLogger().debug("Stop EOF ");break;case 10:g.getLogger().debug("Stop NL2 ");break;case 11:g.getLogger().debug("Stop EOF2 ");break;case 12:g.getLogger().debug("Rule: statement: ",t[a]),typeof t[a].length=="number"?this.$=t[a]:this.$=[t[a]];break;case 13:g.getLogger().debug("Rule: statement #2: ",t[a-1]),this.$=[t[a-1]].concat(t[a]);break;case 14:g.getLogger().debug("Rule: link: ",t[a],c),this.$={edgeTypeStr:t[a],label:""};break;case 15:g.getLogger().debug("Rule: LABEL link: ",t[a-3],t[a-1],t[a]),this.$={edgeTypeStr:t[a],label:t[a-1]};break;case 18:const P=parseInt(t[a]),W=g.generateId();this.$={id:W,type:"space",label:"",width:P,children:[]};break;case 23:g.getLogger().debug("Rule: (nodeStatement link node) ",t[a-2],t[a-1],t[a]," typestr: ",t[a-1].edgeTypeStr);const K=g.edgeStrToEdgeData(t[a-1].edgeTypeStr);this.$=[{id:t[a-2].id,label:t[a-2].label,type:t[a-2].type,directions:t[a-2].directions},{id:t[a-2].id+"-"+t[a].id,start:t[a-2].id,end:t[a].id,label:t[a-1].label,type:"edge",directions:t[a].directions,arrowTypeEnd:K,arrowTypeStart:"arrow_open"},{id:t[a].id,label:t[a].label,type:g.typeStr2Type(t[a].typeStr),directions:t[a].directions}];break;case 24:g.getLogger().debug("Rule: nodeStatement (abc88 node size) ",t[a-1],t[a]),this.$={id:t[a-1].id,label:t[a-1].label,type:g.typeStr2Type(t[a-1].typeStr),directions:t[a-1].directions,widthInColumns:parseInt(t[a],10)};break;case 25:g.getLogger().debug("Rule: nodeStatement (node) ",t[a]),this.$={id:t[a].id,label:t[a].label,type:g.typeStr2Type(t[a].typeStr),directions:t[a].directions,widthInColumns:1};break;case 26:g.getLogger().debug("APA123",this?this:"na"),g.getLogger().debug("COLUMNS: ",t[a]),this.$={type:"column-setting",columns:t[a]==="auto"?-1:parseInt(t[a])};break;case 27:g.getLogger().debug("Rule: id-block statement : ",t[a-2],t[a-1]),g.generateId(),this.$={...t[a-2],type:"composite",children:t[a-1]};break;case 28:g.getLogger().debug("Rule: blockStatement : ",t[a-2],t[a-1],t[a]);const B=g.generateId();this.$={id:B,type:"composite",label:"",children:t[a-1]};break;case 29:g.getLogger().debug("Rule: node (NODE_ID separator): ",t[a]),this.$={id:t[a]};break;case 30:g.getLogger().debug("Rule: node (NODE_ID nodeShapeNLabel separator): ",t[a-1],t[a]),this.$={id:t[a-1],label:t[a].label,typeStr:t[a].typeStr,directions:t[a].directions};break;case 31:g.getLogger().debug("Rule: dirList: ",t[a]),this.$=[t[a]];break;case 32:g.getLogger().debug("Rule: dirList: ",t[a-1],t[a]),this.$=[t[a-1]].concat(t[a]);break;case 33:g.getLogger().debug("Rule: nodeShapeNLabel: ",t[a-2],t[a-1],t[a]),this.$={typeStr:t[a-2]+t[a],label:t[a-1]};break;case 34:g.getLogger().debug("Rule: BLOCK_ARROW nodeShapeNLabel: ",t[a-3],t[a-2]," #3:",t[a-1],t[a]),this.$={typeStr:t[a-3]+t[a],label:t[a-2],directions:t[a-1]};break;case 35:case 36:this.$={type:"classDef",id:t[a-1].trim(),css:t[a].trim()};break;case 37:this.$={type:"applyClass",id:t[a-1].trim(),styleClass:t[a].trim()};break;case 38:this.$={type:"applyStyles",id:t[a-1].trim(),stylesStr:t[a].trim()};break}},"anonymous"),table:[{9:1,10:[1,2]},{1:[3]},{11:3,13:4,19:5,20:6,21:l,22:8,23:9,24:10,25:11,26:12,28:h,29:n,31:i,32:d,40:o,44:f,47:S},{8:[1,20]},e(m,[2,12],{13:4,19:5,20:6,22:8,23:9,24:10,25:11,26:12,11:21,21:l,28:h,29:n,31:i,32:d,40:o,44:f,47:S}),e(x,[2,16],{14:22,15:_,16:O}),e(x,[2,17]),e(x,[2,18]),e(x,[2,19]),e(x,[2,20]),e(x,[2,21]),e(x,[2,22]),e(I,[2,25],{27:[1,25]}),e(x,[2,26]),{19:26,26:12,32:d},{11:27,13:4,19:5,20:6,21:l,22:8,23:9,24:10,25:11,26:12,28:h,29:n,31:i,32:d,40:o,44:f,47:S},{41:[1,28],43:[1,29]},{45:[1,30]},{48:[1,31]},e(D,[2,29],{33:32,36:[1,33],38:[1,34]}),{1:[2,7]},e(m,[2,13]),{26:35,32:d},{32:[2,14]},{17:[1,36]},e(I,[2,24]),{11:37,13:4,14:22,15:_,16:O,19:5,20:6,21:l,22:8,23:9,24:10,25:11,26:12,28:h,29:n,31:i,32:d,40:o,44:f,47:S},{30:[1,38]},{42:[1,39]},{42:[1,40]},{46:[1,41]},{49:[1,42]},e(D,[2,30]),{18:[1,43]},{18:[1,44]},e(I,[2,23]),{18:[1,45]},{30:[1,46]},e(x,[2,28]),e(x,[2,35]),e(x,[2,36]),e(x,[2,37]),e(x,[2,38]),{37:[1,47]},{34:48,35:C},{15:[1,50]},e(x,[2,27]),e(D,[2,33]),{39:[1,51]},{34:52,35:C,39:[2,31]},{32:[2,15]},e(D,[2,34]),{39:[2,32]}],defaultActions:{20:[2,7],23:[2,14],50:[2,15],52:[2,32]},parseError:u(function(c,s){if(s.recoverable)this.trace(c);else{var r=new Error(c);throw r.hash=s,r}},"parseError"),parse:u(function(c){var s=this,r=[0],g=[],p=[null],t=[],b=this.table,a="",P=0,W=0,K=2,B=1,ze=t.slice.call(arguments,1),w=Object.create(this.lexer),M={yy:{}};for(var Q in this.yy)Object.prototype.hasOwnProperty.call(this.yy,Q)&&(M.yy[Q]=this.yy[Q]);w.setInput(c,M.yy),M.yy.lexer=w,M.yy.parser=this,typeof w.yylloc>"u"&&(w.yylloc={});var $=w.yylloc;t.push($);var Ce=w.options&&w.options.ranges;typeof M.yy.parseError=="function"?this.parseError=M.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function Ae(z){r.length=r.length-2*z,p.length=p.length-z,t.length=t.length-z}u(Ae,"popStack");function he(){var z;return z=g.pop()||w.lex()||B,typeof z!="number"&&(z instanceof Array&&(g=z,z=g.pop()),z=s.symbols_[z]||z),z}u(he,"lex");for(var T,Y,A,ee,V={},U,F,ue,X;;){if(Y=r[r.length-1],this.defaultActions[Y]?A=this.defaultActions[Y]:((T===null||typeof T>"u")&&(T=he()),A=b[Y]&&b[Y][T]),typeof A>"u"||!A.length||!A[0]){var te="";X=[];for(U in b[Y])this.terminals_[U]&&U>K&&X.push("'"+this.terminals_[U]+"'");w.showPosition?te="Parse error on line "+(P+1)+`:
+import{a as Re,i as Be,p as ke,m as Pe}from"./chunk-PDCO53Z4-BcfC0Pnz.js";import{i as xe,p as Fe}from"./chunk-Z2VRG6XP-CV0pyCU1.js";import{_ as u,d as Le,l as L,ab as Ke,H as ie,j as H,k as Me,t as Ye,z as We,e as Ve}from"./mermaid.core-D8igZDel.js";import{c as je}from"./clone-DWnk59eF.js";import{G as Ue}from"./graph-Cjb-DGHB.js";import{c as Xe}from"./channel-uApa1cOK.js";import"./app-D7uBbsY3.js";import"./baseUniq-D0lZO5yp.js";var se=function(){var e=u(function(N,c,s,r){for(s=s||{},r=N.length;r--;s[N[r]]=c);return s},"o"),l=[1,7],h=[1,13],n=[1,14],i=[1,15],d=[1,19],o=[1,16],f=[1,17],S=[1,18],m=[8,30],x=[8,21,28,29,30,31,32,40,44,47],_=[1,23],O=[1,24],I=[8,15,16,21,28,29,30,31,32,40,44,47],D=[8,15,16,21,27,28,29,30,31,32,40,44,47],C=[1,49],E={trace:u(function(){},"trace"),yy:{},symbols_:{error:2,spaceLines:3,SPACELINE:4,NL:5,separator:6,SPACE:7,EOF:8,start:9,BLOCK_DIAGRAM_KEY:10,document:11,stop:12,statement:13,link:14,LINK:15,START_LINK:16,LINK_LABEL:17,STR:18,nodeStatement:19,columnsStatement:20,SPACE_BLOCK:21,blockStatement:22,classDefStatement:23,cssClassStatement:24,styleStatement:25,node:26,SIZE:27,COLUMNS:28,"id-block":29,end:30,block:31,NODE_ID:32,nodeShapeNLabel:33,dirList:34,DIR:35,NODE_DSTART:36,NODE_DEND:37,BLOCK_ARROW_START:38,BLOCK_ARROW_END:39,classDef:40,CLASSDEF_ID:41,CLASSDEF_STYLEOPTS:42,DEFAULT:43,class:44,CLASSENTITY_IDS:45,STYLECLASS:46,style:47,STYLE_ENTITY_IDS:48,STYLE_DEFINITION_DATA:49,$accept:0,$end:1},terminals_:{2:"error",4:"SPACELINE",5:"NL",7:"SPACE",8:"EOF",10:"BLOCK_DIAGRAM_KEY",15:"LINK",16:"START_LINK",17:"LINK_LABEL",18:"STR",21:"SPACE_BLOCK",27:"SIZE",28:"COLUMNS",29:"id-block",30:"end",31:"block",32:"NODE_ID",35:"DIR",36:"NODE_DSTART",37:"NODE_DEND",38:"BLOCK_ARROW_START",39:"BLOCK_ARROW_END",40:"classDef",41:"CLASSDEF_ID",42:"CLASSDEF_STYLEOPTS",43:"DEFAULT",44:"class",45:"CLASSENTITY_IDS",46:"STYLECLASS",47:"style",48:"STYLE_ENTITY_IDS",49:"STYLE_DEFINITION_DATA"},productions_:[0,[3,1],[3,2],[3,2],[6,1],[6,1],[6,1],[9,3],[12,1],[12,1],[12,2],[12,2],[11,1],[11,2],[14,1],[14,4],[13,1],[13,1],[13,1],[13,1],[13,1],[13,1],[13,1],[19,3],[19,2],[19,1],[20,1],[22,4],[22,3],[26,1],[26,2],[34,1],[34,2],[33,3],[33,4],[23,3],[23,3],[24,3],[25,3]],performAction:u(function(c,s,r,g,p,t,b){var a=t.length-1;switch(p){case 4:g.getLogger().debug("Rule: separator (NL) ");break;case 5:g.getLogger().debug("Rule: separator (Space) ");break;case 6:g.getLogger().debug("Rule: separator (EOF) ");break;case 7:g.getLogger().debug("Rule: hierarchy: ",t[a-1]),g.setHierarchy(t[a-1]);break;case 8:g.getLogger().debug("Stop NL ");break;case 9:g.getLogger().debug("Stop EOF ");break;case 10:g.getLogger().debug("Stop NL2 ");break;case 11:g.getLogger().debug("Stop EOF2 ");break;case 12:g.getLogger().debug("Rule: statement: ",t[a]),typeof t[a].length=="number"?this.$=t[a]:this.$=[t[a]];break;case 13:g.getLogger().debug("Rule: statement #2: ",t[a-1]),this.$=[t[a-1]].concat(t[a]);break;case 14:g.getLogger().debug("Rule: link: ",t[a],c),this.$={edgeTypeStr:t[a],label:""};break;case 15:g.getLogger().debug("Rule: LABEL link: ",t[a-3],t[a-1],t[a]),this.$={edgeTypeStr:t[a],label:t[a-1]};break;case 18:const P=parseInt(t[a]),W=g.generateId();this.$={id:W,type:"space",label:"",width:P,children:[]};break;case 23:g.getLogger().debug("Rule: (nodeStatement link node) ",t[a-2],t[a-1],t[a]," typestr: ",t[a-1].edgeTypeStr);const K=g.edgeStrToEdgeData(t[a-1].edgeTypeStr);this.$=[{id:t[a-2].id,label:t[a-2].label,type:t[a-2].type,directions:t[a-2].directions},{id:t[a-2].id+"-"+t[a].id,start:t[a-2].id,end:t[a].id,label:t[a-1].label,type:"edge",directions:t[a].directions,arrowTypeEnd:K,arrowTypeStart:"arrow_open"},{id:t[a].id,label:t[a].label,type:g.typeStr2Type(t[a].typeStr),directions:t[a].directions}];break;case 24:g.getLogger().debug("Rule: nodeStatement (abc88 node size) ",t[a-1],t[a]),this.$={id:t[a-1].id,label:t[a-1].label,type:g.typeStr2Type(t[a-1].typeStr),directions:t[a-1].directions,widthInColumns:parseInt(t[a],10)};break;case 25:g.getLogger().debug("Rule: nodeStatement (node) ",t[a]),this.$={id:t[a].id,label:t[a].label,type:g.typeStr2Type(t[a].typeStr),directions:t[a].directions,widthInColumns:1};break;case 26:g.getLogger().debug("APA123",this?this:"na"),g.getLogger().debug("COLUMNS: ",t[a]),this.$={type:"column-setting",columns:t[a]==="auto"?-1:parseInt(t[a])};break;case 27:g.getLogger().debug("Rule: id-block statement : ",t[a-2],t[a-1]),g.generateId(),this.$={...t[a-2],type:"composite",children:t[a-1]};break;case 28:g.getLogger().debug("Rule: blockStatement : ",t[a-2],t[a-1],t[a]);const B=g.generateId();this.$={id:B,type:"composite",label:"",children:t[a-1]};break;case 29:g.getLogger().debug("Rule: node (NODE_ID separator): ",t[a]),this.$={id:t[a]};break;case 30:g.getLogger().debug("Rule: node (NODE_ID nodeShapeNLabel separator): ",t[a-1],t[a]),this.$={id:t[a-1],label:t[a].label,typeStr:t[a].typeStr,directions:t[a].directions};break;case 31:g.getLogger().debug("Rule: dirList: ",t[a]),this.$=[t[a]];break;case 32:g.getLogger().debug("Rule: dirList: ",t[a-1],t[a]),this.$=[t[a-1]].concat(t[a]);break;case 33:g.getLogger().debug("Rule: nodeShapeNLabel: ",t[a-2],t[a-1],t[a]),this.$={typeStr:t[a-2]+t[a],label:t[a-1]};break;case 34:g.getLogger().debug("Rule: BLOCK_ARROW nodeShapeNLabel: ",t[a-3],t[a-2]," #3:",t[a-1],t[a]),this.$={typeStr:t[a-3]+t[a],label:t[a-2],directions:t[a-1]};break;case 35:case 36:this.$={type:"classDef",id:t[a-1].trim(),css:t[a].trim()};break;case 37:this.$={type:"applyClass",id:t[a-1].trim(),styleClass:t[a].trim()};break;case 38:this.$={type:"applyStyles",id:t[a-1].trim(),stylesStr:t[a].trim()};break}},"anonymous"),table:[{9:1,10:[1,2]},{1:[3]},{11:3,13:4,19:5,20:6,21:l,22:8,23:9,24:10,25:11,26:12,28:h,29:n,31:i,32:d,40:o,44:f,47:S},{8:[1,20]},e(m,[2,12],{13:4,19:5,20:6,22:8,23:9,24:10,25:11,26:12,11:21,21:l,28:h,29:n,31:i,32:d,40:o,44:f,47:S}),e(x,[2,16],{14:22,15:_,16:O}),e(x,[2,17]),e(x,[2,18]),e(x,[2,19]),e(x,[2,20]),e(x,[2,21]),e(x,[2,22]),e(I,[2,25],{27:[1,25]}),e(x,[2,26]),{19:26,26:12,32:d},{11:27,13:4,19:5,20:6,21:l,22:8,23:9,24:10,25:11,26:12,28:h,29:n,31:i,32:d,40:o,44:f,47:S},{41:[1,28],43:[1,29]},{45:[1,30]},{48:[1,31]},e(D,[2,29],{33:32,36:[1,33],38:[1,34]}),{1:[2,7]},e(m,[2,13]),{26:35,32:d},{32:[2,14]},{17:[1,36]},e(I,[2,24]),{11:37,13:4,14:22,15:_,16:O,19:5,20:6,21:l,22:8,23:9,24:10,25:11,26:12,28:h,29:n,31:i,32:d,40:o,44:f,47:S},{30:[1,38]},{42:[1,39]},{42:[1,40]},{46:[1,41]},{49:[1,42]},e(D,[2,30]),{18:[1,43]},{18:[1,44]},e(I,[2,23]),{18:[1,45]},{30:[1,46]},e(x,[2,28]),e(x,[2,35]),e(x,[2,36]),e(x,[2,37]),e(x,[2,38]),{37:[1,47]},{34:48,35:C},{15:[1,50]},e(x,[2,27]),e(D,[2,33]),{39:[1,51]},{34:52,35:C,39:[2,31]},{32:[2,15]},e(D,[2,34]),{39:[2,32]}],defaultActions:{20:[2,7],23:[2,14],50:[2,15],52:[2,32]},parseError:u(function(c,s){if(s.recoverable)this.trace(c);else{var r=new Error(c);throw r.hash=s,r}},"parseError"),parse:u(function(c){var s=this,r=[0],g=[],p=[null],t=[],b=this.table,a="",P=0,W=0,K=2,B=1,ze=t.slice.call(arguments,1),w=Object.create(this.lexer),M={yy:{}};for(var Q in this.yy)Object.prototype.hasOwnProperty.call(this.yy,Q)&&(M.yy[Q]=this.yy[Q]);w.setInput(c,M.yy),M.yy.lexer=w,M.yy.parser=this,typeof w.yylloc>"u"&&(w.yylloc={});var $=w.yylloc;t.push($);var Ce=w.options&&w.options.ranges;typeof M.yy.parseError=="function"?this.parseError=M.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function Ae(z){r.length=r.length-2*z,p.length=p.length-z,t.length=t.length-z}u(Ae,"popStack");function he(){var z;return z=g.pop()||w.lex()||B,typeof z!="number"&&(z instanceof Array&&(g=z,z=g.pop()),z=s.symbols_[z]||z),z}u(he,"lex");for(var T,Y,A,ee,V={},U,F,ue,X;;){if(Y=r[r.length-1],this.defaultActions[Y]?A=this.defaultActions[Y]:((T===null||typeof T>"u")&&(T=he()),A=b[Y]&&b[Y][T]),typeof A>"u"||!A.length||!A[0]){var te="";X=[];for(U in b[Y])this.terminals_[U]&&U>K&&X.push("'"+this.terminals_[U]+"'");w.showPosition?te="Parse error on line "+(P+1)+`:
 `+w.showPosition()+`
 Expecting `+X.join(", ")+", got '"+(this.terminals_[T]||T)+"'":te="Parse error on line "+(P+1)+": Unexpected "+(T==B?"end of input":"'"+(this.terminals_[T]||T)+"'"),this.parseError(te,{text:w.match,token:this.terminals_[T]||T,line:w.yylineno,loc:$,expected:X})}if(A[0]instanceof Array&&A.length>1)throw new Error("Parse Error: multiple actions possible at state: "+Y+", token: "+T);switch(A[0]){case 1:r.push(T),p.push(w.yytext),t.push(w.yylloc),r.push(A[1]),T=null,W=w.yyleng,a=w.yytext,P=w.yylineno,$=w.yylloc;break;case 2:if(F=this.productions_[A[1]][1],V.$=p[p.length-F],V._$={first_line:t[t.length-(F||1)].first_line,last_line:t[t.length-1].last_line,first_column:t[t.length-(F||1)].first_column,last_column:t[t.length-1].last_column},Ce&&(V._$.range=[t[t.length-(F||1)].range[0],t[t.length-1].range[1]]),ee=this.performAction.apply(V,[a,W,P,M.yy,A[1],p,t].concat(ze)),typeof ee<"u")return ee;F&&(r=r.slice(0,-1*F*2),p=p.slice(0,-1*F),t=t.slice(0,-1*F)),r.push(this.productions_[A[1]][0]),p.push(V.$),t.push(V._$),ue=b[r[r.length-2]][r[r.length-1]],r.push(ue);break;case 3:return!0}}return!0},"parse")},k=function(){var N={EOF:1,parseError:u(function(s,r){if(this.yy.parser)this.yy.parser.parseError(s,r);else throw new Error(s)},"parseError"),setInput:u(function(c,s){return this.yy=s||this.yy||{},this._input=c,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},"setInput"),input:u(function(){var c=this._input[0];this.yytext+=c,this.yyleng++,this.offset++,this.match+=c,this.matched+=c;var s=c.match(/(?:\r\n?|\n).*/g);return s?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),c},"input"),unput:u(function(c){var s=c.length,r=c.split(/(?:\r\n?|\n)/g);this._input=c+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-s),this.offset-=s;var g=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),r.length-1&&(this.yylineno-=r.length-1);var p=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:r?(r.length===g.length?this.yylloc.first_column:0)+g[g.length-r.length].length-r[0].length:this.yylloc.first_column-s},this.options.ranges&&(this.yylloc.range=[p[0],p[0]+this.yyleng-s]),this.yyleng=this.yytext.length,this},"unput"),more:u(function(){return this._more=!0,this},"more"),reject:u(function(){if(this.options.backtrack_lexer)this._backtrack=!0;else return this.parseError("Lexical error on line "+(this.yylineno+1)+`. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).
 `+this.showPosition(),{text:"",token:null,line:this.yylineno});return this},"reject"),less:u(function(c){this.unput(this.match.slice(c))},"less"),pastInput:u(function(){var c=this.matched.substr(0,this.matched.length-this.match.length);return(c.length>20?"...":"")+c.substr(-20).replace(/\n/g,"")},"pastInput"),upcomingInput:u(function(){var c=this.match;return c.length<20&&(c+=this._input.substr(0,20-c.length)),(c.substr(0,20)+(c.length>20?"...":"")).replace(/\n/g,"")},"upcomingInput"),showPosition:u(function(){var c=this.pastInput(),s=new Array(c.length+1).join("-");return c+this.upcomingInput()+`
diff --git a/assets/browser_dialer.html-BcXJ4Ezq.js b/assets/browser_dialer.html-B6OwvO3Q.js
similarity index 99%
rename from assets/browser_dialer.html-BcXJ4Ezq.js
rename to assets/browser_dialer.html-B6OwvO3Q.js
index b795e44805..c0a5102ab0 100644
--- a/assets/browser_dialer.html-BcXJ4Ezq.js
+++ b/assets/browser_dialer.html-B6OwvO3Q.js
@@ -1 +1 @@
-import{_ as c,r as s,o as h,c as d,a as t,d as o,b as e,w as i,e as u}from"./app-DBM4OJyw.js";const p={},b=e("h1",{id:"browser-dialer",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#browser-dialer"},[e("span",null,"Browser Dialer")])],-1),_=e("h2",{id:"background",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#background"},[e("span",null,"Background")])],-1),w=e("p",null,[o("Xray generally uses uTLS to mimic the behavior of popular browsers, and it can be controlled through the "),e("code",null,"fingerprint"),o(" setting. However, the fingerprints produced by uTLS are an imperfect replica of the real thing, and because uTLS is a popular library, they may be targeted themselves.")],-1),f={href:"https://github.com/v2ray/discussion/issues/754#issuecomment-647934994",target:"_blank",rel:"noopener noreferrer"},g=e("code",null,"localhost:8080",-1),m=e("p",null,"The TLS fingerprinting behavior is perfect this way, and so it may be possible to revive servers that open fine as websites in the browser, but do not connect using any proxying software.",-1),y=e("p",null,"However, there are many drawbacks:",-1),T=e("li",null,"The user has to launch a browser next to the Xray client just for opening the proxy connection.",-1),S=e("li",null,"The browser dialer must not be tunneled through the proxy itself, otherwise there is a loop. TUN users should be cautious.",-1),k={href:"https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS",target:"_blank",rel:"noopener noreferrer"},v=e("code",null,"localhost:8080",-1),x=e("code",null,"proxy.example.com:443",-1),R=e("li",null,"The browser tunnels your traffic using JavaScript, so there is a significant performance penalty (or, battery drain)",-1),L=e("li",null,[o("The configuration to be used with browser dialer cannot use custom SNI or host headers. "),e("code",null,"SNI == host == address"),o(". Custom HTTP headers and "),e("code",null,"tlsSettings"),o(" are ignored entirely.")],-1),X=u('

Configuration

  1. Prepare a usable WebSocket or SplitHTTP configuration. Be aware of the above restrictions.
  2. Launch Xray with XRAY_BROWSER_DIALER=127.0.0.1:8080. On Windows, this can be done as set XRAY_BROWSER_DIALER=... and then launching the core from the console, on Linux the core can be launched as XRAY_BROWSER_DIALER=127.0.0.1:8080 ./xray -c config.json.
  3. Open a browser that is not tunneled through the proxy, or modify the config's routing such that the Xray server's domain goes to freedom directly from the client. Browse to localhost:8080, and open the developer console with F12 to monitor for errors.
  4. For better performance and to bypass arbitrary connection limits enforced by the browser, it is recommended to enable Mux.Cool.

Inner workings

  • Xray listens on http://127.0.0.1:8080, and the browser accesses http://127.0.0.1:8080 to load the JS in the webpage.
  • The JS actively establishes a WebSocket connection to http://127.0.0.1:8080. Xray will use this connection to send instructions, but for now it goes into a connection pool (implemented as Go channel).
  • When a connection needs to be established, Xray receives an available connection from the pool and sends the protocol name, target URL and optional early data.
  • Once the JS successfully connects to the target, it informs Xray and continues to use this conn to bi-directionally forward data.
  • After the connection to the server is closed, the connection to localhost is also closed, but the JS ensures that there is always at least one idle connection available.

WebSocket

',5),B=e("p",null,"According to the browser's needs, the early data mechanism has been adjusted as follows:",-1),I=e("li",null,[o("The server response header will contain the requested "),e("code",null,"Sec-WebSocket-Protocol"),o(", which also initially obfuscates the length characteristic of the WSS handshake response.")],-1),E=e("li",null,[o("The encoding used for early data for browsers is "),e("code",null,"base64.RawURLEncoding"),o(" instead of "),e("code",null,"StdEncoding"),o(", and the server has made it compatible.")],-1),H={href:"https://github.com/XTLS/Xray-core/pull/375",target:"_blank",rel:"noopener noreferrer"},P=e("code",null,"?ed=2048",-1),W=e("code",null,"MaxHeaderBytes",-1),A=e("s",null,"(Although it seems like it would work without modification.)",-1),C=e("h2",{id:"splithttp",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#splithttp"},[e("span",null,"SplitHTTP")])],-1),O=e("p",null,[o("SplitHTTP supports QUIC, but the browser's own QUIC stack may be used as well. In Chrome this can be done through "),e("code",null,"chrome://flags"),o(", in other browsers it may already be enabled or need a different flag.")],-1),N=e("p",null,[o("In general, "),e("code",null,"tlsSettings"),o(" are completely ignored when Browser Dialer is used. Xray does not have any control over which HTTP version the browser selects.")],-1);function J(U,D){const l=s("I18nTip"),n=s("Badge"),r=s("ExternalLinkIcon"),a=s("RouterLink");return h(),d("div",null,[t(l),b,t(n,{text:"BETA",type:"warning"}),o(),t(n,{text:"v1.4.1+",type:"warning"}),_,w,e("p",null,[o("So "),e("a",f,[o("the idea of browser dialer"),t(r)]),o(" is that Xray uses a real browser to establish TLS connections. The way this works is that Xray hosts a small website on "),g,o(", the user opens this website in a browser of their choice, and JavaScript on that page will act as Xray's networking stack (HTTP client, TLS client).")]),m,y,e("ul",null,[T,S,e("li",null,[o("The browser can only speak standard HTTP, which means that only "),t(a,{to:"/en/transports/websocket.html"},{default:i(()=>[o("WebSocket")]),_:1}),o(" and "),t(a,{to:"/en/transports/splithttp.html"},{default:i(()=>[o("SplitHTTP")]),_:1}),o(" are supported")]),e("li",null,[e("a",k,[o("CORS"),t(r)]),o(" needs to be considered when making requests from one website ("),v,o(") to another ("),x,o(")")]),R,L]),X,t(n,{text:"v1.4.1+",type:"warning"}),B,e("ul",null,[I,E,e("li",null,[o("In addition, due to "),e("a",H,[o("Xray-core#375"),t(r)]),o(" recommendations for "),P,o(", this PR also increased server "),W,o(" by 4096. "),A])]),C,t(n,{text:"v1.8.19+",type:"warning"}),O,N])}const j=c(p,[["render",J],["__file","browser_dialer.html.vue"]]);export{j as default}; +import{_ as c,r as s,o as h,c as d,a as t,d as o,b as e,w as i,e as u}from"./app-D7uBbsY3.js";const p={},b=e("h1",{id:"browser-dialer",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#browser-dialer"},[e("span",null,"Browser Dialer")])],-1),_=e("h2",{id:"background",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#background"},[e("span",null,"Background")])],-1),w=e("p",null,[o("Xray generally uses uTLS to mimic the behavior of popular browsers, and it can be controlled through the "),e("code",null,"fingerprint"),o(" setting. However, the fingerprints produced by uTLS are an imperfect replica of the real thing, and because uTLS is a popular library, they may be targeted themselves.")],-1),f={href:"https://github.com/v2ray/discussion/issues/754#issuecomment-647934994",target:"_blank",rel:"noopener noreferrer"},g=e("code",null,"localhost:8080",-1),m=e("p",null,"The TLS fingerprinting behavior is perfect this way, and so it may be possible to revive servers that open fine as websites in the browser, but do not connect using any proxying software.",-1),y=e("p",null,"However, there are many drawbacks:",-1),T=e("li",null,"The user has to launch a browser next to the Xray client just for opening the proxy connection.",-1),S=e("li",null,"The browser dialer must not be tunneled through the proxy itself, otherwise there is a loop. TUN users should be cautious.",-1),k={href:"https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS",target:"_blank",rel:"noopener noreferrer"},v=e("code",null,"localhost:8080",-1),x=e("code",null,"proxy.example.com:443",-1),R=e("li",null,"The browser tunnels your traffic using JavaScript, so there is a significant performance penalty (or, battery drain)",-1),L=e("li",null,[o("The configuration to be used with browser dialer cannot use custom SNI or host headers. "),e("code",null,"SNI == host == address"),o(". Custom HTTP headers and "),e("code",null,"tlsSettings"),o(" are ignored entirely.")],-1),X=u('

Configuration

  1. Prepare a usable WebSocket or SplitHTTP configuration. Be aware of the above restrictions.
  2. Launch Xray with XRAY_BROWSER_DIALER=127.0.0.1:8080. On Windows, this can be done as set XRAY_BROWSER_DIALER=... and then launching the core from the console, on Linux the core can be launched as XRAY_BROWSER_DIALER=127.0.0.1:8080 ./xray -c config.json.
  3. Open a browser that is not tunneled through the proxy, or modify the config's routing such that the Xray server's domain goes to freedom directly from the client. Browse to localhost:8080, and open the developer console with F12 to monitor for errors.
  4. For better performance and to bypass arbitrary connection limits enforced by the browser, it is recommended to enable Mux.Cool.

Inner workings

  • Xray listens on http://127.0.0.1:8080, and the browser accesses http://127.0.0.1:8080 to load the JS in the webpage.
  • The JS actively establishes a WebSocket connection to http://127.0.0.1:8080. Xray will use this connection to send instructions, but for now it goes into a connection pool (implemented as Go channel).
  • When a connection needs to be established, Xray receives an available connection from the pool and sends the protocol name, target URL and optional early data.
  • Once the JS successfully connects to the target, it informs Xray and continues to use this conn to bi-directionally forward data.
  • After the connection to the server is closed, the connection to localhost is also closed, but the JS ensures that there is always at least one idle connection available.

WebSocket

',5),B=e("p",null,"According to the browser's needs, the early data mechanism has been adjusted as follows:",-1),I=e("li",null,[o("The server response header will contain the requested "),e("code",null,"Sec-WebSocket-Protocol"),o(", which also initially obfuscates the length characteristic of the WSS handshake response.")],-1),E=e("li",null,[o("The encoding used for early data for browsers is "),e("code",null,"base64.RawURLEncoding"),o(" instead of "),e("code",null,"StdEncoding"),o(", and the server has made it compatible.")],-1),H={href:"https://github.com/XTLS/Xray-core/pull/375",target:"_blank",rel:"noopener noreferrer"},P=e("code",null,"?ed=2048",-1),W=e("code",null,"MaxHeaderBytes",-1),A=e("s",null,"(Although it seems like it would work without modification.)",-1),C=e("h2",{id:"splithttp",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#splithttp"},[e("span",null,"SplitHTTP")])],-1),O=e("p",null,[o("SplitHTTP supports QUIC, but the browser's own QUIC stack may be used as well. In Chrome this can be done through "),e("code",null,"chrome://flags"),o(", in other browsers it may already be enabled or need a different flag.")],-1),N=e("p",null,[o("In general, "),e("code",null,"tlsSettings"),o(" are completely ignored when Browser Dialer is used. Xray does not have any control over which HTTP version the browser selects.")],-1);function J(U,D){const l=s("I18nTip"),n=s("Badge"),r=s("ExternalLinkIcon"),a=s("RouterLink");return h(),d("div",null,[t(l),b,t(n,{text:"BETA",type:"warning"}),o(),t(n,{text:"v1.4.1+",type:"warning"}),_,w,e("p",null,[o("So "),e("a",f,[o("the idea of browser dialer"),t(r)]),o(" is that Xray uses a real browser to establish TLS connections. The way this works is that Xray hosts a small website on "),g,o(", the user opens this website in a browser of their choice, and JavaScript on that page will act as Xray's networking stack (HTTP client, TLS client).")]),m,y,e("ul",null,[T,S,e("li",null,[o("The browser can only speak standard HTTP, which means that only "),t(a,{to:"/en/transports/websocket.html"},{default:i(()=>[o("WebSocket")]),_:1}),o(" and "),t(a,{to:"/en/transports/splithttp.html"},{default:i(()=>[o("SplitHTTP")]),_:1}),o(" are supported")]),e("li",null,[e("a",k,[o("CORS"),t(r)]),o(" needs to be considered when making requests from one website ("),v,o(") to another ("),x,o(")")]),R,L]),X,t(n,{text:"v1.4.1+",type:"warning"}),B,e("ul",null,[I,E,e("li",null,[o("In addition, due to "),e("a",H,[o("Xray-core#375"),t(r)]),o(" recommendations for "),P,o(", this PR also increased server "),W,o(" by 4096. "),A])]),C,t(n,{text:"v1.8.19+",type:"warning"}),O,N])}const j=c(p,[["render",J],["__file","browser_dialer.html.vue"]]);export{j as default}; diff --git a/assets/browser_dialer.html-DGUfP3Xp.js b/assets/browser_dialer.html-C44hFL-t.js similarity index 98% rename from assets/browser_dialer.html-DGUfP3Xp.js rename to assets/browser_dialer.html-C44hFL-t.js index 4122228f61..561f5feb21 100644 --- a/assets/browser_dialer.html-DGUfP3Xp.js +++ b/assets/browser_dialer.html-C44hFL-t.js @@ -1 +1 @@ -import{_ as d,r as l,o as i,c as _,a as t,b as e,d as o,w as a,e as h}from"./app-DBM4OJyw.js";const u={},p=e("h1",{id:"browser-dialer",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#browser-dialer"},[e("span",null,"Browser Dialer")])],-1),S=e("h2",{id:"背景",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#背景"},[e("span",null,"背景")])],-1),T=e("p",null,[o("通过 uTLS,Xray 可以模拟主流浏览器的 TLS 握手指纹(具体参见 TLS 中 "),e("code",null,"fingerprint"),o(" 选项)。但是仍然不能保证在任意时刻 uTLS 模拟浏览器行为完全一致。")],-1),b={href:"https://github.com/v2ray/discussion/issues/754#issuecomment-647934994",target:"_blank",rel:"noopener noreferrer"},f=e("code",null,"localhost:8080",-1),m=e("p",null,"这个方法简洁的实现了真实的浏览器的 TLS 指纹、行为特征。最大程度抗检测与抗封锁。",-1),R=e("p",null,"不过目前的浏览器转发有以下缺点:",-1),x=e("li",null,"用户需要手动开浏览器",-1),k=e("li",null,"浏览器发出的连接必须直连 使用 tun 的用户需要特别注意容易形成死循环",-1),g=e("code",null,"localhost:8080",-1),y={href:"https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS",target:"_blank",rel:"noopener noreferrer"},L=e("li",null,"因为中间经过 JS 处理数据,会有一些性能损耗",-1),w=e("li",null,[o("不能使用自定义 SNI 或者 Host,也就是说 "),e("code",null,"SNI == host == address"),o("。自定义 HTTP 头以及其它 "),e("code",null,"tlsSettings"),o(" 项会被忽略")],-1),P=h('

配置方法

  1. 准备一份 WebSocket 或 SplitHTTP 配置,注意 address 必须填域名,若需要指定 IP,请配置 DNS 或系统 hosts
  2. 使用环境变量启动 Xray XRAY_BROWSER_DIALER=127.0.0.1:8080。Windows 上命令为 set XRAY_BROWSER_DIALER=127.0.0.1:8080 Linux 上命令为 XRAY_BROWSER_DIALER=127.0.0.1:8080 ./xray -c config.json
  3. 确保浏览器直连(或者在路由中将服务端地址直接由 freedom 发出),打开页面 localhost:8080,还可以 F12ConsoleNetwork
  4. 浏览器会限制发出的连接数,所以建议开启 Mux.Cool

内部通信机制

  • Xray 监听地址端口 http://127.0.0.1:8080,作为 HTTP 服务,浏览器访问地址,加载网页中的 JS。
  • JS 主动向 http://127.0.0.1:8080 建立 WebSocket 连接,成功后,Xray 将连接发给 channel。
  • 需要建立连接时,Xray 从 channel 接收一个可用的连接,并发送目标 URL 和可选的 early data。
  • JS 成功连接到目标后告知 Xray,并继续用这个 conn 全双工双向转发数据,连接关闭行为同步。
  • 连接使用后就会被关闭,但 JS 会确保始终有新空闲连接可用。

WebSocket

',5),X=e("p",null,"根据浏览器的需求,对 early data 机制进行了如下调整:",-1),H=e("li",null,[o("服务端响应头会带有请求的 "),e("code",null,"Sec-WebSocket-Protocol"),o(",这也初步混淆了 WSS 握手响应的长度特征。")],-1),I=e("li",null,[o("用于浏览器的 early data 编码是 "),e("code",null,"base64.RawURLEncoding"),o(" 而不是 "),e("code",null,"StdEncoding"),o(",服务端做了兼容。")],-1),E={href:"https://github.com/XTLS/Xray-core/pull/375",target:"_blank",rel:"noopener noreferrer"},W=e("code",null,"?ed=2048",-1),B=e("code",null,"MaxHeaderBytes",-1),C=e("s",null,"(虽然好像不改也没问题)",-1),N=e("h2",{id:"splithttp",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#splithttp"},[e("span",null,"SplitHTTP")])],-1),v=e("p",null,[o("SplitHTTP 本身支持 QUIC,如果想使用浏览器自己的 QUIC 网络栈,Chrome 可以在 "),e("code",null,"chrome://flags"),o(" 中设定。其它浏览器也有相关选项。")],-1),A=e("p",null,[o("原理上说 "),e("code",null,"tlsSettings"),o(" 项会被忽略,使用哪个 HTTP 版本将完全由浏览器决定。")],-1);function J(D,O){const r=l("I18nTip"),n=l("ExternalLinkIcon"),s=l("RouterLink"),c=l("Badge");return i(),_("div",null,[t(r),p,S,T,e("p",null,[o("对此 "),e("a",b,[o("浏览器转发(browser dialer)"),t(n)]),o("应运而生。用户在自己的浏览器中打开一个页面至 "),f,o(",这个页面利用原生 JS 充当 Xray 的网络栈,与代理服务端建立 TLS,HTTP 连接。")]),m,R,e("ul",null,[x,k,e("li",null,[o("浏览器只能发出 HTTP 连接 所以目前仅支持 "),t(s,{to:"/transports/websocket.html"},{default:a(()=>[o("WebSocket")]),_:1}),o(" 与 "),t(s,{to:"/transports/splithttp.html"},{default:a(()=>[o("SplitHTTP")]),_:1}),o(" 传输方式")]),e("li",null,[o("当浏览器从 "),g,o(" 页面连接至代理服务端,需要考虑 "),e("a",y,[o("CORS"),t(n)])]),L,w]),P,t(c,{text:"v1.4.1+",type:"warning"}),X,e("ul",null,[H,I,e("li",null,[o("此外,由于 "),e("a",E,[o("Xray-core#375"),t(n)]),o(" 推荐 "),W,o(",这个 PR 顺便将服务端一处 "),B,o(" 扩至了 4096。 "),C])]),N,t(c,{text:"v1.8.19+",type:"warning"}),v,A])}const V=d(u,[["render",J],["__file","browser_dialer.html.vue"]]);export{V as default}; +import{_ as d,r as l,o as i,c as _,a as t,b as e,d as o,w as a,e as h}from"./app-D7uBbsY3.js";const u={},p=e("h1",{id:"browser-dialer",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#browser-dialer"},[e("span",null,"Browser Dialer")])],-1),S=e("h2",{id:"背景",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#背景"},[e("span",null,"背景")])],-1),T=e("p",null,[o("通过 uTLS,Xray 可以模拟主流浏览器的 TLS 握手指纹(具体参见 TLS 中 "),e("code",null,"fingerprint"),o(" 选项)。但是仍然不能保证在任意时刻 uTLS 模拟浏览器行为完全一致。")],-1),b={href:"https://github.com/v2ray/discussion/issues/754#issuecomment-647934994",target:"_blank",rel:"noopener noreferrer"},f=e("code",null,"localhost:8080",-1),m=e("p",null,"这个方法简洁的实现了真实的浏览器的 TLS 指纹、行为特征。最大程度抗检测与抗封锁。",-1),R=e("p",null,"不过目前的浏览器转发有以下缺点:",-1),x=e("li",null,"用户需要手动开浏览器",-1),k=e("li",null,"浏览器发出的连接必须直连 使用 tun 的用户需要特别注意容易形成死循环",-1),g=e("code",null,"localhost:8080",-1),y={href:"https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS",target:"_blank",rel:"noopener noreferrer"},L=e("li",null,"因为中间经过 JS 处理数据,会有一些性能损耗",-1),w=e("li",null,[o("不能使用自定义 SNI 或者 Host,也就是说 "),e("code",null,"SNI == host == address"),o("。自定义 HTTP 头以及其它 "),e("code",null,"tlsSettings"),o(" 项会被忽略")],-1),P=h('

配置方法

  1. 准备一份 WebSocket 或 SplitHTTP 配置,注意 address 必须填域名,若需要指定 IP,请配置 DNS 或系统 hosts
  2. 使用环境变量启动 Xray XRAY_BROWSER_DIALER=127.0.0.1:8080。Windows 上命令为 set XRAY_BROWSER_DIALER=127.0.0.1:8080 Linux 上命令为 XRAY_BROWSER_DIALER=127.0.0.1:8080 ./xray -c config.json
  3. 确保浏览器直连(或者在路由中将服务端地址直接由 freedom 发出),打开页面 localhost:8080,还可以 F12ConsoleNetwork
  4. 浏览器会限制发出的连接数,所以建议开启 Mux.Cool

内部通信机制

  • Xray 监听地址端口 http://127.0.0.1:8080,作为 HTTP 服务,浏览器访问地址,加载网页中的 JS。
  • JS 主动向 http://127.0.0.1:8080 建立 WebSocket 连接,成功后,Xray 将连接发给 channel。
  • 需要建立连接时,Xray 从 channel 接收一个可用的连接,并发送目标 URL 和可选的 early data。
  • JS 成功连接到目标后告知 Xray,并继续用这个 conn 全双工双向转发数据,连接关闭行为同步。
  • 连接使用后就会被关闭,但 JS 会确保始终有新空闲连接可用。

WebSocket

',5),X=e("p",null,"根据浏览器的需求,对 early data 机制进行了如下调整:",-1),H=e("li",null,[o("服务端响应头会带有请求的 "),e("code",null,"Sec-WebSocket-Protocol"),o(",这也初步混淆了 WSS 握手响应的长度特征。")],-1),I=e("li",null,[o("用于浏览器的 early data 编码是 "),e("code",null,"base64.RawURLEncoding"),o(" 而不是 "),e("code",null,"StdEncoding"),o(",服务端做了兼容。")],-1),E={href:"https://github.com/XTLS/Xray-core/pull/375",target:"_blank",rel:"noopener noreferrer"},W=e("code",null,"?ed=2048",-1),B=e("code",null,"MaxHeaderBytes",-1),C=e("s",null,"(虽然好像不改也没问题)",-1),N=e("h2",{id:"splithttp",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#splithttp"},[e("span",null,"SplitHTTP")])],-1),v=e("p",null,[o("SplitHTTP 本身支持 QUIC,如果想使用浏览器自己的 QUIC 网络栈,Chrome 可以在 "),e("code",null,"chrome://flags"),o(" 中设定。其它浏览器也有相关选项。")],-1),A=e("p",null,[o("原理上说 "),e("code",null,"tlsSettings"),o(" 项会被忽略,使用哪个 HTTP 版本将完全由浏览器决定。")],-1);function J(D,O){const r=l("I18nTip"),n=l("ExternalLinkIcon"),s=l("RouterLink"),c=l("Badge");return i(),_("div",null,[t(r),p,S,T,e("p",null,[o("对此 "),e("a",b,[o("浏览器转发(browser dialer)"),t(n)]),o("应运而生。用户在自己的浏览器中打开一个页面至 "),f,o(",这个页面利用原生 JS 充当 Xray 的网络栈,与代理服务端建立 TLS,HTTP 连接。")]),m,R,e("ul",null,[x,k,e("li",null,[o("浏览器只能发出 HTTP 连接 所以目前仅支持 "),t(s,{to:"/transports/websocket.html"},{default:a(()=>[o("WebSocket")]),_:1}),o(" 与 "),t(s,{to:"/transports/splithttp.html"},{default:a(()=>[o("SplitHTTP")]),_:1}),o(" 传输方式")]),e("li",null,[o("当浏览器从 "),g,o(" 页面连接至代理服务端,需要考虑 "),e("a",y,[o("CORS"),t(n)])]),L,w]),P,t(c,{text:"v1.4.1+",type:"warning"}),X,e("ul",null,[H,I,e("li",null,[o("此外,由于 "),e("a",E,[o("Xray-core#375"),t(n)]),o(" 推荐 "),W,o(",这个 PR 顺便将服务端一处 "),B,o(" 扩至了 4096。 "),C])]),N,t(c,{text:"v1.8.19+",type:"warning"}),v,A])}const V=d(u,[["render",J],["__file","browser_dialer.html.vue"]]);export{V as default}; diff --git a/assets/browser_dialer.html-bGDmhYds.js b/assets/browser_dialer.html-ClnZpsOW.js similarity index 99% rename from assets/browser_dialer.html-bGDmhYds.js rename to assets/browser_dialer.html-ClnZpsOW.js index f2f2577e04..d943e1dcb9 100644 --- a/assets/browser_dialer.html-bGDmhYds.js +++ b/assets/browser_dialer.html-ClnZpsOW.js @@ -1 +1 @@ -import{_ as i,r as n,o as d,c as h,a as t,d as o,b as e,w as r,e as _}from"./app-DBM4OJyw.js";const u={},p=e("h1",{id:"browser-dialer",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#browser-dialer"},[e("span",null,"Browser Dialer")])],-1),S=e("h2",{id:"предыстория",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#предыстория"},[e("span",null,"Предыстория")])],-1),T=e("p",null,[o("Xray обычно использует uTLS для имитации поведения популярных браузеров, и им можно управлять с помощью настройки "),e("code",null,"fingerprint"),o(". Однако отпечатки, создаваемые uTLS, являются несовершенной копией реальных, и поскольку uTLS является популярной библиотекой, они сами могут стать целью.")],-1),b={href:"https://github.com/v2ray/discussion/issues/754#issuecomment-647934994",target:"_blank",rel:"noopener noreferrer"},f=e("code",null,"localhost:8080",-1),m=e("p",null,"Таким образом, поведение снятия отпечатков TLS является идеальным, и поэтому может быть возможно оживить серверы, которые отлично открываются как веб-сайты в браузере, но не подключаются с использованием какого-либо программного обеспечения для проксирования.",-1),x=e("p",null,"Однако есть много недостатков:",-1),y=e("li",null,"Пользователь должен запускать браузер рядом с клиентом Xray только для открытия прокси-соединения.",-1),g=e("li",null,"Browser Dialer не должен быть туннелирован через сам прокси, иначе возникнет петля. Пользователи TUN должны быть осторожны.",-1),w={href:"https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS",target:"_blank",rel:"noopener noreferrer"},R=e("code",null,"localhost:8080",-1),k=e("code",null,"proxy.example.com:443",-1),X=e("li",null,"Браузер туннелирует ваш трафик с помощью JavaScript, поэтому наблюдается значительное снижение производительности (или разрядка аккумулятора).",-1),L=e("li",null,[o("Конфигурация, используемая с Browser Dialer, не может использовать собственные заголовки SNI или хоста. "),e("code",null,"SNI == host == address"),o(". Пользовательские заголовки HTTP и "),e("code",null,"tlsSettings"),o(" игнорируются полностью.")],-1),B=_('

Конфигурация

  1. Подготовьте рабочую конфигурацию WebSocket или SplitHTTP. Помните о вышеуказанных ограничениях.
  2. Запустите Xray с помощью XRAY_BROWSER_DIALER=127.0.0.1:8080. В Windows это можно сделать как set XRAY_BROWSER_DIALER=..., а затем запустить ядро из консоли, в Linux ядро можно запустить как XRAY_BROWSER_DIALER=127.0.0.1:8080 ./xray -c config.json.
  3. Откройте браузер, который не туннелирован через прокси, или измените маршрутизацию конфигурации таким образом, чтобы домен сервера Xray переходил к freedom непосредственно с клиента. Перейдите по адресу localhost:8080 и откройте консоль разработчика с помощью F12, чтобы отслеживать ошибки.
  4. Для повышения производительности и обхода произвольных ограничений на подключение, применяемых браузером, рекомендуется включить Mux.Cool.

Внутренняя работа

  • Xray прослушивает http://127.0.0.1:8080, а браузер обращается к http://127.0.0.1:8080, чтобы загрузить JS на веб-страницу.
  • JS активно устанавливает соединение WebSocket с http://127.0.0.1:8080. Xray будет использовать это соединение для отправки инструкций, но пока оно попадает в пул соединений (реализованный как канал Go).
  • Когда необходимо установить соединение, Xray получает доступное соединение из пула и отправляет имя протокола, целевой URL-адрес и необязательные ранние данные.
  • Как только JS успешно подключается к цели, он сообщает об этом Xray и продолжает использовать это соединение для двунаправленной пересылки данных.
  • После закрытия соединения с сервером соединение с localhost также закрывается, но JS гарантирует, что всегда доступно как минимум одно незанятое соединение.

WebSocket

',5),E=e("p",null,"В соответствии с потребностями браузера механизм ранних данных был скорректирован следующим образом:",-1),I=e("li",null,[o("Заголовок ответа сервера будет содержать запрошенный "),e("code",null,"Sec-WebSocket-Protocol"),o(", который также изначально obfuscates the length characteristic of the WSS handshake response.")],-1),P=e("li",null,[o("Кодировка, используемая для ранних данных для браузеров, - это "),e("code",null,"base64.RawURLEncoding"),o(" вместо "),e("code",null,"StdEncoding"),o(", и сервер сделал ее совместимой.")],-1),W={href:"https://github.com/XTLS/Xray-core/pull/375",target:"_blank",rel:"noopener noreferrer"},v=e("code",null,"?ed=2048",-1),H=e("code",null,"MaxHeaderBytes",-1),C=e("s",null,"(Хотя, похоже, это будет работать и без модификации.)",-1),D=e("h2",{id:"splithttp",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#splithttp"},[e("span",null,"SplitHTTP")])],-1),N=e("p",null,[o("SplitHTTP поддерживает QUIC, но также может использоваться собственный стек QUIC браузера. В Chrome это можно сделать через "),e("code",null,"chrome://flags"),o(", в других браузерах он может быть уже включен или для него может потребоваться другой флаг.")],-1),A=e("p",null,[o("В общем, "),e("code",null,"tlsSettings"),o(" полностью игнорируются при использовании Browser Dialer. Xray никак не контролирует, какую версию HTTP выбирает браузер.")],-1);function J(U,O){const a=n("I18nTip"),l=n("Badge"),s=n("ExternalLinkIcon"),c=n("RouterLink");return d(),h("div",null,[t(a),p,t(l,{text:"БЕТА",type:"warning"}),o(),t(l,{text:"v1.4.1+",type:"warning"}),S,T,e("p",null,[o("Итак, "),e("a",b,[o("идея Browser Dialer"),t(s)]),o(" заключается в том, что Xray использует настоящий браузер для установления TLS-соединений. Это работает так: Xray запускает небольшой веб-сайт на "),f,o(", пользователь открывает этот веб-сайт в выбранном им браузере, а JavaScript на этой странице будет действовать как сетевой стек Xray (HTTP-клиент, TLS-клиент).")]),m,x,e("ul",null,[y,g,e("li",null,[o("Браузер может работать только со стандартным HTTP, что означает, что поддерживаются только "),t(c,{to:"/ru/transports/websocket.html"},{default:r(()=>[o("WebSocket")]),_:1}),o(" и "),t(c,{to:"/ru/transports/splithttp.html"},{default:r(()=>[o("SplitHTTP")]),_:1}),o(".")]),e("li",null,[e("a",w,[o("CORS"),t(s)]),o(" необходимо учитывать при выполнении запросов с одного веб-сайта ("),R,o(") на другой ("),k,o(").")]),X,L]),B,t(l,{text:"v1.4.1+",type:"warning"}),E,e("ul",null,[I,P,e("li",null,[o("Кроме того, в связи с "),e("a",W,[o("Xray-core#375"),t(s)]),o(" рекомендациями по "),v,o(" этот PR также увеличил сервер "),H,o(" на 4096. "),C])]),D,t(l,{text:"v1.8.19+",type:"warning"}),N,A])}const Y=i(u,[["render",J],["__file","browser_dialer.html.vue"]]);export{Y as default}; +import{_ as i,r as n,o as d,c as h,a as t,d as o,b as e,w as r,e as _}from"./app-D7uBbsY3.js";const u={},p=e("h1",{id:"browser-dialer",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#browser-dialer"},[e("span",null,"Browser Dialer")])],-1),S=e("h2",{id:"предыстория",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#предыстория"},[e("span",null,"Предыстория")])],-1),T=e("p",null,[o("Xray обычно использует uTLS для имитации поведения популярных браузеров, и им можно управлять с помощью настройки "),e("code",null,"fingerprint"),o(". Однако отпечатки, создаваемые uTLS, являются несовершенной копией реальных, и поскольку uTLS является популярной библиотекой, они сами могут стать целью.")],-1),b={href:"https://github.com/v2ray/discussion/issues/754#issuecomment-647934994",target:"_blank",rel:"noopener noreferrer"},f=e("code",null,"localhost:8080",-1),m=e("p",null,"Таким образом, поведение снятия отпечатков TLS является идеальным, и поэтому может быть возможно оживить серверы, которые отлично открываются как веб-сайты в браузере, но не подключаются с использованием какого-либо программного обеспечения для проксирования.",-1),x=e("p",null,"Однако есть много недостатков:",-1),y=e("li",null,"Пользователь должен запускать браузер рядом с клиентом Xray только для открытия прокси-соединения.",-1),g=e("li",null,"Browser Dialer не должен быть туннелирован через сам прокси, иначе возникнет петля. Пользователи TUN должны быть осторожны.",-1),w={href:"https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS",target:"_blank",rel:"noopener noreferrer"},R=e("code",null,"localhost:8080",-1),k=e("code",null,"proxy.example.com:443",-1),X=e("li",null,"Браузер туннелирует ваш трафик с помощью JavaScript, поэтому наблюдается значительное снижение производительности (или разрядка аккумулятора).",-1),L=e("li",null,[o("Конфигурация, используемая с Browser Dialer, не может использовать собственные заголовки SNI или хоста. "),e("code",null,"SNI == host == address"),o(". Пользовательские заголовки HTTP и "),e("code",null,"tlsSettings"),o(" игнорируются полностью.")],-1),B=_('

Конфигурация

  1. Подготовьте рабочую конфигурацию WebSocket или SplitHTTP. Помните о вышеуказанных ограничениях.
  2. Запустите Xray с помощью XRAY_BROWSER_DIALER=127.0.0.1:8080. В Windows это можно сделать как set XRAY_BROWSER_DIALER=..., а затем запустить ядро из консоли, в Linux ядро можно запустить как XRAY_BROWSER_DIALER=127.0.0.1:8080 ./xray -c config.json.
  3. Откройте браузер, который не туннелирован через прокси, или измените маршрутизацию конфигурации таким образом, чтобы домен сервера Xray переходил к freedom непосредственно с клиента. Перейдите по адресу localhost:8080 и откройте консоль разработчика с помощью F12, чтобы отслеживать ошибки.
  4. Для повышения производительности и обхода произвольных ограничений на подключение, применяемых браузером, рекомендуется включить Mux.Cool.

Внутренняя работа

  • Xray прослушивает http://127.0.0.1:8080, а браузер обращается к http://127.0.0.1:8080, чтобы загрузить JS на веб-страницу.
  • JS активно устанавливает соединение WebSocket с http://127.0.0.1:8080. Xray будет использовать это соединение для отправки инструкций, но пока оно попадает в пул соединений (реализованный как канал Go).
  • Когда необходимо установить соединение, Xray получает доступное соединение из пула и отправляет имя протокола, целевой URL-адрес и необязательные ранние данные.
  • Как только JS успешно подключается к цели, он сообщает об этом Xray и продолжает использовать это соединение для двунаправленной пересылки данных.
  • После закрытия соединения с сервером соединение с localhost также закрывается, но JS гарантирует, что всегда доступно как минимум одно незанятое соединение.

WebSocket

',5),E=e("p",null,"В соответствии с потребностями браузера механизм ранних данных был скорректирован следующим образом:",-1),I=e("li",null,[o("Заголовок ответа сервера будет содержать запрошенный "),e("code",null,"Sec-WebSocket-Protocol"),o(", который также изначально obfuscates the length characteristic of the WSS handshake response.")],-1),P=e("li",null,[o("Кодировка, используемая для ранних данных для браузеров, - это "),e("code",null,"base64.RawURLEncoding"),o(" вместо "),e("code",null,"StdEncoding"),o(", и сервер сделал ее совместимой.")],-1),W={href:"https://github.com/XTLS/Xray-core/pull/375",target:"_blank",rel:"noopener noreferrer"},v=e("code",null,"?ed=2048",-1),H=e("code",null,"MaxHeaderBytes",-1),C=e("s",null,"(Хотя, похоже, это будет работать и без модификации.)",-1),D=e("h2",{id:"splithttp",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#splithttp"},[e("span",null,"SplitHTTP")])],-1),N=e("p",null,[o("SplitHTTP поддерживает QUIC, но также может использоваться собственный стек QUIC браузера. В Chrome это можно сделать через "),e("code",null,"chrome://flags"),o(", в других браузерах он может быть уже включен или для него может потребоваться другой флаг.")],-1),A=e("p",null,[o("В общем, "),e("code",null,"tlsSettings"),o(" полностью игнорируются при использовании Browser Dialer. Xray никак не контролирует, какую версию HTTP выбирает браузер.")],-1);function J(U,O){const a=n("I18nTip"),l=n("Badge"),s=n("ExternalLinkIcon"),c=n("RouterLink");return d(),h("div",null,[t(a),p,t(l,{text:"БЕТА",type:"warning"}),o(),t(l,{text:"v1.4.1+",type:"warning"}),S,T,e("p",null,[o("Итак, "),e("a",b,[o("идея Browser Dialer"),t(s)]),o(" заключается в том, что Xray использует настоящий браузер для установления TLS-соединений. Это работает так: Xray запускает небольшой веб-сайт на "),f,o(", пользователь открывает этот веб-сайт в выбранном им браузере, а JavaScript на этой странице будет действовать как сетевой стек Xray (HTTP-клиент, TLS-клиент).")]),m,x,e("ul",null,[y,g,e("li",null,[o("Браузер может работать только со стандартным HTTP, что означает, что поддерживаются только "),t(c,{to:"/ru/transports/websocket.html"},{default:r(()=>[o("WebSocket")]),_:1}),o(" и "),t(c,{to:"/ru/transports/splithttp.html"},{default:r(()=>[o("SplitHTTP")]),_:1}),o(".")]),e("li",null,[e("a",w,[o("CORS"),t(s)]),o(" необходимо учитывать при выполнении запросов с одного веб-сайта ("),R,o(") на другой ("),k,o(").")]),X,L]),B,t(l,{text:"v1.4.1+",type:"warning"}),E,e("ul",null,[I,P,e("li",null,[o("Кроме того, в связи с "),e("a",W,[o("Xray-core#375"),t(s)]),o(" рекомендациями по "),v,o(" этот PR также увеличил сервер "),H,o(" на 4096. "),C])]),D,t(l,{text:"v1.8.19+",type:"warning"}),N,A])}const Y=i(u,[["render",J],["__file","browser_dialer.html.vue"]]);export{Y as default}; diff --git a/assets/c4Diagram-ZHOUKFWV-20XrCBlj.js b/assets/c4Diagram-ZHOUKFWV-rVMnyU9f.js similarity index 99% rename from assets/c4Diagram-ZHOUKFWV-20XrCBlj.js rename to assets/c4Diagram-ZHOUKFWV-rVMnyU9f.js index b086e3f640..8fc0d5e45d 100644 --- a/assets/c4Diagram-ZHOUKFWV-20XrCBlj.js +++ b/assets/c4Diagram-ZHOUKFWV-rVMnyU9f.js @@ -1,4 +1,4 @@ -import{d as Se,g as De}from"./chunk-AIUMCIBP-g55d6rFj.js";import{_ as g,a as Pe,s as Be,g as Ie,b as Me,c as Le,d as Dt,w as Ne,e as $t,f as de,h as Tt,i as ge,j as jt,l as fe,k as Ye,m as je}from"./mermaid.core-DapiNGBY.js";import"./app-DBM4OJyw.js";var Ft=function(){var e=g(function(_t,x,m,v){for(m=m||{},v=_t.length;v--;m[_t[v]]=x);return m},"o"),t=[1,24],s=[1,25],o=[1,26],l=[1,27],a=[1,28],r=[1,63],n=[1,64],i=[1,65],u=[1,66],d=[1,67],f=[1,68],y=[1,69],E=[1,29],O=[1,30],S=[1,31],P=[1,32],M=[1,33],U=[1,34],H=[1,35],q=[1,36],G=[1,37],K=[1,38],J=[1,39],Z=[1,40],$=[1,41],tt=[1,42],et=[1,43],at=[1,44],it=[1,45],nt=[1,46],rt=[1,47],st=[1,48],lt=[1,50],ot=[1,51],ct=[1,52],ht=[1,53],ut=[1,54],dt=[1,55],ft=[1,56],pt=[1,57],yt=[1,58],gt=[1,59],bt=[1,60],Ct=[14,42],Qt=[14,34,36,37,38,39,40,41,42,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74],Ot=[12,14,34,36,37,38,39,40,41,42,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74],k=[1,82],A=[1,83],C=[1,84],w=[1,85],T=[12,14,42],le=[12,14,33,42],Mt=[12,14,33,42,76,77,79,80],vt=[12,33],Ht=[34,36,37,38,39,40,41,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74],qt={trace:g(function(){},"trace"),yy:{},symbols_:{error:2,start:3,mermaidDoc:4,direction:5,direction_tb:6,direction_bt:7,direction_rl:8,direction_lr:9,graphConfig:10,C4_CONTEXT:11,NEWLINE:12,statements:13,EOF:14,C4_CONTAINER:15,C4_COMPONENT:16,C4_DYNAMIC:17,C4_DEPLOYMENT:18,otherStatements:19,diagramStatements:20,otherStatement:21,title:22,accDescription:23,acc_title:24,acc_title_value:25,acc_descr:26,acc_descr_value:27,acc_descr_multiline_value:28,boundaryStatement:29,boundaryStartStatement:30,boundaryStopStatement:31,boundaryStart:32,LBRACE:33,ENTERPRISE_BOUNDARY:34,attributes:35,SYSTEM_BOUNDARY:36,BOUNDARY:37,CONTAINER_BOUNDARY:38,NODE:39,NODE_L:40,NODE_R:41,RBRACE:42,diagramStatement:43,PERSON:44,PERSON_EXT:45,SYSTEM:46,SYSTEM_DB:47,SYSTEM_QUEUE:48,SYSTEM_EXT:49,SYSTEM_EXT_DB:50,SYSTEM_EXT_QUEUE:51,CONTAINER:52,CONTAINER_DB:53,CONTAINER_QUEUE:54,CONTAINER_EXT:55,CONTAINER_EXT_DB:56,CONTAINER_EXT_QUEUE:57,COMPONENT:58,COMPONENT_DB:59,COMPONENT_QUEUE:60,COMPONENT_EXT:61,COMPONENT_EXT_DB:62,COMPONENT_EXT_QUEUE:63,REL:64,BIREL:65,REL_U:66,REL_D:67,REL_L:68,REL_R:69,REL_B:70,REL_INDEX:71,UPDATE_EL_STYLE:72,UPDATE_REL_STYLE:73,UPDATE_LAYOUT_CONFIG:74,attribute:75,STR:76,STR_KEY:77,STR_VALUE:78,ATTRIBUTE:79,ATTRIBUTE_EMPTY:80,$accept:0,$end:1},terminals_:{2:"error",6:"direction_tb",7:"direction_bt",8:"direction_rl",9:"direction_lr",11:"C4_CONTEXT",12:"NEWLINE",14:"EOF",15:"C4_CONTAINER",16:"C4_COMPONENT",17:"C4_DYNAMIC",18:"C4_DEPLOYMENT",22:"title",23:"accDescription",24:"acc_title",25:"acc_title_value",26:"acc_descr",27:"acc_descr_value",28:"acc_descr_multiline_value",33:"LBRACE",34:"ENTERPRISE_BOUNDARY",36:"SYSTEM_BOUNDARY",37:"BOUNDARY",38:"CONTAINER_BOUNDARY",39:"NODE",40:"NODE_L",41:"NODE_R",42:"RBRACE",44:"PERSON",45:"PERSON_EXT",46:"SYSTEM",47:"SYSTEM_DB",48:"SYSTEM_QUEUE",49:"SYSTEM_EXT",50:"SYSTEM_EXT_DB",51:"SYSTEM_EXT_QUEUE",52:"CONTAINER",53:"CONTAINER_DB",54:"CONTAINER_QUEUE",55:"CONTAINER_EXT",56:"CONTAINER_EXT_DB",57:"CONTAINER_EXT_QUEUE",58:"COMPONENT",59:"COMPONENT_DB",60:"COMPONENT_QUEUE",61:"COMPONENT_EXT",62:"COMPONENT_EXT_DB",63:"COMPONENT_EXT_QUEUE",64:"REL",65:"BIREL",66:"REL_U",67:"REL_D",68:"REL_L",69:"REL_R",70:"REL_B",71:"REL_INDEX",72:"UPDATE_EL_STYLE",73:"UPDATE_REL_STYLE",74:"UPDATE_LAYOUT_CONFIG",76:"STR",77:"STR_KEY",78:"STR_VALUE",79:"ATTRIBUTE",80:"ATTRIBUTE_EMPTY"},productions_:[0,[3,1],[3,1],[5,1],[5,1],[5,1],[5,1],[4,1],[10,4],[10,4],[10,4],[10,4],[10,4],[13,1],[13,1],[13,2],[19,1],[19,2],[19,3],[21,1],[21,1],[21,2],[21,2],[21,1],[29,3],[30,3],[30,3],[30,4],[32,2],[32,2],[32,2],[32,2],[32,2],[32,2],[32,2],[31,1],[20,1],[20,2],[20,3],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,1],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[35,1],[35,2],[75,1],[75,2],[75,1],[75,1]],performAction:g(function(x,m,v,b,R,h,Rt){var p=h.length-1;switch(R){case 3:b.setDirection("TB");break;case 4:b.setDirection("BT");break;case 5:b.setDirection("RL");break;case 6:b.setDirection("LR");break;case 8:case 9:case 10:case 11:case 12:b.setC4Type(h[p-3]);break;case 19:b.setTitle(h[p].substring(6)),this.$=h[p].substring(6);break;case 20:b.setAccDescription(h[p].substring(15)),this.$=h[p].substring(15);break;case 21:this.$=h[p].trim(),b.setTitle(this.$);break;case 22:case 23:this.$=h[p].trim(),b.setAccDescription(this.$);break;case 28:h[p].splice(2,0,"ENTERPRISE"),b.addPersonOrSystemBoundary(...h[p]),this.$=h[p];break;case 29:h[p].splice(2,0,"SYSTEM"),b.addPersonOrSystemBoundary(...h[p]),this.$=h[p];break;case 30:b.addPersonOrSystemBoundary(...h[p]),this.$=h[p];break;case 31:h[p].splice(2,0,"CONTAINER"),b.addContainerBoundary(...h[p]),this.$=h[p];break;case 32:b.addDeploymentNode("node",...h[p]),this.$=h[p];break;case 33:b.addDeploymentNode("nodeL",...h[p]),this.$=h[p];break;case 34:b.addDeploymentNode("nodeR",...h[p]),this.$=h[p];break;case 35:b.popBoundaryParseStack();break;case 39:b.addPersonOrSystem("person",...h[p]),this.$=h[p];break;case 40:b.addPersonOrSystem("external_person",...h[p]),this.$=h[p];break;case 41:b.addPersonOrSystem("system",...h[p]),this.$=h[p];break;case 42:b.addPersonOrSystem("system_db",...h[p]),this.$=h[p];break;case 43:b.addPersonOrSystem("system_queue",...h[p]),this.$=h[p];break;case 44:b.addPersonOrSystem("external_system",...h[p]),this.$=h[p];break;case 45:b.addPersonOrSystem("external_system_db",...h[p]),this.$=h[p];break;case 46:b.addPersonOrSystem("external_system_queue",...h[p]),this.$=h[p];break;case 47:b.addContainer("container",...h[p]),this.$=h[p];break;case 48:b.addContainer("container_db",...h[p]),this.$=h[p];break;case 49:b.addContainer("container_queue",...h[p]),this.$=h[p];break;case 50:b.addContainer("external_container",...h[p]),this.$=h[p];break;case 51:b.addContainer("external_container_db",...h[p]),this.$=h[p];break;case 52:b.addContainer("external_container_queue",...h[p]),this.$=h[p];break;case 53:b.addComponent("component",...h[p]),this.$=h[p];break;case 54:b.addComponent("component_db",...h[p]),this.$=h[p];break;case 55:b.addComponent("component_queue",...h[p]),this.$=h[p];break;case 56:b.addComponent("external_component",...h[p]),this.$=h[p];break;case 57:b.addComponent("external_component_db",...h[p]),this.$=h[p];break;case 58:b.addComponent("external_component_queue",...h[p]),this.$=h[p];break;case 60:b.addRel("rel",...h[p]),this.$=h[p];break;case 61:b.addRel("birel",...h[p]),this.$=h[p];break;case 62:b.addRel("rel_u",...h[p]),this.$=h[p];break;case 63:b.addRel("rel_d",...h[p]),this.$=h[p];break;case 64:b.addRel("rel_l",...h[p]),this.$=h[p];break;case 65:b.addRel("rel_r",...h[p]),this.$=h[p];break;case 66:b.addRel("rel_b",...h[p]),this.$=h[p];break;case 67:h[p].splice(0,1),b.addRel("rel",...h[p]),this.$=h[p];break;case 68:b.updateElStyle("update_el_style",...h[p]),this.$=h[p];break;case 69:b.updateRelStyle("update_rel_style",...h[p]),this.$=h[p];break;case 70:b.updateLayoutConfig("update_layout_config",...h[p]),this.$=h[p];break;case 71:this.$=[h[p]];break;case 72:h[p].unshift(h[p-1]),this.$=h[p];break;case 73:case 75:this.$=h[p].trim();break;case 74:let Et={};Et[h[p-1].trim()]=h[p].trim(),this.$=Et;break;case 76:this.$="";break}},"anonymous"),table:[{3:1,4:2,5:3,6:[1,5],7:[1,6],8:[1,7],9:[1,8],10:4,11:[1,9],15:[1,10],16:[1,11],17:[1,12],18:[1,13]},{1:[3]},{1:[2,1]},{1:[2,2]},{1:[2,7]},{1:[2,3]},{1:[2,4]},{1:[2,5]},{1:[2,6]},{12:[1,14]},{12:[1,15]},{12:[1,16]},{12:[1,17]},{12:[1,18]},{13:19,19:20,20:21,21:22,22:t,23:s,24:o,26:l,28:a,29:49,30:61,32:62,34:r,36:n,37:i,38:u,39:d,40:f,41:y,43:23,44:E,45:O,46:S,47:P,48:M,49:U,50:H,51:q,52:G,53:K,54:J,55:Z,56:$,57:tt,58:et,59:at,60:it,61:nt,62:rt,63:st,64:lt,65:ot,66:ct,67:ht,68:ut,69:dt,70:ft,71:pt,72:yt,73:gt,74:bt},{13:70,19:20,20:21,21:22,22:t,23:s,24:o,26:l,28:a,29:49,30:61,32:62,34:r,36:n,37:i,38:u,39:d,40:f,41:y,43:23,44:E,45:O,46:S,47:P,48:M,49:U,50:H,51:q,52:G,53:K,54:J,55:Z,56:$,57:tt,58:et,59:at,60:it,61:nt,62:rt,63:st,64:lt,65:ot,66:ct,67:ht,68:ut,69:dt,70:ft,71:pt,72:yt,73:gt,74:bt},{13:71,19:20,20:21,21:22,22:t,23:s,24:o,26:l,28:a,29:49,30:61,32:62,34:r,36:n,37:i,38:u,39:d,40:f,41:y,43:23,44:E,45:O,46:S,47:P,48:M,49:U,50:H,51:q,52:G,53:K,54:J,55:Z,56:$,57:tt,58:et,59:at,60:it,61:nt,62:rt,63:st,64:lt,65:ot,66:ct,67:ht,68:ut,69:dt,70:ft,71:pt,72:yt,73:gt,74:bt},{13:72,19:20,20:21,21:22,22:t,23:s,24:o,26:l,28:a,29:49,30:61,32:62,34:r,36:n,37:i,38:u,39:d,40:f,41:y,43:23,44:E,45:O,46:S,47:P,48:M,49:U,50:H,51:q,52:G,53:K,54:J,55:Z,56:$,57:tt,58:et,59:at,60:it,61:nt,62:rt,63:st,64:lt,65:ot,66:ct,67:ht,68:ut,69:dt,70:ft,71:pt,72:yt,73:gt,74:bt},{13:73,19:20,20:21,21:22,22:t,23:s,24:o,26:l,28:a,29:49,30:61,32:62,34:r,36:n,37:i,38:u,39:d,40:f,41:y,43:23,44:E,45:O,46:S,47:P,48:M,49:U,50:H,51:q,52:G,53:K,54:J,55:Z,56:$,57:tt,58:et,59:at,60:it,61:nt,62:rt,63:st,64:lt,65:ot,66:ct,67:ht,68:ut,69:dt,70:ft,71:pt,72:yt,73:gt,74:bt},{14:[1,74]},e(Ct,[2,13],{43:23,29:49,30:61,32:62,20:75,34:r,36:n,37:i,38:u,39:d,40:f,41:y,44:E,45:O,46:S,47:P,48:M,49:U,50:H,51:q,52:G,53:K,54:J,55:Z,56:$,57:tt,58:et,59:at,60:it,61:nt,62:rt,63:st,64:lt,65:ot,66:ct,67:ht,68:ut,69:dt,70:ft,71:pt,72:yt,73:gt,74:bt}),e(Ct,[2,14]),e(Qt,[2,16],{12:[1,76]}),e(Ct,[2,36],{12:[1,77]}),e(Ot,[2,19]),e(Ot,[2,20]),{25:[1,78]},{27:[1,79]},e(Ot,[2,23]),{35:80,75:81,76:k,77:A,79:C,80:w},{35:86,75:81,76:k,77:A,79:C,80:w},{35:87,75:81,76:k,77:A,79:C,80:w},{35:88,75:81,76:k,77:A,79:C,80:w},{35:89,75:81,76:k,77:A,79:C,80:w},{35:90,75:81,76:k,77:A,79:C,80:w},{35:91,75:81,76:k,77:A,79:C,80:w},{35:92,75:81,76:k,77:A,79:C,80:w},{35:93,75:81,76:k,77:A,79:C,80:w},{35:94,75:81,76:k,77:A,79:C,80:w},{35:95,75:81,76:k,77:A,79:C,80:w},{35:96,75:81,76:k,77:A,79:C,80:w},{35:97,75:81,76:k,77:A,79:C,80:w},{35:98,75:81,76:k,77:A,79:C,80:w},{35:99,75:81,76:k,77:A,79:C,80:w},{35:100,75:81,76:k,77:A,79:C,80:w},{35:101,75:81,76:k,77:A,79:C,80:w},{35:102,75:81,76:k,77:A,79:C,80:w},{35:103,75:81,76:k,77:A,79:C,80:w},{35:104,75:81,76:k,77:A,79:C,80:w},e(T,[2,59]),{35:105,75:81,76:k,77:A,79:C,80:w},{35:106,75:81,76:k,77:A,79:C,80:w},{35:107,75:81,76:k,77:A,79:C,80:w},{35:108,75:81,76:k,77:A,79:C,80:w},{35:109,75:81,76:k,77:A,79:C,80:w},{35:110,75:81,76:k,77:A,79:C,80:w},{35:111,75:81,76:k,77:A,79:C,80:w},{35:112,75:81,76:k,77:A,79:C,80:w},{35:113,75:81,76:k,77:A,79:C,80:w},{35:114,75:81,76:k,77:A,79:C,80:w},{35:115,75:81,76:k,77:A,79:C,80:w},{20:116,29:49,30:61,32:62,34:r,36:n,37:i,38:u,39:d,40:f,41:y,43:23,44:E,45:O,46:S,47:P,48:M,49:U,50:H,51:q,52:G,53:K,54:J,55:Z,56:$,57:tt,58:et,59:at,60:it,61:nt,62:rt,63:st,64:lt,65:ot,66:ct,67:ht,68:ut,69:dt,70:ft,71:pt,72:yt,73:gt,74:bt},{12:[1,118],33:[1,117]},{35:119,75:81,76:k,77:A,79:C,80:w},{35:120,75:81,76:k,77:A,79:C,80:w},{35:121,75:81,76:k,77:A,79:C,80:w},{35:122,75:81,76:k,77:A,79:C,80:w},{35:123,75:81,76:k,77:A,79:C,80:w},{35:124,75:81,76:k,77:A,79:C,80:w},{35:125,75:81,76:k,77:A,79:C,80:w},{14:[1,126]},{14:[1,127]},{14:[1,128]},{14:[1,129]},{1:[2,8]},e(Ct,[2,15]),e(Qt,[2,17],{21:22,19:130,22:t,23:s,24:o,26:l,28:a}),e(Ct,[2,37],{19:20,20:21,21:22,43:23,29:49,30:61,32:62,13:131,22:t,23:s,24:o,26:l,28:a,34:r,36:n,37:i,38:u,39:d,40:f,41:y,44:E,45:O,46:S,47:P,48:M,49:U,50:H,51:q,52:G,53:K,54:J,55:Z,56:$,57:tt,58:et,59:at,60:it,61:nt,62:rt,63:st,64:lt,65:ot,66:ct,67:ht,68:ut,69:dt,70:ft,71:pt,72:yt,73:gt,74:bt}),e(Ot,[2,21]),e(Ot,[2,22]),e(T,[2,39]),e(le,[2,71],{75:81,35:132,76:k,77:A,79:C,80:w}),e(Mt,[2,73]),{78:[1,133]},e(Mt,[2,75]),e(Mt,[2,76]),e(T,[2,40]),e(T,[2,41]),e(T,[2,42]),e(T,[2,43]),e(T,[2,44]),e(T,[2,45]),e(T,[2,46]),e(T,[2,47]),e(T,[2,48]),e(T,[2,49]),e(T,[2,50]),e(T,[2,51]),e(T,[2,52]),e(T,[2,53]),e(T,[2,54]),e(T,[2,55]),e(T,[2,56]),e(T,[2,57]),e(T,[2,58]),e(T,[2,60]),e(T,[2,61]),e(T,[2,62]),e(T,[2,63]),e(T,[2,64]),e(T,[2,65]),e(T,[2,66]),e(T,[2,67]),e(T,[2,68]),e(T,[2,69]),e(T,[2,70]),{31:134,42:[1,135]},{12:[1,136]},{33:[1,137]},e(vt,[2,28]),e(vt,[2,29]),e(vt,[2,30]),e(vt,[2,31]),e(vt,[2,32]),e(vt,[2,33]),e(vt,[2,34]),{1:[2,9]},{1:[2,10]},{1:[2,11]},{1:[2,12]},e(Qt,[2,18]),e(Ct,[2,38]),e(le,[2,72]),e(Mt,[2,74]),e(T,[2,24]),e(T,[2,35]),e(Ht,[2,25]),e(Ht,[2,26],{12:[1,138]}),e(Ht,[2,27])],defaultActions:{2:[2,1],3:[2,2],4:[2,7],5:[2,3],6:[2,4],7:[2,5],8:[2,6],74:[2,8],126:[2,9],127:[2,10],128:[2,11],129:[2,12]},parseError:g(function(x,m){if(m.recoverable)this.trace(x);else{var v=new Error(x);throw v.hash=m,v}},"parseError"),parse:g(function(x){var m=this,v=[0],b=[],R=[null],h=[],Rt=this.table,p="",Et=0,oe=0,we=2,ce=1,Te=h.slice.call(arguments,1),D=Object.create(this.lexer),kt={yy:{}};for(var Gt in this.yy)Object.prototype.hasOwnProperty.call(this.yy,Gt)&&(kt.yy[Gt]=this.yy[Gt]);D.setInput(x,kt.yy),kt.yy.lexer=D,kt.yy.parser=this,typeof D.yylloc>"u"&&(D.yylloc={});var Kt=D.yylloc;h.push(Kt);var Oe=D.options&&D.options.ranges;typeof kt.yy.parseError=="function"?this.parseError=kt.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function Re(L){v.length=v.length-2*L,R.length=R.length-L,h.length=h.length-L}g(Re,"popStack");function he(){var L;return L=b.pop()||D.lex()||ce,typeof L!="number"&&(L instanceof Array&&(b=L,L=b.pop()),L=m.symbols_[L]||L),L}g(he,"lex");for(var I,At,N,Jt,wt={},Nt,W,ue,Yt;;){if(At=v[v.length-1],this.defaultActions[At]?N=this.defaultActions[At]:((I===null||typeof I>"u")&&(I=he()),N=Rt[At]&&Rt[At][I]),typeof N>"u"||!N.length||!N[0]){var Zt="";Yt=[];for(Nt in Rt[At])this.terminals_[Nt]&&Nt>we&&Yt.push("'"+this.terminals_[Nt]+"'");D.showPosition?Zt="Parse error on line "+(Et+1)+`: +import{d as Se,g as De}from"./chunk-AIUMCIBP-v8d5o65o.js";import{_ as g,a as Pe,s as Be,g as Ie,b as Me,c as Le,d as Dt,w as Ne,e as $t,f as de,h as Tt,i as ge,j as jt,l as fe,k as Ye,m as je}from"./mermaid.core-D8igZDel.js";import"./app-D7uBbsY3.js";var Ft=function(){var e=g(function(_t,x,m,v){for(m=m||{},v=_t.length;v--;m[_t[v]]=x);return m},"o"),t=[1,24],s=[1,25],o=[1,26],l=[1,27],a=[1,28],r=[1,63],n=[1,64],i=[1,65],u=[1,66],d=[1,67],f=[1,68],y=[1,69],E=[1,29],O=[1,30],S=[1,31],P=[1,32],M=[1,33],U=[1,34],H=[1,35],q=[1,36],G=[1,37],K=[1,38],J=[1,39],Z=[1,40],$=[1,41],tt=[1,42],et=[1,43],at=[1,44],it=[1,45],nt=[1,46],rt=[1,47],st=[1,48],lt=[1,50],ot=[1,51],ct=[1,52],ht=[1,53],ut=[1,54],dt=[1,55],ft=[1,56],pt=[1,57],yt=[1,58],gt=[1,59],bt=[1,60],Ct=[14,42],Qt=[14,34,36,37,38,39,40,41,42,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74],Ot=[12,14,34,36,37,38,39,40,41,42,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74],k=[1,82],A=[1,83],C=[1,84],w=[1,85],T=[12,14,42],le=[12,14,33,42],Mt=[12,14,33,42,76,77,79,80],vt=[12,33],Ht=[34,36,37,38,39,40,41,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74],qt={trace:g(function(){},"trace"),yy:{},symbols_:{error:2,start:3,mermaidDoc:4,direction:5,direction_tb:6,direction_bt:7,direction_rl:8,direction_lr:9,graphConfig:10,C4_CONTEXT:11,NEWLINE:12,statements:13,EOF:14,C4_CONTAINER:15,C4_COMPONENT:16,C4_DYNAMIC:17,C4_DEPLOYMENT:18,otherStatements:19,diagramStatements:20,otherStatement:21,title:22,accDescription:23,acc_title:24,acc_title_value:25,acc_descr:26,acc_descr_value:27,acc_descr_multiline_value:28,boundaryStatement:29,boundaryStartStatement:30,boundaryStopStatement:31,boundaryStart:32,LBRACE:33,ENTERPRISE_BOUNDARY:34,attributes:35,SYSTEM_BOUNDARY:36,BOUNDARY:37,CONTAINER_BOUNDARY:38,NODE:39,NODE_L:40,NODE_R:41,RBRACE:42,diagramStatement:43,PERSON:44,PERSON_EXT:45,SYSTEM:46,SYSTEM_DB:47,SYSTEM_QUEUE:48,SYSTEM_EXT:49,SYSTEM_EXT_DB:50,SYSTEM_EXT_QUEUE:51,CONTAINER:52,CONTAINER_DB:53,CONTAINER_QUEUE:54,CONTAINER_EXT:55,CONTAINER_EXT_DB:56,CONTAINER_EXT_QUEUE:57,COMPONENT:58,COMPONENT_DB:59,COMPONENT_QUEUE:60,COMPONENT_EXT:61,COMPONENT_EXT_DB:62,COMPONENT_EXT_QUEUE:63,REL:64,BIREL:65,REL_U:66,REL_D:67,REL_L:68,REL_R:69,REL_B:70,REL_INDEX:71,UPDATE_EL_STYLE:72,UPDATE_REL_STYLE:73,UPDATE_LAYOUT_CONFIG:74,attribute:75,STR:76,STR_KEY:77,STR_VALUE:78,ATTRIBUTE:79,ATTRIBUTE_EMPTY:80,$accept:0,$end:1},terminals_:{2:"error",6:"direction_tb",7:"direction_bt",8:"direction_rl",9:"direction_lr",11:"C4_CONTEXT",12:"NEWLINE",14:"EOF",15:"C4_CONTAINER",16:"C4_COMPONENT",17:"C4_DYNAMIC",18:"C4_DEPLOYMENT",22:"title",23:"accDescription",24:"acc_title",25:"acc_title_value",26:"acc_descr",27:"acc_descr_value",28:"acc_descr_multiline_value",33:"LBRACE",34:"ENTERPRISE_BOUNDARY",36:"SYSTEM_BOUNDARY",37:"BOUNDARY",38:"CONTAINER_BOUNDARY",39:"NODE",40:"NODE_L",41:"NODE_R",42:"RBRACE",44:"PERSON",45:"PERSON_EXT",46:"SYSTEM",47:"SYSTEM_DB",48:"SYSTEM_QUEUE",49:"SYSTEM_EXT",50:"SYSTEM_EXT_DB",51:"SYSTEM_EXT_QUEUE",52:"CONTAINER",53:"CONTAINER_DB",54:"CONTAINER_QUEUE",55:"CONTAINER_EXT",56:"CONTAINER_EXT_DB",57:"CONTAINER_EXT_QUEUE",58:"COMPONENT",59:"COMPONENT_DB",60:"COMPONENT_QUEUE",61:"COMPONENT_EXT",62:"COMPONENT_EXT_DB",63:"COMPONENT_EXT_QUEUE",64:"REL",65:"BIREL",66:"REL_U",67:"REL_D",68:"REL_L",69:"REL_R",70:"REL_B",71:"REL_INDEX",72:"UPDATE_EL_STYLE",73:"UPDATE_REL_STYLE",74:"UPDATE_LAYOUT_CONFIG",76:"STR",77:"STR_KEY",78:"STR_VALUE",79:"ATTRIBUTE",80:"ATTRIBUTE_EMPTY"},productions_:[0,[3,1],[3,1],[5,1],[5,1],[5,1],[5,1],[4,1],[10,4],[10,4],[10,4],[10,4],[10,4],[13,1],[13,1],[13,2],[19,1],[19,2],[19,3],[21,1],[21,1],[21,2],[21,2],[21,1],[29,3],[30,3],[30,3],[30,4],[32,2],[32,2],[32,2],[32,2],[32,2],[32,2],[32,2],[31,1],[20,1],[20,2],[20,3],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,1],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[35,1],[35,2],[75,1],[75,2],[75,1],[75,1]],performAction:g(function(x,m,v,b,R,h,Rt){var p=h.length-1;switch(R){case 3:b.setDirection("TB");break;case 4:b.setDirection("BT");break;case 5:b.setDirection("RL");break;case 6:b.setDirection("LR");break;case 8:case 9:case 10:case 11:case 12:b.setC4Type(h[p-3]);break;case 19:b.setTitle(h[p].substring(6)),this.$=h[p].substring(6);break;case 20:b.setAccDescription(h[p].substring(15)),this.$=h[p].substring(15);break;case 21:this.$=h[p].trim(),b.setTitle(this.$);break;case 22:case 23:this.$=h[p].trim(),b.setAccDescription(this.$);break;case 28:h[p].splice(2,0,"ENTERPRISE"),b.addPersonOrSystemBoundary(...h[p]),this.$=h[p];break;case 29:h[p].splice(2,0,"SYSTEM"),b.addPersonOrSystemBoundary(...h[p]),this.$=h[p];break;case 30:b.addPersonOrSystemBoundary(...h[p]),this.$=h[p];break;case 31:h[p].splice(2,0,"CONTAINER"),b.addContainerBoundary(...h[p]),this.$=h[p];break;case 32:b.addDeploymentNode("node",...h[p]),this.$=h[p];break;case 33:b.addDeploymentNode("nodeL",...h[p]),this.$=h[p];break;case 34:b.addDeploymentNode("nodeR",...h[p]),this.$=h[p];break;case 35:b.popBoundaryParseStack();break;case 39:b.addPersonOrSystem("person",...h[p]),this.$=h[p];break;case 40:b.addPersonOrSystem("external_person",...h[p]),this.$=h[p];break;case 41:b.addPersonOrSystem("system",...h[p]),this.$=h[p];break;case 42:b.addPersonOrSystem("system_db",...h[p]),this.$=h[p];break;case 43:b.addPersonOrSystem("system_queue",...h[p]),this.$=h[p];break;case 44:b.addPersonOrSystem("external_system",...h[p]),this.$=h[p];break;case 45:b.addPersonOrSystem("external_system_db",...h[p]),this.$=h[p];break;case 46:b.addPersonOrSystem("external_system_queue",...h[p]),this.$=h[p];break;case 47:b.addContainer("container",...h[p]),this.$=h[p];break;case 48:b.addContainer("container_db",...h[p]),this.$=h[p];break;case 49:b.addContainer("container_queue",...h[p]),this.$=h[p];break;case 50:b.addContainer("external_container",...h[p]),this.$=h[p];break;case 51:b.addContainer("external_container_db",...h[p]),this.$=h[p];break;case 52:b.addContainer("external_container_queue",...h[p]),this.$=h[p];break;case 53:b.addComponent("component",...h[p]),this.$=h[p];break;case 54:b.addComponent("component_db",...h[p]),this.$=h[p];break;case 55:b.addComponent("component_queue",...h[p]),this.$=h[p];break;case 56:b.addComponent("external_component",...h[p]),this.$=h[p];break;case 57:b.addComponent("external_component_db",...h[p]),this.$=h[p];break;case 58:b.addComponent("external_component_queue",...h[p]),this.$=h[p];break;case 60:b.addRel("rel",...h[p]),this.$=h[p];break;case 61:b.addRel("birel",...h[p]),this.$=h[p];break;case 62:b.addRel("rel_u",...h[p]),this.$=h[p];break;case 63:b.addRel("rel_d",...h[p]),this.$=h[p];break;case 64:b.addRel("rel_l",...h[p]),this.$=h[p];break;case 65:b.addRel("rel_r",...h[p]),this.$=h[p];break;case 66:b.addRel("rel_b",...h[p]),this.$=h[p];break;case 67:h[p].splice(0,1),b.addRel("rel",...h[p]),this.$=h[p];break;case 68:b.updateElStyle("update_el_style",...h[p]),this.$=h[p];break;case 69:b.updateRelStyle("update_rel_style",...h[p]),this.$=h[p];break;case 70:b.updateLayoutConfig("update_layout_config",...h[p]),this.$=h[p];break;case 71:this.$=[h[p]];break;case 72:h[p].unshift(h[p-1]),this.$=h[p];break;case 73:case 75:this.$=h[p].trim();break;case 74:let Et={};Et[h[p-1].trim()]=h[p].trim(),this.$=Et;break;case 76:this.$="";break}},"anonymous"),table:[{3:1,4:2,5:3,6:[1,5],7:[1,6],8:[1,7],9:[1,8],10:4,11:[1,9],15:[1,10],16:[1,11],17:[1,12],18:[1,13]},{1:[3]},{1:[2,1]},{1:[2,2]},{1:[2,7]},{1:[2,3]},{1:[2,4]},{1:[2,5]},{1:[2,6]},{12:[1,14]},{12:[1,15]},{12:[1,16]},{12:[1,17]},{12:[1,18]},{13:19,19:20,20:21,21:22,22:t,23:s,24:o,26:l,28:a,29:49,30:61,32:62,34:r,36:n,37:i,38:u,39:d,40:f,41:y,43:23,44:E,45:O,46:S,47:P,48:M,49:U,50:H,51:q,52:G,53:K,54:J,55:Z,56:$,57:tt,58:et,59:at,60:it,61:nt,62:rt,63:st,64:lt,65:ot,66:ct,67:ht,68:ut,69:dt,70:ft,71:pt,72:yt,73:gt,74:bt},{13:70,19:20,20:21,21:22,22:t,23:s,24:o,26:l,28:a,29:49,30:61,32:62,34:r,36:n,37:i,38:u,39:d,40:f,41:y,43:23,44:E,45:O,46:S,47:P,48:M,49:U,50:H,51:q,52:G,53:K,54:J,55:Z,56:$,57:tt,58:et,59:at,60:it,61:nt,62:rt,63:st,64:lt,65:ot,66:ct,67:ht,68:ut,69:dt,70:ft,71:pt,72:yt,73:gt,74:bt},{13:71,19:20,20:21,21:22,22:t,23:s,24:o,26:l,28:a,29:49,30:61,32:62,34:r,36:n,37:i,38:u,39:d,40:f,41:y,43:23,44:E,45:O,46:S,47:P,48:M,49:U,50:H,51:q,52:G,53:K,54:J,55:Z,56:$,57:tt,58:et,59:at,60:it,61:nt,62:rt,63:st,64:lt,65:ot,66:ct,67:ht,68:ut,69:dt,70:ft,71:pt,72:yt,73:gt,74:bt},{13:72,19:20,20:21,21:22,22:t,23:s,24:o,26:l,28:a,29:49,30:61,32:62,34:r,36:n,37:i,38:u,39:d,40:f,41:y,43:23,44:E,45:O,46:S,47:P,48:M,49:U,50:H,51:q,52:G,53:K,54:J,55:Z,56:$,57:tt,58:et,59:at,60:it,61:nt,62:rt,63:st,64:lt,65:ot,66:ct,67:ht,68:ut,69:dt,70:ft,71:pt,72:yt,73:gt,74:bt},{13:73,19:20,20:21,21:22,22:t,23:s,24:o,26:l,28:a,29:49,30:61,32:62,34:r,36:n,37:i,38:u,39:d,40:f,41:y,43:23,44:E,45:O,46:S,47:P,48:M,49:U,50:H,51:q,52:G,53:K,54:J,55:Z,56:$,57:tt,58:et,59:at,60:it,61:nt,62:rt,63:st,64:lt,65:ot,66:ct,67:ht,68:ut,69:dt,70:ft,71:pt,72:yt,73:gt,74:bt},{14:[1,74]},e(Ct,[2,13],{43:23,29:49,30:61,32:62,20:75,34:r,36:n,37:i,38:u,39:d,40:f,41:y,44:E,45:O,46:S,47:P,48:M,49:U,50:H,51:q,52:G,53:K,54:J,55:Z,56:$,57:tt,58:et,59:at,60:it,61:nt,62:rt,63:st,64:lt,65:ot,66:ct,67:ht,68:ut,69:dt,70:ft,71:pt,72:yt,73:gt,74:bt}),e(Ct,[2,14]),e(Qt,[2,16],{12:[1,76]}),e(Ct,[2,36],{12:[1,77]}),e(Ot,[2,19]),e(Ot,[2,20]),{25:[1,78]},{27:[1,79]},e(Ot,[2,23]),{35:80,75:81,76:k,77:A,79:C,80:w},{35:86,75:81,76:k,77:A,79:C,80:w},{35:87,75:81,76:k,77:A,79:C,80:w},{35:88,75:81,76:k,77:A,79:C,80:w},{35:89,75:81,76:k,77:A,79:C,80:w},{35:90,75:81,76:k,77:A,79:C,80:w},{35:91,75:81,76:k,77:A,79:C,80:w},{35:92,75:81,76:k,77:A,79:C,80:w},{35:93,75:81,76:k,77:A,79:C,80:w},{35:94,75:81,76:k,77:A,79:C,80:w},{35:95,75:81,76:k,77:A,79:C,80:w},{35:96,75:81,76:k,77:A,79:C,80:w},{35:97,75:81,76:k,77:A,79:C,80:w},{35:98,75:81,76:k,77:A,79:C,80:w},{35:99,75:81,76:k,77:A,79:C,80:w},{35:100,75:81,76:k,77:A,79:C,80:w},{35:101,75:81,76:k,77:A,79:C,80:w},{35:102,75:81,76:k,77:A,79:C,80:w},{35:103,75:81,76:k,77:A,79:C,80:w},{35:104,75:81,76:k,77:A,79:C,80:w},e(T,[2,59]),{35:105,75:81,76:k,77:A,79:C,80:w},{35:106,75:81,76:k,77:A,79:C,80:w},{35:107,75:81,76:k,77:A,79:C,80:w},{35:108,75:81,76:k,77:A,79:C,80:w},{35:109,75:81,76:k,77:A,79:C,80:w},{35:110,75:81,76:k,77:A,79:C,80:w},{35:111,75:81,76:k,77:A,79:C,80:w},{35:112,75:81,76:k,77:A,79:C,80:w},{35:113,75:81,76:k,77:A,79:C,80:w},{35:114,75:81,76:k,77:A,79:C,80:w},{35:115,75:81,76:k,77:A,79:C,80:w},{20:116,29:49,30:61,32:62,34:r,36:n,37:i,38:u,39:d,40:f,41:y,43:23,44:E,45:O,46:S,47:P,48:M,49:U,50:H,51:q,52:G,53:K,54:J,55:Z,56:$,57:tt,58:et,59:at,60:it,61:nt,62:rt,63:st,64:lt,65:ot,66:ct,67:ht,68:ut,69:dt,70:ft,71:pt,72:yt,73:gt,74:bt},{12:[1,118],33:[1,117]},{35:119,75:81,76:k,77:A,79:C,80:w},{35:120,75:81,76:k,77:A,79:C,80:w},{35:121,75:81,76:k,77:A,79:C,80:w},{35:122,75:81,76:k,77:A,79:C,80:w},{35:123,75:81,76:k,77:A,79:C,80:w},{35:124,75:81,76:k,77:A,79:C,80:w},{35:125,75:81,76:k,77:A,79:C,80:w},{14:[1,126]},{14:[1,127]},{14:[1,128]},{14:[1,129]},{1:[2,8]},e(Ct,[2,15]),e(Qt,[2,17],{21:22,19:130,22:t,23:s,24:o,26:l,28:a}),e(Ct,[2,37],{19:20,20:21,21:22,43:23,29:49,30:61,32:62,13:131,22:t,23:s,24:o,26:l,28:a,34:r,36:n,37:i,38:u,39:d,40:f,41:y,44:E,45:O,46:S,47:P,48:M,49:U,50:H,51:q,52:G,53:K,54:J,55:Z,56:$,57:tt,58:et,59:at,60:it,61:nt,62:rt,63:st,64:lt,65:ot,66:ct,67:ht,68:ut,69:dt,70:ft,71:pt,72:yt,73:gt,74:bt}),e(Ot,[2,21]),e(Ot,[2,22]),e(T,[2,39]),e(le,[2,71],{75:81,35:132,76:k,77:A,79:C,80:w}),e(Mt,[2,73]),{78:[1,133]},e(Mt,[2,75]),e(Mt,[2,76]),e(T,[2,40]),e(T,[2,41]),e(T,[2,42]),e(T,[2,43]),e(T,[2,44]),e(T,[2,45]),e(T,[2,46]),e(T,[2,47]),e(T,[2,48]),e(T,[2,49]),e(T,[2,50]),e(T,[2,51]),e(T,[2,52]),e(T,[2,53]),e(T,[2,54]),e(T,[2,55]),e(T,[2,56]),e(T,[2,57]),e(T,[2,58]),e(T,[2,60]),e(T,[2,61]),e(T,[2,62]),e(T,[2,63]),e(T,[2,64]),e(T,[2,65]),e(T,[2,66]),e(T,[2,67]),e(T,[2,68]),e(T,[2,69]),e(T,[2,70]),{31:134,42:[1,135]},{12:[1,136]},{33:[1,137]},e(vt,[2,28]),e(vt,[2,29]),e(vt,[2,30]),e(vt,[2,31]),e(vt,[2,32]),e(vt,[2,33]),e(vt,[2,34]),{1:[2,9]},{1:[2,10]},{1:[2,11]},{1:[2,12]},e(Qt,[2,18]),e(Ct,[2,38]),e(le,[2,72]),e(Mt,[2,74]),e(T,[2,24]),e(T,[2,35]),e(Ht,[2,25]),e(Ht,[2,26],{12:[1,138]}),e(Ht,[2,27])],defaultActions:{2:[2,1],3:[2,2],4:[2,7],5:[2,3],6:[2,4],7:[2,5],8:[2,6],74:[2,8],126:[2,9],127:[2,10],128:[2,11],129:[2,12]},parseError:g(function(x,m){if(m.recoverable)this.trace(x);else{var v=new Error(x);throw v.hash=m,v}},"parseError"),parse:g(function(x){var m=this,v=[0],b=[],R=[null],h=[],Rt=this.table,p="",Et=0,oe=0,we=2,ce=1,Te=h.slice.call(arguments,1),D=Object.create(this.lexer),kt={yy:{}};for(var Gt in this.yy)Object.prototype.hasOwnProperty.call(this.yy,Gt)&&(kt.yy[Gt]=this.yy[Gt]);D.setInput(x,kt.yy),kt.yy.lexer=D,kt.yy.parser=this,typeof D.yylloc>"u"&&(D.yylloc={});var Kt=D.yylloc;h.push(Kt);var Oe=D.options&&D.options.ranges;typeof kt.yy.parseError=="function"?this.parseError=kt.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function Re(L){v.length=v.length-2*L,R.length=R.length-L,h.length=h.length-L}g(Re,"popStack");function he(){var L;return L=b.pop()||D.lex()||ce,typeof L!="number"&&(L instanceof Array&&(b=L,L=b.pop()),L=m.symbols_[L]||L),L}g(he,"lex");for(var I,At,N,Jt,wt={},Nt,W,ue,Yt;;){if(At=v[v.length-1],this.defaultActions[At]?N=this.defaultActions[At]:((I===null||typeof I>"u")&&(I=he()),N=Rt[At]&&Rt[At][I]),typeof N>"u"||!N.length||!N[0]){var Zt="";Yt=[];for(Nt in Rt[At])this.terminals_[Nt]&&Nt>we&&Yt.push("'"+this.terminals_[Nt]+"'");D.showPosition?Zt="Parse error on line "+(Et+1)+`: `+D.showPosition()+` Expecting `+Yt.join(", ")+", got '"+(this.terminals_[I]||I)+"'":Zt="Parse error on line "+(Et+1)+": Unexpected "+(I==ce?"end of input":"'"+(this.terminals_[I]||I)+"'"),this.parseError(Zt,{text:D.match,token:this.terminals_[I]||I,line:D.yylineno,loc:Kt,expected:Yt})}if(N[0]instanceof Array&&N.length>1)throw new Error("Parse Error: multiple actions possible at state: "+At+", token: "+I);switch(N[0]){case 1:v.push(I),R.push(D.yytext),h.push(D.yylloc),v.push(N[1]),I=null,oe=D.yyleng,p=D.yytext,Et=D.yylineno,Kt=D.yylloc;break;case 2:if(W=this.productions_[N[1]][1],wt.$=R[R.length-W],wt._$={first_line:h[h.length-(W||1)].first_line,last_line:h[h.length-1].last_line,first_column:h[h.length-(W||1)].first_column,last_column:h[h.length-1].last_column},Oe&&(wt._$.range=[h[h.length-(W||1)].range[0],h[h.length-1].range[1]]),Jt=this.performAction.apply(wt,[p,oe,Et,kt.yy,N[1],R,h].concat(Te)),typeof Jt<"u")return Jt;W&&(v=v.slice(0,-1*W*2),R=R.slice(0,-1*W),h=h.slice(0,-1*W)),v.push(this.productions_[N[1]][0]),R.push(wt.$),h.push(wt._$),ue=Rt[v[v.length-2]][v[v.length-1]],v.push(ue);break;case 3:return!0}}return!0},"parse")},Ce=function(){var _t={EOF:1,parseError:g(function(m,v){if(this.yy.parser)this.yy.parser.parseError(m,v);else throw new Error(m)},"parseError"),setInput:g(function(x,m){return this.yy=m||this.yy||{},this._input=x,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},"setInput"),input:g(function(){var x=this._input[0];this.yytext+=x,this.yyleng++,this.offset++,this.match+=x,this.matched+=x;var m=x.match(/(?:\r\n?|\n).*/g);return m?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),x},"input"),unput:g(function(x){var m=x.length,v=x.split(/(?:\r\n?|\n)/g);this._input=x+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-m),this.offset-=m;var b=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),v.length-1&&(this.yylineno-=v.length-1);var R=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:v?(v.length===b.length?this.yylloc.first_column:0)+b[b.length-v.length].length-v[0].length:this.yylloc.first_column-m},this.options.ranges&&(this.yylloc.range=[R[0],R[0]+this.yyleng-m]),this.yyleng=this.yytext.length,this},"unput"),more:g(function(){return this._more=!0,this},"more"),reject:g(function(){if(this.options.backtrack_lexer)this._backtrack=!0;else return this.parseError("Lexical error on line "+(this.yylineno+1)+`. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true). `+this.showPosition(),{text:"",token:null,line:this.yylineno});return this},"reject"),less:g(function(x){this.unput(this.match.slice(x))},"less"),pastInput:g(function(){var x=this.matched.substr(0,this.matched.length-this.match.length);return(x.length>20?"...":"")+x.substr(-20).replace(/\n/g,"")},"pastInput"),upcomingInput:g(function(){var x=this.match;return x.length<20&&(x+=this._input.substr(0,20-x.length)),(x.substr(0,20)+(x.length>20?"...":"")).replace(/\n/g,"")},"upcomingInput"),showPosition:g(function(){var x=this.pastInput(),m=new Array(x.length+1).join("-");return x+this.upcomingInput()+` diff --git a/assets/ch01-preface.html-Rzsgtj_M.js b/assets/ch01-preface.html-B45aaai4.js similarity index 99% rename from assets/ch01-preface.html-Rzsgtj_M.js rename to assets/ch01-preface.html-B45aaai4.js index e3d53a3021..47b181e091 100644 --- a/assets/ch01-preface.html-Rzsgtj_M.js +++ b/assets/ch01-preface.html-B45aaai4.js @@ -1 +1 @@ -import{_ as s,r as a,o as n,c as o,a as r,e}from"./app-DBM4OJyw.js";const i="/assets/ch01-img01-choice-B3FXW047.png",t={},l=e('

【第 1 章】 小小白白话文

1.1 这篇文档是写给谁的?

一句话:写给 ① 零基础 ② 希望学习自建 VPS 的新人。

1.2 这篇文档不是写给谁的?

包括但不限于:各路大神大能、懒得自己折腾的小白、已经会折腾的高手、确定要用机场的土豪、确定要用一键脚本的逍遥派...... 总之只要有技术基础、或不愿不想自建的同学,您直接关闭本文即可,因为这篇文章大概是入不了您的法眼的,更可能会让您生一肚子闲气,那多划不来。

1.3 郑重声明及其他声明

郑重声明:

鄙人技术奇菜无比,故本文必然挂一漏万破绽百出。您若发现问题还请温柔提醒,莫要人参公鸡。

免责声明:

本文内容请您自行判断是否可信可靠可用,若您根据本文内容建立和使用 VPS 服务器时出了任何问题和不良结果,鄙人概不负责。

啰嗦声明:

基于本文【零基础用户】的目标受众,许多内容会尽力详尽说明,所以语言偏啰嗦,请做好心理准备。

1.4 为什么自建是个难题?

要回答这个问题,就需要稍微多说一点背景信息了。

一、科学上网这件事

科学上网这件事情,说来已经发展了近二十年(震惊!!!.jpg)。最初,自己稍微动动手即可(改改 host、连一下 ssh)、后来需要找一个网页代理,再后来需要写一个私有协议(比如 Shadowsocks)等等。

随着 GFW 技术这十几年来不断的迭代升级,若要完成【自己动手科学上网】这个目标,需要做的事情已经包括但不限于:

  • 了解 Linux 系统基本命令
  • 了解网络传输协议
  • 有技术和经济能力完成 VPS 购买及管理
  • 有技术和经济能力完成域名购买及管理
  • 有技术能力完成 TLS 证书申请 等等。

这就让【自建 VPS 科学上网】这个曾经简单的行为逐渐变成了令新人望而生畏的挑战。

二、零基础用户的无奈

零基础的非技术用户,如果完成上面这一连串的操作,势必要学习大量的知识,但稍微搜索之后,新人只怕会更加迷茫:大量的信息散布在互联网的各个角落:博客、问答网站、群组、论坛、GitHub、Telegram、YouTube 等等等等)。这些信息纷乱复杂、水平良莠不齐、甚至可能互相矛盾。基本上就是不把新人彻底弄晕誓不罢休。

面对这些杂乱无章的信息,新人突然就从【信息匮乏】变成了【信息过剩】。若是几番连蒙带猜的折腾以失败告终(大概率如此)的话,他的积极性势必大受挫折。在这个过程中,若他又恰好去了一些不太友好的地方去求助,恐怕还要雪上加霜的被嘲讽一番:“这么菜,用机场不就行了,瞎折腾什么啊!”、“先去学会 Linux 再回来问吧”。

这时候,大概也只有一声“呵呵”可以表达心情了。

1.5 “用机场不就行了?”

首先,我想反问一下那些冷嘲热讽的人:“用机场”真的就是万灵药吗?

其次,我认为“不懂”和“不想懂”是有本质区别的。态度恶劣的巨婴伸手党自然惹人厌烦,但真心自学却不得要领的人不该受到无端的白眼和歧视,也正是这种对新人不加区分的恶劣社区氛围促使我写下本文。那么闲话少说,我们来看看机场的优势与劣势究竟如何:

一、“机场“的优势

所谓“机场”,就是“线路提供商”。他负责完成 1.4 提到的那一串技术操作和管理,用户则付费获得使用权。所以,它的优点至少有:

  1. 用户操作简单:扫码操作、一键添加规则等
  2. 线路选择多:可解锁不同国家、地区的网络服务;比如 iplc 等专线服务、游戏加速服务等
  3. 接入节点多:所以抵抗节点封锁的能力强一些,封了一个就换下一个

二、“机场”的风险

“方便”这枚硬币的另一面就是“风险”,基于“机场”的技术特点和市场情况,它的风险至少有:

  1. “机场”可完全获得用户信息:用户在网上的所有痕迹,都【必然】经过且【非常可能】长期存储在其服务器上,这些记录无法受到任何具备法律效力的用户隐私协议的约束(窥视、记录你的一举一动
  2. “机场”缺乏市场管理:不可避免存在着以欺诈为目标的恶意商家(主动跑路
  3. “机场”面临监管压力:大机场相对有保障的同时,也无法避免树大招风。2020 年间,已经有几个大机场停运、跑路的事件发生,用户的正常使用受到严重干扰(被动跑路
  4. “机场”技术水平难以确定:线路质量良莠不齐,挂羊头卖狗肉的现象屡见不鲜(速度慢、掉线多、连不上

1.6 那么你到底要不要自建呢?

现在,你已经看到了机场的优势和风险,要用什么,就请各位充分思考并自行决定。毕竟,最适合你的方案才是最好的方案。

It's Your Choice!

  1. 如果决定使用机场的话,现在,你可以关闭本文了。

  2. 如果你决定自建,那就请继续阅读后面的章节吧!!

总之,本文的目标就是成为零基础用户的知识起点,提供对每一步充分的讲解和演示,清清楚楚(甚至婆婆妈妈、絮絮叨叨、啰啰嗦嗦)的协助新人完成【从输入第一条命令开始,完成 VPS 服务器部署,并成功在客户端完成科学上网】的全程。并在这个过程中帮助新人逐步接触和熟悉 Linux 的基础操作,为之后的进一步自学打下基础。

1.7 题外啰嗦几句

  1. 墙外的信息泥沙俱下,请务必学会理性、独立的思辨,不要随意站队,不要轻信猎奇的信息。

  2. 衷心希望大家获得更顺畅的网络后,可以获取更新鲜的知识、更丰富的娱乐、接触更美好的世界、结交更多志同道合的朋友,但不要成为任何有不可告人目的之人的替罪羊。

  3. 你的互联网身份依然是你的身份,绝对的匿名化是极为困难的,所以请务必遵守你个人所在地区和 IP 所在地区的相关法律法规。无论何时,自我保护都是最基本的底线。

1.8 你的进度

⬛⬜⬜⬜⬜⬜⬜⬜ 12.5%

',41);function h(c,d){const p=a("I18nTip");return n(),o("div",null,[r(p),l])}const _=s(t,[["render",h],["__file","ch01-preface.html.vue"]]);export{_ as default}; +import{_ as s,r as a,o as n,c as o,a as r,e}from"./app-D7uBbsY3.js";const i="/assets/ch01-img01-choice-B3FXW047.png",t={},l=e('

【第 1 章】 小小白白话文

1.1 这篇文档是写给谁的?

一句话:写给 ① 零基础 ② 希望学习自建 VPS 的新人。

1.2 这篇文档不是写给谁的?

包括但不限于:各路大神大能、懒得自己折腾的小白、已经会折腾的高手、确定要用机场的土豪、确定要用一键脚本的逍遥派...... 总之只要有技术基础、或不愿不想自建的同学,您直接关闭本文即可,因为这篇文章大概是入不了您的法眼的,更可能会让您生一肚子闲气,那多划不来。

1.3 郑重声明及其他声明

郑重声明:

鄙人技术奇菜无比,故本文必然挂一漏万破绽百出。您若发现问题还请温柔提醒,莫要人参公鸡。

免责声明:

本文内容请您自行判断是否可信可靠可用,若您根据本文内容建立和使用 VPS 服务器时出了任何问题和不良结果,鄙人概不负责。

啰嗦声明:

基于本文【零基础用户】的目标受众,许多内容会尽力详尽说明,所以语言偏啰嗦,请做好心理准备。

1.4 为什么自建是个难题?

要回答这个问题,就需要稍微多说一点背景信息了。

一、科学上网这件事

科学上网这件事情,说来已经发展了近二十年(震惊!!!.jpg)。最初,自己稍微动动手即可(改改 host、连一下 ssh)、后来需要找一个网页代理,再后来需要写一个私有协议(比如 Shadowsocks)等等。

随着 GFW 技术这十几年来不断的迭代升级,若要完成【自己动手科学上网】这个目标,需要做的事情已经包括但不限于:

  • 了解 Linux 系统基本命令
  • 了解网络传输协议
  • 有技术和经济能力完成 VPS 购买及管理
  • 有技术和经济能力完成域名购买及管理
  • 有技术能力完成 TLS 证书申请 等等。

这就让【自建 VPS 科学上网】这个曾经简单的行为逐渐变成了令新人望而生畏的挑战。

二、零基础用户的无奈

零基础的非技术用户,如果完成上面这一连串的操作,势必要学习大量的知识,但稍微搜索之后,新人只怕会更加迷茫:大量的信息散布在互联网的各个角落:博客、问答网站、群组、论坛、GitHub、Telegram、YouTube 等等等等)。这些信息纷乱复杂、水平良莠不齐、甚至可能互相矛盾。基本上就是不把新人彻底弄晕誓不罢休。

面对这些杂乱无章的信息,新人突然就从【信息匮乏】变成了【信息过剩】。若是几番连蒙带猜的折腾以失败告终(大概率如此)的话,他的积极性势必大受挫折。在这个过程中,若他又恰好去了一些不太友好的地方去求助,恐怕还要雪上加霜的被嘲讽一番:“这么菜,用机场不就行了,瞎折腾什么啊!”、“先去学会 Linux 再回来问吧”。

这时候,大概也只有一声“呵呵”可以表达心情了。

1.5 “用机场不就行了?”

首先,我想反问一下那些冷嘲热讽的人:“用机场”真的就是万灵药吗?

其次,我认为“不懂”和“不想懂”是有本质区别的。态度恶劣的巨婴伸手党自然惹人厌烦,但真心自学却不得要领的人不该受到无端的白眼和歧视,也正是这种对新人不加区分的恶劣社区氛围促使我写下本文。那么闲话少说,我们来看看机场的优势与劣势究竟如何:

一、“机场“的优势

所谓“机场”,就是“线路提供商”。他负责完成 1.4 提到的那一串技术操作和管理,用户则付费获得使用权。所以,它的优点至少有:

  1. 用户操作简单:扫码操作、一键添加规则等
  2. 线路选择多:可解锁不同国家、地区的网络服务;比如 iplc 等专线服务、游戏加速服务等
  3. 接入节点多:所以抵抗节点封锁的能力强一些,封了一个就换下一个

二、“机场”的风险

“方便”这枚硬币的另一面就是“风险”,基于“机场”的技术特点和市场情况,它的风险至少有:

  1. “机场”可完全获得用户信息:用户在网上的所有痕迹,都【必然】经过且【非常可能】长期存储在其服务器上,这些记录无法受到任何具备法律效力的用户隐私协议的约束(窥视、记录你的一举一动
  2. “机场”缺乏市场管理:不可避免存在着以欺诈为目标的恶意商家(主动跑路
  3. “机场”面临监管压力:大机场相对有保障的同时,也无法避免树大招风。2020 年间,已经有几个大机场停运、跑路的事件发生,用户的正常使用受到严重干扰(被动跑路
  4. “机场”技术水平难以确定:线路质量良莠不齐,挂羊头卖狗肉的现象屡见不鲜(速度慢、掉线多、连不上

1.6 那么你到底要不要自建呢?

现在,你已经看到了机场的优势和风险,要用什么,就请各位充分思考并自行决定。毕竟,最适合你的方案才是最好的方案。

It's Your Choice!

  1. 如果决定使用机场的话,现在,你可以关闭本文了。

  2. 如果你决定自建,那就请继续阅读后面的章节吧!!

总之,本文的目标就是成为零基础用户的知识起点,提供对每一步充分的讲解和演示,清清楚楚(甚至婆婆妈妈、絮絮叨叨、啰啰嗦嗦)的协助新人完成【从输入第一条命令开始,完成 VPS 服务器部署,并成功在客户端完成科学上网】的全程。并在这个过程中帮助新人逐步接触和熟悉 Linux 的基础操作,为之后的进一步自学打下基础。

1.7 题外啰嗦几句

  1. 墙外的信息泥沙俱下,请务必学会理性、独立的思辨,不要随意站队,不要轻信猎奇的信息。

  2. 衷心希望大家获得更顺畅的网络后,可以获取更新鲜的知识、更丰富的娱乐、接触更美好的世界、结交更多志同道合的朋友,但不要成为任何有不可告人目的之人的替罪羊。

  3. 你的互联网身份依然是你的身份,绝对的匿名化是极为困难的,所以请务必遵守你个人所在地区和 IP 所在地区的相关法律法规。无论何时,自我保护都是最基本的底线。

1.8 你的进度

⬛⬜⬜⬜⬜⬜⬜⬜ 12.5%

',41);function h(c,d){const p=a("I18nTip");return n(),o("div",null,[r(p),l])}const _=s(t,[["render",h],["__file","ch01-preface.html.vue"]]);export{_ as default}; diff --git a/assets/ch01-preface.html-BQg5DEiN.js b/assets/ch01-preface.html-CTOjY6Js.js similarity index 99% rename from assets/ch01-preface.html-BQg5DEiN.js rename to assets/ch01-preface.html-CTOjY6Js.js index ec63a7a08c..0e42798ca6 100644 --- a/assets/ch01-preface.html-BQg5DEiN.js +++ b/assets/ch01-preface.html-CTOjY6Js.js @@ -1 +1 @@ -import{_ as s,r as o,o as p,c as a,a as r,e as t}from"./app-DBM4OJyw.js";const e="/assets/ch01-img01-choice-B3FXW047.png",i={},l=t('

【Глава 1】 Простыми словами

1.1 Для кого эта документация?

В двух словах: для ① новичков без опыта ② желающих научиться настраивать свой собственный VPS.

1.2 Для кого эта документация не предназначена?

В том числе, но не ограничиваясь: для всевозможных гуру и экспертов, для тех, кто слишком ленив, чтобы во всём разбираться самостоятельно, для тех, кто уже умеет настраивать VPS, для тех, кто точно решил пользоваться платными VPN-сервисами, для тех, кто предпочитает использовать готовые скрипты... Короче говоря, если у вас есть технические знания или вы не хотите настраивать всё сами, можете смело закрывать эту статью. Скорее всего, она покажется вам бесполезной и даже может вызвать раздражение, а оно вам надо?

1.3 Важное замечание и другие примечания

Важное замечание:

Я не являюсь техническим экспертом, поэтому в этой статье неизбежны пробелы и неточности. Если вы обнаружите какие-либо ошибки, пожалуйста, дайте мне знать об этом деликатно, без лишних эмоций.

Отказ от ответственности:

Пожалуйста, относитесь к информации, представленной в этой статье, критически и проверяйте её самостоятельно. Я не несу никакой ответственности за любые проблемы или негативные последствия, возникшие в результате использования информации из этой статьи.

Предупреждение о многословности:

Поскольку эта статья предназначена для новичков без опыта, многие вещи будут объяснены максимально подробно. Поэтому будьте готовы к тому, что текст будет довольно многословным.

1.4 Почему самостоятельная настройка — это сложно?

Чтобы ответить на этот вопрос, нужно немного углубиться в историю вопроса.

Во-первых, обход блокировок существует уже почти двадцать лет (Шок! Ужас!). Сначала для этого достаточно было пары манипуляций (поправить файл hosts, подключиться по SSH), потом понадобились веб-прокси, затем — собственные протоколы (например, Shadowsocks) и так далее.

По мере того, как технологии блокировок совершенствовались на протяжении последних десятилетий, для самостоятельного обхода блокировок теперь нужно уметь:

  • Разбираться в основных командах Linux.
  • Понимать принципы работы сетевых протоколов.
  • Иметь технические навыки и средства для покупки и управления VPS.
  • Иметь технические навыки и средства для покупки и управления доменными именами.
  • Уметь получать TLS-сертификаты.
  • И многое другое.

Всё это превратило некогда простую задачу в пугающее испытание для новичков.

Во-вторых, о проблемах новичков.

Начинающим пользователям без технического бэкграунда, чтобы разобраться во всех этих премудростях, приходится изучать огромные массивы информации, разбросанной по всему интернету: блогам, форумам, группам в мессенджерах, репозиториям на GitHub, видео на YouTube и так далее.

Вся эта информация часто оказывается противоречивой, неполной или попросту неверной. Новичкам остаётся только гадать, кому верить и как всё это работает на самом деле.

В итоге вместо нехватки информации новички сталкиваются с её избытком. После нескольких (скорее всего, неудачных) попыток разобраться во всём этом, их энтузиазм угасает. А если по пути им ещё и «посчастливится» обратиться за помощью не в то место, их могут ещё и высмеять: «Ну ты и нуб, проще уж платным VPN пользоваться, зачем изобретать велосипед?» или «Сначала Linux изучи, потом приходи».

В такие моменты остаётся только горько усмехнуться.

1.5 «Почему бы просто не пользоваться платным VPN?»

Во-первых, я хотел бы спросить у любителей подобных советов: разве платные VPN — это панацея?

Во-вторых, я считаю, что «не знать» и «не хотеть знать» — это две большие разницы. Конечно, инфантилы, которые хотят всё и сразу, не прилагая никаких усилий, вызывают только раздражение. Но люди, которые искренне хотят разобраться во всём сами, не заслуживают презрения и издёвок. Именно эта нетерпимость к новичкам и побудила меня написать эту статью.

Давайте разберёмся, в чём плюсы и минусы платных VPN-сервисов.

Плюсы:

  1. Простота использования: сканирование QR-кода, добавление правил в один клик и т.д.
  2. Большой выбор серверов: доступ к ресурсам разных стран и регионов; например, выделенные серверы с низкой задержкой (iplc), серверы для онлайн-игр и т.д.
  3. Множество точек подключения: выше устойчивость к блокировкам, если один сервер заблокируют, можно подключиться к другому.

Риски:

За удобство приходится платить, и в случае с платными VPN-сервисами риски следующие:

  1. VPN-провайдер имеет полный доступ к вашим данным: всё, что вы делаете в интернете, обязательно проходит и с большой вероятностью хранится на серверах провайдера. Эти данные никак не защищены пользовательским соглашением или законом о защите персональных данных (вас могут отслеживать и записывать всё, что вы делаете).
  2. Отсутствие регулирования рынка: высока вероятность нарваться на мошенников (провайдер может в любой момент исчезнуть с вашими деньгами).
  3. Давление со стороны регулирующих органов: крупные VPN-провайдеры, с одной стороны, кажутся более надёжными, но, с другой стороны, чаще привлекают к себе внимание властей. В 2020 году было несколько случаев закрытия и прекращения работы крупных VPN-провайдеров, что привело к серьёзным неудобствам для пользователей (провайдер может быть вынужден прекратить работу).
  4. Непрозрачность технических решений: качество предоставляемых услуг может сильно варьироваться, не редки случаи обмана (низкая скорость, частые обрывы связи, невозможность подключения).

1.6 Так стоит ли настраивать VPN самостоятельно?

Теперь, когда вы знаете о плюсах и минусах платных VPN, решать вам. В конце концов, лучший вариант — тот, который подходит именно вам.

Выбор за вами!

  1. Если вы решили воспользоваться платным VPN, можете закрыть эту статью.

  2. Если же вы решили настроить всё самостоятельно, продолжайте чтение!

Цель этой статьи — стать отправной точкой для новичков, предоставить подробное пошаговое руководство по настройке VPN-сервера на VPS, начиная с ввода первой команды и заканчивая успешным подключением к заблокированным ресурсам.

В процессе настройки вы познакомитесь с основными командами Linux, что станет хорошей базой для дальнейшего изучения этой операционной системы.

1.7 Немного лирики

  1. В интернете много дезинформации, поэтому важно научиться критически мыслить, не поддаваться на провокации и не верить всему, что пишут.
  2. Искренне надеюсь, что, получив доступ к свободному интернету, вы сможете узнавать больше нового, наслаждаться разнообразным контентом, знакомиться с интересными людьми и находить единомышленников.
  3. Ваша личность в интернете — это всё ещё вы. Добиться полной анонимности крайне сложно, поэтому не забывайте о законах вашей страны и стран, IP-адреса которых вы используете. Всегда помните о собственной безопасности.

1.8 Ваш прогресс

⬛⬜⬜⬜⬜⬜⬜⬜ 12.5%

',42);function h(c,g){const n=o("I18nTip");return p(),a("div",null,[r(n),l])}const _=s(i,[["render",h],["__file","ch01-preface.html.vue"]]);export{_ as default}; +import{_ as s,r as o,o as p,c as a,a as r,e as t}from"./app-D7uBbsY3.js";const e="/assets/ch01-img01-choice-B3FXW047.png",i={},l=t('

【Глава 1】 Простыми словами

1.1 Для кого эта документация?

В двух словах: для ① новичков без опыта ② желающих научиться настраивать свой собственный VPS.

1.2 Для кого эта документация не предназначена?

В том числе, но не ограничиваясь: для всевозможных гуру и экспертов, для тех, кто слишком ленив, чтобы во всём разбираться самостоятельно, для тех, кто уже умеет настраивать VPS, для тех, кто точно решил пользоваться платными VPN-сервисами, для тех, кто предпочитает использовать готовые скрипты... Короче говоря, если у вас есть технические знания или вы не хотите настраивать всё сами, можете смело закрывать эту статью. Скорее всего, она покажется вам бесполезной и даже может вызвать раздражение, а оно вам надо?

1.3 Важное замечание и другие примечания

Важное замечание:

Я не являюсь техническим экспертом, поэтому в этой статье неизбежны пробелы и неточности. Если вы обнаружите какие-либо ошибки, пожалуйста, дайте мне знать об этом деликатно, без лишних эмоций.

Отказ от ответственности:

Пожалуйста, относитесь к информации, представленной в этой статье, критически и проверяйте её самостоятельно. Я не несу никакой ответственности за любые проблемы или негативные последствия, возникшие в результате использования информации из этой статьи.

Предупреждение о многословности:

Поскольку эта статья предназначена для новичков без опыта, многие вещи будут объяснены максимально подробно. Поэтому будьте готовы к тому, что текст будет довольно многословным.

1.4 Почему самостоятельная настройка — это сложно?

Чтобы ответить на этот вопрос, нужно немного углубиться в историю вопроса.

Во-первых, обход блокировок существует уже почти двадцать лет (Шок! Ужас!). Сначала для этого достаточно было пары манипуляций (поправить файл hosts, подключиться по SSH), потом понадобились веб-прокси, затем — собственные протоколы (например, Shadowsocks) и так далее.

По мере того, как технологии блокировок совершенствовались на протяжении последних десятилетий, для самостоятельного обхода блокировок теперь нужно уметь:

  • Разбираться в основных командах Linux.
  • Понимать принципы работы сетевых протоколов.
  • Иметь технические навыки и средства для покупки и управления VPS.
  • Иметь технические навыки и средства для покупки и управления доменными именами.
  • Уметь получать TLS-сертификаты.
  • И многое другое.

Всё это превратило некогда простую задачу в пугающее испытание для новичков.

Во-вторых, о проблемах новичков.

Начинающим пользователям без технического бэкграунда, чтобы разобраться во всех этих премудростях, приходится изучать огромные массивы информации, разбросанной по всему интернету: блогам, форумам, группам в мессенджерах, репозиториям на GitHub, видео на YouTube и так далее.

Вся эта информация часто оказывается противоречивой, неполной или попросту неверной. Новичкам остаётся только гадать, кому верить и как всё это работает на самом деле.

В итоге вместо нехватки информации новички сталкиваются с её избытком. После нескольких (скорее всего, неудачных) попыток разобраться во всём этом, их энтузиазм угасает. А если по пути им ещё и «посчастливится» обратиться за помощью не в то место, их могут ещё и высмеять: «Ну ты и нуб, проще уж платным VPN пользоваться, зачем изобретать велосипед?» или «Сначала Linux изучи, потом приходи».

В такие моменты остаётся только горько усмехнуться.

1.5 «Почему бы просто не пользоваться платным VPN?»

Во-первых, я хотел бы спросить у любителей подобных советов: разве платные VPN — это панацея?

Во-вторых, я считаю, что «не знать» и «не хотеть знать» — это две большие разницы. Конечно, инфантилы, которые хотят всё и сразу, не прилагая никаких усилий, вызывают только раздражение. Но люди, которые искренне хотят разобраться во всём сами, не заслуживают презрения и издёвок. Именно эта нетерпимость к новичкам и побудила меня написать эту статью.

Давайте разберёмся, в чём плюсы и минусы платных VPN-сервисов.

Плюсы:

  1. Простота использования: сканирование QR-кода, добавление правил в один клик и т.д.
  2. Большой выбор серверов: доступ к ресурсам разных стран и регионов; например, выделенные серверы с низкой задержкой (iplc), серверы для онлайн-игр и т.д.
  3. Множество точек подключения: выше устойчивость к блокировкам, если один сервер заблокируют, можно подключиться к другому.

Риски:

За удобство приходится платить, и в случае с платными VPN-сервисами риски следующие:

  1. VPN-провайдер имеет полный доступ к вашим данным: всё, что вы делаете в интернете, обязательно проходит и с большой вероятностью хранится на серверах провайдера. Эти данные никак не защищены пользовательским соглашением или законом о защите персональных данных (вас могут отслеживать и записывать всё, что вы делаете).
  2. Отсутствие регулирования рынка: высока вероятность нарваться на мошенников (провайдер может в любой момент исчезнуть с вашими деньгами).
  3. Давление со стороны регулирующих органов: крупные VPN-провайдеры, с одной стороны, кажутся более надёжными, но, с другой стороны, чаще привлекают к себе внимание властей. В 2020 году было несколько случаев закрытия и прекращения работы крупных VPN-провайдеров, что привело к серьёзным неудобствам для пользователей (провайдер может быть вынужден прекратить работу).
  4. Непрозрачность технических решений: качество предоставляемых услуг может сильно варьироваться, не редки случаи обмана (низкая скорость, частые обрывы связи, невозможность подключения).

1.6 Так стоит ли настраивать VPN самостоятельно?

Теперь, когда вы знаете о плюсах и минусах платных VPN, решать вам. В конце концов, лучший вариант — тот, который подходит именно вам.

Выбор за вами!

  1. Если вы решили воспользоваться платным VPN, можете закрыть эту статью.

  2. Если же вы решили настроить всё самостоятельно, продолжайте чтение!

Цель этой статьи — стать отправной точкой для новичков, предоставить подробное пошаговое руководство по настройке VPN-сервера на VPS, начиная с ввода первой команды и заканчивая успешным подключением к заблокированным ресурсам.

В процессе настройки вы познакомитесь с основными командами Linux, что станет хорошей базой для дальнейшего изучения этой операционной системы.

1.7 Немного лирики

  1. В интернете много дезинформации, поэтому важно научиться критически мыслить, не поддаваться на провокации и не верить всему, что пишут.
  2. Искренне надеюсь, что, получив доступ к свободному интернету, вы сможете узнавать больше нового, наслаждаться разнообразным контентом, знакомиться с интересными людьми и находить единомышленников.
  3. Ваша личность в интернете — это всё ещё вы. Добиться полной анонимности крайне сложно, поэтому не забывайте о законах вашей страны и стран, IP-адреса которых вы используете. Всегда помните о собственной безопасности.

1.8 Ваш прогресс

⬛⬜⬜⬜⬜⬜⬜⬜ 12.5%

',42);function h(c,g){const n=o("I18nTip");return p(),a("div",null,[r(n),l])}const _=s(i,[["render",h],["__file","ch01-preface.html.vue"]]);export{_ as default}; diff --git a/assets/ch01-preface.html-CFrG0T3Z.js b/assets/ch01-preface.html-DOL1zdys.js similarity index 99% rename from assets/ch01-preface.html-CFrG0T3Z.js rename to assets/ch01-preface.html-DOL1zdys.js index a1ebefd4be..a0be2c075b 100644 --- a/assets/ch01-preface.html-CFrG0T3Z.js +++ b/assets/ch01-preface.html-DOL1zdys.js @@ -1 +1 @@ -import{_ as t,r as o,o as i,c as n,a,e as s}from"./app-DBM4OJyw.js";const r="/assets/ch01-img01-choice-B3FXW047.png",l={},h=s('

[Chapter 1] Simple and Plain Language

1.1 Who is this document written for?

One sentence: Written for newbies who are (1) absolute beginners and (2) interested in learning how to build their own VPS.

1.2 Who is this document not written for?

Including but not limited to: experts and professionals, beginners who are too lazy to tinker on their own, advanced users who already know how to tinker, wealthy users who insist on using airport services, and those who prefer using one-click scripts. In short, if you have a technical background or don't want to build it yourself, you can close this article directly, because this article may not be suitable for you and may even make you upset.

1.3 Declaration and Other Statements

Declaration:

My technical skills are extremely limited, so this article is inevitably full of errors and flaws. If you find any problems, please kindly point them out and don't be too harsh on me.

Disclaimer:

Please judge the reliability and usability of the content of this article by yourself. If you encounter any problems or negative results when establishing and using a VPS server based on the content of this article, I am not responsible for it.

Verbose statement:

Considering the target audience of this article, which is "users with zero experience", many details will be explained in great detail, so the language may be verbose. Please be mentally prepared for this.

1.4 Why is self-hosting a challenge?

To answer this question, we need to provide a little more background information.

  1. On the matter of accessing the internet through scientific means

The act of accessing the internet using scientific methods has been around for almost 20 years (shocking!!!.jpg). Initially, one could do it with a little effort (changing the host file, using SSH), then one had to find a web proxy, and later, one had to develop a private protocol (such as Shadowsocks) and so on.

With the continuous iteration and upgrade of GFW technology over the past decade, to achieve the goal of [building your own scientific Internet access], the things that need to be done include but are not limited to:

  • Understand basic Linux commands
  • Understand network transmission protocols
  • Have the technical and financial ability to purchase and manage a VPS
  • Have the technical and financial ability to purchase and manage a domain name
  • Have the technical ability to apply for a TLS certificate, and so on.

This has turned the once simple act of [setting up a self-built VPS for accessing the internet in a secure and unrestricted manner] into a daunting challenge that intimidates newcomers.

  1. Helplessness of Zero-based Users

For non-technical users with zero foundation, if they complete the above series of operations, they will inevitably need to learn a lot of knowledge. However, after a little searching, newbies are likely to become even more confused: a large amount of information is scattered in various corners of the Internet: blogs, Q&A sites, groups, forums, GitHub, Telegram, YouTube, and so on. These pieces of information are chaotic and complex, with varying levels of quality, and may even contradict each other. Basically, they won't stop until they completely confuse the newcomer.

Faced with such chaotic information, newcomers suddenly shift from [information scarcity] to [information overload]. If they fail after several attempts of groping and guessing (which is highly probable), their enthusiasm is bound to be greatly frustrated. In this process, if they happen to seek help in some unfriendly places, they may be ridiculed even more: "You're so inexperienced, just use the airport, why bother messing around!" "Go learn Linux first before coming back to ask."

At this moment, probably only an "hehe" can express the mood.

1.5 "Why not just use the airport?"

First of all, I would like to respond to those who ridicule and criticize by asking a question: Is using the airport really a panacea?

Secondly, I believe that there is a fundamental difference between "not understanding" and "not wanting to understand". The bad attitude of some people who just want handouts is naturally annoying, but those who sincerely want to learn but don't know how should not be subject to unjustified contempt and discrimination. It is precisely this kind of bad community atmosphere that does not distinguish between newcomers that prompted me to write this article. So without further ado, let's take a look at the advantages and disadvantages of the airport:

  1. 稳定性高:机场节点数量多,分布广泛,避免了单点故障的风险,保证了整个网络的稳定性。
  2. 速度快:机场的节点通常采用高速服务器和优化的网络架构,网络速度较快,能够满足用户的高速上网需求。
  3. 安全性高:机场通常会采用严格的安全措施,如流量加密、防火墙等,保护用户数据的安全性。
  4. 稳定性高:机场通常采用专业的运维团队进行管理和维护,保证了服务的稳定性和可靠性。
  5. 服务质量高:机场通常会提供完善的客户服务,及时解决用户的问题和反馈,提升用户的满意度。

The so-called "airport" refers to the "line provider". They are responsible for completing the technical operations and management mentioned in section 1.4, while users pay for the right to use the service. Therefore, its advantages include at least:

  1. Simple User Operation: Scan code operation, one-click rule addition, etc.
  2. Multiple Line Options: Can unlock network services in different countries and regions, such as iplc dedicated line services, game acceleration services, etc.
  3. Multiple Access Nodes: Therefore, it has a stronger ability to resist node blocking, if one is blocked, just switch to another one.
  • Risks of "Airport"

"The other side of the coin of 'convenience' is 'risk'. Based on the technical characteristics and market conditions of the 'airport', its risks include at least:"

  1. "Airport" can fully obtain user information: All the traces left by users online will inevitably and very likely be stored on their servers for a long time. These records cannot be restricted by any legally binding user privacy agreement. ("Snooping and recording your every move")
  2. "Airport" lacks market management: There are inevitably malicious merchants who target fraud. ("Actively run away")
  3. "Airport" faces regulatory pressure: While large airports are relatively secure, they cannot avoid attracting attention. In 2020, several large airports experienced shutdowns and runaways, seriously disrupting users' normal usage. ("Passively run away")
  4. "Airport" technical level is difficult to determine: The quality of the line varies greatly, and the phenomenon of falsely advertising quality services is common. ("Slow speed, frequent disconnections, unable to connect")

1.6 So should you build your own website?

Now that you have seen the advantages and risks of the airport, please think carefully and make your own decision on what to use. After all, the best plan is the one that suits you best.

It's Your Choice!

  1. If you decide to use the airport, you can close this article now.

  2. If you decide to build it yourself, please continue reading the following chapters!

In short, the goal of this article is to serve as a starting point for users with zero experience, providing thorough explanations and demonstrations for each step, even if it may seem overly detailed or repetitive. The aim is to assist beginners in completing the entire process of deploying a VPS server from the first command input to successfully accessing the internet via the client, and gradually introducing them to basic Linux operations, laying a foundation for further self-learning.

1.7 Some digressions

  1. There is a wealth of information outside of the wall, so please learn to think rationally and independently. Don't take sides easily and don't believe in sensational information.

  2. We sincerely hope that with a smoother internet, everyone can access fresher knowledge, richer entertainment, experience a better world, and make more like-minded friends, but do not become a scapegoat for anyone with ulterior motives.

  3. Your internet identity is still your identity, and achieving absolute anonymity is extremely difficult. Therefore, please be sure to comply with the relevant laws and regulations in your personal location and the location of your IP address. Self-protection is always the most basic bottom line.

1.8 Your Progress

⬛⬜⬜⬜⬜⬜⬜⬜ 12.5%

',41);function c(d,u){const e=o("I18nTip");return i(),n("div",null,[a(e),h])}const f=t(l,[["render",c],["__file","ch01-preface.html.vue"]]);export{f as default}; +import{_ as t,r as o,o as i,c as n,a,e as s}from"./app-D7uBbsY3.js";const r="/assets/ch01-img01-choice-B3FXW047.png",l={},h=s('

[Chapter 1] Simple and Plain Language

1.1 Who is this document written for?

One sentence: Written for newbies who are (1) absolute beginners and (2) interested in learning how to build their own VPS.

1.2 Who is this document not written for?

Including but not limited to: experts and professionals, beginners who are too lazy to tinker on their own, advanced users who already know how to tinker, wealthy users who insist on using airport services, and those who prefer using one-click scripts. In short, if you have a technical background or don't want to build it yourself, you can close this article directly, because this article may not be suitable for you and may even make you upset.

1.3 Declaration and Other Statements

Declaration:

My technical skills are extremely limited, so this article is inevitably full of errors and flaws. If you find any problems, please kindly point them out and don't be too harsh on me.

Disclaimer:

Please judge the reliability and usability of the content of this article by yourself. If you encounter any problems or negative results when establishing and using a VPS server based on the content of this article, I am not responsible for it.

Verbose statement:

Considering the target audience of this article, which is "users with zero experience", many details will be explained in great detail, so the language may be verbose. Please be mentally prepared for this.

1.4 Why is self-hosting a challenge?

To answer this question, we need to provide a little more background information.

  1. On the matter of accessing the internet through scientific means

The act of accessing the internet using scientific methods has been around for almost 20 years (shocking!!!.jpg). Initially, one could do it with a little effort (changing the host file, using SSH), then one had to find a web proxy, and later, one had to develop a private protocol (such as Shadowsocks) and so on.

With the continuous iteration and upgrade of GFW technology over the past decade, to achieve the goal of [building your own scientific Internet access], the things that need to be done include but are not limited to:

  • Understand basic Linux commands
  • Understand network transmission protocols
  • Have the technical and financial ability to purchase and manage a VPS
  • Have the technical and financial ability to purchase and manage a domain name
  • Have the technical ability to apply for a TLS certificate, and so on.

This has turned the once simple act of [setting up a self-built VPS for accessing the internet in a secure and unrestricted manner] into a daunting challenge that intimidates newcomers.

  1. Helplessness of Zero-based Users

For non-technical users with zero foundation, if they complete the above series of operations, they will inevitably need to learn a lot of knowledge. However, after a little searching, newbies are likely to become even more confused: a large amount of information is scattered in various corners of the Internet: blogs, Q&A sites, groups, forums, GitHub, Telegram, YouTube, and so on. These pieces of information are chaotic and complex, with varying levels of quality, and may even contradict each other. Basically, they won't stop until they completely confuse the newcomer.

Faced with such chaotic information, newcomers suddenly shift from [information scarcity] to [information overload]. If they fail after several attempts of groping and guessing (which is highly probable), their enthusiasm is bound to be greatly frustrated. In this process, if they happen to seek help in some unfriendly places, they may be ridiculed even more: "You're so inexperienced, just use the airport, why bother messing around!" "Go learn Linux first before coming back to ask."

At this moment, probably only an "hehe" can express the mood.

1.5 "Why not just use the airport?"

First of all, I would like to respond to those who ridicule and criticize by asking a question: Is using the airport really a panacea?

Secondly, I believe that there is a fundamental difference between "not understanding" and "not wanting to understand". The bad attitude of some people who just want handouts is naturally annoying, but those who sincerely want to learn but don't know how should not be subject to unjustified contempt and discrimination. It is precisely this kind of bad community atmosphere that does not distinguish between newcomers that prompted me to write this article. So without further ado, let's take a look at the advantages and disadvantages of the airport:

  1. 稳定性高:机场节点数量多,分布广泛,避免了单点故障的风险,保证了整个网络的稳定性。
  2. 速度快:机场的节点通常采用高速服务器和优化的网络架构,网络速度较快,能够满足用户的高速上网需求。
  3. 安全性高:机场通常会采用严格的安全措施,如流量加密、防火墙等,保护用户数据的安全性。
  4. 稳定性高:机场通常采用专业的运维团队进行管理和维护,保证了服务的稳定性和可靠性。
  5. 服务质量高:机场通常会提供完善的客户服务,及时解决用户的问题和反馈,提升用户的满意度。

The so-called "airport" refers to the "line provider". They are responsible for completing the technical operations and management mentioned in section 1.4, while users pay for the right to use the service. Therefore, its advantages include at least:

  1. Simple User Operation: Scan code operation, one-click rule addition, etc.
  2. Multiple Line Options: Can unlock network services in different countries and regions, such as iplc dedicated line services, game acceleration services, etc.
  3. Multiple Access Nodes: Therefore, it has a stronger ability to resist node blocking, if one is blocked, just switch to another one.
  • Risks of "Airport"

"The other side of the coin of 'convenience' is 'risk'. Based on the technical characteristics and market conditions of the 'airport', its risks include at least:"

  1. "Airport" can fully obtain user information: All the traces left by users online will inevitably and very likely be stored on their servers for a long time. These records cannot be restricted by any legally binding user privacy agreement. ("Snooping and recording your every move")
  2. "Airport" lacks market management: There are inevitably malicious merchants who target fraud. ("Actively run away")
  3. "Airport" faces regulatory pressure: While large airports are relatively secure, they cannot avoid attracting attention. In 2020, several large airports experienced shutdowns and runaways, seriously disrupting users' normal usage. ("Passively run away")
  4. "Airport" technical level is difficult to determine: The quality of the line varies greatly, and the phenomenon of falsely advertising quality services is common. ("Slow speed, frequent disconnections, unable to connect")

1.6 So should you build your own website?

Now that you have seen the advantages and risks of the airport, please think carefully and make your own decision on what to use. After all, the best plan is the one that suits you best.

It's Your Choice!

  1. If you decide to use the airport, you can close this article now.

  2. If you decide to build it yourself, please continue reading the following chapters!

In short, the goal of this article is to serve as a starting point for users with zero experience, providing thorough explanations and demonstrations for each step, even if it may seem overly detailed or repetitive. The aim is to assist beginners in completing the entire process of deploying a VPS server from the first command input to successfully accessing the internet via the client, and gradually introducing them to basic Linux operations, laying a foundation for further self-learning.

1.7 Some digressions

  1. There is a wealth of information outside of the wall, so please learn to think rationally and independently. Don't take sides easily and don't believe in sensational information.

  2. We sincerely hope that with a smoother internet, everyone can access fresher knowledge, richer entertainment, experience a better world, and make more like-minded friends, but do not become a scapegoat for anyone with ulterior motives.

  3. Your internet identity is still your identity, and achieving absolute anonymity is extremely difficult. Therefore, please be sure to comply with the relevant laws and regulations in your personal location and the location of your IP address. Self-protection is always the most basic bottom line.

1.8 Your Progress

⬛⬜⬜⬜⬜⬜⬜⬜ 12.5%

',41);function c(d,u){const e=o("I18nTip");return i(),n("div",null,[a(e),h])}const f=t(l,[["render",c],["__file","ch01-preface.html.vue"]]);export{f as default}; diff --git a/assets/ch02-preparation.html-DaAKcAJL.js b/assets/ch02-preparation.html-CBvgJlzh.js similarity index 99% rename from assets/ch02-preparation.html-DaAKcAJL.js rename to assets/ch02-preparation.html-CBvgJlzh.js index d7a63d0f87..35ecfb28bf 100644 --- a/assets/ch02-preparation.html-DaAKcAJL.js +++ b/assets/ch02-preparation.html-CBvgJlzh.js @@ -1 +1 @@ -import{_ as s,r as l,o as i,c,a as o,b as n,d as e,e as r}from"./app-DBM4OJyw.js";const p="/assets/ch02-img01-a-name-DXHjY1Jd.png",d={},u=r('

【Глава 2】 Подготовка

Эта глава особенная, поскольку затрагивает финансовые операции. В соответствии с нейтральной позицией проекта, здесь не будет конкретных рекомендаций. Всё, что я могу сделать, — это рассказать, что вам понадобится.

2.1 Приобретение VPS

Вам нужно получить работающий VPS с не заблокированным IP-адресом и выполнить следующие базовые действия в панели управления:

  1. Установить на VPS операционную систему Debian 10 64-bit.
  2. Записать IP-адрес VPS (в этой статье он будет обозначаться как "100.200.300.400").

    Подсказка

    Это неверный IP-адрес, используемый только в качестве примера. Не забудьте заменить его на свой реальный IP-адрес.

  3. Записать порт (Port) SSH для удалённого подключения к VPS.
  4. Записать имя пользователя и пароль для удалённого подключения по SSH.

Выбор и покупка VPS — дело непростое. Рекомендуем сначала изучить этот вопрос и выбрать тариф, который соответствует вашим финансовым возможностям и требованиям к скорости и качеству связи. Также можно воспользоваться бесплатными (постоянными или временными) предложениями от крупных облачных провайдеров, таких как Oracle Cloud и Google Cloud. Главное — не влезайте в долги.

Пояснение

Несколько слов о выборе Debian 10 в качестве операционной системы. Что бы вы ни слышали в интернете, какой бы дистрибутив Linux ни советовали вам гуру, все эти споры о том, какой Linux лучше, не имеют к вам никакого отношения! Debian 10 — это надёжная и стабильная операционная система, которая отлично подходит для работы VPN-сервера и достаточно оптимизирована (например, имеет специальное ядро для облачных сред и своевременную поддержку BBR). Когда вы освоитесь с Linux, можете попробовать и другие дистрибутивы.

2.2 Выбор доменного имени

Вам нужно получить доменное имя и добавить A-запись, указывающую на IP-адрес вашего VPS, в настройках DNS.

  1. Выберите надёжного международного регистратора доменных имён. Доменная зона (расширение домена) может быть любой, главное — не используйте .cn.
  2. В настройках DNS добавьте A-запись, указывающую на IP-адрес вашего VPS (имя A-записи может быть любым, в этой статье оно будет обозначаться как "a-name". Полное доменное имя будет выглядеть как "a-name.yourdomain.com"). Должно получиться примерно так:

Добавление A-записи

Подсказка

Это не настоящий URL-адрес. Не забудьте заменить его на свой реальный адрес.

2.3 Необходимое программное обеспечение

',13),_=n("p",null,"SSH-клиент для удалённого подключения:",-1),h={href:"https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html",target:"_blank",rel:"noopener noreferrer"},m=n("li",null,"macOS/Linux: Terminal",-1),S=n("p",null,"Программа для передачи файлов:",-1),P={href:"https://winscp.net/eng/index.php",target:"_blank",rel:"noopener noreferrer"},f=n("li",null,"macOS/Linux: Terminal",-1),x=n("p",null,"Хороший текстовый редактор:",-1),g={href:"https://code.visualstudio.com",target:"_blank",rel:"noopener noreferrer"},b=n("h2",{id:"_2-4-ваш-прогресс",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#_2-4-ваш-прогресс"},[n("span",null,"2.4 Ваш прогресс")])],-1),V=n("p",null,"Если вы выполнили все пункты из этого раздела, у вас уже есть всё необходимое, чтобы открыть для себя новый мир. Так чего же мы ждём? Давайте перейдём к следующей главе и сделаем это!",-1),v=n("blockquote",null,[n("p",null,"⬛⬛⬜⬜⬜⬜⬜⬜ 25%")],-1);function k(I,L){const a=l("I18nTip"),t=l("ExternalLinkIcon");return i(),c("div",null,[o(a),u,n("ol",null,[n("li",null,[_,n("ul",null,[n("li",null,[e("Windows: "),n("a",h,[e("PuTTY"),o(t)])]),m])]),n("li",null,[S,n("ul",null,[n("li",null,[e("Windows: "),n("a",P,[e("WinSCP"),o(t)])]),f])]),n("li",null,[x,n("ul",null,[n("li",null,[e("Windows/macOS/Linux: "),n("a",g,[e("VSCode"),o(t)])])])])]),b,V,v])}const w=s(d,[["render",k],["__file","ch02-preparation.html.vue"]]);export{w as default}; +import{_ as s,r as l,o as i,c,a as o,b as n,d as e,e as r}from"./app-D7uBbsY3.js";const p="/assets/ch02-img01-a-name-DXHjY1Jd.png",d={},u=r('

【Глава 2】 Подготовка

Эта глава особенная, поскольку затрагивает финансовые операции. В соответствии с нейтральной позицией проекта, здесь не будет конкретных рекомендаций. Всё, что я могу сделать, — это рассказать, что вам понадобится.

2.1 Приобретение VPS

Вам нужно получить работающий VPS с не заблокированным IP-адресом и выполнить следующие базовые действия в панели управления:

  1. Установить на VPS операционную систему Debian 10 64-bit.
  2. Записать IP-адрес VPS (в этой статье он будет обозначаться как "100.200.300.400").

    Подсказка

    Это неверный IP-адрес, используемый только в качестве примера. Не забудьте заменить его на свой реальный IP-адрес.

  3. Записать порт (Port) SSH для удалённого подключения к VPS.
  4. Записать имя пользователя и пароль для удалённого подключения по SSH.

Выбор и покупка VPS — дело непростое. Рекомендуем сначала изучить этот вопрос и выбрать тариф, который соответствует вашим финансовым возможностям и требованиям к скорости и качеству связи. Также можно воспользоваться бесплатными (постоянными или временными) предложениями от крупных облачных провайдеров, таких как Oracle Cloud и Google Cloud. Главное — не влезайте в долги.

Пояснение

Несколько слов о выборе Debian 10 в качестве операционной системы. Что бы вы ни слышали в интернете, какой бы дистрибутив Linux ни советовали вам гуру, все эти споры о том, какой Linux лучше, не имеют к вам никакого отношения! Debian 10 — это надёжная и стабильная операционная система, которая отлично подходит для работы VPN-сервера и достаточно оптимизирована (например, имеет специальное ядро для облачных сред и своевременную поддержку BBR). Когда вы освоитесь с Linux, можете попробовать и другие дистрибутивы.

2.2 Выбор доменного имени

Вам нужно получить доменное имя и добавить A-запись, указывающую на IP-адрес вашего VPS, в настройках DNS.

  1. Выберите надёжного международного регистратора доменных имён. Доменная зона (расширение домена) может быть любой, главное — не используйте .cn.
  2. В настройках DNS добавьте A-запись, указывающую на IP-адрес вашего VPS (имя A-записи может быть любым, в этой статье оно будет обозначаться как "a-name". Полное доменное имя будет выглядеть как "a-name.yourdomain.com"). Должно получиться примерно так:

Добавление A-записи

Подсказка

Это не настоящий URL-адрес. Не забудьте заменить его на свой реальный адрес.

2.3 Необходимое программное обеспечение

',13),_=n("p",null,"SSH-клиент для удалённого подключения:",-1),h={href:"https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html",target:"_blank",rel:"noopener noreferrer"},m=n("li",null,"macOS/Linux: Terminal",-1),S=n("p",null,"Программа для передачи файлов:",-1),P={href:"https://winscp.net/eng/index.php",target:"_blank",rel:"noopener noreferrer"},f=n("li",null,"macOS/Linux: Terminal",-1),x=n("p",null,"Хороший текстовый редактор:",-1),g={href:"https://code.visualstudio.com",target:"_blank",rel:"noopener noreferrer"},b=n("h2",{id:"_2-4-ваш-прогресс",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#_2-4-ваш-прогресс"},[n("span",null,"2.4 Ваш прогресс")])],-1),V=n("p",null,"Если вы выполнили все пункты из этого раздела, у вас уже есть всё необходимое, чтобы открыть для себя новый мир. Так чего же мы ждём? Давайте перейдём к следующей главе и сделаем это!",-1),v=n("blockquote",null,[n("p",null,"⬛⬛⬜⬜⬜⬜⬜⬜ 25%")],-1);function k(I,L){const a=l("I18nTip"),t=l("ExternalLinkIcon");return i(),c("div",null,[o(a),u,n("ol",null,[n("li",null,[_,n("ul",null,[n("li",null,[e("Windows: "),n("a",h,[e("PuTTY"),o(t)])]),m])]),n("li",null,[S,n("ul",null,[n("li",null,[e("Windows: "),n("a",P,[e("WinSCP"),o(t)])]),f])]),n("li",null,[x,n("ul",null,[n("li",null,[e("Windows/macOS/Linux: "),n("a",g,[e("VSCode"),o(t)])])])])]),b,V,v])}const w=s(d,[["render",k],["__file","ch02-preparation.html.vue"]]);export{w as default}; diff --git a/assets/ch02-preparation.html-B3KTTdXe.js b/assets/ch02-preparation.html-CTibWJno.js similarity index 98% rename from assets/ch02-preparation.html-B3KTTdXe.js rename to assets/ch02-preparation.html-CTibWJno.js index 1679783340..ec7cdea507 100644 --- a/assets/ch02-preparation.html-B3KTTdXe.js +++ b/assets/ch02-preparation.html-CTibWJno.js @@ -1 +1 @@ -import{_ as s,r as a,o as i,c,a as o,b as n,d as e,e as r}from"./app-DBM4OJyw.js";const p="/assets/ch02-img01-a-name-DXHjY1Jd.png",d={},u=r('

【第 2 章】原料准备篇

这一章比较特殊,因为涉及到金钱交易行为,本文基于项目的中立立场,不做具体的推荐。我能做的,是告诉你需要准备哪些东西。

2.1 获取一台 VPS

你需要获取一台健康的、IP 没有被墙的 VPS,并在管理后台做下面这些基础准备:

  1. 在 VPS 的后台安装 Debian 10 64bit 系统
  2. 小本本记下 VPS 的 IP 地址(本文会用 "100.200.300.400" 来表示)

    提示

    这是一个故意写错的非法 IP,请替换成你的真实 IP)

  3. 小本本记下 VPS 的 SSH 远程登陆端口(Port)
  4. 小本本记下 SSH 远程登录的用户名和密码

购买 VPS 是一个比较复杂的事情,建议先去学习一下相关知识,选择适合自己的经济能力和线路需求的即可。另外可以选择薅一些国际大厂的羊毛(比如甲骨文和谷歌提供的永久免费或限时免费的套餐)。总之,务必量力而行。

说明

关于选择 Debian 10 作为操作系统,这里稍微多说一句:不管你在网上听说了什么,不管哪个大神告诉你 XXX 版的 Linux 更好、XXX 版的 Linux 更牛,这些 Linux 的派系之争跟现在的你半毛钱关系也没有!使用 Debian 10 足以让你的 VPS 服务器在安全、稳健运行的同时得到足够的优化(如 cloud 专用内核、及时的 bbr 支持等)。等你对 Linux 熟悉之后,再回头去尝试其他的 Linux 发行版也不迟。

2.2 获取一个心仪的域名

你需要获取一个域名、并在 DNS 设置中添加一条 A 记录,指向你 VPS 的 IP 地址

  1. 请选择靠谱的国际域名服务商。选择一些常见的域名后缀就行,注意不要用 .cn 后缀。
  2. 在 DNS 设置中,添加一条指向你 VPS 的 IP 地址的 A 记录(A 记录的名字可以随便起,本文会用 "a-name" 来表示。完整的域名则会用 "二级域名.你的域名.com" 或者 "a-name.yourdomain.com" 来表示)。效果如下图:

添加A记录

提示

不是一个真实可用的网址,请替换成你的真实网址

2.3 你本地电脑上需要安装的软件

',13),_=n("p",null,"SSH 远程登录工具",-1),h={href:"https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html",target:"_blank",rel:"noopener noreferrer"},m=n("li",null,"macOS/Linux: Terminal",-1),S=n("p",null,"远程文件拷贝工具",-1),x={href:"https://winscp.net/eng/index.php",target:"_blank",rel:"noopener noreferrer"},P=n("li",null,"macOS/Linux: Terminal",-1),f=n("p",null,"靠谱的文本编辑器",-1),b={href:"https://code.visualstudio.com",target:"_blank",rel:"noopener noreferrer"},g=n("h2",{id:"_2-4-你的进度",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#_2-4-你的进度"},[n("span",null,"2.4 你的进度")])],-1),V=n("p",null,"如果上面的原材料你都准备好了的话,你已经拿到了开启新世界大门的钥匙。那还等什么,让我们快点进入下一章,走进这扇门吧!",-1),v=n("blockquote",null,[n("p",null,"⬛⬛⬜⬜⬜⬜⬜⬜ 25%")],-1);function k(I,L){const l=a("I18nTip"),t=a("ExternalLinkIcon");return i(),c("div",null,[o(l),u,n("ol",null,[n("li",null,[_,n("ul",null,[n("li",null,[e("Windows: "),n("a",h,[e("PuTTY"),o(t)])]),m])]),n("li",null,[S,n("ul",null,[n("li",null,[e("Windows: "),n("a",x,[e("WinSCP"),o(t)])]),P])]),n("li",null,[f,n("ul",null,[n("li",null,[e("Windows/macOS/Linux: "),n("a",b,[e("VSCode"),o(t)])])])])]),g,V,v])}const w=s(d,[["render",k],["__file","ch02-preparation.html.vue"]]);export{w as default}; +import{_ as s,r as a,o as i,c,a as o,b as n,d as e,e as r}from"./app-D7uBbsY3.js";const p="/assets/ch02-img01-a-name-DXHjY1Jd.png",d={},u=r('

【第 2 章】原料准备篇

这一章比较特殊,因为涉及到金钱交易行为,本文基于项目的中立立场,不做具体的推荐。我能做的,是告诉你需要准备哪些东西。

2.1 获取一台 VPS

你需要获取一台健康的、IP 没有被墙的 VPS,并在管理后台做下面这些基础准备:

  1. 在 VPS 的后台安装 Debian 10 64bit 系统
  2. 小本本记下 VPS 的 IP 地址(本文会用 "100.200.300.400" 来表示)

    提示

    这是一个故意写错的非法 IP,请替换成你的真实 IP)

  3. 小本本记下 VPS 的 SSH 远程登陆端口(Port)
  4. 小本本记下 SSH 远程登录的用户名和密码

购买 VPS 是一个比较复杂的事情,建议先去学习一下相关知识,选择适合自己的经济能力和线路需求的即可。另外可以选择薅一些国际大厂的羊毛(比如甲骨文和谷歌提供的永久免费或限时免费的套餐)。总之,务必量力而行。

说明

关于选择 Debian 10 作为操作系统,这里稍微多说一句:不管你在网上听说了什么,不管哪个大神告诉你 XXX 版的 Linux 更好、XXX 版的 Linux 更牛,这些 Linux 的派系之争跟现在的你半毛钱关系也没有!使用 Debian 10 足以让你的 VPS 服务器在安全、稳健运行的同时得到足够的优化(如 cloud 专用内核、及时的 bbr 支持等)。等你对 Linux 熟悉之后,再回头去尝试其他的 Linux 发行版也不迟。

2.2 获取一个心仪的域名

你需要获取一个域名、并在 DNS 设置中添加一条 A 记录,指向你 VPS 的 IP 地址

  1. 请选择靠谱的国际域名服务商。选择一些常见的域名后缀就行,注意不要用 .cn 后缀。
  2. 在 DNS 设置中,添加一条指向你 VPS 的 IP 地址的 A 记录(A 记录的名字可以随便起,本文会用 "a-name" 来表示。完整的域名则会用 "二级域名.你的域名.com" 或者 "a-name.yourdomain.com" 来表示)。效果如下图:

添加A记录

提示

不是一个真实可用的网址,请替换成你的真实网址

2.3 你本地电脑上需要安装的软件

',13),_=n("p",null,"SSH 远程登录工具",-1),h={href:"https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html",target:"_blank",rel:"noopener noreferrer"},m=n("li",null,"macOS/Linux: Terminal",-1),S=n("p",null,"远程文件拷贝工具",-1),x={href:"https://winscp.net/eng/index.php",target:"_blank",rel:"noopener noreferrer"},P=n("li",null,"macOS/Linux: Terminal",-1),f=n("p",null,"靠谱的文本编辑器",-1),b={href:"https://code.visualstudio.com",target:"_blank",rel:"noopener noreferrer"},g=n("h2",{id:"_2-4-你的进度",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#_2-4-你的进度"},[n("span",null,"2.4 你的进度")])],-1),V=n("p",null,"如果上面的原材料你都准备好了的话,你已经拿到了开启新世界大门的钥匙。那还等什么,让我们快点进入下一章,走进这扇门吧!",-1),v=n("blockquote",null,[n("p",null,"⬛⬛⬜⬜⬜⬜⬜⬜ 25%")],-1);function k(I,L){const l=a("I18nTip"),t=a("ExternalLinkIcon");return i(),c("div",null,[o(l),u,n("ol",null,[n("li",null,[_,n("ul",null,[n("li",null,[e("Windows: "),n("a",h,[e("PuTTY"),o(t)])]),m])]),n("li",null,[S,n("ul",null,[n("li",null,[e("Windows: "),n("a",x,[e("WinSCP"),o(t)])]),P])]),n("li",null,[f,n("ul",null,[n("li",null,[e("Windows/macOS/Linux: "),n("a",b,[e("VSCode"),o(t)])])])])]),g,V,v])}const w=s(d,[["render",k],["__file","ch02-preparation.html.vue"]]);export{w as default}; diff --git a/assets/ch02-preparation.html-CpQikq-R.js b/assets/ch02-preparation.html-D2OoAhSr.js similarity index 98% rename from assets/ch02-preparation.html-CpQikq-R.js rename to assets/ch02-preparation.html-D2OoAhSr.js index 2944079c5c..4f65269e26 100644 --- a/assets/ch02-preparation.html-CpQikq-R.js +++ b/assets/ch02-preparation.html-D2OoAhSr.js @@ -1 +1 @@ -import{_ as r,r as n,o as s,c as l,a as t,b as e,d as o,e as c}from"./app-DBM4OJyw.js";const d="/assets/ch02-img01-a-name-DXHjY1Jd.png",h={},u=c('

[Chapter 2] Preparation of Raw Materials

This chapter is rather special because it involves monetary transactions. This article takes a neutral stance on the project and does not make specific recommendations. What I can do is to tell you what you need to prepare.

2.1 Acquiring a VPS

You need to obtain a healthy VPS with an unblocked IP, and perform the following basic preparations in the management console:

  1. Install Debian 10 64-bit system in the backend of VPS.
  2. Write down the IP address of VPS in a notebook (this article will use "100.200.300.400" as an example, which is an intentionally incorrect and illegal IP address. Please replace it with your real IP address).
  3. Write down the SSH remote login port of VPS in a notebook.
  4. Write down the username and password for SSH remote login in a notebook.

Buying a VPS is a relatively complex matter. It is recommended to first learn the relevant knowledge and choose one that suits your own economic ability and line requirements. In addition, you can choose to take advantage of some benefits offered by international giants (such as permanent free or limited-time free packages offered by Oracle and Google). In any case, you must act within your means.

Explanation

Regarding the choice of Debian 10 as the operating system, let me elaborate a bit: No matter what you have heard online, no matter which guru has told you that XXX version of Linux is better or XXX version of Linux is more powerful, these sectarian disputes have nothing to do with you right now! Using Debian 10 is enough to optimize your VPS server for security, stability, and performance (such as using cloud-optimized kernel, timely support of BBR, etc.). After you become familiar with Linux, you can try other Linux distributions.

2.2 Obtaining a Desired Domain Name

You need to obtain a domain name and add an A record in the DNS settings, pointing to the IP address of your VPS.

  1. Please choose a reliable international domain name service provider. Choose some common domain name suffixes, and make sure not to use the .cn suffix.
  2. In the DNS settings, add an A record pointing to the IP address of your VPS (the name of the A record can be anything, and in this article, it will be represented by "a-name"). The complete domain name will be represented by "subdomain.yourdomain.com" or "a-name.yourdomain.com". The effect is as shown in the picture below:

Add A Record

Tip

This is not a real usable website. Please replace it with your real website URL.

2.3 Software you need to install on your local computer

  1. SSH remote login tool
',14),p={href:"https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html",target:"_blank",rel:"noopener noreferrer"},m=e("ul",null,[e("li",null,"macOS/Linux: Terminal")],-1),f=e("ol",{start:"2"},[e("li",null,"Remote file copying tool")],-1),g={href:"https://winscp.net/eng/index.php",target:"_blank",rel:"noopener noreferrer"},y=e("ul",null,[e("li",null,"macOS/Linux: Terminal")],-1),_={start:"3"},b={href:"https://code.visualstudio.com",target:"_blank",rel:"noopener noreferrer"},w=e("h2",{id:"_2-4-your-progress",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2-4-your-progress"},[e("span",null,"2.4 Your Progress")])],-1),v=e("p",null,"If you have all the raw materials ready as mentioned above, you have already obtained the key to unlocking the door to a new world. So, what are you waiting for? Let's quickly move on to the next chapter and step through this door!",-1),x=e("blockquote",null,[e("p",null,"⬛⬛⬜⬜⬜⬜⬜⬜ 25%")],-1);function k(S,P){const i=n("I18nTip"),a=n("ExternalLinkIcon");return s(),l("div",null,[t(i),u,e("ul",null,[e("li",null,[o("Windows: "),e("a",p,[o("PuTTY"),t(a)]),m])]),f,e("ul",null,[e("li",null,[o("Windows: "),e("a",g,[o("WinSCP"),t(a)]),y])]),e("ol",_,[e("li",null,[o("Reliable text editor "),e("ul",null,[e("li",null,[o("Windows/macOS/Linux: "),e("a",b,[o("VSCode"),t(a)])])])])]),w,v,x])}const q=r(h,[["render",k],["__file","ch02-preparation.html.vue"]]);export{q as default}; +import{_ as r,r as n,o as s,c as l,a as t,b as e,d as o,e as c}from"./app-D7uBbsY3.js";const d="/assets/ch02-img01-a-name-DXHjY1Jd.png",h={},u=c('

[Chapter 2] Preparation of Raw Materials

This chapter is rather special because it involves monetary transactions. This article takes a neutral stance on the project and does not make specific recommendations. What I can do is to tell you what you need to prepare.

2.1 Acquiring a VPS

You need to obtain a healthy VPS with an unblocked IP, and perform the following basic preparations in the management console:

  1. Install Debian 10 64-bit system in the backend of VPS.
  2. Write down the IP address of VPS in a notebook (this article will use "100.200.300.400" as an example, which is an intentionally incorrect and illegal IP address. Please replace it with your real IP address).
  3. Write down the SSH remote login port of VPS in a notebook.
  4. Write down the username and password for SSH remote login in a notebook.

Buying a VPS is a relatively complex matter. It is recommended to first learn the relevant knowledge and choose one that suits your own economic ability and line requirements. In addition, you can choose to take advantage of some benefits offered by international giants (such as permanent free or limited-time free packages offered by Oracle and Google). In any case, you must act within your means.

Explanation

Regarding the choice of Debian 10 as the operating system, let me elaborate a bit: No matter what you have heard online, no matter which guru has told you that XXX version of Linux is better or XXX version of Linux is more powerful, these sectarian disputes have nothing to do with you right now! Using Debian 10 is enough to optimize your VPS server for security, stability, and performance (such as using cloud-optimized kernel, timely support of BBR, etc.). After you become familiar with Linux, you can try other Linux distributions.

2.2 Obtaining a Desired Domain Name

You need to obtain a domain name and add an A record in the DNS settings, pointing to the IP address of your VPS.

  1. Please choose a reliable international domain name service provider. Choose some common domain name suffixes, and make sure not to use the .cn suffix.
  2. In the DNS settings, add an A record pointing to the IP address of your VPS (the name of the A record can be anything, and in this article, it will be represented by "a-name"). The complete domain name will be represented by "subdomain.yourdomain.com" or "a-name.yourdomain.com". The effect is as shown in the picture below:

Add A Record

Tip

This is not a real usable website. Please replace it with your real website URL.

2.3 Software you need to install on your local computer

  1. SSH remote login tool
',14),p={href:"https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html",target:"_blank",rel:"noopener noreferrer"},m=e("ul",null,[e("li",null,"macOS/Linux: Terminal")],-1),f=e("ol",{start:"2"},[e("li",null,"Remote file copying tool")],-1),g={href:"https://winscp.net/eng/index.php",target:"_blank",rel:"noopener noreferrer"},y=e("ul",null,[e("li",null,"macOS/Linux: Terminal")],-1),_={start:"3"},b={href:"https://code.visualstudio.com",target:"_blank",rel:"noopener noreferrer"},w=e("h2",{id:"_2-4-your-progress",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2-4-your-progress"},[e("span",null,"2.4 Your Progress")])],-1),v=e("p",null,"If you have all the raw materials ready as mentioned above, you have already obtained the key to unlocking the door to a new world. So, what are you waiting for? Let's quickly move on to the next chapter and step through this door!",-1),x=e("blockquote",null,[e("p",null,"⬛⬛⬜⬜⬜⬜⬜⬜ 25%")],-1);function k(S,P){const i=n("I18nTip"),a=n("ExternalLinkIcon");return s(),l("div",null,[t(i),u,e("ul",null,[e("li",null,[o("Windows: "),e("a",p,[o("PuTTY"),t(a)]),m])]),f,e("ul",null,[e("li",null,[o("Windows: "),e("a",g,[o("WinSCP"),t(a)]),y])]),e("ol",_,[e("li",null,[o("Reliable text editor "),e("ul",null,[e("li",null,[o("Windows/macOS/Linux: "),e("a",b,[o("VSCode"),t(a)])])])])]),w,v,x])}const q=r(h,[["render",k],["__file","ch02-preparation.html.vue"]]);export{q as default}; diff --git a/assets/ch03-ssh.html-D4Fp2rOo.js b/assets/ch03-ssh.html-ChZfg0hU.js similarity index 99% rename from assets/ch03-ssh.html-D4Fp2rOo.js rename to assets/ch03-ssh.html-ChZfg0hU.js index dae10f407e..ddee5bc1da 100644 --- a/assets/ch03-ssh.html-D4Fp2rOo.js +++ b/assets/ch03-ssh.html-ChZfg0hU.js @@ -1,3 +1,3 @@ -import{_ as c,r as o,o as i,c as d,a as n,b as e,d as t,w as r,e as p}from"./app-DBM4OJyw.js";const u="/assets/ch03-img01-putty-download-Bz5MUwAJ.png",h="/assets/ch03-img02-putty-settings-DjkSkJO_.png",_="/assets/ch03-img03-putty-keepalive-BlaoAerP.png",g="/assets/ch03-img04-ssh-login-CzV3PNlG.png",m="/assets/ch03-img05-ssh-login-success-l_VdE5HU.png",x="/assets/ch03-img06-apt-upgrade-full--w3BBGrx.gif",P={},S=e("h1",{id:"【第-3-章】远程登录篇",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#【第-3-章】远程登录篇"},[e("span",null,"【第 3 章】远程登录篇")])],-1),v=e("h2",{id:"_3-1-远程登录-vps-putty",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_3-1-远程登录-vps-putty"},[e("span",null,"3.1 远程登录 VPS (PuTTY)")])],-1),b=e("p",null,"首先,鉴于零基础人群中 Windows 的用户基数最大,所以本文以 Windows 为例进行展示。",-1),f=e("p",null,"其次,虽然 Windows 10 之后的 PowerShell 和 WSL 也可以达到很好的 SSH 操作体验。但是因为并非所有版本的 Windows 都有最新的组件,故本文还是以老牌的 PuTTY 为例,进行 SSH 远程登录的操作详解。(使用其他工具的话、在 SSH 登陆之后的操作都是一样的)",-1),k=e("p",null,"下面就跟我一步步操作吧。",-1),y={href:"https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html",target:"_blank",rel:"noopener noreferrer"},T=e("p",null,[e("img",{src:u,alt:"下载PuTTY"})],-1),L=e("strong",null,[t("IP 地址(VPS IP)"),e("strong",null,"和"),t("端口(VPS PORT)")],-1),w=e("p",null,[e("img",{src:h,alt:"设置PuTTY"})],-1),V=e("li",null,[e("p",null,[t("我建议将 "),e("code",null,"Connection"),t(" 中的 "),e("code",null,"keepalive"),t(" 设置为 "),e("code",null,"60"),t(" 秒,防止你一段时间没有操作之后 SSH 自动断线。另外务必再次保存设置。")]),e("p",null,[e("img",{src:_,alt:"防止频繁断线"})])],-1),B=p('

注意

对 PuTTY 的任何设置更新都要再次手动保存 Session,不然关闭后就会丢失

  1. 点击 Open 就会进入 SSH 连接窗口,对应下图输入用户名与密码,与你的 VPS 远程主机建立连接。(本文假设默认用户名是 root,另外,在 Linux 系统输入密码的时候,是不会出现 ****** 这种提示符的,这样可以避免密码长度泄漏,不是你的键盘坏掉了哦!)

    SSH远程登录

3.2 成功登录 SSH!初识命令行界面!

  1. 如果你的信息都填写正确,你将会看到类似下图的界面,说明已登录成功:

    初次登录VPS

    这个界面,就等于远程服务器的【桌面】,但它没有你熟悉的图标和鼠标,没有绚丽的色彩,有的只是简单文字,这就是【命令行界面】- Command Line Interface,或者缩写为 CLI

    接下来的所有操作,都需要你像电影里的黑客一样,在这个命令行界面中完成。也许你会觉得陌生,但请相信我,使用命令行既不可怕,也不神秘。说到底,它只不过是把你习惯的鼠标操作变成了文字指令而已,你说一句,它做一句

  2. 现在,你可以稍微观察并熟悉一下命令行环境,这个界面其实已经告诉了你一些有用的信息了,比如系统内核版本(比如图内是 4.19.37-5)、上次登录时间及 IP 等。当然根据 VPS 的不同,你看到的界面可能会略有不同。

  3. 请注意命令行最下面一行,闪动的光标左边,有一串字符。图中显示的是root@vps-server:~#,这一串要怎么理解呢?很简单:

    • 现在的用户是 root
    • root 所在的服务器是 vps-server
    • root 现在所在的文件夹是 ~
    • # 之后是你可以输入命令的地方

    前两个很直观,无需多说。第三个是关于 Linux 的文件夹系统,现在也不需要过于深入,你只需要知道,"~"就是【当前用户的大本营】。第四个,提示符#,你也不用管,只需要知道,未来文章中会写一些需要你输入的命令,都会以 "#" 或者 "$" 开头,提示你后面是你输入命令的地方。(所以你复制命令的时候,只需要复制后面的内容,不要复制提示符)

3.3 第一次更新 Linux 的软件!

  1. 正如你的手机,无论安卓还是 iPhone,为了 APP 及时更新(获取安全补丁和新功能),都会时不时从应用商店获得更新信息,并且提示你有多少个 APP 可更新。Linux 系统也有逻辑十分类似的更新机制。所以只要你会更新手机 APP,就能学会更新 Linux 软件!

  2. Linux 下,每个 APP 都叫做一个“包” (package)。管理 APP 的程序自然就叫做“包管理器”(Package Manager)。你可以通过它安装、更新、卸载各种软件、甚至更新 Linux 系统本身。Linux 下的包管理器非常强大,此处按下不表,现在你只需要知道 Debian 系统的包管理器叫做 apt 即可。接下来,我们就先使用 apt 做一次软件的全面更新,让你熟悉它的基本操作。

  3. 小小白白 Linux 基础命令:

    编号命令名称命令说明
    cmd-01apt update查询软件更新
    cmd-02apt upgrade执行软件更新
  4. 现在请输入第一条命令,获取更新信息

    apt update
    +import{_ as c,r as o,o as i,c as d,a as n,b as e,d as t,w as r,e as p}from"./app-D7uBbsY3.js";const u="/assets/ch03-img01-putty-download-Bz5MUwAJ.png",h="/assets/ch03-img02-putty-settings-DjkSkJO_.png",_="/assets/ch03-img03-putty-keepalive-BlaoAerP.png",g="/assets/ch03-img04-ssh-login-CzV3PNlG.png",m="/assets/ch03-img05-ssh-login-success-l_VdE5HU.png",x="/assets/ch03-img06-apt-upgrade-full--w3BBGrx.gif",P={},S=e("h1",{id:"【第-3-章】远程登录篇",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#【第-3-章】远程登录篇"},[e("span",null,"【第 3 章】远程登录篇")])],-1),v=e("h2",{id:"_3-1-远程登录-vps-putty",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_3-1-远程登录-vps-putty"},[e("span",null,"3.1 远程登录 VPS (PuTTY)")])],-1),b=e("p",null,"首先,鉴于零基础人群中 Windows 的用户基数最大,所以本文以 Windows 为例进行展示。",-1),f=e("p",null,"其次,虽然 Windows 10 之后的 PowerShell 和 WSL 也可以达到很好的 SSH 操作体验。但是因为并非所有版本的 Windows 都有最新的组件,故本文还是以老牌的 PuTTY 为例,进行 SSH 远程登录的操作详解。(使用其他工具的话、在 SSH 登陆之后的操作都是一样的)",-1),k=e("p",null,"下面就跟我一步步操作吧。",-1),y={href:"https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html",target:"_blank",rel:"noopener noreferrer"},T=e("p",null,[e("img",{src:u,alt:"下载PuTTY"})],-1),L=e("strong",null,[t("IP 地址(VPS IP)"),e("strong",null,"和"),t("端口(VPS PORT)")],-1),w=e("p",null,[e("img",{src:h,alt:"设置PuTTY"})],-1),V=e("li",null,[e("p",null,[t("我建议将 "),e("code",null,"Connection"),t(" 中的 "),e("code",null,"keepalive"),t(" 设置为 "),e("code",null,"60"),t(" 秒,防止你一段时间没有操作之后 SSH 自动断线。另外务必再次保存设置。")]),e("p",null,[e("img",{src:_,alt:"防止频繁断线"})])],-1),B=p('

    注意

    对 PuTTY 的任何设置更新都要再次手动保存 Session,不然关闭后就会丢失

    1. 点击 Open 就会进入 SSH 连接窗口,对应下图输入用户名与密码,与你的 VPS 远程主机建立连接。(本文假设默认用户名是 root,另外,在 Linux 系统输入密码的时候,是不会出现 ****** 这种提示符的,这样可以避免密码长度泄漏,不是你的键盘坏掉了哦!)

      SSH远程登录

    3.2 成功登录 SSH!初识命令行界面!

    1. 如果你的信息都填写正确,你将会看到类似下图的界面,说明已登录成功:

      初次登录VPS

      这个界面,就等于远程服务器的【桌面】,但它没有你熟悉的图标和鼠标,没有绚丽的色彩,有的只是简单文字,这就是【命令行界面】- Command Line Interface,或者缩写为 CLI

      接下来的所有操作,都需要你像电影里的黑客一样,在这个命令行界面中完成。也许你会觉得陌生,但请相信我,使用命令行既不可怕,也不神秘。说到底,它只不过是把你习惯的鼠标操作变成了文字指令而已,你说一句,它做一句

    2. 现在,你可以稍微观察并熟悉一下命令行环境,这个界面其实已经告诉了你一些有用的信息了,比如系统内核版本(比如图内是 4.19.37-5)、上次登录时间及 IP 等。当然根据 VPS 的不同,你看到的界面可能会略有不同。

    3. 请注意命令行最下面一行,闪动的光标左边,有一串字符。图中显示的是root@vps-server:~#,这一串要怎么理解呢?很简单:

      • 现在的用户是 root
      • root 所在的服务器是 vps-server
      • root 现在所在的文件夹是 ~
      • # 之后是你可以输入命令的地方

      前两个很直观,无需多说。第三个是关于 Linux 的文件夹系统,现在也不需要过于深入,你只需要知道,"~"就是【当前用户的大本营】。第四个,提示符#,你也不用管,只需要知道,未来文章中会写一些需要你输入的命令,都会以 "#" 或者 "$" 开头,提示你后面是你输入命令的地方。(所以你复制命令的时候,只需要复制后面的内容,不要复制提示符)

    3.3 第一次更新 Linux 的软件!

    1. 正如你的手机,无论安卓还是 iPhone,为了 APP 及时更新(获取安全补丁和新功能),都会时不时从应用商店获得更新信息,并且提示你有多少个 APP 可更新。Linux 系统也有逻辑十分类似的更新机制。所以只要你会更新手机 APP,就能学会更新 Linux 软件!

    2. Linux 下,每个 APP 都叫做一个“包” (package)。管理 APP 的程序自然就叫做“包管理器”(Package Manager)。你可以通过它安装、更新、卸载各种软件、甚至更新 Linux 系统本身。Linux 下的包管理器非常强大,此处按下不表,现在你只需要知道 Debian 系统的包管理器叫做 apt 即可。接下来,我们就先使用 apt 做一次软件的全面更新,让你熟悉它的基本操作。

    3. 小小白白 Linux 基础命令:

      编号命令名称命令说明
      cmd-01apt update查询软件更新
      cmd-02apt upgrade执行软件更新
    4. 现在请输入第一条命令,获取更新信息

      apt update
       
    5. 然后请输入第二条命令,并在询问是否继续安装 (Y/n) 时输入 y 并回车确认,开始安装

      apt upgrade
       
    6. 完整流程演示如下:

      初次软件更新流程演示

    3.4 你的进度

    恭喜你又迈出了坚实的一步! 现在,你已经可以通过 SSH 来登录你的远程服务器了!那登录进去之后,除了升级软件之外,应该再做点什么呢?敬请进入下一章一探究竟吧!

    ⬛⬛⬛⬜⬜⬜⬜⬜ 37.5%

    ',9);function E(H,I){const s=o("I18nTip"),l=o("ExternalLinkIcon"),a=o("RouterLink");return i(),d("div",null,[n(s),S,v,b,f,k,e("ol",null,[e("li",null,[e("p",null,[t("进入 PuTTY 的"),e("a",y,[t("官网"),n(l)]),t(",选择适合你操作系统的版本下载。(本文以 64 位版本为例)")]),T]),e("li",null,[e("p",null,[t("安装运行后,将会看到 PuTTY 的主界面。现在请拿出你上一章记东西的"),n(a,{to:"/document/level-0/ch02-preparation.html#21-%E8%8E%B7%E5%8F%96%E4%B8%80%E5%8F%B0vps"},{default:r(()=>[t("小本本")]),_:1}),t(",在下图的对应位置填入你 VPS 的"),L,t("。为了方便以后使用时不用重复输入,我们可以保存会话 (Saved Sessions),未来使用时只要按 Load 即可一键载入设置。")]),w]),V]),B])}const Y=c(P,[["render",E],["__file","ch03-ssh.html.vue"]]);export{Y as default}; diff --git a/assets/ch03-ssh.html-GVNNjQoi.js b/assets/ch03-ssh.html-DYiYMrsa.js similarity index 99% rename from assets/ch03-ssh.html-GVNNjQoi.js rename to assets/ch03-ssh.html-DYiYMrsa.js index b18014c7a8..f262bc6aea 100644 --- a/assets/ch03-ssh.html-GVNNjQoi.js +++ b/assets/ch03-ssh.html-DYiYMrsa.js @@ -1,3 +1,3 @@ -import{_ as i,r as o,o as r,c as l,a as n,b as e,d as t,e as d}from"./app-DBM4OJyw.js";const c="/assets/ch03-img01-putty-download-Bz5MUwAJ.png",h="/assets/ch03-img02-putty-settings-DjkSkJO_.png",u="/assets/ch03-img03-putty-keepalive-BlaoAerP.png",p="/assets/ch03-img04-ssh-login-CzV3PNlG.png",m="/assets/ch03-img05-ssh-login-success-l_VdE5HU.png",g="/assets/ch03-img06-apt-upgrade-full--w3BBGrx.gif",f={},y=e("h1",{id:"chapter-3-remote-login",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#chapter-3-remote-login"},[e("span",null,"[Chapter 3] Remote Login")])],-1),w=e("h2",{id:"_3-1-remote-login-to-vps-putty",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_3-1-remote-login-to-vps-putty"},[e("span",null,"3.1 Remote Login to VPS (PuTTY)")])],-1),v=e("p",null,"First of all, considering that the user base of Windows is the largest among the zero-based population, this article uses Windows as an example for demonstration.",-1),b=e("p",null,"Secondly, although PowerShell and WSL after Windows 10 can also achieve a good SSH operation experience, not all versions of Windows have the latest components. Therefore, this article uses the classic PuTTY as an example to provide a detailed explanation of SSH remote login operation. (If you use other tools, the operations after the SSH login are the same.)",-1),_=e("p",null,"Follow me step by step and let's start the operation.",-1),x={href:"https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html",target:"_blank",rel:"noopener noreferrer"},k=d('

    Download PuTTY

    1. After installation and running, you will see the main interface of PuTTY. Now please take out your notebook from the previous chapter where you wrote down the IP address (VPS IP) and port (VPS PORT) of your VPS in the corresponding positions of the following figure. In order to save time and avoid repeatedly entering these details in the future, we can save the session (Saved Sessions), and simply load it in the future with one click.

    PuTTY Settings

    1. I suggest setting keepalive to 60 seconds in the Connection to prevent SSH from automatically disconnecting after a period of inactivity. Be sure to save the settings again.

    Prevent frequent disconnection

    Attention

    Any update to the PuTTY configuration needs to be manually saved to the session again. Otherwise, it will be lost after closing.

    1. Click on Open to enter the SSH connection window, then enter the username and password corresponding to the following figure to establish a connection with your VPS remote host. (This article assumes that the default username is root. Also, when entering a password in the Linux system, there will be no prompt like ******, which can avoid password length leakage. It's not that your keyboard is broken!)

    SSH Remote Login

    3.2 Successfully Logging in SSH! Introduction to Command Line Interface!

    1. If you have filled in your information correctly, you will see a similar interface as the picture below, indicating that you have successfully logged in:

    Logging in to VPS for the first time

    This interface is equivalent to the "desktop" of a remote server, but it does not have familiar icons and a mouse, nor does it have colorful graphics. Instead, all you see is simple text. This is the "Command Line Interface" - shortened as CLI.

    All the following operations require you to act like a hacker in a movie and complete them in this command-line interface. Maybe you will feel unfamiliar, but please believe me, using the command-line interface is neither scary nor mysterious. In the end, it just turns your familiar mouse operations into textual commands, you say it, it does it.

    1. Now, you can observe and familiarize yourself with the command line environment a little bit. This interface has actually provided you with some useful information, such as the system kernel version (e.g. 4.19.37-5 in the picture), last login time and IP address. Of course, depending on the VPS, the interface you see may be slightly different.

    2. Please pay attention to the line at the bottom of the command line, to the left of the flashing cursor, there is a string of characters. The one shown in the figure is root@vps-server:~#. How to understand this string? It's very simple:

    • The current user is root
    • The server where root is located is vps-server
    • The current directory where root is located is ~
    • After # is the place where you can input commands.

    The first two are pretty straightforward, no need to explain further. The third one is about the folder system in Linux. You don't need to go too deep into it for now. Just know that "~" represents the home directory of the current user. As for the fourth one, the prompt symbol "#", you don't need to worry about it either. Just know that in future articles, there will be some commands that you need to input, and they will be preceded by "#" or "$" to indicate where you should input the command. (So when you copy the command, just copy the content after the prompt symbol and don't copy the prompt symbol itself.)

    3.3 Updating software on Linux for the first time!

    1. Just like your phone, whether it's Android or iPhone, in order to keep your apps up-to-date (to get security patches and new features), you will occasionally receive update notifications from the app store, telling you how many apps need to be updated. Linux systems also have a similar update mechanism that works logically. So as long as you know how to update phone apps, you can learn how to update Linux software!

    2. In Linux, each application is called a "package". The program that manages the applications is naturally called a "package manager". You can use it to install, update, and uninstall various software, and even update the Linux system itself. Package managers in Linux are very powerful, but we won't go into details here. For now, you only need to know that the package manager for the Debian system is called apt. Next, we will first use apt to do a comprehensive update of the software to familiarize you with its basic operations.

    3. Tiny White Linux Basic Commands:

    NumberCommand NameCommand Description
    cmd-01apt updateQuery software updates
    cmd-02apt upgradePerform software updates
    1. Now, please enter the first command to get update information.
    apt update
    +import{_ as i,r as o,o as r,c as l,a as n,b as e,d as t,e as d}from"./app-D7uBbsY3.js";const c="/assets/ch03-img01-putty-download-Bz5MUwAJ.png",h="/assets/ch03-img02-putty-settings-DjkSkJO_.png",u="/assets/ch03-img03-putty-keepalive-BlaoAerP.png",p="/assets/ch03-img04-ssh-login-CzV3PNlG.png",m="/assets/ch03-img05-ssh-login-success-l_VdE5HU.png",g="/assets/ch03-img06-apt-upgrade-full--w3BBGrx.gif",f={},y=e("h1",{id:"chapter-3-remote-login",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#chapter-3-remote-login"},[e("span",null,"[Chapter 3] Remote Login")])],-1),w=e("h2",{id:"_3-1-remote-login-to-vps-putty",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_3-1-remote-login-to-vps-putty"},[e("span",null,"3.1 Remote Login to VPS (PuTTY)")])],-1),v=e("p",null,"First of all, considering that the user base of Windows is the largest among the zero-based population, this article uses Windows as an example for demonstration.",-1),b=e("p",null,"Secondly, although PowerShell and WSL after Windows 10 can also achieve a good SSH operation experience, not all versions of Windows have the latest components. Therefore, this article uses the classic PuTTY as an example to provide a detailed explanation of SSH remote login operation. (If you use other tools, the operations after the SSH login are the same.)",-1),_=e("p",null,"Follow me step by step and let's start the operation.",-1),x={href:"https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html",target:"_blank",rel:"noopener noreferrer"},k=d('

    Download PuTTY

    1. After installation and running, you will see the main interface of PuTTY. Now please take out your notebook from the previous chapter where you wrote down the IP address (VPS IP) and port (VPS PORT) of your VPS in the corresponding positions of the following figure. In order to save time and avoid repeatedly entering these details in the future, we can save the session (Saved Sessions), and simply load it in the future with one click.

    PuTTY Settings

    1. I suggest setting keepalive to 60 seconds in the Connection to prevent SSH from automatically disconnecting after a period of inactivity. Be sure to save the settings again.

    Prevent frequent disconnection

    Attention

    Any update to the PuTTY configuration needs to be manually saved to the session again. Otherwise, it will be lost after closing.

    1. Click on Open to enter the SSH connection window, then enter the username and password corresponding to the following figure to establish a connection with your VPS remote host. (This article assumes that the default username is root. Also, when entering a password in the Linux system, there will be no prompt like ******, which can avoid password length leakage. It's not that your keyboard is broken!)

    SSH Remote Login

    3.2 Successfully Logging in SSH! Introduction to Command Line Interface!

    1. If you have filled in your information correctly, you will see a similar interface as the picture below, indicating that you have successfully logged in:

    Logging in to VPS for the first time

    This interface is equivalent to the "desktop" of a remote server, but it does not have familiar icons and a mouse, nor does it have colorful graphics. Instead, all you see is simple text. This is the "Command Line Interface" - shortened as CLI.

    All the following operations require you to act like a hacker in a movie and complete them in this command-line interface. Maybe you will feel unfamiliar, but please believe me, using the command-line interface is neither scary nor mysterious. In the end, it just turns your familiar mouse operations into textual commands, you say it, it does it.

    1. Now, you can observe and familiarize yourself with the command line environment a little bit. This interface has actually provided you with some useful information, such as the system kernel version (e.g. 4.19.37-5 in the picture), last login time and IP address. Of course, depending on the VPS, the interface you see may be slightly different.

    2. Please pay attention to the line at the bottom of the command line, to the left of the flashing cursor, there is a string of characters. The one shown in the figure is root@vps-server:~#. How to understand this string? It's very simple:

    • The current user is root
    • The server where root is located is vps-server
    • The current directory where root is located is ~
    • After # is the place where you can input commands.

    The first two are pretty straightforward, no need to explain further. The third one is about the folder system in Linux. You don't need to go too deep into it for now. Just know that "~" represents the home directory of the current user. As for the fourth one, the prompt symbol "#", you don't need to worry about it either. Just know that in future articles, there will be some commands that you need to input, and they will be preceded by "#" or "$" to indicate where you should input the command. (So when you copy the command, just copy the content after the prompt symbol and don't copy the prompt symbol itself.)

    3.3 Updating software on Linux for the first time!

    1. Just like your phone, whether it's Android or iPhone, in order to keep your apps up-to-date (to get security patches and new features), you will occasionally receive update notifications from the app store, telling you how many apps need to be updated. Linux systems also have a similar update mechanism that works logically. So as long as you know how to update phone apps, you can learn how to update Linux software!

    2. In Linux, each application is called a "package". The program that manages the applications is naturally called a "package manager". You can use it to install, update, and uninstall various software, and even update the Linux system itself. Package managers in Linux are very powerful, but we won't go into details here. For now, you only need to know that the package manager for the Debian system is called apt. Next, we will first use apt to do a comprehensive update of the software to familiarize you with its basic operations.

    3. Tiny White Linux Basic Commands:

    NumberCommand NameCommand Description
    cmd-01apt updateQuery software updates
    cmd-02apt upgradePerform software updates
    1. Now, please enter the first command to get update information.
    apt update
     

    This is a command used in a Linux terminal to update the package list from the repositories configured on the system.

    1. Then enter the second command, and when asked if you want to continue installing (Y/n), type y and press enter to confirm and start the installation.
    apt upgrade
     

    This is a command in the shell terminal to upgrade the installed packages on a Debian or Ubuntu Linux system.

    1. The complete demonstration of the process is as follows:

    Demonstration of the software update process for the first time

    3.4 Your Progress

    Congratulations on taking another solid step! Now, you can log in to your remote server via SSH! After logging in, besides upgrading the software, what else should you do? Please enter the next chapter to find out!

    ⬛⬛⬛⬜⬜⬜⬜⬜ 37.5%

    ',30);function S(T,P){const s=o("I18nTip"),a=o("ExternalLinkIcon");return r(),l("div",null,[n(s),y,w,v,b,_,e("ol",null,[e("li",null,[t("Go to the "),e("a",x,[t("official website"),n(a)]),t(" of PuTTY and download the version that suits your operating system (this article uses the 64-bit version as an example).")])]),k])}const q=i(f,[["render",S],["__file","ch03-ssh.html.vue"]]);export{q as default}; diff --git a/assets/ch03-ssh.html-C-e-7t3_.js b/assets/ch03-ssh.html-Dm-1-GXk.js similarity index 99% rename from assets/ch03-ssh.html-C-e-7t3_.js rename to assets/ch03-ssh.html-Dm-1-GXk.js index ac57909e21..8ec4147069 100644 --- a/assets/ch03-ssh.html-C-e-7t3_.js +++ b/assets/ch03-ssh.html-Dm-1-GXk.js @@ -1,3 +1,3 @@ -import{_ as c,r as o,o as d,c as i,a as n,b as e,d as t,w as r,e as p}from"./app-DBM4OJyw.js";const u="/assets/ch03-img01-putty-download-Bz5MUwAJ.png",h="/assets/ch03-img02-putty-settings-DjkSkJO_.png",_="/assets/ch03-img03-putty-keepalive-BlaoAerP.png",g="/assets/ch03-img04-ssh-login-CzV3PNlG.png",m="/assets/ch03-img05-ssh-login-success-l_VdE5HU.png",x="/assets/ch03-img06-apt-upgrade-full--w3BBGrx.gif",v={},S=e("h1",{id:"【глава-3】-удаленное-подключение",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#【глава-3】-удаленное-подключение"},[e("span",null,"【Глава 3】 Удалённое подключение")])],-1),b=e("h2",{id:"_3-1-удаленное-подключение-к-vps-putty",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_3-1-удаленное-подключение-к-vps-putty"},[e("span",null,"3.1 Удалённое подключение к VPS (PuTTY)")])],-1),f=e("p",null,"Во-первых, поскольку Windows является самой распространённой операционной системой среди новичков, в этой статье мы будем использовать её в качестве примера.",-1),k=e("p",null,"Во-вторых, хотя PowerShell и WSL в Windows 10 и выше также предоставляют удобные инструменты для работы по SSH, не все версии Windows имеют эти компоненты. Поэтому в этой статье мы рассмотрим подключение по SSH с помощью старого доброго PuTTY. (После подключения по SSH действия во всех программах будут одинаковыми.)",-1),P=e("p",null,"Итак, давайте начнём.",-1),y={href:"https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html",target:"_blank",rel:"noopener noreferrer"},T=e("p",null,[e("img",{src:u,alt:"Скачать PuTTY"})],-1),B=e("strong",null,"IP-адрес",-1),L=e("strong",null,"порт",-1),w=e("p",null,[e("img",{src:h,alt:"Настройка PuTTY"})],-1),D=e("li",null,[e("p",null,[t("Рекомендуем установить значение "),e("code",null,"keepalive"),t(" в разделе "),e("code",null,"Connection"),t(" равным "),e("code",null,"60"),t(" секундам, чтобы предотвратить разрыв SSH-соединения, если вы долгое время не будете выполнять никаких действий. Не забудьте снова сохранить настройки.")]),e("p",null,[e("img",{src:_,alt:"Предотвращение разрывов соединения"})])],-1),V=p('

    Внимание

    После любых изменений настроек PuTTY необходимо сохранить сеанс, иначе они будут потеряны при закрытии программы.

    1. Нажмите кнопку "Open", чтобы открыть окно SSH-подключения. Введите имя пользователя и пароль для подключения к вашему VPS (в этой статье предполагается, что имя пользователя по умолчанию — root. Обратите внимание, что при вводе пароля в Linux не отображаются символы ******. Это сделано для того, чтобы скрыть длину пароля. Не пугайтесь, ваша клавиатура в порядке!).

      Подключение по SSH

    3.2 Успешное подключение по SSH! Знакомство с командной строкой!

    1. Если вы всё сделали правильно, вы увидите примерно такой экран, как на рисунке ниже. Это означает, что вы успешно подключились к серверу:

      Первое подключение к VPS

      Этот экран — аналог «рабочего стола» на удалённом сервере, но здесь нет привычных значков, курсора мыши и ярких цветов. Только текст. Это и есть командная строкаCommand Line Interface или сокращённо CLI.

      Все дальнейшие действия вам придётся выполнять в командной строке, как хакер в кино. Возможно, поначалу это покажется вам непривычным, но поверьте, в использовании командной строки нет ничего страшного или сложного. По сути, это всего лишь способ взаимодействия с компьютером с помощью текстовых команд вместо графического интерфейса. Вы пишете команду, а компьютер её выполняет.

    2. Теперь можете немного осмотреться и познакомиться с командной строкой. На этом экране уже есть полезная информация, например, версия ядра системы (в данном случае 4.19.37-5), время последнего входа в систему, IP-адрес и т.д. Конечно, в зависимости от VPS, ваш экран может выглядеть немного иначе.

    3. Обратите внимание на последнюю строку командной строки. Слева от мигающего курсора находится набор символов. В данном случае это root@vps-server:~#. Что это значит? Всё просто:

      • Текущий пользователь: root.
      • Имя сервера, на котором работает пользователь root: vps-server.
      • Текущий каталог, в котором находится пользователь root: ~.
      • Символ # указывает на то, что после него можно вводить команды.

      Первые два пункта интуитивно понятны и не требуют пояснений. Третий пункт относится к файловой системе Linux. Сейчас вам не нужно вдаваться в подробности, достаточно знать, что ~ — это «домашний каталог» текущего пользователя. Четвёртый пункт, символ #, также не требует особого внимания. Просто знайте, что в дальнейшем все команды, которые вам нужно будет вводить, будут начинаться с # или $. Это будет означать, что после этого символа нужно ввести команду (поэтому при копировании команд копируйте только текст после, без символа # или $).

    3.3 Первое обновление программного обеспечения Linux!

    1. Так же, как и ваш телефон, будь то Android или iPhone, Linux нуждается в регулярном обновлении программного обеспечения для получения исправлений безопасности и новых функций. В Linux каждое приложение называется «пакетом» (package). А программа, которая управляет пакетами, называется «менеджером пакетов» (Package Manager). С помощью менеджера пакетов можно устанавливать, обновлять и удалять программы, а также обновлять саму систему Linux. Менеджеры пакетов Linux очень мощные, но сейчас вам достаточно знать, что в Debian используется менеджер пакетов apt. Давайте обновим систему с помощью apt, чтобы вы познакомились с его основными функциями.

    2. Базовые команды Linux:

      НомерКомандаОписание
      cmd-01apt updateПроверить обновления
      cmd-02apt upgradeУстановить обновления
    3. Введите первую команду, чтобы получить информацию об обновлениях:

      apt update
      +import{_ as c,r as o,o as d,c as i,a as n,b as e,d as t,w as r,e as p}from"./app-D7uBbsY3.js";const u="/assets/ch03-img01-putty-download-Bz5MUwAJ.png",h="/assets/ch03-img02-putty-settings-DjkSkJO_.png",_="/assets/ch03-img03-putty-keepalive-BlaoAerP.png",g="/assets/ch03-img04-ssh-login-CzV3PNlG.png",m="/assets/ch03-img05-ssh-login-success-l_VdE5HU.png",x="/assets/ch03-img06-apt-upgrade-full--w3BBGrx.gif",v={},S=e("h1",{id:"【глава-3】-удаленное-подключение",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#【глава-3】-удаленное-подключение"},[e("span",null,"【Глава 3】 Удалённое подключение")])],-1),b=e("h2",{id:"_3-1-удаленное-подключение-к-vps-putty",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_3-1-удаленное-подключение-к-vps-putty"},[e("span",null,"3.1 Удалённое подключение к VPS (PuTTY)")])],-1),f=e("p",null,"Во-первых, поскольку Windows является самой распространённой операционной системой среди новичков, в этой статье мы будем использовать её в качестве примера.",-1),k=e("p",null,"Во-вторых, хотя PowerShell и WSL в Windows 10 и выше также предоставляют удобные инструменты для работы по SSH, не все версии Windows имеют эти компоненты. Поэтому в этой статье мы рассмотрим подключение по SSH с помощью старого доброго PuTTY. (После подключения по SSH действия во всех программах будут одинаковыми.)",-1),P=e("p",null,"Итак, давайте начнём.",-1),y={href:"https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html",target:"_blank",rel:"noopener noreferrer"},T=e("p",null,[e("img",{src:u,alt:"Скачать PuTTY"})],-1),B=e("strong",null,"IP-адрес",-1),L=e("strong",null,"порт",-1),w=e("p",null,[e("img",{src:h,alt:"Настройка PuTTY"})],-1),D=e("li",null,[e("p",null,[t("Рекомендуем установить значение "),e("code",null,"keepalive"),t(" в разделе "),e("code",null,"Connection"),t(" равным "),e("code",null,"60"),t(" секундам, чтобы предотвратить разрыв SSH-соединения, если вы долгое время не будете выполнять никаких действий. Не забудьте снова сохранить настройки.")]),e("p",null,[e("img",{src:_,alt:"Предотвращение разрывов соединения"})])],-1),V=p('

      Внимание

      После любых изменений настроек PuTTY необходимо сохранить сеанс, иначе они будут потеряны при закрытии программы.

      1. Нажмите кнопку "Open", чтобы открыть окно SSH-подключения. Введите имя пользователя и пароль для подключения к вашему VPS (в этой статье предполагается, что имя пользователя по умолчанию — root. Обратите внимание, что при вводе пароля в Linux не отображаются символы ******. Это сделано для того, чтобы скрыть длину пароля. Не пугайтесь, ваша клавиатура в порядке!).

        Подключение по SSH

      3.2 Успешное подключение по SSH! Знакомство с командной строкой!

      1. Если вы всё сделали правильно, вы увидите примерно такой экран, как на рисунке ниже. Это означает, что вы успешно подключились к серверу:

        Первое подключение к VPS

        Этот экран — аналог «рабочего стола» на удалённом сервере, но здесь нет привычных значков, курсора мыши и ярких цветов. Только текст. Это и есть командная строкаCommand Line Interface или сокращённо CLI.

        Все дальнейшие действия вам придётся выполнять в командной строке, как хакер в кино. Возможно, поначалу это покажется вам непривычным, но поверьте, в использовании командной строки нет ничего страшного или сложного. По сути, это всего лишь способ взаимодействия с компьютером с помощью текстовых команд вместо графического интерфейса. Вы пишете команду, а компьютер её выполняет.

      2. Теперь можете немного осмотреться и познакомиться с командной строкой. На этом экране уже есть полезная информация, например, версия ядра системы (в данном случае 4.19.37-5), время последнего входа в систему, IP-адрес и т.д. Конечно, в зависимости от VPS, ваш экран может выглядеть немного иначе.

      3. Обратите внимание на последнюю строку командной строки. Слева от мигающего курсора находится набор символов. В данном случае это root@vps-server:~#. Что это значит? Всё просто:

        • Текущий пользователь: root.
        • Имя сервера, на котором работает пользователь root: vps-server.
        • Текущий каталог, в котором находится пользователь root: ~.
        • Символ # указывает на то, что после него можно вводить команды.

        Первые два пункта интуитивно понятны и не требуют пояснений. Третий пункт относится к файловой системе Linux. Сейчас вам не нужно вдаваться в подробности, достаточно знать, что ~ — это «домашний каталог» текущего пользователя. Четвёртый пункт, символ #, также не требует особого внимания. Просто знайте, что в дальнейшем все команды, которые вам нужно будет вводить, будут начинаться с # или $. Это будет означать, что после этого символа нужно ввести команду (поэтому при копировании команд копируйте только текст после, без символа # или $).

      3.3 Первое обновление программного обеспечения Linux!

      1. Так же, как и ваш телефон, будь то Android или iPhone, Linux нуждается в регулярном обновлении программного обеспечения для получения исправлений безопасности и новых функций. В Linux каждое приложение называется «пакетом» (package). А программа, которая управляет пакетами, называется «менеджером пакетов» (Package Manager). С помощью менеджера пакетов можно устанавливать, обновлять и удалять программы, а также обновлять саму систему Linux. Менеджеры пакетов Linux очень мощные, но сейчас вам достаточно знать, что в Debian используется менеджер пакетов apt. Давайте обновим систему с помощью apt, чтобы вы познакомились с его основными функциями.

      2. Базовые команды Linux:

        НомерКомандаОписание
        cmd-01apt updateПроверить обновления
        cmd-02apt upgradeУстановить обновления
      3. Введите первую команду, чтобы получить информацию об обновлениях:

        apt update
         
      4. Затем введите вторую команду. При появлении запроса на подтверждение установки (Y/n) введите y и нажмите Enter, чтобы начать установку.

        apt upgrade
         
      5. Весь процесс показан на гифке ниже:

        Демонстрация процесса обновления

      3.4 Ваш прогресс

      Поздравляем, вы сделали ещё один важный шаг! Теперь вы умеете подключаться к своему серверу по SSH! Но что делать после подключения, кроме обновления системы? Узнаем в следующей главе!

      ⬛⬛⬛⬜⬜⬜⬜⬜ 37.5%

      ',9);function H(I,Y){const s=o("I18nTip"),l=o("ExternalLinkIcon"),a=o("RouterLink");return d(),i("div",null,[n(s),S,b,f,k,P,e("ol",null,[e("li",null,[e("p",null,[t("Перейдите на "),e("a",y,[t("официальный сайт"),n(l)]),t(" PuTTY и скачайте версию, подходящую для вашей операционной системы (в этой статье мы будем использовать 64-битную версию).")]),T]),e("li",null,[e("p",null,[t("Запустите PuTTY. Откроется главное окно программы. Теперь возьмите "),n(a,{to:"/ru/document/level-0/ch02-preparation.html#21-%D0%BF%D0%BE%D0%BB%D1%83%D1%87%D0%B5%D0%BD%D0%B8%D0%B5-vps"},{default:r(()=>[t("блокнот")]),_:1}),t(", в который вы записывали информацию в предыдущей главе, и введите "),B,t(" и "),L,t(" вашего VPS в соответствующие поля (на скриншоте ниже). Чтобы не вводить эти данные каждый раз, можно сохранить сеанс (Saved Sessions). В дальнейшем вы сможете загрузить сохранённые настройки одним кликом.")]),w]),D]),V])}const E=c(v,[["render",H],["__file","ch03-ssh.html.vue"]]);export{E as default}; diff --git a/assets/ch04-security.html-BmDPDZZi.js b/assets/ch04-security.html-BxNi21Mp.js similarity index 99% rename from assets/ch04-security.html-BmDPDZZi.js rename to assets/ch04-security.html-BxNi21Mp.js index 12728ec72a..c46a83700f 100644 --- a/assets/ch04-security.html-BmDPDZZi.js +++ b/assets/ch04-security.html-BxNi21Mp.js @@ -1,4 +1,4 @@ -import{_ as l,r as o,o as n,c as a,a as c,b as e,d as t,e as s}from"./app-DBM4OJyw.js";const p="/assets/ch04-img01-nano-ui-B4Aenfjz.png",r="/assets/ch04-img02-sshd-conf-full-Dv8kUzC-.gif",u="/assets/ch04-img03-adduser-B0VGcN0p.png",h="/assets/ch04-img04-adduser-full-DgDkjVtm.gif",g="/assets/ch04-img05-sudo-full-DeKisL39.gif",m="/assets/ch04-img06-ssh-no-root-full-DZeR7uks.gif",_="/assets/ch04-img07-putty-default-user-D6pt-VE-.png",v="/assets/ch04-img08-puttygen-save-CHw98Rml.png",S="/assets/ch04-img09-puttygen-save-keys-NM1Wm7kW.png",b="/assets/ch04-img10-winscp-import-session-sXjUnOBu.png",x="/assets/ch04-img11-winscp-ui-AN7pET93.png",y="/assets/ch04-img12-winscp-locations-XArMgNVV.png",P="/assets/ch04-img13-winscp-newfolder-key-CM1OfBQF.png",f="/assets/ch04-img14-winscp-upload-key-BygTVpGm.png",k="/assets/ch04-img15-winscp-rename-key-8iQ3gLs7.png",T="/assets/ch04-img16-winscp-full-B_z2QlO-.gif",V="/assets/ch04-img17-rsa-login-full-CZytVZwr.gif",L="/assets/ch04-img18-putty-privatekey-location-DW84vHHi.png",A="/assets/ch04-img19-putty-privatekey-passphrase-DQfUeTjA.png",w="/assets/ch04-img20-winscp-privatekey-location-LtQ_87aZ.png",H={},Y=s(`

      【第 4 章】安全防护篇

      4.1 为什么要做安全防护

      Linux 服务器的安全防护是一个纷繁复杂的巨大课题。无数的网站、APP、服务、甚至线下基础设施都建立在 Linux 的基石之上,这背后牵涉到巨大的经济利益和商业价值,当然也就就意味着黑灰产有巨大的攻击动力。但是这些服务是如此重要、根本不允许出现重大的安全漏洞。于是无数的运维专业人员都在安全攻防的战场上拼搏努力,这才让大家能享受到基本稳定的现代化数字生活。

      现在,你拥有了一台 VPS,并且将会敞开他的数据访问渠道来达到流量转发的目标,那就相当于你已经置身于安全攻防战场的第一线、直面所有风险。但与此同时,新人由于知识和信息的不足,看待安全问题是总是难免两极分化:要么觉得轻如鸿毛和自己没有半点关系,要么觉得重于泰山甚至惶惶不可终日。

      • 对于前者,我的建议是:安全无小事,尽量多查一些安全方面的信息,免得自己真的受了损失才后悔莫及

      • 对于后者,我的建议是:不用紧张,我们的服务器仍不具有太高的价值、一般不会吸引到高水平的攻击,需要面对的基本都是一些自动化脚本的恶意扫描和登录尝试,跟着本文做一些基础的防护即可

      4.2 具体的风险到底是什么

      就像我们在《远程登录篇》配置的一样,任何人只需要知道【IP 地址】+【端口】+【用户名】+【密码】这四个要素,就能登录你的 VPS 服务器。那很显然,这四要素的安全就是我们要防护的底线。我们来逐一分析:

      1. 【IP 地址】:恶意脚本会随机尝试和扫描 IP 段,可以简单认为是公开信息、无法隐藏

      2. 【端口】:如果使用默认端口,那么【端口 = 22

      3. 【用户名】:如果使用默认用户,那么【用户名 = root

      4. 【密码】:密码不存在默认值,一定是由 VPS 后台随机生成或由你自行设置的。也就是说,如果你的服务器都是默认设置,则四要素中的三个已经是已知的,那么你整个服务器的安全,就全部寄托在一串小小的密码上了。这时有几种情况:

        • 如果你用了 VPS 管理后台随机生成密码,它一般包含随机的十几个大小写混杂的字母和符号,相对比较安全

        • 如果你为了好记、把密码改成了类似123456这种超弱的密码,破解你的 VPS 服务器可谓不费吹灰之力

        • 如果你为了好记、把密码改成了比较复杂、但在别的地方用过的密码,其实也并不安全。你要明白黑客手里有作弊器,比如说密码表,包含数万、数十万、数百万甚至更多曾经泄漏的真实密码)

      5. 但你要明白,没有哪个黑客真的要坐在电脑前一次一次的尝试你的密码,全部的攻击尝试都是恶意脚本自动进行的,它会 24 小时不眠不休的工作。也许每天你酣睡之时,你的服务器都在经受着一轮又一轮的冲击。

        一旦密码被成功撞破,意味着你的四要素全部被攻击者掌握,恶意脚本就会快速登录服务器、获取服务器的最高 root 控制权、安装部署它的恶意服务,然后就可以用你的服务器来 24 小时做各种坏事(比如挖矿、传播病毒、发送垃圾邮件、欺诈邮件、做 BT 中继、甚至暗网公众节点等等等等)。如果恶意脚本比较克制,其实可以做到相当的隐蔽性。而新人一般也不会去观察留意 VPS 的登录记录、进程变化、CPU 占用变化、流量变化等指标,你其实就很难发现自己被黑了。直到你的 VPS 服务商封禁你的账号、或者收到律师函为止。

      6. 别忘了,你获得 VPS 时大概率需要使用真实的支付信息,你登录各种网站、社交平台时也会留下你的 IP 地址,这些都与你的身份有直接或者间接的关系。于是,一旦这些坏事发生,它们就不可避免的与你产生了关联。

      4.3 我们要做的安全防护有哪些

      基于上述分析,我们要做的,自然就是对【端口】、【用户名】、【密码】这三要素进行加强,来降低被攻破的风险:

      1. 【端口】:将 SSH 远程登录端口修改为【非 22 端口】 (4.4)
      2. 【用户名】:建立【非 root】的新用户、并禁用 root 用户 SSH 远程登录 (4.5、4.6)
      3. 【密码】:SSH 启用 RSA 密钥验证登录、同时禁用密码验证登录 (4.7)

      记得按顺序来,别把自己锁在门外了。

      4.4 将 SSH 远程登录端口修改为非 22 端口

      现在,我们来解决【端口 = 22】的问题。(注意:有些 VPS 服务商,默认的端口已经是非 22 端口,那么你可以忽略这一步,当然也可以跟着本文改成别的端口)

      1. 小小白白 Linux 基础命令:

        编号命令名称命令说明
        cmd-03nano文本编辑器
        cmd-04systemctl restart重启某个服务
      2. 小小白白 Linux 基础配置文件

        编号配置文件位置文件说明
        conf-01/etc/ssh/sshd_configSSH 远程登录程序设置
      3. 我们要做的第一件事,当然就是【用nano这个文本编辑器打开SSH远程登录程序设置】,在 Windows 下,你会【找到文件并双击】,在 Linux 下该怎么办呢?仔细看看上面的命令说明,是不是就很简单了?没错,就是:

        nano /etc/ssh/sshd_config
        +import{_ as l,r as o,o as n,c as a,a as c,b as e,d as t,e as s}from"./app-D7uBbsY3.js";const p="/assets/ch04-img01-nano-ui-B4Aenfjz.png",r="/assets/ch04-img02-sshd-conf-full-Dv8kUzC-.gif",u="/assets/ch04-img03-adduser-B0VGcN0p.png",h="/assets/ch04-img04-adduser-full-DgDkjVtm.gif",g="/assets/ch04-img05-sudo-full-DeKisL39.gif",m="/assets/ch04-img06-ssh-no-root-full-DZeR7uks.gif",_="/assets/ch04-img07-putty-default-user-D6pt-VE-.png",v="/assets/ch04-img08-puttygen-save-CHw98Rml.png",S="/assets/ch04-img09-puttygen-save-keys-NM1Wm7kW.png",b="/assets/ch04-img10-winscp-import-session-sXjUnOBu.png",x="/assets/ch04-img11-winscp-ui-AN7pET93.png",y="/assets/ch04-img12-winscp-locations-XArMgNVV.png",P="/assets/ch04-img13-winscp-newfolder-key-CM1OfBQF.png",f="/assets/ch04-img14-winscp-upload-key-BygTVpGm.png",k="/assets/ch04-img15-winscp-rename-key-8iQ3gLs7.png",T="/assets/ch04-img16-winscp-full-B_z2QlO-.gif",V="/assets/ch04-img17-rsa-login-full-CZytVZwr.gif",L="/assets/ch04-img18-putty-privatekey-location-DW84vHHi.png",A="/assets/ch04-img19-putty-privatekey-passphrase-DQfUeTjA.png",w="/assets/ch04-img20-winscp-privatekey-location-LtQ_87aZ.png",H={},Y=s(`

        【第 4 章】安全防护篇

        4.1 为什么要做安全防护

        Linux 服务器的安全防护是一个纷繁复杂的巨大课题。无数的网站、APP、服务、甚至线下基础设施都建立在 Linux 的基石之上,这背后牵涉到巨大的经济利益和商业价值,当然也就就意味着黑灰产有巨大的攻击动力。但是这些服务是如此重要、根本不允许出现重大的安全漏洞。于是无数的运维专业人员都在安全攻防的战场上拼搏努力,这才让大家能享受到基本稳定的现代化数字生活。

        现在,你拥有了一台 VPS,并且将会敞开他的数据访问渠道来达到流量转发的目标,那就相当于你已经置身于安全攻防战场的第一线、直面所有风险。但与此同时,新人由于知识和信息的不足,看待安全问题是总是难免两极分化:要么觉得轻如鸿毛和自己没有半点关系,要么觉得重于泰山甚至惶惶不可终日。

        • 对于前者,我的建议是:安全无小事,尽量多查一些安全方面的信息,免得自己真的受了损失才后悔莫及

        • 对于后者,我的建议是:不用紧张,我们的服务器仍不具有太高的价值、一般不会吸引到高水平的攻击,需要面对的基本都是一些自动化脚本的恶意扫描和登录尝试,跟着本文做一些基础的防护即可

        4.2 具体的风险到底是什么

        就像我们在《远程登录篇》配置的一样,任何人只需要知道【IP 地址】+【端口】+【用户名】+【密码】这四个要素,就能登录你的 VPS 服务器。那很显然,这四要素的安全就是我们要防护的底线。我们来逐一分析:

        1. 【IP 地址】:恶意脚本会随机尝试和扫描 IP 段,可以简单认为是公开信息、无法隐藏

        2. 【端口】:如果使用默认端口,那么【端口 = 22

        3. 【用户名】:如果使用默认用户,那么【用户名 = root

        4. 【密码】:密码不存在默认值,一定是由 VPS 后台随机生成或由你自行设置的。也就是说,如果你的服务器都是默认设置,则四要素中的三个已经是已知的,那么你整个服务器的安全,就全部寄托在一串小小的密码上了。这时有几种情况:

          • 如果你用了 VPS 管理后台随机生成密码,它一般包含随机的十几个大小写混杂的字母和符号,相对比较安全

          • 如果你为了好记、把密码改成了类似123456这种超弱的密码,破解你的 VPS 服务器可谓不费吹灰之力

          • 如果你为了好记、把密码改成了比较复杂、但在别的地方用过的密码,其实也并不安全。你要明白黑客手里有作弊器,比如说密码表,包含数万、数十万、数百万甚至更多曾经泄漏的真实密码)

        5. 但你要明白,没有哪个黑客真的要坐在电脑前一次一次的尝试你的密码,全部的攻击尝试都是恶意脚本自动进行的,它会 24 小时不眠不休的工作。也许每天你酣睡之时,你的服务器都在经受着一轮又一轮的冲击。

          一旦密码被成功撞破,意味着你的四要素全部被攻击者掌握,恶意脚本就会快速登录服务器、获取服务器的最高 root 控制权、安装部署它的恶意服务,然后就可以用你的服务器来 24 小时做各种坏事(比如挖矿、传播病毒、发送垃圾邮件、欺诈邮件、做 BT 中继、甚至暗网公众节点等等等等)。如果恶意脚本比较克制,其实可以做到相当的隐蔽性。而新人一般也不会去观察留意 VPS 的登录记录、进程变化、CPU 占用变化、流量变化等指标,你其实就很难发现自己被黑了。直到你的 VPS 服务商封禁你的账号、或者收到律师函为止。

        6. 别忘了,你获得 VPS 时大概率需要使用真实的支付信息,你登录各种网站、社交平台时也会留下你的 IP 地址,这些都与你的身份有直接或者间接的关系。于是,一旦这些坏事发生,它们就不可避免的与你产生了关联。

        4.3 我们要做的安全防护有哪些

        基于上述分析,我们要做的,自然就是对【端口】、【用户名】、【密码】这三要素进行加强,来降低被攻破的风险:

        1. 【端口】:将 SSH 远程登录端口修改为【非 22 端口】 (4.4)
        2. 【用户名】:建立【非 root】的新用户、并禁用 root 用户 SSH 远程登录 (4.5、4.6)
        3. 【密码】:SSH 启用 RSA 密钥验证登录、同时禁用密码验证登录 (4.7)

        记得按顺序来,别把自己锁在门外了。

        4.4 将 SSH 远程登录端口修改为非 22 端口

        现在,我们来解决【端口 = 22】的问题。(注意:有些 VPS 服务商,默认的端口已经是非 22 端口,那么你可以忽略这一步,当然也可以跟着本文改成别的端口)

        1. 小小白白 Linux 基础命令:

          编号命令名称命令说明
          cmd-03nano文本编辑器
          cmd-04systemctl restart重启某个服务
        2. 小小白白 Linux 基础配置文件

          编号配置文件位置文件说明
          conf-01/etc/ssh/sshd_configSSH 远程登录程序设置
        3. 我们要做的第一件事,当然就是【用nano这个文本编辑器打开SSH远程登录程序设置】,在 Windows 下,你会【找到文件并双击】,在 Linux 下该怎么办呢?仔细看看上面的命令说明,是不是就很简单了?没错,就是:

          nano /etc/ssh/sshd_config
           
        4. 文件打开后,你就进入了nano的界面,稍微观察一下,你会发现,它把重要的快捷键都显示在屏幕下方了(下图红框内),直接开卷考试、不用死记硬背,是不是很贴心呢?

          nano的界面

        1. 我们要做的第二件事,是【在打开的文件中找到Port这一项,并修改它的端口】。Port 后面的数字就是 SSH 的端口,一般建议把它改成一个大于1024小于65535的整数(本文以9753为例)。请结合nano的快捷键,想一下该怎么操作呢?果然,你又说对了!就是:

          • 使用 ctrl+w 进入搜索模式,然后输入 Port 22 并回车
          • 删除 22 并改成 9753
          • 说明:如果这一行开头有个#,证明这一行【不生效】(被注释掉了),你可像我一样在文件最后写一个不带#的,或者把#删掉就好。

          注意

          本文以9753为例,就意味着随着本文的发布,这个端口会变成一个不大不小的特征,也许会被攻击者优先尝试、也许被 GFW 干扰、阻断。所以我强烈建议你用一个自己想到的其他端口,毕竟,你有 6 万多个端口可以自由选择。

        1. 我们要做的第三件事,是【保存文件并退出】

          • 如果第 3 步你有仔细观察,就会发现保存并不是常见的 ctrl+s

          • 正确的快捷键:保存是 ctrl+o + 回车,退出是 ctrl+x

          • (部分操作系统) 新增一个防火墙规则,设置为新增的SSH端口, 否则实例重启后无法SSH登陆。

          • 如 Ubuntu 的 ufw

          sudo ufw allow 9753/tcp
           
        2. 我们最后要做的事,是【重启 ssh 服务,使变更生效】

          systemctl restart ssh
           

          然后可以尝试在ssh软件上打开新的会话尝试是否可以连上,如果出现问题可以通过旧的ssh会话修改配置(重启sshd时已经打开的ssh不会被关闭)

        3. 完整流程演示如下:

          修改非22端口演示

        4. 修改 PuTTY 配置

          现在新的端口已经生效,下次使用 PuTTY 登录时就要用9753了。所以现在请到 PuTTY 的设置中修改端口号码,然后保存 Session。嗯,你应该知道去哪里改了吧?(如果不知道的话,要重读前面的内容了哦!)

        4.5 建立非 root 的新用户

        第二步,我们来解决【用户名 = root】的问题。

        首先你要理解, Linux 系统中的root,不仅仅是一个管理员账号那么简单。它是整个系统的【根基】、是系统的主宰、至高无上的神。一旦root账号出现安全问题,整个系统都只能任人鱼肉、无处可逃。那么就跟随我进行操作吧:

        1. 小小白白 Linux 基础命令:

          编号命令名称命令说明
          cmd-05adduser给系统新增用户
          cmd-06apt install安装某个软件
          cmd-07visudo修改 sudo 权限设置专用编辑器
        2. 我们要做的第一件事,是【新增一个用户并设定登录密码】,名字你可以随便起,我这里以vpsadmin为例:

          adduser vpsadmin
          diff --git a/assets/ch04-security.html-C34Buqpd.js b/assets/ch04-security.html-DF1Uapzz.js
          similarity index 99%
          rename from assets/ch04-security.html-C34Buqpd.js
          rename to assets/ch04-security.html-DF1Uapzz.js
          index 13939f250c..d74a8f90fe 100644
          --- a/assets/ch04-security.html-C34Buqpd.js
          +++ b/assets/ch04-security.html-DF1Uapzz.js
          @@ -1,4 +1,4 @@
          -import{_ as r,r as t,o as l,c,a as o,b as s,d as e,e as a}from"./app-DBM4OJyw.js";const d="/assets/ch04-img01-nano-ui-B4Aenfjz.png",h="/assets/ch04-img02-sshd-conf-full-Dv8kUzC-.gif",u="/assets/ch04-img03-adduser-B0VGcN0p.png",p="/assets/ch04-img04-adduser-full-DgDkjVtm.gif",m="/assets/ch04-img05-sudo-full-DeKisL39.gif",g="/assets/ch04-img06-ssh-no-root-full-DZeR7uks.gif",y="/assets/ch04-img07-putty-default-user-D6pt-VE-.png",f="/assets/ch04-img08-puttygen-save-CHw98Rml.png",w="/assets/ch04-img09-puttygen-save-keys-NM1Wm7kW.png",v="/assets/ch04-img10-winscp-import-session-sXjUnOBu.png",b="/assets/ch04-img11-winscp-ui-AN7pET93.png",k="/assets/ch04-img12-winscp-locations-XArMgNVV.png",S="/assets/ch04-img13-winscp-newfolder-key-CM1OfBQF.png",x="/assets/ch04-img14-winscp-upload-key-BygTVpGm.png",T="/assets/ch04-img15-winscp-rename-key-8iQ3gLs7.png",_="/assets/ch04-img16-winscp-full-B_z2QlO-.gif",P="/assets/ch04-img17-rsa-login-full-CZytVZwr.gif",I="/assets/ch04-img18-putty-privatekey-location-DW84vHHi.png",A="/assets/ch04-img19-putty-privatekey-passphrase-DQfUeTjA.png",C="/assets/ch04-img20-winscp-privatekey-location-LtQ_87aZ.png",L={},q=a(`

          [Chapter 4] Security and Protection

          4.1 Why Do We Need Security Protection?

          Security protection for Linux servers is a complex and huge subject. Countless websites, apps, services, and even offline infrastructure are built on the foundation of Linux, which involves huge economic benefits and commercial value. This also means that there is a huge motivation for black and gray industries to launch attacks. However, these services are so important that major security vulnerabilities are not allowed. Therefore, countless operation and maintenance professionals are working hard on the battlefield of security attacks and defense, which enables us to enjoy a basic stable modern digital life.

          Now, you have a VPS and will open its data access channel to achieve the goal of traffic forwarding, which means you are now on the front line of the security battle and face all risks. However, at the same time, newcomers tend to have a polarized view of security issues due to lack of knowledge and information: either they feel it is as light as a feather and has nothing to do with them, or they feel it is as heavy as Mount Tai and feel anxious all day long.

          • For the former, my suggestion is: safety is of utmost importance. Try to gather more information on safety issues to avoid regretting after experiencing losses.

          • For the latter, my suggestion is: don't worry too much, our servers still don't have too much value and generally won't attract high-level attacks. The basic threats we need to face are mostly malicious scans and login attempts from some automated scripts. Just follow this article to do some basic protection.

          4.2 What are the specific risks

          Just like the configuration we did in the "Remote Login" section, anyone who knows the four elements of [IP address] + [port] + [username] + [password] can log in to your VPS server. So obviously, the security of these four elements is the bottom line that we need to protect. Let's analyze them one by one:

          1. [IP Address]: Malicious scripts randomly attempt to scan IP ranges, which can be regarded as public information and cannot be hidden.

          2. [Port]: If you are using the default port, then [Port = 22].

          3. [Username]: If using the default user, then [Username = root]

          4. [Password]: There is no default value for the password. It must be randomly generated by the VPS backend or set by you. In other words, if all the settings of your server are default, then three of the four elements are already known. Therefore, the security of your entire server relies on a small password. In this case, there are several situations:

          • If you use a VPS management background to generate passwords randomly, it usually contains random uppercase and lowercase letters, symbols, and is relatively secure.

          • If you changed your password to something super weak like 123456 just for the sake of easy memorization, hacking into your VPS server would be a piece of cake.

          • If you change your password to a more complex one that you have used elsewhere just for the sake of easy memory, it is not really safe. You should understand that hackers have cheats in their hands, such as password tables, which contain tens of thousands, hundreds of thousands, millions, or even more real leaked passwords.

          1. But you should understand that no hacker really sits in front of a computer and tries your password repeatedly. All attack attempts are carried out automatically by malicious scripts, which work tirelessly for 24 hours. Perhaps while you are sleeping soundly every night, your server is enduring round after round of attacks.

          Once the password is successfully cracked, it means that all four of your elements have been mastered by the attacker. The malicious script will quickly log in to the server, obtain the highest root control of the server, install and deploy its malicious services, and then use your server to do all kinds of bad things 24 hours a day (such as mining, spreading viruses, sending spam emails, fraudulent emails, acting as a BT relay, and even dark web public nodes, and so on). If the malicious script is relatively restrained, it can actually achieve considerable concealment. Generally, newcomers will not observe and pay attention to indicators such as login records, process changes, CPU usage changes, and traffic changes of the VPS, so it is difficult for you to discover that you have been hacked. Until your VPS service provider blocks your account or you receive a lawyer's letter.

          1. Don't forget that when you obtain a VPS, you probably need to use your real payment information, and when you log in to various websites and social platforms, your IP address will also be recorded, which has a direct or indirect relationship with your identity. Therefore, once these bad things happen, they will inevitably be associated with you.

          4.3 What security measures do we need to take

          Based on the above analysis, what we need to do is to strengthen the three elements of [port], [username], and [password] to reduce the risk of being hacked.

          1. [Port]: Modify the SSH remote login port to a [non-22 port] (4.4).
          2. [Username]: Create a [non-root] new user and disable root user SSH remote login (4.5, 4.6).
          3. [Password]: Enable RSA key verification for SSH login and disable password verification login (4.7).

          Remember to follow the order and don't lock yourself out.

          4.4 Change the SSH Remote Login Port to a Non-22 Port

          Now, let's solve the problem of "port = 22". (Note: some VPS service providers have non-22 ports set as default, so you can ignore this step if that's the case. Of course, you can also follow this article to change it to another port.)

          1. Basic commands of Little White Linux:
          IDCommand NameDescription
          cmd-03nanoText editor
          cmd-04systemctl restartRestart a service
          1. Basic Configuration Files of Little White Linux
          NumberConfiguration File LocationFile Description
          conf-01/etc/ssh/sshd_configSSH Remote Login Program Settings
          1. The first thing we need to do, of course, is to [open the SSH remote login program settings with the text editor nano]. In Windows, you will [find the file and double-click] it. What should you do in Linux? Take a close look at the command instructions above, isn't it simple? Yes, it is:
          nano /etc/ssh/sshd_config
          +import{_ as r,r as t,o as l,c,a as o,b as s,d as e,e as a}from"./app-D7uBbsY3.js";const d="/assets/ch04-img01-nano-ui-B4Aenfjz.png",h="/assets/ch04-img02-sshd-conf-full-Dv8kUzC-.gif",u="/assets/ch04-img03-adduser-B0VGcN0p.png",p="/assets/ch04-img04-adduser-full-DgDkjVtm.gif",m="/assets/ch04-img05-sudo-full-DeKisL39.gif",g="/assets/ch04-img06-ssh-no-root-full-DZeR7uks.gif",y="/assets/ch04-img07-putty-default-user-D6pt-VE-.png",f="/assets/ch04-img08-puttygen-save-CHw98Rml.png",w="/assets/ch04-img09-puttygen-save-keys-NM1Wm7kW.png",v="/assets/ch04-img10-winscp-import-session-sXjUnOBu.png",b="/assets/ch04-img11-winscp-ui-AN7pET93.png",k="/assets/ch04-img12-winscp-locations-XArMgNVV.png",S="/assets/ch04-img13-winscp-newfolder-key-CM1OfBQF.png",x="/assets/ch04-img14-winscp-upload-key-BygTVpGm.png",T="/assets/ch04-img15-winscp-rename-key-8iQ3gLs7.png",_="/assets/ch04-img16-winscp-full-B_z2QlO-.gif",P="/assets/ch04-img17-rsa-login-full-CZytVZwr.gif",I="/assets/ch04-img18-putty-privatekey-location-DW84vHHi.png",A="/assets/ch04-img19-putty-privatekey-passphrase-DQfUeTjA.png",C="/assets/ch04-img20-winscp-privatekey-location-LtQ_87aZ.png",L={},q=a(`

          [Chapter 4] Security and Protection

          4.1 Why Do We Need Security Protection?

          Security protection for Linux servers is a complex and huge subject. Countless websites, apps, services, and even offline infrastructure are built on the foundation of Linux, which involves huge economic benefits and commercial value. This also means that there is a huge motivation for black and gray industries to launch attacks. However, these services are so important that major security vulnerabilities are not allowed. Therefore, countless operation and maintenance professionals are working hard on the battlefield of security attacks and defense, which enables us to enjoy a basic stable modern digital life.

          Now, you have a VPS and will open its data access channel to achieve the goal of traffic forwarding, which means you are now on the front line of the security battle and face all risks. However, at the same time, newcomers tend to have a polarized view of security issues due to lack of knowledge and information: either they feel it is as light as a feather and has nothing to do with them, or they feel it is as heavy as Mount Tai and feel anxious all day long.

          • For the former, my suggestion is: safety is of utmost importance. Try to gather more information on safety issues to avoid regretting after experiencing losses.

          • For the latter, my suggestion is: don't worry too much, our servers still don't have too much value and generally won't attract high-level attacks. The basic threats we need to face are mostly malicious scans and login attempts from some automated scripts. Just follow this article to do some basic protection.

          4.2 What are the specific risks

          Just like the configuration we did in the "Remote Login" section, anyone who knows the four elements of [IP address] + [port] + [username] + [password] can log in to your VPS server. So obviously, the security of these four elements is the bottom line that we need to protect. Let's analyze them one by one:

          1. [IP Address]: Malicious scripts randomly attempt to scan IP ranges, which can be regarded as public information and cannot be hidden.

          2. [Port]: If you are using the default port, then [Port = 22].

          3. [Username]: If using the default user, then [Username = root]

          4. [Password]: There is no default value for the password. It must be randomly generated by the VPS backend or set by you. In other words, if all the settings of your server are default, then three of the four elements are already known. Therefore, the security of your entire server relies on a small password. In this case, there are several situations:

          • If you use a VPS management background to generate passwords randomly, it usually contains random uppercase and lowercase letters, symbols, and is relatively secure.

          • If you changed your password to something super weak like 123456 just for the sake of easy memorization, hacking into your VPS server would be a piece of cake.

          • If you change your password to a more complex one that you have used elsewhere just for the sake of easy memory, it is not really safe. You should understand that hackers have cheats in their hands, such as password tables, which contain tens of thousands, hundreds of thousands, millions, or even more real leaked passwords.

          1. But you should understand that no hacker really sits in front of a computer and tries your password repeatedly. All attack attempts are carried out automatically by malicious scripts, which work tirelessly for 24 hours. Perhaps while you are sleeping soundly every night, your server is enduring round after round of attacks.

          Once the password is successfully cracked, it means that all four of your elements have been mastered by the attacker. The malicious script will quickly log in to the server, obtain the highest root control of the server, install and deploy its malicious services, and then use your server to do all kinds of bad things 24 hours a day (such as mining, spreading viruses, sending spam emails, fraudulent emails, acting as a BT relay, and even dark web public nodes, and so on). If the malicious script is relatively restrained, it can actually achieve considerable concealment. Generally, newcomers will not observe and pay attention to indicators such as login records, process changes, CPU usage changes, and traffic changes of the VPS, so it is difficult for you to discover that you have been hacked. Until your VPS service provider blocks your account or you receive a lawyer's letter.

          1. Don't forget that when you obtain a VPS, you probably need to use your real payment information, and when you log in to various websites and social platforms, your IP address will also be recorded, which has a direct or indirect relationship with your identity. Therefore, once these bad things happen, they will inevitably be associated with you.

          4.3 What security measures do we need to take

          Based on the above analysis, what we need to do is to strengthen the three elements of [port], [username], and [password] to reduce the risk of being hacked.

          1. [Port]: Modify the SSH remote login port to a [non-22 port] (4.4).
          2. [Username]: Create a [non-root] new user and disable root user SSH remote login (4.5, 4.6).
          3. [Password]: Enable RSA key verification for SSH login and disable password verification login (4.7).

          Remember to follow the order and don't lock yourself out.

          4.4 Change the SSH Remote Login Port to a Non-22 Port

          Now, let's solve the problem of "port = 22". (Note: some VPS service providers have non-22 ports set as default, so you can ignore this step if that's the case. Of course, you can also follow this article to change it to another port.)

          1. Basic commands of Little White Linux:
          IDCommand NameDescription
          cmd-03nanoText editor
          cmd-04systemctl restartRestart a service
          1. Basic Configuration Files of Little White Linux
          NumberConfiguration File LocationFile Description
          conf-01/etc/ssh/sshd_configSSH Remote Login Program Settings
          1. The first thing we need to do, of course, is to [open the SSH remote login program settings with the text editor nano]. In Windows, you will [find the file and double-click] it. What should you do in Linux? Take a close look at the command instructions above, isn't it simple? Yes, it is:
          nano /etc/ssh/sshd_config
           

          This is a command in the shell terminal to open the sshd_config file located in the /etc/ssh/ directory using the nano text editor.

          1. Once the file is opened, you will enter the interface of nano. After observing for a while, you will find that it displays important shortcut keys at the bottom of the screen (enclosed in a red box in the figure below). You can take the exam directly without memorizing them, which is very user-friendly, isn't it?

          Interface of nano

          1. The second thing we need to do is to find the Port item in the opened file and modify its port. The number after Port is the SSH port. It is generally recommended to change it to an integer greater than 1024 and less than 65535 (this article takes 9753 as an example). Please think about how to operate it with the shortcut keys of nano. You are right again! It is:
          • Use ctrl+w to enter search mode, then type Port 22 and press Enter
          • Delete 22 and replace it with 9753
          • Note: If this line starts with #, it means that this line is [commented out] and [does not take effect]. You can write a new line at the end of the file without #, or delete the # to enable this line.

          Warning

          This article uses 9753 as an example, which means that with the release of this article, this port will become a feature that may be prioritized or blocked by attackers or the Great Firewall of China. Therefore, I strongly recommend that you use another port that you come up with yourself, after all, you have over 60,000 ports to choose from freely.

          1. The third thing we need to do is to [save the file and exit].
          • If you observed carefully in step 3, you would have noticed that saving is not done by the common ctrl+s.
          • The correct shortcut keys: save is ctrl+o + enter, and exit is ctrl+x.
          • (For some operating systems) Add a firewall rule to set the new SSH port, otherwise, you won't be able to log in via SSH after the instance restarts.
          • For example, on Ubuntu using ufw.
          sudo ufw allow 9753/tcp
           
          1. The last thing we need to do is to [restart the SSH service to make the changes take effect].
          systemctl restart ssh
           

          Then you can try opening a new session in your SSH software to check if you can connect. If there are any issues, you can modify the configuration through the old SSH session (SSH connections that are already open will not be closed when restarting sshd).

          1. The complete process demonstration is as follows:

          Demonstration of modifying non-22 port

          1. Modify PuTTY Configuration

          "Now that the new port is in effect, you will need to use 9753 the next time you log in with PuTTY. So please go to the PuTTY settings to change the port number and save the session. Well, you should know where to change it, right? (If you don't know, you need to reread the previous content!)"

          4.5 Creating a New User Without Root Access

          In the second step, let's solve the issue of the username being root.

          Firstly, you need to understand that root in Linux system is not just a simple administrator account. It is the foundation of the entire system, the ruler and the supreme god of the system. Once the root account has security issues, the entire system will be vulnerable and there will be nowhere to hide. So, let's follow me to carry out the operations:

          1. Little White Linux Basic Commands:
          NumberCommand NameCommand Description
          cmd-05adduserAdd new user to the system
          cmd-06apt installInstall a software package
          cmd-07visudoSpecial editor to modify sudo permission settings
          1. The first thing we need to do is to [add a new user and set a login password]. You can choose any name you want, here I will use vpsadmin as an example:
          adduser vpsadmin
          diff --git a/assets/ch04-security.html-UQusRUO6.js b/assets/ch04-security.html-Odh5MrhM.js
          similarity index 99%
          rename from assets/ch04-security.html-UQusRUO6.js
          rename to assets/ch04-security.html-Odh5MrhM.js
          index 47068275bc..2bf44b143b 100644
          --- a/assets/ch04-security.html-UQusRUO6.js
          +++ b/assets/ch04-security.html-Odh5MrhM.js
          @@ -1,4 +1,4 @@
          -import{_ as l,r as o,o as c,c as a,a as d,b as e,d as t,e as s}from"./app-DBM4OJyw.js";const p="/assets/ch04-img01-nano-ui-B4Aenfjz.png",r="/assets/ch04-img02-sshd-conf-full-Dv8kUzC-.gif",g="/assets/ch04-img03-adduser-B0VGcN0p.png",u="/assets/ch04-img04-adduser-full-DgDkjVtm.gif",h="/assets/ch04-img05-sudo-full-DeKisL39.gif",m="/assets/ch04-img06-ssh-no-root-full-DZeR7uks.gif",S="/assets/ch04-img07-putty-default-user-D6pt-VE-.png",_="/assets/ch04-img08-puttygen-save-CHw98Rml.png",v="/assets/ch04-img09-puttygen-save-keys-NM1Wm7kW.png",b="/assets/ch04-img10-winscp-import-session-sXjUnOBu.png",f="/assets/ch04-img11-winscp-ui-AN7pET93.png",y="/assets/ch04-img12-winscp-locations-XArMgNVV.png",x="/assets/ch04-img13-winscp-newfolder-key-CM1OfBQF.png",P="/assets/ch04-img14-winscp-upload-key-BygTVpGm.png",k="/assets/ch04-img15-winscp-rename-key-8iQ3gLs7.png",T="/assets/ch04-img16-winscp-full-B_z2QlO-.gif",H="/assets/ch04-img17-rsa-login-full-CZytVZwr.gif",L="/assets/ch04-img18-putty-privatekey-location-DW84vHHi.png",C="/assets/ch04-img19-putty-privatekey-passphrase-DQfUeTjA.png",V="/assets/ch04-img20-winscp-privatekey-location-LtQ_87aZ.png",w={},A=s(`

          【Глава 4】 Обеспечение безопасности

          4.1 Зачем нужна безопасность?

          Безопасность Linux-серверов — это обширная и сложная тема. Бесчисленные веб-сайты, приложения, сервисы и даже критически важная инфраструктура построены на базе Linux. За всем этим стоят огромные деньги и коммерческие интересы, что, естественно, привлекает злоумышленников. В то же время надёжная работа этих сервисов крайне важна, поэтому любые серьёзные уязвимости недопустимы. Именно поэтому множество специалистов по безопасности изо дня в день ведут борьбу на передовой, обеспечивая стабильную работу цифрового мира, к которому мы все привыкли.

          Теперь, когда у вас есть собственный VPS-сервер, и вы собираетесь открыть на нём порты для перенаправления трафика, вы фактически оказываетесь на передовой этой борьбы и подвергаетесь тем же рискам. В то же время, новички, не обладающие достаточными знаниями и информацией, склонны впадать в крайности: либо они считают, что им ничего не угрожает, либо же, наоборот, впадают в паранойю.

          • Первым я бы посоветовал не относиться к безопасности легкомысленно и изучить этот вопрос более подробно, чтобы потом не пришлось кусать локти.

          • Вторым я бы посоветовал не паниковать. Ваш сервер вряд ли представляет собой лакомую цель для серьёзных злоумышленников, поэтому вам достаточно базовых мер защиты от автоматических сканеров и ботов, о которых мы и поговорим в этой главе.

          4.2 Какие именно риски существуют?

          Как мы уже говорили в главе про удалённое подключение, для доступа к вашему VPS достаточно знать четыре вещи: IP-адрес, порт, имя пользователя и пароль. Очевидно, что эти четыре элемента нужно защищать в первую очередь. Давайте разберём каждый из них:

          1. IP-адрес: злоумышленники могут сканировать целые диапазоны IP-адресов в поисках уязвимых серверов. Ваш IP-адрес — это публичная информация, которую невозможно скрыть.

          2. Порт: если вы используете настройки по умолчанию, то порт SSH равен 22.

          3. Имя пользователя: если вы используете настройки по умолчанию, то имя пользователя — root.

          4. Пароль: пароль не имеет значения по умолчанию. Он либо генерируется автоматически при создании VPS, либо задаётся вами. Таким образом, если вы не меняли настройки сервера, то три из четырёх элементов уже известны злоумышленникам, и вся безопасность вашего сервера держится на одном только пароле. Возможны следующие варианты:

            • Вы используете автоматически сгенерированный пароль из панели управления VPS. Такие пароли обычно состоят из случайного набора символов (букв в разных регистрах, цифр и спецсимволов) и достаточно надёжны.

            • Вы установили простой пароль, например, 123456. Взломать такой сервер не составит труда.

            • Вы установили сложный пароль, который используете где-то ещё. Это тоже небезопасно. Злоумышленники используют специальные программы, которые перебирают миллионы ранее скомпрометированных паролей из утечек данных.

          5. Важно понимать, что никакой хакер не будет лично подбирать ваш пароль. Все атаки выполняются автоматически с помощью специальных скриптов, которые работают круглосуточно. Пока вы спите, ваш сервер может подвергаться атакам.

            Если пароль будет подобран, злоумышленники получат полный доступ к вашему серверу (права пользователя root), смогут установить на него вредоносное ПО и использовать его в своих целях (например, для майнинга криптовалюты, рассылки спама, фишинговых атак, организации торрент-трекера, размещения публичных узлов для доступа к даркнету и т.д.). При этом злоумышленники могут действовать очень скрытно, и вы даже не заметите, что ваш сервер взломан, пока не получите уведомление от хостинг-провайдера о блокировке вашего аккаунта или, что ещё хуже, повестку в суд.

          6. Не забывайте, что при покупке VPS вы, скорее всего, указывали свои реальные платёжные данные. А при посещении сайтов и использовании социальных сетей ваш IP-адрес также сохраняется. Всё это может быть использовано против вас. Поэтому, если на вашем сервере произойдёт что-то противозаконное, отвечать за это придётся вам.

          4.3 Какие меры безопасности нужно предпринять?

          Исходя из всего вышесказанного, нам нужно защитить порт, имя пользователя и пароль, чтобы снизить риск взлома. Для этого необходимо:

          1. Изменить порт SSH на нестандартный (отличный от 22) (см. раздел 4.4).
          2. Создать нового пользователя (не root) и запретить удалённое подключение по SSH для пользователя root (см. разделы 4.5 и 4.6).
          3. Настроить аутентификацию по SSH-ключам и запретить аутентификацию по паролю (см. раздел 4.7).

          Выполняйте эти действия по порядку, чтобы не оказаться случайно заблокированным на своём же сервере.

          4.4 Изменение порта SSH

          Давайте решим проблему с портом SSH, который по умолчанию равен 22 (обратите внимание: у некоторых хостинг-провайдеров порт SSH по умолчанию уже отличается от 22. В этом случае вы можете пропустить этот шаг, но можете и изменить порт ещё раз, следуя инструкциям ниже).

          1. Базовые команды Linux:

            НомерКомандаОписание
            cmd-03nanoТекстовый редактор
            cmd-04systemctl restartПерезапуск службы
          2. Важные файлы конфигурации Linux:

            НомерПуть к файлуОписание
            conf-01/etc/ssh/sshd_configНастройки SSH-сервера
          3. Первое, что нужно сделать, — это открыть файл настроек SSH-сервера (/etc/ssh/sshd_config) в текстовом редакторе nano. В Windows вы бы просто нашли этот файл и дважды кликнули по нему. А как это сделать в Linux? Если вы внимательно читали предыдущие разделы, то наверняка уже догадались! Правильно, нужно выполнить команду:

            nano /etc/ssh/sshd_config
            +import{_ as l,r as o,o as c,c as a,a as d,b as e,d as t,e as s}from"./app-D7uBbsY3.js";const p="/assets/ch04-img01-nano-ui-B4Aenfjz.png",r="/assets/ch04-img02-sshd-conf-full-Dv8kUzC-.gif",g="/assets/ch04-img03-adduser-B0VGcN0p.png",u="/assets/ch04-img04-adduser-full-DgDkjVtm.gif",h="/assets/ch04-img05-sudo-full-DeKisL39.gif",m="/assets/ch04-img06-ssh-no-root-full-DZeR7uks.gif",S="/assets/ch04-img07-putty-default-user-D6pt-VE-.png",_="/assets/ch04-img08-puttygen-save-CHw98Rml.png",v="/assets/ch04-img09-puttygen-save-keys-NM1Wm7kW.png",b="/assets/ch04-img10-winscp-import-session-sXjUnOBu.png",f="/assets/ch04-img11-winscp-ui-AN7pET93.png",y="/assets/ch04-img12-winscp-locations-XArMgNVV.png",x="/assets/ch04-img13-winscp-newfolder-key-CM1OfBQF.png",P="/assets/ch04-img14-winscp-upload-key-BygTVpGm.png",k="/assets/ch04-img15-winscp-rename-key-8iQ3gLs7.png",T="/assets/ch04-img16-winscp-full-B_z2QlO-.gif",H="/assets/ch04-img17-rsa-login-full-CZytVZwr.gif",L="/assets/ch04-img18-putty-privatekey-location-DW84vHHi.png",C="/assets/ch04-img19-putty-privatekey-passphrase-DQfUeTjA.png",V="/assets/ch04-img20-winscp-privatekey-location-LtQ_87aZ.png",w={},A=s(`

            【Глава 4】 Обеспечение безопасности

            4.1 Зачем нужна безопасность?

            Безопасность Linux-серверов — это обширная и сложная тема. Бесчисленные веб-сайты, приложения, сервисы и даже критически важная инфраструктура построены на базе Linux. За всем этим стоят огромные деньги и коммерческие интересы, что, естественно, привлекает злоумышленников. В то же время надёжная работа этих сервисов крайне важна, поэтому любые серьёзные уязвимости недопустимы. Именно поэтому множество специалистов по безопасности изо дня в день ведут борьбу на передовой, обеспечивая стабильную работу цифрового мира, к которому мы все привыкли.

            Теперь, когда у вас есть собственный VPS-сервер, и вы собираетесь открыть на нём порты для перенаправления трафика, вы фактически оказываетесь на передовой этой борьбы и подвергаетесь тем же рискам. В то же время, новички, не обладающие достаточными знаниями и информацией, склонны впадать в крайности: либо они считают, что им ничего не угрожает, либо же, наоборот, впадают в паранойю.

            • Первым я бы посоветовал не относиться к безопасности легкомысленно и изучить этот вопрос более подробно, чтобы потом не пришлось кусать локти.

            • Вторым я бы посоветовал не паниковать. Ваш сервер вряд ли представляет собой лакомую цель для серьёзных злоумышленников, поэтому вам достаточно базовых мер защиты от автоматических сканеров и ботов, о которых мы и поговорим в этой главе.

            4.2 Какие именно риски существуют?

            Как мы уже говорили в главе про удалённое подключение, для доступа к вашему VPS достаточно знать четыре вещи: IP-адрес, порт, имя пользователя и пароль. Очевидно, что эти четыре элемента нужно защищать в первую очередь. Давайте разберём каждый из них:

            1. IP-адрес: злоумышленники могут сканировать целые диапазоны IP-адресов в поисках уязвимых серверов. Ваш IP-адрес — это публичная информация, которую невозможно скрыть.

            2. Порт: если вы используете настройки по умолчанию, то порт SSH равен 22.

            3. Имя пользователя: если вы используете настройки по умолчанию, то имя пользователя — root.

            4. Пароль: пароль не имеет значения по умолчанию. Он либо генерируется автоматически при создании VPS, либо задаётся вами. Таким образом, если вы не меняли настройки сервера, то три из четырёх элементов уже известны злоумышленникам, и вся безопасность вашего сервера держится на одном только пароле. Возможны следующие варианты:

              • Вы используете автоматически сгенерированный пароль из панели управления VPS. Такие пароли обычно состоят из случайного набора символов (букв в разных регистрах, цифр и спецсимволов) и достаточно надёжны.

              • Вы установили простой пароль, например, 123456. Взломать такой сервер не составит труда.

              • Вы установили сложный пароль, который используете где-то ещё. Это тоже небезопасно. Злоумышленники используют специальные программы, которые перебирают миллионы ранее скомпрометированных паролей из утечек данных.

            5. Важно понимать, что никакой хакер не будет лично подбирать ваш пароль. Все атаки выполняются автоматически с помощью специальных скриптов, которые работают круглосуточно. Пока вы спите, ваш сервер может подвергаться атакам.

              Если пароль будет подобран, злоумышленники получат полный доступ к вашему серверу (права пользователя root), смогут установить на него вредоносное ПО и использовать его в своих целях (например, для майнинга криптовалюты, рассылки спама, фишинговых атак, организации торрент-трекера, размещения публичных узлов для доступа к даркнету и т.д.). При этом злоумышленники могут действовать очень скрытно, и вы даже не заметите, что ваш сервер взломан, пока не получите уведомление от хостинг-провайдера о блокировке вашего аккаунта или, что ещё хуже, повестку в суд.

            6. Не забывайте, что при покупке VPS вы, скорее всего, указывали свои реальные платёжные данные. А при посещении сайтов и использовании социальных сетей ваш IP-адрес также сохраняется. Всё это может быть использовано против вас. Поэтому, если на вашем сервере произойдёт что-то противозаконное, отвечать за это придётся вам.

            4.3 Какие меры безопасности нужно предпринять?

            Исходя из всего вышесказанного, нам нужно защитить порт, имя пользователя и пароль, чтобы снизить риск взлома. Для этого необходимо:

            1. Изменить порт SSH на нестандартный (отличный от 22) (см. раздел 4.4).
            2. Создать нового пользователя (не root) и запретить удалённое подключение по SSH для пользователя root (см. разделы 4.5 и 4.6).
            3. Настроить аутентификацию по SSH-ключам и запретить аутентификацию по паролю (см. раздел 4.7).

            Выполняйте эти действия по порядку, чтобы не оказаться случайно заблокированным на своём же сервере.

            4.4 Изменение порта SSH

            Давайте решим проблему с портом SSH, который по умолчанию равен 22 (обратите внимание: у некоторых хостинг-провайдеров порт SSH по умолчанию уже отличается от 22. В этом случае вы можете пропустить этот шаг, но можете и изменить порт ещё раз, следуя инструкциям ниже).

            1. Базовые команды Linux:

              НомерКомандаОписание
              cmd-03nanoТекстовый редактор
              cmd-04systemctl restartПерезапуск службы
            2. Важные файлы конфигурации Linux:

              НомерПуть к файлуОписание
              conf-01/etc/ssh/sshd_configНастройки SSH-сервера
            3. Первое, что нужно сделать, — это открыть файл настроек SSH-сервера (/etc/ssh/sshd_config) в текстовом редакторе nano. В Windows вы бы просто нашли этот файл и дважды кликнули по нему. А как это сделать в Linux? Если вы внимательно читали предыдущие разделы, то наверняка уже догадались! Правильно, нужно выполнить команду:

              nano /etc/ssh/sshd_config
               
            4. После открытия файла вы увидите интерфейс редактора nano. Обратите внимание на нижнюю часть экрана, где перечислены основные горячие клавиши (на скриншоте ниже выделены красной рамкой). Не нужно ничего заучивать, всё необходимое всегда перед глазами!

              Интерфейс nano

            1. Второе, что нужно сделать, — это найти строку, начинающуюся с Port, и изменить номер порта. Число после Port — это номер порта SSH. Рекомендуется использовать число в диапазоне от 1024 до 65535 (в этой статье мы будем использовать порт 9753). Как это сделать, используя горячие клавиши nano? Вы уже наверняка догадались!

              • Нажмите Ctrl+W, чтобы открыть поиск, введите Port 22 и нажмите Enter.
              • Замените 22 на 9753.
              • Примечание: если в начале строки стоит символ #, значит, эта строка закомментирована и не будет применяться. Вы можете либо раскомментировать её (удалив #), либо добавить новую строку без # в конце файла, как показано на скриншоте.

              Внимание

              Использование порта 9753 в этой статье делает его менее безопасным, поскольку злоумышленники могут начать сканировать этот порт в первую очередь. Кроме того, этот порт может быть заблокирован некоторыми провайдерами. Поэтому настоятельно рекомендуем использовать другой порт. У вас в распоряжении более 60 тысяч портов, так что выбрать есть из чего.

            1. Третье, что нужно сделать, — это сохранить изменения и выйти из редактора.

              • Как вы уже могли заметить, для сохранения файла используется не Ctrl+S, как в большинстве программ.
              • Горячие клавиши: Ctrl+O — сохранить, Ctrl+X — выйти.
            • Добавьте новое правило в брандмауэр, чтобы открыть новый порт SSH. В противном случае, после перезагрузки инстанса, подключение по SSH будет недоступно.

            • Пример для Ubuntu с использованием ufw:

              sudo ufw allow 9753/tcp
               
            1. И последнее, что нужно сделать, — это перезапустить SSH-сервер, чтобы изменения вступили в силу.

              systemctl restart ssh
               

            Затем можно попробовать открыть новую сессию в SSH-клиенте и проверить подключение. Если возникнут проблемы, можно изменить конфигурацию в старой SSH-сессии (открытые SSH-соединения не будут разорваны при перезапуске службы SSHD).

            1. Весь процесс показан на гифке ниже:

              Изменение порта SSH

            2. Изменение настроек PuTTY

              Теперь, когда вы изменили порт SSH, вам нужно указать новый порт (9753) в настройках PuTTY. Вы ведь помните, где это делается? (Если нет, вернитесь и перечитайте предыдущие разделы!)

            4.5 Создание нового пользователя

            Перейдём ко второму шагу — избавлению от пользователя root.

            Прежде всего, нужно понимать, что пользователь root в Linux — это не просто администратор. Это корень системы, её основа, верховный правитель. Если безопасность учётной записи root будет нарушена, под угрозой окажется вся система.

            1. Базовые команды Linux:

              НомерКомандаОписание
              cmd-05adduserДобавление нового пользователя
              cmd-06apt installУстановка программного обеспечения
              cmd-07visudoРедактор файла sudoers
            2. Первое, что нужно сделать, — это создать нового пользователя и установить для него пароль. Имя пользователя может быть любым, в этой статье мы будем использовать имя vpsadmin.

              adduser vpsadmin
              diff --git a/assets/ch05-webpage.html-CE51MwWG.js b/assets/ch05-webpage.html-BX0vFLsv.js
              similarity index 99%
              rename from assets/ch05-webpage.html-CE51MwWG.js
              rename to assets/ch05-webpage.html-BX0vFLsv.js
              index aa2255f360..bf9dcf07bf 100644
              --- a/assets/ch05-webpage.html-CE51MwWG.js
              +++ b/assets/ch05-webpage.html-BX0vFLsv.js
              @@ -1,4 +1,4 @@
              -import{_ as a,r as s,o as t,c as e,a as o,e as i}from"./app-DBM4OJyw.js";const p="/assets/ch05-img01-nginx-default-running-C4PeIKwj.png",l="/assets/ch05-img02-nginx-conf-full-C_TeO_k2.gif",c="/assets/ch05-img03-nginx-http-running-CYGBxUEw.png",u={},r=i(`

              Chapter 5: Website Building

              5.1 Why should you create a website?

              Some newcomers may be confused: why do I need to build a website for securing an open digital environment? I don't know how to code! Isn't it very complicated?

              First, let's answer the first question. The reasons for building a website are:

              1. Apply for a legitimate TLS certificate (very important)
              2. Provide reasonable fallback to prevent active probing attacks and improve security
              3. Set up a camouflage site (such as a blog, private cloud storage, multimedia site, game site, etc.) with a reasonable frontend when directly accessed, making traffic usage look more legitimate.

              Now let's answer the second question:

              1. As a demonstration, this article uses only the simplest "single-file HTML page + Nginx" setup to achieve the above objectives, so it is very easy.
              2. This website can not only be used for camouflage but also for real development and growth. The complexity depends entirely on you.
              3. For the goals of "camouflage" and "website operation", uniqueness and personalization are needed. Students who need this can search and learn by themselves. This content has completely deviated from scientific online access, so this article will not go into depth.

              5.2 Log in to VPS, install and run Nginx

              1. Here we use commands that have been explained in detail before, so they won't be repeated. If you don't understand, please refer to the previous chapters.

                sudo apt update && sudo apt install nginx
                +import{_ as a,r as s,o as t,c as e,a as o,e as i}from"./app-D7uBbsY3.js";const p="/assets/ch05-img01-nginx-default-running-C4PeIKwj.png",l="/assets/ch05-img02-nginx-conf-full-C_TeO_k2.gif",c="/assets/ch05-img03-nginx-http-running-CYGBxUEw.png",u={},r=i(`

                Chapter 5: Website Building

                5.1 Why should you create a website?

                Some newcomers may be confused: why do I need to build a website for securing an open digital environment? I don't know how to code! Isn't it very complicated?

                First, let's answer the first question. The reasons for building a website are:

                1. Apply for a legitimate TLS certificate (very important)
                2. Provide reasonable fallback to prevent active probing attacks and improve security
                3. Set up a camouflage site (such as a blog, private cloud storage, multimedia site, game site, etc.) with a reasonable frontend when directly accessed, making traffic usage look more legitimate.

                Now let's answer the second question:

                1. As a demonstration, this article uses only the simplest "single-file HTML page + Nginx" setup to achieve the above objectives, so it is very easy.
                2. This website can not only be used for camouflage but also for real development and growth. The complexity depends entirely on you.
                3. For the goals of "camouflage" and "website operation", uniqueness and personalization are needed. Students who need this can search and learn by themselves. This content has completely deviated from scientific online access, so this article will not go into depth.

                5.2 Log in to VPS, install and run Nginx

                1. Here we use commands that have been explained in detail before, so they won't be repeated. If you don't understand, please refer to the previous chapters.

                  sudo apt update && sudo apt install nginx
                   
                2. After completion, Nginx will automatically run. Open the browser on Windows and enter http://100.200.300.400:80. If you see the interface shown below, it means Nginx is running normally.

                  Nginx default interface

                5.3 Create the simplest web page

                1. Basic Linux commands for beginners:

                  No.Command NameCommand Description
                  cmd-10mkdirCreate a new folder
                  cmd-11systemctl reloadReload a specific service
                2. Basic Linux configuration files for beginners:

                  No.Configuration File LocationFile Description
                  conf-02/etc/nginx/nginx.confNginx program settings
                3. Create a dedicated folder /home/vpsadmin/www/webpage/ for the website and create the web page file index.html

                  mkdir -p ~/www/webpage/ && nano ~/www/webpage/index.html
                   

                Warning

                If you are not using the username vpsadmin, please be sure to understand the meaning of the "~" symbol in this command (this is related to Step 5 content):

                • If it is a non-root user, "~" is equivalent to /home/username
                • If it is a root user, "~" is equivalent to /root
                1. Copy the entire content below, save (ctrl+o) and exit (ctrl+x).

                  <html lang="">
                     <!-- Text between angle brackets is an HTML tag and is not displayed.
                  diff --git a/assets/ch05-webpage.html-d_ZCA_oR.js b/assets/ch05-webpage.html-D5rnT9ca.js
                  similarity index 99%
                  rename from assets/ch05-webpage.html-d_ZCA_oR.js
                  rename to assets/ch05-webpage.html-D5rnT9ca.js
                  index ae22e72c42..a2f08858be 100644
                  --- a/assets/ch05-webpage.html-d_ZCA_oR.js
                  +++ b/assets/ch05-webpage.html-D5rnT9ca.js
                  @@ -1,4 +1,4 @@
                  -import{_ as a,r as s,o as t,c as e,a as p,e as l}from"./app-DBM4OJyw.js";const c="/assets/ch05-img01-nginx-default-running-C4PeIKwj.png",i="/assets/ch05-img02-nginx-conf-full-C_TeO_k2.gif",o="/assets/ch05-img03-nginx-http-running-CYGBxUEw.png",d={},u=l(`

                  【第 5 章】网站建设篇

                  5.1 为什么要做一个网站?

                  新人也许会迷惑,为什么科学上网还要建一个网站?我不会编程啊,是不是特别麻烦?

                  先回答第一个问题,建网站的原因有:

                  1. 申请合法的 TLS 证书(非常重要)
                  2. 提供合理的回落,防止主动探测攻击,提高安全性
                  3. 建设一个伪装站(如博客、私人网盘、多媒体网站、游戏网站等),直接访问时有合理的前台,使流量使用看上去更合理。

                  再回答第二个问题:

                  1. 本文作为演示,仅仅使用了一个最简单的【单文件 html 页面 + Nginx】来搭建,以此完成上面的目标,所以【非常简单】
                  2. 这个网站完全可以不仅仅是伪装,而是真的做大做强,这个复杂性就完全取决于你了
                  3. 对于“伪装”和“网站运营”这个目标,需要的就是各不相同、秀出真我,需要的同学可以自行搜索学习。这个内容已经完全偏离了科学上网,本文就不深入解析了。

                  5.2 登录 VPS、安装运行 Nginx

                  1. 这里用到的,都是之前已经详解过的命令,所以就不重复讲解了。看不懂的同学可以看看前面的章节哦。

                    sudo apt update && sudo apt install nginx
                    +import{_ as a,r as s,o as t,c as e,a as p,e as l}from"./app-D7uBbsY3.js";const c="/assets/ch05-img01-nginx-default-running-C4PeIKwj.png",i="/assets/ch05-img02-nginx-conf-full-C_TeO_k2.gif",o="/assets/ch05-img03-nginx-http-running-CYGBxUEw.png",d={},u=l(`

                    【第 5 章】网站建设篇

                    5.1 为什么要做一个网站?

                    新人也许会迷惑,为什么科学上网还要建一个网站?我不会编程啊,是不是特别麻烦?

                    先回答第一个问题,建网站的原因有:

                    1. 申请合法的 TLS 证书(非常重要)
                    2. 提供合理的回落,防止主动探测攻击,提高安全性
                    3. 建设一个伪装站(如博客、私人网盘、多媒体网站、游戏网站等),直接访问时有合理的前台,使流量使用看上去更合理。

                    再回答第二个问题:

                    1. 本文作为演示,仅仅使用了一个最简单的【单文件 html 页面 + Nginx】来搭建,以此完成上面的目标,所以【非常简单】
                    2. 这个网站完全可以不仅仅是伪装,而是真的做大做强,这个复杂性就完全取决于你了
                    3. 对于“伪装”和“网站运营”这个目标,需要的就是各不相同、秀出真我,需要的同学可以自行搜索学习。这个内容已经完全偏离了科学上网,本文就不深入解析了。

                    5.2 登录 VPS、安装运行 Nginx

                    1. 这里用到的,都是之前已经详解过的命令,所以就不重复讲解了。看不懂的同学可以看看前面的章节哦。

                      sudo apt update && sudo apt install nginx
                       
                    2. 完成后,Nginx 已经自动运行。此时打开 Windows 上的浏览器并输入 http://100.200.300.400:80,若看到下图的界面就说明 Nginx 已经正常在运行了。

                      Nginx默认界面

                    3. 如果无法看到上述Nginx默认页面,可能是需要配置Debian系统上默认的防火墙组件Uncomplicated Firewall (UFW),以便启用 HTTP (80) 和 HTTPS (443) 端口流量。

                      a. 验证方法,输入:

                      sudo ufw status
                       

                      b. 如果输出如下,表明80和433端口未开启,需要执行c步骤

                      Status: active
                       To                         Action      From
                      diff --git a/assets/ch05-webpage.html-DzMKIlk9.js b/assets/ch05-webpage.html-yQkzjvqw.js
                      similarity index 99%
                      rename from assets/ch05-webpage.html-DzMKIlk9.js
                      rename to assets/ch05-webpage.html-yQkzjvqw.js
                      index 1c454d0bbf..0aaafb66de 100644
                      --- a/assets/ch05-webpage.html-DzMKIlk9.js
                      +++ b/assets/ch05-webpage.html-yQkzjvqw.js
                      @@ -1,4 +1,4 @@
                      -import{_ as a,r as s,o as t,c as e,a as p,e as l}from"./app-DBM4OJyw.js";const i="/assets/ch05-img01-nginx-default-running-C4PeIKwj.png",o="/assets/ch05-img02-nginx-conf-full-C_TeO_k2.gif",c="/assets/ch05-img03-nginx-http-running-CYGBxUEw.png",d={},u=l(`

                      【Глава 5】 Создание веб-сайта

                      5.1 Зачем нужен веб-сайт?

                      Начинающие пользователи могут задаться вопросом: зачем создавать веб-сайт для обхода блокировок? Я не программист, это же сложно?

                      Начнём с первого вопроса. Веб-сайт нужен для того, чтобы:

                      1. Получить действующий SSL-сертификат (это очень важно).
                      2. Обеспечить маскировку трафика (fallback) и защититься от атак, направленных на выявление VPN-серверов.
                      3. Создать сайт-прикрытие (например, блог, облачное хранилище, медиа-портал, игровой сайт), который будет отображаться при прямом доступе к серверу, делая использование VPN менее заметным.

                      Теперь ответим на второй вопрос:

                      1. В этой статье мы создадим максимально простой веб-сайт, состоящий из одного HTML-файла и работающий на веб-сервере Nginx, чтобы решить поставленные выше задачи. Это очень просто.
                      2. Этот веб-сайт не обязательно должен быть просто прикрытием. Вы можете развивать его и превратить в полноценный проект. Всё зависит от ваших желаний и возможностей.
                      3. Создание сайта-прикрытия и его продвижение — это отдельная большая тема, которая выходит за рамки этой статьи. Если вам интересно, вы можете найти информацию об этом в интернете.

                      5.2 Подключение к VPS и установка Nginx

                      1. В этом разделе мы будем использовать команды, которые уже были подробно рассмотрены ранее. Если вы что-то не понимаете, вернитесь и перечитайте предыдущие главы.

                        sudo apt update && sudo apt install nginx
                        +import{_ as a,r as s,o as t,c as e,a as p,e as l}from"./app-D7uBbsY3.js";const i="/assets/ch05-img01-nginx-default-running-C4PeIKwj.png",o="/assets/ch05-img02-nginx-conf-full-C_TeO_k2.gif",c="/assets/ch05-img03-nginx-http-running-CYGBxUEw.png",d={},u=l(`

                        【Глава 5】 Создание веб-сайта

                        5.1 Зачем нужен веб-сайт?

                        Начинающие пользователи могут задаться вопросом: зачем создавать веб-сайт для обхода блокировок? Я не программист, это же сложно?

                        Начнём с первого вопроса. Веб-сайт нужен для того, чтобы:

                        1. Получить действующий SSL-сертификат (это очень важно).
                        2. Обеспечить маскировку трафика (fallback) и защититься от атак, направленных на выявление VPN-серверов.
                        3. Создать сайт-прикрытие (например, блог, облачное хранилище, медиа-портал, игровой сайт), который будет отображаться при прямом доступе к серверу, делая использование VPN менее заметным.

                        Теперь ответим на второй вопрос:

                        1. В этой статье мы создадим максимально простой веб-сайт, состоящий из одного HTML-файла и работающий на веб-сервере Nginx, чтобы решить поставленные выше задачи. Это очень просто.
                        2. Этот веб-сайт не обязательно должен быть просто прикрытием. Вы можете развивать его и превратить в полноценный проект. Всё зависит от ваших желаний и возможностей.
                        3. Создание сайта-прикрытия и его продвижение — это отдельная большая тема, которая выходит за рамки этой статьи. Если вам интересно, вы можете найти информацию об этом в интернете.

                        5.2 Подключение к VPS и установка Nginx

                        1. В этом разделе мы будем использовать команды, которые уже были подробно рассмотрены ранее. Если вы что-то не понимаете, вернитесь и перечитайте предыдущие главы.

                          sudo apt update && sudo apt install nginx
                           
                        2. После завершения установки Nginx запустится автоматически. Откройте браузер на своём компьютере и введите адрес http://100.200.300.400:80. Если вы увидите страницу, как на скриншоте ниже, значит, Nginx работает.

                          Стандартная страница Nginx

                        3. Если вы не видите страницу Nginx, возможно, вам нужно настроить Uncomplicated Firewall (UFW), стандартный брандмауэр в Debian, чтобы разрешить трафик на портах HTTP (80) и HTTPS (443).

                          a. Чтобы проверить, введите:

                          sudo ufw status
                           

                          b. Если вывод команды такой, как показано ниже, это означает, что порты 80 и 443 закрыты. Выполните действия, описанные в пункте c.

                          Status: active
                           To                         Action      From
                          diff --git a/assets/ch06-certificates.html-bt0w3WX5.js b/assets/ch06-certificates.html-B4kZdJAn.js
                          similarity index 99%
                          rename from assets/ch06-certificates.html-bt0w3WX5.js
                          rename to assets/ch06-certificates.html-B4kZdJAn.js
                          index b5c3e369de..befc3ef154 100644
                          --- a/assets/ch06-certificates.html-bt0w3WX5.js
                          +++ b/assets/ch06-certificates.html-B4kZdJAn.js
                          @@ -1,4 +1,4 @@
                          -import{_ as c,r as s,o as p,c as l,a,b as n,d as e,e as t}from"./app-DBM4OJyw.js";const r="/assets/ch06-img01-acme-install-Dowds3tU.gif",d={},u=t('

                          [Chapter 6] Certificate Management

                          6.1 Applying for a TLS Certificate

                          Next, we need to apply for a real TLS certificate for our domain name, so that the website has the ability to encrypt with standard TLS and the ability to access via HTTPS. This is the most important tool for Xray and other current security proxy tools to ensure fully encrypted traffic.

                          Warning

                          Please do not use self-signed certificates lightly. It does not make the operation much simpler, but adds unnecessary risks (such as man-in-the-middle attacks).

                          ',4),m={href:"https://github.com/acmesh-official/acme.sh",target:"_blank",rel:"noopener noreferrer"},b=n("code",null,"acme.sh",-1),k=t(`

                          In addition, I believe that you have gradually become familiar with the basic operations of Linux. Therefore, from this chapter on, commands that have appeared multiple times will no longer have screenshots and will only be briefly described. If you really can't remember how to use them, just review the previous chapters.

                          6.2 Install acme.sh

                          1. Basic Linux commands for beginners:

                            NumberCommandDescription
                            cmd-12wgetRetrieve (or download) a webpage file
                            cmd-13acme.shCommands related to acme.sh certificate management
                          2. Run the installation script.

                          wget -O - https://get.acme.sh | sh
                          +import{_ as c,r as s,o as p,c as l,a,b as n,d as e,e as t}from"./app-D7uBbsY3.js";const r="/assets/ch06-img01-acme-install-Dowds3tU.gif",d={},u=t('

                          [Chapter 6] Certificate Management

                          6.1 Applying for a TLS Certificate

                          Next, we need to apply for a real TLS certificate for our domain name, so that the website has the ability to encrypt with standard TLS and the ability to access via HTTPS. This is the most important tool for Xray and other current security proxy tools to ensure fully encrypted traffic.

                          Warning

                          Please do not use self-signed certificates lightly. It does not make the operation much simpler, but adds unnecessary risks (such as man-in-the-middle attacks).

                          ',4),m={href:"https://github.com/acmesh-official/acme.sh",target:"_blank",rel:"noopener noreferrer"},b=n("code",null,"acme.sh",-1),k=t(`

                          In addition, I believe that you have gradually become familiar with the basic operations of Linux. Therefore, from this chapter on, commands that have appeared multiple times will no longer have screenshots and will only be briefly described. If you really can't remember how to use them, just review the previous chapters.

                          6.2 Install acme.sh

                          1. Basic Linux commands for beginners:

                            NumberCommandDescription
                            cmd-12wgetRetrieve (or download) a webpage file
                            cmd-13acme.shCommands related to acme.sh certificate management
                          2. Run the installation script.

                          wget -O - https://get.acme.sh | sh
                           
                          1. Make the acme.sh command effective.
                          . .bashrc
                           

                          (Note: This command is used to source (load) the .bashrc file in the shell environment.)

                          1. Enable acme.sh automatic upgrade.
                          acme.sh --upgrade --auto-upgrade
                           
                          1. The complete process up to this point is shown in the following diagram:

                          acme.sh installation demo

                          6.3 Testing Certificate Application

                          Before officially applying for the certificate, we use the testing command (--issue --test) to verify if the application can be successfully submitted. This can avoid repeated failures in applying for a certificate due to incorrect local configuration, exceeding the frequency limit of Let's Encrypt (such as a maximum of 5 failures per hour, per domain, or per user), which may prevent the subsequent steps from being carried out.

                          1. The command to apply for a test certificate is as follows (this article uses ECC certificate as an example, because there is really no reason not to use it nowadays):
                          acme.sh --issue --server letsencrypt --test -d subdomain.yourdomain.com -w /home/vpsadmin/www/webpage --keylength ec-256
                          diff --git a/assets/ch06-certificates.html-BTgSQmX4.js b/assets/ch06-certificates.html-DPu9Gv70.js
                          similarity index 99%
                          rename from assets/ch06-certificates.html-BTgSQmX4.js
                          rename to assets/ch06-certificates.html-DPu9Gv70.js
                          index e842945348..482c5c7893 100644
                          --- a/assets/ch06-certificates.html-BTgSQmX4.js
                          +++ b/assets/ch06-certificates.html-DPu9Gv70.js
                          @@ -1,4 +1,4 @@
                          -import{_ as i,r as s,o as l,c as o,a,b as n,d as e,e as t}from"./app-DBM4OJyw.js";const r="/assets/ch06-img01-acme-install-Dowds3tU.gif",d={},u=t('

                          【Глава 6】 Управление сертификатами

                          6.1 Получение SSL-сертификата

                          Теперь нам нужно получить действующий SSL-сертификат для нашего доменного имени, чтобы веб-сайт работал по протоколу HTTPS. Это важнейший инструмент для обеспечения безопасности трафика при использовании современных VPN-сервисов, таких как Xray.

                          Внимание

                          Не используйте самоподписанные сертификаты. Это ненамного упростит задачу, но создаст дополнительные риски (например, возможность атак типа «человек посередине»).

                          ',4),m={href:"https://github.com/acmesh-official/acme.sh",target:"_blank",rel:"noopener noreferrer"},k=n("code",null,"acme.sh",-1),b=t(`

                          Я уверен, что вы уже освоились с базовыми командами Linux, поэтому скриншоты с выводом команд, которые мы уже использовали ранее, будут опущены. Если вы забыли, как выполнять ту или иную команду, вернитесь и перечитайте предыдущие главы.

                          6.2 Установка acme.sh

                          1. Базовые команды Linux:

                            НомерКомандаОписание
                            cmd-12wgetЗагрузка файла из интернета
                            cmd-13acme.shУправление сертификатами
                          2. Запустите скрипт установки:

                            wget -O -  https://get.acme.sh | sh
                            +import{_ as i,r as s,o as l,c as o,a,b as n,d as e,e as t}from"./app-D7uBbsY3.js";const r="/assets/ch06-img01-acme-install-Dowds3tU.gif",d={},u=t('

                            【Глава 6】 Управление сертификатами

                            6.1 Получение SSL-сертификата

                            Теперь нам нужно получить действующий SSL-сертификат для нашего доменного имени, чтобы веб-сайт работал по протоколу HTTPS. Это важнейший инструмент для обеспечения безопасности трафика при использовании современных VPN-сервисов, таких как Xray.

                            Внимание

                            Не используйте самоподписанные сертификаты. Это ненамного упростит задачу, но создаст дополнительные риски (например, возможность атак типа «человек посередине»).

                            ',4),m={href:"https://github.com/acmesh-official/acme.sh",target:"_blank",rel:"noopener noreferrer"},k=n("code",null,"acme.sh",-1),b=t(`

                            Я уверен, что вы уже освоились с базовыми командами Linux, поэтому скриншоты с выводом команд, которые мы уже использовали ранее, будут опущены. Если вы забыли, как выполнять ту или иную команду, вернитесь и перечитайте предыдущие главы.

                            6.2 Установка acme.sh

                            1. Базовые команды Linux:

                              НомерКомандаОписание
                              cmd-12wgetЗагрузка файла из интернета
                              cmd-13acme.shУправление сертификатами
                            2. Запустите скрипт установки:

                              wget -O -  https://get.acme.sh | sh
                               
                            3. Сделайте команду acme.sh доступной:

                              . .bashrc
                               
                            4. Включите автоматическое обновление acme.sh:

                              acme.sh --upgrade --auto-upgrade
                               
                            5. Весь процесс установки показан на гифке ниже:

                              Установка acme.sh

                            6.3 Тестовый запрос сертификата

                            Перед тем, как запросить настоящий сертификат, давайте сделаем тестовый запрос (--issue --test), чтобы убедиться, что всё настроено правильно. Это позволит избежать превышения лимита на количество запросов Let's Encrypt (например, не более 5 неудачных запросов в час для одного домена и одного аккаунта).

                            1. Команда для тестового запроса сертификата (в этой статье мы будем использовать сертификаты ECC, поскольку на сегодняшний день нет причин не использовать их):

                              acme.sh --issue --server letsencrypt --test -d поддомен.ваш_домен.com -w /home/vpsadmin/www/webpage --keylength ec-256
                              diff --git a/assets/ch06-certificates.html-Dwdk6ToP.js b/assets/ch06-certificates.html-INcZvyys.js
                              similarity index 99%
                              rename from assets/ch06-certificates.html-Dwdk6ToP.js
                              rename to assets/ch06-certificates.html-INcZvyys.js
                              index e326d3c57b..5f6fb5ef02 100644
                              --- a/assets/ch06-certificates.html-Dwdk6ToP.js
                              +++ b/assets/ch06-certificates.html-INcZvyys.js
                              @@ -1,4 +1,4 @@
                              -import{_ as i,r as s,o as l,c as o,a,b as n,d as e,e as t}from"./app-DBM4OJyw.js";const r="/assets/ch06-img01-acme-install-Dowds3tU.gif",d={},u=t('

                              【第 6 章】证书管理篇

                              6.1 申请 TLS 证书

                              接下来我们要做的,是为我们的域名申请一个真实的 TLS 证书,使网站具备标准 TLS 加密的能力及 HTTPS 访问的能力。这就是 Xray 等现阶段安全代理工具确保流量充分加密最重要的工具。

                              注意

                              请不要轻易使用自签证书。它并没有让操作简单太多,但增加了无谓的风险(如中间人攻击)。

                              ',4),m={href:"https://github.com/acmesh-official/acme.sh",target:"_blank",rel:"noopener noreferrer"},k=n("code",null,"acme.sh",-1),b=t(`

                              另外,我相信,现在你已经逐渐熟悉了 Linux 的基础操作,所以已经多次出现的命令从本章开始不再重复截图、只做简单的描述。如果实在想不起来怎么用的话,就稍微复习一下前面的章节吧。

                              6.2 安装 acme.sh

                              1. 小小白白 Linux 基础命令:

                                编号命令名称命令说明
                                cmd-12wget访问(或下载)某个网页文件
                                cmd-13acme.shacme.sh 证书管理相关的命令
                              2. 运行安装脚本

                                wget -O -  https://get.acme.sh | sh
                                +import{_ as i,r as s,o as l,c as o,a,b as n,d as e,e as t}from"./app-D7uBbsY3.js";const r="/assets/ch06-img01-acme-install-Dowds3tU.gif",d={},u=t('

                                【第 6 章】证书管理篇

                                6.1 申请 TLS 证书

                                接下来我们要做的,是为我们的域名申请一个真实的 TLS 证书,使网站具备标准 TLS 加密的能力及 HTTPS 访问的能力。这就是 Xray 等现阶段安全代理工具确保流量充分加密最重要的工具。

                                注意

                                请不要轻易使用自签证书。它并没有让操作简单太多,但增加了无谓的风险(如中间人攻击)。

                                ',4),m={href:"https://github.com/acmesh-official/acme.sh",target:"_blank",rel:"noopener noreferrer"},k=n("code",null,"acme.sh",-1),b=t(`

                                另外,我相信,现在你已经逐渐熟悉了 Linux 的基础操作,所以已经多次出现的命令从本章开始不再重复截图、只做简单的描述。如果实在想不起来怎么用的话,就稍微复习一下前面的章节吧。

                                6.2 安装 acme.sh

                                1. 小小白白 Linux 基础命令:

                                  编号命令名称命令说明
                                  cmd-12wget访问(或下载)某个网页文件
                                  cmd-13acme.shacme.sh 证书管理相关的命令
                                2. 运行安装脚本

                                  wget -O -  https://get.acme.sh | sh
                                   
                                3. acme.sh 命令生效

                                  . .bashrc
                                   
                                4. 开启 acme.sh 的自动升级

                                  acme.sh --upgrade --auto-upgrade
                                   
                                5. 到这一步的完整流程如下图:

                                  acme.sh安装演示

                                6.3 测试证书申请

                                在正式申请证书之前,我们先用测试命令(--issue --test)来验证是否可以成功申请,这样可以避免在本地配置有误时,反复申请证书失败,超过 Let's Encrypt 的频率上限(比如,每小时、每个域名、每个用户失败最多 5 次),导致后面的步骤无法进行。

                                1. 测试证书申请的命令如下(本文均以 ECC 证书为例,因为时至今日,实在没什么理由不用它):

                                  acme.sh --issue --server letsencrypt --test -d 二级域名.你的域名.com -w /home/vpsadmin/www/webpage --keylength ec-256
                                  diff --git a/assets/ch07-xray-server.html-o9DNRP9E.js b/assets/ch07-xray-server.html-BkxuKbOE.js
                                  similarity index 99%
                                  rename from assets/ch07-xray-server.html-o9DNRP9E.js
                                  rename to assets/ch07-xray-server.html-BkxuKbOE.js
                                  index 2ac742a1cd..a0ea931ac9 100644
                                  --- a/assets/ch07-xray-server.html-o9DNRP9E.js
                                  +++ b/assets/ch07-xray-server.html-BkxuKbOE.js
                                  @@ -1,4 +1,4 @@
                                  -import{_ as c,r as o,o as d,c as p,a as e,b as s,d as n,w as r,e as a}from"./app-DBM4OJyw.js";const u="/assets/ch07-img01-xray-install-6RUithnp.gif",v="/assets/ch07-img02-xray-cert-install-BVo1KeA2.png",m="/assets/ch07-img03-crontab-cert-renew-B_dwSLtg.gif",b="/assets/ch07-img04-xray-log-and-config-BP5ccZ8k.gif",h="/assets/ch07-img05-xray-start-and-status-Cl6yKbrT.gif",g="/assets/ch07-img06-bbr-proper-BpzfpFMr.gif",k="/assets/ch07-img07-http-to-https-QYIcd_gO.gif",y="/assets/ch07-img08-http-to-https-check-7ZPa5fw-.png",x={},q=a('

                                  【第 7 章】Xray 服务器篇

                                  7.1 博观而约取,厚积而薄发

                                  本文撰写过程中,大佬开玩笑的吐槽到:你这教程,居然连载了 6 章都还没到 Xray,不知道的还以为你是“手把手教你建网站”教程呢。(我竟无法反驳.jpg!)

                                  其实这样的结构是我多番思考之后的决定,毕竟只有打好基础,才能在后面事半功倍快速反超。我在群里看到许多新人连nano都无法正确使用,也不会用WinSCP,远程手写编辑出来的config.json自然错误百出,连查错也变得举步维艰。

                                  注意

                                  经过了前 6 章的准备,各位已经跟我一起翻越了 Linux 基本操作、VPS 远程管理、网页搭建、域名管理、证书申请等等几座大山。是不是回头看看,觉得其实非常简单呢?现在我们有了如此扎实的准备,接下来安装和配置 Xray 时会有一种【水到渠成】的轻快感觉。

                                  后面要做的事情非常简单:

                                  1. 安装
                                  2. 配置(如安装 TLS 证书、config.json
                                  3. 运行
                                  4. 优化(如更新内核、开启bbr、网站http访问自动跳转https等)

                                  7.2 安装 Xray

                                  ',8),_={href:"https://github.com/XTLS/Xray-core",target:"_blank",rel:"noopener noreferrer"},f=s("code",null,"MPL 2.0",-1),X={href:"https://github.com/XTLS/Xray-install",target:"_blank",rel:"noopener noreferrer"},B=s("strong",null,"本文使用的是【非 root 用户】安装模式",-1),w=a(`

                                  写本文时,安装脚本在使用非 root 账户时有一些小 bug,所以我决定正好把这几步分开操作,可以顺便说明一下 Linux 下的删除命令。

                                  1. 小小白白 Linux 基础命令:

                                    编号命令名称命令说明
                                    cmd-14rm删除命令
                                  2. 将安装脚本下载至本地:

                                    wget https://github.com/XTLS/Xray-install/raw/main/install-release.sh
                                    +import{_ as c,r as o,o as d,c as p,a as e,b as s,d as n,w as r,e as a}from"./app-D7uBbsY3.js";const u="/assets/ch07-img01-xray-install-6RUithnp.gif",v="/assets/ch07-img02-xray-cert-install-BVo1KeA2.png",m="/assets/ch07-img03-crontab-cert-renew-B_dwSLtg.gif",b="/assets/ch07-img04-xray-log-and-config-BP5ccZ8k.gif",h="/assets/ch07-img05-xray-start-and-status-Cl6yKbrT.gif",g="/assets/ch07-img06-bbr-proper-BpzfpFMr.gif",k="/assets/ch07-img07-http-to-https-QYIcd_gO.gif",y="/assets/ch07-img08-http-to-https-check-7ZPa5fw-.png",x={},q=a('

                                    【第 7 章】Xray 服务器篇

                                    7.1 博观而约取,厚积而薄发

                                    本文撰写过程中,大佬开玩笑的吐槽到:你这教程,居然连载了 6 章都还没到 Xray,不知道的还以为你是“手把手教你建网站”教程呢。(我竟无法反驳.jpg!)

                                    其实这样的结构是我多番思考之后的决定,毕竟只有打好基础,才能在后面事半功倍快速反超。我在群里看到许多新人连nano都无法正确使用,也不会用WinSCP,远程手写编辑出来的config.json自然错误百出,连查错也变得举步维艰。

                                    注意

                                    经过了前 6 章的准备,各位已经跟我一起翻越了 Linux 基本操作、VPS 远程管理、网页搭建、域名管理、证书申请等等几座大山。是不是回头看看,觉得其实非常简单呢?现在我们有了如此扎实的准备,接下来安装和配置 Xray 时会有一种【水到渠成】的轻快感觉。

                                    后面要做的事情非常简单:

                                    1. 安装
                                    2. 配置(如安装 TLS 证书、config.json
                                    3. 运行
                                    4. 优化(如更新内核、开启bbr、网站http访问自动跳转https等)

                                    7.2 安装 Xray

                                    ',8),_={href:"https://github.com/XTLS/Xray-core",target:"_blank",rel:"noopener noreferrer"},f=s("code",null,"MPL 2.0",-1),X={href:"https://github.com/XTLS/Xray-install",target:"_blank",rel:"noopener noreferrer"},B=s("strong",null,"本文使用的是【非 root 用户】安装模式",-1),w=a(`

                                    写本文时,安装脚本在使用非 root 账户时有一些小 bug,所以我决定正好把这几步分开操作,可以顺便说明一下 Linux 下的删除命令。

                                    1. 小小白白 Linux 基础命令:

                                      编号命令名称命令说明
                                      cmd-14rm删除命令
                                    2. 将安装脚本下载至本地:

                                      wget https://github.com/XTLS/Xray-install/raw/main/install-release.sh
                                       
                                    3. 执行安装命令

                                      sudo bash install-release.sh
                                       
                                    4. 使用完成之后可以删除该脚本

                                      rm ~/install-release.sh
                                       

                                      注意

                                      使用 rm 命令删除文件的时候,默认其实就是删除现在所在的文件夹下的文件。但是,我依然写了完整的路径~/install-release.sh,这是我使用 rm 时的一个安全习惯、也是我把安装分成几步之后想强调一下的内容。如果你听过一些“程序员从删库到跑路”之类的段子,大概就知道为什么了。

                                    5. 完整流程演示如下:

                                      Xray服务器端安装流程演示

                                    7.3 给 Xray 配置 TLS 证书

                                    ',3),S={href:"https://github.com/acmesh-official/acme.sh/wiki/%E8%AF%B4%E6%98%8E#3-copy%E5%AE%89%E8%A3%85-%E8%AF%81%E4%B9%A6",target:"_blank",rel:"noopener noreferrer"},L=s("code",null,"acme.sh",-1),R=s("code",null,"--install-cert",-1),T=s("code",null,"xray-core",-1),D=a(`
                                  3. 为了规避非 root 账户的各种潜在的权限困扰,我们在 vpsadmin 账户下建立一个证书文件夹

                                    mkdir ~/xray_cert
                                    diff --git a/assets/ch07-xray-server.html-BDc78tiF.js b/assets/ch07-xray-server.html-C8Y2-LpN.js
                                    similarity index 99%
                                    rename from assets/ch07-xray-server.html-BDc78tiF.js
                                    rename to assets/ch07-xray-server.html-C8Y2-LpN.js
                                    index d00ab1d671..a2e53e2150 100644
                                    --- a/assets/ch07-xray-server.html-BDc78tiF.js
                                    +++ b/assets/ch07-xray-server.html-C8Y2-LpN.js
                                    @@ -1,4 +1,4 @@
                                    -import{_ as c,r as o,o as d,c as p,a as e,b as s,d as n,w as r,e as a}from"./app-DBM4OJyw.js";const u="/assets/ch07-img01-xray-install-6RUithnp.gif",v="/assets/ch07-img02-xray-cert-install-BVo1KeA2.png",m="/assets/ch07-img03-crontab-cert-renew-B_dwSLtg.gif",b="/assets/ch07-img04-xray-log-and-config-BP5ccZ8k.gif",h="/assets/ch07-img05-xray-start-and-status-Cl6yKbrT.gif",g="/assets/ch07-img06-bbr-proper-BpzfpFMr.gif",k="/assets/ch07-img07-http-to-https-QYIcd_gO.gif",y="/assets/ch07-img08-http-to-https-check-7ZPa5fw-.png",q={},x=a('

                                    【Глава 7】Настройка Xray на сервере

                                    7.1 Познать многое, усвоить нужное; копить постепенно, тратить осмотрительно

                                    Во время написания этого руководства один знакомый в шутку заметил: "Твое руководство уже 6 глав публикуется, а до Xray всё никак не дойдёт. Кто не знает, подумает, что это руководство "Создание сайта с нуля". (И ведь не поспоришь! 😂)

                                    На самом деле такая структура — результат моего осознанного решения. Ведь только заложив прочный фундамент, можно в дальнейшем двигаться вперёд семимильными шагами. Я видел в чатах много новичков, которые не могут правильно использовать даже nano, не говоря уже о WinSCP. Из-за этого их config.json, написанные вручную на удалённом сервере, пестрят ошибками, а поиск и исправление этих ошибок превращается в мучение.

                                    Внимание

                                    Пройдя первые 6 глав, мы вместе с вами преодолели несколько важных этапов: освоили базовые операции Linux, научились удалённо управлять VPS, разобрались с установкой веб-сервера, управлением доменными именами, получением SSL-сертификатов. Оглядываясь назад, разве всё это кажется таким уж сложным? Теперь, имея такой солидный багаж знаний, мы подойдём к установке и настройке Xray с чувством лёгкости и уверенности, ведь всё уже готово!

                                    Дальнейшие шаги предельно просты:

                                    1. Установка
                                    2. Настройка (например, установка TLS-сертификата, настройка config.json)
                                    3. Запуск
                                    4. Оптимизация (например, обновление ядра, включение bbr, автоматическое перенаправление http-запросов на https и т. д.)

                                    7.2 Установка Xray

                                    ',8),_={href:"https://github.com/XTLS/Xray-core",target:"_blank",rel:"noopener noreferrer"},f=s("code",null,"MPL 2.0",-1),X=s("strong",null,"конфигурации",-1),B={href:"https://github.com/XTLS/Xray-install",target:"_blank",rel:"noopener noreferrer"},T=s("strong",null,"В данном руководстве мы будем использовать установку от имени непривилегированного пользователя",-1),w=a(`

                                    На момент написания руководства в скрипте есть небольшая ошибка при установке от имени непривилегированного пользователя, поэтому мы выполним эти шаги вручную. Заодно рассмотрим команду удаления файлов в Linux.

                                    1. Базовые команды Linux:

                                      НомерКомандаОписание
                                      cmd-14rmУдаление файлов
                                    2. Скачиваем установочный скрипт:

                                      wget https://github.com/XTLS/Xray-install/raw/main/install-release.sh
                                      +import{_ as c,r as o,o as d,c as p,a as e,b as s,d as n,w as r,e as a}from"./app-D7uBbsY3.js";const u="/assets/ch07-img01-xray-install-6RUithnp.gif",v="/assets/ch07-img02-xray-cert-install-BVo1KeA2.png",m="/assets/ch07-img03-crontab-cert-renew-B_dwSLtg.gif",b="/assets/ch07-img04-xray-log-and-config-BP5ccZ8k.gif",h="/assets/ch07-img05-xray-start-and-status-Cl6yKbrT.gif",g="/assets/ch07-img06-bbr-proper-BpzfpFMr.gif",k="/assets/ch07-img07-http-to-https-QYIcd_gO.gif",y="/assets/ch07-img08-http-to-https-check-7ZPa5fw-.png",q={},x=a('

                                      【Глава 7】Настройка Xray на сервере

                                      7.1 Познать многое, усвоить нужное; копить постепенно, тратить осмотрительно

                                      Во время написания этого руководства один знакомый в шутку заметил: "Твое руководство уже 6 глав публикуется, а до Xray всё никак не дойдёт. Кто не знает, подумает, что это руководство "Создание сайта с нуля". (И ведь не поспоришь! 😂)

                                      На самом деле такая структура — результат моего осознанного решения. Ведь только заложив прочный фундамент, можно в дальнейшем двигаться вперёд семимильными шагами. Я видел в чатах много новичков, которые не могут правильно использовать даже nano, не говоря уже о WinSCP. Из-за этого их config.json, написанные вручную на удалённом сервере, пестрят ошибками, а поиск и исправление этих ошибок превращается в мучение.

                                      Внимание

                                      Пройдя первые 6 глав, мы вместе с вами преодолели несколько важных этапов: освоили базовые операции Linux, научились удалённо управлять VPS, разобрались с установкой веб-сервера, управлением доменными именами, получением SSL-сертификатов. Оглядываясь назад, разве всё это кажется таким уж сложным? Теперь, имея такой солидный багаж знаний, мы подойдём к установке и настройке Xray с чувством лёгкости и уверенности, ведь всё уже готово!

                                      Дальнейшие шаги предельно просты:

                                      1. Установка
                                      2. Настройка (например, установка TLS-сертификата, настройка config.json)
                                      3. Запуск
                                      4. Оптимизация (например, обновление ядра, включение bbr, автоматическое перенаправление http-запросов на https и т. д.)

                                      7.2 Установка Xray

                                      ',8),_={href:"https://github.com/XTLS/Xray-core",target:"_blank",rel:"noopener noreferrer"},f=s("code",null,"MPL 2.0",-1),X=s("strong",null,"конфигурации",-1),B={href:"https://github.com/XTLS/Xray-install",target:"_blank",rel:"noopener noreferrer"},T=s("strong",null,"В данном руководстве мы будем использовать установку от имени непривилегированного пользователя",-1),w=a(`

                                      На момент написания руководства в скрипте есть небольшая ошибка при установке от имени непривилегированного пользователя, поэтому мы выполним эти шаги вручную. Заодно рассмотрим команду удаления файлов в Linux.

                                      1. Базовые команды Linux:

                                        НомерКомандаОписание
                                        cmd-14rmУдаление файлов
                                      2. Скачиваем установочный скрипт:

                                        wget https://github.com/XTLS/Xray-install/raw/main/install-release.sh
                                         
                                      3. Запускаем установку:

                                        sudo bash install-release.sh
                                         
                                      4. После завершения установки удаляем скрипт:

                                        rm ~/install-release.sh
                                         

                                        Внимание

                                        При использовании команды rm для удаления файлов по умолчанию подразумевается удаление файлов в текущей директории. Однако я всё же указал полный путь: ~/install-release.sh. Это моя привычка, которая повышает безопасность при использовании rm. Думаю, вы слышали истории про "программиста, который удалил базу данных и сбежал". 😉

                                      5. Весь процесс показан на гифке:

                                        Процесс установки Xray на сервер

                                      7.3 Установка TLS-сертификата для Xray

                                      ',3),S={href:"https://github.com/acmesh-official/acme.sh/wiki/%E8%AF%B4%E6%98%8E#3-copy%E5%AE%89%E8%A3%85-%E8%AF%81%E4%B9%A6",target:"_blank",rel:"noopener noreferrer"},L=s("code",null,"acme.sh",-1),P=s("code",null,"--install-cert",-1),R=s("code",null,"xray-core",-1),D=a(`
                                    3. Чтобы избежать проблем с правами доступа при работе от имени непривилегированного пользователя, создадим папку для сертификатов в домашней директории пользователя vpsadmin:

                                      mkdir ~/xray_cert
                                      diff --git a/assets/ch07-xray-server.html-BpVDHJdR.js b/assets/ch07-xray-server.html-DacKAZFX.js
                                      similarity index 99%
                                      rename from assets/ch07-xray-server.html-BpVDHJdR.js
                                      rename to assets/ch07-xray-server.html-DacKAZFX.js
                                      index 64e2e1a379..b7dc819f67 100644
                                      --- a/assets/ch07-xray-server.html-BpVDHJdR.js
                                      +++ b/assets/ch07-xray-server.html-DacKAZFX.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as c,r as o,o as r,c as d,a as s,b as e,d as t,w as p,e as a}from"./app-DBM4OJyw.js";const u="/assets/ch07-img01-xray-install-6RUithnp.gif",h="/assets/ch07-img02-xray-cert-install-BVo1KeA2.png",m="/assets/ch07-img03-crontab-cert-renew-B_dwSLtg.gif",v="/assets/ch07-img04-xray-log-and-config-BP5ccZ8k.gif",b="/assets/ch07-img05-xray-start-and-status-Cl6yKbrT.gif",g="/assets/ch07-img06-bbr-proper-BpzfpFMr.gif",f="/assets/ch07-img07-http-to-https-QYIcd_gO.gif",y="/assets/ch07-img08-http-to-https-check-7ZPa5fw-.png",k={},w=a('

                                      [Chapter 7]Xray Server

                                      7.1 Study broadly, Act decisively.

                                      During the writing of this article, the boss joked: Your tutorial has been serialized for 6 chapters and has not yet reached Xray. People who don’t know would think that you are a "hand-in-hand teaching you to build a website" tutorial. (I can't refute it.jpg!)

                                      In fact, this structure is my decision after much thinking. After all, only by laying a solid foundation can you quickly surpass others with half the effort. I saw many newcomers in the group who can't even use nano correctly, nor can they use WinSCP. The config.json edited by remote handwriting is naturally full of errors, and even error checking becomes difficult.

                                      Warning

                                      After the preparation of the first 6 chapters, you have already climbed over several mountains with me, such as basic Linux operations, VPS remote management, web page construction, domain name management, certificate application, etc. Do you think it is actually very simple when you look back? Now that we have such solid preparations, we will have a light feeling of [smooth success] when installing and configuring Xray.

                                      The things to do next are very simple:

                                      1. Installation
                                      2. Configuration (such as installing TLS certificates, config.json)
                                      3. Run
                                      4. Optimization (such as updating the kernel, enabling bbr, automatically redirecting http visits to https, etc.)

                                      7.2 Install Xray

                                      ',8),x={href:"https://github.com/XTLS/Xray-core",target:"_blank",rel:"noopener noreferrer"},q=e("code",null,"MPL 2.0",-1),_={href:"https://github.com/XTLS/Xray-install",target:"_blank",rel:"noopener noreferrer"},I=e("strong",null,"This article uses the [non-root user] installation mode",-1),T=a(`

                                      When writing this article, the installation script had some minor bugs when using a non-root account, so I decided to separate these steps and explain the deletion command under Linux.

                                      1. Basic Linux commands for beginners:

                                        NumberCommand nameCommand description
                                        cmd-14rmdelete
                                      2. Download the installation script:

                                      wget https://github.com/XTLS/Xray-install/raw/main/install-release.sh
                                      +import{_ as c,r as o,o as r,c as d,a as s,b as e,d as t,w as p,e as a}from"./app-D7uBbsY3.js";const u="/assets/ch07-img01-xray-install-6RUithnp.gif",h="/assets/ch07-img02-xray-cert-install-BVo1KeA2.png",m="/assets/ch07-img03-crontab-cert-renew-B_dwSLtg.gif",v="/assets/ch07-img04-xray-log-and-config-BP5ccZ8k.gif",b="/assets/ch07-img05-xray-start-and-status-Cl6yKbrT.gif",g="/assets/ch07-img06-bbr-proper-BpzfpFMr.gif",f="/assets/ch07-img07-http-to-https-QYIcd_gO.gif",y="/assets/ch07-img08-http-to-https-check-7ZPa5fw-.png",k={},w=a('

                                      [Chapter 7]Xray Server

                                      7.1 Study broadly, Act decisively.

                                      During the writing of this article, the boss joked: Your tutorial has been serialized for 6 chapters and has not yet reached Xray. People who don’t know would think that you are a "hand-in-hand teaching you to build a website" tutorial. (I can't refute it.jpg!)

                                      In fact, this structure is my decision after much thinking. After all, only by laying a solid foundation can you quickly surpass others with half the effort. I saw many newcomers in the group who can't even use nano correctly, nor can they use WinSCP. The config.json edited by remote handwriting is naturally full of errors, and even error checking becomes difficult.

                                      Warning

                                      After the preparation of the first 6 chapters, you have already climbed over several mountains with me, such as basic Linux operations, VPS remote management, web page construction, domain name management, certificate application, etc. Do you think it is actually very simple when you look back? Now that we have such solid preparations, we will have a light feeling of [smooth success] when installing and configuring Xray.

                                      The things to do next are very simple:

                                      1. Installation
                                      2. Configuration (such as installing TLS certificates, config.json)
                                      3. Run
                                      4. Optimization (such as updating the kernel, enabling bbr, automatically redirecting http visits to https, etc.)

                                      7.2 Install Xray

                                      ',8),x={href:"https://github.com/XTLS/Xray-core",target:"_blank",rel:"noopener noreferrer"},q=e("code",null,"MPL 2.0",-1),_={href:"https://github.com/XTLS/Xray-install",target:"_blank",rel:"noopener noreferrer"},I=e("strong",null,"This article uses the [non-root user] installation mode",-1),T=a(`

                                      When writing this article, the installation script had some minor bugs when using a non-root account, so I decided to separate these steps and explain the deletion command under Linux.

                                      1. Basic Linux commands for beginners:

                                        NumberCommand nameCommand description
                                        cmd-14rmdelete
                                      2. Download the installation script:

                                      wget https://github.com/XTLS/Xray-install/raw/main/install-release.sh
                                       
                                      1. Execute the installation command
                                      sudo bash install-release.sh
                                       
                                      1. You can delete the script after use
                                      rm ~/install-release.sh
                                       

                                      Warning

                                      When you use the rm command to delete files, the default is to delete the files in the current folder. However, I still wrote the full path: ~/install-release.sh, which is a safety habit I have when using rm, and it is also what I want to emphasize after I divide the installation into several steps. If you have heard some jokes like "Programmers go from deleting libraries to running away", you probably know why.

                                      1. The complete process is demonstrated as follows:

                                      Xray server installation process demonstration

                                      7.3 Configure TLS certificate for Xray

                                      ',11),B={href:"https://github.com/acmesh-official/acme.sh/wiki/%E8%AF%B4%E6%98%8E#3-copy%E5%AE%89%E8%A3%85-%E8%AF%81%E4%B9%A6",target:"_blank",rel:"noopener noreferrer"},X=e("code",null,"acme.sh",-1),S=e("code",null,"--install-cert",-1),R=e("code",null,"xray-core",-1),C=a(`
                                      1. In order to avoid various potential permission problems of non-root accounts, we create a certificate folder under the vpsadmin account
                                      mkdir ~/xray_cert
                                      diff --git a/assets/ch08-xray-clients.html-D5SRFBa5.js b/assets/ch08-xray-clients.html-CXbOJkkz.js
                                      similarity index 99%
                                      rename from assets/ch08-xray-clients.html-D5SRFBa5.js
                                      rename to assets/ch08-xray-clients.html-CXbOJkkz.js
                                      index b395b0e537..5fb3633213 100644
                                      --- a/assets/ch08-xray-clients.html-D5SRFBa5.js
                                      +++ b/assets/ch08-xray-clients.html-CXbOJkkz.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as i,r as e,o as u,c as r,a,b as n,d as s,w as l,e as t}from"./app-DBM4OJyw.js";const d="/assets/ch08-img01-flow-WM46EXe9.png",k="/assets/ch08-img02-buzz-BOq4OTxL.png",v={},m=t('

                                      【Глава 8】Настройка Xray на клиенте

                                      8.1 Как работает Xray: краткое описание

                                      Чтобы правильно настраивать и использовать Xray, важно понимать принципы его работы. Новичкам поможет упрощённая схема, на которой не показаны некоторые сложные моменты:

                                      Поток данных в Xray

                                      Ключевые моменты:

                                      1. Приложение должно самостоятельно или с помощью стороннего инструмента перенаправить трафик на входящее подключение (inbounds) клиента Xray.

                                      2. Поступивший на клиент трафик обрабатывается модулем маршрутизации (routing) в соответствии с заданными правилами и перенаправляется на разные исходящие подключения (outbounds) клиента Xray, например:

                                        • Трафик на китайские ресурсы — напрямую (direct)
                                        • Трафик на зарубежные ресурсы — через VPS (proxy)
                                        • Рекламный трафик — блокируется (block)
                                      3. Трафик на зарубежные ресурсы, перенаправленный на VPS, проходит через Великий Китайский Файрвол и попадает на входящее подключение (inbounds) сервера Xray.

                                      4. Как и на клиенте, трафик, поступивший на сервер, обрабатывается модулем маршрутизации (routing) в соответствии с заданными правилами и перенаправляется на разные исходящие подключения (outbounds):

                                        • Поскольку сервер находится за пределами Китая, трафик по умолчанию идёт напрямую, что позволяет получить доступ к заблокированным ресурсам (direct).
                                        • При необходимости можно настроить перенаправление трафика на другие VPS (proxy).
                                        • На сервере также можно блокировать нежелательный трафик, например, рекламу или торренты (block).
                                      ',6),q={class:"custom-container warning"},b=n("p",{class:"custom-container-title"},"Внимание!",-1),g=n("p",null,[s("Важно помнить, что маршрутизация в "),n("code",null,"Xray"),s(" очень гибкая, и описанный выше сценарий — лишь один из множества возможных.")],-1),y=n("p",null,[s("Используя файлы "),n("code",null,"geosite.dat"),s(" и "),n("code",null,"geoip.dat"),s(", можно очень гибко управлять маршрутизацией трафика по доменным именам и IP-адресам. Это гораздо удобнее, чем устаревший "),n("code",null,"GFWList"),s(", поскольку позволяет очень точно настроить правила: например, можно разрешить прямое подключение к доменам Apple, перенаправить трафик на домены Amazon через прокси-сервер, блокировать доступ к доменам Baidu и т. д.")],-1),h=n("h2",{id:"_8-2-подключение-клиента-к-серверу",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#_8-2-подключение-клиента-к-серверу"},[n("span",null,"8.2 Подключение клиента к серверу")])],-1),_=n("p",null,[s("Теперь, когда вы понимаете принципы работы "),n("code",null,"Xray"),s(", настройка клиента сводится к тому, чтобы "),n("strong",null,"сообщить ему, как подключиться к вашему VPS"),s(". Это как настроить "),n("code",null,"PuTTY"),s(" для подключения к серверу, только в случае с Xray параметров подключения больше, чем IP-адрес, порт, имя пользователя и пароль.")],-1),x=n("code",null,"Xray",-1),f=n("code",null,"VLESS",-1),S=n("code",null,"XTLS",-1),X=t('
                                      • Адрес сервера: sub.yourdomain.com
                                      • Порт сервера: 443
                                      • Протокол: vless
                                      • Поток: xtls-rprx-vision (режим vision подходит для всех платформ)
                                      • Идентификатор: uuiduuid-uuid-uuid-uuid-uuiduuiduuid
                                      • Безопасность: "allowInsecure": false

                                      Ниже приведен список популярных клиентов Xray для мобильных и настольных устройств. Каждый клиент имеет свой собственный интерфейс, поэтому я не буду делать скриншоты для каждого из них. Внимательно изучите документацию к выбранному клиенту и укажите нужные параметры подключения.

                                      Внимание!

                                      Многие клиенты поддерживают как xray-core, так и v2fly-core. Но по умолчанию может использоваться не тот, который вам нужен. Убедитесь, что вы выбрали нужный инструмент!

                                      ',3),w=n("p",null,[n("strong",null,"v2rayN - для Windows")],-1),T={href:"https://github.com/2dust/v2rayN/releases",target:"_blank",rel:"noopener noreferrer"},N=n("li",null,"Настройте клиент в соответствии с документацией",-1),L=n("p",null,[n("strong",null,"v2rayNG - для Android")],-1),P={href:"https://github.com/2dust/v2rayNG/releases",target:"_blank",rel:"noopener noreferrer"},V=n("li",null,"Настройте клиент в соответствии с документацией",-1),I=n("li",null,[n("p",null,[n("strong",null,"Shadowrocket - для iOS, macOS на базе Apple M1")]),n("ul",null,[n("li",null,[s("Создайте учётную запись iCloud "),n("strong",null,"не"),s(" в китайском регионе")]),n("li",null,"Купите приложение в App Store"),n("li",null,"Настройте клиент в соответствии с документацией")])],-1),O=n("p",null,[n("strong",null,"Qv2ray - кроссплатформенный графический интерфейс для Linux, Windows, macOS")],-1),C={href:"https://github.com/Qv2ray/Qv2ray/releases",target:"_blank",rel:"noopener noreferrer"},D={href:"https://github.com/Qv2ray/Qv2ray/actions",target:"_blank",rel:"noopener noreferrer"},j={href:"https://qv2ray.net/",target:"_blank",rel:"noopener noreferrer"},G=n("li",null,"Настройте клиент в соответствии с документацией",-1),H=n("p",null,[n("strong",null,"V2RayXS - клиент для macOS, основанный на V2RayX и использующий xray-core")],-1),A={href:"https://github.com/tzmax/v2rayXS/releases",target:"_blank",rel:"noopener noreferrer"},W={href:"https://github.com/XTLS/Xray-core/issues/91",target:"_blank",rel:"noopener noreferrer"},E=n("li",null,"Настройте клиент в соответствии с документацией",-1),Q=t('

                                      На этом этапе ваша система готова к работе!

                                      8.3 Дополнительное задание 1: настройка xray-core на ПК вручную

                                      Хотя на предыдущем шаге мы уже всё настроили, любознательным и обладающим хорошей памятью читателям наверняка вспомнятся мои слова из предыдущей главы о том, что xray-core можно запускать как на сервере, так и на клиенте. Так как же использовать xray-core в качестве клиента?

                                      Чтобы ответить на этот вопрос, я добавил этот раздел с дополнительным заданием. Оно немного выходит за рамки основного материала и может показаться сложным, но у него есть свои преимущества:

                                      • Вы всегда будете использовать самую последнюю версию xray-core, не дожидаясь, пока разработчики клиентов выпустят обновления.
                                      • Вы получите максимальную гибкость в настройке маршрутизации (хотя стоит отметить, что Qv2ray имеет мощный редактор маршрутизации, который позволяет настраивать все функции xray-core).
                                      • Вы сэкономите системные ресурсы (графические клиенты всегда потребляют больше ресурсов, чем консольные).

                                      Недостаток этого способа заключается в том, что вам придётся настраивать клиент вручную, редактируя файл конфигурации. Но ведь на сервере вы уже делали это, так что ничего сложного здесь нет. Давайте разберёмся по шагам:

                                      ',6),B=n("code",null,"xray-core",-1),z={href:"https://github.com/XTLS/Xray-core/releases",target:"_blank",rel:"noopener noreferrer"},K=t(`
                                    4. Создайте пустой файл конфигурации config.json в той же папке (думаю, с этим проблем не возникнет).

                                    5. Что значит "удобное место"? Это зависит от платформы.

                                    6. Заполните файл конфигурации.

                                      • Я написал пример конфигурации, основанный на схеме из раздела 8.1 (прямое подключение к китайским ресурсам, проксирование трафика на зарубежные ресурсы через VPS, блокировка рекламы) и параметрах подключения из раздела 8.2.
                                      • Замените uuid на идентификатор из вашей конфигурации сервера.
                                      • Замените address на доменное имя вашего сервера.
                                      • Замените serverName на доменное имя вашего сервера.
                                      • Я добавил подробные комментарии к каждому разделу конфигурации.
                                      // ССЫЛКИ:
                                      +import{_ as i,r as e,o as u,c as r,a,b as n,d as s,w as l,e as t}from"./app-D7uBbsY3.js";const d="/assets/ch08-img01-flow-WM46EXe9.png",k="/assets/ch08-img02-buzz-BOq4OTxL.png",v={},m=t('

                                      【Глава 8】Настройка Xray на клиенте

                                      8.1 Как работает Xray: краткое описание

                                      Чтобы правильно настраивать и использовать Xray, важно понимать принципы его работы. Новичкам поможет упрощённая схема, на которой не показаны некоторые сложные моменты:

                                      Поток данных в Xray

                                      Ключевые моменты:

                                      1. Приложение должно самостоятельно или с помощью стороннего инструмента перенаправить трафик на входящее подключение (inbounds) клиента Xray.

                                      2. Поступивший на клиент трафик обрабатывается модулем маршрутизации (routing) в соответствии с заданными правилами и перенаправляется на разные исходящие подключения (outbounds) клиента Xray, например:

                                        • Трафик на китайские ресурсы — напрямую (direct)
                                        • Трафик на зарубежные ресурсы — через VPS (proxy)
                                        • Рекламный трафик — блокируется (block)
                                      3. Трафик на зарубежные ресурсы, перенаправленный на VPS, проходит через Великий Китайский Файрвол и попадает на входящее подключение (inbounds) сервера Xray.

                                      4. Как и на клиенте, трафик, поступивший на сервер, обрабатывается модулем маршрутизации (routing) в соответствии с заданными правилами и перенаправляется на разные исходящие подключения (outbounds):

                                        • Поскольку сервер находится за пределами Китая, трафик по умолчанию идёт напрямую, что позволяет получить доступ к заблокированным ресурсам (direct).
                                        • При необходимости можно настроить перенаправление трафика на другие VPS (proxy).
                                        • На сервере также можно блокировать нежелательный трафик, например, рекламу или торренты (block).
                                      ',6),q={class:"custom-container warning"},b=n("p",{class:"custom-container-title"},"Внимание!",-1),g=n("p",null,[s("Важно помнить, что маршрутизация в "),n("code",null,"Xray"),s(" очень гибкая, и описанный выше сценарий — лишь один из множества возможных.")],-1),y=n("p",null,[s("Используя файлы "),n("code",null,"geosite.dat"),s(" и "),n("code",null,"geoip.dat"),s(", можно очень гибко управлять маршрутизацией трафика по доменным именам и IP-адресам. Это гораздо удобнее, чем устаревший "),n("code",null,"GFWList"),s(", поскольку позволяет очень точно настроить правила: например, можно разрешить прямое подключение к доменам Apple, перенаправить трафик на домены Amazon через прокси-сервер, блокировать доступ к доменам Baidu и т. д.")],-1),h=n("h2",{id:"_8-2-подключение-клиента-к-серверу",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#_8-2-подключение-клиента-к-серверу"},[n("span",null,"8.2 Подключение клиента к серверу")])],-1),_=n("p",null,[s("Теперь, когда вы понимаете принципы работы "),n("code",null,"Xray"),s(", настройка клиента сводится к тому, чтобы "),n("strong",null,"сообщить ему, как подключиться к вашему VPS"),s(". Это как настроить "),n("code",null,"PuTTY"),s(" для подключения к серверу, только в случае с Xray параметров подключения больше, чем IP-адрес, порт, имя пользователя и пароль.")],-1),x=n("code",null,"Xray",-1),f=n("code",null,"VLESS",-1),S=n("code",null,"XTLS",-1),X=t('
                                      • Адрес сервера: sub.yourdomain.com
                                      • Порт сервера: 443
                                      • Протокол: vless
                                      • Поток: xtls-rprx-vision (режим vision подходит для всех платформ)
                                      • Идентификатор: uuiduuid-uuid-uuid-uuid-uuiduuiduuid
                                      • Безопасность: "allowInsecure": false

                                      Ниже приведен список популярных клиентов Xray для мобильных и настольных устройств. Каждый клиент имеет свой собственный интерфейс, поэтому я не буду делать скриншоты для каждого из них. Внимательно изучите документацию к выбранному клиенту и укажите нужные параметры подключения.

                                      Внимание!

                                      Многие клиенты поддерживают как xray-core, так и v2fly-core. Но по умолчанию может использоваться не тот, который вам нужен. Убедитесь, что вы выбрали нужный инструмент!

                                      ',3),w=n("p",null,[n("strong",null,"v2rayN - для Windows")],-1),T={href:"https://github.com/2dust/v2rayN/releases",target:"_blank",rel:"noopener noreferrer"},N=n("li",null,"Настройте клиент в соответствии с документацией",-1),L=n("p",null,[n("strong",null,"v2rayNG - для Android")],-1),P={href:"https://github.com/2dust/v2rayNG/releases",target:"_blank",rel:"noopener noreferrer"},V=n("li",null,"Настройте клиент в соответствии с документацией",-1),I=n("li",null,[n("p",null,[n("strong",null,"Shadowrocket - для iOS, macOS на базе Apple M1")]),n("ul",null,[n("li",null,[s("Создайте учётную запись iCloud "),n("strong",null,"не"),s(" в китайском регионе")]),n("li",null,"Купите приложение в App Store"),n("li",null,"Настройте клиент в соответствии с документацией")])],-1),O=n("p",null,[n("strong",null,"Qv2ray - кроссплатформенный графический интерфейс для Linux, Windows, macOS")],-1),C={href:"https://github.com/Qv2ray/Qv2ray/releases",target:"_blank",rel:"noopener noreferrer"},D={href:"https://github.com/Qv2ray/Qv2ray/actions",target:"_blank",rel:"noopener noreferrer"},j={href:"https://qv2ray.net/",target:"_blank",rel:"noopener noreferrer"},G=n("li",null,"Настройте клиент в соответствии с документацией",-1),H=n("p",null,[n("strong",null,"V2RayXS - клиент для macOS, основанный на V2RayX и использующий xray-core")],-1),A={href:"https://github.com/tzmax/v2rayXS/releases",target:"_blank",rel:"noopener noreferrer"},W={href:"https://github.com/XTLS/Xray-core/issues/91",target:"_blank",rel:"noopener noreferrer"},E=n("li",null,"Настройте клиент в соответствии с документацией",-1),Q=t('

                                      На этом этапе ваша система готова к работе!

                                      8.3 Дополнительное задание 1: настройка xray-core на ПК вручную

                                      Хотя на предыдущем шаге мы уже всё настроили, любознательным и обладающим хорошей памятью читателям наверняка вспомнятся мои слова из предыдущей главы о том, что xray-core можно запускать как на сервере, так и на клиенте. Так как же использовать xray-core в качестве клиента?

                                      Чтобы ответить на этот вопрос, я добавил этот раздел с дополнительным заданием. Оно немного выходит за рамки основного материала и может показаться сложным, но у него есть свои преимущества:

                                      • Вы всегда будете использовать самую последнюю версию xray-core, не дожидаясь, пока разработчики клиентов выпустят обновления.
                                      • Вы получите максимальную гибкость в настройке маршрутизации (хотя стоит отметить, что Qv2ray имеет мощный редактор маршрутизации, который позволяет настраивать все функции xray-core).
                                      • Вы сэкономите системные ресурсы (графические клиенты всегда потребляют больше ресурсов, чем консольные).

                                      Недостаток этого способа заключается в том, что вам придётся настраивать клиент вручную, редактируя файл конфигурации. Но ведь на сервере вы уже делали это, так что ничего сложного здесь нет. Давайте разберёмся по шагам:

                                      ',6),B=n("code",null,"xray-core",-1),z={href:"https://github.com/XTLS/Xray-core/releases",target:"_blank",rel:"noopener noreferrer"},K=t(`
                                    7. Создайте пустой файл конфигурации config.json в той же папке (думаю, с этим проблем не возникнет).

                                    8. Что значит "удобное место"? Это зависит от платформы.

                                    9. Заполните файл конфигурации.

                                      • Я написал пример конфигурации, основанный на схеме из раздела 8.1 (прямое подключение к китайским ресурсам, проксирование трафика на зарубежные ресурсы через VPS, блокировка рекламы) и параметрах подключения из раздела 8.2.
                                      • Замените uuid на идентификатор из вашей конфигурации сервера.
                                      • Замените address на доменное имя вашего сервера.
                                      • Замените serverName на доменное имя вашего сервера.
                                      • Я добавил подробные комментарии к каждому разделу конфигурации.
                                      // ССЫЛКИ:
                                       // https://github.com/XTLS/Xray-examples
                                       // https://xtls.github.io/config/
                                       
                                      diff --git a/assets/ch08-xray-clients.html-BACa2yr0.js b/assets/ch08-xray-clients.html-D4O5No-H.js
                                      similarity index 99%
                                      rename from assets/ch08-xray-clients.html-BACa2yr0.js
                                      rename to assets/ch08-xray-clients.html-D4O5No-H.js
                                      index de0a2a50ff..57bc0562cd 100644
                                      --- a/assets/ch08-xray-clients.html-BACa2yr0.js
                                      +++ b/assets/ch08-xray-clients.html-D4O5No-H.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as i,r as e,o as u,c as r,a,b as n,d as s,w as l,e as t}from"./app-DBM4OJyw.js";const d="/assets/ch08-img01-flow-WM46EXe9.png",k="/assets/ch08-img02-buzz-BOq4OTxL.png",v={},m=t('

                                      【第 8 章】Xray 客户端篇

                                      8.1 Xray 的工作原理简述

                                      要正确的配置和使用Xray,就需要正确的理解其工作原理,对于新人,可以先看看下面简化的示意图(省略了许多复杂的设置):

                                      Xray数据流向

                                      这其中的关键点是:

                                      1. APP 要主动或借助转发工具,将数据【流入(inbounds)】Xray 客户端

                                      2. 流量进入客户端后,会被【客户端路由(routing)】按规则处理后,向不同方向【流出(outbounds)Xray 客户端。比如:

                                        1. 国内流量直连(direct
                                        2. 国外流量转发 VPS(proxy
                                        3. 广告流量屏蔽(block
                                      3. 向 VPS 转发的国外流量,会跨过防火墙,【流入(inbounds)】 Xray 服务器端

                                      4. 流量进入服务器端后,与客户端一样,会被【服务器端路由(routing)】按规则处理后,向不同方向【流出(outbounds)】:

                                        1. 因为已经在防火墙之外,所以流量默认直连,你就可以访问到不存在网站们了(direct
                                        2. 如果需要在不同的 VPS 之间做链式转发,就可以继续配置转发规则(proxy
                                        3. 你可以在服务器端继续禁用各种你想禁用的流量,如广告、BT 下载等(block
                                      ',6),q={class:"custom-container warning"},b=n("p",{class:"custom-container-title"},"注意",-1),g=n("p",null,[s("请务必记得,"),n("code",null,"Xray"),s(" 的路由配置非常灵活,上面的说明只是无限可能性中的一种。")],-1),y=n("p",null,[s("借助 "),n("code",null,"geosite.dat"),s(" 和 "),n("code",null,"geoip.dat"),s(" 这两个文件,可以很灵活的从【域名】和【IP】这两个角度、不留死角的控制流量流出的方向。这比曾经单一笼统的 "),n("code",null,"GFWList"),s(" 强大很多很多,可以做到非常细致的微调:比如可以指定 Apple 域名直连或转发、指定亚马逊域名代理或转发,百度的域名屏蔽等等。。。)")],-1),h=n("h2",{id:"_8-2-客户端与服务器端正确连接",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#_8-2-客户端与服务器端正确连接"},[n("span",null,"8.2 客户端与服务器端正确连接")])],-1),_=n("p",null,[s("现在你已经理解了 "),n("code",null,"Xray"),s(" 的工作原理,那么接下来的配置,其实就是【告诉你的客户端如何连接 VPS 服务器】。这和你已经很熟悉的、告诉"),n("code",null,"PuTTY"),s("如何远程连接服务器是一样的。只不过 Xray 连接时的要素不止是【IP 地址】+【端口】+【用户名】+【密码】这四要素了。")],-1),x=n("code",null,"Xray",-1),f=n("code",null,"config.json",-1),S=n("code",null,"Xray",-1),X=n("code",null,"VLESS",-1),N=n("code",null,"XTLS",-1),P=t('
                                      • 服务器【地址】: a-name.yourdomain.com
                                      • 服务器【端口】: 443
                                      • 连接的【协议】: vless
                                      • 连接的【流控】: xtls-rprx-vision (vision 模式适合全平台)
                                      • 连接的【验证】: uuiduuid-uuid-uuid-uuiduuiduuid
                                      • 连接的【安全】: "allowInsecure": false

                                      鉴于新人一般都会使用手机 APP 或者电脑的 GUI 客户端,我就把常用的客户端罗列在下面。每个客户端都有自己独特的配置界面,逐一截图展示并不现实,所以请你务必仔细阅读这些客户端的说明、然后把上述要素填入合适的地方即可。

                                      注意

                                      许多工具其实是同时支持 xray-corev2fly-core 的,但默认内置的不一定是哪个,所以别忘记检查一下是否是你想要的那个在工作哦!

                                      ',3),w=n("p",null,[n("strong",null,"v2rayN - 适用于 Windows 平台")],-1),I={href:"https://github.com/2dust/v2rayN/releases",target:"_blank",rel:"noopener noreferrer"},T=n("li",null,"请根据该客户端的说明进行设置",-1),L=n("p",null,[n("strong",null,"v2rayNG - 适用于 Android 平台")],-1),V={href:"https://github.com/2dust/v2rayNG/releases",target:"_blank",rel:"noopener noreferrer"},C=n("li",null,"请根据该客户端的说明进行设置",-1),D=n("li",null,[n("p",null,[n("strong",null,"Shadowrocket - 适用于 iOS, 基于苹果 M 芯片的 macOS")]),n("ul",null,[n("li",null,"你需要注册一个【非中国区】的 iCloud 账户"),n("li",null,"你需要通过 App Store 搜索并购买"),n("li",null,"请根据该客户端的说明进行设置")])],-1),E=n("p",null,[n("strong",null,"Qv2ray - 跨平台图形界面,适用于 Linux, Windows, macOS")],-1),O={href:"https://github.com/Qv2ray/Qv2ray/releases",target:"_blank",rel:"noopener noreferrer"},j={href:"https://github.com/Qv2ray/Qv2ray/actions",target:"_blank",rel:"noopener noreferrer"},G={href:"https://qv2ray.net/",target:"_blank",rel:"noopener noreferrer"},A=n("li",null,"请根据该客户端的说明进行设置",-1),R=n("p",null,[n("strong",null,"V2RayXS - 基于 V2RayX 开发的一款使用 xray-core 的 macOS 客户端")],-1),B={href:"https://github.com/tzmax/v2rayXS/releases",target:"_blank",rel:"noopener noreferrer"},W={href:"https://github.com/XTLS/Xray-core/issues/91",target:"_blank",rel:"noopener noreferrer"},H=n("li",null,"请根据该客户端的说明进行设置",-1),Q=t('

                                      到这一步,你的全套配置就已经可以正常使用啦!

                                      8.3 附加题 1:在 PC 端手工配置 xray-core

                                      虽然到上面一步已经可以结束了,但是如果你是个好奇心强、记忆力好的的同学,一定会想起来我在上一章说过,你把xray-core 的二进制文件“放在服务器运行,它就是服务器端;你把它下载到本地电脑运行,它就是客户端。” 那究竟要怎样直接使用 xray-core 做客户端呢?

                                      为了回答这个问题,我加入了附加题章节,有一点点超纲,有一点点麻烦,但费这个笔墨是因为这个方式有它的优势:

                                      • 第一时间获得最新版而无需等待 APP 升级适配

                                      • 灵活自由的路由配置能力(当然 GUI 客户端中 Qv2ray 的高级路由编辑器非常强大,也可以完整实现 xray-core 的路由配置功能)

                                      • 节约系统资源 (GUI 界面一定会有资源消耗,消耗的多少则取决于客户端的实现)

                                      它的劣势应该就是【需要手写配置文件】有点麻烦了。但其实,你想想,服务器上你已经成功的写过一次了,现在又有什么区别呢?接下来,还是老样子,我们分解一下步骤:

                                      ',6),F={href:"https://github.com/XTLS/Xray-core/releases",target:"_blank",rel:"noopener noreferrer"},Y=t(`
                                    10. 在合适的文件夹建立空白配置文件:config.json (自己常用平台下新建文件大家肯定都会,这就真不用啰嗦了)

                                    11. 至于什么是“合适的文件夹”?这就取决于具体的平台了~

                                    12. 填写客户端配置

                                      • 我就以 8.1 原理说明里展示的基本三类分流(国内流量直连、国际流量转发 VPS、广告流量屏蔽),结合 8.2 的连接要素,写成一个配置文件
                                      • 请将 uuid 替换成与你服务器一致的 uuid
                                      • 请将 address 替换成你的真实域名
                                      • 请将 serverName 替换成你的真实域名
                                      • 各个配置模块的说明我都已经(很啰嗦的)放在对应的配置点上了
                                      // REFERENCE:
                                      +import{_ as i,r as e,o as u,c as r,a,b as n,d as s,w as l,e as t}from"./app-D7uBbsY3.js";const d="/assets/ch08-img01-flow-WM46EXe9.png",k="/assets/ch08-img02-buzz-BOq4OTxL.png",v={},m=t('

                                      【第 8 章】Xray 客户端篇

                                      8.1 Xray 的工作原理简述

                                      要正确的配置和使用Xray,就需要正确的理解其工作原理,对于新人,可以先看看下面简化的示意图(省略了许多复杂的设置):

                                      Xray数据流向

                                      这其中的关键点是:

                                      1. APP 要主动或借助转发工具,将数据【流入(inbounds)】Xray 客户端

                                      2. 流量进入客户端后,会被【客户端路由(routing)】按规则处理后,向不同方向【流出(outbounds)Xray 客户端。比如:

                                        1. 国内流量直连(direct
                                        2. 国外流量转发 VPS(proxy
                                        3. 广告流量屏蔽(block
                                      3. 向 VPS 转发的国外流量,会跨过防火墙,【流入(inbounds)】 Xray 服务器端

                                      4. 流量进入服务器端后,与客户端一样,会被【服务器端路由(routing)】按规则处理后,向不同方向【流出(outbounds)】:

                                        1. 因为已经在防火墙之外,所以流量默认直连,你就可以访问到不存在网站们了(direct
                                        2. 如果需要在不同的 VPS 之间做链式转发,就可以继续配置转发规则(proxy
                                        3. 你可以在服务器端继续禁用各种你想禁用的流量,如广告、BT 下载等(block
                                      ',6),q={class:"custom-container warning"},b=n("p",{class:"custom-container-title"},"注意",-1),g=n("p",null,[s("请务必记得,"),n("code",null,"Xray"),s(" 的路由配置非常灵活,上面的说明只是无限可能性中的一种。")],-1),y=n("p",null,[s("借助 "),n("code",null,"geosite.dat"),s(" 和 "),n("code",null,"geoip.dat"),s(" 这两个文件,可以很灵活的从【域名】和【IP】这两个角度、不留死角的控制流量流出的方向。这比曾经单一笼统的 "),n("code",null,"GFWList"),s(" 强大很多很多,可以做到非常细致的微调:比如可以指定 Apple 域名直连或转发、指定亚马逊域名代理或转发,百度的域名屏蔽等等。。。)")],-1),h=n("h2",{id:"_8-2-客户端与服务器端正确连接",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#_8-2-客户端与服务器端正确连接"},[n("span",null,"8.2 客户端与服务器端正确连接")])],-1),_=n("p",null,[s("现在你已经理解了 "),n("code",null,"Xray"),s(" 的工作原理,那么接下来的配置,其实就是【告诉你的客户端如何连接 VPS 服务器】。这和你已经很熟悉的、告诉"),n("code",null,"PuTTY"),s("如何远程连接服务器是一样的。只不过 Xray 连接时的要素不止是【IP 地址】+【端口】+【用户名】+【密码】这四要素了。")],-1),x=n("code",null,"Xray",-1),f=n("code",null,"config.json",-1),S=n("code",null,"Xray",-1),X=n("code",null,"VLESS",-1),N=n("code",null,"XTLS",-1),P=t('
                                      • 服务器【地址】: a-name.yourdomain.com
                                      • 服务器【端口】: 443
                                      • 连接的【协议】: vless
                                      • 连接的【流控】: xtls-rprx-vision (vision 模式适合全平台)
                                      • 连接的【验证】: uuiduuid-uuid-uuid-uuiduuiduuid
                                      • 连接的【安全】: "allowInsecure": false

                                      鉴于新人一般都会使用手机 APP 或者电脑的 GUI 客户端,我就把常用的客户端罗列在下面。每个客户端都有自己独特的配置界面,逐一截图展示并不现实,所以请你务必仔细阅读这些客户端的说明、然后把上述要素填入合适的地方即可。

                                      注意

                                      许多工具其实是同时支持 xray-corev2fly-core 的,但默认内置的不一定是哪个,所以别忘记检查一下是否是你想要的那个在工作哦!

                                      ',3),w=n("p",null,[n("strong",null,"v2rayN - 适用于 Windows 平台")],-1),I={href:"https://github.com/2dust/v2rayN/releases",target:"_blank",rel:"noopener noreferrer"},T=n("li",null,"请根据该客户端的说明进行设置",-1),L=n("p",null,[n("strong",null,"v2rayNG - 适用于 Android 平台")],-1),V={href:"https://github.com/2dust/v2rayNG/releases",target:"_blank",rel:"noopener noreferrer"},C=n("li",null,"请根据该客户端的说明进行设置",-1),D=n("li",null,[n("p",null,[n("strong",null,"Shadowrocket - 适用于 iOS, 基于苹果 M 芯片的 macOS")]),n("ul",null,[n("li",null,"你需要注册一个【非中国区】的 iCloud 账户"),n("li",null,"你需要通过 App Store 搜索并购买"),n("li",null,"请根据该客户端的说明进行设置")])],-1),E=n("p",null,[n("strong",null,"Qv2ray - 跨平台图形界面,适用于 Linux, Windows, macOS")],-1),O={href:"https://github.com/Qv2ray/Qv2ray/releases",target:"_blank",rel:"noopener noreferrer"},j={href:"https://github.com/Qv2ray/Qv2ray/actions",target:"_blank",rel:"noopener noreferrer"},G={href:"https://qv2ray.net/",target:"_blank",rel:"noopener noreferrer"},A=n("li",null,"请根据该客户端的说明进行设置",-1),R=n("p",null,[n("strong",null,"V2RayXS - 基于 V2RayX 开发的一款使用 xray-core 的 macOS 客户端")],-1),B={href:"https://github.com/tzmax/v2rayXS/releases",target:"_blank",rel:"noopener noreferrer"},W={href:"https://github.com/XTLS/Xray-core/issues/91",target:"_blank",rel:"noopener noreferrer"},H=n("li",null,"请根据该客户端的说明进行设置",-1),Q=t('

                                      到这一步,你的全套配置就已经可以正常使用啦!

                                      8.3 附加题 1:在 PC 端手工配置 xray-core

                                      虽然到上面一步已经可以结束了,但是如果你是个好奇心强、记忆力好的的同学,一定会想起来我在上一章说过,你把xray-core 的二进制文件“放在服务器运行,它就是服务器端;你把它下载到本地电脑运行,它就是客户端。” 那究竟要怎样直接使用 xray-core 做客户端呢?

                                      为了回答这个问题,我加入了附加题章节,有一点点超纲,有一点点麻烦,但费这个笔墨是因为这个方式有它的优势:

                                      • 第一时间获得最新版而无需等待 APP 升级适配

                                      • 灵活自由的路由配置能力(当然 GUI 客户端中 Qv2ray 的高级路由编辑器非常强大,也可以完整实现 xray-core 的路由配置功能)

                                      • 节约系统资源 (GUI 界面一定会有资源消耗,消耗的多少则取决于客户端的实现)

                                      它的劣势应该就是【需要手写配置文件】有点麻烦了。但其实,你想想,服务器上你已经成功的写过一次了,现在又有什么区别呢?接下来,还是老样子,我们分解一下步骤:

                                      ',6),F={href:"https://github.com/XTLS/Xray-core/releases",target:"_blank",rel:"noopener noreferrer"},Y=t(`
                                    13. 在合适的文件夹建立空白配置文件:config.json (自己常用平台下新建文件大家肯定都会,这就真不用啰嗦了)

                                    14. 至于什么是“合适的文件夹”?这就取决于具体的平台了~

                                    15. 填写客户端配置

                                      • 我就以 8.1 原理说明里展示的基本三类分流(国内流量直连、国际流量转发 VPS、广告流量屏蔽),结合 8.2 的连接要素,写成一个配置文件
                                      • 请将 uuid 替换成与你服务器一致的 uuid
                                      • 请将 address 替换成你的真实域名
                                      • 请将 serverName 替换成你的真实域名
                                      • 各个配置模块的说明我都已经(很啰嗦的)放在对应的配置点上了
                                      // REFERENCE:
                                       // https://github.com/XTLS/Xray-examples
                                       // https://xtls.github.io/config/
                                       
                                      diff --git a/assets/ch08-xray-clients.html-BPrKhFMK.js b/assets/ch08-xray-clients.html-djwoDk-t.js
                                      similarity index 99%
                                      rename from assets/ch08-xray-clients.html-BPrKhFMK.js
                                      rename to assets/ch08-xray-clients.html-djwoDk-t.js
                                      index 8213699755..3d60374439 100644
                                      --- a/assets/ch08-xray-clients.html-BPrKhFMK.js
                                      +++ b/assets/ch08-xray-clients.html-djwoDk-t.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as i,r as e,o as u,c as r,a,b as n,d as s,w as l,e as t}from"./app-DBM4OJyw.js";const d="/assets/ch08-img01-flow-D6WwDTFA.png",k="/assets/ch08-img02-buzz-BOq4OTxL.png",v={},m=t('

                                      【第 8 章】Xray 客户端篇

                                      8.1 Xray 的工作原理简述

                                      要正确的配置和使用Xray,就需要正确的理解其工作原理,对于新人,可以先看看下面简化的示意图(省略了许多复杂的设置):

                                      Xray数据流向

                                      这其中的关键点是:

                                      1. APP 要主动或借助转发工具,将数据【流入(inbounds)】Xray 客户端

                                      2. 流量进入客户端后,会被【客户端路由(routing)】按规则处理后,向不同方向【流出(outbounds)Xray 客户端。比如:

                                        1. 国内流量直连(direct
                                        2. 国外流量转发 VPS(proxy
                                        3. 广告流量屏蔽(block
                                      3. 向 VPS 转发的国外流量,会跨过防火墙,【流入(inbounds)】 Xray 服务器端

                                      4. 流量进入服务器端后,与客户端一样,会被【服务器端路由(routing)】按规则处理后,向不同方向【流出(outbounds)】:

                                        1. 因为已经在防火墙之外,所以流量默认直连,你就可以访问到不存在网站们了(direct
                                        2. 如果需要在不同的 VPS 之间做链式转发,就可以继续配置转发规则(proxy
                                        3. 你可以在服务器端继续禁用各种你想禁用的流量,如广告、BT 下载等(block
                                      ',6),q={class:"custom-container warning"},b=n("p",{class:"custom-container-title"},"注意",-1),g=n("p",null,[s("请务必记得,"),n("code",null,"Xray"),s(" 的路由配置非常灵活,上面的说明只是无限可能性中的一种。")],-1),y=n("p",null,[s("借助 "),n("code",null,"geosite.dat"),s(" 和 "),n("code",null,"geoip.dat"),s(" 这两个文件,可以很灵活的从【域名】和【IP】这两个角度、不留死角的控制流量流出的方向。这比曾经单一笼统的 "),n("code",null,"GFWList"),s(" 强大很多很多,可以做到非常细致的微调:比如可以指定 Apple 域名直连或转发、指定亚马逊域名代理或转发,百度的域名屏蔽等等。。。)")],-1),h=n("h2",{id:"_8-2-客户端与服务器端正确连接",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#_8-2-客户端与服务器端正确连接"},[n("span",null,"8.2 客户端与服务器端正确连接")])],-1),_=n("p",null,[s("现在你已经理解了 "),n("code",null,"Xray"),s(" 的工作原理,那么接下来的配置,其实就是【告诉你的客户端如何连接 VPS 服务器】。这和你已经很熟悉的、告诉"),n("code",null,"PuTTY"),s("如何远程连接服务器是一样的。只不过 Xray 连接时的要素不止是【IP 地址】+【端口】+【用户名】+【密码】这四要素了。")],-1),x=n("code",null,"Xray",-1),f=n("code",null,"config.json",-1),S=n("code",null,"Xray",-1),X=n("code",null,"VLESS",-1),w=n("code",null,"XTLS",-1),N=t('
                                      • 服务器【地址】: a-name.yourdomain.com
                                      • 服务器【端口】: 443
                                      • 连接的【协议】: vless
                                      • 连接的【流控】: xtls-rprx-vision (vision 模式适合全平台)
                                      • 连接的【验证】: uuiduuid-uuid-uuid-uuiduuiduuid
                                      • 连接的【安全】: "allowInsecure": false

                                      鉴于新人一般都会使用手机 APP 或者电脑的 GUI 客户端,我就把常用的客户端罗列在下面。每个客户端都有自己独特的配置界面,逐一截图展示并不现实,所以请你务必仔细阅读这些客户端的说明、然后把上述要素填入合适的地方即可。

                                      注意

                                      许多工具其实是同时支持 xray-corev2fly-core 的,但默认内置的不一定是哪个,所以别忘记检查一下是否是你想要的那个在工作哦!

                                      ',3),P=n("p",null,[n("strong",null,"v2rayN - 适用于 Windows 平台")],-1),T={href:"https://github.com/2dust/v2rayN/releases",target:"_blank",rel:"noopener noreferrer"},I=n("li",null,"请根据该客户端的说明进行设置",-1),L=n("p",null,[n("strong",null,"v2rayNG - 适用于 Android 平台")],-1),V={href:"https://github.com/2dust/v2rayNG/releases",target:"_blank",rel:"noopener noreferrer"},C=n("li",null,"请根据该客户端的说明进行设置",-1),D=n("li",null,[n("p",null,[n("strong",null,"Shadowrocket - 适用于 iOS, 基于苹果 M 芯片的 macOS")]),n("ul",null,[n("li",null,"你需要注册一个【非中国区】的 iCloud 账户"),n("li",null,"你需要通过 App Store 搜索并购买"),n("li",null,"请根据该客户端的说明进行设置")])],-1),O=n("p",null,[n("strong",null,"Qv2ray - 跨平台图形界面,适用于 Linux, Windows, macOS")],-1),j={href:"https://github.com/Qv2ray/Qv2ray/releases",target:"_blank",rel:"noopener noreferrer"},A={href:"https://github.com/Qv2ray/Qv2ray/actions",target:"_blank",rel:"noopener noreferrer"},E={href:"https://qv2ray.net/",target:"_blank",rel:"noopener noreferrer"},G=n("li",null,"请根据该客户端的说明进行设置",-1),R=n("p",null,[n("strong",null,"V2RayXS - 基于 V2RayX 开发的一款使用 xray-core 的 macOS 客户端")],-1),B={href:"https://github.com/tzmax/v2rayXS/releases",target:"_blank",rel:"noopener noreferrer"},W={href:"https://github.com/XTLS/Xray-core/issues/91",target:"_blank",rel:"noopener noreferrer"},F=n("li",null,"请根据该客户端的说明进行设置",-1),H=t('

                                      到这一步,你的全套配置就已经可以正常使用啦!

                                      8.3 附加题 1:在 PC 端手工配置 xray-core

                                      虽然到上面一步已经可以结束了,但是如果你是个好奇心强、记忆力好的的同学,一定会想起来我在上一章说过,你把xray-core 的二进制文件“放在服务器运行,它就是服务器端;你把它下载到本地电脑运行,它就是客户端。” 那究竟要怎样直接使用 xray-core 做客户端呢?

                                      为了回答这个问题,我加入了附加题章节,有一点点超纲,有一点点麻烦,但费这个笔墨是因为这个方式有它的优势:

                                      • 第一时间获得最新版而无需等待 APP 升级适配

                                      • 灵活自由的路由配置能力(当然 GUI 客户端中 Qv2ray 的高级路由编辑器非常强大,也可以完整实现 xray-core 的路由配置功能)

                                      • 节约系统资源 (GUI 界面一定会有资源消耗,消耗的多少则取决于客户端的实现)

                                      它的劣势应该就是【需要手写配置文件】有点麻烦了。但其实,你想想,服务器上你已经成功的写过一次了,现在又有什么区别呢?接下来,还是老样子,我们分解一下步骤:

                                      ',6),Q={href:"https://github.com/XTLS/Xray-core/releases",target:"_blank",rel:"noopener noreferrer"},Y=t(`
                                    16. 在合适的文件夹建立空白配置文件:config.json (自己常用平台下新建文件大家肯定都会,这就真不用啰嗦了)

                                    17. 至于什么是“合适的文件夹”?这就取决于具体的平台了~

                                    18. 填写客户端配置

                                      • 我就以 8.1 原理说明里展示的基本三类分流(国内流量直连、国际流量转发 VPS、广告流量屏蔽),结合 8.2 的连接要素,写成一个配置文件
                                      • 请将 uuid 替换成与你服务器一致的 uuid
                                      • 请将 address 替换成你的真实域名
                                      • 请将 serverName 替换成你的真实域名
                                      • 各个配置模块的说明我都已经(很啰嗦的)放在对应的配置点上了
                                      // REFERENCE:
                                      +import{_ as i,r as e,o as u,c as r,a,b as n,d as s,w as l,e as t}from"./app-D7uBbsY3.js";const d="/assets/ch08-img01-flow-D6WwDTFA.png",k="/assets/ch08-img02-buzz-BOq4OTxL.png",v={},m=t('

                                      【第 8 章】Xray 客户端篇

                                      8.1 Xray 的工作原理简述

                                      要正确的配置和使用Xray,就需要正确的理解其工作原理,对于新人,可以先看看下面简化的示意图(省略了许多复杂的设置):

                                      Xray数据流向

                                      这其中的关键点是:

                                      1. APP 要主动或借助转发工具,将数据【流入(inbounds)】Xray 客户端

                                      2. 流量进入客户端后,会被【客户端路由(routing)】按规则处理后,向不同方向【流出(outbounds)Xray 客户端。比如:

                                        1. 国内流量直连(direct
                                        2. 国外流量转发 VPS(proxy
                                        3. 广告流量屏蔽(block
                                      3. 向 VPS 转发的国外流量,会跨过防火墙,【流入(inbounds)】 Xray 服务器端

                                      4. 流量进入服务器端后,与客户端一样,会被【服务器端路由(routing)】按规则处理后,向不同方向【流出(outbounds)】:

                                        1. 因为已经在防火墙之外,所以流量默认直连,你就可以访问到不存在网站们了(direct
                                        2. 如果需要在不同的 VPS 之间做链式转发,就可以继续配置转发规则(proxy
                                        3. 你可以在服务器端继续禁用各种你想禁用的流量,如广告、BT 下载等(block
                                      ',6),q={class:"custom-container warning"},b=n("p",{class:"custom-container-title"},"注意",-1),g=n("p",null,[s("请务必记得,"),n("code",null,"Xray"),s(" 的路由配置非常灵活,上面的说明只是无限可能性中的一种。")],-1),y=n("p",null,[s("借助 "),n("code",null,"geosite.dat"),s(" 和 "),n("code",null,"geoip.dat"),s(" 这两个文件,可以很灵活的从【域名】和【IP】这两个角度、不留死角的控制流量流出的方向。这比曾经单一笼统的 "),n("code",null,"GFWList"),s(" 强大很多很多,可以做到非常细致的微调:比如可以指定 Apple 域名直连或转发、指定亚马逊域名代理或转发,百度的域名屏蔽等等。。。)")],-1),h=n("h2",{id:"_8-2-客户端与服务器端正确连接",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#_8-2-客户端与服务器端正确连接"},[n("span",null,"8.2 客户端与服务器端正确连接")])],-1),_=n("p",null,[s("现在你已经理解了 "),n("code",null,"Xray"),s(" 的工作原理,那么接下来的配置,其实就是【告诉你的客户端如何连接 VPS 服务器】。这和你已经很熟悉的、告诉"),n("code",null,"PuTTY"),s("如何远程连接服务器是一样的。只不过 Xray 连接时的要素不止是【IP 地址】+【端口】+【用户名】+【密码】这四要素了。")],-1),x=n("code",null,"Xray",-1),f=n("code",null,"config.json",-1),S=n("code",null,"Xray",-1),X=n("code",null,"VLESS",-1),w=n("code",null,"XTLS",-1),N=t('
                                      • 服务器【地址】: a-name.yourdomain.com
                                      • 服务器【端口】: 443
                                      • 连接的【协议】: vless
                                      • 连接的【流控】: xtls-rprx-vision (vision 模式适合全平台)
                                      • 连接的【验证】: uuiduuid-uuid-uuid-uuiduuiduuid
                                      • 连接的【安全】: "allowInsecure": false

                                      鉴于新人一般都会使用手机 APP 或者电脑的 GUI 客户端,我就把常用的客户端罗列在下面。每个客户端都有自己独特的配置界面,逐一截图展示并不现实,所以请你务必仔细阅读这些客户端的说明、然后把上述要素填入合适的地方即可。

                                      注意

                                      许多工具其实是同时支持 xray-corev2fly-core 的,但默认内置的不一定是哪个,所以别忘记检查一下是否是你想要的那个在工作哦!

                                      ',3),P=n("p",null,[n("strong",null,"v2rayN - 适用于 Windows 平台")],-1),T={href:"https://github.com/2dust/v2rayN/releases",target:"_blank",rel:"noopener noreferrer"},I=n("li",null,"请根据该客户端的说明进行设置",-1),L=n("p",null,[n("strong",null,"v2rayNG - 适用于 Android 平台")],-1),V={href:"https://github.com/2dust/v2rayNG/releases",target:"_blank",rel:"noopener noreferrer"},C=n("li",null,"请根据该客户端的说明进行设置",-1),D=n("li",null,[n("p",null,[n("strong",null,"Shadowrocket - 适用于 iOS, 基于苹果 M 芯片的 macOS")]),n("ul",null,[n("li",null,"你需要注册一个【非中国区】的 iCloud 账户"),n("li",null,"你需要通过 App Store 搜索并购买"),n("li",null,"请根据该客户端的说明进行设置")])],-1),O=n("p",null,[n("strong",null,"Qv2ray - 跨平台图形界面,适用于 Linux, Windows, macOS")],-1),j={href:"https://github.com/Qv2ray/Qv2ray/releases",target:"_blank",rel:"noopener noreferrer"},A={href:"https://github.com/Qv2ray/Qv2ray/actions",target:"_blank",rel:"noopener noreferrer"},E={href:"https://qv2ray.net/",target:"_blank",rel:"noopener noreferrer"},G=n("li",null,"请根据该客户端的说明进行设置",-1),R=n("p",null,[n("strong",null,"V2RayXS - 基于 V2RayX 开发的一款使用 xray-core 的 macOS 客户端")],-1),B={href:"https://github.com/tzmax/v2rayXS/releases",target:"_blank",rel:"noopener noreferrer"},W={href:"https://github.com/XTLS/Xray-core/issues/91",target:"_blank",rel:"noopener noreferrer"},F=n("li",null,"请根据该客户端的说明进行设置",-1),H=t('

                                      到这一步,你的全套配置就已经可以正常使用啦!

                                      8.3 附加题 1:在 PC 端手工配置 xray-core

                                      虽然到上面一步已经可以结束了,但是如果你是个好奇心强、记忆力好的的同学,一定会想起来我在上一章说过,你把xray-core 的二进制文件“放在服务器运行,它就是服务器端;你把它下载到本地电脑运行,它就是客户端。” 那究竟要怎样直接使用 xray-core 做客户端呢?

                                      为了回答这个问题,我加入了附加题章节,有一点点超纲,有一点点麻烦,但费这个笔墨是因为这个方式有它的优势:

                                      • 第一时间获得最新版而无需等待 APP 升级适配

                                      • 灵活自由的路由配置能力(当然 GUI 客户端中 Qv2ray 的高级路由编辑器非常强大,也可以完整实现 xray-core 的路由配置功能)

                                      • 节约系统资源 (GUI 界面一定会有资源消耗,消耗的多少则取决于客户端的实现)

                                      它的劣势应该就是【需要手写配置文件】有点麻烦了。但其实,你想想,服务器上你已经成功的写过一次了,现在又有什么区别呢?接下来,还是老样子,我们分解一下步骤:

                                      ',6),Q={href:"https://github.com/XTLS/Xray-core/releases",target:"_blank",rel:"noopener noreferrer"},Y=t(`
                                    19. 在合适的文件夹建立空白配置文件:config.json (自己常用平台下新建文件大家肯定都会,这就真不用啰嗦了)

                                    20. 至于什么是“合适的文件夹”?这就取决于具体的平台了~

                                    21. 填写客户端配置

                                      • 我就以 8.1 原理说明里展示的基本三类分流(国内流量直连、国际流量转发 VPS、广告流量屏蔽),结合 8.2 的连接要素,写成一个配置文件
                                      • 请将 uuid 替换成与你服务器一致的 uuid
                                      • 请将 address 替换成你的真实域名
                                      • 请将 serverName 替换成你的真实域名
                                      • 各个配置模块的说明我都已经(很啰嗦的)放在对应的配置点上了
                                      // REFERENCE:
                                       // https://github.com/XTLS/Xray-examples
                                       // https://xtls.github.io/config/
                                       
                                      diff --git a/assets/ch09-appendix.html-Bek16BV4.js b/assets/ch09-appendix.html-BLhf4FLL.js
                                      similarity index 99%
                                      rename from assets/ch09-appendix.html-Bek16BV4.js
                                      rename to assets/ch09-appendix.html-BLhf4FLL.js
                                      index 67de6c0aa5..39d439d225 100644
                                      --- a/assets/ch09-appendix.html-Bek16BV4.js
                                      +++ b/assets/ch09-appendix.html-BLhf4FLL.js
                                      @@ -1 +1 @@
                                      -import{_ as c,r as o,o as i,c as _,a as e,b as t,w as n,d as s}from"./app-DBM4OJyw.js";const a={},r=t("h1",{id:"глава-9-приложение",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#глава-9-приложение"},[t("span",null,"[Глава 9] Приложение")])],-1),h=t("h2",{id:"_1-индекс-основных-команд-linux-для-начинающих",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#_1-индекс-основных-команд-linux-для-начинающих"},[t("span",null,"1. Индекс основных команд Linux для начинающих")])],-1),u=t("thead",null,[t("tr",null,[t("th",{style:{"text-align":"center"}},"Номер"),t("th",{style:{"text-align":"left"}},"Название команды"),t("th",{style:{"text-align":"left"}},"Описание команды"),t("th",{style:{"text-align":"center"}},"Глава")])],-1),y=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-01")],-1),x=t("td",{style:{"text-align":"left"}},[t("code",null,"apt update")],-1),g=t("td",{style:{"text-align":"left"}},"Обновление списка пакетов",-1),f={style:{"text-align":"center"}},m=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-02")],-1),v=t("td",{style:{"text-align":"left"}},[t("code",null,"apt upgrade")],-1),p=t("td",{style:{"text-align":"left"}},"Обновление пакетов системы",-1),b={style:{"text-align":"center"}},X=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-03")],-1),L=t("td",{style:{"text-align":"left"}},[t("code",null,"nano")],-1),T=t("td",{style:{"text-align":"left"}},"Текстовый редактор",-1),k={style:{"text-align":"center"}},w=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-04")],-1),N=t("td",{style:{"text-align":"left"}},[t("code",null,"systemctl restart")],-1),S=t("td",{style:{"text-align":"left"}},"Перезапуск сервиса",-1),A={style:{"text-align":"center"}},B=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-05")],-1),C=t("td",{style:{"text-align":"left"}},[t("code",null,"adduser")],-1),V=t("td",{style:{"text-align":"left"}},"Добавление пользователя",-1),I={style:{"text-align":"center"}},P=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-06")],-1),R=t("td",{style:{"text-align":"left"}},[t("code",null,"apt install")],-1),j=t("td",{style:{"text-align":"left"}},"Установка пакета",-1),E={style:{"text-align":"center"}},H=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-07")],-1),q=t("td",{style:{"text-align":"left"}},[t("code",null,"visudo")],-1),z=t("td",{style:{"text-align":"left"}},"Редактор для настройки sudo",-1),D={style:{"text-align":"center"}},F=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-08")],-1),G=t("td",{style:{"text-align":"left"}},[t("code",null,"sudo")],-1),J=t("td",{style:{"text-align":"left"}},"Выполнение команды от имени root",-1),K={style:{"text-align":"center"}},M=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-09")],-1),O=t("td",{style:{"text-align":"left"}},[t("code",null,"chmod")],-1),Q=t("td",{style:{"text-align":"left"}},"Изменение прав доступа к файлу/папке",-1),U={style:{"text-align":"center"}},W=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-10")],-1),Y=t("td",{style:{"text-align":"left"}},[t("code",null,"mkdir")],-1),Z=t("td",{style:{"text-align":"left"}},"Создание папки",-1),$={style:{"text-align":"center"}},tt=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-11")],-1),et=t("td",{style:{"text-align":"left"}},[t("code",null,"systemctl reload")],-1),lt=t("td",{style:{"text-align":"left"}},"Перезагрузка конфигурации сервиса",-1),nt={style:{"text-align":"center"}},st=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-12")],-1),ot=t("td",{style:{"text-align":"left"}},[t("code",null,"wget")],-1),dt=t("td",{style:{"text-align":"left"}},"Загрузка файла/страницы из сети",-1),ct={style:{"text-align":"center"}},it=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-13")],-1),_t=t("td",{style:{"text-align":"left"}},[t("code",null,"acme.sh")],-1),at=t("td",{style:{"text-align":"left"}},"Управление сертификатами с помощью acme.sh",-1),rt={style:{"text-align":"center"}},ht=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-14")],-1),ut=t("td",{style:{"text-align":"left"}},[t("code",null,"rm")],-1),yt=t("td",{style:{"text-align":"left"}},"Удаление файлов/папок",-1),xt={style:{"text-align":"center"}},gt=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-15")],-1),ft=t("td",{style:{"text-align":"left"}},[t("code",null,"crontab -e")],-1),mt=t("td",{style:{"text-align":"left"}},"Редактирование crontab текущего пользователя",-1),vt={style:{"text-align":"center"}},pt=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-16")],-1),bt=t("td",{style:{"text-align":"left"}},[t("code",null,"touch")],-1),Xt=t("td",{style:{"text-align":"left"}},"Создание пустого файла",-1),Lt={style:{"text-align":"center"}},Tt=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-17")],-1),kt=t("td",{style:{"text-align":"left"}},[t("code",null,"systemctl")],-1),wt=t("td",{style:{"text-align":"left"}},"Базовые команды управления сервисами systemd",-1),Nt={style:{"text-align":"center"}},St=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-18")],-1),At=t("td",{style:{"text-align":"left"}},[t("code",null,"reboot")],-1),Bt=t("td",{style:{"text-align":"left"}},"Перезагрузка Linux",-1),Ct={style:{"text-align":"center"}},Vt=t("h2",{id:"_2-индекс-важных-конфигурационных-фаилов-linux",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#_2-индекс-важных-конфигурационных-фаилов-linux"},[t("span",null,"2. Индекс важных конфигурационных файлов Linux")])],-1),It=t("thead",null,[t("tr",null,[t("th",{style:{"text-align":"center"}},"Номер"),t("th",{style:{"text-align":"left"}},"Расположение файла"),t("th",{style:{"text-align":"left"}},"Описание файла"),t("th",{style:{"text-align":"center"}},"Глава")])],-1),Pt=t("td",{style:{"text-align":"center"}},[t("code",null,"conf-01")],-1),Rt=t("td",{style:{"text-align":"left"}},[t("code",null,"/etc/ssh/sshd_config")],-1),jt=t("td",{style:{"text-align":"left"}},"Конфигурация SSH сервера",-1),Et={style:{"text-align":"center"}},Ht=t("td",{style:{"text-align":"center"}},[t("code",null,"conf-02")],-1),qt=t("td",{style:{"text-align":"left"}},[t("code",null,"/etc/nginx/nginx.conf")],-1),zt=t("td",{style:{"text-align":"left"}},"Конфигурация Nginx",-1),Dt={style:{"text-align":"center"}},Ft=t("td",{style:{"text-align":"center"}},[t("code",null,"conf-03")],-1),Gt=t("td",{style:{"text-align":"left"}},[t("code",null,"/etc/apt/sources.list")],-1),Jt=t("td",{style:{"text-align":"left"}},"Список репозиториев APT",-1),Kt={style:{"text-align":"center"}},Mt=t("td",{style:{"text-align":"center"}},[t("code",null,"conf-04")],-1),Ot=t("td",{style:{"text-align":"left"}},[t("code",null,"/etc/apt/sources.list.d/vpsadmin.list")],-1),Qt=t("td",{style:{"text-align":"left"}},"Список пользовательских репозиториев APT",-1),Ut={style:{"text-align":"center"}},Wt=t("td",{style:{"text-align":"center"}},[t("code",null,"conf-05")],-1),Yt=t("td",{style:{"text-align":"left"}},[t("code",null,"crontab -e")],-1),Zt=t("td",{style:{"text-align":"left"}},"Crontab текущего пользователя",-1),$t={style:{"text-align":"center"}},te=t("td",{style:{"text-align":"center"}},[t("code",null,"conf-06")],-1),ee=t("td",{style:{"text-align":"left"}},[t("code",null,"/etc/sysctl.conf")],-1),le=t("td",{style:{"text-align":"left"}},"Настройки ядра Linux",-1),ne={style:{"text-align":"center"}},se=t("td",{style:{"text-align":"center"}},[t("code",null,"conf-07")],-1),oe=t("td",{style:{"text-align":"left"}},[t("code",null,"/etc/sysctl.d/vpsadmin.conf")],-1),de=t("td",{style:{"text-align":"left"}},"Пользовательские настройки ядра Linux",-1),ce={style:{"text-align":"center"}},ie=t("h2",{id:"_3-индекс-важных-фаилов-xray",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#_3-индекс-важных-фаилов-xray"},[t("span",null,"3. Индекс важных файлов Xray")])],-1),_e=t("thead",null,[t("tr",null,[t("th",{style:{"text-align":"center"}},"Номер"),t("th",{style:{"text-align":"left"}},"Расположение файла"),t("th",{style:{"text-align":"left"}},"Описание файла"),t("th",{style:{"text-align":"center"}},"Глава")])],-1),ae=t("td",{style:{"text-align":"center"}},[t("code",null,"xray-01")],-1),re=t("td",{style:{"text-align":"left"}},[t("code",null,"/usr/local/etc/xray/config.json")],-1),he=t("td",{style:{"text-align":"left"}},"Конфигурация Xray",-1),ue={style:{"text-align":"center"}},ye=t("td",{style:{"text-align":"center"}},[t("code",null,"xray-02")],-1),xe=t("td",{style:{"text-align":"left"}},[t("code",null,"/home/vpsadmin/xray_cert/xray.cert")],-1),ge=t("td",{style:{"text-align":"left"}},"TLS сертификат",-1),fe={style:{"text-align":"center"}},me=t("td",{style:{"text-align":"center"}},[t("code",null,"xray-03")],-1),ve=t("td",{style:{"text-align":"left"}},[t("code",null,"/home/vpsadmin/xray_cert/xray.key")],-1),pe=t("td",{style:{"text-align":"left"}},"TLS ключ",-1),be={style:{"text-align":"center"}},Xe=t("td",{style:{"text-align":"center"}},[t("code",null,"xray-04")],-1),Le=t("td",{style:{"text-align":"left"}},[t("code",null,"/home/vpsadmin/xray_log/access.log")],-1),Te=t("td",{style:{"text-align":"left"}},"Лог доступа Xray",-1),ke={style:{"text-align":"center"}},we=t("td",{style:{"text-align":"center"}},[t("code",null,"xray-05")],-1),Ne=t("td",{style:{"text-align":"left"}},[t("code",null,"/home/vpsadmin/xray_log/error.log")],-1),Se=t("td",{style:{"text-align":"left"}},"Лог ошибок Xray",-1),Ae={style:{"text-align":"center"}};function Be(Ce,Ve){const d=o("I18nTip"),l=o("RouterLink");return i(),_("div",null,[e(d),r,h,t("table",null,[u,t("tbody",null,[t("tr",null,[y,x,g,t("td",f,[e(l,{to:"/ru/document/level-0/ch03-ssh.html"},{default:n(()=>[s("Глава о удаленном подключении")]),_:1})])]),t("tr",null,[m,v,p,t("td",b,[e(l,{to:"/ru/document/level-0/ch03-ssh.html"},{default:n(()=>[s("Глава о удаленном подключении")]),_:1})])]),t("tr",null,[X,L,T,t("td",k,[e(l,{to:"/ru/document/level-0/ch04-security.html"},{default:n(()=>[s("Глава о безопасности")]),_:1})])]),t("tr",null,[w,N,S,t("td",A,[e(l,{to:"/ru/document/level-0/ch04-security.html"},{default:n(()=>[s("Глава о безопасности")]),_:1})])]),t("tr",null,[B,C,V,t("td",I,[e(l,{to:"/ru/document/level-0/ch04-security.html"},{default:n(()=>[s("Глава о безопасности")]),_:1})])]),t("tr",null,[P,R,j,t("td",E,[e(l,{to:"/ru/document/level-0/ch04-security.html"},{default:n(()=>[s("Глава о безопасности")]),_:1})])]),t("tr",null,[H,q,z,t("td",D,[e(l,{to:"/ru/document/level-0/ch04-security.html"},{default:n(()=>[s("Глава о безопасности")]),_:1})])]),t("tr",null,[F,G,J,t("td",K,[e(l,{to:"/ru/document/level-0/ch04-security.html"},{default:n(()=>[s("Глава о безопасности")]),_:1})])]),t("tr",null,[M,O,Q,t("td",U,[e(l,{to:"/ru/document/level-0/ch04-security.html"},{default:n(()=>[s("Глава о безопасности")]),_:1})])]),t("tr",null,[W,Y,Z,t("td",$,[e(l,{to:"/ru/document/level-0/ch05-webpage.html"},{default:n(()=>[s("Глава о создании сайта")]),_:1})])]),t("tr",null,[tt,et,lt,t("td",nt,[e(l,{to:"/ru/document/level-0/ch05-webpage.html"},{default:n(()=>[s("Глава о создании сайта")]),_:1})])]),t("tr",null,[st,ot,dt,t("td",ct,[e(l,{to:"/ru/document/level-0/ch06-certificates.html"},{default:n(()=>[s("Глава об управлении сертификатами")]),_:1})])]),t("tr",null,[it,_t,at,t("td",rt,[e(l,{to:"/ru/document/level-0/ch06-certificates.html"},{default:n(()=>[s("Глава об управлении сертификатами")]),_:1})])]),t("tr",null,[ht,ut,yt,t("td",xt,[e(l,{to:"/ru/document/level-0/ch07-xray-server.html"},{default:n(()=>[s("Глава о Xray сервере")]),_:1})])]),t("tr",null,[gt,ft,mt,t("td",vt,[e(l,{to:"/ru/document/level-0/ch07-xray-server.html"},{default:n(()=>[s("Глава о Xray сервере")]),_:1})])]),t("tr",null,[pt,bt,Xt,t("td",Lt,[e(l,{to:"/ru/document/level-0/ch07-xray-server.html"},{default:n(()=>[s("Глава о Xray сервере")]),_:1})])]),t("tr",null,[Tt,kt,wt,t("td",Nt,[e(l,{to:"/ru/document/level-0/ch07-xray-server.html"},{default:n(()=>[s("Глава о Xray сервере")]),_:1})])]),t("tr",null,[St,At,Bt,t("td",Ct,[e(l,{to:"/ru/document/level-0/ch07-xray-server.html"},{default:n(()=>[s("Глава о Xray сервере")]),_:1})])])])]),Vt,t("table",null,[It,t("tbody",null,[t("tr",null,[Pt,Rt,jt,t("td",Et,[e(l,{to:"/ru/document/level-0/ch03-ssh.html"},{default:n(()=>[s("Глава о удаленном подключении")]),_:1})])]),t("tr",null,[Ht,qt,zt,t("td",Dt,[e(l,{to:"/ru/document/level-0/ch05-webpage.html"},{default:n(()=>[s("Глава о создании сайта")]),_:1})])]),t("tr",null,[Ft,Gt,Jt,t("td",Kt,[e(l,{to:"/ru/document/level-0/ch07-xray-server.html"},{default:n(()=>[s("Глава о Xray сервере")]),_:1})])]),t("tr",null,[Mt,Ot,Qt,t("td",Ut,[e(l,{to:"/ru/document/level-0/ch07-xray-server.html"},{default:n(()=>[s("Глава о Xray сервере")]),_:1})])]),t("tr",null,[Wt,Yt,Zt,t("td",$t,[e(l,{to:"/ru/document/level-0/ch07-xray-server.html"},{default:n(()=>[s("Глава о Xray сервере")]),_:1})])]),t("tr",null,[te,ee,le,t("td",ne,[e(l,{to:"/ru/document/level-0/ch07-xray-server.html"},{default:n(()=>[s("Глава о Xray сервере")]),_:1})])]),t("tr",null,[se,oe,de,t("td",ce,[e(l,{to:"/ru/document/level-0/ch07-xray-server.html"},{default:n(()=>[s("Глава о Xray сервере")]),_:1})])])])]),ie,t("table",null,[_e,t("tbody",null,[t("tr",null,[ae,re,he,t("td",ue,[e(l,{to:"/ru/document/level-0/ch07-xray-server.html"},{default:n(()=>[s("Глава о Xray сервере")]),_:1})])]),t("tr",null,[ye,xe,ge,t("td",fe,[e(l,{to:"/ru/document/level-0/ch07-xray-server.html"},{default:n(()=>[s("Глава о Xray сервере")]),_:1})])]),t("tr",null,[me,ve,pe,t("td",be,[e(l,{to:"/ru/document/level-0/ch07-xray-server.html"},{default:n(()=>[s("Глава о Xray сервере")]),_:1})])]),t("tr",null,[Xe,Le,Te,t("td",ke,[e(l,{to:"/ru/document/level-0/ch07-xray-server.html"},{default:n(()=>[s("Глава о Xray сервере")]),_:1})])]),t("tr",null,[we,Ne,Se,t("td",Ae,[e(l,{to:"/ru/document/level-0/ch07-xray-server.html"},{default:n(()=>[s("Глава о Xray сервере")]),_:1})])])])])])}const Pe=c(a,[["render",Be],["__file","ch09-appendix.html.vue"]]);export{Pe as default};
                                      +import{_ as c,r as o,o as i,c as _,a as e,b as t,w as n,d as s}from"./app-D7uBbsY3.js";const a={},r=t("h1",{id:"глава-9-приложение",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#глава-9-приложение"},[t("span",null,"[Глава 9] Приложение")])],-1),h=t("h2",{id:"_1-индекс-основных-команд-linux-для-начинающих",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#_1-индекс-основных-команд-linux-для-начинающих"},[t("span",null,"1. Индекс основных команд Linux для начинающих")])],-1),u=t("thead",null,[t("tr",null,[t("th",{style:{"text-align":"center"}},"Номер"),t("th",{style:{"text-align":"left"}},"Название команды"),t("th",{style:{"text-align":"left"}},"Описание команды"),t("th",{style:{"text-align":"center"}},"Глава")])],-1),y=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-01")],-1),x=t("td",{style:{"text-align":"left"}},[t("code",null,"apt update")],-1),g=t("td",{style:{"text-align":"left"}},"Обновление списка пакетов",-1),f={style:{"text-align":"center"}},m=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-02")],-1),v=t("td",{style:{"text-align":"left"}},[t("code",null,"apt upgrade")],-1),p=t("td",{style:{"text-align":"left"}},"Обновление пакетов системы",-1),b={style:{"text-align":"center"}},X=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-03")],-1),L=t("td",{style:{"text-align":"left"}},[t("code",null,"nano")],-1),T=t("td",{style:{"text-align":"left"}},"Текстовый редактор",-1),k={style:{"text-align":"center"}},w=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-04")],-1),N=t("td",{style:{"text-align":"left"}},[t("code",null,"systemctl restart")],-1),S=t("td",{style:{"text-align":"left"}},"Перезапуск сервиса",-1),A={style:{"text-align":"center"}},B=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-05")],-1),C=t("td",{style:{"text-align":"left"}},[t("code",null,"adduser")],-1),V=t("td",{style:{"text-align":"left"}},"Добавление пользователя",-1),I={style:{"text-align":"center"}},P=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-06")],-1),R=t("td",{style:{"text-align":"left"}},[t("code",null,"apt install")],-1),j=t("td",{style:{"text-align":"left"}},"Установка пакета",-1),E={style:{"text-align":"center"}},H=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-07")],-1),q=t("td",{style:{"text-align":"left"}},[t("code",null,"visudo")],-1),z=t("td",{style:{"text-align":"left"}},"Редактор для настройки sudo",-1),D={style:{"text-align":"center"}},F=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-08")],-1),G=t("td",{style:{"text-align":"left"}},[t("code",null,"sudo")],-1),J=t("td",{style:{"text-align":"left"}},"Выполнение команды от имени root",-1),K={style:{"text-align":"center"}},M=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-09")],-1),O=t("td",{style:{"text-align":"left"}},[t("code",null,"chmod")],-1),Q=t("td",{style:{"text-align":"left"}},"Изменение прав доступа к файлу/папке",-1),U={style:{"text-align":"center"}},W=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-10")],-1),Y=t("td",{style:{"text-align":"left"}},[t("code",null,"mkdir")],-1),Z=t("td",{style:{"text-align":"left"}},"Создание папки",-1),$={style:{"text-align":"center"}},tt=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-11")],-1),et=t("td",{style:{"text-align":"left"}},[t("code",null,"systemctl reload")],-1),lt=t("td",{style:{"text-align":"left"}},"Перезагрузка конфигурации сервиса",-1),nt={style:{"text-align":"center"}},st=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-12")],-1),ot=t("td",{style:{"text-align":"left"}},[t("code",null,"wget")],-1),dt=t("td",{style:{"text-align":"left"}},"Загрузка файла/страницы из сети",-1),ct={style:{"text-align":"center"}},it=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-13")],-1),_t=t("td",{style:{"text-align":"left"}},[t("code",null,"acme.sh")],-1),at=t("td",{style:{"text-align":"left"}},"Управление сертификатами с помощью acme.sh",-1),rt={style:{"text-align":"center"}},ht=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-14")],-1),ut=t("td",{style:{"text-align":"left"}},[t("code",null,"rm")],-1),yt=t("td",{style:{"text-align":"left"}},"Удаление файлов/папок",-1),xt={style:{"text-align":"center"}},gt=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-15")],-1),ft=t("td",{style:{"text-align":"left"}},[t("code",null,"crontab -e")],-1),mt=t("td",{style:{"text-align":"left"}},"Редактирование crontab текущего пользователя",-1),vt={style:{"text-align":"center"}},pt=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-16")],-1),bt=t("td",{style:{"text-align":"left"}},[t("code",null,"touch")],-1),Xt=t("td",{style:{"text-align":"left"}},"Создание пустого файла",-1),Lt={style:{"text-align":"center"}},Tt=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-17")],-1),kt=t("td",{style:{"text-align":"left"}},[t("code",null,"systemctl")],-1),wt=t("td",{style:{"text-align":"left"}},"Базовые команды управления сервисами systemd",-1),Nt={style:{"text-align":"center"}},St=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-18")],-1),At=t("td",{style:{"text-align":"left"}},[t("code",null,"reboot")],-1),Bt=t("td",{style:{"text-align":"left"}},"Перезагрузка Linux",-1),Ct={style:{"text-align":"center"}},Vt=t("h2",{id:"_2-индекс-важных-конфигурационных-фаилов-linux",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#_2-индекс-важных-конфигурационных-фаилов-linux"},[t("span",null,"2. Индекс важных конфигурационных файлов Linux")])],-1),It=t("thead",null,[t("tr",null,[t("th",{style:{"text-align":"center"}},"Номер"),t("th",{style:{"text-align":"left"}},"Расположение файла"),t("th",{style:{"text-align":"left"}},"Описание файла"),t("th",{style:{"text-align":"center"}},"Глава")])],-1),Pt=t("td",{style:{"text-align":"center"}},[t("code",null,"conf-01")],-1),Rt=t("td",{style:{"text-align":"left"}},[t("code",null,"/etc/ssh/sshd_config")],-1),jt=t("td",{style:{"text-align":"left"}},"Конфигурация SSH сервера",-1),Et={style:{"text-align":"center"}},Ht=t("td",{style:{"text-align":"center"}},[t("code",null,"conf-02")],-1),qt=t("td",{style:{"text-align":"left"}},[t("code",null,"/etc/nginx/nginx.conf")],-1),zt=t("td",{style:{"text-align":"left"}},"Конфигурация Nginx",-1),Dt={style:{"text-align":"center"}},Ft=t("td",{style:{"text-align":"center"}},[t("code",null,"conf-03")],-1),Gt=t("td",{style:{"text-align":"left"}},[t("code",null,"/etc/apt/sources.list")],-1),Jt=t("td",{style:{"text-align":"left"}},"Список репозиториев APT",-1),Kt={style:{"text-align":"center"}},Mt=t("td",{style:{"text-align":"center"}},[t("code",null,"conf-04")],-1),Ot=t("td",{style:{"text-align":"left"}},[t("code",null,"/etc/apt/sources.list.d/vpsadmin.list")],-1),Qt=t("td",{style:{"text-align":"left"}},"Список пользовательских репозиториев APT",-1),Ut={style:{"text-align":"center"}},Wt=t("td",{style:{"text-align":"center"}},[t("code",null,"conf-05")],-1),Yt=t("td",{style:{"text-align":"left"}},[t("code",null,"crontab -e")],-1),Zt=t("td",{style:{"text-align":"left"}},"Crontab текущего пользователя",-1),$t={style:{"text-align":"center"}},te=t("td",{style:{"text-align":"center"}},[t("code",null,"conf-06")],-1),ee=t("td",{style:{"text-align":"left"}},[t("code",null,"/etc/sysctl.conf")],-1),le=t("td",{style:{"text-align":"left"}},"Настройки ядра Linux",-1),ne={style:{"text-align":"center"}},se=t("td",{style:{"text-align":"center"}},[t("code",null,"conf-07")],-1),oe=t("td",{style:{"text-align":"left"}},[t("code",null,"/etc/sysctl.d/vpsadmin.conf")],-1),de=t("td",{style:{"text-align":"left"}},"Пользовательские настройки ядра Linux",-1),ce={style:{"text-align":"center"}},ie=t("h2",{id:"_3-индекс-важных-фаилов-xray",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#_3-индекс-важных-фаилов-xray"},[t("span",null,"3. Индекс важных файлов Xray")])],-1),_e=t("thead",null,[t("tr",null,[t("th",{style:{"text-align":"center"}},"Номер"),t("th",{style:{"text-align":"left"}},"Расположение файла"),t("th",{style:{"text-align":"left"}},"Описание файла"),t("th",{style:{"text-align":"center"}},"Глава")])],-1),ae=t("td",{style:{"text-align":"center"}},[t("code",null,"xray-01")],-1),re=t("td",{style:{"text-align":"left"}},[t("code",null,"/usr/local/etc/xray/config.json")],-1),he=t("td",{style:{"text-align":"left"}},"Конфигурация Xray",-1),ue={style:{"text-align":"center"}},ye=t("td",{style:{"text-align":"center"}},[t("code",null,"xray-02")],-1),xe=t("td",{style:{"text-align":"left"}},[t("code",null,"/home/vpsadmin/xray_cert/xray.cert")],-1),ge=t("td",{style:{"text-align":"left"}},"TLS сертификат",-1),fe={style:{"text-align":"center"}},me=t("td",{style:{"text-align":"center"}},[t("code",null,"xray-03")],-1),ve=t("td",{style:{"text-align":"left"}},[t("code",null,"/home/vpsadmin/xray_cert/xray.key")],-1),pe=t("td",{style:{"text-align":"left"}},"TLS ключ",-1),be={style:{"text-align":"center"}},Xe=t("td",{style:{"text-align":"center"}},[t("code",null,"xray-04")],-1),Le=t("td",{style:{"text-align":"left"}},[t("code",null,"/home/vpsadmin/xray_log/access.log")],-1),Te=t("td",{style:{"text-align":"left"}},"Лог доступа Xray",-1),ke={style:{"text-align":"center"}},we=t("td",{style:{"text-align":"center"}},[t("code",null,"xray-05")],-1),Ne=t("td",{style:{"text-align":"left"}},[t("code",null,"/home/vpsadmin/xray_log/error.log")],-1),Se=t("td",{style:{"text-align":"left"}},"Лог ошибок Xray",-1),Ae={style:{"text-align":"center"}};function Be(Ce,Ve){const d=o("I18nTip"),l=o("RouterLink");return i(),_("div",null,[e(d),r,h,t("table",null,[u,t("tbody",null,[t("tr",null,[y,x,g,t("td",f,[e(l,{to:"/ru/document/level-0/ch03-ssh.html"},{default:n(()=>[s("Глава о удаленном подключении")]),_:1})])]),t("tr",null,[m,v,p,t("td",b,[e(l,{to:"/ru/document/level-0/ch03-ssh.html"},{default:n(()=>[s("Глава о удаленном подключении")]),_:1})])]),t("tr",null,[X,L,T,t("td",k,[e(l,{to:"/ru/document/level-0/ch04-security.html"},{default:n(()=>[s("Глава о безопасности")]),_:1})])]),t("tr",null,[w,N,S,t("td",A,[e(l,{to:"/ru/document/level-0/ch04-security.html"},{default:n(()=>[s("Глава о безопасности")]),_:1})])]),t("tr",null,[B,C,V,t("td",I,[e(l,{to:"/ru/document/level-0/ch04-security.html"},{default:n(()=>[s("Глава о безопасности")]),_:1})])]),t("tr",null,[P,R,j,t("td",E,[e(l,{to:"/ru/document/level-0/ch04-security.html"},{default:n(()=>[s("Глава о безопасности")]),_:1})])]),t("tr",null,[H,q,z,t("td",D,[e(l,{to:"/ru/document/level-0/ch04-security.html"},{default:n(()=>[s("Глава о безопасности")]),_:1})])]),t("tr",null,[F,G,J,t("td",K,[e(l,{to:"/ru/document/level-0/ch04-security.html"},{default:n(()=>[s("Глава о безопасности")]),_:1})])]),t("tr",null,[M,O,Q,t("td",U,[e(l,{to:"/ru/document/level-0/ch04-security.html"},{default:n(()=>[s("Глава о безопасности")]),_:1})])]),t("tr",null,[W,Y,Z,t("td",$,[e(l,{to:"/ru/document/level-0/ch05-webpage.html"},{default:n(()=>[s("Глава о создании сайта")]),_:1})])]),t("tr",null,[tt,et,lt,t("td",nt,[e(l,{to:"/ru/document/level-0/ch05-webpage.html"},{default:n(()=>[s("Глава о создании сайта")]),_:1})])]),t("tr",null,[st,ot,dt,t("td",ct,[e(l,{to:"/ru/document/level-0/ch06-certificates.html"},{default:n(()=>[s("Глава об управлении сертификатами")]),_:1})])]),t("tr",null,[it,_t,at,t("td",rt,[e(l,{to:"/ru/document/level-0/ch06-certificates.html"},{default:n(()=>[s("Глава об управлении сертификатами")]),_:1})])]),t("tr",null,[ht,ut,yt,t("td",xt,[e(l,{to:"/ru/document/level-0/ch07-xray-server.html"},{default:n(()=>[s("Глава о Xray сервере")]),_:1})])]),t("tr",null,[gt,ft,mt,t("td",vt,[e(l,{to:"/ru/document/level-0/ch07-xray-server.html"},{default:n(()=>[s("Глава о Xray сервере")]),_:1})])]),t("tr",null,[pt,bt,Xt,t("td",Lt,[e(l,{to:"/ru/document/level-0/ch07-xray-server.html"},{default:n(()=>[s("Глава о Xray сервере")]),_:1})])]),t("tr",null,[Tt,kt,wt,t("td",Nt,[e(l,{to:"/ru/document/level-0/ch07-xray-server.html"},{default:n(()=>[s("Глава о Xray сервере")]),_:1})])]),t("tr",null,[St,At,Bt,t("td",Ct,[e(l,{to:"/ru/document/level-0/ch07-xray-server.html"},{default:n(()=>[s("Глава о Xray сервере")]),_:1})])])])]),Vt,t("table",null,[It,t("tbody",null,[t("tr",null,[Pt,Rt,jt,t("td",Et,[e(l,{to:"/ru/document/level-0/ch03-ssh.html"},{default:n(()=>[s("Глава о удаленном подключении")]),_:1})])]),t("tr",null,[Ht,qt,zt,t("td",Dt,[e(l,{to:"/ru/document/level-0/ch05-webpage.html"},{default:n(()=>[s("Глава о создании сайта")]),_:1})])]),t("tr",null,[Ft,Gt,Jt,t("td",Kt,[e(l,{to:"/ru/document/level-0/ch07-xray-server.html"},{default:n(()=>[s("Глава о Xray сервере")]),_:1})])]),t("tr",null,[Mt,Ot,Qt,t("td",Ut,[e(l,{to:"/ru/document/level-0/ch07-xray-server.html"},{default:n(()=>[s("Глава о Xray сервере")]),_:1})])]),t("tr",null,[Wt,Yt,Zt,t("td",$t,[e(l,{to:"/ru/document/level-0/ch07-xray-server.html"},{default:n(()=>[s("Глава о Xray сервере")]),_:1})])]),t("tr",null,[te,ee,le,t("td",ne,[e(l,{to:"/ru/document/level-0/ch07-xray-server.html"},{default:n(()=>[s("Глава о Xray сервере")]),_:1})])]),t("tr",null,[se,oe,de,t("td",ce,[e(l,{to:"/ru/document/level-0/ch07-xray-server.html"},{default:n(()=>[s("Глава о Xray сервере")]),_:1})])])])]),ie,t("table",null,[_e,t("tbody",null,[t("tr",null,[ae,re,he,t("td",ue,[e(l,{to:"/ru/document/level-0/ch07-xray-server.html"},{default:n(()=>[s("Глава о Xray сервере")]),_:1})])]),t("tr",null,[ye,xe,ge,t("td",fe,[e(l,{to:"/ru/document/level-0/ch07-xray-server.html"},{default:n(()=>[s("Глава о Xray сервере")]),_:1})])]),t("tr",null,[me,ve,pe,t("td",be,[e(l,{to:"/ru/document/level-0/ch07-xray-server.html"},{default:n(()=>[s("Глава о Xray сервере")]),_:1})])]),t("tr",null,[Xe,Le,Te,t("td",ke,[e(l,{to:"/ru/document/level-0/ch07-xray-server.html"},{default:n(()=>[s("Глава о Xray сервере")]),_:1})])]),t("tr",null,[we,Ne,Se,t("td",Ae,[e(l,{to:"/ru/document/level-0/ch07-xray-server.html"},{default:n(()=>[s("Глава о Xray сервере")]),_:1})])])])])])}const Pe=c(a,[["render",Be],["__file","ch09-appendix.html.vue"]]);export{Pe as default};
                                      diff --git a/assets/ch09-appendix.html-DQ43Ovyc.js b/assets/ch09-appendix.html-CAGkKWfM.js
                                      similarity index 99%
                                      rename from assets/ch09-appendix.html-DQ43Ovyc.js
                                      rename to assets/ch09-appendix.html-CAGkKWfM.js
                                      index c17bf4a7db..e5b55ce8be 100644
                                      --- a/assets/ch09-appendix.html-DQ43Ovyc.js
                                      +++ b/assets/ch09-appendix.html-CAGkKWfM.js
                                      @@ -1 +1 @@
                                      -import{_ as c,r as o,o as i,c as _,a as l,b as t,w as s,d as e}from"./app-DBM4OJyw.js";const a={},r=t("h1",{id:"【第-9-章】附录",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#【第-9-章】附录"},[t("span",null,"【第 9 章】附录")])],-1),h=t("h2",{id:"_1-小小白白-linux-基础命令索引",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#_1-小小白白-linux-基础命令索引"},[t("span",null,"1. 小小白白 Linux 基础命令索引")])],-1),u=t("thead",null,[t("tr",null,[t("th",{style:{"text-align":"center"}},"编号"),t("th",{style:{"text-align":"left"}},"命令名称"),t("th",{style:{"text-align":"left"}},"命令说明"),t("th",{style:{"text-align":"center"}},"出现篇章")])],-1),y=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-01")],-1),x=t("td",{style:{"text-align":"left"}},[t("code",null,"apt update")],-1),g=t("td",{style:{"text-align":"left"}},"查询软件更新",-1),f={style:{"text-align":"center"}},m=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-02")],-1),v=t("td",{style:{"text-align":"left"}},[t("code",null,"apt upgrade")],-1),p=t("td",{style:{"text-align":"left"}},"执行软件更新",-1),X={style:{"text-align":"center"}},b=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-03")],-1),k=t("td",{style:{"text-align":"left"}},[t("code",null,"nano")],-1),L=t("td",{style:{"text-align":"left"}},"文本编辑器",-1),w={style:{"text-align":"center"}},T=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-04")],-1),N=t("td",{style:{"text-align":"left"}},[t("code",null,"systemctl restart")],-1),S=t("td",{style:{"text-align":"left"}},"重启某个服务",-1),B={style:{"text-align":"center"}},V=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-05")],-1),C=t("td",{style:{"text-align":"left"}},[t("code",null,"adduser")],-1),I=t("td",{style:{"text-align":"left"}},"给系统新增用户",-1),R={style:{"text-align":"center"}},j=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-06")],-1),A=t("td",{style:{"text-align":"left"}},[t("code",null,"apt install")],-1),E=t("td",{style:{"text-align":"left"}},"安装某个软件",-1),H={style:{"text-align":"center"}},q=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-07")],-1),z=t("td",{style:{"text-align":"left"}},[t("code",null,"visudo")],-1),D=t("td",{style:{"text-align":"left"}},"修改 sudo 权限设置专用编辑器",-1),F={style:{"text-align":"center"}},G=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-08")],-1),J=t("td",{style:{"text-align":"left"}},[t("code",null,"sudo")],-1),K=t("td",{style:{"text-align":"left"}},[e("用"),t("code",null,"root"),e("权限运行某个命令")],-1),M={style:{"text-align":"center"}},O=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-09")],-1),P=t("td",{style:{"text-align":"left"}},[t("code",null,"chmod")],-1),Q=t("td",{style:{"text-align":"left"}},"修改目标文件/文件夹的权限",-1),U={style:{"text-align":"center"}},W=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-10")],-1),Y=t("td",{style:{"text-align":"left"}},[t("code",null,"mkdir")],-1),Z=t("td",{style:{"text-align":"left"}},"新建文件夹",-1),$={style:{"text-align":"center"}},tt=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-11")],-1),et=t("td",{style:{"text-align":"left"}},[t("code",null,"systemctl reload")],-1),lt=t("td",{style:{"text-align":"left"}},"重新加载某个服务",-1),nt={style:{"text-align":"center"}},st=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-12")],-1),ot=t("td",{style:{"text-align":"left"}},[t("code",null,"wget")],-1),dt=t("td",{style:{"text-align":"left"}},"访问(或下载)某个网页文件",-1),ct={style:{"text-align":"center"}},it=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-13")],-1),_t=t("td",{style:{"text-align":"left"}},[t("code",null,"acme.sh")],-1),at=t("td",{style:{"text-align":"left"}},"acme.sh 证书管理相关的命令",-1),rt={style:{"text-align":"center"}},ht=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-14")],-1),ut=t("td",{style:{"text-align":"left"}},[t("code",null,"rm")],-1),yt=t("td",{style:{"text-align":"left"}},"删除命令",-1),xt={style:{"text-align":"center"}},gt=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-15")],-1),ft=t("td",{style:{"text-align":"left"}},[t("code",null,"crontab -e")],-1),mt=t("td",{style:{"text-align":"left"}},"编辑当前用户的定时任务",-1),vt={style:{"text-align":"center"}},pt=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-16")],-1),Xt=t("td",{style:{"text-align":"left"}},[t("code",null,"touch")],-1),bt=t("td",{style:{"text-align":"left"}},"建立空白文件",-1),kt={style:{"text-align":"center"}},Lt=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-17")],-1),wt=t("td",{style:{"text-align":"left"}},[t("code",null,"systemctl")],-1),Tt=t("td",{style:{"text-align":"left"}},[t("code",null,"systemd"),e("基本服务管理命令")],-1),Nt={style:{"text-align":"center"}},St=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-18")],-1),Bt=t("td",{style:{"text-align":"left"}},[t("code",null,"reboot")],-1),Vt=t("td",{style:{"text-align":"left"}},"重启 Linux 系统",-1),Ct={style:{"text-align":"center"}},It=t("h2",{id:"_2-小小白白-linux-重要配置文件索引",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#_2-小小白白-linux-重要配置文件索引"},[t("span",null,"2. 小小白白 Linux 重要配置文件索引")])],-1),Rt=t("thead",null,[t("tr",null,[t("th",{style:{"text-align":"center"}},"编号"),t("th",{style:{"text-align":"left"}},"配置文件位置"),t("th",{style:{"text-align":"left"}},"文件说明"),t("th",{style:{"text-align":"center"}},"出现篇章")])],-1),jt=t("td",{style:{"text-align":"center"}},[t("code",null,"conf-01")],-1),At=t("td",{style:{"text-align":"left"}},[t("code",null,"/etc/ssh/sshd_config")],-1),Et=t("td",{style:{"text-align":"left"}},"SSH 远程登录程序设置",-1),Ht={style:{"text-align":"center"}},qt=t("td",{style:{"text-align":"center"}},[t("code",null,"conf-02")],-1),zt=t("td",{style:{"text-align":"left"}},[t("code",null,"/etc/nginx/nginx.conf")],-1),Dt=t("td",{style:{"text-align":"left"}},"Nginx 程序设置",-1),Ft={style:{"text-align":"center"}},Gt=t("td",{style:{"text-align":"center"}},[t("code",null,"conf-03")],-1),Jt=t("td",{style:{"text-align":"left"}},[t("code",null,"/etc/apt/sources.list")],-1),Kt=t("td",{style:{"text-align":"left"}},"apt 软件源列表",-1),Mt={style:{"text-align":"center"}},Ot=t("td",{style:{"text-align":"center"}},[t("code",null,"conf-04")],-1),Pt=t("td",{style:{"text-align":"left"}},[t("code",null,"/etc/apt/sources.list.d/vpsadmin.list")],-1),Qt=t("td",{style:{"text-align":"left"}},"用户自定义软件源列表列表",-1),Ut={style:{"text-align":"center"}},Wt=t("td",{style:{"text-align":"center"}},[t("code",null,"conf-05")],-1),Yt=t("td",{style:{"text-align":"left"}},[t("code",null,"crontab -e")],-1),Zt=t("td",{style:{"text-align":"left"}},"当前用户的定时任务",-1),$t={style:{"text-align":"center"}},te=t("td",{style:{"text-align":"center"}},[t("code",null,"conf-06")],-1),ee=t("td",{style:{"text-align":"left"}},[t("code",null,"/etc/sysctl.conf")],-1),le=t("td",{style:{"text-align":"left"}},"手动设置 kernel 参数",-1),ne={style:{"text-align":"center"}},se=t("td",{style:{"text-align":"center"}},[t("code",null,"conf-07")],-1),oe=t("td",{style:{"text-align":"left"}},[t("code",null,"/etc/sysctl.d/vpsadmin.conf")],-1),de=t("td",{style:{"text-align":"left"}},"用户自定义 kernel 参数配置文件",-1),ce={style:{"text-align":"center"}},ie=t("h2",{id:"_3-小小白白-xray-重要文件索引",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#_3-小小白白-xray-重要文件索引"},[t("span",null,"3. 小小白白 Xray 重要文件索引")])],-1),_e=t("thead",null,[t("tr",null,[t("th",{style:{"text-align":"center"}},"编号"),t("th",{style:{"text-align":"left"}},"配置文件位置"),t("th",{style:{"text-align":"left"}},"文件说明"),t("th",{style:{"text-align":"center"}},"出现篇章")])],-1),ae=t("td",{style:{"text-align":"center"}},[t("code",null,"xray-01")],-1),re=t("td",{style:{"text-align":"left"}},[t("code",null,"/usr/local/etc/xray/config.json")],-1),he=t("td",{style:{"text-align":"left"}},"Xray 程序设置",-1),ue={style:{"text-align":"center"}},ye=t("td",{style:{"text-align":"center"}},[t("code",null,"xray-02")],-1),xe=t("td",{style:{"text-align":"left"}},[t("code",null,"/home/vpsadmin/xray_cert/xray.cert")],-1),ge=t("td",{style:{"text-align":"left"}},"TLS 证书",-1),fe={style:{"text-align":"center"}},me=t("td",{style:{"text-align":"center"}},[t("code",null,"xray-03")],-1),ve=t("td",{style:{"text-align":"left"}},[t("code",null,"/home/vpsadmin/xray_cert/xray.key")],-1),pe=t("td",{style:{"text-align":"left"}},"TLS 私钥",-1),Xe={style:{"text-align":"center"}},be=t("td",{style:{"text-align":"center"}},[t("code",null,"xray-04")],-1),ke=t("td",{style:{"text-align":"left"}},[t("code",null,"/home/vpsadmin/xray_log/access.log")],-1),Le=t("td",{style:{"text-align":"left"}},"Xray 访问日志",-1),we={style:{"text-align":"center"}},Te=t("td",{style:{"text-align":"center"}},[t("code",null,"xray-05")],-1),Ne=t("td",{style:{"text-align":"left"}},[t("code",null,"/home/vpsadmin/xray_log/error.log")],-1),Se=t("td",{style:{"text-align":"left"}},"Xray 错误日志",-1),Be={style:{"text-align":"center"}};function Ve(Ce,Ie){const d=o("I18nTip"),n=o("RouterLink");return i(),_("div",null,[l(d),r,h,t("table",null,[u,t("tbody",null,[t("tr",null,[y,x,g,t("td",f,[l(n,{to:"/en/document/level-0/ch03-ssh.html"},{default:s(()=>[e("《远程登录篇》")]),_:1})])]),t("tr",null,[m,v,p,t("td",X,[l(n,{to:"/en/document/level-0/ch03-ssh.html"},{default:s(()=>[e("《远程登录篇》")]),_:1})])]),t("tr",null,[b,k,L,t("td",w,[l(n,{to:"/en/document/level-0/ch04-security.html"},{default:s(()=>[e("《安全防护篇》")]),_:1})])]),t("tr",null,[T,N,S,t("td",B,[l(n,{to:"/en/document/level-0/ch04-security.html"},{default:s(()=>[e("《安全防护篇》")]),_:1})])]),t("tr",null,[V,C,I,t("td",R,[l(n,{to:"/en/document/level-0/ch04-security.html"},{default:s(()=>[e("《安全防护篇》")]),_:1})])]),t("tr",null,[j,A,E,t("td",H,[l(n,{to:"/en/document/level-0/ch04-security.html"},{default:s(()=>[e("《安全防护篇》")]),_:1})])]),t("tr",null,[q,z,D,t("td",F,[l(n,{to:"/en/document/level-0/ch04-security.html"},{default:s(()=>[e("《安全防护篇》")]),_:1})])]),t("tr",null,[G,J,K,t("td",M,[l(n,{to:"/en/document/level-0/ch04-security.html"},{default:s(()=>[e("《安全防护篇》")]),_:1})])]),t("tr",null,[O,P,Q,t("td",U,[l(n,{to:"/en/document/level-0/ch04-security.html"},{default:s(()=>[e("《安全防护篇》")]),_:1})])]),t("tr",null,[W,Y,Z,t("td",$,[l(n,{to:"/en/document/level-0/ch05-webpage.html"},{default:s(()=>[e("《网站建设篇》")]),_:1})])]),t("tr",null,[tt,et,lt,t("td",nt,[l(n,{to:"/en/document/level-0/ch05-webpage.html"},{default:s(()=>[e("《网站建设篇》")]),_:1})])]),t("tr",null,[st,ot,dt,t("td",ct,[l(n,{to:"/en/document/level-0/ch06-certificates.html"},{default:s(()=>[e("《证书管理篇》")]),_:1})])]),t("tr",null,[it,_t,at,t("td",rt,[l(n,{to:"/en/document/level-0/ch06-certificates.html"},{default:s(()=>[e("《证书管理篇》")]),_:1})])]),t("tr",null,[ht,ut,yt,t("td",xt,[l(n,{to:"/en/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])]),t("tr",null,[gt,ft,mt,t("td",vt,[l(n,{to:"/en/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])]),t("tr",null,[pt,Xt,bt,t("td",kt,[l(n,{to:"/en/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])]),t("tr",null,[Lt,wt,Tt,t("td",Nt,[l(n,{to:"/en/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])]),t("tr",null,[St,Bt,Vt,t("td",Ct,[l(n,{to:"/en/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])])])]),It,t("table",null,[Rt,t("tbody",null,[t("tr",null,[jt,At,Et,t("td",Ht,[l(n,{to:"/en/document/level-0/ch03-ssh.html"},{default:s(()=>[e("《远程登录篇》")]),_:1})])]),t("tr",null,[qt,zt,Dt,t("td",Ft,[l(n,{to:"/en/document/level-0/ch05-webpage.html"},{default:s(()=>[e("《网站建设篇》")]),_:1})])]),t("tr",null,[Gt,Jt,Kt,t("td",Mt,[l(n,{to:"/en/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])]),t("tr",null,[Ot,Pt,Qt,t("td",Ut,[l(n,{to:"/en/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])]),t("tr",null,[Wt,Yt,Zt,t("td",$t,[l(n,{to:"/en/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])]),t("tr",null,[te,ee,le,t("td",ne,[l(n,{to:"/en/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])]),t("tr",null,[se,oe,de,t("td",ce,[l(n,{to:"/en/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])])])]),ie,t("table",null,[_e,t("tbody",null,[t("tr",null,[ae,re,he,t("td",ue,[l(n,{to:"/en/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])]),t("tr",null,[ye,xe,ge,t("td",fe,[l(n,{to:"/en/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])]),t("tr",null,[me,ve,pe,t("td",Xe,[l(n,{to:"/en/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])]),t("tr",null,[be,ke,Le,t("td",we,[l(n,{to:"/en/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])]),t("tr",null,[Te,Ne,Se,t("td",Be,[l(n,{to:"/en/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])])])])])}const je=c(a,[["render",Ve],["__file","ch09-appendix.html.vue"]]);export{je as default};
                                      +import{_ as c,r as o,o as i,c as _,a as l,b as t,w as s,d as e}from"./app-D7uBbsY3.js";const a={},r=t("h1",{id:"【第-9-章】附录",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#【第-9-章】附录"},[t("span",null,"【第 9 章】附录")])],-1),h=t("h2",{id:"_1-小小白白-linux-基础命令索引",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#_1-小小白白-linux-基础命令索引"},[t("span",null,"1. 小小白白 Linux 基础命令索引")])],-1),u=t("thead",null,[t("tr",null,[t("th",{style:{"text-align":"center"}},"编号"),t("th",{style:{"text-align":"left"}},"命令名称"),t("th",{style:{"text-align":"left"}},"命令说明"),t("th",{style:{"text-align":"center"}},"出现篇章")])],-1),y=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-01")],-1),x=t("td",{style:{"text-align":"left"}},[t("code",null,"apt update")],-1),g=t("td",{style:{"text-align":"left"}},"查询软件更新",-1),f={style:{"text-align":"center"}},m=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-02")],-1),v=t("td",{style:{"text-align":"left"}},[t("code",null,"apt upgrade")],-1),p=t("td",{style:{"text-align":"left"}},"执行软件更新",-1),X={style:{"text-align":"center"}},b=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-03")],-1),k=t("td",{style:{"text-align":"left"}},[t("code",null,"nano")],-1),L=t("td",{style:{"text-align":"left"}},"文本编辑器",-1),w={style:{"text-align":"center"}},T=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-04")],-1),N=t("td",{style:{"text-align":"left"}},[t("code",null,"systemctl restart")],-1),S=t("td",{style:{"text-align":"left"}},"重启某个服务",-1),B={style:{"text-align":"center"}},V=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-05")],-1),C=t("td",{style:{"text-align":"left"}},[t("code",null,"adduser")],-1),I=t("td",{style:{"text-align":"left"}},"给系统新增用户",-1),R={style:{"text-align":"center"}},j=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-06")],-1),A=t("td",{style:{"text-align":"left"}},[t("code",null,"apt install")],-1),E=t("td",{style:{"text-align":"left"}},"安装某个软件",-1),H={style:{"text-align":"center"}},q=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-07")],-1),z=t("td",{style:{"text-align":"left"}},[t("code",null,"visudo")],-1),D=t("td",{style:{"text-align":"left"}},"修改 sudo 权限设置专用编辑器",-1),F={style:{"text-align":"center"}},G=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-08")],-1),J=t("td",{style:{"text-align":"left"}},[t("code",null,"sudo")],-1),K=t("td",{style:{"text-align":"left"}},[e("用"),t("code",null,"root"),e("权限运行某个命令")],-1),M={style:{"text-align":"center"}},O=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-09")],-1),P=t("td",{style:{"text-align":"left"}},[t("code",null,"chmod")],-1),Q=t("td",{style:{"text-align":"left"}},"修改目标文件/文件夹的权限",-1),U={style:{"text-align":"center"}},W=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-10")],-1),Y=t("td",{style:{"text-align":"left"}},[t("code",null,"mkdir")],-1),Z=t("td",{style:{"text-align":"left"}},"新建文件夹",-1),$={style:{"text-align":"center"}},tt=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-11")],-1),et=t("td",{style:{"text-align":"left"}},[t("code",null,"systemctl reload")],-1),lt=t("td",{style:{"text-align":"left"}},"重新加载某个服务",-1),nt={style:{"text-align":"center"}},st=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-12")],-1),ot=t("td",{style:{"text-align":"left"}},[t("code",null,"wget")],-1),dt=t("td",{style:{"text-align":"left"}},"访问(或下载)某个网页文件",-1),ct={style:{"text-align":"center"}},it=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-13")],-1),_t=t("td",{style:{"text-align":"left"}},[t("code",null,"acme.sh")],-1),at=t("td",{style:{"text-align":"left"}},"acme.sh 证书管理相关的命令",-1),rt={style:{"text-align":"center"}},ht=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-14")],-1),ut=t("td",{style:{"text-align":"left"}},[t("code",null,"rm")],-1),yt=t("td",{style:{"text-align":"left"}},"删除命令",-1),xt={style:{"text-align":"center"}},gt=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-15")],-1),ft=t("td",{style:{"text-align":"left"}},[t("code",null,"crontab -e")],-1),mt=t("td",{style:{"text-align":"left"}},"编辑当前用户的定时任务",-1),vt={style:{"text-align":"center"}},pt=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-16")],-1),Xt=t("td",{style:{"text-align":"left"}},[t("code",null,"touch")],-1),bt=t("td",{style:{"text-align":"left"}},"建立空白文件",-1),kt={style:{"text-align":"center"}},Lt=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-17")],-1),wt=t("td",{style:{"text-align":"left"}},[t("code",null,"systemctl")],-1),Tt=t("td",{style:{"text-align":"left"}},[t("code",null,"systemd"),e("基本服务管理命令")],-1),Nt={style:{"text-align":"center"}},St=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-18")],-1),Bt=t("td",{style:{"text-align":"left"}},[t("code",null,"reboot")],-1),Vt=t("td",{style:{"text-align":"left"}},"重启 Linux 系统",-1),Ct={style:{"text-align":"center"}},It=t("h2",{id:"_2-小小白白-linux-重要配置文件索引",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#_2-小小白白-linux-重要配置文件索引"},[t("span",null,"2. 小小白白 Linux 重要配置文件索引")])],-1),Rt=t("thead",null,[t("tr",null,[t("th",{style:{"text-align":"center"}},"编号"),t("th",{style:{"text-align":"left"}},"配置文件位置"),t("th",{style:{"text-align":"left"}},"文件说明"),t("th",{style:{"text-align":"center"}},"出现篇章")])],-1),jt=t("td",{style:{"text-align":"center"}},[t("code",null,"conf-01")],-1),At=t("td",{style:{"text-align":"left"}},[t("code",null,"/etc/ssh/sshd_config")],-1),Et=t("td",{style:{"text-align":"left"}},"SSH 远程登录程序设置",-1),Ht={style:{"text-align":"center"}},qt=t("td",{style:{"text-align":"center"}},[t("code",null,"conf-02")],-1),zt=t("td",{style:{"text-align":"left"}},[t("code",null,"/etc/nginx/nginx.conf")],-1),Dt=t("td",{style:{"text-align":"left"}},"Nginx 程序设置",-1),Ft={style:{"text-align":"center"}},Gt=t("td",{style:{"text-align":"center"}},[t("code",null,"conf-03")],-1),Jt=t("td",{style:{"text-align":"left"}},[t("code",null,"/etc/apt/sources.list")],-1),Kt=t("td",{style:{"text-align":"left"}},"apt 软件源列表",-1),Mt={style:{"text-align":"center"}},Ot=t("td",{style:{"text-align":"center"}},[t("code",null,"conf-04")],-1),Pt=t("td",{style:{"text-align":"left"}},[t("code",null,"/etc/apt/sources.list.d/vpsadmin.list")],-1),Qt=t("td",{style:{"text-align":"left"}},"用户自定义软件源列表列表",-1),Ut={style:{"text-align":"center"}},Wt=t("td",{style:{"text-align":"center"}},[t("code",null,"conf-05")],-1),Yt=t("td",{style:{"text-align":"left"}},[t("code",null,"crontab -e")],-1),Zt=t("td",{style:{"text-align":"left"}},"当前用户的定时任务",-1),$t={style:{"text-align":"center"}},te=t("td",{style:{"text-align":"center"}},[t("code",null,"conf-06")],-1),ee=t("td",{style:{"text-align":"left"}},[t("code",null,"/etc/sysctl.conf")],-1),le=t("td",{style:{"text-align":"left"}},"手动设置 kernel 参数",-1),ne={style:{"text-align":"center"}},se=t("td",{style:{"text-align":"center"}},[t("code",null,"conf-07")],-1),oe=t("td",{style:{"text-align":"left"}},[t("code",null,"/etc/sysctl.d/vpsadmin.conf")],-1),de=t("td",{style:{"text-align":"left"}},"用户自定义 kernel 参数配置文件",-1),ce={style:{"text-align":"center"}},ie=t("h2",{id:"_3-小小白白-xray-重要文件索引",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#_3-小小白白-xray-重要文件索引"},[t("span",null,"3. 小小白白 Xray 重要文件索引")])],-1),_e=t("thead",null,[t("tr",null,[t("th",{style:{"text-align":"center"}},"编号"),t("th",{style:{"text-align":"left"}},"配置文件位置"),t("th",{style:{"text-align":"left"}},"文件说明"),t("th",{style:{"text-align":"center"}},"出现篇章")])],-1),ae=t("td",{style:{"text-align":"center"}},[t("code",null,"xray-01")],-1),re=t("td",{style:{"text-align":"left"}},[t("code",null,"/usr/local/etc/xray/config.json")],-1),he=t("td",{style:{"text-align":"left"}},"Xray 程序设置",-1),ue={style:{"text-align":"center"}},ye=t("td",{style:{"text-align":"center"}},[t("code",null,"xray-02")],-1),xe=t("td",{style:{"text-align":"left"}},[t("code",null,"/home/vpsadmin/xray_cert/xray.cert")],-1),ge=t("td",{style:{"text-align":"left"}},"TLS 证书",-1),fe={style:{"text-align":"center"}},me=t("td",{style:{"text-align":"center"}},[t("code",null,"xray-03")],-1),ve=t("td",{style:{"text-align":"left"}},[t("code",null,"/home/vpsadmin/xray_cert/xray.key")],-1),pe=t("td",{style:{"text-align":"left"}},"TLS 私钥",-1),Xe={style:{"text-align":"center"}},be=t("td",{style:{"text-align":"center"}},[t("code",null,"xray-04")],-1),ke=t("td",{style:{"text-align":"left"}},[t("code",null,"/home/vpsadmin/xray_log/access.log")],-1),Le=t("td",{style:{"text-align":"left"}},"Xray 访问日志",-1),we={style:{"text-align":"center"}},Te=t("td",{style:{"text-align":"center"}},[t("code",null,"xray-05")],-1),Ne=t("td",{style:{"text-align":"left"}},[t("code",null,"/home/vpsadmin/xray_log/error.log")],-1),Se=t("td",{style:{"text-align":"left"}},"Xray 错误日志",-1),Be={style:{"text-align":"center"}};function Ve(Ce,Ie){const d=o("I18nTip"),n=o("RouterLink");return i(),_("div",null,[l(d),r,h,t("table",null,[u,t("tbody",null,[t("tr",null,[y,x,g,t("td",f,[l(n,{to:"/en/document/level-0/ch03-ssh.html"},{default:s(()=>[e("《远程登录篇》")]),_:1})])]),t("tr",null,[m,v,p,t("td",X,[l(n,{to:"/en/document/level-0/ch03-ssh.html"},{default:s(()=>[e("《远程登录篇》")]),_:1})])]),t("tr",null,[b,k,L,t("td",w,[l(n,{to:"/en/document/level-0/ch04-security.html"},{default:s(()=>[e("《安全防护篇》")]),_:1})])]),t("tr",null,[T,N,S,t("td",B,[l(n,{to:"/en/document/level-0/ch04-security.html"},{default:s(()=>[e("《安全防护篇》")]),_:1})])]),t("tr",null,[V,C,I,t("td",R,[l(n,{to:"/en/document/level-0/ch04-security.html"},{default:s(()=>[e("《安全防护篇》")]),_:1})])]),t("tr",null,[j,A,E,t("td",H,[l(n,{to:"/en/document/level-0/ch04-security.html"},{default:s(()=>[e("《安全防护篇》")]),_:1})])]),t("tr",null,[q,z,D,t("td",F,[l(n,{to:"/en/document/level-0/ch04-security.html"},{default:s(()=>[e("《安全防护篇》")]),_:1})])]),t("tr",null,[G,J,K,t("td",M,[l(n,{to:"/en/document/level-0/ch04-security.html"},{default:s(()=>[e("《安全防护篇》")]),_:1})])]),t("tr",null,[O,P,Q,t("td",U,[l(n,{to:"/en/document/level-0/ch04-security.html"},{default:s(()=>[e("《安全防护篇》")]),_:1})])]),t("tr",null,[W,Y,Z,t("td",$,[l(n,{to:"/en/document/level-0/ch05-webpage.html"},{default:s(()=>[e("《网站建设篇》")]),_:1})])]),t("tr",null,[tt,et,lt,t("td",nt,[l(n,{to:"/en/document/level-0/ch05-webpage.html"},{default:s(()=>[e("《网站建设篇》")]),_:1})])]),t("tr",null,[st,ot,dt,t("td",ct,[l(n,{to:"/en/document/level-0/ch06-certificates.html"},{default:s(()=>[e("《证书管理篇》")]),_:1})])]),t("tr",null,[it,_t,at,t("td",rt,[l(n,{to:"/en/document/level-0/ch06-certificates.html"},{default:s(()=>[e("《证书管理篇》")]),_:1})])]),t("tr",null,[ht,ut,yt,t("td",xt,[l(n,{to:"/en/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])]),t("tr",null,[gt,ft,mt,t("td",vt,[l(n,{to:"/en/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])]),t("tr",null,[pt,Xt,bt,t("td",kt,[l(n,{to:"/en/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])]),t("tr",null,[Lt,wt,Tt,t("td",Nt,[l(n,{to:"/en/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])]),t("tr",null,[St,Bt,Vt,t("td",Ct,[l(n,{to:"/en/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])])])]),It,t("table",null,[Rt,t("tbody",null,[t("tr",null,[jt,At,Et,t("td",Ht,[l(n,{to:"/en/document/level-0/ch03-ssh.html"},{default:s(()=>[e("《远程登录篇》")]),_:1})])]),t("tr",null,[qt,zt,Dt,t("td",Ft,[l(n,{to:"/en/document/level-0/ch05-webpage.html"},{default:s(()=>[e("《网站建设篇》")]),_:1})])]),t("tr",null,[Gt,Jt,Kt,t("td",Mt,[l(n,{to:"/en/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])]),t("tr",null,[Ot,Pt,Qt,t("td",Ut,[l(n,{to:"/en/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])]),t("tr",null,[Wt,Yt,Zt,t("td",$t,[l(n,{to:"/en/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])]),t("tr",null,[te,ee,le,t("td",ne,[l(n,{to:"/en/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])]),t("tr",null,[se,oe,de,t("td",ce,[l(n,{to:"/en/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])])])]),ie,t("table",null,[_e,t("tbody",null,[t("tr",null,[ae,re,he,t("td",ue,[l(n,{to:"/en/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])]),t("tr",null,[ye,xe,ge,t("td",fe,[l(n,{to:"/en/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])]),t("tr",null,[me,ve,pe,t("td",Xe,[l(n,{to:"/en/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])]),t("tr",null,[be,ke,Le,t("td",we,[l(n,{to:"/en/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])]),t("tr",null,[Te,Ne,Se,t("td",Be,[l(n,{to:"/en/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])])])])])}const je=c(a,[["render",Ve],["__file","ch09-appendix.html.vue"]]);export{je as default};
                                      diff --git a/assets/ch09-appendix.html-DH1J1Cus.js b/assets/ch09-appendix.html-Z0-Hyrvi.js
                                      similarity index 99%
                                      rename from assets/ch09-appendix.html-DH1J1Cus.js
                                      rename to assets/ch09-appendix.html-Z0-Hyrvi.js
                                      index 10e372b650..9e57a940a1 100644
                                      --- a/assets/ch09-appendix.html-DH1J1Cus.js
                                      +++ b/assets/ch09-appendix.html-Z0-Hyrvi.js
                                      @@ -1 +1 @@
                                      -import{_ as c,r as o,o as i,c as _,a as l,b as t,w as s,d as e}from"./app-DBM4OJyw.js";const a={},r=t("h1",{id:"【第-9-章】附录",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#【第-9-章】附录"},[t("span",null,"【第 9 章】附录")])],-1),h=t("h2",{id:"_1-小小白白-linux-基础命令索引",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#_1-小小白白-linux-基础命令索引"},[t("span",null,"1. 小小白白 Linux 基础命令索引")])],-1),u=t("thead",null,[t("tr",null,[t("th",{style:{"text-align":"center"}},"编号"),t("th",{style:{"text-align":"left"}},"命令名称"),t("th",{style:{"text-align":"left"}},"命令说明"),t("th",{style:{"text-align":"center"}},"出现篇章")])],-1),y=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-01")],-1),x=t("td",{style:{"text-align":"left"}},[t("code",null,"apt update")],-1),g=t("td",{style:{"text-align":"left"}},"查询软件更新",-1),f={style:{"text-align":"center"}},m=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-02")],-1),v=t("td",{style:{"text-align":"left"}},[t("code",null,"apt upgrade")],-1),p=t("td",{style:{"text-align":"left"}},"执行软件更新",-1),X={style:{"text-align":"center"}},b=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-03")],-1),k=t("td",{style:{"text-align":"left"}},[t("code",null,"nano")],-1),L=t("td",{style:{"text-align":"left"}},"文本编辑器",-1),w={style:{"text-align":"center"}},T=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-04")],-1),N=t("td",{style:{"text-align":"left"}},[t("code",null,"systemctl restart")],-1),S=t("td",{style:{"text-align":"left"}},"重启某个服务",-1),B={style:{"text-align":"center"}},V=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-05")],-1),C=t("td",{style:{"text-align":"left"}},[t("code",null,"adduser")],-1),I=t("td",{style:{"text-align":"left"}},"给系统新增用户",-1),R={style:{"text-align":"center"}},j=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-06")],-1),A=t("td",{style:{"text-align":"left"}},[t("code",null,"apt install")],-1),E=t("td",{style:{"text-align":"left"}},"安装某个软件",-1),H={style:{"text-align":"center"}},q=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-07")],-1),z=t("td",{style:{"text-align":"left"}},[t("code",null,"visudo")],-1),D=t("td",{style:{"text-align":"left"}},"修改 sudo 权限设置专用编辑器",-1),F={style:{"text-align":"center"}},G=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-08")],-1),J=t("td",{style:{"text-align":"left"}},[t("code",null,"sudo")],-1),K=t("td",{style:{"text-align":"left"}},[e("用"),t("code",null,"root"),e("权限运行某个命令")],-1),M={style:{"text-align":"center"}},O=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-09")],-1),P=t("td",{style:{"text-align":"left"}},[t("code",null,"chmod")],-1),Q=t("td",{style:{"text-align":"left"}},"修改目标文件/文件夹的权限",-1),U={style:{"text-align":"center"}},W=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-10")],-1),Y=t("td",{style:{"text-align":"left"}},[t("code",null,"mkdir")],-1),Z=t("td",{style:{"text-align":"left"}},"新建文件夹",-1),$={style:{"text-align":"center"}},tt=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-11")],-1),et=t("td",{style:{"text-align":"left"}},[t("code",null,"systemctl reload")],-1),lt=t("td",{style:{"text-align":"left"}},"重新加载某个服务",-1),nt={style:{"text-align":"center"}},st=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-12")],-1),ot=t("td",{style:{"text-align":"left"}},[t("code",null,"wget")],-1),dt=t("td",{style:{"text-align":"left"}},"访问(或下载)某个网页文件",-1),ct={style:{"text-align":"center"}},it=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-13")],-1),_t=t("td",{style:{"text-align":"left"}},[t("code",null,"acme.sh")],-1),at=t("td",{style:{"text-align":"left"}},"acme.sh 证书管理相关的命令",-1),rt={style:{"text-align":"center"}},ht=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-14")],-1),ut=t("td",{style:{"text-align":"left"}},[t("code",null,"rm")],-1),yt=t("td",{style:{"text-align":"left"}},"删除命令",-1),xt={style:{"text-align":"center"}},gt=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-15")],-1),ft=t("td",{style:{"text-align":"left"}},[t("code",null,"crontab -e")],-1),mt=t("td",{style:{"text-align":"left"}},"编辑当前用户的定时任务",-1),vt={style:{"text-align":"center"}},pt=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-16")],-1),Xt=t("td",{style:{"text-align":"left"}},[t("code",null,"touch")],-1),bt=t("td",{style:{"text-align":"left"}},"建立空白文件",-1),kt={style:{"text-align":"center"}},Lt=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-17")],-1),wt=t("td",{style:{"text-align":"left"}},[t("code",null,"systemctl")],-1),Tt=t("td",{style:{"text-align":"left"}},[t("code",null,"systemd"),e("基本服务管理命令")],-1),Nt={style:{"text-align":"center"}},St=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-18")],-1),Bt=t("td",{style:{"text-align":"left"}},[t("code",null,"reboot")],-1),Vt=t("td",{style:{"text-align":"left"}},"重启 Linux 系统",-1),Ct={style:{"text-align":"center"}},It=t("h2",{id:"_2-小小白白-linux-重要配置文件索引",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#_2-小小白白-linux-重要配置文件索引"},[t("span",null,"2. 小小白白 Linux 重要配置文件索引")])],-1),Rt=t("thead",null,[t("tr",null,[t("th",{style:{"text-align":"center"}},"编号"),t("th",{style:{"text-align":"left"}},"配置文件位置"),t("th",{style:{"text-align":"left"}},"文件说明"),t("th",{style:{"text-align":"center"}},"出现篇章")])],-1),jt=t("td",{style:{"text-align":"center"}},[t("code",null,"conf-01")],-1),At=t("td",{style:{"text-align":"left"}},[t("code",null,"/etc/ssh/sshd_config")],-1),Et=t("td",{style:{"text-align":"left"}},"SSH 远程登录程序设置",-1),Ht={style:{"text-align":"center"}},qt=t("td",{style:{"text-align":"center"}},[t("code",null,"conf-02")],-1),zt=t("td",{style:{"text-align":"left"}},[t("code",null,"/etc/nginx/nginx.conf")],-1),Dt=t("td",{style:{"text-align":"left"}},"Nginx 程序设置",-1),Ft={style:{"text-align":"center"}},Gt=t("td",{style:{"text-align":"center"}},[t("code",null,"conf-03")],-1),Jt=t("td",{style:{"text-align":"left"}},[t("code",null,"/etc/apt/sources.list")],-1),Kt=t("td",{style:{"text-align":"left"}},"apt 软件源列表",-1),Mt={style:{"text-align":"center"}},Ot=t("td",{style:{"text-align":"center"}},[t("code",null,"conf-04")],-1),Pt=t("td",{style:{"text-align":"left"}},[t("code",null,"/etc/apt/sources.list.d/vpsadmin.list")],-1),Qt=t("td",{style:{"text-align":"left"}},"用户自定义软件源列表列表",-1),Ut={style:{"text-align":"center"}},Wt=t("td",{style:{"text-align":"center"}},[t("code",null,"conf-05")],-1),Yt=t("td",{style:{"text-align":"left"}},[t("code",null,"crontab -e")],-1),Zt=t("td",{style:{"text-align":"left"}},"当前用户的定时任务",-1),$t={style:{"text-align":"center"}},te=t("td",{style:{"text-align":"center"}},[t("code",null,"conf-06")],-1),ee=t("td",{style:{"text-align":"left"}},[t("code",null,"/etc/sysctl.conf")],-1),le=t("td",{style:{"text-align":"left"}},"手动设置 kernel 参数",-1),ne={style:{"text-align":"center"}},se=t("td",{style:{"text-align":"center"}},[t("code",null,"conf-07")],-1),oe=t("td",{style:{"text-align":"left"}},[t("code",null,"/etc/sysctl.d/vpsadmin.conf")],-1),de=t("td",{style:{"text-align":"left"}},"用户自定义 kernel 参数配置文件",-1),ce={style:{"text-align":"center"}},ie=t("h2",{id:"_3-小小白白-xray-重要文件索引",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#_3-小小白白-xray-重要文件索引"},[t("span",null,"3. 小小白白 Xray 重要文件索引")])],-1),_e=t("thead",null,[t("tr",null,[t("th",{style:{"text-align":"center"}},"编号"),t("th",{style:{"text-align":"left"}},"配置文件位置"),t("th",{style:{"text-align":"left"}},"文件说明"),t("th",{style:{"text-align":"center"}},"出现篇章")])],-1),ae=t("td",{style:{"text-align":"center"}},[t("code",null,"xray-01")],-1),re=t("td",{style:{"text-align":"left"}},[t("code",null,"/usr/local/etc/xray/config.json")],-1),he=t("td",{style:{"text-align":"left"}},"Xray 程序设置",-1),ue={style:{"text-align":"center"}},ye=t("td",{style:{"text-align":"center"}},[t("code",null,"xray-02")],-1),xe=t("td",{style:{"text-align":"left"}},[t("code",null,"/home/vpsadmin/xray_cert/xray.cert")],-1),ge=t("td",{style:{"text-align":"left"}},"TLS 证书",-1),fe={style:{"text-align":"center"}},me=t("td",{style:{"text-align":"center"}},[t("code",null,"xray-03")],-1),ve=t("td",{style:{"text-align":"left"}},[t("code",null,"/home/vpsadmin/xray_cert/xray.key")],-1),pe=t("td",{style:{"text-align":"left"}},"TLS 私钥",-1),Xe={style:{"text-align":"center"}},be=t("td",{style:{"text-align":"center"}},[t("code",null,"xray-04")],-1),ke=t("td",{style:{"text-align":"left"}},[t("code",null,"/home/vpsadmin/xray_log/access.log")],-1),Le=t("td",{style:{"text-align":"left"}},"Xray 访问日志",-1),we={style:{"text-align":"center"}},Te=t("td",{style:{"text-align":"center"}},[t("code",null,"xray-05")],-1),Ne=t("td",{style:{"text-align":"left"}},[t("code",null,"/home/vpsadmin/xray_log/error.log")],-1),Se=t("td",{style:{"text-align":"left"}},"Xray 错误日志",-1),Be={style:{"text-align":"center"}};function Ve(Ce,Ie){const d=o("I18nTip"),n=o("RouterLink");return i(),_("div",null,[l(d),r,h,t("table",null,[u,t("tbody",null,[t("tr",null,[y,x,g,t("td",f,[l(n,{to:"/document/level-0/ch03-ssh.html"},{default:s(()=>[e("《远程登录篇》")]),_:1})])]),t("tr",null,[m,v,p,t("td",X,[l(n,{to:"/document/level-0/ch03-ssh.html"},{default:s(()=>[e("《远程登录篇》")]),_:1})])]),t("tr",null,[b,k,L,t("td",w,[l(n,{to:"/document/level-0/ch04-security.html"},{default:s(()=>[e("《安全防护篇》")]),_:1})])]),t("tr",null,[T,N,S,t("td",B,[l(n,{to:"/document/level-0/ch04-security.html"},{default:s(()=>[e("《安全防护篇》")]),_:1})])]),t("tr",null,[V,C,I,t("td",R,[l(n,{to:"/document/level-0/ch04-security.html"},{default:s(()=>[e("《安全防护篇》")]),_:1})])]),t("tr",null,[j,A,E,t("td",H,[l(n,{to:"/document/level-0/ch04-security.html"},{default:s(()=>[e("《安全防护篇》")]),_:1})])]),t("tr",null,[q,z,D,t("td",F,[l(n,{to:"/document/level-0/ch04-security.html"},{default:s(()=>[e("《安全防护篇》")]),_:1})])]),t("tr",null,[G,J,K,t("td",M,[l(n,{to:"/document/level-0/ch04-security.html"},{default:s(()=>[e("《安全防护篇》")]),_:1})])]),t("tr",null,[O,P,Q,t("td",U,[l(n,{to:"/document/level-0/ch04-security.html"},{default:s(()=>[e("《安全防护篇》")]),_:1})])]),t("tr",null,[W,Y,Z,t("td",$,[l(n,{to:"/document/level-0/ch05-webpage.html"},{default:s(()=>[e("《网站建设篇》")]),_:1})])]),t("tr",null,[tt,et,lt,t("td",nt,[l(n,{to:"/document/level-0/ch05-webpage.html"},{default:s(()=>[e("《网站建设篇》")]),_:1})])]),t("tr",null,[st,ot,dt,t("td",ct,[l(n,{to:"/document/level-0/ch06-certificates.html"},{default:s(()=>[e("《证书管理篇》")]),_:1})])]),t("tr",null,[it,_t,at,t("td",rt,[l(n,{to:"/document/level-0/ch06-certificates.html"},{default:s(()=>[e("《证书管理篇》")]),_:1})])]),t("tr",null,[ht,ut,yt,t("td",xt,[l(n,{to:"/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])]),t("tr",null,[gt,ft,mt,t("td",vt,[l(n,{to:"/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])]),t("tr",null,[pt,Xt,bt,t("td",kt,[l(n,{to:"/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])]),t("tr",null,[Lt,wt,Tt,t("td",Nt,[l(n,{to:"/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])]),t("tr",null,[St,Bt,Vt,t("td",Ct,[l(n,{to:"/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])])])]),It,t("table",null,[Rt,t("tbody",null,[t("tr",null,[jt,At,Et,t("td",Ht,[l(n,{to:"/document/level-0/ch03-ssh.html"},{default:s(()=>[e("《远程登录篇》")]),_:1})])]),t("tr",null,[qt,zt,Dt,t("td",Ft,[l(n,{to:"/document/level-0/ch05-webpage.html"},{default:s(()=>[e("《网站建设篇》")]),_:1})])]),t("tr",null,[Gt,Jt,Kt,t("td",Mt,[l(n,{to:"/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])]),t("tr",null,[Ot,Pt,Qt,t("td",Ut,[l(n,{to:"/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])]),t("tr",null,[Wt,Yt,Zt,t("td",$t,[l(n,{to:"/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])]),t("tr",null,[te,ee,le,t("td",ne,[l(n,{to:"/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])]),t("tr",null,[se,oe,de,t("td",ce,[l(n,{to:"/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])])])]),ie,t("table",null,[_e,t("tbody",null,[t("tr",null,[ae,re,he,t("td",ue,[l(n,{to:"/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])]),t("tr",null,[ye,xe,ge,t("td",fe,[l(n,{to:"/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])]),t("tr",null,[me,ve,pe,t("td",Xe,[l(n,{to:"/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])]),t("tr",null,[be,ke,Le,t("td",we,[l(n,{to:"/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])]),t("tr",null,[Te,Ne,Se,t("td",Be,[l(n,{to:"/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])])])])])}const je=c(a,[["render",Ve],["__file","ch09-appendix.html.vue"]]);export{je as default};
                                      +import{_ as c,r as o,o as i,c as _,a as l,b as t,w as s,d as e}from"./app-D7uBbsY3.js";const a={},r=t("h1",{id:"【第-9-章】附录",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#【第-9-章】附录"},[t("span",null,"【第 9 章】附录")])],-1),h=t("h2",{id:"_1-小小白白-linux-基础命令索引",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#_1-小小白白-linux-基础命令索引"},[t("span",null,"1. 小小白白 Linux 基础命令索引")])],-1),u=t("thead",null,[t("tr",null,[t("th",{style:{"text-align":"center"}},"编号"),t("th",{style:{"text-align":"left"}},"命令名称"),t("th",{style:{"text-align":"left"}},"命令说明"),t("th",{style:{"text-align":"center"}},"出现篇章")])],-1),y=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-01")],-1),x=t("td",{style:{"text-align":"left"}},[t("code",null,"apt update")],-1),g=t("td",{style:{"text-align":"left"}},"查询软件更新",-1),f={style:{"text-align":"center"}},m=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-02")],-1),v=t("td",{style:{"text-align":"left"}},[t("code",null,"apt upgrade")],-1),p=t("td",{style:{"text-align":"left"}},"执行软件更新",-1),X={style:{"text-align":"center"}},b=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-03")],-1),k=t("td",{style:{"text-align":"left"}},[t("code",null,"nano")],-1),L=t("td",{style:{"text-align":"left"}},"文本编辑器",-1),w={style:{"text-align":"center"}},T=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-04")],-1),N=t("td",{style:{"text-align":"left"}},[t("code",null,"systemctl restart")],-1),S=t("td",{style:{"text-align":"left"}},"重启某个服务",-1),B={style:{"text-align":"center"}},V=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-05")],-1),C=t("td",{style:{"text-align":"left"}},[t("code",null,"adduser")],-1),I=t("td",{style:{"text-align":"left"}},"给系统新增用户",-1),R={style:{"text-align":"center"}},j=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-06")],-1),A=t("td",{style:{"text-align":"left"}},[t("code",null,"apt install")],-1),E=t("td",{style:{"text-align":"left"}},"安装某个软件",-1),H={style:{"text-align":"center"}},q=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-07")],-1),z=t("td",{style:{"text-align":"left"}},[t("code",null,"visudo")],-1),D=t("td",{style:{"text-align":"left"}},"修改 sudo 权限设置专用编辑器",-1),F={style:{"text-align":"center"}},G=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-08")],-1),J=t("td",{style:{"text-align":"left"}},[t("code",null,"sudo")],-1),K=t("td",{style:{"text-align":"left"}},[e("用"),t("code",null,"root"),e("权限运行某个命令")],-1),M={style:{"text-align":"center"}},O=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-09")],-1),P=t("td",{style:{"text-align":"left"}},[t("code",null,"chmod")],-1),Q=t("td",{style:{"text-align":"left"}},"修改目标文件/文件夹的权限",-1),U={style:{"text-align":"center"}},W=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-10")],-1),Y=t("td",{style:{"text-align":"left"}},[t("code",null,"mkdir")],-1),Z=t("td",{style:{"text-align":"left"}},"新建文件夹",-1),$={style:{"text-align":"center"}},tt=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-11")],-1),et=t("td",{style:{"text-align":"left"}},[t("code",null,"systemctl reload")],-1),lt=t("td",{style:{"text-align":"left"}},"重新加载某个服务",-1),nt={style:{"text-align":"center"}},st=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-12")],-1),ot=t("td",{style:{"text-align":"left"}},[t("code",null,"wget")],-1),dt=t("td",{style:{"text-align":"left"}},"访问(或下载)某个网页文件",-1),ct={style:{"text-align":"center"}},it=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-13")],-1),_t=t("td",{style:{"text-align":"left"}},[t("code",null,"acme.sh")],-1),at=t("td",{style:{"text-align":"left"}},"acme.sh 证书管理相关的命令",-1),rt={style:{"text-align":"center"}},ht=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-14")],-1),ut=t("td",{style:{"text-align":"left"}},[t("code",null,"rm")],-1),yt=t("td",{style:{"text-align":"left"}},"删除命令",-1),xt={style:{"text-align":"center"}},gt=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-15")],-1),ft=t("td",{style:{"text-align":"left"}},[t("code",null,"crontab -e")],-1),mt=t("td",{style:{"text-align":"left"}},"编辑当前用户的定时任务",-1),vt={style:{"text-align":"center"}},pt=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-16")],-1),Xt=t("td",{style:{"text-align":"left"}},[t("code",null,"touch")],-1),bt=t("td",{style:{"text-align":"left"}},"建立空白文件",-1),kt={style:{"text-align":"center"}},Lt=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-17")],-1),wt=t("td",{style:{"text-align":"left"}},[t("code",null,"systemctl")],-1),Tt=t("td",{style:{"text-align":"left"}},[t("code",null,"systemd"),e("基本服务管理命令")],-1),Nt={style:{"text-align":"center"}},St=t("td",{style:{"text-align":"center"}},[t("code",null,"cmd-18")],-1),Bt=t("td",{style:{"text-align":"left"}},[t("code",null,"reboot")],-1),Vt=t("td",{style:{"text-align":"left"}},"重启 Linux 系统",-1),Ct={style:{"text-align":"center"}},It=t("h2",{id:"_2-小小白白-linux-重要配置文件索引",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#_2-小小白白-linux-重要配置文件索引"},[t("span",null,"2. 小小白白 Linux 重要配置文件索引")])],-1),Rt=t("thead",null,[t("tr",null,[t("th",{style:{"text-align":"center"}},"编号"),t("th",{style:{"text-align":"left"}},"配置文件位置"),t("th",{style:{"text-align":"left"}},"文件说明"),t("th",{style:{"text-align":"center"}},"出现篇章")])],-1),jt=t("td",{style:{"text-align":"center"}},[t("code",null,"conf-01")],-1),At=t("td",{style:{"text-align":"left"}},[t("code",null,"/etc/ssh/sshd_config")],-1),Et=t("td",{style:{"text-align":"left"}},"SSH 远程登录程序设置",-1),Ht={style:{"text-align":"center"}},qt=t("td",{style:{"text-align":"center"}},[t("code",null,"conf-02")],-1),zt=t("td",{style:{"text-align":"left"}},[t("code",null,"/etc/nginx/nginx.conf")],-1),Dt=t("td",{style:{"text-align":"left"}},"Nginx 程序设置",-1),Ft={style:{"text-align":"center"}},Gt=t("td",{style:{"text-align":"center"}},[t("code",null,"conf-03")],-1),Jt=t("td",{style:{"text-align":"left"}},[t("code",null,"/etc/apt/sources.list")],-1),Kt=t("td",{style:{"text-align":"left"}},"apt 软件源列表",-1),Mt={style:{"text-align":"center"}},Ot=t("td",{style:{"text-align":"center"}},[t("code",null,"conf-04")],-1),Pt=t("td",{style:{"text-align":"left"}},[t("code",null,"/etc/apt/sources.list.d/vpsadmin.list")],-1),Qt=t("td",{style:{"text-align":"left"}},"用户自定义软件源列表列表",-1),Ut={style:{"text-align":"center"}},Wt=t("td",{style:{"text-align":"center"}},[t("code",null,"conf-05")],-1),Yt=t("td",{style:{"text-align":"left"}},[t("code",null,"crontab -e")],-1),Zt=t("td",{style:{"text-align":"left"}},"当前用户的定时任务",-1),$t={style:{"text-align":"center"}},te=t("td",{style:{"text-align":"center"}},[t("code",null,"conf-06")],-1),ee=t("td",{style:{"text-align":"left"}},[t("code",null,"/etc/sysctl.conf")],-1),le=t("td",{style:{"text-align":"left"}},"手动设置 kernel 参数",-1),ne={style:{"text-align":"center"}},se=t("td",{style:{"text-align":"center"}},[t("code",null,"conf-07")],-1),oe=t("td",{style:{"text-align":"left"}},[t("code",null,"/etc/sysctl.d/vpsadmin.conf")],-1),de=t("td",{style:{"text-align":"left"}},"用户自定义 kernel 参数配置文件",-1),ce={style:{"text-align":"center"}},ie=t("h2",{id:"_3-小小白白-xray-重要文件索引",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#_3-小小白白-xray-重要文件索引"},[t("span",null,"3. 小小白白 Xray 重要文件索引")])],-1),_e=t("thead",null,[t("tr",null,[t("th",{style:{"text-align":"center"}},"编号"),t("th",{style:{"text-align":"left"}},"配置文件位置"),t("th",{style:{"text-align":"left"}},"文件说明"),t("th",{style:{"text-align":"center"}},"出现篇章")])],-1),ae=t("td",{style:{"text-align":"center"}},[t("code",null,"xray-01")],-1),re=t("td",{style:{"text-align":"left"}},[t("code",null,"/usr/local/etc/xray/config.json")],-1),he=t("td",{style:{"text-align":"left"}},"Xray 程序设置",-1),ue={style:{"text-align":"center"}},ye=t("td",{style:{"text-align":"center"}},[t("code",null,"xray-02")],-1),xe=t("td",{style:{"text-align":"left"}},[t("code",null,"/home/vpsadmin/xray_cert/xray.cert")],-1),ge=t("td",{style:{"text-align":"left"}},"TLS 证书",-1),fe={style:{"text-align":"center"}},me=t("td",{style:{"text-align":"center"}},[t("code",null,"xray-03")],-1),ve=t("td",{style:{"text-align":"left"}},[t("code",null,"/home/vpsadmin/xray_cert/xray.key")],-1),pe=t("td",{style:{"text-align":"left"}},"TLS 私钥",-1),Xe={style:{"text-align":"center"}},be=t("td",{style:{"text-align":"center"}},[t("code",null,"xray-04")],-1),ke=t("td",{style:{"text-align":"left"}},[t("code",null,"/home/vpsadmin/xray_log/access.log")],-1),Le=t("td",{style:{"text-align":"left"}},"Xray 访问日志",-1),we={style:{"text-align":"center"}},Te=t("td",{style:{"text-align":"center"}},[t("code",null,"xray-05")],-1),Ne=t("td",{style:{"text-align":"left"}},[t("code",null,"/home/vpsadmin/xray_log/error.log")],-1),Se=t("td",{style:{"text-align":"left"}},"Xray 错误日志",-1),Be={style:{"text-align":"center"}};function Ve(Ce,Ie){const d=o("I18nTip"),n=o("RouterLink");return i(),_("div",null,[l(d),r,h,t("table",null,[u,t("tbody",null,[t("tr",null,[y,x,g,t("td",f,[l(n,{to:"/document/level-0/ch03-ssh.html"},{default:s(()=>[e("《远程登录篇》")]),_:1})])]),t("tr",null,[m,v,p,t("td",X,[l(n,{to:"/document/level-0/ch03-ssh.html"},{default:s(()=>[e("《远程登录篇》")]),_:1})])]),t("tr",null,[b,k,L,t("td",w,[l(n,{to:"/document/level-0/ch04-security.html"},{default:s(()=>[e("《安全防护篇》")]),_:1})])]),t("tr",null,[T,N,S,t("td",B,[l(n,{to:"/document/level-0/ch04-security.html"},{default:s(()=>[e("《安全防护篇》")]),_:1})])]),t("tr",null,[V,C,I,t("td",R,[l(n,{to:"/document/level-0/ch04-security.html"},{default:s(()=>[e("《安全防护篇》")]),_:1})])]),t("tr",null,[j,A,E,t("td",H,[l(n,{to:"/document/level-0/ch04-security.html"},{default:s(()=>[e("《安全防护篇》")]),_:1})])]),t("tr",null,[q,z,D,t("td",F,[l(n,{to:"/document/level-0/ch04-security.html"},{default:s(()=>[e("《安全防护篇》")]),_:1})])]),t("tr",null,[G,J,K,t("td",M,[l(n,{to:"/document/level-0/ch04-security.html"},{default:s(()=>[e("《安全防护篇》")]),_:1})])]),t("tr",null,[O,P,Q,t("td",U,[l(n,{to:"/document/level-0/ch04-security.html"},{default:s(()=>[e("《安全防护篇》")]),_:1})])]),t("tr",null,[W,Y,Z,t("td",$,[l(n,{to:"/document/level-0/ch05-webpage.html"},{default:s(()=>[e("《网站建设篇》")]),_:1})])]),t("tr",null,[tt,et,lt,t("td",nt,[l(n,{to:"/document/level-0/ch05-webpage.html"},{default:s(()=>[e("《网站建设篇》")]),_:1})])]),t("tr",null,[st,ot,dt,t("td",ct,[l(n,{to:"/document/level-0/ch06-certificates.html"},{default:s(()=>[e("《证书管理篇》")]),_:1})])]),t("tr",null,[it,_t,at,t("td",rt,[l(n,{to:"/document/level-0/ch06-certificates.html"},{default:s(()=>[e("《证书管理篇》")]),_:1})])]),t("tr",null,[ht,ut,yt,t("td",xt,[l(n,{to:"/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])]),t("tr",null,[gt,ft,mt,t("td",vt,[l(n,{to:"/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])]),t("tr",null,[pt,Xt,bt,t("td",kt,[l(n,{to:"/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])]),t("tr",null,[Lt,wt,Tt,t("td",Nt,[l(n,{to:"/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])]),t("tr",null,[St,Bt,Vt,t("td",Ct,[l(n,{to:"/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])])])]),It,t("table",null,[Rt,t("tbody",null,[t("tr",null,[jt,At,Et,t("td",Ht,[l(n,{to:"/document/level-0/ch03-ssh.html"},{default:s(()=>[e("《远程登录篇》")]),_:1})])]),t("tr",null,[qt,zt,Dt,t("td",Ft,[l(n,{to:"/document/level-0/ch05-webpage.html"},{default:s(()=>[e("《网站建设篇》")]),_:1})])]),t("tr",null,[Gt,Jt,Kt,t("td",Mt,[l(n,{to:"/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])]),t("tr",null,[Ot,Pt,Qt,t("td",Ut,[l(n,{to:"/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])]),t("tr",null,[Wt,Yt,Zt,t("td",$t,[l(n,{to:"/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])]),t("tr",null,[te,ee,le,t("td",ne,[l(n,{to:"/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])]),t("tr",null,[se,oe,de,t("td",ce,[l(n,{to:"/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])])])]),ie,t("table",null,[_e,t("tbody",null,[t("tr",null,[ae,re,he,t("td",ue,[l(n,{to:"/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])]),t("tr",null,[ye,xe,ge,t("td",fe,[l(n,{to:"/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])]),t("tr",null,[me,ve,pe,t("td",Xe,[l(n,{to:"/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])]),t("tr",null,[be,ke,Le,t("td",we,[l(n,{to:"/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])]),t("tr",null,[Te,Ne,Se,t("td",Be,[l(n,{to:"/document/level-0/ch07-xray-server.html"},{default:s(()=>[e("《Xray 服务器篇》")]),_:1})])])])])])}const je=c(a,[["render",Ve],["__file","ch09-appendix.html.vue"]]);export{je as default};
                                      diff --git a/assets/channel-BHWICgEe.js b/assets/channel-BHWICgEe.js
                                      deleted file mode 100644
                                      index 354a2d52c6..0000000000
                                      --- a/assets/channel-BHWICgEe.js
                                      +++ /dev/null
                                      @@ -1 +0,0 @@
                                      -import{U as a,E as n}from"./mermaid.core-DapiNGBY.js";const t=(r,o)=>a.lang.round(n.parse(r)[o]);export{t as c};
                                      diff --git a/assets/channel-uApa1cOK.js b/assets/channel-uApa1cOK.js
                                      new file mode 100644
                                      index 0000000000..11ae2abff8
                                      --- /dev/null
                                      +++ b/assets/channel-uApa1cOK.js
                                      @@ -0,0 +1 @@
                                      +import{U as a,E as n}from"./mermaid.core-D8igZDel.js";const t=(r,o)=>a.lang.round(n.parse(r)[o]);export{t as c};
                                      diff --git a/assets/chunk-AIUMCIBP-g55d6rFj.js b/assets/chunk-AIUMCIBP-v8d5o65o.js
                                      similarity index 95%
                                      rename from assets/chunk-AIUMCIBP-g55d6rFj.js
                                      rename to assets/chunk-AIUMCIBP-v8d5o65o.js
                                      index cbd12fc00b..f4009646a4 100644
                                      --- a/assets/chunk-AIUMCIBP-g55d6rFj.js
                                      +++ b/assets/chunk-AIUMCIBP-v8d5o65o.js
                                      @@ -1 +1 @@
                                      -import{_ as n,n as c,m as l}from"./mermaid.core-DapiNGBY.js";var o=n((a,t)=>{const e=a.append("rect");if(e.attr("x",t.x),e.attr("y",t.y),e.attr("fill",t.fill),e.attr("stroke",t.stroke),e.attr("width",t.width),e.attr("height",t.height),t.name&&e.attr("name",t.name),t.rx&&e.attr("rx",t.rx),t.ry&&e.attr("ry",t.ry),t.attrs!==void 0)for(const r in t.attrs)e.attr(r,t.attrs[r]);return t.class&&e.attr("class",t.class),e},"drawRect"),d=n((a,t)=>{const e={x:t.startx,y:t.starty,width:t.stopx-t.startx,height:t.stopy-t.starty,fill:t.fill,stroke:t.stroke,class:"rect"};o(a,e).lower()},"drawBackgroundRect"),g=n((a,t)=>{const e=t.text.replace(c," "),r=a.append("text");r.attr("x",t.x),r.attr("y",t.y),r.attr("class","legend"),r.style("text-anchor",t.anchor),t.class&&r.attr("class",t.class);const s=r.append("tspan");return s.attr("x",t.x+t.textMargin*2),s.text(e),r},"drawText"),m=n((a,t,e,r)=>{const s=a.append("image");s.attr("x",t),s.attr("y",e);const i=l(r);s.attr("xlink:href",i)},"drawImage"),h=n((a,t,e,r)=>{const s=a.append("use");s.attr("x",t),s.attr("y",e);const i=l(r);s.attr("xlink:href",`#${i}`)},"drawEmbeddedImage"),y=n(()=>({x:0,y:0,width:100,height:100,fill:"#EDF2AE",stroke:"#666",anchor:"start",rx:0,ry:0}),"getNoteRect"),p=n(()=>({x:0,y:0,width:100,height:100,"text-anchor":"start",style:"#666",textMargin:0,rx:0,ry:0,tspan:!0}),"getTextObj");export{p as a,d as b,h as c,o as d,m as e,g as f,y as g};
                                      +import{_ as n,n as c,m as l}from"./mermaid.core-D8igZDel.js";var o=n((a,t)=>{const e=a.append("rect");if(e.attr("x",t.x),e.attr("y",t.y),e.attr("fill",t.fill),e.attr("stroke",t.stroke),e.attr("width",t.width),e.attr("height",t.height),t.name&&e.attr("name",t.name),t.rx&&e.attr("rx",t.rx),t.ry&&e.attr("ry",t.ry),t.attrs!==void 0)for(const r in t.attrs)e.attr(r,t.attrs[r]);return t.class&&e.attr("class",t.class),e},"drawRect"),d=n((a,t)=>{const e={x:t.startx,y:t.starty,width:t.stopx-t.startx,height:t.stopy-t.starty,fill:t.fill,stroke:t.stroke,class:"rect"};o(a,e).lower()},"drawBackgroundRect"),g=n((a,t)=>{const e=t.text.replace(c," "),r=a.append("text");r.attr("x",t.x),r.attr("y",t.y),r.attr("class","legend"),r.style("text-anchor",t.anchor),t.class&&r.attr("class",t.class);const s=r.append("tspan");return s.attr("x",t.x+t.textMargin*2),s.text(e),r},"drawText"),m=n((a,t,e,r)=>{const s=a.append("image");s.attr("x",t),s.attr("y",e);const i=l(r);s.attr("xlink:href",i)},"drawImage"),h=n((a,t,e,r)=>{const s=a.append("use");s.attr("x",t),s.attr("y",e);const i=l(r);s.attr("xlink:href",`#${i}`)},"drawEmbeddedImage"),y=n(()=>({x:0,y:0,width:100,height:100,fill:"#EDF2AE",stroke:"#666",anchor:"start",rx:0,ry:0}),"getNoteRect"),p=n(()=>({x:0,y:0,width:100,height:100,"text-anchor":"start",style:"#666",textMargin:0,rx:0,ry:0,tspan:!0}),"getTextObj");export{p as a,d as b,h as c,o as d,m as e,g as f,y as g};
                                      diff --git a/assets/chunk-FBCX6ULS-BW7zNCW8.js b/assets/chunk-FBCX6ULS-B99hIK7X.js
                                      similarity index 66%
                                      rename from assets/chunk-FBCX6ULS-BW7zNCW8.js
                                      rename to assets/chunk-FBCX6ULS-B99hIK7X.js
                                      index c6dfc68d05..463d1ced9b 100644
                                      --- a/assets/chunk-FBCX6ULS-BW7zNCW8.js
                                      +++ b/assets/chunk-FBCX6ULS-B99hIK7X.js
                                      @@ -1 +1 @@
                                      -import{_ as s}from"./mermaid.core-DapiNGBY.js";var t,e=(t=class{constructor(i){this.init=i,this.records=this.init()}reset(){this.records=this.init()}},s(t,"ImperativeState"),t);export{e as I};
                                      +import{_ as s}from"./mermaid.core-D8igZDel.js";var t,e=(t=class{constructor(i){this.init=i,this.records=this.init()}reset(){this.records=this.init()}},s(t,"ImperativeState"),t);export{e as I};
                                      diff --git a/assets/chunk-FUIDI54P-DcJSRBm9.js b/assets/chunk-FUIDI54P-B3wdDwu1.js
                                      similarity index 90%
                                      rename from assets/chunk-FUIDI54P-DcJSRBm9.js
                                      rename to assets/chunk-FUIDI54P-B3wdDwu1.js
                                      index 34092a0303..b7a5744a61 100644
                                      --- a/assets/chunk-FUIDI54P-DcJSRBm9.js
                                      +++ b/assets/chunk-FUIDI54P-B3wdDwu1.js
                                      @@ -1 +1 @@
                                      -import{_ as n,j as r,k as d,l as g}from"./mermaid.core-DapiNGBY.js";var u=n((t,e)=>{let o;return e==="sandbox"&&(o=r("#i"+t)),(e==="sandbox"?r(o.nodes()[0].contentDocument.body):r("body")).select(`[id="${t}"]`)},"getDiagramElement"),b=n((t,e,o,i)=>{t.attr("class",o);const{width:a,height:s,x:h,y:x}=l(t,e);d(t,s,a,i);const c=w(h,x,a,s,e);t.attr("viewBox",c),g.debug(`viewBox configured: ${c} with padding: ${e}`)},"setupViewPortForSVG"),l=n((t,e)=>{var i;const o=((i=t.node())==null?void 0:i.getBBox())||{width:0,height:0,x:0,y:0};return{width:o.width+e*2,height:o.height+e*2,x:o.x,y:o.y}},"calculateDimensionsWithPadding"),w=n((t,e,o,i,a)=>`${t-a} ${e-a} ${o} ${i}`,"createViewBox");export{u as g,b as s};
                                      +import{_ as n,j as r,k as d,l as g}from"./mermaid.core-D8igZDel.js";var u=n((t,e)=>{let o;return e==="sandbox"&&(o=r("#i"+t)),(e==="sandbox"?r(o.nodes()[0].contentDocument.body):r("body")).select(`[id="${t}"]`)},"getDiagramElement"),b=n((t,e,o,i)=>{t.attr("class",o);const{width:a,height:s,x:h,y:x}=l(t,e);d(t,s,a,i);const c=w(h,x,a,s,e);t.attr("viewBox",c),g.debug(`viewBox configured: ${c} with padding: ${e}`)},"setupViewPortForSVG"),l=n((t,e)=>{var i;const o=((i=t.node())==null?void 0:i.getBBox())||{width:0,height:0,x:0,y:0};return{width:o.width+e*2,height:o.height+e*2,x:o.x,y:o.y}},"calculateDimensionsWithPadding"),w=n((t,e,o,i,a)=>`${t-a} ${e-a} ${o} ${i}`,"createViewBox");export{u as g,b as s};
                                      diff --git a/assets/chunk-IBIA4ERB-Cq5yRPLn.js b/assets/chunk-IBIA4ERB-LOBGu4Xm.js
                                      similarity index 99%
                                      rename from assets/chunk-IBIA4ERB-Cq5yRPLn.js
                                      rename to assets/chunk-IBIA4ERB-LOBGu4Xm.js
                                      index 41ec7bb1b3..7513616d02 100644
                                      --- a/assets/chunk-IBIA4ERB-Cq5yRPLn.js
                                      +++ b/assets/chunk-IBIA4ERB-LOBGu4Xm.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as n,i as lt,d as D,a9 as Ve,s as ct,g as ot,b as ht,c as At,q as pt,r as ft,e as x,t as dt,l as Ct,u as $e,j as K}from"./mermaid.core-DapiNGBY.js";var Pe=function(){var e=n(function(O,a,l,A){for(l=l||{},A=O.length;A--;l[O[A]]=a);return l},"o"),i=[1,17],r=[1,18],h=[1,19],c=[1,39],f=[1,40],d=[1,25],B=[1,23],S=[1,24],N=[1,31],Ee=[1,32],ge=[1,33],me=[1,34],be=[1,35],ke=[1,36],Te=[1,26],ye=[1,27],Fe=[1,28],De=[1,29],E=[1,43],_e=[1,30],g=[1,42],m=[1,44],b=[1,41],T=[1,45],Be=[1,9],o=[1,8,9],Q=[1,56],X=[1,57],W=[1,58],q=[1,59],H=[1,60],Se=[1,61],ve=[1,62],J=[1,8,9,39],Ke=[1,74],G=[1,8,9,12,13,21,37,39,42,59,60,61,62,63,64,65,70,72],Z=[1,8,9,12,13,19,21,37,39,42,46,59,60,61,62,63,64,65,70,72,74,80,95,97,98],$=[13,74,80,95,97,98],U=[13,64,65,74,80,95,97,98],Ye=[13,59,60,61,62,63,74,80,95,97,98],Ne=[1,93],ee=[1,110],te=[1,108],se=[1,102],ie=[1,103],ue=[1,104],ne=[1,105],ae=[1,106],re=[1,107],le=[1,109],Le=[1,8,9,37,39,42],ce=[1,8,9,21],je=[1,8,9,78],v=[1,8,9,21,73,74,78,80,81,82,83,84,85],xe={trace:n(function(){},"trace"),yy:{},symbols_:{error:2,start:3,mermaidDoc:4,statements:5,graphConfig:6,CLASS_DIAGRAM:7,NEWLINE:8,EOF:9,statement:10,classLabel:11,SQS:12,STR:13,SQE:14,namespaceName:15,alphaNumToken:16,className:17,classLiteralName:18,GENERICTYPE:19,relationStatement:20,LABEL:21,namespaceStatement:22,classStatement:23,memberStatement:24,annotationStatement:25,clickStatement:26,styleStatement:27,cssClassStatement:28,noteStatement:29,direction:30,acc_title:31,acc_title_value:32,acc_descr:33,acc_descr_value:34,acc_descr_multiline_value:35,namespaceIdentifier:36,STRUCT_START:37,classStatements:38,STRUCT_STOP:39,NAMESPACE:40,classIdentifier:41,STYLE_SEPARATOR:42,members:43,CLASS:44,ANNOTATION_START:45,ANNOTATION_END:46,MEMBER:47,SEPARATOR:48,relation:49,NOTE_FOR:50,noteText:51,NOTE:52,direction_tb:53,direction_bt:54,direction_rl:55,direction_lr:56,relationType:57,lineType:58,AGGREGATION:59,EXTENSION:60,COMPOSITION:61,DEPENDENCY:62,LOLLIPOP:63,LINE:64,DOTTED_LINE:65,CALLBACK:66,LINK:67,LINK_TARGET:68,CLICK:69,CALLBACK_NAME:70,CALLBACK_ARGS:71,HREF:72,STYLE:73,ALPHA:74,stylesOpt:75,CSSCLASS:76,style:77,COMMA:78,styleComponent:79,NUM:80,COLON:81,UNIT:82,SPACE:83,BRKT:84,PCT:85,commentToken:86,textToken:87,graphCodeTokens:88,textNoTagsToken:89,TAGSTART:90,TAGEND:91,"==":92,"--":93,DEFAULT:94,MINUS:95,keywords:96,UNICODE_TEXT:97,BQUOTE_STR:98,$accept:0,$end:1},terminals_:{2:"error",7:"CLASS_DIAGRAM",8:"NEWLINE",9:"EOF",12:"SQS",13:"STR",14:"SQE",19:"GENERICTYPE",21:"LABEL",31:"acc_title",32:"acc_title_value",33:"acc_descr",34:"acc_descr_value",35:"acc_descr_multiline_value",37:"STRUCT_START",39:"STRUCT_STOP",40:"NAMESPACE",42:"STYLE_SEPARATOR",44:"CLASS",45:"ANNOTATION_START",46:"ANNOTATION_END",47:"MEMBER",48:"SEPARATOR",50:"NOTE_FOR",52:"NOTE",53:"direction_tb",54:"direction_bt",55:"direction_rl",56:"direction_lr",59:"AGGREGATION",60:"EXTENSION",61:"COMPOSITION",62:"DEPENDENCY",63:"LOLLIPOP",64:"LINE",65:"DOTTED_LINE",66:"CALLBACK",67:"LINK",68:"LINK_TARGET",69:"CLICK",70:"CALLBACK_NAME",71:"CALLBACK_ARGS",72:"HREF",73:"STYLE",74:"ALPHA",76:"CSSCLASS",78:"COMMA",80:"NUM",81:"COLON",82:"UNIT",83:"SPACE",84:"BRKT",85:"PCT",88:"graphCodeTokens",90:"TAGSTART",91:"TAGEND",92:"==",93:"--",94:"DEFAULT",95:"MINUS",96:"keywords",97:"UNICODE_TEXT",98:"BQUOTE_STR"},productions_:[0,[3,1],[3,1],[4,1],[6,4],[5,1],[5,2],[5,3],[11,3],[15,1],[15,2],[17,1],[17,1],[17,2],[17,2],[17,2],[10,1],[10,2],[10,1],[10,1],[10,1],[10,1],[10,1],[10,1],[10,1],[10,1],[10,1],[10,2],[10,2],[10,1],[22,4],[22,5],[36,2],[38,1],[38,2],[38,3],[23,1],[23,3],[23,4],[23,6],[41,2],[41,3],[25,4],[43,1],[43,2],[24,1],[24,2],[24,1],[24,1],[20,3],[20,4],[20,4],[20,5],[29,3],[29,2],[30,1],[30,1],[30,1],[30,1],[49,3],[49,2],[49,2],[49,1],[57,1],[57,1],[57,1],[57,1],[57,1],[58,1],[58,1],[26,3],[26,4],[26,3],[26,4],[26,4],[26,5],[26,3],[26,4],[26,4],[26,5],[26,4],[26,5],[26,5],[26,6],[27,3],[28,3],[75,1],[75,3],[77,1],[77,2],[79,1],[79,1],[79,1],[79,1],[79,1],[79,1],[79,1],[79,1],[79,1],[86,1],[86,1],[87,1],[87,1],[87,1],[87,1],[87,1],[87,1],[87,1],[89,1],[89,1],[89,1],[89,1],[16,1],[16,1],[16,1],[16,1],[18,1],[51,1]],performAction:n(function(a,l,A,u,p,t,z){var s=t.length-1;switch(p){case 8:this.$=t[s-1];break;case 9:case 11:case 12:this.$=t[s];break;case 10:case 13:this.$=t[s-1]+t[s];break;case 14:case 15:this.$=t[s-1]+"~"+t[s]+"~";break;case 16:u.addRelation(t[s]);break;case 17:t[s-1].title=u.cleanupLabel(t[s]),u.addRelation(t[s-1]);break;case 27:this.$=t[s].trim(),u.setAccTitle(this.$);break;case 28:case 29:this.$=t[s].trim(),u.setAccDescription(this.$);break;case 30:u.addClassesToNamespace(t[s-3],t[s-1]);break;case 31:u.addClassesToNamespace(t[s-4],t[s-1]);break;case 32:this.$=t[s],u.addNamespace(t[s]);break;case 33:this.$=[t[s]];break;case 34:this.$=[t[s-1]];break;case 35:t[s].unshift(t[s-2]),this.$=t[s];break;case 37:u.setCssClass(t[s-2],t[s]);break;case 38:u.addMembers(t[s-3],t[s-1]);break;case 39:u.setCssClass(t[s-5],t[s-3]),u.addMembers(t[s-5],t[s-1]);break;case 40:this.$=t[s],u.addClass(t[s]);break;case 41:this.$=t[s-1],u.addClass(t[s-1]),u.setClassLabel(t[s-1],t[s]);break;case 42:u.addAnnotation(t[s],t[s-2]);break;case 43:this.$=[t[s]];break;case 44:t[s].push(t[s-1]),this.$=t[s];break;case 45:break;case 46:u.addMember(t[s-1],u.cleanupLabel(t[s]));break;case 47:break;case 48:break;case 49:this.$={id1:t[s-2],id2:t[s],relation:t[s-1],relationTitle1:"none",relationTitle2:"none"};break;case 50:this.$={id1:t[s-3],id2:t[s],relation:t[s-1],relationTitle1:t[s-2],relationTitle2:"none"};break;case 51:this.$={id1:t[s-3],id2:t[s],relation:t[s-2],relationTitle1:"none",relationTitle2:t[s-1]};break;case 52:this.$={id1:t[s-4],id2:t[s],relation:t[s-2],relationTitle1:t[s-3],relationTitle2:t[s-1]};break;case 53:u.addNote(t[s],t[s-1]);break;case 54:u.addNote(t[s]);break;case 55:u.setDirection("TB");break;case 56:u.setDirection("BT");break;case 57:u.setDirection("RL");break;case 58:u.setDirection("LR");break;case 59:this.$={type1:t[s-2],type2:t[s],lineType:t[s-1]};break;case 60:this.$={type1:"none",type2:t[s],lineType:t[s-1]};break;case 61:this.$={type1:t[s-1],type2:"none",lineType:t[s]};break;case 62:this.$={type1:"none",type2:"none",lineType:t[s]};break;case 63:this.$=u.relationType.AGGREGATION;break;case 64:this.$=u.relationType.EXTENSION;break;case 65:this.$=u.relationType.COMPOSITION;break;case 66:this.$=u.relationType.DEPENDENCY;break;case 67:this.$=u.relationType.LOLLIPOP;break;case 68:this.$=u.lineType.LINE;break;case 69:this.$=u.lineType.DOTTED_LINE;break;case 70:case 76:this.$=t[s-2],u.setClickEvent(t[s-1],t[s]);break;case 71:case 77:this.$=t[s-3],u.setClickEvent(t[s-2],t[s-1]),u.setTooltip(t[s-2],t[s]);break;case 72:this.$=t[s-2],u.setLink(t[s-1],t[s]);break;case 73:this.$=t[s-3],u.setLink(t[s-2],t[s-1],t[s]);break;case 74:this.$=t[s-3],u.setLink(t[s-2],t[s-1]),u.setTooltip(t[s-2],t[s]);break;case 75:this.$=t[s-4],u.setLink(t[s-3],t[s-2],t[s]),u.setTooltip(t[s-3],t[s-1]);break;case 78:this.$=t[s-3],u.setClickEvent(t[s-2],t[s-1],t[s]);break;case 79:this.$=t[s-4],u.setClickEvent(t[s-3],t[s-2],t[s-1]),u.setTooltip(t[s-3],t[s]);break;case 80:this.$=t[s-3],u.setLink(t[s-2],t[s]);break;case 81:this.$=t[s-4],u.setLink(t[s-3],t[s-1],t[s]);break;case 82:this.$=t[s-4],u.setLink(t[s-3],t[s-1]),u.setTooltip(t[s-3],t[s]);break;case 83:this.$=t[s-5],u.setLink(t[s-4],t[s-2],t[s]),u.setTooltip(t[s-4],t[s-1]);break;case 84:this.$=t[s-2],u.setCssStyle(t[s-1],t[s]);break;case 85:u.setCssClass(t[s-1],t[s]);break;case 86:this.$=[t[s]];break;case 87:t[s-2].push(t[s]),this.$=t[s-2];break;case 89:this.$=t[s-1]+t[s];break}},"anonymous"),table:[{3:1,4:2,5:3,6:4,7:[1,6],10:5,16:37,17:20,18:38,20:7,22:8,23:9,24:10,25:11,26:12,27:13,28:14,29:15,30:16,31:i,33:r,35:h,36:21,40:c,41:22,44:f,45:d,47:B,48:S,50:N,52:Ee,53:ge,54:me,55:be,56:ke,66:Te,67:ye,69:Fe,73:De,74:E,76:_e,80:g,95:m,97:b,98:T},{1:[3]},{1:[2,1]},{1:[2,2]},{1:[2,3]},e(Be,[2,5],{8:[1,46]}),{8:[1,47]},e(o,[2,16],{21:[1,48]}),e(o,[2,18]),e(o,[2,19]),e(o,[2,20]),e(o,[2,21]),e(o,[2,22]),e(o,[2,23]),e(o,[2,24]),e(o,[2,25]),e(o,[2,26]),{32:[1,49]},{34:[1,50]},e(o,[2,29]),e(o,[2,45],{49:51,57:54,58:55,13:[1,52],21:[1,53],59:Q,60:X,61:W,62:q,63:H,64:Se,65:ve}),{37:[1,63]},e(J,[2,36],{37:[1,65],42:[1,64]}),e(o,[2,47]),e(o,[2,48]),{16:66,74:E,80:g,95:m,97:b},{16:37,17:67,18:38,74:E,80:g,95:m,97:b,98:T},{16:37,17:68,18:38,74:E,80:g,95:m,97:b,98:T},{16:37,17:69,18:38,74:E,80:g,95:m,97:b,98:T},{74:[1,70]},{13:[1,71]},{16:37,17:72,18:38,74:E,80:g,95:m,97:b,98:T},{13:Ke,51:73},e(o,[2,55]),e(o,[2,56]),e(o,[2,57]),e(o,[2,58]),e(G,[2,11],{16:37,18:38,17:75,19:[1,76],74:E,80:g,95:m,97:b,98:T}),e(G,[2,12],{19:[1,77]}),{15:78,16:79,74:E,80:g,95:m,97:b},{16:37,17:80,18:38,74:E,80:g,95:m,97:b,98:T},e(Z,[2,112]),e(Z,[2,113]),e(Z,[2,114]),e(Z,[2,115]),e([1,8,9,12,13,19,21,37,39,42,59,60,61,62,63,64,65,70,72],[2,116]),e(Be,[2,6],{10:5,20:7,22:8,23:9,24:10,25:11,26:12,27:13,28:14,29:15,30:16,17:20,36:21,41:22,16:37,18:38,5:81,31:i,33:r,35:h,40:c,44:f,45:d,47:B,48:S,50:N,52:Ee,53:ge,54:me,55:be,56:ke,66:Te,67:ye,69:Fe,73:De,74:E,76:_e,80:g,95:m,97:b,98:T}),{5:82,10:5,16:37,17:20,18:38,20:7,22:8,23:9,24:10,25:11,26:12,27:13,28:14,29:15,30:16,31:i,33:r,35:h,36:21,40:c,41:22,44:f,45:d,47:B,48:S,50:N,52:Ee,53:ge,54:me,55:be,56:ke,66:Te,67:ye,69:Fe,73:De,74:E,76:_e,80:g,95:m,97:b,98:T},e(o,[2,17]),e(o,[2,27]),e(o,[2,28]),{13:[1,84],16:37,17:83,18:38,74:E,80:g,95:m,97:b,98:T},{49:85,57:54,58:55,59:Q,60:X,61:W,62:q,63:H,64:Se,65:ve},e(o,[2,46]),{58:86,64:Se,65:ve},e($,[2,62],{57:87,59:Q,60:X,61:W,62:q,63:H}),e(U,[2,63]),e(U,[2,64]),e(U,[2,65]),e(U,[2,66]),e(U,[2,67]),e(Ye,[2,68]),e(Ye,[2,69]),{8:[1,89],23:90,38:88,41:22,44:f},{16:91,74:E,80:g,95:m,97:b},{43:92,47:Ne},{46:[1,94]},{13:[1,95]},{13:[1,96]},{70:[1,97],72:[1,98]},{21:ee,73:te,74:se,75:99,77:100,79:101,80:ie,81:ue,82:ne,83:ae,84:re,85:le},{74:[1,111]},{13:Ke,51:112},e(o,[2,54]),e(o,[2,117]),e(G,[2,13]),e(G,[2,14]),e(G,[2,15]),{37:[2,32]},{15:113,16:79,37:[2,9],74:E,80:g,95:m,97:b},e(Le,[2,40],{11:114,12:[1,115]}),e(Be,[2,7]),{9:[1,116]},e(ce,[2,49]),{16:37,17:117,18:38,74:E,80:g,95:m,97:b,98:T},{13:[1,119],16:37,17:118,18:38,74:E,80:g,95:m,97:b,98:T},e($,[2,61],{57:120,59:Q,60:X,61:W,62:q,63:H}),e($,[2,60]),{39:[1,121]},{23:90,38:122,41:22,44:f},{8:[1,123],39:[2,33]},e(J,[2,37],{37:[1,124]}),{39:[1,125]},{39:[2,43],43:126,47:Ne},{16:37,17:127,18:38,74:E,80:g,95:m,97:b,98:T},e(o,[2,70],{13:[1,128]}),e(o,[2,72],{13:[1,130],68:[1,129]}),e(o,[2,76],{13:[1,131],71:[1,132]}),{13:[1,133]},e(o,[2,84],{78:[1,134]}),e(je,[2,86],{79:135,21:ee,73:te,74:se,80:ie,81:ue,82:ne,83:ae,84:re,85:le}),e(v,[2,88]),e(v,[2,90]),e(v,[2,91]),e(v,[2,92]),e(v,[2,93]),e(v,[2,94]),e(v,[2,95]),e(v,[2,96]),e(v,[2,97]),e(v,[2,98]),e(o,[2,85]),e(o,[2,53]),{37:[2,10]},e(Le,[2,41]),{13:[1,136]},{1:[2,4]},e(ce,[2,51]),e(ce,[2,50]),{16:37,17:137,18:38,74:E,80:g,95:m,97:b,98:T},e($,[2,59]),e(o,[2,30]),{39:[1,138]},{23:90,38:139,39:[2,34],41:22,44:f},{43:140,47:Ne},e(J,[2,38]),{39:[2,44]},e(o,[2,42]),e(o,[2,71]),e(o,[2,73]),e(o,[2,74],{68:[1,141]}),e(o,[2,77]),e(o,[2,78],{13:[1,142]}),e(o,[2,80],{13:[1,144],68:[1,143]}),{21:ee,73:te,74:se,77:145,79:101,80:ie,81:ue,82:ne,83:ae,84:re,85:le},e(v,[2,89]),{14:[1,146]},e(ce,[2,52]),e(o,[2,31]),{39:[2,35]},{39:[1,147]},e(o,[2,75]),e(o,[2,79]),e(o,[2,81]),e(o,[2,82],{68:[1,148]}),e(je,[2,87],{79:135,21:ee,73:te,74:se,80:ie,81:ue,82:ne,83:ae,84:re,85:le}),e(Le,[2,8]),e(J,[2,39]),e(o,[2,83])],defaultActions:{2:[2,1],3:[2,2],4:[2,3],78:[2,32],113:[2,10],116:[2,4],126:[2,44],139:[2,35]},parseError:n(function(a,l){if(l.recoverable)this.trace(a);else{var A=new Error(a);throw A.hash=l,A}},"parseError"),parse:n(function(a){var l=this,A=[0],u=[],p=[null],t=[],z=this.table,s="",he=0,Qe=0,ut=2,Xe=1,nt=t.slice.call(arguments,1),k=Object.create(this.lexer),R={yy:{}};for(var Ie in this.yy)Object.prototype.hasOwnProperty.call(this.yy,Ie)&&(R.yy[Ie]=this.yy[Ie]);k.setInput(a,R.yy),R.yy.lexer=k,R.yy.parser=this,typeof k.yylloc>"u"&&(k.yylloc={});var Oe=k.yylloc;t.push(Oe);var at=k.options&&k.options.ranges;typeof R.yy.parseError=="function"?this.parseError=R.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function rt(F){A.length=A.length-2*F,p.length=p.length-F,t.length=t.length-F}n(rt,"popStack");function We(){var F;return F=u.pop()||k.lex()||Xe,typeof F!="number"&&(F instanceof Array&&(u=F,F=u.pop()),F=l.symbols_[F]||F),F}n(We,"lex");for(var y,w,_,Re,M={},Ae,L,qe,pe;;){if(w=A[A.length-1],this.defaultActions[w]?_=this.defaultActions[w]:((y===null||typeof y>"u")&&(y=We()),_=z[w]&&z[w][y]),typeof _>"u"||!_.length||!_[0]){var we="";pe=[];for(Ae in z[w])this.terminals_[Ae]&&Ae>ut&&pe.push("'"+this.terminals_[Ae]+"'");k.showPosition?we="Parse error on line "+(he+1)+`:
                                      +import{_ as n,i as lt,d as D,a9 as Ve,s as ct,g as ot,b as ht,c as At,q as pt,r as ft,e as x,t as dt,l as Ct,u as $e,j as K}from"./mermaid.core-D8igZDel.js";var Pe=function(){var e=n(function(O,a,l,A){for(l=l||{},A=O.length;A--;l[O[A]]=a);return l},"o"),i=[1,17],r=[1,18],h=[1,19],c=[1,39],f=[1,40],d=[1,25],B=[1,23],S=[1,24],N=[1,31],Ee=[1,32],ge=[1,33],me=[1,34],be=[1,35],ke=[1,36],Te=[1,26],ye=[1,27],Fe=[1,28],De=[1,29],E=[1,43],_e=[1,30],g=[1,42],m=[1,44],b=[1,41],T=[1,45],Be=[1,9],o=[1,8,9],Q=[1,56],X=[1,57],W=[1,58],q=[1,59],H=[1,60],Se=[1,61],ve=[1,62],J=[1,8,9,39],Ke=[1,74],G=[1,8,9,12,13,21,37,39,42,59,60,61,62,63,64,65,70,72],Z=[1,8,9,12,13,19,21,37,39,42,46,59,60,61,62,63,64,65,70,72,74,80,95,97,98],$=[13,74,80,95,97,98],U=[13,64,65,74,80,95,97,98],Ye=[13,59,60,61,62,63,74,80,95,97,98],Ne=[1,93],ee=[1,110],te=[1,108],se=[1,102],ie=[1,103],ue=[1,104],ne=[1,105],ae=[1,106],re=[1,107],le=[1,109],Le=[1,8,9,37,39,42],ce=[1,8,9,21],je=[1,8,9,78],v=[1,8,9,21,73,74,78,80,81,82,83,84,85],xe={trace:n(function(){},"trace"),yy:{},symbols_:{error:2,start:3,mermaidDoc:4,statements:5,graphConfig:6,CLASS_DIAGRAM:7,NEWLINE:8,EOF:9,statement:10,classLabel:11,SQS:12,STR:13,SQE:14,namespaceName:15,alphaNumToken:16,className:17,classLiteralName:18,GENERICTYPE:19,relationStatement:20,LABEL:21,namespaceStatement:22,classStatement:23,memberStatement:24,annotationStatement:25,clickStatement:26,styleStatement:27,cssClassStatement:28,noteStatement:29,direction:30,acc_title:31,acc_title_value:32,acc_descr:33,acc_descr_value:34,acc_descr_multiline_value:35,namespaceIdentifier:36,STRUCT_START:37,classStatements:38,STRUCT_STOP:39,NAMESPACE:40,classIdentifier:41,STYLE_SEPARATOR:42,members:43,CLASS:44,ANNOTATION_START:45,ANNOTATION_END:46,MEMBER:47,SEPARATOR:48,relation:49,NOTE_FOR:50,noteText:51,NOTE:52,direction_tb:53,direction_bt:54,direction_rl:55,direction_lr:56,relationType:57,lineType:58,AGGREGATION:59,EXTENSION:60,COMPOSITION:61,DEPENDENCY:62,LOLLIPOP:63,LINE:64,DOTTED_LINE:65,CALLBACK:66,LINK:67,LINK_TARGET:68,CLICK:69,CALLBACK_NAME:70,CALLBACK_ARGS:71,HREF:72,STYLE:73,ALPHA:74,stylesOpt:75,CSSCLASS:76,style:77,COMMA:78,styleComponent:79,NUM:80,COLON:81,UNIT:82,SPACE:83,BRKT:84,PCT:85,commentToken:86,textToken:87,graphCodeTokens:88,textNoTagsToken:89,TAGSTART:90,TAGEND:91,"==":92,"--":93,DEFAULT:94,MINUS:95,keywords:96,UNICODE_TEXT:97,BQUOTE_STR:98,$accept:0,$end:1},terminals_:{2:"error",7:"CLASS_DIAGRAM",8:"NEWLINE",9:"EOF",12:"SQS",13:"STR",14:"SQE",19:"GENERICTYPE",21:"LABEL",31:"acc_title",32:"acc_title_value",33:"acc_descr",34:"acc_descr_value",35:"acc_descr_multiline_value",37:"STRUCT_START",39:"STRUCT_STOP",40:"NAMESPACE",42:"STYLE_SEPARATOR",44:"CLASS",45:"ANNOTATION_START",46:"ANNOTATION_END",47:"MEMBER",48:"SEPARATOR",50:"NOTE_FOR",52:"NOTE",53:"direction_tb",54:"direction_bt",55:"direction_rl",56:"direction_lr",59:"AGGREGATION",60:"EXTENSION",61:"COMPOSITION",62:"DEPENDENCY",63:"LOLLIPOP",64:"LINE",65:"DOTTED_LINE",66:"CALLBACK",67:"LINK",68:"LINK_TARGET",69:"CLICK",70:"CALLBACK_NAME",71:"CALLBACK_ARGS",72:"HREF",73:"STYLE",74:"ALPHA",76:"CSSCLASS",78:"COMMA",80:"NUM",81:"COLON",82:"UNIT",83:"SPACE",84:"BRKT",85:"PCT",88:"graphCodeTokens",90:"TAGSTART",91:"TAGEND",92:"==",93:"--",94:"DEFAULT",95:"MINUS",96:"keywords",97:"UNICODE_TEXT",98:"BQUOTE_STR"},productions_:[0,[3,1],[3,1],[4,1],[6,4],[5,1],[5,2],[5,3],[11,3],[15,1],[15,2],[17,1],[17,1],[17,2],[17,2],[17,2],[10,1],[10,2],[10,1],[10,1],[10,1],[10,1],[10,1],[10,1],[10,1],[10,1],[10,1],[10,2],[10,2],[10,1],[22,4],[22,5],[36,2],[38,1],[38,2],[38,3],[23,1],[23,3],[23,4],[23,6],[41,2],[41,3],[25,4],[43,1],[43,2],[24,1],[24,2],[24,1],[24,1],[20,3],[20,4],[20,4],[20,5],[29,3],[29,2],[30,1],[30,1],[30,1],[30,1],[49,3],[49,2],[49,2],[49,1],[57,1],[57,1],[57,1],[57,1],[57,1],[58,1],[58,1],[26,3],[26,4],[26,3],[26,4],[26,4],[26,5],[26,3],[26,4],[26,4],[26,5],[26,4],[26,5],[26,5],[26,6],[27,3],[28,3],[75,1],[75,3],[77,1],[77,2],[79,1],[79,1],[79,1],[79,1],[79,1],[79,1],[79,1],[79,1],[79,1],[86,1],[86,1],[87,1],[87,1],[87,1],[87,1],[87,1],[87,1],[87,1],[89,1],[89,1],[89,1],[89,1],[16,1],[16,1],[16,1],[16,1],[18,1],[51,1]],performAction:n(function(a,l,A,u,p,t,z){var s=t.length-1;switch(p){case 8:this.$=t[s-1];break;case 9:case 11:case 12:this.$=t[s];break;case 10:case 13:this.$=t[s-1]+t[s];break;case 14:case 15:this.$=t[s-1]+"~"+t[s]+"~";break;case 16:u.addRelation(t[s]);break;case 17:t[s-1].title=u.cleanupLabel(t[s]),u.addRelation(t[s-1]);break;case 27:this.$=t[s].trim(),u.setAccTitle(this.$);break;case 28:case 29:this.$=t[s].trim(),u.setAccDescription(this.$);break;case 30:u.addClassesToNamespace(t[s-3],t[s-1]);break;case 31:u.addClassesToNamespace(t[s-4],t[s-1]);break;case 32:this.$=t[s],u.addNamespace(t[s]);break;case 33:this.$=[t[s]];break;case 34:this.$=[t[s-1]];break;case 35:t[s].unshift(t[s-2]),this.$=t[s];break;case 37:u.setCssClass(t[s-2],t[s]);break;case 38:u.addMembers(t[s-3],t[s-1]);break;case 39:u.setCssClass(t[s-5],t[s-3]),u.addMembers(t[s-5],t[s-1]);break;case 40:this.$=t[s],u.addClass(t[s]);break;case 41:this.$=t[s-1],u.addClass(t[s-1]),u.setClassLabel(t[s-1],t[s]);break;case 42:u.addAnnotation(t[s],t[s-2]);break;case 43:this.$=[t[s]];break;case 44:t[s].push(t[s-1]),this.$=t[s];break;case 45:break;case 46:u.addMember(t[s-1],u.cleanupLabel(t[s]));break;case 47:break;case 48:break;case 49:this.$={id1:t[s-2],id2:t[s],relation:t[s-1],relationTitle1:"none",relationTitle2:"none"};break;case 50:this.$={id1:t[s-3],id2:t[s],relation:t[s-1],relationTitle1:t[s-2],relationTitle2:"none"};break;case 51:this.$={id1:t[s-3],id2:t[s],relation:t[s-2],relationTitle1:"none",relationTitle2:t[s-1]};break;case 52:this.$={id1:t[s-4],id2:t[s],relation:t[s-2],relationTitle1:t[s-3],relationTitle2:t[s-1]};break;case 53:u.addNote(t[s],t[s-1]);break;case 54:u.addNote(t[s]);break;case 55:u.setDirection("TB");break;case 56:u.setDirection("BT");break;case 57:u.setDirection("RL");break;case 58:u.setDirection("LR");break;case 59:this.$={type1:t[s-2],type2:t[s],lineType:t[s-1]};break;case 60:this.$={type1:"none",type2:t[s],lineType:t[s-1]};break;case 61:this.$={type1:t[s-1],type2:"none",lineType:t[s]};break;case 62:this.$={type1:"none",type2:"none",lineType:t[s]};break;case 63:this.$=u.relationType.AGGREGATION;break;case 64:this.$=u.relationType.EXTENSION;break;case 65:this.$=u.relationType.COMPOSITION;break;case 66:this.$=u.relationType.DEPENDENCY;break;case 67:this.$=u.relationType.LOLLIPOP;break;case 68:this.$=u.lineType.LINE;break;case 69:this.$=u.lineType.DOTTED_LINE;break;case 70:case 76:this.$=t[s-2],u.setClickEvent(t[s-1],t[s]);break;case 71:case 77:this.$=t[s-3],u.setClickEvent(t[s-2],t[s-1]),u.setTooltip(t[s-2],t[s]);break;case 72:this.$=t[s-2],u.setLink(t[s-1],t[s]);break;case 73:this.$=t[s-3],u.setLink(t[s-2],t[s-1],t[s]);break;case 74:this.$=t[s-3],u.setLink(t[s-2],t[s-1]),u.setTooltip(t[s-2],t[s]);break;case 75:this.$=t[s-4],u.setLink(t[s-3],t[s-2],t[s]),u.setTooltip(t[s-3],t[s-1]);break;case 78:this.$=t[s-3],u.setClickEvent(t[s-2],t[s-1],t[s]);break;case 79:this.$=t[s-4],u.setClickEvent(t[s-3],t[s-2],t[s-1]),u.setTooltip(t[s-3],t[s]);break;case 80:this.$=t[s-3],u.setLink(t[s-2],t[s]);break;case 81:this.$=t[s-4],u.setLink(t[s-3],t[s-1],t[s]);break;case 82:this.$=t[s-4],u.setLink(t[s-3],t[s-1]),u.setTooltip(t[s-3],t[s]);break;case 83:this.$=t[s-5],u.setLink(t[s-4],t[s-2],t[s]),u.setTooltip(t[s-4],t[s-1]);break;case 84:this.$=t[s-2],u.setCssStyle(t[s-1],t[s]);break;case 85:u.setCssClass(t[s-1],t[s]);break;case 86:this.$=[t[s]];break;case 87:t[s-2].push(t[s]),this.$=t[s-2];break;case 89:this.$=t[s-1]+t[s];break}},"anonymous"),table:[{3:1,4:2,5:3,6:4,7:[1,6],10:5,16:37,17:20,18:38,20:7,22:8,23:9,24:10,25:11,26:12,27:13,28:14,29:15,30:16,31:i,33:r,35:h,36:21,40:c,41:22,44:f,45:d,47:B,48:S,50:N,52:Ee,53:ge,54:me,55:be,56:ke,66:Te,67:ye,69:Fe,73:De,74:E,76:_e,80:g,95:m,97:b,98:T},{1:[3]},{1:[2,1]},{1:[2,2]},{1:[2,3]},e(Be,[2,5],{8:[1,46]}),{8:[1,47]},e(o,[2,16],{21:[1,48]}),e(o,[2,18]),e(o,[2,19]),e(o,[2,20]),e(o,[2,21]),e(o,[2,22]),e(o,[2,23]),e(o,[2,24]),e(o,[2,25]),e(o,[2,26]),{32:[1,49]},{34:[1,50]},e(o,[2,29]),e(o,[2,45],{49:51,57:54,58:55,13:[1,52],21:[1,53],59:Q,60:X,61:W,62:q,63:H,64:Se,65:ve}),{37:[1,63]},e(J,[2,36],{37:[1,65],42:[1,64]}),e(o,[2,47]),e(o,[2,48]),{16:66,74:E,80:g,95:m,97:b},{16:37,17:67,18:38,74:E,80:g,95:m,97:b,98:T},{16:37,17:68,18:38,74:E,80:g,95:m,97:b,98:T},{16:37,17:69,18:38,74:E,80:g,95:m,97:b,98:T},{74:[1,70]},{13:[1,71]},{16:37,17:72,18:38,74:E,80:g,95:m,97:b,98:T},{13:Ke,51:73},e(o,[2,55]),e(o,[2,56]),e(o,[2,57]),e(o,[2,58]),e(G,[2,11],{16:37,18:38,17:75,19:[1,76],74:E,80:g,95:m,97:b,98:T}),e(G,[2,12],{19:[1,77]}),{15:78,16:79,74:E,80:g,95:m,97:b},{16:37,17:80,18:38,74:E,80:g,95:m,97:b,98:T},e(Z,[2,112]),e(Z,[2,113]),e(Z,[2,114]),e(Z,[2,115]),e([1,8,9,12,13,19,21,37,39,42,59,60,61,62,63,64,65,70,72],[2,116]),e(Be,[2,6],{10:5,20:7,22:8,23:9,24:10,25:11,26:12,27:13,28:14,29:15,30:16,17:20,36:21,41:22,16:37,18:38,5:81,31:i,33:r,35:h,40:c,44:f,45:d,47:B,48:S,50:N,52:Ee,53:ge,54:me,55:be,56:ke,66:Te,67:ye,69:Fe,73:De,74:E,76:_e,80:g,95:m,97:b,98:T}),{5:82,10:5,16:37,17:20,18:38,20:7,22:8,23:9,24:10,25:11,26:12,27:13,28:14,29:15,30:16,31:i,33:r,35:h,36:21,40:c,41:22,44:f,45:d,47:B,48:S,50:N,52:Ee,53:ge,54:me,55:be,56:ke,66:Te,67:ye,69:Fe,73:De,74:E,76:_e,80:g,95:m,97:b,98:T},e(o,[2,17]),e(o,[2,27]),e(o,[2,28]),{13:[1,84],16:37,17:83,18:38,74:E,80:g,95:m,97:b,98:T},{49:85,57:54,58:55,59:Q,60:X,61:W,62:q,63:H,64:Se,65:ve},e(o,[2,46]),{58:86,64:Se,65:ve},e($,[2,62],{57:87,59:Q,60:X,61:W,62:q,63:H}),e(U,[2,63]),e(U,[2,64]),e(U,[2,65]),e(U,[2,66]),e(U,[2,67]),e(Ye,[2,68]),e(Ye,[2,69]),{8:[1,89],23:90,38:88,41:22,44:f},{16:91,74:E,80:g,95:m,97:b},{43:92,47:Ne},{46:[1,94]},{13:[1,95]},{13:[1,96]},{70:[1,97],72:[1,98]},{21:ee,73:te,74:se,75:99,77:100,79:101,80:ie,81:ue,82:ne,83:ae,84:re,85:le},{74:[1,111]},{13:Ke,51:112},e(o,[2,54]),e(o,[2,117]),e(G,[2,13]),e(G,[2,14]),e(G,[2,15]),{37:[2,32]},{15:113,16:79,37:[2,9],74:E,80:g,95:m,97:b},e(Le,[2,40],{11:114,12:[1,115]}),e(Be,[2,7]),{9:[1,116]},e(ce,[2,49]),{16:37,17:117,18:38,74:E,80:g,95:m,97:b,98:T},{13:[1,119],16:37,17:118,18:38,74:E,80:g,95:m,97:b,98:T},e($,[2,61],{57:120,59:Q,60:X,61:W,62:q,63:H}),e($,[2,60]),{39:[1,121]},{23:90,38:122,41:22,44:f},{8:[1,123],39:[2,33]},e(J,[2,37],{37:[1,124]}),{39:[1,125]},{39:[2,43],43:126,47:Ne},{16:37,17:127,18:38,74:E,80:g,95:m,97:b,98:T},e(o,[2,70],{13:[1,128]}),e(o,[2,72],{13:[1,130],68:[1,129]}),e(o,[2,76],{13:[1,131],71:[1,132]}),{13:[1,133]},e(o,[2,84],{78:[1,134]}),e(je,[2,86],{79:135,21:ee,73:te,74:se,80:ie,81:ue,82:ne,83:ae,84:re,85:le}),e(v,[2,88]),e(v,[2,90]),e(v,[2,91]),e(v,[2,92]),e(v,[2,93]),e(v,[2,94]),e(v,[2,95]),e(v,[2,96]),e(v,[2,97]),e(v,[2,98]),e(o,[2,85]),e(o,[2,53]),{37:[2,10]},e(Le,[2,41]),{13:[1,136]},{1:[2,4]},e(ce,[2,51]),e(ce,[2,50]),{16:37,17:137,18:38,74:E,80:g,95:m,97:b,98:T},e($,[2,59]),e(o,[2,30]),{39:[1,138]},{23:90,38:139,39:[2,34],41:22,44:f},{43:140,47:Ne},e(J,[2,38]),{39:[2,44]},e(o,[2,42]),e(o,[2,71]),e(o,[2,73]),e(o,[2,74],{68:[1,141]}),e(o,[2,77]),e(o,[2,78],{13:[1,142]}),e(o,[2,80],{13:[1,144],68:[1,143]}),{21:ee,73:te,74:se,77:145,79:101,80:ie,81:ue,82:ne,83:ae,84:re,85:le},e(v,[2,89]),{14:[1,146]},e(ce,[2,52]),e(o,[2,31]),{39:[2,35]},{39:[1,147]},e(o,[2,75]),e(o,[2,79]),e(o,[2,81]),e(o,[2,82],{68:[1,148]}),e(je,[2,87],{79:135,21:ee,73:te,74:se,80:ie,81:ue,82:ne,83:ae,84:re,85:le}),e(Le,[2,8]),e(J,[2,39]),e(o,[2,83])],defaultActions:{2:[2,1],3:[2,2],4:[2,3],78:[2,32],113:[2,10],116:[2,4],126:[2,44],139:[2,35]},parseError:n(function(a,l){if(l.recoverable)this.trace(a);else{var A=new Error(a);throw A.hash=l,A}},"parseError"),parse:n(function(a){var l=this,A=[0],u=[],p=[null],t=[],z=this.table,s="",he=0,Qe=0,ut=2,Xe=1,nt=t.slice.call(arguments,1),k=Object.create(this.lexer),R={yy:{}};for(var Ie in this.yy)Object.prototype.hasOwnProperty.call(this.yy,Ie)&&(R.yy[Ie]=this.yy[Ie]);k.setInput(a,R.yy),R.yy.lexer=k,R.yy.parser=this,typeof k.yylloc>"u"&&(k.yylloc={});var Oe=k.yylloc;t.push(Oe);var at=k.options&&k.options.ranges;typeof R.yy.parseError=="function"?this.parseError=R.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function rt(F){A.length=A.length-2*F,p.length=p.length-F,t.length=t.length-F}n(rt,"popStack");function We(){var F;return F=u.pop()||k.lex()||Xe,typeof F!="number"&&(F instanceof Array&&(u=F,F=u.pop()),F=l.symbols_[F]||F),F}n(We,"lex");for(var y,w,_,Re,M={},Ae,L,qe,pe;;){if(w=A[A.length-1],this.defaultActions[w]?_=this.defaultActions[w]:((y===null||typeof y>"u")&&(y=We()),_=z[w]&&z[w][y]),typeof _>"u"||!_.length||!_[0]){var we="";pe=[];for(Ae in z[w])this.terminals_[Ae]&&Ae>ut&&pe.push("'"+this.terminals_[Ae]+"'");k.showPosition?we="Parse error on line "+(he+1)+`:
                                       `+k.showPosition()+`
                                       Expecting `+pe.join(", ")+", got '"+(this.terminals_[y]||y)+"'":we="Parse error on line "+(he+1)+": Unexpected "+(y==Xe?"end of input":"'"+(this.terminals_[y]||y)+"'"),this.parseError(we,{text:k.match,token:this.terminals_[y]||y,line:k.yylineno,loc:Oe,expected:pe})}if(_[0]instanceof Array&&_.length>1)throw new Error("Parse Error: multiple actions possible at state: "+w+", token: "+y);switch(_[0]){case 1:A.push(y),p.push(k.yytext),t.push(k.yylloc),A.push(_[1]),y=null,Qe=k.yyleng,s=k.yytext,he=k.yylineno,Oe=k.yylloc;break;case 2:if(L=this.productions_[_[1]][1],M.$=p[p.length-L],M._$={first_line:t[t.length-(L||1)].first_line,last_line:t[t.length-1].last_line,first_column:t[t.length-(L||1)].first_column,last_column:t[t.length-1].last_column},at&&(M._$.range=[t[t.length-(L||1)].range[0],t[t.length-1].range[1]]),Re=this.performAction.apply(M,[s,Qe,he,R.yy,_[1],p,t].concat(nt)),typeof Re<"u")return Re;L&&(A=A.slice(0,-1*L*2),p=p.slice(0,-1*L),t=t.slice(0,-1*L)),A.push(this.productions_[_[1]][0]),p.push(M.$),t.push(M._$),qe=z[A[A.length-2]][A[A.length-1]],A.push(qe);break;case 3:return!0}}return!0},"parse")},it=function(){var O={EOF:1,parseError:n(function(l,A){if(this.yy.parser)this.yy.parser.parseError(l,A);else throw new Error(l)},"parseError"),setInput:n(function(a,l){return this.yy=l||this.yy||{},this._input=a,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},"setInput"),input:n(function(){var a=this._input[0];this.yytext+=a,this.yyleng++,this.offset++,this.match+=a,this.matched+=a;var l=a.match(/(?:\r\n?|\n).*/g);return l?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),a},"input"),unput:n(function(a){var l=a.length,A=a.split(/(?:\r\n?|\n)/g);this._input=a+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-l),this.offset-=l;var u=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),A.length-1&&(this.yylineno-=A.length-1);var p=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:A?(A.length===u.length?this.yylloc.first_column:0)+u[u.length-A.length].length-A[0].length:this.yylloc.first_column-l},this.options.ranges&&(this.yylloc.range=[p[0],p[0]+this.yyleng-l]),this.yyleng=this.yytext.length,this},"unput"),more:n(function(){return this._more=!0,this},"more"),reject:n(function(){if(this.options.backtrack_lexer)this._backtrack=!0;else return this.parseError("Lexical error on line "+(this.yylineno+1)+`. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).
                                       `+this.showPosition(),{text:"",token:null,line:this.yylineno});return this},"reject"),less:n(function(a){this.unput(this.match.slice(a))},"less"),pastInput:n(function(){var a=this.matched.substr(0,this.matched.length-this.match.length);return(a.length>20?"...":"")+a.substr(-20).replace(/\n/g,"")},"pastInput"),upcomingInput:n(function(){var a=this.match;return a.length<20&&(a+=this._input.substr(0,20-a.length)),(a.substr(0,20)+(a.length>20?"...":"")).replace(/\n/g,"")},"upcomingInput"),showPosition:n(function(){var a=this.pastInput(),l=new Array(a.length+1).join("-");return a+this.upcomingInput()+`
                                      diff --git a/assets/chunk-JJENOPKO-CSqkWYi8.js b/assets/chunk-JJENOPKO-7opA8rsx.js
                                      similarity index 78%
                                      rename from assets/chunk-JJENOPKO-CSqkWYi8.js
                                      rename to assets/chunk-JJENOPKO-7opA8rsx.js
                                      index 574647e59b..9e578dfd6f 100644
                                      --- a/assets/chunk-JJENOPKO-CSqkWYi8.js
                                      +++ b/assets/chunk-JJENOPKO-7opA8rsx.js
                                      @@ -1 +1 @@
                                      -import{_ as l}from"./mermaid.core-DapiNGBY.js";function m(e,c){var i,t,o;e.accDescr&&((i=c.setAccDescription)==null||i.call(c,e.accDescr)),e.accTitle&&((t=c.setAccTitle)==null||t.call(c,e.accTitle)),e.title&&((o=c.setDiagramTitle)==null||o.call(c,e.title))}l(m,"populateCommonDb");export{m as p};
                                      +import{_ as l}from"./mermaid.core-D8igZDel.js";function m(e,c){var i,t,o;e.accDescr&&((i=c.setAccDescription)==null||i.call(c,e.accDescr)),e.accTitle&&((t=c.setAccTitle)==null||t.call(c,e.accTitle)),e.title&&((o=c.setDiagramTitle)==null||o.call(c,e.title))}l(m,"populateCommonDb");export{m as p};
                                      diff --git a/assets/chunk-PDCO53Z4-RQMWNvLJ.js b/assets/chunk-PDCO53Z4-BcfC0Pnz.js
                                      similarity index 98%
                                      rename from assets/chunk-PDCO53Z4-RQMWNvLJ.js
                                      rename to assets/chunk-PDCO53Z4-BcfC0Pnz.js
                                      index c261c1019e..41f7cabe4d 100644
                                      --- a/assets/chunk-PDCO53Z4-RQMWNvLJ.js
                                      +++ b/assets/chunk-PDCO53Z4-BcfC0Pnz.js
                                      @@ -1,4 +1,4 @@
                                      -import{a as y}from"./chunk-Z2VRG6XP-DsASRjJ5.js";import{_ as f,d as g,A as W,D as C,j as H,l as m,ae as R,u as w,af as X,a2 as Y,a8 as U}from"./mermaid.core-DapiNGBY.js";var O=f((r,t,a,h)=>{t.forEach(o=>{J[o](r,a,h)})},"insertMarkers"),Z=f((r,t,a)=>{m.trace("Making markers for ",a),r.append("defs").append("marker").attr("id",a+"_"+t+"-extensionStart").attr("class","marker extension "+t).attr("refX",18).attr("refY",7).attr("markerWidth",190).attr("markerHeight",240).attr("orient","auto").append("path").attr("d","M 1,7 L18,13 V 1 Z"),r.append("defs").append("marker").attr("id",a+"_"+t+"-extensionEnd").attr("class","marker extension "+t).attr("refX",1).attr("refY",7).attr("markerWidth",20).attr("markerHeight",28).attr("orient","auto").append("path").attr("d","M 1,1 V 13 L18,7 Z")},"extension"),A=f((r,t,a)=>{r.append("defs").append("marker").attr("id",a+"_"+t+"-compositionStart").attr("class","marker composition "+t).attr("refX",18).attr("refY",7).attr("markerWidth",190).attr("markerHeight",240).attr("orient","auto").append("path").attr("d","M 18,7 L9,13 L1,7 L9,1 Z"),r.append("defs").append("marker").attr("id",a+"_"+t+"-compositionEnd").attr("class","marker composition "+t).attr("refX",1).attr("refY",7).attr("markerWidth",20).attr("markerHeight",28).attr("orient","auto").append("path").attr("d","M 18,7 L9,13 L1,7 L9,1 Z")},"composition"),I=f((r,t,a)=>{r.append("defs").append("marker").attr("id",a+"_"+t+"-aggregationStart").attr("class","marker aggregation "+t).attr("refX",18).attr("refY",7).attr("markerWidth",190).attr("markerHeight",240).attr("orient","auto").append("path").attr("d","M 18,7 L9,13 L1,7 L9,1 Z"),r.append("defs").append("marker").attr("id",a+"_"+t+"-aggregationEnd").attr("class","marker aggregation "+t).attr("refX",1).attr("refY",7).attr("markerWidth",20).attr("markerHeight",28).attr("orient","auto").append("path").attr("d","M 18,7 L9,13 L1,7 L9,1 Z")},"aggregation"),N=f((r,t,a)=>{r.append("defs").append("marker").attr("id",a+"_"+t+"-dependencyStart").attr("class","marker dependency "+t).attr("refX",6).attr("refY",7).attr("markerWidth",190).attr("markerHeight",240).attr("orient","auto").append("path").attr("d","M 5,7 L9,13 L1,7 L9,1 Z"),r.append("defs").append("marker").attr("id",a+"_"+t+"-dependencyEnd").attr("class","marker dependency "+t).attr("refX",13).attr("refY",7).attr("markerWidth",20).attr("markerHeight",28).attr("orient","auto").append("path").attr("d","M 18,7 L9,13 L14,7 L9,1 Z")},"dependency"),q=f((r,t,a)=>{r.append("defs").append("marker").attr("id",a+"_"+t+"-lollipopStart").attr("class","marker lollipop "+t).attr("refX",13).attr("refY",7).attr("markerWidth",190).attr("markerHeight",240).attr("orient","auto").append("circle").attr("stroke","black").attr("fill","transparent").attr("cx",7).attr("cy",7).attr("r",6),r.append("defs").append("marker").attr("id",a+"_"+t+"-lollipopEnd").attr("class","marker lollipop "+t).attr("refX",1).attr("refY",7).attr("markerWidth",190).attr("markerHeight",240).attr("orient","auto").append("circle").attr("stroke","black").attr("fill","transparent").attr("cx",7).attr("cy",7).attr("r",6)},"lollipop"),Q=f((r,t,a)=>{r.append("marker").attr("id",a+"_"+t+"-pointEnd").attr("class","marker "+t).attr("viewBox","0 0 10 10").attr("refX",6).attr("refY",5).attr("markerUnits","userSpaceOnUse").attr("markerWidth",12).attr("markerHeight",12).attr("orient","auto").append("path").attr("d","M 0 0 L 10 5 L 0 10 z").attr("class","arrowMarkerPath").style("stroke-width",1).style("stroke-dasharray","1,0"),r.append("marker").attr("id",a+"_"+t+"-pointStart").attr("class","marker "+t).attr("viewBox","0 0 10 10").attr("refX",4.5).attr("refY",5).attr("markerUnits","userSpaceOnUse").attr("markerWidth",12).attr("markerHeight",12).attr("orient","auto").append("path").attr("d","M 0 5 L 10 10 L 10 0 z").attr("class","arrowMarkerPath").style("stroke-width",1).style("stroke-dasharray","1,0")},"point"),z=f((r,t,a)=>{r.append("marker").attr("id",a+"_"+t+"-circleEnd").attr("class","marker "+t).attr("viewBox","0 0 10 10").attr("refX",11).attr("refY",5).attr("markerUnits","userSpaceOnUse").attr("markerWidth",11).attr("markerHeight",11).attr("orient","auto").append("circle").attr("cx","5").attr("cy","5").attr("r","5").attr("class","arrowMarkerPath").style("stroke-width",1).style("stroke-dasharray","1,0"),r.append("marker").attr("id",a+"_"+t+"-circleStart").attr("class","marker "+t).attr("viewBox","0 0 10 10").attr("refX",-1).attr("refY",5).attr("markerUnits","userSpaceOnUse").attr("markerWidth",11).attr("markerHeight",11).attr("orient","auto").append("circle").attr("cx","5").attr("cy","5").attr("r","5").attr("class","arrowMarkerPath").style("stroke-width",1).style("stroke-dasharray","1,0")},"circle"),F=f((r,t,a)=>{r.append("marker").attr("id",a+"_"+t+"-crossEnd").attr("class","marker cross "+t).attr("viewBox","0 0 11 11").attr("refX",12).attr("refY",5.2).attr("markerUnits","userSpaceOnUse").attr("markerWidth",11).attr("markerHeight",11).attr("orient","auto").append("path").attr("d","M 1,1 l 9,9 M 10,1 l -9,9").attr("class","arrowMarkerPath").style("stroke-width",2).style("stroke-dasharray","1,0"),r.append("marker").attr("id",a+"_"+t+"-crossStart").attr("class","marker cross "+t).attr("viewBox","0 0 11 11").attr("refX",-1).attr("refY",5.2).attr("markerUnits","userSpaceOnUse").attr("markerWidth",11).attr("markerHeight",11).attr("orient","auto").append("path").attr("d","M 1,1 l 9,9 M 10,1 l -9,9").attr("class","arrowMarkerPath").style("stroke-width",2).style("stroke-dasharray","1,0")},"cross"),G=f((r,t,a)=>{r.append("defs").append("marker").attr("id",a+"_"+t+"-barbEnd").attr("refX",19).attr("refY",7).attr("markerWidth",20).attr("markerHeight",14).attr("markerUnits","strokeWidth").attr("orient","auto").append("path").attr("d","M 19,7 L9,13 L14,7 L9,1 Z")},"barb"),J={extension:Z,composition:A,aggregation:I,dependency:N,lollipop:q,point:Q,circle:z,cross:F,barb:G},at=O,V=f((r,t,a,h,o)=>{t.arrowTypeStart&&E(r,"start",t.arrowTypeStart,a,h,o),t.arrowTypeEnd&&E(r,"end",t.arrowTypeEnd,a,h,o)},"addEdgeMarkers"),j={arrow_cross:"cross",arrow_point:"point",arrow_barb:"barb",arrow_circle:"circle",aggregation:"aggregation",extension:"extension",composition:"composition",dependency:"dependency",lollipop:"lollipop"},E=f((r,t,a,h,o,c)=>{const n=j[a];if(!n){m.warn(`Unknown arrow type: ${a}`);return}const e=t==="start"?"Start":"End";r.attr(`marker-${t}`,`url(${h}#${o}_${c}-${n}${e})`)},"addEdgeMarker"),v={},k={},rt=f(()=>{v={},k={}},"clear"),et=f((r,t)=>{const a=g(),h=W(a.flowchart.htmlLabels),o=t.labelType==="markdown"?C(r,t.label,{style:t.labelStyle,useHtmlLabels:h,addSvgBackground:!0},a):y(t.label,t.labelStyle),c=r.insert("g").attr("class","edgeLabel"),n=c.insert("g").attr("class","label");n.node().appendChild(o);let e=o.getBBox();if(h){const i=o.children[0],l=H(o);e=i.getBoundingClientRect(),l.attr("width",e.width),l.attr("height",e.height)}n.attr("transform","translate("+-e.width/2+", "+-e.height/2+")"),v[t.id]=c,t.width=e.width,t.height=e.height;let s;if(t.startLabelLeft){const i=y(t.startLabelLeft,t.labelStyle),l=r.insert("g").attr("class","edgeTerminals"),d=l.insert("g").attr("class","inner");s=d.node().appendChild(i);const p=i.getBBox();d.attr("transform","translate("+-p.width/2+", "+-p.height/2+")"),k[t.id]||(k[t.id]={}),k[t.id].startLeft=l,u(s,t.startLabelLeft)}if(t.startLabelRight){const i=y(t.startLabelRight,t.labelStyle),l=r.insert("g").attr("class","edgeTerminals"),d=l.insert("g").attr("class","inner");s=l.node().appendChild(i),d.node().appendChild(i);const p=i.getBBox();d.attr("transform","translate("+-p.width/2+", "+-p.height/2+")"),k[t.id]||(k[t.id]={}),k[t.id].startRight=l,u(s,t.startLabelRight)}if(t.endLabelLeft){const i=y(t.endLabelLeft,t.labelStyle),l=r.insert("g").attr("class","edgeTerminals"),d=l.insert("g").attr("class","inner");s=d.node().appendChild(i);const p=i.getBBox();d.attr("transform","translate("+-p.width/2+", "+-p.height/2+")"),l.node().appendChild(i),k[t.id]||(k[t.id]={}),k[t.id].endLeft=l,u(s,t.endLabelLeft)}if(t.endLabelRight){const i=y(t.endLabelRight,t.labelStyle),l=r.insert("g").attr("class","edgeTerminals"),d=l.insert("g").attr("class","inner");s=d.node().appendChild(i);const p=i.getBBox();d.attr("transform","translate("+-p.width/2+", "+-p.height/2+")"),l.node().appendChild(i),k[t.id]||(k[t.id]={}),k[t.id].endRight=l,u(s,t.endLabelRight)}return o},"insertEdgeLabel");function u(r,t){g().flowchart.htmlLabels&&r&&(r.style.width=t.length*9+"px",r.style.height="12px")}f(u,"setTerminalWidth");var st=f((r,t)=>{m.debug("Moving label abc88 ",r.id,r.label,v[r.id],t);let a=t.updatedPath?t.updatedPath:t.originalPath;const h=g(),{subGraphTitleTotalMargin:o}=R(h);if(r.label){const c=v[r.id];let n=r.x,e=r.y;if(a){const s=w.calcLabelPosition(a);m.debug("Moving label "+r.label+" from (",n,",",e,") to (",s.x,",",s.y,") abc88"),t.updatedPath&&(n=s.x,e=s.y)}c.attr("transform",`translate(${n}, ${e+o/2})`)}if(r.startLabelLeft){const c=k[r.id].startLeft;let n=r.x,e=r.y;if(a){const s=w.calcTerminalLabelPosition(r.arrowTypeStart?10:0,"start_left",a);n=s.x,e=s.y}c.attr("transform",`translate(${n}, ${e})`)}if(r.startLabelRight){const c=k[r.id].startRight;let n=r.x,e=r.y;if(a){const s=w.calcTerminalLabelPosition(r.arrowTypeStart?10:0,"start_right",a);n=s.x,e=s.y}c.attr("transform",`translate(${n}, ${e})`)}if(r.endLabelLeft){const c=k[r.id].endLeft;let n=r.x,e=r.y;if(a){const s=w.calcTerminalLabelPosition(r.arrowTypeEnd?10:0,"end_left",a);n=s.x,e=s.y}c.attr("transform",`translate(${n}, ${e})`)}if(r.endLabelRight){const c=k[r.id].endRight;let n=r.x,e=r.y;if(a){const s=w.calcTerminalLabelPosition(r.arrowTypeEnd?10:0,"end_right",a);n=s.x,e=s.y}c.attr("transform",`translate(${n}, ${e})`)}},"positionEdgeLabel"),K=f((r,t)=>{const a=r.x,h=r.y,o=Math.abs(t.x-a),c=Math.abs(t.y-h),n=r.width/2,e=r.height/2;return o>=n||c>=e},"outsideNode"),D=f((r,t,a)=>{m.debug(`intersection calc abc89:
                                      +import{a as y}from"./chunk-Z2VRG6XP-CV0pyCU1.js";import{_ as f,d as g,A as W,D as C,j as H,l as m,ae as R,u as w,af as X,a2 as Y,a8 as U}from"./mermaid.core-D8igZDel.js";var O=f((r,t,a,h)=>{t.forEach(o=>{J[o](r,a,h)})},"insertMarkers"),Z=f((r,t,a)=>{m.trace("Making markers for ",a),r.append("defs").append("marker").attr("id",a+"_"+t+"-extensionStart").attr("class","marker extension "+t).attr("refX",18).attr("refY",7).attr("markerWidth",190).attr("markerHeight",240).attr("orient","auto").append("path").attr("d","M 1,7 L18,13 V 1 Z"),r.append("defs").append("marker").attr("id",a+"_"+t+"-extensionEnd").attr("class","marker extension "+t).attr("refX",1).attr("refY",7).attr("markerWidth",20).attr("markerHeight",28).attr("orient","auto").append("path").attr("d","M 1,1 V 13 L18,7 Z")},"extension"),A=f((r,t,a)=>{r.append("defs").append("marker").attr("id",a+"_"+t+"-compositionStart").attr("class","marker composition "+t).attr("refX",18).attr("refY",7).attr("markerWidth",190).attr("markerHeight",240).attr("orient","auto").append("path").attr("d","M 18,7 L9,13 L1,7 L9,1 Z"),r.append("defs").append("marker").attr("id",a+"_"+t+"-compositionEnd").attr("class","marker composition "+t).attr("refX",1).attr("refY",7).attr("markerWidth",20).attr("markerHeight",28).attr("orient","auto").append("path").attr("d","M 18,7 L9,13 L1,7 L9,1 Z")},"composition"),I=f((r,t,a)=>{r.append("defs").append("marker").attr("id",a+"_"+t+"-aggregationStart").attr("class","marker aggregation "+t).attr("refX",18).attr("refY",7).attr("markerWidth",190).attr("markerHeight",240).attr("orient","auto").append("path").attr("d","M 18,7 L9,13 L1,7 L9,1 Z"),r.append("defs").append("marker").attr("id",a+"_"+t+"-aggregationEnd").attr("class","marker aggregation "+t).attr("refX",1).attr("refY",7).attr("markerWidth",20).attr("markerHeight",28).attr("orient","auto").append("path").attr("d","M 18,7 L9,13 L1,7 L9,1 Z")},"aggregation"),N=f((r,t,a)=>{r.append("defs").append("marker").attr("id",a+"_"+t+"-dependencyStart").attr("class","marker dependency "+t).attr("refX",6).attr("refY",7).attr("markerWidth",190).attr("markerHeight",240).attr("orient","auto").append("path").attr("d","M 5,7 L9,13 L1,7 L9,1 Z"),r.append("defs").append("marker").attr("id",a+"_"+t+"-dependencyEnd").attr("class","marker dependency "+t).attr("refX",13).attr("refY",7).attr("markerWidth",20).attr("markerHeight",28).attr("orient","auto").append("path").attr("d","M 18,7 L9,13 L14,7 L9,1 Z")},"dependency"),q=f((r,t,a)=>{r.append("defs").append("marker").attr("id",a+"_"+t+"-lollipopStart").attr("class","marker lollipop "+t).attr("refX",13).attr("refY",7).attr("markerWidth",190).attr("markerHeight",240).attr("orient","auto").append("circle").attr("stroke","black").attr("fill","transparent").attr("cx",7).attr("cy",7).attr("r",6),r.append("defs").append("marker").attr("id",a+"_"+t+"-lollipopEnd").attr("class","marker lollipop "+t).attr("refX",1).attr("refY",7).attr("markerWidth",190).attr("markerHeight",240).attr("orient","auto").append("circle").attr("stroke","black").attr("fill","transparent").attr("cx",7).attr("cy",7).attr("r",6)},"lollipop"),Q=f((r,t,a)=>{r.append("marker").attr("id",a+"_"+t+"-pointEnd").attr("class","marker "+t).attr("viewBox","0 0 10 10").attr("refX",6).attr("refY",5).attr("markerUnits","userSpaceOnUse").attr("markerWidth",12).attr("markerHeight",12).attr("orient","auto").append("path").attr("d","M 0 0 L 10 5 L 0 10 z").attr("class","arrowMarkerPath").style("stroke-width",1).style("stroke-dasharray","1,0"),r.append("marker").attr("id",a+"_"+t+"-pointStart").attr("class","marker "+t).attr("viewBox","0 0 10 10").attr("refX",4.5).attr("refY",5).attr("markerUnits","userSpaceOnUse").attr("markerWidth",12).attr("markerHeight",12).attr("orient","auto").append("path").attr("d","M 0 5 L 10 10 L 10 0 z").attr("class","arrowMarkerPath").style("stroke-width",1).style("stroke-dasharray","1,0")},"point"),z=f((r,t,a)=>{r.append("marker").attr("id",a+"_"+t+"-circleEnd").attr("class","marker "+t).attr("viewBox","0 0 10 10").attr("refX",11).attr("refY",5).attr("markerUnits","userSpaceOnUse").attr("markerWidth",11).attr("markerHeight",11).attr("orient","auto").append("circle").attr("cx","5").attr("cy","5").attr("r","5").attr("class","arrowMarkerPath").style("stroke-width",1).style("stroke-dasharray","1,0"),r.append("marker").attr("id",a+"_"+t+"-circleStart").attr("class","marker "+t).attr("viewBox","0 0 10 10").attr("refX",-1).attr("refY",5).attr("markerUnits","userSpaceOnUse").attr("markerWidth",11).attr("markerHeight",11).attr("orient","auto").append("circle").attr("cx","5").attr("cy","5").attr("r","5").attr("class","arrowMarkerPath").style("stroke-width",1).style("stroke-dasharray","1,0")},"circle"),F=f((r,t,a)=>{r.append("marker").attr("id",a+"_"+t+"-crossEnd").attr("class","marker cross "+t).attr("viewBox","0 0 11 11").attr("refX",12).attr("refY",5.2).attr("markerUnits","userSpaceOnUse").attr("markerWidth",11).attr("markerHeight",11).attr("orient","auto").append("path").attr("d","M 1,1 l 9,9 M 10,1 l -9,9").attr("class","arrowMarkerPath").style("stroke-width",2).style("stroke-dasharray","1,0"),r.append("marker").attr("id",a+"_"+t+"-crossStart").attr("class","marker cross "+t).attr("viewBox","0 0 11 11").attr("refX",-1).attr("refY",5.2).attr("markerUnits","userSpaceOnUse").attr("markerWidth",11).attr("markerHeight",11).attr("orient","auto").append("path").attr("d","M 1,1 l 9,9 M 10,1 l -9,9").attr("class","arrowMarkerPath").style("stroke-width",2).style("stroke-dasharray","1,0")},"cross"),G=f((r,t,a)=>{r.append("defs").append("marker").attr("id",a+"_"+t+"-barbEnd").attr("refX",19).attr("refY",7).attr("markerWidth",20).attr("markerHeight",14).attr("markerUnits","strokeWidth").attr("orient","auto").append("path").attr("d","M 19,7 L9,13 L14,7 L9,1 Z")},"barb"),J={extension:Z,composition:A,aggregation:I,dependency:N,lollipop:q,point:Q,circle:z,cross:F,barb:G},at=O,V=f((r,t,a,h,o)=>{t.arrowTypeStart&&E(r,"start",t.arrowTypeStart,a,h,o),t.arrowTypeEnd&&E(r,"end",t.arrowTypeEnd,a,h,o)},"addEdgeMarkers"),j={arrow_cross:"cross",arrow_point:"point",arrow_barb:"barb",arrow_circle:"circle",aggregation:"aggregation",extension:"extension",composition:"composition",dependency:"dependency",lollipop:"lollipop"},E=f((r,t,a,h,o,c)=>{const n=j[a];if(!n){m.warn(`Unknown arrow type: ${a}`);return}const e=t==="start"?"Start":"End";r.attr(`marker-${t}`,`url(${h}#${o}_${c}-${n}${e})`)},"addEdgeMarker"),v={},k={},rt=f(()=>{v={},k={}},"clear"),et=f((r,t)=>{const a=g(),h=W(a.flowchart.htmlLabels),o=t.labelType==="markdown"?C(r,t.label,{style:t.labelStyle,useHtmlLabels:h,addSvgBackground:!0},a):y(t.label,t.labelStyle),c=r.insert("g").attr("class","edgeLabel"),n=c.insert("g").attr("class","label");n.node().appendChild(o);let e=o.getBBox();if(h){const i=o.children[0],l=H(o);e=i.getBoundingClientRect(),l.attr("width",e.width),l.attr("height",e.height)}n.attr("transform","translate("+-e.width/2+", "+-e.height/2+")"),v[t.id]=c,t.width=e.width,t.height=e.height;let s;if(t.startLabelLeft){const i=y(t.startLabelLeft,t.labelStyle),l=r.insert("g").attr("class","edgeTerminals"),d=l.insert("g").attr("class","inner");s=d.node().appendChild(i);const p=i.getBBox();d.attr("transform","translate("+-p.width/2+", "+-p.height/2+")"),k[t.id]||(k[t.id]={}),k[t.id].startLeft=l,u(s,t.startLabelLeft)}if(t.startLabelRight){const i=y(t.startLabelRight,t.labelStyle),l=r.insert("g").attr("class","edgeTerminals"),d=l.insert("g").attr("class","inner");s=l.node().appendChild(i),d.node().appendChild(i);const p=i.getBBox();d.attr("transform","translate("+-p.width/2+", "+-p.height/2+")"),k[t.id]||(k[t.id]={}),k[t.id].startRight=l,u(s,t.startLabelRight)}if(t.endLabelLeft){const i=y(t.endLabelLeft,t.labelStyle),l=r.insert("g").attr("class","edgeTerminals"),d=l.insert("g").attr("class","inner");s=d.node().appendChild(i);const p=i.getBBox();d.attr("transform","translate("+-p.width/2+", "+-p.height/2+")"),l.node().appendChild(i),k[t.id]||(k[t.id]={}),k[t.id].endLeft=l,u(s,t.endLabelLeft)}if(t.endLabelRight){const i=y(t.endLabelRight,t.labelStyle),l=r.insert("g").attr("class","edgeTerminals"),d=l.insert("g").attr("class","inner");s=d.node().appendChild(i);const p=i.getBBox();d.attr("transform","translate("+-p.width/2+", "+-p.height/2+")"),l.node().appendChild(i),k[t.id]||(k[t.id]={}),k[t.id].endRight=l,u(s,t.endLabelRight)}return o},"insertEdgeLabel");function u(r,t){g().flowchart.htmlLabels&&r&&(r.style.width=t.length*9+"px",r.style.height="12px")}f(u,"setTerminalWidth");var st=f((r,t)=>{m.debug("Moving label abc88 ",r.id,r.label,v[r.id],t);let a=t.updatedPath?t.updatedPath:t.originalPath;const h=g(),{subGraphTitleTotalMargin:o}=R(h);if(r.label){const c=v[r.id];let n=r.x,e=r.y;if(a){const s=w.calcLabelPosition(a);m.debug("Moving label "+r.label+" from (",n,",",e,") to (",s.x,",",s.y,") abc88"),t.updatedPath&&(n=s.x,e=s.y)}c.attr("transform",`translate(${n}, ${e+o/2})`)}if(r.startLabelLeft){const c=k[r.id].startLeft;let n=r.x,e=r.y;if(a){const s=w.calcTerminalLabelPosition(r.arrowTypeStart?10:0,"start_left",a);n=s.x,e=s.y}c.attr("transform",`translate(${n}, ${e})`)}if(r.startLabelRight){const c=k[r.id].startRight;let n=r.x,e=r.y;if(a){const s=w.calcTerminalLabelPosition(r.arrowTypeStart?10:0,"start_right",a);n=s.x,e=s.y}c.attr("transform",`translate(${n}, ${e})`)}if(r.endLabelLeft){const c=k[r.id].endLeft;let n=r.x,e=r.y;if(a){const s=w.calcTerminalLabelPosition(r.arrowTypeEnd?10:0,"end_left",a);n=s.x,e=s.y}c.attr("transform",`translate(${n}, ${e})`)}if(r.endLabelRight){const c=k[r.id].endRight;let n=r.x,e=r.y;if(a){const s=w.calcTerminalLabelPosition(r.arrowTypeEnd?10:0,"end_right",a);n=s.x,e=s.y}c.attr("transform",`translate(${n}, ${e})`)}},"positionEdgeLabel"),K=f((r,t)=>{const a=r.x,h=r.y,o=Math.abs(t.x-a),c=Math.abs(t.y-h),n=r.width/2,e=r.height/2;return o>=n||c>=e},"outsideNode"),D=f((r,t,a)=>{m.debug(`intersection calc abc89:
                                         outsidePoint: ${JSON.stringify(t)}
                                         insidePoint : ${JSON.stringify(a)}
                                         node        : x:${r.x} y:${r.y} w:${r.width} h:${r.height}`);const h=r.x,o=r.y,c=Math.abs(h-a.x),n=r.width/2;let e=a.xMath.abs(h-t.x)*s){let d=a.y{m.debug("abc88 cutPathAtIntersect",r,t);let a=[],h=r[0],o=!1;return r.forEach(c=>{if(!K(t,c)&&!o){const n=D(t,h,c);let e=!1;a.forEach(s=>{e=e||s.x===n.x&&s.y===n.y}),a.some(s=>s.x===n.x&&s.y===n.y)||a.push(n),o=!0}else h=c,o||a.push(c)}),a},"cutPathAtIntersect"),nt=f(function(r,t,a,h,o,c,n){let e=a.points;m.debug("abc88 InsertEdge: edge=",a,"e=",t);let s=!1;const i=c.node(t.v);var l=c.node(t.w);l!=null&&l.intersect&&(i!=null&&i.intersect)&&(e=e.slice(1,a.points.length-1),e.unshift(i.intersect(e[0])),e.push(l.intersect(e[e.length-1]))),a.toCluster&&(m.debug("to cluster abc88",h[a.toCluster]),e=_(a.points,h[a.toCluster].node),s=!0),a.fromCluster&&(m.debug("from cluster abc88",h[a.fromCluster]),e=_(e.reverse(),h[a.fromCluster].node).reverse(),s=!0);const d=e.filter(T=>!Number.isNaN(T.y));let p=U;a.curve&&(o==="graph"||o==="flowchart")&&(p=a.curve);const{x,y:$}=X(a),S=Y().x(x).y($).curve(p);let b;switch(a.thickness){case"normal":b="edge-thickness-normal";break;case"thick":b="edge-thickness-thick";break;case"invisible":b="edge-thickness-thick";break;default:b=""}switch(a.pattern){case"solid":b+=" edge-pattern-solid";break;case"dotted":b+=" edge-pattern-dotted";break;case"dashed":b+=" edge-pattern-dashed";break}const B=r.append("path").attr("d",S(d)).attr("id",a.id).attr("class"," "+b+(a.classes?" "+a.classes:"")).attr("style",a.style);let L="";(g().flowchart.arrowMarkerAbsolute||g().state.arrowMarkerAbsolute)&&(L=window.location.protocol+"//"+window.location.host+window.location.pathname+window.location.search,L=L.replace(/\(/g,"\\("),L=L.replace(/\)/g,"\\)")),V(B,a,L,n,o);let M={};return s&&(M.updatedPath=e),M.originalPath=a.points,M},"insertEdge");export{nt as a,rt as c,et as i,at as m,st as p};
                                      diff --git a/assets/chunk-SVGOEX7Z-7nrOxk8C.js b/assets/chunk-SVGOEX7Z-FYkNEjJq.js
                                      similarity index 99%
                                      rename from assets/chunk-SVGOEX7Z-7nrOxk8C.js
                                      rename to assets/chunk-SVGOEX7Z-FYkNEjJq.js
                                      index 0eefdb1594..f7f62a8e66 100644
                                      --- a/assets/chunk-SVGOEX7Z-7nrOxk8C.js
                                      +++ b/assets/chunk-SVGOEX7Z-FYkNEjJq.js
                                      @@ -1,4 +1,4 @@
                                      -import{g as De,s as Ce}from"./chunk-FUIDI54P-DcJSRBm9.js";import{_ as r,e as H,d as x,g as xe,s as Ae,b as Le,c as Ie,q as Re,r as Oe,l as b,y as Ne,u as we,t as $e,ag as Pe}from"./mermaid.core-DapiNGBY.js";var Ot=function(){var t=r(function($,o,u,n){for(u=u||{},n=$.length;n--;u[$[n]]=o);return u},"o"),e=[1,2],c=[1,3],a=[1,4],d=[2,4],s=[1,9],p=[1,11],g=[1,16],l=[1,17],_=[1,18],v=[1,19],A=[1,32],B=[1,20],Y=[1,21],I=[1,22],f=[1,23],L=[1,24],R=[1,26],F=[1,27],V=[1,28],N=[1,29],w=[1,30],rt=[1,31],at=[1,34],nt=[1,35],lt=[1,36],ot=[1,37],J=[1,33],S=[1,4,5,16,17,19,21,22,24,25,26,27,28,29,33,35,37,38,42,45,48,49,50,51,54],ct=[1,4,5,14,15,16,17,19,21,22,24,25,26,27,28,29,33,35,37,38,42,45,48,49,50,51,54],Vt=[4,5,16,17,19,21,22,24,25,26,27,28,29,33,35,37,38,42,45,48,49,50,51,54],kt={trace:r(function(){},"trace"),yy:{},symbols_:{error:2,start:3,SPACE:4,NL:5,SD:6,document:7,line:8,statement:9,classDefStatement:10,styleStatement:11,cssClassStatement:12,idStatement:13,DESCR:14,"-->":15,HIDE_EMPTY:16,scale:17,WIDTH:18,COMPOSIT_STATE:19,STRUCT_START:20,STRUCT_STOP:21,STATE_DESCR:22,AS:23,ID:24,FORK:25,JOIN:26,CHOICE:27,CONCURRENT:28,note:29,notePosition:30,NOTE_TEXT:31,direction:32,acc_title:33,acc_title_value:34,acc_descr:35,acc_descr_value:36,acc_descr_multiline_value:37,classDef:38,CLASSDEF_ID:39,CLASSDEF_STYLEOPTS:40,DEFAULT:41,style:42,STYLE_IDS:43,STYLEDEF_STYLEOPTS:44,class:45,CLASSENTITY_IDS:46,STYLECLASS:47,direction_tb:48,direction_bt:49,direction_rl:50,direction_lr:51,eol:52,";":53,EDGE_STATE:54,STYLE_SEPARATOR:55,left_of:56,right_of:57,$accept:0,$end:1},terminals_:{2:"error",4:"SPACE",5:"NL",6:"SD",14:"DESCR",15:"-->",16:"HIDE_EMPTY",17:"scale",18:"WIDTH",19:"COMPOSIT_STATE",20:"STRUCT_START",21:"STRUCT_STOP",22:"STATE_DESCR",23:"AS",24:"ID",25:"FORK",26:"JOIN",27:"CHOICE",28:"CONCURRENT",29:"note",31:"NOTE_TEXT",33:"acc_title",34:"acc_title_value",35:"acc_descr",36:"acc_descr_value",37:"acc_descr_multiline_value",38:"classDef",39:"CLASSDEF_ID",40:"CLASSDEF_STYLEOPTS",41:"DEFAULT",42:"style",43:"STYLE_IDS",44:"STYLEDEF_STYLEOPTS",45:"class",46:"CLASSENTITY_IDS",47:"STYLECLASS",48:"direction_tb",49:"direction_bt",50:"direction_rl",51:"direction_lr",53:";",54:"EDGE_STATE",55:"STYLE_SEPARATOR",56:"left_of",57:"right_of"},productions_:[0,[3,2],[3,2],[3,2],[7,0],[7,2],[8,2],[8,1],[8,1],[9,1],[9,1],[9,1],[9,1],[9,2],[9,3],[9,4],[9,1],[9,2],[9,1],[9,4],[9,3],[9,6],[9,1],[9,1],[9,1],[9,1],[9,4],[9,4],[9,1],[9,2],[9,2],[9,1],[10,3],[10,3],[11,3],[12,3],[32,1],[32,1],[32,1],[32,1],[52,1],[52,1],[13,1],[13,1],[13,3],[13,3],[30,1],[30,1]],performAction:r(function(o,u,n,y,T,i,q){var h=i.length-1;switch(T){case 3:return y.setRootDoc(i[h]),i[h];case 4:this.$=[];break;case 5:i[h]!="nl"&&(i[h-1].push(i[h]),this.$=i[h-1]);break;case 6:case 7:this.$=i[h];break;case 8:this.$="nl";break;case 12:this.$=i[h];break;case 13:const Q=i[h-1];Q.description=y.trimColon(i[h]),this.$=Q;break;case 14:this.$={stmt:"relation",state1:i[h-2],state2:i[h]};break;case 15:const Dt=y.trimColon(i[h]);this.$={stmt:"relation",state1:i[h-3],state2:i[h-1],description:Dt};break;case 19:this.$={stmt:"state",id:i[h-3],type:"default",description:"",doc:i[h-1]};break;case 20:var M=i[h],W=i[h-2].trim();if(i[h].match(":")){var ht=i[h].split(":");M=ht[0],W=[W,ht[1]]}this.$={stmt:"state",id:M,type:"default",description:W};break;case 21:this.$={stmt:"state",id:i[h-3],type:"default",description:i[h-5],doc:i[h-1]};break;case 22:this.$={stmt:"state",id:i[h],type:"fork"};break;case 23:this.$={stmt:"state",id:i[h],type:"join"};break;case 24:this.$={stmt:"state",id:i[h],type:"choice"};break;case 25:this.$={stmt:"state",id:y.getDividerId(),type:"divider"};break;case 26:this.$={stmt:"state",id:i[h-1].trim(),note:{position:i[h-2].trim(),text:i[h].trim()}};break;case 29:this.$=i[h].trim(),y.setAccTitle(this.$);break;case 30:case 31:this.$=i[h].trim(),y.setAccDescription(this.$);break;case 32:case 33:this.$={stmt:"classDef",id:i[h-1].trim(),classes:i[h].trim()};break;case 34:this.$={stmt:"style",id:i[h-1].trim(),styleClass:i[h].trim()};break;case 35:this.$={stmt:"applyClass",id:i[h-1].trim(),styleClass:i[h].trim()};break;case 36:y.setDirection("TB"),this.$={stmt:"dir",value:"TB"};break;case 37:y.setDirection("BT"),this.$={stmt:"dir",value:"BT"};break;case 38:y.setDirection("RL"),this.$={stmt:"dir",value:"RL"};break;case 39:y.setDirection("LR"),this.$={stmt:"dir",value:"LR"};break;case 42:case 43:this.$={stmt:"state",id:i[h].trim(),type:"default",description:""};break;case 44:this.$={stmt:"state",id:i[h-2].trim(),classes:[i[h].trim()],type:"default",description:""};break;case 45:this.$={stmt:"state",id:i[h-2].trim(),classes:[i[h].trim()],type:"default",description:""};break}},"anonymous"),table:[{3:1,4:e,5:c,6:a},{1:[3]},{3:5,4:e,5:c,6:a},{3:6,4:e,5:c,6:a},t([1,4,5,16,17,19,22,24,25,26,27,28,29,33,35,37,38,42,45,48,49,50,51,54],d,{7:7}),{1:[2,1]},{1:[2,2]},{1:[2,3],4:s,5:p,8:8,9:10,10:12,11:13,12:14,13:15,16:g,17:l,19:_,22:v,24:A,25:B,26:Y,27:I,28:f,29:L,32:25,33:R,35:F,37:V,38:N,42:w,45:rt,48:at,49:nt,50:lt,51:ot,54:J},t(S,[2,5]),{9:38,10:12,11:13,12:14,13:15,16:g,17:l,19:_,22:v,24:A,25:B,26:Y,27:I,28:f,29:L,32:25,33:R,35:F,37:V,38:N,42:w,45:rt,48:at,49:nt,50:lt,51:ot,54:J},t(S,[2,7]),t(S,[2,8]),t(S,[2,9]),t(S,[2,10]),t(S,[2,11]),t(S,[2,12],{14:[1,39],15:[1,40]}),t(S,[2,16]),{18:[1,41]},t(S,[2,18],{20:[1,42]}),{23:[1,43]},t(S,[2,22]),t(S,[2,23]),t(S,[2,24]),t(S,[2,25]),{30:44,31:[1,45],56:[1,46],57:[1,47]},t(S,[2,28]),{34:[1,48]},{36:[1,49]},t(S,[2,31]),{39:[1,50],41:[1,51]},{43:[1,52]},{46:[1,53]},t(ct,[2,42],{55:[1,54]}),t(ct,[2,43],{55:[1,55]}),t(S,[2,36]),t(S,[2,37]),t(S,[2,38]),t(S,[2,39]),t(S,[2,6]),t(S,[2,13]),{13:56,24:A,54:J},t(S,[2,17]),t(Vt,d,{7:57}),{24:[1,58]},{24:[1,59]},{23:[1,60]},{24:[2,46]},{24:[2,47]},t(S,[2,29]),t(S,[2,30]),{40:[1,61]},{40:[1,62]},{44:[1,63]},{47:[1,64]},{24:[1,65]},{24:[1,66]},t(S,[2,14],{14:[1,67]}),{4:s,5:p,8:8,9:10,10:12,11:13,12:14,13:15,16:g,17:l,19:_,21:[1,68],22:v,24:A,25:B,26:Y,27:I,28:f,29:L,32:25,33:R,35:F,37:V,38:N,42:w,45:rt,48:at,49:nt,50:lt,51:ot,54:J},t(S,[2,20],{20:[1,69]}),{31:[1,70]},{24:[1,71]},t(S,[2,32]),t(S,[2,33]),t(S,[2,34]),t(S,[2,35]),t(ct,[2,44]),t(ct,[2,45]),t(S,[2,15]),t(S,[2,19]),t(Vt,d,{7:72}),t(S,[2,26]),t(S,[2,27]),{4:s,5:p,8:8,9:10,10:12,11:13,12:14,13:15,16:g,17:l,19:_,21:[1,73],22:v,24:A,25:B,26:Y,27:I,28:f,29:L,32:25,33:R,35:F,37:V,38:N,42:w,45:rt,48:at,49:nt,50:lt,51:ot,54:J},t(S,[2,21])],defaultActions:{5:[2,1],6:[2,2],46:[2,46],47:[2,47]},parseError:r(function(o,u){if(u.recoverable)this.trace(o);else{var n=new Error(o);throw n.hash=u,n}},"parseError"),parse:r(function(o){var u=this,n=[0],y=[],T=[null],i=[],q=this.table,h="",M=0,W=0,ht=2,Q=1,Dt=i.slice.call(arguments,1),E=Object.create(this.lexer),U={yy:{}};for(var Ct in this.yy)Object.prototype.hasOwnProperty.call(this.yy,Ct)&&(U.yy[Ct]=this.yy[Ct]);E.setInput(o,U.yy),U.yy.lexer=E,U.yy.parser=this,typeof E.yylloc>"u"&&(E.yylloc={});var xt=E.yylloc;i.push(xt);var me=E.options&&E.options.ranges;typeof U.yy.parseError=="function"?this.parseError=U.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function ke(D){n.length=n.length-2*D,T.length=T.length-D,i.length=i.length-D}r(ke,"popStack");function Mt(){var D;return D=y.pop()||E.lex()||Q,typeof D!="number"&&(D instanceof Array&&(y=D,D=y.pop()),D=u.symbols_[D]||D),D}r(Mt,"lex");for(var m,j,C,At,X={},dt,O,Ut,ft;;){if(j=n[n.length-1],this.defaultActions[j]?C=this.defaultActions[j]:((m===null||typeof m>"u")&&(m=Mt()),C=q[j]&&q[j][m]),typeof C>"u"||!C.length||!C[0]){var Lt="";ft=[];for(dt in q[j])this.terminals_[dt]&&dt>ht&&ft.push("'"+this.terminals_[dt]+"'");E.showPosition?Lt="Parse error on line "+(M+1)+`:
                                      +import{g as De,s as Ce}from"./chunk-FUIDI54P-B3wdDwu1.js";import{_ as r,e as H,d as x,g as xe,s as Ae,b as Le,c as Ie,q as Re,r as Oe,l as b,y as Ne,u as we,t as $e,ag as Pe}from"./mermaid.core-D8igZDel.js";var Ot=function(){var t=r(function($,o,u,n){for(u=u||{},n=$.length;n--;u[$[n]]=o);return u},"o"),e=[1,2],c=[1,3],a=[1,4],d=[2,4],s=[1,9],p=[1,11],g=[1,16],l=[1,17],_=[1,18],v=[1,19],A=[1,32],B=[1,20],Y=[1,21],I=[1,22],f=[1,23],L=[1,24],R=[1,26],F=[1,27],V=[1,28],N=[1,29],w=[1,30],rt=[1,31],at=[1,34],nt=[1,35],lt=[1,36],ot=[1,37],J=[1,33],S=[1,4,5,16,17,19,21,22,24,25,26,27,28,29,33,35,37,38,42,45,48,49,50,51,54],ct=[1,4,5,14,15,16,17,19,21,22,24,25,26,27,28,29,33,35,37,38,42,45,48,49,50,51,54],Vt=[4,5,16,17,19,21,22,24,25,26,27,28,29,33,35,37,38,42,45,48,49,50,51,54],kt={trace:r(function(){},"trace"),yy:{},symbols_:{error:2,start:3,SPACE:4,NL:5,SD:6,document:7,line:8,statement:9,classDefStatement:10,styleStatement:11,cssClassStatement:12,idStatement:13,DESCR:14,"-->":15,HIDE_EMPTY:16,scale:17,WIDTH:18,COMPOSIT_STATE:19,STRUCT_START:20,STRUCT_STOP:21,STATE_DESCR:22,AS:23,ID:24,FORK:25,JOIN:26,CHOICE:27,CONCURRENT:28,note:29,notePosition:30,NOTE_TEXT:31,direction:32,acc_title:33,acc_title_value:34,acc_descr:35,acc_descr_value:36,acc_descr_multiline_value:37,classDef:38,CLASSDEF_ID:39,CLASSDEF_STYLEOPTS:40,DEFAULT:41,style:42,STYLE_IDS:43,STYLEDEF_STYLEOPTS:44,class:45,CLASSENTITY_IDS:46,STYLECLASS:47,direction_tb:48,direction_bt:49,direction_rl:50,direction_lr:51,eol:52,";":53,EDGE_STATE:54,STYLE_SEPARATOR:55,left_of:56,right_of:57,$accept:0,$end:1},terminals_:{2:"error",4:"SPACE",5:"NL",6:"SD",14:"DESCR",15:"-->",16:"HIDE_EMPTY",17:"scale",18:"WIDTH",19:"COMPOSIT_STATE",20:"STRUCT_START",21:"STRUCT_STOP",22:"STATE_DESCR",23:"AS",24:"ID",25:"FORK",26:"JOIN",27:"CHOICE",28:"CONCURRENT",29:"note",31:"NOTE_TEXT",33:"acc_title",34:"acc_title_value",35:"acc_descr",36:"acc_descr_value",37:"acc_descr_multiline_value",38:"classDef",39:"CLASSDEF_ID",40:"CLASSDEF_STYLEOPTS",41:"DEFAULT",42:"style",43:"STYLE_IDS",44:"STYLEDEF_STYLEOPTS",45:"class",46:"CLASSENTITY_IDS",47:"STYLECLASS",48:"direction_tb",49:"direction_bt",50:"direction_rl",51:"direction_lr",53:";",54:"EDGE_STATE",55:"STYLE_SEPARATOR",56:"left_of",57:"right_of"},productions_:[0,[3,2],[3,2],[3,2],[7,0],[7,2],[8,2],[8,1],[8,1],[9,1],[9,1],[9,1],[9,1],[9,2],[9,3],[9,4],[9,1],[9,2],[9,1],[9,4],[9,3],[9,6],[9,1],[9,1],[9,1],[9,1],[9,4],[9,4],[9,1],[9,2],[9,2],[9,1],[10,3],[10,3],[11,3],[12,3],[32,1],[32,1],[32,1],[32,1],[52,1],[52,1],[13,1],[13,1],[13,3],[13,3],[30,1],[30,1]],performAction:r(function(o,u,n,y,T,i,q){var h=i.length-1;switch(T){case 3:return y.setRootDoc(i[h]),i[h];case 4:this.$=[];break;case 5:i[h]!="nl"&&(i[h-1].push(i[h]),this.$=i[h-1]);break;case 6:case 7:this.$=i[h];break;case 8:this.$="nl";break;case 12:this.$=i[h];break;case 13:const Q=i[h-1];Q.description=y.trimColon(i[h]),this.$=Q;break;case 14:this.$={stmt:"relation",state1:i[h-2],state2:i[h]};break;case 15:const Dt=y.trimColon(i[h]);this.$={stmt:"relation",state1:i[h-3],state2:i[h-1],description:Dt};break;case 19:this.$={stmt:"state",id:i[h-3],type:"default",description:"",doc:i[h-1]};break;case 20:var M=i[h],W=i[h-2].trim();if(i[h].match(":")){var ht=i[h].split(":");M=ht[0],W=[W,ht[1]]}this.$={stmt:"state",id:M,type:"default",description:W};break;case 21:this.$={stmt:"state",id:i[h-3],type:"default",description:i[h-5],doc:i[h-1]};break;case 22:this.$={stmt:"state",id:i[h],type:"fork"};break;case 23:this.$={stmt:"state",id:i[h],type:"join"};break;case 24:this.$={stmt:"state",id:i[h],type:"choice"};break;case 25:this.$={stmt:"state",id:y.getDividerId(),type:"divider"};break;case 26:this.$={stmt:"state",id:i[h-1].trim(),note:{position:i[h-2].trim(),text:i[h].trim()}};break;case 29:this.$=i[h].trim(),y.setAccTitle(this.$);break;case 30:case 31:this.$=i[h].trim(),y.setAccDescription(this.$);break;case 32:case 33:this.$={stmt:"classDef",id:i[h-1].trim(),classes:i[h].trim()};break;case 34:this.$={stmt:"style",id:i[h-1].trim(),styleClass:i[h].trim()};break;case 35:this.$={stmt:"applyClass",id:i[h-1].trim(),styleClass:i[h].trim()};break;case 36:y.setDirection("TB"),this.$={stmt:"dir",value:"TB"};break;case 37:y.setDirection("BT"),this.$={stmt:"dir",value:"BT"};break;case 38:y.setDirection("RL"),this.$={stmt:"dir",value:"RL"};break;case 39:y.setDirection("LR"),this.$={stmt:"dir",value:"LR"};break;case 42:case 43:this.$={stmt:"state",id:i[h].trim(),type:"default",description:""};break;case 44:this.$={stmt:"state",id:i[h-2].trim(),classes:[i[h].trim()],type:"default",description:""};break;case 45:this.$={stmt:"state",id:i[h-2].trim(),classes:[i[h].trim()],type:"default",description:""};break}},"anonymous"),table:[{3:1,4:e,5:c,6:a},{1:[3]},{3:5,4:e,5:c,6:a},{3:6,4:e,5:c,6:a},t([1,4,5,16,17,19,22,24,25,26,27,28,29,33,35,37,38,42,45,48,49,50,51,54],d,{7:7}),{1:[2,1]},{1:[2,2]},{1:[2,3],4:s,5:p,8:8,9:10,10:12,11:13,12:14,13:15,16:g,17:l,19:_,22:v,24:A,25:B,26:Y,27:I,28:f,29:L,32:25,33:R,35:F,37:V,38:N,42:w,45:rt,48:at,49:nt,50:lt,51:ot,54:J},t(S,[2,5]),{9:38,10:12,11:13,12:14,13:15,16:g,17:l,19:_,22:v,24:A,25:B,26:Y,27:I,28:f,29:L,32:25,33:R,35:F,37:V,38:N,42:w,45:rt,48:at,49:nt,50:lt,51:ot,54:J},t(S,[2,7]),t(S,[2,8]),t(S,[2,9]),t(S,[2,10]),t(S,[2,11]),t(S,[2,12],{14:[1,39],15:[1,40]}),t(S,[2,16]),{18:[1,41]},t(S,[2,18],{20:[1,42]}),{23:[1,43]},t(S,[2,22]),t(S,[2,23]),t(S,[2,24]),t(S,[2,25]),{30:44,31:[1,45],56:[1,46],57:[1,47]},t(S,[2,28]),{34:[1,48]},{36:[1,49]},t(S,[2,31]),{39:[1,50],41:[1,51]},{43:[1,52]},{46:[1,53]},t(ct,[2,42],{55:[1,54]}),t(ct,[2,43],{55:[1,55]}),t(S,[2,36]),t(S,[2,37]),t(S,[2,38]),t(S,[2,39]),t(S,[2,6]),t(S,[2,13]),{13:56,24:A,54:J},t(S,[2,17]),t(Vt,d,{7:57}),{24:[1,58]},{24:[1,59]},{23:[1,60]},{24:[2,46]},{24:[2,47]},t(S,[2,29]),t(S,[2,30]),{40:[1,61]},{40:[1,62]},{44:[1,63]},{47:[1,64]},{24:[1,65]},{24:[1,66]},t(S,[2,14],{14:[1,67]}),{4:s,5:p,8:8,9:10,10:12,11:13,12:14,13:15,16:g,17:l,19:_,21:[1,68],22:v,24:A,25:B,26:Y,27:I,28:f,29:L,32:25,33:R,35:F,37:V,38:N,42:w,45:rt,48:at,49:nt,50:lt,51:ot,54:J},t(S,[2,20],{20:[1,69]}),{31:[1,70]},{24:[1,71]},t(S,[2,32]),t(S,[2,33]),t(S,[2,34]),t(S,[2,35]),t(ct,[2,44]),t(ct,[2,45]),t(S,[2,15]),t(S,[2,19]),t(Vt,d,{7:72}),t(S,[2,26]),t(S,[2,27]),{4:s,5:p,8:8,9:10,10:12,11:13,12:14,13:15,16:g,17:l,19:_,21:[1,73],22:v,24:A,25:B,26:Y,27:I,28:f,29:L,32:25,33:R,35:F,37:V,38:N,42:w,45:rt,48:at,49:nt,50:lt,51:ot,54:J},t(S,[2,21])],defaultActions:{5:[2,1],6:[2,2],46:[2,46],47:[2,47]},parseError:r(function(o,u){if(u.recoverable)this.trace(o);else{var n=new Error(o);throw n.hash=u,n}},"parseError"),parse:r(function(o){var u=this,n=[0],y=[],T=[null],i=[],q=this.table,h="",M=0,W=0,ht=2,Q=1,Dt=i.slice.call(arguments,1),E=Object.create(this.lexer),U={yy:{}};for(var Ct in this.yy)Object.prototype.hasOwnProperty.call(this.yy,Ct)&&(U.yy[Ct]=this.yy[Ct]);E.setInput(o,U.yy),U.yy.lexer=E,U.yy.parser=this,typeof E.yylloc>"u"&&(E.yylloc={});var xt=E.yylloc;i.push(xt);var me=E.options&&E.options.ranges;typeof U.yy.parseError=="function"?this.parseError=U.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function ke(D){n.length=n.length-2*D,T.length=T.length-D,i.length=i.length-D}r(ke,"popStack");function Mt(){var D;return D=y.pop()||E.lex()||Q,typeof D!="number"&&(D instanceof Array&&(y=D,D=y.pop()),D=u.symbols_[D]||D),D}r(Mt,"lex");for(var m,j,C,At,X={},dt,O,Ut,ft;;){if(j=n[n.length-1],this.defaultActions[j]?C=this.defaultActions[j]:((m===null||typeof m>"u")&&(m=Mt()),C=q[j]&&q[j][m]),typeof C>"u"||!C.length||!C[0]){var Lt="";ft=[];for(dt in q[j])this.terminals_[dt]&&dt>ht&&ft.push("'"+this.terminals_[dt]+"'");E.showPosition?Lt="Parse error on line "+(M+1)+`:
                                       `+E.showPosition()+`
                                       Expecting `+ft.join(", ")+", got '"+(this.terminals_[m]||m)+"'":Lt="Parse error on line "+(M+1)+": Unexpected "+(m==Q?"end of input":"'"+(this.terminals_[m]||m)+"'"),this.parseError(Lt,{text:E.match,token:this.terminals_[m]||m,line:E.yylineno,loc:xt,expected:ft})}if(C[0]instanceof Array&&C.length>1)throw new Error("Parse Error: multiple actions possible at state: "+j+", token: "+m);switch(C[0]){case 1:n.push(m),T.push(E.yytext),i.push(E.yylloc),n.push(C[1]),m=null,W=E.yyleng,h=E.yytext,M=E.yylineno,xt=E.yylloc;break;case 2:if(O=this.productions_[C[1]][1],X.$=T[T.length-O],X._$={first_line:i[i.length-(O||1)].first_line,last_line:i[i.length-1].last_line,first_column:i[i.length-(O||1)].first_column,last_column:i[i.length-1].last_column},me&&(X._$.range=[i[i.length-(O||1)].range[0],i[i.length-1].range[1]]),At=this.performAction.apply(X,[h,W,M,U.yy,C[1],T,i].concat(Dt)),typeof At<"u")return At;O&&(n=n.slice(0,-1*O*2),T=T.slice(0,-1*O),i=i.slice(0,-1*O)),n.push(this.productions_[C[1]][0]),T.push(X.$),i.push(X._$),Ut=q[n[n.length-2]][n[n.length-1]],n.push(Ut);break;case 3:return!0}}return!0},"parse")},be=function(){var $={EOF:1,parseError:r(function(u,n){if(this.yy.parser)this.yy.parser.parseError(u,n);else throw new Error(u)},"parseError"),setInput:r(function(o,u){return this.yy=u||this.yy||{},this._input=o,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},"setInput"),input:r(function(){var o=this._input[0];this.yytext+=o,this.yyleng++,this.offset++,this.match+=o,this.matched+=o;var u=o.match(/(?:\r\n?|\n).*/g);return u?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),o},"input"),unput:r(function(o){var u=o.length,n=o.split(/(?:\r\n?|\n)/g);this._input=o+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-u),this.offset-=u;var y=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),n.length-1&&(this.yylineno-=n.length-1);var T=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:n?(n.length===y.length?this.yylloc.first_column:0)+y[y.length-n.length].length-n[0].length:this.yylloc.first_column-u},this.options.ranges&&(this.yylloc.range=[T[0],T[0]+this.yyleng-u]),this.yyleng=this.yytext.length,this},"unput"),more:r(function(){return this._more=!0,this},"more"),reject:r(function(){if(this.options.backtrack_lexer)this._backtrack=!0;else return this.parseError("Lexical error on line "+(this.yylineno+1)+`. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).
                                       `+this.showPosition(),{text:"",token:null,line:this.yylineno});return this},"reject"),less:r(function(o){this.unput(this.match.slice(o))},"less"),pastInput:r(function(){var o=this.matched.substr(0,this.matched.length-this.match.length);return(o.length>20?"...":"")+o.substr(-20).replace(/\n/g,"")},"pastInput"),upcomingInput:r(function(){var o=this.match;return o.length<20&&(o+=this._input.substr(0,20-o.length)),(o.substr(0,20)+(o.length>20?"...":"")).replace(/\n/g,"")},"upcomingInput"),showPosition:r(function(){var o=this.pastInput(),u=new Array(o.length+1).join("-");return o+this.upcomingInput()+`
                                      diff --git a/assets/chunk-Z2VRG6XP-DsASRjJ5.js b/assets/chunk-Z2VRG6XP-CV0pyCU1.js
                                      similarity index 99%
                                      rename from assets/chunk-Z2VRG6XP-DsASRjJ5.js
                                      rename to assets/chunk-Z2VRG6XP-CV0pyCU1.js
                                      index d19f8e145b..7b4da78967 100644
                                      --- a/assets/chunk-Z2VRG6XP-DsASRjJ5.js
                                      +++ b/assets/chunk-Z2VRG6XP-CV0pyCU1.js
                                      @@ -1 +1 @@
                                      -import{_ as o,j as T,l as L,d as N,A,B as ct,C as X,D as lt,i as J}from"./mermaid.core-DapiNGBY.js";function K(l,t){t&&l.attr("style",t)}o(K,"applyStyle");function Z(l){const t=T(document.createElementNS("http://www.w3.org/2000/svg","foreignObject")),c=t.append("xhtml:div"),e=l.label,s=l.isNode?"nodeLabel":"edgeLabel",r=c.append("span");return r.html(e),K(r,l.labelStyle),r.attr("class",s),K(c,l.labelStyle),c.style("display","inline-block"),c.style("white-space","nowrap"),c.attr("xmlns","http://www.w3.org/1999/xhtml"),t.node()}o(Z,"addHtmlLabel");var nt=o((l,t,c,e)=>{let s=l||"";if(typeof s=="object"&&(s=s[0]),A(N().flowchart.htmlLabels)){s=s.replace(/\\n|\n/g,"
                                      "),L.debug("vertexText"+s);const r={isNode:e,label:ct(X(s)),labelStyle:t.replace("fill:","color:")};return Z(r)}else{const r=document.createElementNS("http://www.w3.org/2000/svg","text");r.setAttribute("style",t.replace("color:","fill:"));let a=[];typeof s=="string"?a=s.split(/\\n|\n|/gi):Array.isArray(s)?a=s:a=[];for(const i of a){const n=document.createElementNS("http://www.w3.org/2000/svg","tspan");n.setAttributeNS("http://www.w3.org/XML/1998/namespace","xml:space","preserve"),n.setAttribute("dy","1em"),n.setAttribute("x","0"),c?n.setAttribute("class","title-row"):n.setAttribute("class","row"),n.textContent=i.trim(),r.appendChild(n)}return r}},"createLabel"),R=nt,_=o(async(l,t,c,e)=>{const s=N();let r;const a=t.useHtmlLabels||A(s.flowchart.htmlLabels);c?r=c:r="node default";const i=l.insert("g").attr("class",r).attr("id",t.domId||t.id),n=i.insert("g").attr("class","label").attr("style",t.labelStyle);let y;t.labelText===void 0?y="":y=typeof t.labelText=="string"?t.labelText:t.labelText[0];const h=n.node();let x;t.labelType==="markdown"?x=lt(n,J(X(y),s),{useHtmlLabels:a,width:t.width||s.flowchart.wrappingWidth,classes:"markdown-node-label"},s):x=h.appendChild(R(J(X(y),s),t.labelStyle,!1,e));let f=x.getBBox();const g=t.padding/2;if(A(s.flowchart.htmlLabels)){const d=x.children[0],m=T(x),p=d.getElementsByTagName("img");if(p){const C=y.replace(/]*>/g,"").trim()==="";await Promise.all([...p].map(S=>new Promise(E=>{function B(){if(S.style.display="flex",S.style.flexDirection="column",C){const j=s.fontSize?s.fontSize:window.getComputedStyle(document.body).fontSize,F=parseInt(j,10)*5+"px";S.style.minWidth=F,S.style.maxWidth=F}else S.style.width="100%";E(S)}o(B,"setupImage"),setTimeout(()=>{S.complete&&B()}),S.addEventListener("error",B),S.addEventListener("load",B)})))}f=d.getBoundingClientRect(),m.attr("width",f.width),m.attr("height",f.height)}return a?n.attr("transform","translate("+-f.width/2+", "+-f.height/2+")"):n.attr("transform","translate(0, "+-f.height/2+")"),t.centerLabel&&n.attr("transform","translate("+-f.width/2+", "+-f.height/2+")"),n.insert("rect",":first-child"),{shapeSvg:i,bbox:f,halfPadding:g,label:n}},"labelHelper"),w=o((l,t)=>{const c=t.node().getBBox();l.width=c.width,l.height=c.height},"updateNodeBounds");function D(l,t,c,e){return l.insert("polygon",":first-child").attr("points",e.map(function(s){return s.x+","+s.y}).join(" ")).attr("class","label-container").attr("transform","translate("+-t/2+","+c/2+")")}o(D,"insertPolygonShape");var ht=o(l=>{const t=new Set;for(const c of l)switch(c){case"x":t.add("right"),t.add("left");break;case"y":t.add("up"),t.add("down");break;default:t.add(c);break}return t},"expandAndDeduplicateDirections"),ot=o((l,t,c)=>{const e=ht(l),s=2,r=t.height+2*c.padding,a=r/s,i=t.width+2*a+c.padding,n=c.padding/2;return e.has("right")&&e.has("left")&&e.has("up")&&e.has("down")?[{x:0,y:0},{x:a,y:0},{x:i/2,y:2*n},{x:i-a,y:0},{x:i,y:0},{x:i,y:-r/3},{x:i+2*n,y:-r/2},{x:i,y:-2*r/3},{x:i,y:-r},{x:i-a,y:-r},{x:i/2,y:-r-2*n},{x:a,y:-r},{x:0,y:-r},{x:0,y:-2*r/3},{x:-2*n,y:-r/2},{x:0,y:-r/3}]:e.has("right")&&e.has("left")&&e.has("up")?[{x:a,y:0},{x:i-a,y:0},{x:i,y:-r/2},{x:i-a,y:-r},{x:a,y:-r},{x:0,y:-r/2}]:e.has("right")&&e.has("left")&&e.has("down")?[{x:0,y:0},{x:a,y:-r},{x:i-a,y:-r},{x:i,y:0}]:e.has("right")&&e.has("up")&&e.has("down")?[{x:0,y:0},{x:i,y:-a},{x:i,y:-r+a},{x:0,y:-r}]:e.has("left")&&e.has("up")&&e.has("down")?[{x:i,y:0},{x:0,y:-a},{x:0,y:-r+a},{x:i,y:-r}]:e.has("right")&&e.has("left")?[{x:a,y:0},{x:a,y:-n},{x:i-a,y:-n},{x:i-a,y:0},{x:i,y:-r/2},{x:i-a,y:-r},{x:i-a,y:-r+n},{x:a,y:-r+n},{x:a,y:-r},{x:0,y:-r/2}]:e.has("up")&&e.has("down")?[{x:i/2,y:0},{x:0,y:-n},{x:a,y:-n},{x:a,y:-r+n},{x:0,y:-r+n},{x:i/2,y:-r},{x:i,y:-r+n},{x:i-a,y:-r+n},{x:i-a,y:-n},{x:i,y:-n}]:e.has("right")&&e.has("up")?[{x:0,y:0},{x:i,y:-a},{x:0,y:-r}]:e.has("right")&&e.has("down")?[{x:0,y:0},{x:i,y:0},{x:0,y:-r}]:e.has("left")&&e.has("up")?[{x:i,y:0},{x:0,y:-a},{x:i,y:-r}]:e.has("left")&&e.has("down")?[{x:i,y:0},{x:0,y:0},{x:i,y:-r}]:e.has("right")?[{x:a,y:-n},{x:a,y:-n},{x:i-a,y:-n},{x:i-a,y:0},{x:i,y:-r/2},{x:i-a,y:-r},{x:i-a,y:-r+n},{x:a,y:-r+n},{x:a,y:-r+n}]:e.has("left")?[{x:a,y:0},{x:a,y:-n},{x:i-a,y:-n},{x:i-a,y:-r+n},{x:a,y:-r+n},{x:a,y:-r},{x:0,y:-r/2}]:e.has("up")?[{x:a,y:-n},{x:a,y:-r+n},{x:0,y:-r+n},{x:i/2,y:-r},{x:i,y:-r+n},{x:i-a,y:-r+n},{x:i-a,y:-n}]:e.has("down")?[{x:i/2,y:0},{x:0,y:-n},{x:a,y:-n},{x:a,y:-r+n},{x:i-a,y:-r+n},{x:i-a,y:-n},{x:i,y:-n}]:[{x:0,y:0}]},"getArrowPoints");function tt(l,t){return l.intersect(t)}o(tt,"intersectNode");var yt=tt;function rt(l,t,c,e){var s=l.x,r=l.y,a=s-e.x,i=r-e.y,n=Math.sqrt(t*t*i*i+c*c*a*a),y=Math.abs(t*c*a/n);e.x0}o(U,"sameSign");var gt=st,ft=it;function it(l,t,c){var e=l.x,s=l.y,r=[],a=Number.POSITIVE_INFINITY,i=Number.POSITIVE_INFINITY;typeof t.forEach=="function"?t.forEach(function(d){a=Math.min(a,d.x),i=Math.min(i,d.y)}):(a=Math.min(a,t.x),i=Math.min(i,t.y));for(var n=e-l.width/2-a,y=s-l.height/2-i,h=0;h1&&r.sort(function(d,m){var p=d.x-c.x,C=d.y-c.y,S=Math.sqrt(p*p+C*C),E=m.x-c.x,B=m.y-c.y,j=Math.sqrt(E*E+B*B);return S{var c=l.x,e=l.y,s=t.x-c,r=t.y-e,a=l.width/2,i=l.height/2,n,y;return Math.abs(r)*a>Math.abs(s)*i?(r<0&&(i=-i),n=r===0?0:i*s/r,y=i):(s<0&&(a=-a),n=a,y=s===0?0:a*r/s),{x:c+n,y:e+y}},"intersectRect"),pt=dt,u={node:yt,circle:xt,ellipse:at,polygon:ft,rect:pt},ut=o(async(l,t)=>{t.useHtmlLabels||N().flowchart.htmlLabels||(t.centerLabel=!0);const{shapeSvg:e,bbox:s,halfPadding:r}=await _(l,t,"node "+t.classes,!0);L.info("Classes = ",t.classes);const a=e.insert("rect",":first-child");return a.attr("rx",t.rx).attr("ry",t.ry).attr("x",-s.width/2-r).attr("y",-s.height/2-r).attr("width",s.width+t.padding).attr("height",s.height+t.padding),w(t,a),t.intersect=function(i){return u.rect(t,i)},e},"note"),wt=ut,V=o(l=>l?" "+l:"","formatClass"),I=o((l,t)=>`${t||"node default"}${V(l.classes)} ${V(l.class)}`,"getClassesFromNode"),G=o(async(l,t)=>{const{shapeSvg:c,bbox:e}=await _(l,t,I(t,void 0),!0),s=e.width+t.padding,r=e.height+t.padding,a=s+r,i=[{x:a/2,y:0},{x:a,y:-a/2},{x:a/2,y:-a},{x:0,y:-a/2}];L.info("Question main (Circle)");const n=D(c,a,a,i);return n.attr("style",t.style),w(t,n),t.intersect=function(y){return L.warn("Intersect called"),u.polygon(t,i,y)},c},"question"),bt=o((l,t)=>{const c=l.insert("g").attr("class","node default").attr("id",t.domId||t.id),e=28,s=[{x:0,y:e/2},{x:e/2,y:0},{x:0,y:-e/2},{x:-e/2,y:0}];return c.insert("polygon",":first-child").attr("points",s.map(function(a){return a.x+","+a.y}).join(" ")).attr("class","state-start").attr("r",7).attr("width",28).attr("height",28),t.width=28,t.height=28,t.intersect=function(a){return u.circle(t,14,a)},c},"choice"),vt=o(async(l,t)=>{const{shapeSvg:c,bbox:e}=await _(l,t,I(t,void 0),!0),s=4,r=e.height+t.padding,a=r/s,i=e.width+2*a+t.padding,n=[{x:a,y:0},{x:i-a,y:0},{x:i,y:-r/2},{x:i-a,y:-r},{x:a,y:-r},{x:0,y:-r/2}],y=D(c,i,r,n);return y.attr("style",t.style),w(t,y),t.intersect=function(h){return u.polygon(t,n,h)},c},"hexagon"),mt=o(async(l,t)=>{const{shapeSvg:c,bbox:e}=await _(l,t,void 0,!0),s=2,r=e.height+2*t.padding,a=r/s,i=e.width+2*a+t.padding,n=ot(t.directions,e,t),y=D(c,i,r,n);return y.attr("style",t.style),w(t,y),t.intersect=function(h){return u.polygon(t,n,h)},c},"block_arrow"),St=o(async(l,t)=>{const{shapeSvg:c,bbox:e}=await _(l,t,I(t,void 0),!0),s=e.width+t.padding,r=e.height+t.padding,a=[{x:-r/2,y:0},{x:s,y:0},{x:s,y:-r},{x:-r/2,y:-r},{x:0,y:-r/2}];return D(c,s,r,a).attr("style",t.style),t.width=s+r,t.height=r,t.intersect=function(n){return u.polygon(t,a,n)},c},"rect_left_inv_arrow"),Lt=o(async(l,t)=>{const{shapeSvg:c,bbox:e}=await _(l,t,I(t),!0),s=e.width+t.padding,r=e.height+t.padding,a=[{x:-2*r/6,y:0},{x:s-r/6,y:0},{x:s+2*r/6,y:-r},{x:r/6,y:-r}],i=D(c,s,r,a);return i.attr("style",t.style),w(t,i),t.intersect=function(n){return u.polygon(t,a,n)},c},"lean_right"),_t=o(async(l,t)=>{const{shapeSvg:c,bbox:e}=await _(l,t,I(t,void 0),!0),s=e.width+t.padding,r=e.height+t.padding,a=[{x:2*r/6,y:0},{x:s+r/6,y:0},{x:s-2*r/6,y:-r},{x:-r/6,y:-r}],i=D(c,s,r,a);return i.attr("style",t.style),w(t,i),t.intersect=function(n){return u.polygon(t,a,n)},c},"lean_left"),Bt=o(async(l,t)=>{const{shapeSvg:c,bbox:e}=await _(l,t,I(t,void 0),!0),s=e.width+t.padding,r=e.height+t.padding,a=[{x:-2*r/6,y:0},{x:s+2*r/6,y:0},{x:s-r/6,y:-r},{x:r/6,y:-r}],i=D(c,s,r,a);return i.attr("style",t.style),w(t,i),t.intersect=function(n){return u.polygon(t,a,n)},c},"trapezoid"),Ct=o(async(l,t)=>{const{shapeSvg:c,bbox:e}=await _(l,t,I(t,void 0),!0),s=e.width+t.padding,r=e.height+t.padding,a=[{x:r/6,y:0},{x:s-r/6,y:0},{x:s+2*r/6,y:-r},{x:-2*r/6,y:-r}],i=D(c,s,r,a);return i.attr("style",t.style),w(t,i),t.intersect=function(n){return u.polygon(t,a,n)},c},"inv_trapezoid"),Tt=o(async(l,t)=>{const{shapeSvg:c,bbox:e}=await _(l,t,I(t,void 0),!0),s=e.width+t.padding,r=e.height+t.padding,a=[{x:0,y:0},{x:s+r/2,y:0},{x:s,y:-r/2},{x:s+r/2,y:-r},{x:0,y:-r}],i=D(c,s,r,a);return i.attr("style",t.style),w(t,i),t.intersect=function(n){return u.polygon(t,a,n)},c},"rect_right_inv_arrow"),kt=o(async(l,t)=>{const{shapeSvg:c,bbox:e}=await _(l,t,I(t,void 0),!0),s=e.width+t.padding,r=s/2,a=r/(2.5+s/50),i=e.height+a+t.padding,n="M 0,"+a+" a "+r+","+a+" 0,0,0 "+s+" 0 a "+r+","+a+" 0,0,0 "+-s+" 0 l 0,"+i+" a "+r+","+a+" 0,0,0 "+s+" 0 l 0,"+-i,y=c.attr("label-offset-y",a).insert("path",":first-child").attr("style",t.style).attr("d",n).attr("transform","translate("+-s/2+","+-(i/2+a)+")");return w(t,y),t.intersect=function(h){const x=u.rect(t,h),f=x.x-t.x;if(r!=0&&(Math.abs(f)t.height/2-a)){let g=a*a*(1-f*f/(r*r));g!=0&&(g=Math.sqrt(g)),g=a-g,h.y-t.y>0&&(g=-g),x.y+=g}return x},c},"cylinder"),Nt=o(async(l,t)=>{const{shapeSvg:c,bbox:e,halfPadding:s}=await _(l,t,"node "+t.classes+" "+t.class,!0),r=c.insert("rect",":first-child"),a=t.positioned?t.width:e.width+t.padding,i=t.positioned?t.height:e.height+t.padding,n=t.positioned?-a/2:-e.width/2-s,y=t.positioned?-i/2:-e.height/2-s;if(r.attr("class","basic label-container").attr("style",t.style).attr("rx",t.rx).attr("ry",t.ry).attr("x",n).attr("y",y).attr("width",a).attr("height",i),t.props){const h=new Set(Object.keys(t.props));t.props.borders&&(O(r,t.props.borders,a,i),h.delete("borders")),h.forEach(x=>{L.warn(`Unknown node property ${x}`)})}return w(t,r),t.intersect=function(h){return u.rect(t,h)},c},"rect"),It=o(async(l,t)=>{const{shapeSvg:c,bbox:e,halfPadding:s}=await _(l,t,"node "+t.classes,!0),r=c.insert("rect",":first-child"),a=t.positioned?t.width:e.width+t.padding,i=t.positioned?t.height:e.height+t.padding,n=t.positioned?-a/2:-e.width/2-s,y=t.positioned?-i/2:-e.height/2-s;if(r.attr("class","basic cluster composite label-container").attr("style",t.style).attr("rx",t.rx).attr("ry",t.ry).attr("x",n).attr("y",y).attr("width",a).attr("height",i),t.props){const h=new Set(Object.keys(t.props));t.props.borders&&(O(r,t.props.borders,a,i),h.delete("borders")),h.forEach(x=>{L.warn(`Unknown node property ${x}`)})}return w(t,r),t.intersect=function(h){return u.rect(t,h)},c},"composite"),Dt=o(async(l,t)=>{const{shapeSvg:c}=await _(l,t,"label",!0);L.trace("Classes = ",t.class);const e=c.insert("rect",":first-child"),s=0,r=0;if(e.attr("width",s).attr("height",r),c.attr("class","label edgeLabel"),t.props){const a=new Set(Object.keys(t.props));t.props.borders&&(O(e,t.props.borders,s,r),a.delete("borders")),a.forEach(i=>{L.warn(`Unknown node property ${i}`)})}return w(t,e),t.intersect=function(a){return u.rect(t,a)},c},"labelRect");function O(l,t,c,e){const s=[],r=o(i=>{s.push(i,0)},"addBorder"),a=o(i=>{s.push(0,i)},"skipBorder");t.includes("t")?(L.debug("add top border"),r(c)):a(c),t.includes("r")?(L.debug("add right border"),r(e)):a(e),t.includes("b")?(L.debug("add bottom border"),r(c)):a(c),t.includes("l")?(L.debug("add left border"),r(e)):a(e),l.attr("stroke-dasharray",s.join(" "))}o(O,"applyNodePropertyBorders");var Et=o((l,t)=>{let c;t.classes?c="node "+t.classes:c="node default";const e=l.insert("g").attr("class",c).attr("id",t.domId||t.id),s=e.insert("rect",":first-child"),r=e.insert("line"),a=e.insert("g").attr("class","label"),i=t.labelText.flat?t.labelText.flat():t.labelText;let n="";typeof i=="object"?n=i[0]:n=i,L.info("Label text abc79",n,i,typeof i=="object");const y=a.node().appendChild(R(n,t.labelStyle,!0,!0));let h={width:0,height:0};if(A(N().flowchart.htmlLabels)){const m=y.children[0],p=T(y);h=m.getBoundingClientRect(),p.attr("width",h.width),p.attr("height",h.height)}L.info("Text 2",i);const x=i.slice(1,i.length);let f=y.getBBox();const g=a.node().appendChild(R(x.join?x.join("
                                      "):x,t.labelStyle,!0,!0));if(A(N().flowchart.htmlLabels)){const m=g.children[0],p=T(g);h=m.getBoundingClientRect(),p.attr("width",h.width),p.attr("height",h.height)}const d=t.padding/2;return T(g).attr("transform","translate( "+(h.width>f.width?0:(f.width-h.width)/2)+", "+(f.height+d+5)+")"),T(y).attr("transform","translate( "+(h.width{const{shapeSvg:c,bbox:e}=await _(l,t,I(t,void 0),!0),s=e.height+t.padding,r=e.width+s/4+t.padding,a=c.insert("rect",":first-child").attr("style",t.style).attr("rx",s/2).attr("ry",s/2).attr("x",-r/2).attr("y",-s/2).attr("width",r).attr("height",s);return w(t,a),t.intersect=function(i){return u.rect(t,i)},c},"stadium"),At=o(async(l,t)=>{const{shapeSvg:c,bbox:e,halfPadding:s}=await _(l,t,I(t,void 0),!0),r=c.insert("circle",":first-child");return r.attr("style",t.style).attr("rx",t.rx).attr("ry",t.ry).attr("r",e.width/2+s).attr("width",e.width+t.padding).attr("height",e.height+t.padding),L.info("Circle main"),w(t,r),t.intersect=function(a){return L.info("Circle intersect",t,e.width/2+s,a),u.circle(t,e.width/2+s,a)},c},"circle"),jt=o(async(l,t)=>{const{shapeSvg:c,bbox:e,halfPadding:s}=await _(l,t,I(t,void 0),!0),r=5,a=c.insert("g",":first-child"),i=a.insert("circle"),n=a.insert("circle");return a.attr("class",t.class),i.attr("style",t.style).attr("rx",t.rx).attr("ry",t.ry).attr("r",e.width/2+s+r).attr("width",e.width+t.padding+r*2).attr("height",e.height+t.padding+r*2),n.attr("style",t.style).attr("rx",t.rx).attr("ry",t.ry).attr("r",e.width/2+s).attr("width",e.width+t.padding).attr("height",e.height+t.padding),L.info("DoubleCircle main"),w(t,i),t.intersect=function(y){return L.info("DoubleCircle intersect",t,e.width/2+s+r,y),u.circle(t,e.width/2+s+r,y)},c},"doublecircle"),Pt=o(async(l,t)=>{const{shapeSvg:c,bbox:e}=await _(l,t,I(t,void 0),!0),s=e.width+t.padding,r=e.height+t.padding,a=[{x:0,y:0},{x:s,y:0},{x:s,y:-r},{x:0,y:-r},{x:0,y:0},{x:-8,y:0},{x:s+8,y:0},{x:s+8,y:-r},{x:-8,y:-r},{x:-8,y:0}],i=D(c,s,r,a);return i.attr("style",t.style),w(t,i),t.intersect=function(n){return u.polygon(t,a,n)},c},"subroutine"),Rt=o((l,t)=>{const c=l.insert("g").attr("class","node default").attr("id",t.domId||t.id),e=c.insert("circle",":first-child");return e.attr("class","state-start").attr("r",7).attr("width",14).attr("height",14),w(t,e),t.intersect=function(s){return u.circle(t,7,s)},c},"start"),Q=o((l,t,c)=>{const e=l.insert("g").attr("class","node default").attr("id",t.domId||t.id);let s=70,r=10;c==="LR"&&(s=10,r=70);const a=e.append("rect").attr("x",-1*s/2).attr("y",-1*r/2).attr("width",s).attr("height",r).attr("class","fork-join");return w(t,a),t.height=t.height+t.padding/2,t.width=t.width+t.padding/2,t.intersect=function(i){return u.rect(t,i)},e},"forkJoin"),Ht=o((l,t)=>{const c=l.insert("g").attr("class","node default").attr("id",t.domId||t.id),e=c.insert("circle",":first-child"),s=c.insert("circle",":first-child");return s.attr("class","state-start").attr("r",7).attr("width",14).attr("height",14),e.attr("class","state-end").attr("r",5).attr("width",10).attr("height",10),w(t,s),t.intersect=function(r){return u.circle(t,7,r)},c},"end"),zt=o((l,t)=>{var Y;const c=t.padding/2,e=4,s=8;let r;t.classes?r="node "+t.classes:r="node default";const a=l.insert("g").attr("class",r).attr("id",t.domId||t.id),i=a.insert("rect",":first-child"),n=a.insert("line"),y=a.insert("line");let h=0,x=e;const f=a.insert("g").attr("class","label");let g=0;const d=(Y=t.classData.annotations)==null?void 0:Y[0],m=t.classData.annotations[0]?"«"+t.classData.annotations[0]+"»":"",p=f.node().appendChild(R(m,t.labelStyle,!0,!0));let C=p.getBBox();if(A(N().flowchart.htmlLabels)){const b=p.children[0],v=T(p);C=b.getBoundingClientRect(),v.attr("width",C.width),v.attr("height",C.height)}t.classData.annotations[0]&&(x+=C.height+e,h+=C.width);let S=t.classData.label;t.classData.type!==void 0&&t.classData.type!==""&&(N().flowchart.htmlLabels?S+="<"+t.classData.type+">":S+="<"+t.classData.type+">");const E=f.node().appendChild(R(S,t.labelStyle,!0,!0));T(E).attr("class","classTitle");let B=E.getBBox();if(A(N().flowchart.htmlLabels)){const b=E.children[0],v=T(E);B=b.getBoundingClientRect(),v.attr("width",B.width),v.attr("height",B.height)}x+=B.height+e,B.width>h&&(h=B.width);const j=[];t.classData.members.forEach(b=>{const v=b.getDisplayDetails();let P=v.displayText;N().flowchart.htmlLabels&&(P=P.replace(//g,">"));const M=f.node().appendChild(R(P,v.cssStyle?v.cssStyle:t.labelStyle,!0,!0));let k=M.getBBox();if(A(N().flowchart.htmlLabels)){const $=M.children[0],z=T(M);k=$.getBoundingClientRect(),z.attr("width",k.width),z.attr("height",k.height)}k.width>h&&(h=k.width),x+=k.height+e,j.push(M)}),x+=s;const W=[];if(t.classData.methods.forEach(b=>{const v=b.getDisplayDetails();let P=v.displayText;N().flowchart.htmlLabels&&(P=P.replace(//g,">"));const M=f.node().appendChild(R(P,v.cssStyle?v.cssStyle:t.labelStyle,!0,!0));let k=M.getBBox();if(A(N().flowchart.htmlLabels)){const $=M.children[0],z=T(M);k=$.getBoundingClientRect(),z.attr("width",k.width),z.attr("height",k.height)}k.width>h&&(h=k.width),x+=k.height+e,W.push(M)}),x+=s,d){let b=(h-C.width)/2;T(p).attr("transform","translate( "+(-1*h/2+b)+", "+-1*x/2+")"),g=C.height+e}let F=(h-B.width)/2;return T(E).attr("transform","translate( "+(-1*h/2+F)+", "+(-1*x/2+g)+")"),g+=B.height+e,n.attr("class","divider").attr("x1",-h/2-c).attr("x2",h/2+c).attr("y1",-x/2-c+s+g).attr("y2",-x/2-c+s+g),g+=s,j.forEach(b=>{T(b).attr("transform","translate( "+-h/2+", "+(-1*x/2+g+s/2)+")");const v=b==null?void 0:b.getBBox();g+=((v==null?void 0:v.height)??0)+e}),g+=s,y.attr("class","divider").attr("x1",-h/2-c).attr("x2",h/2+c).attr("y1",-x/2-c+s+g).attr("y2",-x/2-c+s+g),g+=s,W.forEach(b=>{T(b).attr("transform","translate( "+-h/2+", "+(-1*x/2+g)+")");const v=b==null?void 0:b.getBBox();g+=((v==null?void 0:v.height)??0)+e}),i.attr("style",t.style).attr("class","outer title-state").attr("x",-h/2-c).attr("y",-(x/2)-c).attr("width",h+t.padding).attr("height",x+t.padding),w(t,i),t.intersect=function(b){return u.rect(t,b)},a},"class_box"),q={rhombus:G,composite:It,question:G,rect:Nt,labelRect:Dt,rectWithTitle:Et,choice:bt,circle:At,doublecircle:jt,stadium:Mt,hexagon:vt,block_arrow:mt,rect_left_inv_arrow:St,lean_right:Lt,lean_left:_t,trapezoid:Bt,inv_trapezoid:Ct,rect_right_inv_arrow:Tt,cylinder:kt,start:Rt,end:Ht,note:wt,subroutine:Pt,fork:Q,join:Q,class_box:zt},H={},Ot=o(async(l,t,c)=>{let e,s;if(t.link){let r;N().securityLevel==="sandbox"?r="_top":t.linkTarget&&(r=t.linkTarget||"_blank"),e=l.insert("svg:a").attr("xlink:href",t.link).attr("target",r),s=await q[t.shape](e,t,c)}else s=await q[t.shape](l,t,c),e=s;return t.tooltip&&s.attr("title",t.tooltip),t.class&&s.attr("class","node default "+t.class),H[t.id]=e,t.haveCallback&&H[t.id].attr("class",H[t.id].attr("class")+" clickable"),e},"insertNode"),Wt=o((l,t)=>{H[t.id]=l},"setNodeElem"),$t=o(()=>{H={}},"clear"),Xt=o(l=>{const t=H[l.id];L.trace("Transforming node",l.diff,l,"translate("+(l.x-l.width/2-5)+", "+l.width/2+")");const c=8,e=l.diff||0;return l.clusterNode?t.attr("transform","translate("+(l.x+e-l.width/2)+", "+(l.y-l.height/2-c)+")"):t.attr("transform","translate("+l.x+", "+l.y+")"),e},"positionNode");export{R as a,pt as b,$t as c,Ot as i,Xt as p,Wt as s,w as u}; +import{_ as o,j as T,l as L,d as N,A,B as ct,C as X,D as lt,i as J}from"./mermaid.core-D8igZDel.js";function K(l,t){t&&l.attr("style",t)}o(K,"applyStyle");function Z(l){const t=T(document.createElementNS("http://www.w3.org/2000/svg","foreignObject")),c=t.append("xhtml:div"),e=l.label,s=l.isNode?"nodeLabel":"edgeLabel",r=c.append("span");return r.html(e),K(r,l.labelStyle),r.attr("class",s),K(c,l.labelStyle),c.style("display","inline-block"),c.style("white-space","nowrap"),c.attr("xmlns","http://www.w3.org/1999/xhtml"),t.node()}o(Z,"addHtmlLabel");var nt=o((l,t,c,e)=>{let s=l||"";if(typeof s=="object"&&(s=s[0]),A(N().flowchart.htmlLabels)){s=s.replace(/\\n|\n/g,"
                                      "),L.debug("vertexText"+s);const r={isNode:e,label:ct(X(s)),labelStyle:t.replace("fill:","color:")};return Z(r)}else{const r=document.createElementNS("http://www.w3.org/2000/svg","text");r.setAttribute("style",t.replace("color:","fill:"));let a=[];typeof s=="string"?a=s.split(/\\n|\n|/gi):Array.isArray(s)?a=s:a=[];for(const i of a){const n=document.createElementNS("http://www.w3.org/2000/svg","tspan");n.setAttributeNS("http://www.w3.org/XML/1998/namespace","xml:space","preserve"),n.setAttribute("dy","1em"),n.setAttribute("x","0"),c?n.setAttribute("class","title-row"):n.setAttribute("class","row"),n.textContent=i.trim(),r.appendChild(n)}return r}},"createLabel"),R=nt,_=o(async(l,t,c,e)=>{const s=N();let r;const a=t.useHtmlLabels||A(s.flowchart.htmlLabels);c?r=c:r="node default";const i=l.insert("g").attr("class",r).attr("id",t.domId||t.id),n=i.insert("g").attr("class","label").attr("style",t.labelStyle);let y;t.labelText===void 0?y="":y=typeof t.labelText=="string"?t.labelText:t.labelText[0];const h=n.node();let x;t.labelType==="markdown"?x=lt(n,J(X(y),s),{useHtmlLabels:a,width:t.width||s.flowchart.wrappingWidth,classes:"markdown-node-label"},s):x=h.appendChild(R(J(X(y),s),t.labelStyle,!1,e));let f=x.getBBox();const g=t.padding/2;if(A(s.flowchart.htmlLabels)){const d=x.children[0],m=T(x),p=d.getElementsByTagName("img");if(p){const C=y.replace(/]*>/g,"").trim()==="";await Promise.all([...p].map(S=>new Promise(E=>{function B(){if(S.style.display="flex",S.style.flexDirection="column",C){const j=s.fontSize?s.fontSize:window.getComputedStyle(document.body).fontSize,F=parseInt(j,10)*5+"px";S.style.minWidth=F,S.style.maxWidth=F}else S.style.width="100%";E(S)}o(B,"setupImage"),setTimeout(()=>{S.complete&&B()}),S.addEventListener("error",B),S.addEventListener("load",B)})))}f=d.getBoundingClientRect(),m.attr("width",f.width),m.attr("height",f.height)}return a?n.attr("transform","translate("+-f.width/2+", "+-f.height/2+")"):n.attr("transform","translate(0, "+-f.height/2+")"),t.centerLabel&&n.attr("transform","translate("+-f.width/2+", "+-f.height/2+")"),n.insert("rect",":first-child"),{shapeSvg:i,bbox:f,halfPadding:g,label:n}},"labelHelper"),w=o((l,t)=>{const c=t.node().getBBox();l.width=c.width,l.height=c.height},"updateNodeBounds");function D(l,t,c,e){return l.insert("polygon",":first-child").attr("points",e.map(function(s){return s.x+","+s.y}).join(" ")).attr("class","label-container").attr("transform","translate("+-t/2+","+c/2+")")}o(D,"insertPolygonShape");var ht=o(l=>{const t=new Set;for(const c of l)switch(c){case"x":t.add("right"),t.add("left");break;case"y":t.add("up"),t.add("down");break;default:t.add(c);break}return t},"expandAndDeduplicateDirections"),ot=o((l,t,c)=>{const e=ht(l),s=2,r=t.height+2*c.padding,a=r/s,i=t.width+2*a+c.padding,n=c.padding/2;return e.has("right")&&e.has("left")&&e.has("up")&&e.has("down")?[{x:0,y:0},{x:a,y:0},{x:i/2,y:2*n},{x:i-a,y:0},{x:i,y:0},{x:i,y:-r/3},{x:i+2*n,y:-r/2},{x:i,y:-2*r/3},{x:i,y:-r},{x:i-a,y:-r},{x:i/2,y:-r-2*n},{x:a,y:-r},{x:0,y:-r},{x:0,y:-2*r/3},{x:-2*n,y:-r/2},{x:0,y:-r/3}]:e.has("right")&&e.has("left")&&e.has("up")?[{x:a,y:0},{x:i-a,y:0},{x:i,y:-r/2},{x:i-a,y:-r},{x:a,y:-r},{x:0,y:-r/2}]:e.has("right")&&e.has("left")&&e.has("down")?[{x:0,y:0},{x:a,y:-r},{x:i-a,y:-r},{x:i,y:0}]:e.has("right")&&e.has("up")&&e.has("down")?[{x:0,y:0},{x:i,y:-a},{x:i,y:-r+a},{x:0,y:-r}]:e.has("left")&&e.has("up")&&e.has("down")?[{x:i,y:0},{x:0,y:-a},{x:0,y:-r+a},{x:i,y:-r}]:e.has("right")&&e.has("left")?[{x:a,y:0},{x:a,y:-n},{x:i-a,y:-n},{x:i-a,y:0},{x:i,y:-r/2},{x:i-a,y:-r},{x:i-a,y:-r+n},{x:a,y:-r+n},{x:a,y:-r},{x:0,y:-r/2}]:e.has("up")&&e.has("down")?[{x:i/2,y:0},{x:0,y:-n},{x:a,y:-n},{x:a,y:-r+n},{x:0,y:-r+n},{x:i/2,y:-r},{x:i,y:-r+n},{x:i-a,y:-r+n},{x:i-a,y:-n},{x:i,y:-n}]:e.has("right")&&e.has("up")?[{x:0,y:0},{x:i,y:-a},{x:0,y:-r}]:e.has("right")&&e.has("down")?[{x:0,y:0},{x:i,y:0},{x:0,y:-r}]:e.has("left")&&e.has("up")?[{x:i,y:0},{x:0,y:-a},{x:i,y:-r}]:e.has("left")&&e.has("down")?[{x:i,y:0},{x:0,y:0},{x:i,y:-r}]:e.has("right")?[{x:a,y:-n},{x:a,y:-n},{x:i-a,y:-n},{x:i-a,y:0},{x:i,y:-r/2},{x:i-a,y:-r},{x:i-a,y:-r+n},{x:a,y:-r+n},{x:a,y:-r+n}]:e.has("left")?[{x:a,y:0},{x:a,y:-n},{x:i-a,y:-n},{x:i-a,y:-r+n},{x:a,y:-r+n},{x:a,y:-r},{x:0,y:-r/2}]:e.has("up")?[{x:a,y:-n},{x:a,y:-r+n},{x:0,y:-r+n},{x:i/2,y:-r},{x:i,y:-r+n},{x:i-a,y:-r+n},{x:i-a,y:-n}]:e.has("down")?[{x:i/2,y:0},{x:0,y:-n},{x:a,y:-n},{x:a,y:-r+n},{x:i-a,y:-r+n},{x:i-a,y:-n},{x:i,y:-n}]:[{x:0,y:0}]},"getArrowPoints");function tt(l,t){return l.intersect(t)}o(tt,"intersectNode");var yt=tt;function rt(l,t,c,e){var s=l.x,r=l.y,a=s-e.x,i=r-e.y,n=Math.sqrt(t*t*i*i+c*c*a*a),y=Math.abs(t*c*a/n);e.x0}o(U,"sameSign");var gt=st,ft=it;function it(l,t,c){var e=l.x,s=l.y,r=[],a=Number.POSITIVE_INFINITY,i=Number.POSITIVE_INFINITY;typeof t.forEach=="function"?t.forEach(function(d){a=Math.min(a,d.x),i=Math.min(i,d.y)}):(a=Math.min(a,t.x),i=Math.min(i,t.y));for(var n=e-l.width/2-a,y=s-l.height/2-i,h=0;h1&&r.sort(function(d,m){var p=d.x-c.x,C=d.y-c.y,S=Math.sqrt(p*p+C*C),E=m.x-c.x,B=m.y-c.y,j=Math.sqrt(E*E+B*B);return S{var c=l.x,e=l.y,s=t.x-c,r=t.y-e,a=l.width/2,i=l.height/2,n,y;return Math.abs(r)*a>Math.abs(s)*i?(r<0&&(i=-i),n=r===0?0:i*s/r,y=i):(s<0&&(a=-a),n=a,y=s===0?0:a*r/s),{x:c+n,y:e+y}},"intersectRect"),pt=dt,u={node:yt,circle:xt,ellipse:at,polygon:ft,rect:pt},ut=o(async(l,t)=>{t.useHtmlLabels||N().flowchart.htmlLabels||(t.centerLabel=!0);const{shapeSvg:e,bbox:s,halfPadding:r}=await _(l,t,"node "+t.classes,!0);L.info("Classes = ",t.classes);const a=e.insert("rect",":first-child");return a.attr("rx",t.rx).attr("ry",t.ry).attr("x",-s.width/2-r).attr("y",-s.height/2-r).attr("width",s.width+t.padding).attr("height",s.height+t.padding),w(t,a),t.intersect=function(i){return u.rect(t,i)},e},"note"),wt=ut,V=o(l=>l?" "+l:"","formatClass"),I=o((l,t)=>`${t||"node default"}${V(l.classes)} ${V(l.class)}`,"getClassesFromNode"),G=o(async(l,t)=>{const{shapeSvg:c,bbox:e}=await _(l,t,I(t,void 0),!0),s=e.width+t.padding,r=e.height+t.padding,a=s+r,i=[{x:a/2,y:0},{x:a,y:-a/2},{x:a/2,y:-a},{x:0,y:-a/2}];L.info("Question main (Circle)");const n=D(c,a,a,i);return n.attr("style",t.style),w(t,n),t.intersect=function(y){return L.warn("Intersect called"),u.polygon(t,i,y)},c},"question"),bt=o((l,t)=>{const c=l.insert("g").attr("class","node default").attr("id",t.domId||t.id),e=28,s=[{x:0,y:e/2},{x:e/2,y:0},{x:0,y:-e/2},{x:-e/2,y:0}];return c.insert("polygon",":first-child").attr("points",s.map(function(a){return a.x+","+a.y}).join(" ")).attr("class","state-start").attr("r",7).attr("width",28).attr("height",28),t.width=28,t.height=28,t.intersect=function(a){return u.circle(t,14,a)},c},"choice"),vt=o(async(l,t)=>{const{shapeSvg:c,bbox:e}=await _(l,t,I(t,void 0),!0),s=4,r=e.height+t.padding,a=r/s,i=e.width+2*a+t.padding,n=[{x:a,y:0},{x:i-a,y:0},{x:i,y:-r/2},{x:i-a,y:-r},{x:a,y:-r},{x:0,y:-r/2}],y=D(c,i,r,n);return y.attr("style",t.style),w(t,y),t.intersect=function(h){return u.polygon(t,n,h)},c},"hexagon"),mt=o(async(l,t)=>{const{shapeSvg:c,bbox:e}=await _(l,t,void 0,!0),s=2,r=e.height+2*t.padding,a=r/s,i=e.width+2*a+t.padding,n=ot(t.directions,e,t),y=D(c,i,r,n);return y.attr("style",t.style),w(t,y),t.intersect=function(h){return u.polygon(t,n,h)},c},"block_arrow"),St=o(async(l,t)=>{const{shapeSvg:c,bbox:e}=await _(l,t,I(t,void 0),!0),s=e.width+t.padding,r=e.height+t.padding,a=[{x:-r/2,y:0},{x:s,y:0},{x:s,y:-r},{x:-r/2,y:-r},{x:0,y:-r/2}];return D(c,s,r,a).attr("style",t.style),t.width=s+r,t.height=r,t.intersect=function(n){return u.polygon(t,a,n)},c},"rect_left_inv_arrow"),Lt=o(async(l,t)=>{const{shapeSvg:c,bbox:e}=await _(l,t,I(t),!0),s=e.width+t.padding,r=e.height+t.padding,a=[{x:-2*r/6,y:0},{x:s-r/6,y:0},{x:s+2*r/6,y:-r},{x:r/6,y:-r}],i=D(c,s,r,a);return i.attr("style",t.style),w(t,i),t.intersect=function(n){return u.polygon(t,a,n)},c},"lean_right"),_t=o(async(l,t)=>{const{shapeSvg:c,bbox:e}=await _(l,t,I(t,void 0),!0),s=e.width+t.padding,r=e.height+t.padding,a=[{x:2*r/6,y:0},{x:s+r/6,y:0},{x:s-2*r/6,y:-r},{x:-r/6,y:-r}],i=D(c,s,r,a);return i.attr("style",t.style),w(t,i),t.intersect=function(n){return u.polygon(t,a,n)},c},"lean_left"),Bt=o(async(l,t)=>{const{shapeSvg:c,bbox:e}=await _(l,t,I(t,void 0),!0),s=e.width+t.padding,r=e.height+t.padding,a=[{x:-2*r/6,y:0},{x:s+2*r/6,y:0},{x:s-r/6,y:-r},{x:r/6,y:-r}],i=D(c,s,r,a);return i.attr("style",t.style),w(t,i),t.intersect=function(n){return u.polygon(t,a,n)},c},"trapezoid"),Ct=o(async(l,t)=>{const{shapeSvg:c,bbox:e}=await _(l,t,I(t,void 0),!0),s=e.width+t.padding,r=e.height+t.padding,a=[{x:r/6,y:0},{x:s-r/6,y:0},{x:s+2*r/6,y:-r},{x:-2*r/6,y:-r}],i=D(c,s,r,a);return i.attr("style",t.style),w(t,i),t.intersect=function(n){return u.polygon(t,a,n)},c},"inv_trapezoid"),Tt=o(async(l,t)=>{const{shapeSvg:c,bbox:e}=await _(l,t,I(t,void 0),!0),s=e.width+t.padding,r=e.height+t.padding,a=[{x:0,y:0},{x:s+r/2,y:0},{x:s,y:-r/2},{x:s+r/2,y:-r},{x:0,y:-r}],i=D(c,s,r,a);return i.attr("style",t.style),w(t,i),t.intersect=function(n){return u.polygon(t,a,n)},c},"rect_right_inv_arrow"),kt=o(async(l,t)=>{const{shapeSvg:c,bbox:e}=await _(l,t,I(t,void 0),!0),s=e.width+t.padding,r=s/2,a=r/(2.5+s/50),i=e.height+a+t.padding,n="M 0,"+a+" a "+r+","+a+" 0,0,0 "+s+" 0 a "+r+","+a+" 0,0,0 "+-s+" 0 l 0,"+i+" a "+r+","+a+" 0,0,0 "+s+" 0 l 0,"+-i,y=c.attr("label-offset-y",a).insert("path",":first-child").attr("style",t.style).attr("d",n).attr("transform","translate("+-s/2+","+-(i/2+a)+")");return w(t,y),t.intersect=function(h){const x=u.rect(t,h),f=x.x-t.x;if(r!=0&&(Math.abs(f)t.height/2-a)){let g=a*a*(1-f*f/(r*r));g!=0&&(g=Math.sqrt(g)),g=a-g,h.y-t.y>0&&(g=-g),x.y+=g}return x},c},"cylinder"),Nt=o(async(l,t)=>{const{shapeSvg:c,bbox:e,halfPadding:s}=await _(l,t,"node "+t.classes+" "+t.class,!0),r=c.insert("rect",":first-child"),a=t.positioned?t.width:e.width+t.padding,i=t.positioned?t.height:e.height+t.padding,n=t.positioned?-a/2:-e.width/2-s,y=t.positioned?-i/2:-e.height/2-s;if(r.attr("class","basic label-container").attr("style",t.style).attr("rx",t.rx).attr("ry",t.ry).attr("x",n).attr("y",y).attr("width",a).attr("height",i),t.props){const h=new Set(Object.keys(t.props));t.props.borders&&(O(r,t.props.borders,a,i),h.delete("borders")),h.forEach(x=>{L.warn(`Unknown node property ${x}`)})}return w(t,r),t.intersect=function(h){return u.rect(t,h)},c},"rect"),It=o(async(l,t)=>{const{shapeSvg:c,bbox:e,halfPadding:s}=await _(l,t,"node "+t.classes,!0),r=c.insert("rect",":first-child"),a=t.positioned?t.width:e.width+t.padding,i=t.positioned?t.height:e.height+t.padding,n=t.positioned?-a/2:-e.width/2-s,y=t.positioned?-i/2:-e.height/2-s;if(r.attr("class","basic cluster composite label-container").attr("style",t.style).attr("rx",t.rx).attr("ry",t.ry).attr("x",n).attr("y",y).attr("width",a).attr("height",i),t.props){const h=new Set(Object.keys(t.props));t.props.borders&&(O(r,t.props.borders,a,i),h.delete("borders")),h.forEach(x=>{L.warn(`Unknown node property ${x}`)})}return w(t,r),t.intersect=function(h){return u.rect(t,h)},c},"composite"),Dt=o(async(l,t)=>{const{shapeSvg:c}=await _(l,t,"label",!0);L.trace("Classes = ",t.class);const e=c.insert("rect",":first-child"),s=0,r=0;if(e.attr("width",s).attr("height",r),c.attr("class","label edgeLabel"),t.props){const a=new Set(Object.keys(t.props));t.props.borders&&(O(e,t.props.borders,s,r),a.delete("borders")),a.forEach(i=>{L.warn(`Unknown node property ${i}`)})}return w(t,e),t.intersect=function(a){return u.rect(t,a)},c},"labelRect");function O(l,t,c,e){const s=[],r=o(i=>{s.push(i,0)},"addBorder"),a=o(i=>{s.push(0,i)},"skipBorder");t.includes("t")?(L.debug("add top border"),r(c)):a(c),t.includes("r")?(L.debug("add right border"),r(e)):a(e),t.includes("b")?(L.debug("add bottom border"),r(c)):a(c),t.includes("l")?(L.debug("add left border"),r(e)):a(e),l.attr("stroke-dasharray",s.join(" "))}o(O,"applyNodePropertyBorders");var Et=o((l,t)=>{let c;t.classes?c="node "+t.classes:c="node default";const e=l.insert("g").attr("class",c).attr("id",t.domId||t.id),s=e.insert("rect",":first-child"),r=e.insert("line"),a=e.insert("g").attr("class","label"),i=t.labelText.flat?t.labelText.flat():t.labelText;let n="";typeof i=="object"?n=i[0]:n=i,L.info("Label text abc79",n,i,typeof i=="object");const y=a.node().appendChild(R(n,t.labelStyle,!0,!0));let h={width:0,height:0};if(A(N().flowchart.htmlLabels)){const m=y.children[0],p=T(y);h=m.getBoundingClientRect(),p.attr("width",h.width),p.attr("height",h.height)}L.info("Text 2",i);const x=i.slice(1,i.length);let f=y.getBBox();const g=a.node().appendChild(R(x.join?x.join("
                                      "):x,t.labelStyle,!0,!0));if(A(N().flowchart.htmlLabels)){const m=g.children[0],p=T(g);h=m.getBoundingClientRect(),p.attr("width",h.width),p.attr("height",h.height)}const d=t.padding/2;return T(g).attr("transform","translate( "+(h.width>f.width?0:(f.width-h.width)/2)+", "+(f.height+d+5)+")"),T(y).attr("transform","translate( "+(h.width{const{shapeSvg:c,bbox:e}=await _(l,t,I(t,void 0),!0),s=e.height+t.padding,r=e.width+s/4+t.padding,a=c.insert("rect",":first-child").attr("style",t.style).attr("rx",s/2).attr("ry",s/2).attr("x",-r/2).attr("y",-s/2).attr("width",r).attr("height",s);return w(t,a),t.intersect=function(i){return u.rect(t,i)},c},"stadium"),At=o(async(l,t)=>{const{shapeSvg:c,bbox:e,halfPadding:s}=await _(l,t,I(t,void 0),!0),r=c.insert("circle",":first-child");return r.attr("style",t.style).attr("rx",t.rx).attr("ry",t.ry).attr("r",e.width/2+s).attr("width",e.width+t.padding).attr("height",e.height+t.padding),L.info("Circle main"),w(t,r),t.intersect=function(a){return L.info("Circle intersect",t,e.width/2+s,a),u.circle(t,e.width/2+s,a)},c},"circle"),jt=o(async(l,t)=>{const{shapeSvg:c,bbox:e,halfPadding:s}=await _(l,t,I(t,void 0),!0),r=5,a=c.insert("g",":first-child"),i=a.insert("circle"),n=a.insert("circle");return a.attr("class",t.class),i.attr("style",t.style).attr("rx",t.rx).attr("ry",t.ry).attr("r",e.width/2+s+r).attr("width",e.width+t.padding+r*2).attr("height",e.height+t.padding+r*2),n.attr("style",t.style).attr("rx",t.rx).attr("ry",t.ry).attr("r",e.width/2+s).attr("width",e.width+t.padding).attr("height",e.height+t.padding),L.info("DoubleCircle main"),w(t,i),t.intersect=function(y){return L.info("DoubleCircle intersect",t,e.width/2+s+r,y),u.circle(t,e.width/2+s+r,y)},c},"doublecircle"),Pt=o(async(l,t)=>{const{shapeSvg:c,bbox:e}=await _(l,t,I(t,void 0),!0),s=e.width+t.padding,r=e.height+t.padding,a=[{x:0,y:0},{x:s,y:0},{x:s,y:-r},{x:0,y:-r},{x:0,y:0},{x:-8,y:0},{x:s+8,y:0},{x:s+8,y:-r},{x:-8,y:-r},{x:-8,y:0}],i=D(c,s,r,a);return i.attr("style",t.style),w(t,i),t.intersect=function(n){return u.polygon(t,a,n)},c},"subroutine"),Rt=o((l,t)=>{const c=l.insert("g").attr("class","node default").attr("id",t.domId||t.id),e=c.insert("circle",":first-child");return e.attr("class","state-start").attr("r",7).attr("width",14).attr("height",14),w(t,e),t.intersect=function(s){return u.circle(t,7,s)},c},"start"),Q=o((l,t,c)=>{const e=l.insert("g").attr("class","node default").attr("id",t.domId||t.id);let s=70,r=10;c==="LR"&&(s=10,r=70);const a=e.append("rect").attr("x",-1*s/2).attr("y",-1*r/2).attr("width",s).attr("height",r).attr("class","fork-join");return w(t,a),t.height=t.height+t.padding/2,t.width=t.width+t.padding/2,t.intersect=function(i){return u.rect(t,i)},e},"forkJoin"),Ht=o((l,t)=>{const c=l.insert("g").attr("class","node default").attr("id",t.domId||t.id),e=c.insert("circle",":first-child"),s=c.insert("circle",":first-child");return s.attr("class","state-start").attr("r",7).attr("width",14).attr("height",14),e.attr("class","state-end").attr("r",5).attr("width",10).attr("height",10),w(t,s),t.intersect=function(r){return u.circle(t,7,r)},c},"end"),zt=o((l,t)=>{var Y;const c=t.padding/2,e=4,s=8;let r;t.classes?r="node "+t.classes:r="node default";const a=l.insert("g").attr("class",r).attr("id",t.domId||t.id),i=a.insert("rect",":first-child"),n=a.insert("line"),y=a.insert("line");let h=0,x=e;const f=a.insert("g").attr("class","label");let g=0;const d=(Y=t.classData.annotations)==null?void 0:Y[0],m=t.classData.annotations[0]?"«"+t.classData.annotations[0]+"»":"",p=f.node().appendChild(R(m,t.labelStyle,!0,!0));let C=p.getBBox();if(A(N().flowchart.htmlLabels)){const b=p.children[0],v=T(p);C=b.getBoundingClientRect(),v.attr("width",C.width),v.attr("height",C.height)}t.classData.annotations[0]&&(x+=C.height+e,h+=C.width);let S=t.classData.label;t.classData.type!==void 0&&t.classData.type!==""&&(N().flowchart.htmlLabels?S+="<"+t.classData.type+">":S+="<"+t.classData.type+">");const E=f.node().appendChild(R(S,t.labelStyle,!0,!0));T(E).attr("class","classTitle");let B=E.getBBox();if(A(N().flowchart.htmlLabels)){const b=E.children[0],v=T(E);B=b.getBoundingClientRect(),v.attr("width",B.width),v.attr("height",B.height)}x+=B.height+e,B.width>h&&(h=B.width);const j=[];t.classData.members.forEach(b=>{const v=b.getDisplayDetails();let P=v.displayText;N().flowchart.htmlLabels&&(P=P.replace(//g,">"));const M=f.node().appendChild(R(P,v.cssStyle?v.cssStyle:t.labelStyle,!0,!0));let k=M.getBBox();if(A(N().flowchart.htmlLabels)){const $=M.children[0],z=T(M);k=$.getBoundingClientRect(),z.attr("width",k.width),z.attr("height",k.height)}k.width>h&&(h=k.width),x+=k.height+e,j.push(M)}),x+=s;const W=[];if(t.classData.methods.forEach(b=>{const v=b.getDisplayDetails();let P=v.displayText;N().flowchart.htmlLabels&&(P=P.replace(//g,">"));const M=f.node().appendChild(R(P,v.cssStyle?v.cssStyle:t.labelStyle,!0,!0));let k=M.getBBox();if(A(N().flowchart.htmlLabels)){const $=M.children[0],z=T(M);k=$.getBoundingClientRect(),z.attr("width",k.width),z.attr("height",k.height)}k.width>h&&(h=k.width),x+=k.height+e,W.push(M)}),x+=s,d){let b=(h-C.width)/2;T(p).attr("transform","translate( "+(-1*h/2+b)+", "+-1*x/2+")"),g=C.height+e}let F=(h-B.width)/2;return T(E).attr("transform","translate( "+(-1*h/2+F)+", "+(-1*x/2+g)+")"),g+=B.height+e,n.attr("class","divider").attr("x1",-h/2-c).attr("x2",h/2+c).attr("y1",-x/2-c+s+g).attr("y2",-x/2-c+s+g),g+=s,j.forEach(b=>{T(b).attr("transform","translate( "+-h/2+", "+(-1*x/2+g+s/2)+")");const v=b==null?void 0:b.getBBox();g+=((v==null?void 0:v.height)??0)+e}),g+=s,y.attr("class","divider").attr("x1",-h/2-c).attr("x2",h/2+c).attr("y1",-x/2-c+s+g).attr("y2",-x/2-c+s+g),g+=s,W.forEach(b=>{T(b).attr("transform","translate( "+-h/2+", "+(-1*x/2+g)+")");const v=b==null?void 0:b.getBBox();g+=((v==null?void 0:v.height)??0)+e}),i.attr("style",t.style).attr("class","outer title-state").attr("x",-h/2-c).attr("y",-(x/2)-c).attr("width",h+t.padding).attr("height",x+t.padding),w(t,i),t.intersect=function(b){return u.rect(t,b)},a},"class_box"),q={rhombus:G,composite:It,question:G,rect:Nt,labelRect:Dt,rectWithTitle:Et,choice:bt,circle:At,doublecircle:jt,stadium:Mt,hexagon:vt,block_arrow:mt,rect_left_inv_arrow:St,lean_right:Lt,lean_left:_t,trapezoid:Bt,inv_trapezoid:Ct,rect_right_inv_arrow:Tt,cylinder:kt,start:Rt,end:Ht,note:wt,subroutine:Pt,fork:Q,join:Q,class_box:zt},H={},Ot=o(async(l,t,c)=>{let e,s;if(t.link){let r;N().securityLevel==="sandbox"?r="_top":t.linkTarget&&(r=t.linkTarget||"_blank"),e=l.insert("svg:a").attr("xlink:href",t.link).attr("target",r),s=await q[t.shape](e,t,c)}else s=await q[t.shape](l,t,c),e=s;return t.tooltip&&s.attr("title",t.tooltip),t.class&&s.attr("class","node default "+t.class),H[t.id]=e,t.haveCallback&&H[t.id].attr("class",H[t.id].attr("class")+" clickable"),e},"insertNode"),Wt=o((l,t)=>{H[t.id]=l},"setNodeElem"),$t=o(()=>{H={}},"clear"),Xt=o(l=>{const t=H[l.id];L.trace("Transforming node",l.diff,l,"translate("+(l.x-l.width/2-5)+", "+l.width/2+")");const c=8,e=l.diff||0;return l.clusterNode?t.attr("transform","translate("+(l.x+e-l.width/2)+", "+(l.y-l.height/2-c)+")"):t.attr("transform","translate("+l.x+", "+l.y+")"),e},"positionNode");export{R as a,pt as b,$t as c,Ot as i,Xt as p,Wt as s,w as u}; diff --git a/assets/classDiagram-MQQPYQM5-D7Ouc99y.js b/assets/classDiagram-MQQPYQM5-p-htZl6Q.js similarity index 96% rename from assets/classDiagram-MQQPYQM5-D7Ouc99y.js rename to assets/classDiagram-MQQPYQM5-p-htZl6Q.js index 00c9577fb2..f33eff2c81 100644 --- a/assets/classDiagram-MQQPYQM5-D7Ouc99y.js +++ b/assets/classDiagram-MQQPYQM5-p-htZl6Q.js @@ -1,2 +1,2 @@ -import{c as G,a as N,s as I}from"./chunk-IBIA4ERB-Cq5yRPLn.js";import{_ as f,d as S,l as u,j as B,k as W,a2 as P,a8 as R,u as _,a9 as X}from"./mermaid.core-DapiNGBY.js";import{G as Y}from"./graph-Oq3lz9SV.js";import{l as $}from"./layout-7AWYeW5Q.js";import"./app-DBM4OJyw.js";import"./baseUniq-ZJgB7efo.js";import"./basePickBy-BXIHjUx3.js";var H=0,J=f(function(i,a,t,o,p){const g=f(function(e){switch(e){case p.db.relationType.AGGREGATION:return"aggregation";case p.db.relationType.EXTENSION:return"extension";case p.db.relationType.COMPOSITION:return"composition";case p.db.relationType.DEPENDENCY:return"dependency";case p.db.relationType.LOLLIPOP:return"lollipop"}},"getRelationType");a.points=a.points.filter(e=>!Number.isNaN(e.y));const s=a.points,c=P().x(function(e){return e.x}).y(function(e){return e.y}).curve(R),n=i.append("path").attr("d",c(s)).attr("id","edge"+H).attr("class","relation");let r="";o.arrowMarkerAbsolute&&(r=window.location.protocol+"//"+window.location.host+window.location.pathname+window.location.search,r=r.replace(/\(/g,"\\("),r=r.replace(/\)/g,"\\)")),t.relation.lineType==1&&n.attr("class","relation dashed-line"),t.relation.lineType==10&&n.attr("class","relation dotted-line"),t.relation.type1!=="none"&&n.attr("marker-start","url("+r+"#"+g(t.relation.type1)+"Start)"),t.relation.type2!=="none"&&n.attr("marker-end","url("+r+"#"+g(t.relation.type2)+"End)");let m,h;const x=a.points.length;let b=_.calcLabelPosition(a.points);m=b.x,h=b.y;let y,w,k,v;if(x%2!==0&&x>1){let e=_.calcCardinalityPosition(t.relation.type1!=="none",a.points,a.points[0]),d=_.calcCardinalityPosition(t.relation.type2!=="none",a.points,a.points[x-1]);u.debug("cardinality_1_point "+JSON.stringify(e)),u.debug("cardinality_2_point "+JSON.stringify(d)),y=e.x,w=e.y,k=d.x,v=d.y}if(t.title!==void 0){const e=i.append("g").attr("class","classLabel"),d=e.append("text").attr("class","label").attr("x",m).attr("y",h).attr("fill","red").attr("text-anchor","middle").text(t.title);window.label=d;const l=d.node().getBBox();e.insert("rect",":first-child").attr("class","box").attr("x",l.x-o.padding/2).attr("y",l.y-o.padding/2).attr("width",l.width+o.padding).attr("height",l.height+o.padding)}u.info("Rendering relation "+JSON.stringify(t)),t.relationTitle1!==void 0&&t.relationTitle1!=="none"&&i.append("g").attr("class","cardinality").append("text").attr("class","type1").attr("x",y).attr("y",w).attr("fill","black").attr("font-size","6").text(t.relationTitle1),t.relationTitle2!==void 0&&t.relationTitle2!=="none"&&i.append("g").attr("class","cardinality").append("text").attr("class","type2").attr("x",k).attr("y",v).attr("fill","black").attr("font-size","6").text(t.relationTitle2),H++},"drawEdge"),O=f(function(i,a,t,o){u.debug("Rendering class ",a,t);const p=a.id,g={id:p,label:a.id,width:0,height:0},s=i.append("g").attr("id",o.db.lookUpDomId(p)).attr("class","classGroup");let c;a.link?c=s.append("svg:a").attr("xlink:href",a.link).attr("target",a.linkTarget).append("text").attr("y",t.textHeight+t.padding).attr("x",0):c=s.append("text").attr("y",t.textHeight+t.padding).attr("x",0);let n=!0;a.annotations.forEach(function(d){const l=c.append("tspan").text("«"+d+"»");n||l.attr("dy",t.textHeight),n=!1});let r=A(a);const m=c.append("tspan").text(r).attr("class","title");n||m.attr("dy",t.textHeight);const h=c.node().getBBox().height;let x,b,y;if(a.members.length>0){x=s.append("line").attr("x1",0).attr("y1",t.padding+h+t.dividerMargin/2).attr("y2",t.padding+h+t.dividerMargin/2);const d=s.append("text").attr("x",t.padding).attr("y",h+t.dividerMargin+t.textHeight).attr("fill","white").attr("class","classText");n=!0,a.members.forEach(function(l){C(d,l,n,t),n=!1}),b=d.node().getBBox()}if(a.methods.length>0){y=s.append("line").attr("x1",0).attr("y1",t.padding+h+t.dividerMargin+b.height).attr("y2",t.padding+h+t.dividerMargin+b.height);const d=s.append("text").attr("x",t.padding).attr("y",h+2*t.dividerMargin+b.height+t.textHeight).attr("fill","white").attr("class","classText");n=!0,a.methods.forEach(function(l){C(d,l,n,t),n=!1})}const w=s.node().getBBox();var k=" ";a.cssClasses.length>0&&(k=k+a.cssClasses.join(" "));const e=s.insert("rect",":first-child").attr("x",0).attr("y",0).attr("width",w.width+2*t.padding).attr("height",w.height+t.padding+.5*t.dividerMargin).attr("class",k).node().getBBox().width;return c.node().childNodes.forEach(function(d){d.setAttribute("x",(e-d.getBBox().width)/2)}),a.tooltip&&c.insert("title").text(a.tooltip),x&&x.attr("x2",e),y&&y.attr("x2",e),g.width=e,g.height=w.height+t.padding+.5*t.dividerMargin,g},"drawClass"),A=f(function(i){let a=i.id;return i.type&&(a+="<"+X(i.type)+">"),a},"getClassTitleString"),Z=f(function(i,a,t,o){u.debug("Rendering note ",a,t);const p=a.id,g={id:p,text:a.text,width:0,height:0},s=i.append("g").attr("id",p).attr("class","classGroup");let c=s.append("text").attr("y",t.textHeight+t.padding).attr("x",0);const n=JSON.parse(`"${a.text}"`).split(` +import{c as G,a as N,s as I}from"./chunk-IBIA4ERB-LOBGu4Xm.js";import{_ as f,d as S,l as u,j as B,k as W,a2 as P,a8 as R,u as _,a9 as X}from"./mermaid.core-D8igZDel.js";import{G as Y}from"./graph-Cjb-DGHB.js";import{l as $}from"./layout-CHeuV-iP.js";import"./app-D7uBbsY3.js";import"./baseUniq-D0lZO5yp.js";import"./basePickBy-DpnmgMOi.js";var H=0,J=f(function(i,a,t,o,p){const g=f(function(e){switch(e){case p.db.relationType.AGGREGATION:return"aggregation";case p.db.relationType.EXTENSION:return"extension";case p.db.relationType.COMPOSITION:return"composition";case p.db.relationType.DEPENDENCY:return"dependency";case p.db.relationType.LOLLIPOP:return"lollipop"}},"getRelationType");a.points=a.points.filter(e=>!Number.isNaN(e.y));const s=a.points,c=P().x(function(e){return e.x}).y(function(e){return e.y}).curve(R),n=i.append("path").attr("d",c(s)).attr("id","edge"+H).attr("class","relation");let r="";o.arrowMarkerAbsolute&&(r=window.location.protocol+"//"+window.location.host+window.location.pathname+window.location.search,r=r.replace(/\(/g,"\\("),r=r.replace(/\)/g,"\\)")),t.relation.lineType==1&&n.attr("class","relation dashed-line"),t.relation.lineType==10&&n.attr("class","relation dotted-line"),t.relation.type1!=="none"&&n.attr("marker-start","url("+r+"#"+g(t.relation.type1)+"Start)"),t.relation.type2!=="none"&&n.attr("marker-end","url("+r+"#"+g(t.relation.type2)+"End)");let m,h;const x=a.points.length;let b=_.calcLabelPosition(a.points);m=b.x,h=b.y;let y,w,k,v;if(x%2!==0&&x>1){let e=_.calcCardinalityPosition(t.relation.type1!=="none",a.points,a.points[0]),d=_.calcCardinalityPosition(t.relation.type2!=="none",a.points,a.points[x-1]);u.debug("cardinality_1_point "+JSON.stringify(e)),u.debug("cardinality_2_point "+JSON.stringify(d)),y=e.x,w=e.y,k=d.x,v=d.y}if(t.title!==void 0){const e=i.append("g").attr("class","classLabel"),d=e.append("text").attr("class","label").attr("x",m).attr("y",h).attr("fill","red").attr("text-anchor","middle").text(t.title);window.label=d;const l=d.node().getBBox();e.insert("rect",":first-child").attr("class","box").attr("x",l.x-o.padding/2).attr("y",l.y-o.padding/2).attr("width",l.width+o.padding).attr("height",l.height+o.padding)}u.info("Rendering relation "+JSON.stringify(t)),t.relationTitle1!==void 0&&t.relationTitle1!=="none"&&i.append("g").attr("class","cardinality").append("text").attr("class","type1").attr("x",y).attr("y",w).attr("fill","black").attr("font-size","6").text(t.relationTitle1),t.relationTitle2!==void 0&&t.relationTitle2!=="none"&&i.append("g").attr("class","cardinality").append("text").attr("class","type2").attr("x",k).attr("y",v).attr("fill","black").attr("font-size","6").text(t.relationTitle2),H++},"drawEdge"),O=f(function(i,a,t,o){u.debug("Rendering class ",a,t);const p=a.id,g={id:p,label:a.id,width:0,height:0},s=i.append("g").attr("id",o.db.lookUpDomId(p)).attr("class","classGroup");let c;a.link?c=s.append("svg:a").attr("xlink:href",a.link).attr("target",a.linkTarget).append("text").attr("y",t.textHeight+t.padding).attr("x",0):c=s.append("text").attr("y",t.textHeight+t.padding).attr("x",0);let n=!0;a.annotations.forEach(function(d){const l=c.append("tspan").text("«"+d+"»");n||l.attr("dy",t.textHeight),n=!1});let r=A(a);const m=c.append("tspan").text(r).attr("class","title");n||m.attr("dy",t.textHeight);const h=c.node().getBBox().height;let x,b,y;if(a.members.length>0){x=s.append("line").attr("x1",0).attr("y1",t.padding+h+t.dividerMargin/2).attr("y2",t.padding+h+t.dividerMargin/2);const d=s.append("text").attr("x",t.padding).attr("y",h+t.dividerMargin+t.textHeight).attr("fill","white").attr("class","classText");n=!0,a.members.forEach(function(l){C(d,l,n,t),n=!1}),b=d.node().getBBox()}if(a.methods.length>0){y=s.append("line").attr("x1",0).attr("y1",t.padding+h+t.dividerMargin+b.height).attr("y2",t.padding+h+t.dividerMargin+b.height);const d=s.append("text").attr("x",t.padding).attr("y",h+2*t.dividerMargin+b.height+t.textHeight).attr("fill","white").attr("class","classText");n=!0,a.methods.forEach(function(l){C(d,l,n,t),n=!1})}const w=s.node().getBBox();var k=" ";a.cssClasses.length>0&&(k=k+a.cssClasses.join(" "));const e=s.insert("rect",":first-child").attr("x",0).attr("y",0).attr("width",w.width+2*t.padding).attr("height",w.height+t.padding+.5*t.dividerMargin).attr("class",k).node().getBBox().width;return c.node().childNodes.forEach(function(d){d.setAttribute("x",(e-d.getBBox().width)/2)}),a.tooltip&&c.insert("title").text(a.tooltip),x&&x.attr("x2",e),y&&y.attr("x2",e),g.width=e,g.height=w.height+t.padding+.5*t.dividerMargin,g},"drawClass"),A=f(function(i){let a=i.id;return i.type&&(a+="<"+X(i.type)+">"),a},"getClassTitleString"),Z=f(function(i,a,t,o){u.debug("Rendering note ",a,t);const p=a.id,g={id:p,text:a.text,width:0,height:0},s=i.append("g").attr("id",p).attr("class","classGroup");let c=s.append("text").attr("y",t.textHeight+t.padding).attr("x",0);const n=JSON.parse(`"${a.text}"`).split(` `);n.forEach(function(x){u.debug(`Adding line: ${x}`),c.append("tspan").text(x).attr("class","title").attr("dy",t.textHeight)});const r=s.node().getBBox(),h=s.insert("rect",":first-child").attr("x",0).attr("y",0).attr("width",r.width+2*t.padding).attr("height",r.height+n.length*t.textHeight+t.padding+.5*t.dividerMargin).node().getBBox().width;return c.node().childNodes.forEach(function(x){x.setAttribute("x",(h-x.getBBox().width)/2)}),g.width=h,g.height=r.height+n.length*t.textHeight+t.padding+.5*t.dividerMargin,g},"drawNote"),C=f(function(i,a,t,o){const{displayText:p,cssStyle:g}=a.getDisplayDetails(),s=i.append("tspan").attr("x",o.padding).text(p);g!==""&&s.attr("style",a.cssStyle),t||s.attr("dy",o.textHeight)},"addTspan"),M={getClassTitleString:A,drawClass:O,drawEdge:J,drawNote:Z},L={},E=20,T=f(function(i){const a=Object.entries(L).find(t=>t[1].label===i);if(a)return a[0]},"getGraphId"),F=f(function(i){i.append("defs").append("marker").attr("id","extensionStart").attr("class","extension").attr("refX",0).attr("refY",7).attr("markerWidth",190).attr("markerHeight",240).attr("orient","auto").append("path").attr("d","M 1,7 L18,13 V 1 Z"),i.append("defs").append("marker").attr("id","extensionEnd").attr("refX",19).attr("refY",7).attr("markerWidth",20).attr("markerHeight",28).attr("orient","auto").append("path").attr("d","M 1,1 V 13 L18,7 Z"),i.append("defs").append("marker").attr("id","compositionStart").attr("class","extension").attr("refX",0).attr("refY",7).attr("markerWidth",190).attr("markerHeight",240).attr("orient","auto").append("path").attr("d","M 18,7 L9,13 L1,7 L9,1 Z"),i.append("defs").append("marker").attr("id","compositionEnd").attr("refX",19).attr("refY",7).attr("markerWidth",20).attr("markerHeight",28).attr("orient","auto").append("path").attr("d","M 18,7 L9,13 L1,7 L9,1 Z"),i.append("defs").append("marker").attr("id","aggregationStart").attr("class","extension").attr("refX",0).attr("refY",7).attr("markerWidth",190).attr("markerHeight",240).attr("orient","auto").append("path").attr("d","M 18,7 L9,13 L1,7 L9,1 Z"),i.append("defs").append("marker").attr("id","aggregationEnd").attr("refX",19).attr("refY",7).attr("markerWidth",20).attr("markerHeight",28).attr("orient","auto").append("path").attr("d","M 18,7 L9,13 L1,7 L9,1 Z"),i.append("defs").append("marker").attr("id","dependencyStart").attr("class","extension").attr("refX",0).attr("refY",7).attr("markerWidth",190).attr("markerHeight",240).attr("orient","auto").append("path").attr("d","M 5,7 L9,13 L1,7 L9,1 Z"),i.append("defs").append("marker").attr("id","dependencyEnd").attr("refX",19).attr("refY",7).attr("markerWidth",20).attr("markerHeight",28).attr("orient","auto").append("path").attr("d","M 18,7 L9,13 L14,7 L9,1 Z")},"insertMarkers"),U=f(function(i,a,t,o){const p=S().class;L={},u.info("Rendering diagram "+i);const g=S().securityLevel;let s;g==="sandbox"&&(s=B("#i"+a));const c=g==="sandbox"?B(s.nodes()[0].contentDocument.body):B("body"),n=c.select(`[id='${a}']`);F(n);const r=new Y({multigraph:!0});r.setGraph({isMultiGraph:!0}),r.setDefaultEdgeLabel(function(){return{}});const m=o.db.getClasses(),h=[...m.keys()];for(const e of h){const d=m.get(e),l=M.drawClass(n,d,p,o);L[l.id]=l,r.setNode(l.id,l),u.info("Org height: "+l.height)}o.db.getRelations().forEach(function(e){u.info("tjoho"+T(e.id1)+T(e.id2)+JSON.stringify(e)),r.setEdge(T(e.id1),T(e.id2),{relation:e},e.title||"DEFAULT")}),o.db.getNotes().forEach(function(e){u.debug(`Adding note: ${JSON.stringify(e)}`);const d=M.drawNote(n,e,p,o);L[d.id]=d,r.setNode(d.id,d),e.class&&m.has(e.class)&&r.setEdge(e.id,T(e.class),{relation:{id1:e.id,id2:e.class,relation:{type1:"none",type2:"none",lineType:10}}},"DEFAULT")}),$(r),r.nodes().forEach(function(e){e!==void 0&&r.node(e)!==void 0&&(u.debug("Node "+e+": "+JSON.stringify(r.node(e))),c.select("#"+(o.db.lookUpDomId(e)||e)).attr("transform","translate("+(r.node(e).x-r.node(e).width/2)+","+(r.node(e).y-r.node(e).height/2)+" )"))}),r.edges().forEach(function(e){e!==void 0&&r.edge(e)!==void 0&&(u.debug("Edge "+e.v+" -> "+e.w+": "+JSON.stringify(r.edge(e))),M.drawEdge(n,r.edge(e),r.edge(e).relation,p,o))});const y=n.node().getBBox(),w=y.width+E*2,k=y.height+E*2;W(n,k,w,p.useMaxWidth);const v=`${y.x-E} ${y.y-E} ${w} ${k}`;u.debug(`viewBox ${v}`),n.attr("viewBox",v)},"draw"),z={draw:U},et={parser:G,db:N,renderer:z,styles:I,init:f(i=>{i.class||(i.class={}),i.class.arrowMarkerAbsolute=i.arrowMarkerAbsolute,N.clear()},"init")};export{et as diagram}; diff --git a/assets/classDiagram-v2-4S5WAI72-OQWCgw14.js b/assets/classDiagram-v2-4S5WAI72-Dw_LLb4W.js similarity index 96% rename from assets/classDiagram-v2-4S5WAI72-OQWCgw14.js rename to assets/classDiagram-v2-4S5WAI72-Dw_LLb4W.js index 94f71f480b..efd7ce4b9a 100644 --- a/assets/classDiagram-v2-4S5WAI72-OQWCgw14.js +++ b/assets/classDiagram-v2-4S5WAI72-Dw_LLb4W.js @@ -1,2 +1,2 @@ -import{m as tt,c as et,i as nt,a as it,p as st}from"./chunk-PDCO53Z4-RQMWNvLJ.js";import{c as at,a as G,s as rt}from"./chunk-IBIA4ERB-Cq5yRPLn.js";import{c as lt,u as ot,s as ct,i as dt,p as M,a as F,b as R}from"./chunk-Z2VRG6XP-DsASRjJ5.js";import{_ as g,l as s,d as m,j as T,u as ft,aa as ut,ab as $,ac as H,ad as z,v as ht,e as W,ae as J,A as B,D as gt}from"./mermaid.core-DapiNGBY.js";import{G as q}from"./graph-Oq3lz9SV.js";import{l as wt}from"./layout-7AWYeW5Q.js";import{w as S}from"./json-BFhFIfeY.js";import"./app-DBM4OJyw.js";import"./baseUniq-ZJgB7efo.js";import"./basePickBy-BXIHjUx3.js";import"./clone-B3i2nD77.js";var u={},x={},V={},yt=g(()=>{x={},V={},u={}},"clear"),L=g((e,t)=>(s.trace("In isDescendant",t," ",e," = ",x[t].includes(e)),!!x[t].includes(e)),"isDescendant"),bt=g((e,t)=>(s.info("Descendants of ",t," is ",x[t]),s.info("Edge is ",e),e.v===t||e.w===t?!1:x[t]?x[t].includes(e.v)||L(e.v,t)||L(e.w,t)||x[t].includes(e.w):(s.debug("Tilt, ",t,",not in descendants"),!1)),"edgeInCluster"),j=g((e,t,n,l)=>{s.warn("Copying children of ",e,"root",l,"data",t.node(e),l);const i=t.children(e)||[];e!==l&&i.push(e),s.warn("Copying (nodes) clusterId",e,"nodes",i),i.forEach(a=>{if(t.children(a).length>0)j(a,t,n,l);else{const r=t.node(a);s.info("cp ",a," to ",l," with parent ",e),n.setNode(a,r),l!==t.parent(a)&&(s.warn("Setting parent",a,t.parent(a)),n.setParent(a,t.parent(a))),e!==l&&a!==e?(s.debug("Setting parent",a,e),n.setParent(a,e)):(s.info("In copy ",e,"root",l,"data",t.node(e),l),s.debug("Not Setting parent for node=",a,"cluster!==rootId",e!==l,"node!==clusterId",a!==e));const f=t.edges(a);s.debug("Copying Edges",f),f.forEach(d=>{s.info("Edge",d);const h=t.edge(d.v,d.w,d.name);s.info("Edge data",h,l);try{bt(d,l)?(s.info("Copying as ",d.v,d.w,h,d.name),n.setEdge(d.v,d.w,h,d.name),s.info("newGraph edges ",n.edges(),n.edge(n.edges()[0]))):s.info("Skipping copy of edge ",d.v,"-->",d.w," rootId: ",l," clusterId:",e)}catch(b){s.error(b)}})}s.debug("Removing node",a),t.removeNode(a)})},"copy"),K=g((e,t)=>{const n=t.children(e);let l=[...n];for(const i of n)V[i]=e,l=[...l,...K(i,t)];return l},"extractDescendants"),k=g((e,t)=>{s.trace("Searching",e);const n=t.children(e);if(s.trace("Searching children of id ",e,n),n.length<1)return s.trace("This is a valid node",e),e;for(const l of n){const i=k(l,t);if(i)return s.trace("Found replacement for",e," => ",i),i}},"findNonClusterChild"),X=g(e=>!u[e]||!u[e].externalConnections?e:u[e]?u[e].id:e,"getAnchorId"),mt=g((e,t)=>{if(!e||t>10){s.debug("Opting out, no graph ");return}else s.debug("Opting in, graph ");e.nodes().forEach(function(n){e.children(n).length>0&&(s.warn("Cluster identified",n," Replacement id in edges: ",k(n,e)),x[n]=K(n,e),u[n]={id:k(n,e),clusterData:e.node(n)})}),e.nodes().forEach(function(n){const l=e.children(n),i=e.edges();l.length>0?(s.debug("Cluster identified",n,x),i.forEach(a=>{if(a.v!==n&&a.w!==n){const r=L(a.v,n),f=L(a.w,n);r^f&&(s.warn("Edge: ",a," leaves cluster ",n),s.warn("Descendants of XXX ",n,": ",x[n]),u[n].externalConnections=!0)}})):s.debug("Not a cluster ",n,x)});for(let n of Object.keys(u)){const l=u[n].id,i=e.parent(l);i!==n&&u[i]&&!u[i].externalConnections&&(u[n].id=i)}e.edges().forEach(function(n){const l=e.edge(n);s.warn("Edge "+n.v+" -> "+n.w+": "+JSON.stringify(n)),s.warn("Edge "+n.v+" -> "+n.w+": "+JSON.stringify(e.edge(n)));let i=n.v,a=n.w;if(s.warn("Fix XXX",u,"ids:",n.v,n.w,"Translating: ",u[n.v]," --- ",u[n.w]),u[n.v]&&u[n.w]&&u[n.v]===u[n.w]){s.warn("Fixing and trixing link to self - removing XXX",n.v,n.w,n.name),s.warn("Fixing and trixing - removing XXX",n.v,n.w,n.name),i=X(n.v),a=X(n.w),e.removeEdge(n.v,n.w,n.name);const r=n.w+"---"+n.v;e.setNode(r,{domId:r,id:r,labelStyle:"",labelText:l.label,padding:0,shape:"labelRect",style:""});const f=structuredClone(l),d=structuredClone(l);f.label="",f.arrowTypeEnd="none",d.label="",f.fromCluster=n.v,d.toCluster=n.v,e.setEdge(i,r,f,n.name+"-cyclic-special"),e.setEdge(r,a,d,n.name+"-cyclic-special")}else if(u[n.v]||u[n.w]){if(s.warn("Fixing and trixing - removing XXX",n.v,n.w,n.name),i=X(n.v),a=X(n.w),e.removeEdge(n.v,n.w,n.name),i!==n.v){const r=e.parent(i);u[r].externalConnections=!0,l.fromCluster=n.v}if(a!==n.w){const r=e.parent(a);u[r].externalConnections=!0,l.toCluster=n.w}s.warn("Fix Replacing with XXX",i,a,n.name),e.setEdge(i,a,l,n.name)}}),s.warn("Adjusted Graph",S(e)),Q(e,0),s.trace(u)},"adjustClustersAndEdges"),Q=g((e,t)=>{var i,a;if(s.warn("extractor - ",t,S(e),e.children("D")),t>10){s.error("Bailing out");return}let n=e.nodes(),l=!1;for(const r of n){const f=e.children(r);l=l||f.length>0}if(!l){s.debug("Done, no node has children",e.nodes());return}s.debug("Nodes = ",n,t);for(const r of n)if(s.debug("Extracting node",r,u,u[r]&&!u[r].externalConnections,!e.parent(r),e.node(r),e.children("D")," Depth ",t),!u[r])s.debug("Not a cluster",r,t);else if(!u[r].externalConnections&&e.children(r)&&e.children(r).length>0){s.warn("Cluster without external connections, without a parent and with children",r,t);let d=e.graph().rankdir==="TB"?"LR":"TB";(a=(i=u[r])==null?void 0:i.clusterData)!=null&&a.dir&&(d=u[r].clusterData.dir,s.warn("Fixing dir",u[r].clusterData.dir,d));const h=new q({multigraph:!0,compound:!0}).setGraph({rankdir:d,nodesep:50,ranksep:50,marginx:8,marginy:8}).setDefaultEdgeLabel(function(){return{}});s.warn("Old graph before copy",S(e)),j(r,e,h,r),e.setNode(r,{clusterNode:!0,id:r,clusterData:u[r].clusterData,labelText:u[r].labelText,graph:h}),s.warn("New graph after copy node: (",r,")",S(h)),s.debug("Old graph after copy",S(e))}else s.warn("Cluster ** ",r," **not meeting the criteria !externalConnections:",!u[r].externalConnections," no parent: ",!e.parent(r)," children ",e.children(r)&&e.children(r).length>0,e.children("D"),t),s.debug(u);n=e.nodes(),s.warn("New list of nodes",n);for(const r of n){const f=e.node(r);s.warn(" Now next level",r,f),f.clusterNode&&Q(f.graph,t+1)}},"extractor"),U=g((e,t)=>{if(t.length===0)return[];let n=Object.assign(t);return t.forEach(l=>{const i=e.children(l),a=U(e,i);n=[...n,...a]}),n},"sorter"),vt=g(e=>U(e,e.children()),"sortNodesByHierarchy"),pt=g((e,t)=>{s.info("Creating subgraph rect for ",t.id,t);const n=m(),l=e.insert("g").attr("class","cluster"+(t.class?" "+t.class:"")).attr("id",t.id),i=l.insert("rect",":first-child"),a=B(n.flowchart.htmlLabels),r=l.insert("g").attr("class","cluster-label"),f=t.labelType==="markdown"?gt(r,t.labelText,{style:t.labelStyle,useHtmlLabels:a},n):r.node().appendChild(F(t.labelText,t.labelStyle,void 0,!0));let d=f.getBBox();if(B(n.flowchart.htmlLabels)){const c=f.children[0],o=T(f);d=c.getBoundingClientRect(),o.attr("width",d.width),o.attr("height",d.height)}const h=0*t.padding,b=h/2,y=t.width<=d.width+h?d.width+h:t.width;t.width<=d.width+h?t.diff=(d.width-t.width)/2-t.padding/2:t.diff=-t.padding/2,s.trace("Data ",t,JSON.stringify(t)),i.attr("style",t.style).attr("rx",t.rx).attr("ry",t.ry).attr("x",t.x-y/2).attr("y",t.y-t.height/2-b).attr("width",y).attr("height",t.height+h);const{subGraphTitleTopMargin:v}=J(n);a?r.attr("transform",`translate(${t.x-d.width/2}, ${t.y-t.height/2+v})`):r.attr("transform",`translate(${t.x}, ${t.y-t.height/2+v})`);const w=i.node().getBBox();return t.width=w.width,t.height=w.height,t.intersect=function(c){return R(t,c)},l},"rect"),xt=g((e,t)=>{const n=e.insert("g").attr("class","note-cluster").attr("id",t.id),l=n.insert("rect",":first-child"),i=0*t.padding,a=i/2;l.attr("rx",t.rx).attr("ry",t.ry).attr("x",t.x-t.width/2-a).attr("y",t.y-t.height/2-a).attr("width",t.width+i).attr("height",t.height+i).attr("fill","none");const r=l.node().getBBox();return t.width=r.width,t.height=r.height,t.intersect=function(f){return R(t,f)},n},"noteGroup"),St=g((e,t)=>{const n=m(),l=e.insert("g").attr("class",t.classes).attr("id",t.id),i=l.insert("rect",":first-child"),a=l.insert("g").attr("class","cluster-label"),r=l.append("rect"),f=a.node().appendChild(F(t.labelText,t.labelStyle,void 0,!0));let d=f.getBBox();if(B(n.flowchart.htmlLabels)){const c=f.children[0],o=T(f);d=c.getBoundingClientRect(),o.attr("width",d.width),o.attr("height",d.height)}d=f.getBBox();const h=0*t.padding,b=h/2,y=t.width<=d.width+t.padding?d.width+t.padding:t.width;t.width<=d.width+t.padding?t.diff=(d.width+t.padding*0-t.width)/2:t.diff=-t.padding/2,i.attr("class","outer").attr("x",t.x-y/2-b).attr("y",t.y-t.height/2-b).attr("width",y+h).attr("height",t.height+h),r.attr("class","inner").attr("x",t.x-y/2-b).attr("y",t.y-t.height/2-b+d.height-1).attr("width",y+h).attr("height",t.height+h-d.height-3);const{subGraphTitleTopMargin:v}=J(n);a.attr("transform",`translate(${t.x-d.width/2}, ${t.y-t.height/2-t.padding/3+(B(n.flowchart.htmlLabels)?5:3)+v})`);const w=i.node().getBBox();return t.height=w.height,t.intersect=function(c){return R(t,c)},l},"roundedWithTitle"),Nt=g((e,t)=>{const n=e.insert("g").attr("class",t.classes).attr("id",t.id),l=n.insert("rect",":first-child"),i=0*t.padding,a=i/2;l.attr("class","divider").attr("x",t.x-t.width/2-a).attr("y",t.y-t.height/2).attr("width",t.width+i).attr("height",t.height+i);const r=l.node().getBBox();return t.width=r.width,t.height=r.height,t.diff=-t.padding/2,t.intersect=function(f){return R(t,f)},n},"divider"),Et={rect:pt,roundedWithTitle:St,noteGroup:xt,divider:Nt},Y={},Ct=g((e,t)=>{s.trace("Inserting cluster");const n=t.shape||"rect";Y[t.id]=Et[n](e,t)},"insertCluster"),Tt=g(()=>{Y={}},"clear"),Z=g(async(e,t,n,l,i,a)=>{s.info("Graph in recursive render: XXX",S(t),i);const r=t.graph().rankdir;s.trace("Dir in recursive render - dir:",r);const f=e.insert("g").attr("class","root");t.nodes()?s.info("Recursive render XXX",t.nodes()):s.info("No nodes found for",t),t.edges().length>0&&s.trace("Recursive edges",t.edge(t.edges()[0]));const d=f.insert("g").attr("class","clusters"),h=f.insert("g").attr("class","edgePaths"),b=f.insert("g").attr("class","edgeLabels"),y=f.insert("g").attr("class","nodes");await Promise.all(t.nodes().map(async function(c){const o=t.node(c);if(i!==void 0){const p=JSON.parse(JSON.stringify(i.clusterData));s.info("Setting data for cluster XXX (",c,") ",p,i),t.setNode(i.id,p),t.parent(c)||(s.trace("Setting parent",c,i.id),t.setParent(c,i.id,p))}if(s.info("(Insert) Node XXX"+c+": "+JSON.stringify(t.node(c))),o!=null&&o.clusterNode){s.info("Cluster identified",c,o.width,t.node(c));const{ranksep:p,nodesep:E}=t.graph();o.graph.setGraph({...o.graph.graph(),ranksep:p,nodesep:E});const D=await Z(y,o.graph,n,l,t.node(c),a),N=D.elem;ot(o,N),o.diff=D.diff||0,s.info("Node bounds (abc123)",c,o,o.width,o.x,o.y),ct(N,o),s.warn("Recursive render complete ",N,o)}else t.children(c).length>0?(s.info("Cluster - the non recursive path XXX",c,o.id,o,t),s.info(k(o.id,t)),u[o.id]={id:k(o.id,t),node:o}):(s.info("Node - the non recursive path",c,o.id,o),await dt(y,t.node(c),r))})),t.edges().forEach(async function(c){const o=t.edge(c.v,c.w,c.name);s.info("Edge "+c.v+" -> "+c.w+": "+JSON.stringify(c)),s.info("Edge "+c.v+" -> "+c.w+": ",c," ",JSON.stringify(t.edge(c))),s.info("Fix",u,"ids:",c.v,c.w,"Translating: ",u[c.v],u[c.w]),await nt(b,o)}),t.edges().forEach(function(c){s.info("Edge "+c.v+" -> "+c.w+": "+JSON.stringify(c))}),s.info("Graph before layout:",JSON.stringify(S(t))),s.info("#############################################"),s.info("### Layout ###"),s.info("#############################################"),s.info(t),wt(t),s.info("Graph after layout:",JSON.stringify(S(t)));let v=0;const{subGraphTitleTotalMargin:w}=J(a);return vt(t).forEach(function(c){const o=t.node(c);s.info("Position "+c+": "+JSON.stringify(t.node(c))),s.info("Position "+c+": ("+o.x,","+o.y,") width: ",o.width," height: ",o.height),o!=null&&o.clusterNode?(o.y+=w,M(o)):t.children(c).length>0?(o.height+=w,Ct(d,o),u[o.id].node=o):(o.y+=w/2,M(o))}),t.edges().forEach(function(c){const o=t.edge(c);s.info("Edge "+c.v+" -> "+c.w+": "+JSON.stringify(o),o),o.points.forEach(E=>E.y+=w/2);const p=it(h,c,o,u,n,t,l);st(o,p)}),t.nodes().forEach(function(c){const o=t.node(c);s.info(c,o.type,o.diff),o.type==="group"&&(v=o.diff)}),{elem:f,diff:v}},"recursiveRender"),kt=g(async(e,t,n,l,i)=>{tt(e,n,l,i),lt(),et(),Tt(),yt(),s.warn("Graph at first:",JSON.stringify(S(t))),mt(t),s.warn("Graph after:",JSON.stringify(S(t)));const a=m();await Z(e,t,l,i,void 0,a)},"render"),O=g(e=>W.sanitizeText(e,m()),"sanitizeText"),_={dividerMargin:10,padding:5,textHeight:10,curve:void 0},Dt=g(function(e,t,n,l){s.info("keys:",[...e.keys()]),s.info(e),e.forEach(function(i){var f,d;const r={shape:"rect",id:i.id,domId:i.domId,labelText:O(i.id),labelStyle:"",style:"fill: none; stroke: black",padding:((f=m().flowchart)==null?void 0:f.padding)??((d=m().class)==null?void 0:d.padding)};t.setNode(i.id,r),I(i.classes,t,n,l,i.id),s.info("setNode",r)})},"addNamespaces"),I=g(function(e,t,n,l,i){s.info("keys:",[...e.keys()]),s.info(e),[...e.values()].filter(a=>a.parent===i).forEach(function(a){var v,w;const r=a.cssClasses.join(" "),f=$(a.styles),d=a.label??a.id,h=0,y={labelStyle:f.labelStyle,shape:"class_box",labelText:O(d),classData:a,rx:h,ry:h,class:r,style:f.style,id:a.id,domId:a.domId,tooltip:l.db.getTooltip(a.id,i)||"",haveCallback:a.haveCallback,link:a.link,width:a.type==="group"?500:void 0,type:a.type,padding:((v=m().flowchart)==null?void 0:v.padding)??((w=m().class)==null?void 0:w.padding)};t.setNode(a.id,y),i&&t.setParent(a.id,i),s.info("setNode",y)})},"addClasses"),Xt=g(function(e,t,n,l){s.info(e),e.forEach(function(i,a){var o,p;const r=i,f="",d={labelStyle:"",style:""},h=r.text,b=0,v={labelStyle:d.labelStyle,shape:"note",labelText:O(h),noteData:r,rx:b,ry:b,class:f,style:d.style,id:r.id,domId:r.id,tooltip:"",type:"note",padding:((o=m().flowchart)==null?void 0:o.padding)??((p=m().class)==null?void 0:p.padding)};if(t.setNode(r.id,v),s.info("setNode",v),!r.class||!l.has(r.class))return;const w=n+a,c={id:`edgeNote${w}`,classes:"relation",pattern:"dotted",arrowhead:"none",startLabelRight:"",endLabelLeft:"",arrowTypeStart:"none",arrowTypeEnd:"none",style:"fill:none",labelStyle:"",curve:H(_.curve,z)};t.setEdge(r.id,r.class,c,w)})},"addNotes"),Bt=g(function(e,t){const n=m().flowchart;let l=0;e.forEach(function(i){var r;l++;const a={classes:"relation",pattern:i.relation.lineType==1?"dashed":"solid",id:ht(i.id1,i.id2,{prefix:"id",counter:l}),arrowhead:i.type==="arrow_open"?"none":"normal",startLabelRight:i.relationTitle1==="none"?"":i.relationTitle1,endLabelLeft:i.relationTitle2==="none"?"":i.relationTitle2,arrowTypeStart:A(i.relation.type1),arrowTypeEnd:A(i.relation.type2),style:"fill:none",labelStyle:"",curve:H(n==null?void 0:n.curve,z)};if(s.info(a,i),i.style!==void 0){const f=$(i.style);a.style=f.style,a.labelStyle=f.labelStyle}i.text=i.title,i.text===void 0?i.style!==void 0&&(a.arrowheadStyle="fill: #333"):(a.arrowheadStyle="fill: #333",a.labelpos="c",((r=m().flowchart)==null?void 0:r.htmlLabels)??m().htmlLabels?(a.labelType="html",a.label=''+i.text+""):(a.labelType="text",a.label=i.text.replace(W.lineBreakRegex,` +import{m as tt,c as et,i as nt,a as it,p as st}from"./chunk-PDCO53Z4-BcfC0Pnz.js";import{c as at,a as G,s as rt}from"./chunk-IBIA4ERB-LOBGu4Xm.js";import{c as lt,u as ot,s as ct,i as dt,p as M,a as F,b as R}from"./chunk-Z2VRG6XP-CV0pyCU1.js";import{_ as g,l as s,d as m,j as T,u as ft,aa as ut,ab as $,ac as H,ad as z,v as ht,e as W,ae as J,A as B,D as gt}from"./mermaid.core-D8igZDel.js";import{G as q}from"./graph-Cjb-DGHB.js";import{l as wt}from"./layout-CHeuV-iP.js";import{w as S}from"./json-31kD9U7J.js";import"./app-D7uBbsY3.js";import"./baseUniq-D0lZO5yp.js";import"./basePickBy-DpnmgMOi.js";import"./clone-DWnk59eF.js";var u={},x={},V={},yt=g(()=>{x={},V={},u={}},"clear"),L=g((e,t)=>(s.trace("In isDescendant",t," ",e," = ",x[t].includes(e)),!!x[t].includes(e)),"isDescendant"),bt=g((e,t)=>(s.info("Descendants of ",t," is ",x[t]),s.info("Edge is ",e),e.v===t||e.w===t?!1:x[t]?x[t].includes(e.v)||L(e.v,t)||L(e.w,t)||x[t].includes(e.w):(s.debug("Tilt, ",t,",not in descendants"),!1)),"edgeInCluster"),j=g((e,t,n,l)=>{s.warn("Copying children of ",e,"root",l,"data",t.node(e),l);const i=t.children(e)||[];e!==l&&i.push(e),s.warn("Copying (nodes) clusterId",e,"nodes",i),i.forEach(a=>{if(t.children(a).length>0)j(a,t,n,l);else{const r=t.node(a);s.info("cp ",a," to ",l," with parent ",e),n.setNode(a,r),l!==t.parent(a)&&(s.warn("Setting parent",a,t.parent(a)),n.setParent(a,t.parent(a))),e!==l&&a!==e?(s.debug("Setting parent",a,e),n.setParent(a,e)):(s.info("In copy ",e,"root",l,"data",t.node(e),l),s.debug("Not Setting parent for node=",a,"cluster!==rootId",e!==l,"node!==clusterId",a!==e));const f=t.edges(a);s.debug("Copying Edges",f),f.forEach(d=>{s.info("Edge",d);const h=t.edge(d.v,d.w,d.name);s.info("Edge data",h,l);try{bt(d,l)?(s.info("Copying as ",d.v,d.w,h,d.name),n.setEdge(d.v,d.w,h,d.name),s.info("newGraph edges ",n.edges(),n.edge(n.edges()[0]))):s.info("Skipping copy of edge ",d.v,"-->",d.w," rootId: ",l," clusterId:",e)}catch(b){s.error(b)}})}s.debug("Removing node",a),t.removeNode(a)})},"copy"),K=g((e,t)=>{const n=t.children(e);let l=[...n];for(const i of n)V[i]=e,l=[...l,...K(i,t)];return l},"extractDescendants"),k=g((e,t)=>{s.trace("Searching",e);const n=t.children(e);if(s.trace("Searching children of id ",e,n),n.length<1)return s.trace("This is a valid node",e),e;for(const l of n){const i=k(l,t);if(i)return s.trace("Found replacement for",e," => ",i),i}},"findNonClusterChild"),X=g(e=>!u[e]||!u[e].externalConnections?e:u[e]?u[e].id:e,"getAnchorId"),mt=g((e,t)=>{if(!e||t>10){s.debug("Opting out, no graph ");return}else s.debug("Opting in, graph ");e.nodes().forEach(function(n){e.children(n).length>0&&(s.warn("Cluster identified",n," Replacement id in edges: ",k(n,e)),x[n]=K(n,e),u[n]={id:k(n,e),clusterData:e.node(n)})}),e.nodes().forEach(function(n){const l=e.children(n),i=e.edges();l.length>0?(s.debug("Cluster identified",n,x),i.forEach(a=>{if(a.v!==n&&a.w!==n){const r=L(a.v,n),f=L(a.w,n);r^f&&(s.warn("Edge: ",a," leaves cluster ",n),s.warn("Descendants of XXX ",n,": ",x[n]),u[n].externalConnections=!0)}})):s.debug("Not a cluster ",n,x)});for(let n of Object.keys(u)){const l=u[n].id,i=e.parent(l);i!==n&&u[i]&&!u[i].externalConnections&&(u[n].id=i)}e.edges().forEach(function(n){const l=e.edge(n);s.warn("Edge "+n.v+" -> "+n.w+": "+JSON.stringify(n)),s.warn("Edge "+n.v+" -> "+n.w+": "+JSON.stringify(e.edge(n)));let i=n.v,a=n.w;if(s.warn("Fix XXX",u,"ids:",n.v,n.w,"Translating: ",u[n.v]," --- ",u[n.w]),u[n.v]&&u[n.w]&&u[n.v]===u[n.w]){s.warn("Fixing and trixing link to self - removing XXX",n.v,n.w,n.name),s.warn("Fixing and trixing - removing XXX",n.v,n.w,n.name),i=X(n.v),a=X(n.w),e.removeEdge(n.v,n.w,n.name);const r=n.w+"---"+n.v;e.setNode(r,{domId:r,id:r,labelStyle:"",labelText:l.label,padding:0,shape:"labelRect",style:""});const f=structuredClone(l),d=structuredClone(l);f.label="",f.arrowTypeEnd="none",d.label="",f.fromCluster=n.v,d.toCluster=n.v,e.setEdge(i,r,f,n.name+"-cyclic-special"),e.setEdge(r,a,d,n.name+"-cyclic-special")}else if(u[n.v]||u[n.w]){if(s.warn("Fixing and trixing - removing XXX",n.v,n.w,n.name),i=X(n.v),a=X(n.w),e.removeEdge(n.v,n.w,n.name),i!==n.v){const r=e.parent(i);u[r].externalConnections=!0,l.fromCluster=n.v}if(a!==n.w){const r=e.parent(a);u[r].externalConnections=!0,l.toCluster=n.w}s.warn("Fix Replacing with XXX",i,a,n.name),e.setEdge(i,a,l,n.name)}}),s.warn("Adjusted Graph",S(e)),Q(e,0),s.trace(u)},"adjustClustersAndEdges"),Q=g((e,t)=>{var i,a;if(s.warn("extractor - ",t,S(e),e.children("D")),t>10){s.error("Bailing out");return}let n=e.nodes(),l=!1;for(const r of n){const f=e.children(r);l=l||f.length>0}if(!l){s.debug("Done, no node has children",e.nodes());return}s.debug("Nodes = ",n,t);for(const r of n)if(s.debug("Extracting node",r,u,u[r]&&!u[r].externalConnections,!e.parent(r),e.node(r),e.children("D")," Depth ",t),!u[r])s.debug("Not a cluster",r,t);else if(!u[r].externalConnections&&e.children(r)&&e.children(r).length>0){s.warn("Cluster without external connections, without a parent and with children",r,t);let d=e.graph().rankdir==="TB"?"LR":"TB";(a=(i=u[r])==null?void 0:i.clusterData)!=null&&a.dir&&(d=u[r].clusterData.dir,s.warn("Fixing dir",u[r].clusterData.dir,d));const h=new q({multigraph:!0,compound:!0}).setGraph({rankdir:d,nodesep:50,ranksep:50,marginx:8,marginy:8}).setDefaultEdgeLabel(function(){return{}});s.warn("Old graph before copy",S(e)),j(r,e,h,r),e.setNode(r,{clusterNode:!0,id:r,clusterData:u[r].clusterData,labelText:u[r].labelText,graph:h}),s.warn("New graph after copy node: (",r,")",S(h)),s.debug("Old graph after copy",S(e))}else s.warn("Cluster ** ",r," **not meeting the criteria !externalConnections:",!u[r].externalConnections," no parent: ",!e.parent(r)," children ",e.children(r)&&e.children(r).length>0,e.children("D"),t),s.debug(u);n=e.nodes(),s.warn("New list of nodes",n);for(const r of n){const f=e.node(r);s.warn(" Now next level",r,f),f.clusterNode&&Q(f.graph,t+1)}},"extractor"),U=g((e,t)=>{if(t.length===0)return[];let n=Object.assign(t);return t.forEach(l=>{const i=e.children(l),a=U(e,i);n=[...n,...a]}),n},"sorter"),vt=g(e=>U(e,e.children()),"sortNodesByHierarchy"),pt=g((e,t)=>{s.info("Creating subgraph rect for ",t.id,t);const n=m(),l=e.insert("g").attr("class","cluster"+(t.class?" "+t.class:"")).attr("id",t.id),i=l.insert("rect",":first-child"),a=B(n.flowchart.htmlLabels),r=l.insert("g").attr("class","cluster-label"),f=t.labelType==="markdown"?gt(r,t.labelText,{style:t.labelStyle,useHtmlLabels:a},n):r.node().appendChild(F(t.labelText,t.labelStyle,void 0,!0));let d=f.getBBox();if(B(n.flowchart.htmlLabels)){const c=f.children[0],o=T(f);d=c.getBoundingClientRect(),o.attr("width",d.width),o.attr("height",d.height)}const h=0*t.padding,b=h/2,y=t.width<=d.width+h?d.width+h:t.width;t.width<=d.width+h?t.diff=(d.width-t.width)/2-t.padding/2:t.diff=-t.padding/2,s.trace("Data ",t,JSON.stringify(t)),i.attr("style",t.style).attr("rx",t.rx).attr("ry",t.ry).attr("x",t.x-y/2).attr("y",t.y-t.height/2-b).attr("width",y).attr("height",t.height+h);const{subGraphTitleTopMargin:v}=J(n);a?r.attr("transform",`translate(${t.x-d.width/2}, ${t.y-t.height/2+v})`):r.attr("transform",`translate(${t.x}, ${t.y-t.height/2+v})`);const w=i.node().getBBox();return t.width=w.width,t.height=w.height,t.intersect=function(c){return R(t,c)},l},"rect"),xt=g((e,t)=>{const n=e.insert("g").attr("class","note-cluster").attr("id",t.id),l=n.insert("rect",":first-child"),i=0*t.padding,a=i/2;l.attr("rx",t.rx).attr("ry",t.ry).attr("x",t.x-t.width/2-a).attr("y",t.y-t.height/2-a).attr("width",t.width+i).attr("height",t.height+i).attr("fill","none");const r=l.node().getBBox();return t.width=r.width,t.height=r.height,t.intersect=function(f){return R(t,f)},n},"noteGroup"),St=g((e,t)=>{const n=m(),l=e.insert("g").attr("class",t.classes).attr("id",t.id),i=l.insert("rect",":first-child"),a=l.insert("g").attr("class","cluster-label"),r=l.append("rect"),f=a.node().appendChild(F(t.labelText,t.labelStyle,void 0,!0));let d=f.getBBox();if(B(n.flowchart.htmlLabels)){const c=f.children[0],o=T(f);d=c.getBoundingClientRect(),o.attr("width",d.width),o.attr("height",d.height)}d=f.getBBox();const h=0*t.padding,b=h/2,y=t.width<=d.width+t.padding?d.width+t.padding:t.width;t.width<=d.width+t.padding?t.diff=(d.width+t.padding*0-t.width)/2:t.diff=-t.padding/2,i.attr("class","outer").attr("x",t.x-y/2-b).attr("y",t.y-t.height/2-b).attr("width",y+h).attr("height",t.height+h),r.attr("class","inner").attr("x",t.x-y/2-b).attr("y",t.y-t.height/2-b+d.height-1).attr("width",y+h).attr("height",t.height+h-d.height-3);const{subGraphTitleTopMargin:v}=J(n);a.attr("transform",`translate(${t.x-d.width/2}, ${t.y-t.height/2-t.padding/3+(B(n.flowchart.htmlLabels)?5:3)+v})`);const w=i.node().getBBox();return t.height=w.height,t.intersect=function(c){return R(t,c)},l},"roundedWithTitle"),Nt=g((e,t)=>{const n=e.insert("g").attr("class",t.classes).attr("id",t.id),l=n.insert("rect",":first-child"),i=0*t.padding,a=i/2;l.attr("class","divider").attr("x",t.x-t.width/2-a).attr("y",t.y-t.height/2).attr("width",t.width+i).attr("height",t.height+i);const r=l.node().getBBox();return t.width=r.width,t.height=r.height,t.diff=-t.padding/2,t.intersect=function(f){return R(t,f)},n},"divider"),Et={rect:pt,roundedWithTitle:St,noteGroup:xt,divider:Nt},Y={},Ct=g((e,t)=>{s.trace("Inserting cluster");const n=t.shape||"rect";Y[t.id]=Et[n](e,t)},"insertCluster"),Tt=g(()=>{Y={}},"clear"),Z=g(async(e,t,n,l,i,a)=>{s.info("Graph in recursive render: XXX",S(t),i);const r=t.graph().rankdir;s.trace("Dir in recursive render - dir:",r);const f=e.insert("g").attr("class","root");t.nodes()?s.info("Recursive render XXX",t.nodes()):s.info("No nodes found for",t),t.edges().length>0&&s.trace("Recursive edges",t.edge(t.edges()[0]));const d=f.insert("g").attr("class","clusters"),h=f.insert("g").attr("class","edgePaths"),b=f.insert("g").attr("class","edgeLabels"),y=f.insert("g").attr("class","nodes");await Promise.all(t.nodes().map(async function(c){const o=t.node(c);if(i!==void 0){const p=JSON.parse(JSON.stringify(i.clusterData));s.info("Setting data for cluster XXX (",c,") ",p,i),t.setNode(i.id,p),t.parent(c)||(s.trace("Setting parent",c,i.id),t.setParent(c,i.id,p))}if(s.info("(Insert) Node XXX"+c+": "+JSON.stringify(t.node(c))),o!=null&&o.clusterNode){s.info("Cluster identified",c,o.width,t.node(c));const{ranksep:p,nodesep:E}=t.graph();o.graph.setGraph({...o.graph.graph(),ranksep:p,nodesep:E});const D=await Z(y,o.graph,n,l,t.node(c),a),N=D.elem;ot(o,N),o.diff=D.diff||0,s.info("Node bounds (abc123)",c,o,o.width,o.x,o.y),ct(N,o),s.warn("Recursive render complete ",N,o)}else t.children(c).length>0?(s.info("Cluster - the non recursive path XXX",c,o.id,o,t),s.info(k(o.id,t)),u[o.id]={id:k(o.id,t),node:o}):(s.info("Node - the non recursive path",c,o.id,o),await dt(y,t.node(c),r))})),t.edges().forEach(async function(c){const o=t.edge(c.v,c.w,c.name);s.info("Edge "+c.v+" -> "+c.w+": "+JSON.stringify(c)),s.info("Edge "+c.v+" -> "+c.w+": ",c," ",JSON.stringify(t.edge(c))),s.info("Fix",u,"ids:",c.v,c.w,"Translating: ",u[c.v],u[c.w]),await nt(b,o)}),t.edges().forEach(function(c){s.info("Edge "+c.v+" -> "+c.w+": "+JSON.stringify(c))}),s.info("Graph before layout:",JSON.stringify(S(t))),s.info("#############################################"),s.info("### Layout ###"),s.info("#############################################"),s.info(t),wt(t),s.info("Graph after layout:",JSON.stringify(S(t)));let v=0;const{subGraphTitleTotalMargin:w}=J(a);return vt(t).forEach(function(c){const o=t.node(c);s.info("Position "+c+": "+JSON.stringify(t.node(c))),s.info("Position "+c+": ("+o.x,","+o.y,") width: ",o.width," height: ",o.height),o!=null&&o.clusterNode?(o.y+=w,M(o)):t.children(c).length>0?(o.height+=w,Ct(d,o),u[o.id].node=o):(o.y+=w/2,M(o))}),t.edges().forEach(function(c){const o=t.edge(c);s.info("Edge "+c.v+" -> "+c.w+": "+JSON.stringify(o),o),o.points.forEach(E=>E.y+=w/2);const p=it(h,c,o,u,n,t,l);st(o,p)}),t.nodes().forEach(function(c){const o=t.node(c);s.info(c,o.type,o.diff),o.type==="group"&&(v=o.diff)}),{elem:f,diff:v}},"recursiveRender"),kt=g(async(e,t,n,l,i)=>{tt(e,n,l,i),lt(),et(),Tt(),yt(),s.warn("Graph at first:",JSON.stringify(S(t))),mt(t),s.warn("Graph after:",JSON.stringify(S(t)));const a=m();await Z(e,t,l,i,void 0,a)},"render"),O=g(e=>W.sanitizeText(e,m()),"sanitizeText"),_={dividerMargin:10,padding:5,textHeight:10,curve:void 0},Dt=g(function(e,t,n,l){s.info("keys:",[...e.keys()]),s.info(e),e.forEach(function(i){var f,d;const r={shape:"rect",id:i.id,domId:i.domId,labelText:O(i.id),labelStyle:"",style:"fill: none; stroke: black",padding:((f=m().flowchart)==null?void 0:f.padding)??((d=m().class)==null?void 0:d.padding)};t.setNode(i.id,r),I(i.classes,t,n,l,i.id),s.info("setNode",r)})},"addNamespaces"),I=g(function(e,t,n,l,i){s.info("keys:",[...e.keys()]),s.info(e),[...e.values()].filter(a=>a.parent===i).forEach(function(a){var v,w;const r=a.cssClasses.join(" "),f=$(a.styles),d=a.label??a.id,h=0,y={labelStyle:f.labelStyle,shape:"class_box",labelText:O(d),classData:a,rx:h,ry:h,class:r,style:f.style,id:a.id,domId:a.domId,tooltip:l.db.getTooltip(a.id,i)||"",haveCallback:a.haveCallback,link:a.link,width:a.type==="group"?500:void 0,type:a.type,padding:((v=m().flowchart)==null?void 0:v.padding)??((w=m().class)==null?void 0:w.padding)};t.setNode(a.id,y),i&&t.setParent(a.id,i),s.info("setNode",y)})},"addClasses"),Xt=g(function(e,t,n,l){s.info(e),e.forEach(function(i,a){var o,p;const r=i,f="",d={labelStyle:"",style:""},h=r.text,b=0,v={labelStyle:d.labelStyle,shape:"note",labelText:O(h),noteData:r,rx:b,ry:b,class:f,style:d.style,id:r.id,domId:r.id,tooltip:"",type:"note",padding:((o=m().flowchart)==null?void 0:o.padding)??((p=m().class)==null?void 0:p.padding)};if(t.setNode(r.id,v),s.info("setNode",v),!r.class||!l.has(r.class))return;const w=n+a,c={id:`edgeNote${w}`,classes:"relation",pattern:"dotted",arrowhead:"none",startLabelRight:"",endLabelLeft:"",arrowTypeStart:"none",arrowTypeEnd:"none",style:"fill:none",labelStyle:"",curve:H(_.curve,z)};t.setEdge(r.id,r.class,c,w)})},"addNotes"),Bt=g(function(e,t){const n=m().flowchart;let l=0;e.forEach(function(i){var r;l++;const a={classes:"relation",pattern:i.relation.lineType==1?"dashed":"solid",id:ht(i.id1,i.id2,{prefix:"id",counter:l}),arrowhead:i.type==="arrow_open"?"none":"normal",startLabelRight:i.relationTitle1==="none"?"":i.relationTitle1,endLabelLeft:i.relationTitle2==="none"?"":i.relationTitle2,arrowTypeStart:A(i.relation.type1),arrowTypeEnd:A(i.relation.type2),style:"fill:none",labelStyle:"",curve:H(n==null?void 0:n.curve,z)};if(s.info(a,i),i.style!==void 0){const f=$(i.style);a.style=f.style,a.labelStyle=f.labelStyle}i.text=i.title,i.text===void 0?i.style!==void 0&&(a.arrowheadStyle="fill: #333"):(a.arrowheadStyle="fill: #333",a.labelpos="c",((r=m().flowchart)==null?void 0:r.htmlLabels)??m().htmlLabels?(a.labelType="html",a.label=''+i.text+""):(a.labelType="text",a.label=i.text.replace(W.lineBreakRegex,` `),i.style===void 0&&(a.style=a.style||"stroke: #333; stroke-width: 1.5px;fill:none"),a.labelStyle=a.labelStyle.replace("color:","fill:"))),t.setEdge(i.id1,i.id2,a,l)})},"addRelations"),Lt=g(function(e){_={..._,...e}},"setConf"),Rt=g(async function(e,t,n,l){s.info("Drawing class - ",t);const i=m().flowchart??m().class,a=m().securityLevel;s.info("config:",i);const r=(i==null?void 0:i.nodeSpacing)??50,f=(i==null?void 0:i.rankSpacing)??50,d=new q({multigraph:!0,compound:!0}).setGraph({rankdir:l.db.getDirection(),nodesep:r,ranksep:f,marginx:8,marginy:8}).setDefaultEdgeLabel(function(){return{}}),h=l.db.getNamespaces(),b=l.db.getClasses(),y=l.db.getRelations(),v=l.db.getNotes();s.info(y),Dt(h,d,t,l),I(b,d,t,l),Bt(y,d),Xt(v,d,y.length+1,b);let w;a==="sandbox"&&(w=T("#i"+t));const c=a==="sandbox"?T(w.nodes()[0].contentDocument.body):T("body"),o=c.select(`[id="${t}"]`),p=c.select("#"+t+" g");if(await kt(p,d,["aggregation","extension","composition","dependency","lollipop"],"classDiagram",t),ft.insertTitle(o,"classTitleText",(i==null?void 0:i.titleTopMargin)??5,l.db.getDiagramTitle()),ut(d,o,i==null?void 0:i.diagramPadding,i==null?void 0:i.useMaxWidth),!(i!=null&&i.htmlLabels)){const E=a==="sandbox"?w.nodes()[0].contentDocument:document,D=E.querySelectorAll('[id="'+t+'"] .edgeLabel .label');for(const N of D){const P=N.getBBox(),C=E.createElementNS("http://www.w3.org/2000/svg","rect");C.setAttribute("rx",0),C.setAttribute("ry",0),C.setAttribute("width",P.width),C.setAttribute("height",P.height),N.insertBefore(C,N.firstChild)}}},"draw");function A(e){let t;switch(e){case 0:t="aggregation";break;case 1:t="extension";break;case 2:t="composition";break;case 3:t="dependency";break;case 4:t="lollipop";break;default:t="none"}return t}g(A,"getArrowMarker");var _t={setConf:Lt,draw:Rt},qt={parser:at,db:G,renderer:_t,styles:rt,init:g(e=>{e.class||(e.class={}),e.class.arrowMarkerAbsolute=e.arrowMarkerAbsolute,G.clear()},"init")};export{qt as diagram}; diff --git a/assets/clone-B3i2nD77.js b/assets/clone-B3i2nD77.js deleted file mode 100644 index 5eb00db47c..0000000000 --- a/assets/clone-B3i2nD77.js +++ /dev/null @@ -1 +0,0 @@ -import{b as r}from"./baseUniq-ZJgB7efo.js";var e=4;function a(o){return r(o,e)}export{a as c}; diff --git a/assets/clone-DWnk59eF.js b/assets/clone-DWnk59eF.js new file mode 100644 index 0000000000..6af705446a --- /dev/null +++ b/assets/clone-DWnk59eF.js @@ -0,0 +1 @@ +import{b as r}from"./baseUniq-D0lZO5yp.js";var e=4;function a(o){return r(o,e)}export{a as c}; diff --git a/assets/command.html-DM-t2Q6w.js b/assets/command.html-BD6DsLl0.js similarity index 99% rename from assets/command.html-DM-t2Q6w.js rename to assets/command.html-BD6DsLl0.js index 02e5639bb1..b1df6d7c3d 100644 --- a/assets/command.html-DM-t2Q6w.js +++ b/assets/command.html-BD6DsLl0.js @@ -1,4 +1,4 @@ -import{_ as t,r as a,o as l,c as r,a as s,b as e,w as c,d as n,e as o}from"./app-DBM4OJyw.js";const v={},u=o(`

                                      命令参数

                                      提示

                                      Xray 使用 Go 风格的命令及参数

                                      获取基本命令

                                      您可以运行 xray help 来获得所有 xray 最基础的用法, 以及可用的命令及说明。

                                      Xray is a platform for building proxies.
                                      +import{_ as t,r as a,o as l,c as r,a as s,b as e,w as c,d as n,e as o}from"./app-D7uBbsY3.js";const v={},u=o(`

                                      命令参数

                                      提示

                                      Xray 使用 Go 风格的命令及参数

                                      获取基本命令

                                      您可以运行 xray help 来获得所有 xray 最基础的用法, 以及可用的命令及说明。

                                      Xray is a platform for building proxies.
                                       
                                       Usage:
                                       
                                      diff --git a/assets/command.html-CrJVUr4J.js b/assets/command.html-BeR19Y5B.js
                                      similarity index 99%
                                      rename from assets/command.html-CrJVUr4J.js
                                      rename to assets/command.html-BeR19Y5B.js
                                      index a3de541a15..3d83a5c7c9 100644
                                      --- a/assets/command.html-CrJVUr4J.js
                                      +++ b/assets/command.html-BeR19Y5B.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as d,r as a,o as l,c as r,a as s,b as e,d as n,w as c,e as o}from"./app-DBM4OJyw.js";const u={},v=o(`

                                      Command Parameters

                                      Tip

                                      Xray uses Go-style commands and parameters

                                      Get Basic Commands

                                      You can run xray helpto get the most basic usage of all xray, as well as available commands and instructions.

                                      Xray is a platform for building proxies.
                                      +import{_ as d,r as a,o as l,c as r,a as s,b as e,d as n,w as c,e as o}from"./app-D7uBbsY3.js";const u={},v=o(`

                                      Command Parameters

                                      Tip

                                      Xray uses Go-style commands and parameters

                                      Get Basic Commands

                                      You can run xray helpto get the most basic usage of all xray, as well as available commands and instructions.

                                      Xray is a platform for building proxies.
                                       
                                       Usage:
                                       
                                      diff --git a/assets/command.html-mB_BYdZd.js b/assets/command.html-DwCdhhuq.js
                                      similarity index 99%
                                      rename from assets/command.html-mB_BYdZd.js
                                      rename to assets/command.html-DwCdhhuq.js
                                      index 4908ab5c37..15559994a6 100644
                                      --- a/assets/command.html-mB_BYdZd.js
                                      +++ b/assets/command.html-DwCdhhuq.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as d,r as a,o as l,c as r,a as s,b as e,d as n,w as c,e as o}from"./app-DBM4OJyw.js";const u={},v=o(`

                                      Командные аргументы

                                      Подсказка

                                      Xray использует команды и аргументы в стиле Go.

                                      Базовые команды

                                      Вы можете запустить xray help, чтобы получить список всех базовых команд Xray, а также их описание и примеры использования.

                                      Xray is a platform for building proxies.
                                      +import{_ as d,r as a,o as l,c as r,a as s,b as e,d as n,w as c,e as o}from"./app-D7uBbsY3.js";const u={},v=o(`

                                      Командные аргументы

                                      Подсказка

                                      Xray использует команды и аргументы в стиле Go.

                                      Базовые команды

                                      Вы можете запустить xray help, чтобы получить список всех базовых команд Xray, а также их описание и примеры использования.

                                      Xray is a platform for building proxies.
                                       
                                       Usage:
                                       
                                      diff --git a/assets/compile.html-ZO7e59Ko.js b/assets/compile.html-B_SG4Rjg.js
                                      similarity index 99%
                                      rename from assets/compile.html-ZO7e59Ko.js
                                      rename to assets/compile.html-B_SG4Rjg.js
                                      index cb9ae9507e..3fbbb1423b 100644
                                      --- a/assets/compile.html-ZO7e59Ko.js
                                      +++ b/assets/compile.html-B_SG4Rjg.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as t,r as o,o as i,c as r,a as e,b as a,d as s,e as c}from"./app-DBM4OJyw.js";const p={},d=a("h1",{id:"编译文档",tabindex:"-1"},[a("a",{class:"header-anchor",href:"#编译文档"},[a("span",null,"编译文档")])],-1),u=a("h2",{id:"前序工作",tabindex:"-1"},[a("a",{class:"header-anchor",href:"#前序工作"},[a("span",null,"前序工作")])],-1),h={href:"https://golang.org/",target:"_blank",rel:"noopener noreferrer"},v={class:"custom-container tip"},m=a("p",{class:"custom-container-title"},"TIP",-1),b={href:"https://golang.org/doc/install",target:"_blank",rel:"noopener noreferrer"},g=c(`

                                      如果你不幸使用 Windows, 请 务必 使用 Powershell

                                      拉取 Xray 源代码

                                      git clone https://github.com/XTLS/Xray-core.git
                                      +import{_ as t,r as o,o as i,c as r,a as e,b as a,d as s,e as c}from"./app-D7uBbsY3.js";const p={},d=a("h1",{id:"编译文档",tabindex:"-1"},[a("a",{class:"header-anchor",href:"#编译文档"},[a("span",null,"编译文档")])],-1),u=a("h2",{id:"前序工作",tabindex:"-1"},[a("a",{class:"header-anchor",href:"#前序工作"},[a("span",null,"前序工作")])],-1),h={href:"https://golang.org/",target:"_blank",rel:"noopener noreferrer"},v={class:"custom-container tip"},m=a("p",{class:"custom-container-title"},"TIP",-1),b={href:"https://golang.org/doc/install",target:"_blank",rel:"noopener noreferrer"},g=c(`

                                      如果你不幸使用 Windows, 请 务必 使用 Powershell

                                      拉取 Xray 源代码

                                      git clone https://github.com/XTLS/Xray-core.git
                                       cd Xray-core && go mod download
                                       

                                      如果你闲的没事干,可以试试 GitHub 官方工具: gh repo clone XTLS/Xray-core

                                      注意:在无法正常访问 Google 的网络环境,依赖无法被正常拉取,需要先设置 GOPROXY

                                      go env -w GOPROXY=https://goproxy.io,direct
                                       

                                      构建二进制

                                      Внимание

                                      本小节的命令需要在 Xray 根目录内运行。

                                      Windows(Powershell):

                                      $env:CGO_ENABLED=0
                                      diff --git a/assets/compile.html-DXk7Z9BM.js b/assets/compile.html-BaQu-P3E.js
                                      similarity index 99%
                                      rename from assets/compile.html-DXk7Z9BM.js
                                      rename to assets/compile.html-BaQu-P3E.js
                                      index 8d57c13e52..595009f83a 100644
                                      --- a/assets/compile.html-DXk7Z9BM.js
                                      +++ b/assets/compile.html-BaQu-P3E.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as t,r as o,o as i,c as r,a as e,b as a,d as s,e as c}from"./app-DBM4OJyw.js";const p={},d=a("h1",{id:"编译文档",tabindex:"-1"},[a("a",{class:"header-anchor",href:"#编译文档"},[a("span",null,"编译文档")])],-1),u=a("h2",{id:"前序工作",tabindex:"-1"},[a("a",{class:"header-anchor",href:"#前序工作"},[a("span",null,"前序工作")])],-1),h={href:"https://golang.org/",target:"_blank",rel:"noopener noreferrer"},v={class:"custom-container tip"},m=a("p",{class:"custom-container-title"},"TIP",-1),b={href:"https://golang.org/doc/install",target:"_blank",rel:"noopener noreferrer"},g=c(`

                                      如果你不幸使用 Windows, 请 务必 使用 Powershell

                                      拉取 Xray 源代码

                                      git clone https://github.com/XTLS/Xray-core.git
                                      +import{_ as t,r as o,o as i,c as r,a as e,b as a,d as s,e as c}from"./app-D7uBbsY3.js";const p={},d=a("h1",{id:"编译文档",tabindex:"-1"},[a("a",{class:"header-anchor",href:"#编译文档"},[a("span",null,"编译文档")])],-1),u=a("h2",{id:"前序工作",tabindex:"-1"},[a("a",{class:"header-anchor",href:"#前序工作"},[a("span",null,"前序工作")])],-1),h={href:"https://golang.org/",target:"_blank",rel:"noopener noreferrer"},v={class:"custom-container tip"},m=a("p",{class:"custom-container-title"},"TIP",-1),b={href:"https://golang.org/doc/install",target:"_blank",rel:"noopener noreferrer"},g=c(`

                                      如果你不幸使用 Windows, 请 务必 使用 Powershell

                                      拉取 Xray 源代码

                                      git clone https://github.com/XTLS/Xray-core.git
                                       cd Xray-core && go mod download
                                       

                                      如果你闲的没事干,可以试试 GitHub 官方工具: gh repo clone XTLS/Xray-core

                                      注意:在无法正常访问 Google 的网络环境,依赖无法被正常拉取,需要先设置 GOPROXY

                                      go env -w GOPROXY=https://goproxy.io,direct
                                       

                                      构建二进制

                                      注意

                                      本小节的命令需要在 Xray 根目录内运行。

                                      Windows(Powershell):

                                      $env:CGO_ENABLED=0
                                      diff --git a/assets/compile.html-B9Zh6vRY.js b/assets/compile.html-sA6hddT4.js
                                      similarity index 99%
                                      rename from assets/compile.html-B9Zh6vRY.js
                                      rename to assets/compile.html-sA6hddT4.js
                                      index 454a991058..6858d0ede8 100644
                                      --- a/assets/compile.html-B9Zh6vRY.js
                                      +++ b/assets/compile.html-sA6hddT4.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as i,r as o,o as l,c as r,a as s,b as e,d as a,e as c}from"./app-DBM4OJyw.js";const d={},p=e("h1",{id:"compile-the-document",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#compile-the-document"},[e("span",null,"Compile the document")])],-1),u=e("h2",{id:"preparatory-work",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#preparatory-work"},[e("span",null,"Preparatory Work")])],-1),h={href:"https://golang.org/",target:"_blank",rel:"noopener noreferrer"},m={class:"custom-container tip"},g=e("p",{class:"custom-container-title"},"TIP",-1),b={href:"https://golang.org/doc/install",target:"_blank",rel:"noopener noreferrer"},v=c(`

                                      If you happen to use Windows, please make sure to use Powershell.

                                      Pull Xray source code

                                      git clone https://github.com/XTLS/Xray-core.git
                                      +import{_ as i,r as o,o as l,c as r,a as s,b as e,d as a,e as c}from"./app-D7uBbsY3.js";const d={},p=e("h1",{id:"compile-the-document",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#compile-the-document"},[e("span",null,"Compile the document")])],-1),u=e("h2",{id:"preparatory-work",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#preparatory-work"},[e("span",null,"Preparatory Work")])],-1),h={href:"https://golang.org/",target:"_blank",rel:"noopener noreferrer"},m={class:"custom-container tip"},g=e("p",{class:"custom-container-title"},"TIP",-1),b={href:"https://golang.org/doc/install",target:"_blank",rel:"noopener noreferrer"},v=c(`

                                      If you happen to use Windows, please make sure to use Powershell.

                                      Pull Xray source code

                                      git clone https://github.com/XTLS/Xray-core.git
                                       cd Xray-core && go mod download
                                       

                                      If you have free time, you can try GitHub's official tool: gh repo clone XTLS/Xray-core

                                      Note: In a network environment where Google cannot be accessed normally, dependencies cannot be pulled normally, and GOPROXY needs to be set first:

                                      go env -w GOPROXY=https://goproxy.io,direct
                                       

                                      Build Binary

                                      Warning

                                      This command needs to be executed within Xray root directory.

                                      Windows(Powershell):

                                      $env:CGO_ENABLED=0
                                      diff --git a/assets/config.html-DFUKOYQn.js b/assets/config.html-BQlgOjHP.js
                                      similarity index 99%
                                      rename from assets/config.html-DFUKOYQn.js
                                      rename to assets/config.html-BQlgOjHP.js
                                      index 7d4fa1d135..cad9a827fb 100644
                                      --- a/assets/config.html-DFUKOYQn.js
                                      +++ b/assets/config.html-BQlgOjHP.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as i,r as o,o as l,c as u,a,b as s,d as n,w as e,e as r}from"./app-DBM4OJyw.js";const d={},k=s("h1",{id:"配置运行",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#配置运行"},[s("span",null,"配置运行")])],-1),v=s("p",null,[s("a",{href:"./install"},"下载并安装"),n(" 了 Xray 之后,您需要对它进行一下配置。")],-1),m={href:"https://github.com/XTLS/Xray-examples",target:"_blank",rel:"noopener noreferrer"},b=r(`

                                      警告

                                      为了避免你的流量被解密,
                                      你应该使用 xray uuiduuidgen 生成一个独一无二的uuid
                                      在服务端上,放入 inbounds[0].settings.clients[0].id
                                      在客户端内,放入 outbounds[0].settings.vnext[0].users[0].id

                                      服务端配置

                                      你需要一台防火墙外的服务器,来运行服务器端的 Xray。配置如下:

                                      {
                                      +import{_ as i,r as o,o as l,c as u,a,b as s,d as n,w as e,e as r}from"./app-D7uBbsY3.js";const d={},k=s("h1",{id:"配置运行",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#配置运行"},[s("span",null,"配置运行")])],-1),v=s("p",null,[s("a",{href:"./install"},"下载并安装"),n(" 了 Xray 之后,您需要对它进行一下配置。")],-1),m={href:"https://github.com/XTLS/Xray-examples",target:"_blank",rel:"noopener noreferrer"},b=r(`

                                      警告

                                      为了避免你的流量被解密,
                                      你应该使用 xray uuiduuidgen 生成一个独一无二的uuid
                                      在服务端上,放入 inbounds[0].settings.clients[0].id
                                      在客户端内,放入 outbounds[0].settings.vnext[0].users[0].id

                                      服务端配置

                                      你需要一台防火墙外的服务器,来运行服务器端的 Xray。配置如下:

                                      {
                                         "inbounds": [
                                           {
                                             "port": 10086, // 服务器监听端口
                                      diff --git a/assets/config.html-DmHh-Zu1.js b/assets/config.html-ByKuPk47.js
                                      similarity index 99%
                                      rename from assets/config.html-DmHh-Zu1.js
                                      rename to assets/config.html-ByKuPk47.js
                                      index c611d40467..f7818526f8 100644
                                      --- a/assets/config.html-DmHh-Zu1.js
                                      +++ b/assets/config.html-ByKuPk47.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as i,r as o,o as l,c as u,a,b as s,d as n,w as e,e as r}from"./app-DBM4OJyw.js";const d={},k=s("h1",{id:"настроика-и-запуск",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#настроика-и-запуск"},[s("span",null,"Настройка и запуск")])],-1),v=s("p",null,[n("После того, как вы "),s("a",{href:"./install"},"скачали и установили"),n(" Xray, вам потребуется его настроить.")],-1),m={href:"https://github.com/XTLS/Xray-examples",target:"_blank",rel:"noopener noreferrer"},b=r(`

                                      Предупреждение

                                      Во избежание расшифровки вашего трафика
                                      следует сгенерировать уникальный UUID с помощью команды xray uuid или uuidgen,
                                      который затем нужно вставить на стороне сервера в поле inbounds[0].settings.clients[0].id,
                                      а на стороне клиента - в поле outbounds[0].settings.vnext[0].users[0].id.

                                      Настройка сервера

                                      Вам понадобится сервер с публичным IP-адресом (не за NAT), на котором будет запущен Xray. Конфигурация сервера:

                                      {
                                      +import{_ as i,r as o,o as l,c as u,a,b as s,d as n,w as e,e as r}from"./app-D7uBbsY3.js";const d={},k=s("h1",{id:"настроика-и-запуск",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#настроика-и-запуск"},[s("span",null,"Настройка и запуск")])],-1),v=s("p",null,[n("После того, как вы "),s("a",{href:"./install"},"скачали и установили"),n(" Xray, вам потребуется его настроить.")],-1),m={href:"https://github.com/XTLS/Xray-examples",target:"_blank",rel:"noopener noreferrer"},b=r(`

                                      Предупреждение

                                      Во избежание расшифровки вашего трафика
                                      следует сгенерировать уникальный UUID с помощью команды xray uuid или uuidgen,
                                      который затем нужно вставить на стороне сервера в поле inbounds[0].settings.clients[0].id,
                                      а на стороне клиента - в поле outbounds[0].settings.vnext[0].users[0].id.

                                      Настройка сервера

                                      Вам понадобится сервер с публичным IP-адресом (не за NAT), на котором будет запущен Xray. Конфигурация сервера:

                                      {
                                         "inbounds": [
                                           {
                                             "port": 10086, // Порт, который слушает сервер
                                      diff --git a/assets/config.html-P39U8JiI.js b/assets/config.html-Cx5EaDWl.js
                                      similarity index 99%
                                      rename from assets/config.html-P39U8JiI.js
                                      rename to assets/config.html-Cx5EaDWl.js
                                      index d9eda98c13..e4fc8a845c 100644
                                      --- a/assets/config.html-P39U8JiI.js
                                      +++ b/assets/config.html-Cx5EaDWl.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as c,r as o,o as l,c as r,a,b as s,d as n,w as e,e as u}from"./app-DBM4OJyw.js";const d={},v=s("h1",{id:"configure-and-run",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#configure-and-run"},[s("span",null,"Configure and Run")])],-1),k={href:"https://github.com/XTLS/Xray-examples",target:"_blank",rel:"noopener noreferrer"},m=u(`

                                      Server Configuration

                                      You need a server outside the firewall to run server-side Xray. The configuration is as follows:

                                      {
                                      +import{_ as c,r as o,o as l,c as r,a,b as s,d as n,w as e,e as u}from"./app-D7uBbsY3.js";const d={},v=s("h1",{id:"configure-and-run",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#configure-and-run"},[s("span",null,"Configure and Run")])],-1),k={href:"https://github.com/XTLS/Xray-examples",target:"_blank",rel:"noopener noreferrer"},m=u(`

                                      Server Configuration

                                      You need a server outside the firewall to run server-side Xray. The configuration is as follows:

                                      {
                                         "inbounds": [
                                           {
                                             "port": 10086, // The port on which the server is listening
                                      diff --git a/assets/dagre-CQ6OS2HX-BRwnzFkj.js b/assets/dagre-CQ6OS2HX-BAsLDm3b.js
                                      similarity index 97%
                                      rename from assets/dagre-CQ6OS2HX-BRwnzFkj.js
                                      rename to assets/dagre-CQ6OS2HX-BAsLDm3b.js
                                      index 2d1c039388..7b984fb642 100644
                                      --- a/assets/dagre-CQ6OS2HX-BRwnzFkj.js
                                      +++ b/assets/dagre-CQ6OS2HX-BAsLDm3b.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as w,am as T,an as F,ao as M,ap as Y,l as i,d as _,aq as j,ar as H,as as q,ae as z,at as O,au as K,av as Q,aw as U,ax as V}from"./mermaid.core-DapiNGBY.js";import{G as k}from"./graph-Oq3lz9SV.js";import{l as W}from"./layout-7AWYeW5Q.js";import{w as y}from"./json-BFhFIfeY.js";import"./app-DBM4OJyw.js";import"./baseUniq-ZJgB7efo.js";import"./basePickBy-BXIHjUx3.js";import"./clone-B3i2nD77.js";var d=new Map,N=new Map,P=new Map,Z=w(()=>{N.clear(),P.clear(),d.clear()},"clear"),p=w((n,t)=>{const e=N.get(t)||[];return i.trace("In isDescendant",t," ",n," = ",e.includes(n)),e.includes(n)},"isDescendant"),$=w((n,t)=>{const e=N.get(t)||[];return i.info("Descendants of ",t," is ",e),i.info("Edge is ",n),n.v===t||n.w===t?!1:e?e.includes(n.v)||p(n.v,t)||p(n.w,t)||e.includes(n.w):(i.debug("Tilt, ",t,",not in descendants"),!1)},"edgeInCluster"),B=w((n,t,e,o)=>{i.warn("Copying children of ",n,"root",o,"data",t.node(n),o);const l=t.children(n)||[];n!==o&&l.push(n),i.warn("Copying (nodes) clusterId",n,"nodes",l),l.forEach(c=>{if(t.children(c).length>0)B(c,t,e,o);else{const r=t.node(c);i.info("cp ",c," to ",o," with parent ",n),e.setNode(c,r),o!==t.parent(c)&&(i.warn("Setting parent",c,t.parent(c)),e.setParent(c,t.parent(c))),n!==o&&c!==n?(i.debug("Setting parent",c,n),e.setParent(c,n)):(i.info("In copy ",n,"root",o,"data",t.node(n),o),i.debug("Not Setting parent for node=",c,"cluster!==rootId",n!==o,"node!==clusterId",c!==n));const g=t.edges(c);i.debug("Copying Edges",g),g.forEach(a=>{i.info("Edge",a);const u=t.edge(a.v,a.w,a.name);i.info("Edge data",u,o);try{$(a,o)?(i.info("Copying as ",a.v,a.w,u,a.name),e.setEdge(a.v,a.w,u,a.name),i.info("newGraph edges ",e.edges(),e.edge(e.edges()[0]))):i.info("Skipping copy of edge ",a.v,"-->",a.w," rootId: ",o," clusterId:",n)}catch(X){i.error(X)}})}i.debug("Removing node",c),t.removeNode(c)})},"copy"),J=w((n,t)=>{const e=t.children(n);let o=[...e];for(const l of e)P.set(l,n),o=[...o,...J(l,t)];return o},"extractDescendants"),L=w((n,t,e)=>{const o=n.edges().filter(a=>a.v===t||a.w===t),l=n.edges().filter(a=>a.v===e||a.w===e),c=o.map(a=>({v:a.v===t?e:a.v,w:a.w===t?t:a.w})),r=l.map(a=>({v:a.v,w:a.w}));return c.filter(a=>r.some(u=>a.v===u.v&&a.w===u.w))},"findCommonEdges"),C=w((n,t,e)=>{const o=t.children(n);if(i.trace("Searching children of id ",n,o),o.length<1)return n;let l;for(const c of o){const r=C(c,t,e),g=L(t,e,r);if(r)if(g.length>0)l=r;else return r}return l},"findNonClusterChild"),S=w(n=>!d.has(n)||!d.get(n).externalConnections?n:d.has(n)?d.get(n).id:n,"getAnchorId"),I=w((n,t)=>{if(!n||t>10){i.debug("Opting out, no graph ");return}else i.debug("Opting in, graph ");n.nodes().forEach(function(e){n.children(e).length>0&&(i.warn("Cluster identified",e," Replacement id in edges: ",C(e,n,e)),N.set(e,J(e,n)),d.set(e,{id:C(e,n,e),clusterData:n.node(e)}))}),n.nodes().forEach(function(e){const o=n.children(e),l=n.edges();o.length>0?(i.debug("Cluster identified",e,N),l.forEach(c=>{const r=p(c.v,e),g=p(c.w,e);r^g&&(i.warn("Edge: ",c," leaves cluster ",e),i.warn("Descendants of XXX ",e,": ",N.get(e)),d.get(e).externalConnections=!0)})):i.debug("Not a cluster ",e,N)});for(let e of d.keys()){const o=d.get(e).id,l=n.parent(o);l!==e&&d.has(l)&&!d.get(l).externalConnections&&(d.get(e).id=l)}n.edges().forEach(function(e){const o=n.edge(e);i.warn("Edge "+e.v+" -> "+e.w+": "+JSON.stringify(e)),i.warn("Edge "+e.v+" -> "+e.w+": "+JSON.stringify(n.edge(e)));let l=e.v,c=e.w;if(i.warn("Fix XXX",d,"ids:",e.v,e.w,"Translating: ",d.get(e.v)," --- ",d.get(e.w)),d.get(e.v)&&d.get(e.w)&&d.get(e.v)===d.get(e.w)){i.warn("Fixing and trying link to self - removing XXX",e.v,e.w,e.name),i.warn("Fixing and trying - removing XXX",e.v,e.w,e.name),l=S(e.v),c=S(e.w),n.removeEdge(e.v,e.w,e.name);const r=e.w+"---"+e.v+"---1",g=e.w+"---"+e.v+"---2";n.setNode(r,{domId:r,id:r,labelStyle:"",label:"",padding:0,shape:"labelRect",style:"",width:10,height:10}),n.setNode(g,{domId:g,id:g,labelStyle:"",padding:0,shape:"labelRect",style:"",width:10,height:10});const a=structuredClone(o),u=structuredClone(o),X=structuredClone(o);a.label="",a.arrowTypeEnd="none",a.id=e.name+"-cyclic-special-1",u.arrowTypeEnd="none",u.id=e.name+"-cyclic-special-mid",X.label="",a.fromCluster=e.v,X.toCluster=e.v,X.id=e.name+"-cyclic-special-2",n.setEdge(l,r,a,e.name+"-cyclic-special-0"),n.setEdge(r,g,u,e.name+"-cyclic-special-1"),n.setEdge(g,c,X,e.name+"-cyclic-special-2")}else if(d.get(e.v)||d.get(e.w)){if(i.warn("Fixing and trying - removing XXX",e.v,e.w,e.name),l=S(e.v),c=S(e.w),n.removeEdge(e.v,e.w,e.name),l!==e.v){const r=n.parent(l);d.get(r).externalConnections=!0,o.fromCluster=e.v}if(c!==e.w){const r=n.parent(c);d.get(r).externalConnections=!0,o.toCluster=e.w}i.warn("Fix Replacing with XXX",l,c,e.name),n.setEdge(l,c,o,e.name)}}),i.warn("Adjusted Graph",y(n)),A(n,0),i.trace(d)},"adjustClustersAndEdges"),A=w((n,t)=>{var l,c;if(i.warn("extractor - ",t,y(n),n.children("D")),t>10){i.error("Bailing out");return}let e=n.nodes(),o=!1;for(const r of e){const g=n.children(r);o=o||g.length>0}if(!o){i.debug("Done, no node has children",n.nodes());return}i.debug("Nodes = ",e,t);for(const r of e)if(i.debug("Extracting node",r,d,d.has(r)&&!d.get(r).externalConnections,!n.parent(r),n.node(r),n.children("D")," Depth ",t),!d.has(r))i.debug("Not a cluster",r,t);else if(!d.get(r).externalConnections&&n.children(r)&&n.children(r).length>0){i.warn("Cluster without external connections, without a parent and with children",r,t);let a=n.graph().rankdir==="TB"?"LR":"TB";(c=(l=d.get(r))==null?void 0:l.clusterData)!=null&&c.dir&&(a=d.get(r).clusterData.dir,i.warn("Fixing dir",d.get(r).clusterData.dir,a));const u=new k({multigraph:!0,compound:!0}).setGraph({rankdir:a,nodesep:50,ranksep:50,marginx:8,marginy:8}).setDefaultEdgeLabel(function(){return{}});i.warn("Old graph before copy",y(n)),B(r,n,u,r),n.setNode(r,{clusterNode:!0,id:r,clusterData:d.get(r).clusterData,label:d.get(r).label,graph:u}),i.warn("New graph after copy node: (",r,")",y(u)),i.debug("Old graph after copy",y(n))}else i.warn("Cluster ** ",r," **not meeting the criteria !externalConnections:",!d.get(r).externalConnections," no parent: ",!n.parent(r)," children ",n.children(r)&&n.children(r).length>0,n.children("D"),t),i.debug(d);e=n.nodes(),i.warn("New list of nodes",e);for(const r of e){const g=n.node(r);i.warn(" Now next level",r,g),g.clusterNode&&A(g.graph,t+1)}},"extractor"),R=w((n,t)=>{if(t.length===0)return[];let e=Object.assign([],t);return t.forEach(o=>{const l=n.children(o),c=R(n,l);e=[...e,...c]}),e},"sorter"),ee=w(n=>R(n,n.children()),"sortNodesByHierarchy"),G=w(async(n,t,e,o,l,c)=>{i.info("Graph in recursive render: XXX",y(t),l);const r=t.graph().rankdir;i.trace("Dir in recursive render - dir:",r);const g=n.insert("g").attr("class","root");t.nodes()?i.info("Recursive render XXX",t.nodes()):i.info("No nodes found for",t),t.edges().length>0&&i.info("Recursive edges",t.edge(t.edges()[0]));const a=g.insert("g").attr("class","clusters"),u=g.insert("g").attr("class","edgePaths"),X=g.insert("g").attr("class","edgeLabels"),m=g.insert("g").attr("class","nodes");await Promise.all(t.nodes().map(async function(f){const s=t.node(f);if(l!==void 0){const v=JSON.parse(JSON.stringify(l.clusterData));i.trace(`Setting data for parent cluster XXX
                                      +import{_ as w,am as T,an as F,ao as M,ap as Y,l as i,d as _,aq as j,ar as H,as as q,ae as z,at as O,au as K,av as Q,aw as U,ax as V}from"./mermaid.core-D8igZDel.js";import{G as k}from"./graph-Cjb-DGHB.js";import{l as W}from"./layout-CHeuV-iP.js";import{w as y}from"./json-31kD9U7J.js";import"./app-D7uBbsY3.js";import"./baseUniq-D0lZO5yp.js";import"./basePickBy-DpnmgMOi.js";import"./clone-DWnk59eF.js";var d=new Map,N=new Map,P=new Map,Z=w(()=>{N.clear(),P.clear(),d.clear()},"clear"),p=w((n,t)=>{const e=N.get(t)||[];return i.trace("In isDescendant",t," ",n," = ",e.includes(n)),e.includes(n)},"isDescendant"),$=w((n,t)=>{const e=N.get(t)||[];return i.info("Descendants of ",t," is ",e),i.info("Edge is ",n),n.v===t||n.w===t?!1:e?e.includes(n.v)||p(n.v,t)||p(n.w,t)||e.includes(n.w):(i.debug("Tilt, ",t,",not in descendants"),!1)},"edgeInCluster"),B=w((n,t,e,o)=>{i.warn("Copying children of ",n,"root",o,"data",t.node(n),o);const l=t.children(n)||[];n!==o&&l.push(n),i.warn("Copying (nodes) clusterId",n,"nodes",l),l.forEach(c=>{if(t.children(c).length>0)B(c,t,e,o);else{const r=t.node(c);i.info("cp ",c," to ",o," with parent ",n),e.setNode(c,r),o!==t.parent(c)&&(i.warn("Setting parent",c,t.parent(c)),e.setParent(c,t.parent(c))),n!==o&&c!==n?(i.debug("Setting parent",c,n),e.setParent(c,n)):(i.info("In copy ",n,"root",o,"data",t.node(n),o),i.debug("Not Setting parent for node=",c,"cluster!==rootId",n!==o,"node!==clusterId",c!==n));const g=t.edges(c);i.debug("Copying Edges",g),g.forEach(a=>{i.info("Edge",a);const u=t.edge(a.v,a.w,a.name);i.info("Edge data",u,o);try{$(a,o)?(i.info("Copying as ",a.v,a.w,u,a.name),e.setEdge(a.v,a.w,u,a.name),i.info("newGraph edges ",e.edges(),e.edge(e.edges()[0]))):i.info("Skipping copy of edge ",a.v,"-->",a.w," rootId: ",o," clusterId:",n)}catch(X){i.error(X)}})}i.debug("Removing node",c),t.removeNode(c)})},"copy"),J=w((n,t)=>{const e=t.children(n);let o=[...e];for(const l of e)P.set(l,n),o=[...o,...J(l,t)];return o},"extractDescendants"),L=w((n,t,e)=>{const o=n.edges().filter(a=>a.v===t||a.w===t),l=n.edges().filter(a=>a.v===e||a.w===e),c=o.map(a=>({v:a.v===t?e:a.v,w:a.w===t?t:a.w})),r=l.map(a=>({v:a.v,w:a.w}));return c.filter(a=>r.some(u=>a.v===u.v&&a.w===u.w))},"findCommonEdges"),C=w((n,t,e)=>{const o=t.children(n);if(i.trace("Searching children of id ",n,o),o.length<1)return n;let l;for(const c of o){const r=C(c,t,e),g=L(t,e,r);if(r)if(g.length>0)l=r;else return r}return l},"findNonClusterChild"),S=w(n=>!d.has(n)||!d.get(n).externalConnections?n:d.has(n)?d.get(n).id:n,"getAnchorId"),I=w((n,t)=>{if(!n||t>10){i.debug("Opting out, no graph ");return}else i.debug("Opting in, graph ");n.nodes().forEach(function(e){n.children(e).length>0&&(i.warn("Cluster identified",e," Replacement id in edges: ",C(e,n,e)),N.set(e,J(e,n)),d.set(e,{id:C(e,n,e),clusterData:n.node(e)}))}),n.nodes().forEach(function(e){const o=n.children(e),l=n.edges();o.length>0?(i.debug("Cluster identified",e,N),l.forEach(c=>{const r=p(c.v,e),g=p(c.w,e);r^g&&(i.warn("Edge: ",c," leaves cluster ",e),i.warn("Descendants of XXX ",e,": ",N.get(e)),d.get(e).externalConnections=!0)})):i.debug("Not a cluster ",e,N)});for(let e of d.keys()){const o=d.get(e).id,l=n.parent(o);l!==e&&d.has(l)&&!d.get(l).externalConnections&&(d.get(e).id=l)}n.edges().forEach(function(e){const o=n.edge(e);i.warn("Edge "+e.v+" -> "+e.w+": "+JSON.stringify(e)),i.warn("Edge "+e.v+" -> "+e.w+": "+JSON.stringify(n.edge(e)));let l=e.v,c=e.w;if(i.warn("Fix XXX",d,"ids:",e.v,e.w,"Translating: ",d.get(e.v)," --- ",d.get(e.w)),d.get(e.v)&&d.get(e.w)&&d.get(e.v)===d.get(e.w)){i.warn("Fixing and trying link to self - removing XXX",e.v,e.w,e.name),i.warn("Fixing and trying - removing XXX",e.v,e.w,e.name),l=S(e.v),c=S(e.w),n.removeEdge(e.v,e.w,e.name);const r=e.w+"---"+e.v+"---1",g=e.w+"---"+e.v+"---2";n.setNode(r,{domId:r,id:r,labelStyle:"",label:"",padding:0,shape:"labelRect",style:"",width:10,height:10}),n.setNode(g,{domId:g,id:g,labelStyle:"",padding:0,shape:"labelRect",style:"",width:10,height:10});const a=structuredClone(o),u=structuredClone(o),X=structuredClone(o);a.label="",a.arrowTypeEnd="none",a.id=e.name+"-cyclic-special-1",u.arrowTypeEnd="none",u.id=e.name+"-cyclic-special-mid",X.label="",a.fromCluster=e.v,X.toCluster=e.v,X.id=e.name+"-cyclic-special-2",n.setEdge(l,r,a,e.name+"-cyclic-special-0"),n.setEdge(r,g,u,e.name+"-cyclic-special-1"),n.setEdge(g,c,X,e.name+"-cyclic-special-2")}else if(d.get(e.v)||d.get(e.w)){if(i.warn("Fixing and trying - removing XXX",e.v,e.w,e.name),l=S(e.v),c=S(e.w),n.removeEdge(e.v,e.w,e.name),l!==e.v){const r=n.parent(l);d.get(r).externalConnections=!0,o.fromCluster=e.v}if(c!==e.w){const r=n.parent(c);d.get(r).externalConnections=!0,o.toCluster=e.w}i.warn("Fix Replacing with XXX",l,c,e.name),n.setEdge(l,c,o,e.name)}}),i.warn("Adjusted Graph",y(n)),A(n,0),i.trace(d)},"adjustClustersAndEdges"),A=w((n,t)=>{var l,c;if(i.warn("extractor - ",t,y(n),n.children("D")),t>10){i.error("Bailing out");return}let e=n.nodes(),o=!1;for(const r of e){const g=n.children(r);o=o||g.length>0}if(!o){i.debug("Done, no node has children",n.nodes());return}i.debug("Nodes = ",e,t);for(const r of e)if(i.debug("Extracting node",r,d,d.has(r)&&!d.get(r).externalConnections,!n.parent(r),n.node(r),n.children("D")," Depth ",t),!d.has(r))i.debug("Not a cluster",r,t);else if(!d.get(r).externalConnections&&n.children(r)&&n.children(r).length>0){i.warn("Cluster without external connections, without a parent and with children",r,t);let a=n.graph().rankdir==="TB"?"LR":"TB";(c=(l=d.get(r))==null?void 0:l.clusterData)!=null&&c.dir&&(a=d.get(r).clusterData.dir,i.warn("Fixing dir",d.get(r).clusterData.dir,a));const u=new k({multigraph:!0,compound:!0}).setGraph({rankdir:a,nodesep:50,ranksep:50,marginx:8,marginy:8}).setDefaultEdgeLabel(function(){return{}});i.warn("Old graph before copy",y(n)),B(r,n,u,r),n.setNode(r,{clusterNode:!0,id:r,clusterData:d.get(r).clusterData,label:d.get(r).label,graph:u}),i.warn("New graph after copy node: (",r,")",y(u)),i.debug("Old graph after copy",y(n))}else i.warn("Cluster ** ",r," **not meeting the criteria !externalConnections:",!d.get(r).externalConnections," no parent: ",!n.parent(r)," children ",n.children(r)&&n.children(r).length>0,n.children("D"),t),i.debug(d);e=n.nodes(),i.warn("New list of nodes",e);for(const r of e){const g=n.node(r);i.warn(" Now next level",r,g),g.clusterNode&&A(g.graph,t+1)}},"extractor"),R=w((n,t)=>{if(t.length===0)return[];let e=Object.assign([],t);return t.forEach(o=>{const l=n.children(o),c=R(n,l);e=[...e,...c]}),e},"sorter"),ee=w(n=>R(n,n.children()),"sortNodesByHierarchy"),G=w(async(n,t,e,o,l,c)=>{i.info("Graph in recursive render: XXX",y(t),l);const r=t.graph().rankdir;i.trace("Dir in recursive render - dir:",r);const g=n.insert("g").attr("class","root");t.nodes()?i.info("Recursive render XXX",t.nodes()):i.info("No nodes found for",t),t.edges().length>0&&i.info("Recursive edges",t.edge(t.edges()[0]));const a=g.insert("g").attr("class","clusters"),u=g.insert("g").attr("class","edgePaths"),X=g.insert("g").attr("class","edgeLabels"),m=g.insert("g").attr("class","nodes");await Promise.all(t.nodes().map(async function(f){const s=t.node(f);if(l!==void 0){const v=JSON.parse(JSON.stringify(l.clusterData));i.trace(`Setting data for parent cluster XXX
                                        Node.id = `,f,`
                                        data=`,v.height,`
                                       Parent cluster`,l.height),t.setNode(l.id,v),t.parent(f)||(i.trace("Setting parent",f,l.id),t.setParent(f,l.id,v))}if(i.info("(Insert) Node XXX"+f+": "+JSON.stringify(t.node(f))),s!=null&&s.clusterNode){i.info("Cluster identified XBX",f,s.width,t.node(f));const{ranksep:v,nodesep:h}=t.graph();s.graph.setGraph({...s.graph.graph(),ranksep:v+25,nodesep:h});const E=await G(m,s.graph,e,o,t.node(f),c),b=E.elem;j(s,b),s.diff=E.diff||0,i.info("New compound node after recursive render XAX",f,"width",s.width,"height",s.height),H(b,s)}else t.children(f).length>0?(i.info("Cluster - the non recursive path XBX",f,s.id,s,s.width,"Graph:",t),i.info(C(s.id,t)),d.set(s.id,{id:C(s.id,t),node:s})):(i.trace("Node - the non recursive path XAX",f,s.id,s),await q(m,t.node(f),r))})),await w(async()=>{const f=t.edges().map(async function(s){const v=t.edge(s.v,s.w,s.name);i.info("Edge "+s.v+" -> "+s.w+": "+JSON.stringify(s)),i.info("Edge "+s.v+" -> "+s.w+": ",s," ",JSON.stringify(t.edge(s))),i.info("Fix",d,"ids:",s.v,s.w,"Translating: ",d.get(s.v),d.get(s.w)),await V(X,v)});await Promise.all(f)},"processEdges")(),i.info("Graph before layout:",JSON.stringify(y(t))),i.info("############################################# XXX"),i.info("###                Layout                 ### XXX"),i.info("############################################# XXX"),W(t),i.info("Graph after layout:",JSON.stringify(y(t)));let D=0,{subGraphTitleTotalMargin:x}=z(c);return await Promise.all(ee(t).map(async function(f){var v;const s=t.node(f);if(i.info("Position XBX => "+f+": ("+s.x,","+s.y,") width: ",s.width," height: ",s.height),s!=null&&s.clusterNode)s.y+=x,i.info("A tainted cluster node XBX1",f,s.id,s.width,s.height,s.x,s.y,t.parent(f)),d.get(s.id).node=s,O(s);else if(t.children(f).length>0){i.info("A pure cluster node XBX1",f,s.id,s.x,s.y,s.width,s.height,t.parent(f)),s.height+=x,t.node(s.parentId);const h=(s==null?void 0:s.padding)/2||0,E=((v=s==null?void 0:s.labelBBox)==null?void 0:v.height)||0,b=E-h||0;i.debug("OffsetY",b,"labelHeight",E,"halfPadding",h),await K(a,s),d.get(s.id).node=s}else{const h=t.node(s.parentId);s.y+=x/2,i.info("A regular node XBX1 - using the padding",s.id,"parent",s.parentId,s.width,s.height,s.x,s.y,"offsetY",s.offsetY,"parent",h,h==null?void 0:h.offsetY,s),O(s)}})),t.edges().forEach(function(f){const s=t.edge(f);i.info("Edge "+f.v+" -> "+f.w+": "+JSON.stringify(s),s),s.points.forEach(b=>b.y+=x/2);const v=t.node(f.v);var h=t.node(f.w);const E=Q(u,s,d,e,v,h,o);U(s,E)}),t.nodes().forEach(function(f){const s=t.node(f);i.info(f,s.type,s.diff),s.isGroup&&(D=s.diff)}),i.warn("Returning from recursive render XAX",g,D),{elem:g,diff:D}},"recursiveRender"),le=w(async(n,t)=>{var c,r,g,a,u,X;const e=new k({multigraph:!0,compound:!0}).setGraph({rankdir:n.direction,nodesep:((c=n.config)==null?void 0:c.nodeSpacing)||((g=(r=n.config)==null?void 0:r.flowchart)==null?void 0:g.nodeSpacing)||n.nodeSpacing,ranksep:((a=n.config)==null?void 0:a.rankSpacing)||((X=(u=n.config)==null?void 0:u.flowchart)==null?void 0:X.rankSpacing)||n.rankSpacing,marginx:8,marginy:8}).setDefaultEdgeLabel(function(){return{}}),o=t.select("g");T(o,n.markers,n.type,n.diagramId),F(),M(),Y(),Z(),n.nodes.forEach(m=>{e.setNode(m.id,{...m}),m.parentId&&e.setParent(m.id,m.parentId)}),i.debug("Edges:",n.edges),n.edges.forEach(m=>{e.setEdge(m.start,m.end,{...m},m.id)}),i.warn("Graph at first:",JSON.stringify(y(e))),I(e),i.warn("Graph after:",JSON.stringify(y(e)));const l=_();await G(o,e,n.type,n.diagramId,void 0,l)},"render");export{le as render};
                                      diff --git a/assets/design.html-Tm1rZHD2.js b/assets/design.html-B_2qYX1J.js
                                      similarity index 97%
                                      rename from assets/design.html-Tm1rZHD2.js
                                      rename to assets/design.html-B_2qYX1J.js
                                      index a4c2a5d989..583a12cd17 100644
                                      --- a/assets/design.html-Tm1rZHD2.js
                                      +++ b/assets/design.html-B_2qYX1J.js
                                      @@ -1 +1 @@
                                      -import{_ as l,r as t,o as c,c as i,a as o,b as e,d as n,w as h,e as d}from"./app-DBM4OJyw.js";const _="/assets/framework-Bf6xCZ4u.png",p={},u=d('

                                      设计目标

                                      • Xray 内核提供了一个平台,支持必要的网络代理功能,在其之上可以进二次开发,以提供更好的用户体验;
                                      • 以跨平台为首要原则,以减少二次开发的成本;

                                      架构

                                      Architecture

                                      内核分为三层:应用层、代理层和传输层。

                                      每一层内包含数个模块,模块间互相独立,同类型的模块可无缝替换。

                                      应用层

                                      应用层包含一些代理层中常用的功能,这些功能被抽象出来,以便在不同的代理模块中复用。

                                      应用层的模块应为纯软件实现,与硬件或平台相关的技术无关。

                                      重要模块列表:

                                      ',10),x=e("li",null,"Dispatcher: 用于把入站代理所接收到的数据,传送给出站代理;",-1),f=e("li",null,"DNS: 内置的 DNS 服务器模块;",-1),b=e("li",null,"Proxy Manager: 代理管理器;",-1),m=e("h3",{id:"代理层",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#代理层"},[e("span",null,"代理层")])],-1),g=e("p",null,"代理层分为两部分:入站代理(Inbound Proxy)和出站代理(Outbound Proxy)。",-1),y=e("p",null,"两部分相互独立,入站代理不依赖于某个特定的出站代理,反之亦然。",-1),k=e("h4",{id:"入站代理",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#入站代理"},[e("span",null,"入站代理")])],-1),I={href:"https://github.com/xtls/Xray-core/blob/main/proxy/proxy.go",target:"_blank",rel:"noopener noreferrer"},N=e("h4",{id:"出站代理",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#出站代理"},[e("span",null,"出站代理")])],-1),B={href:"https://github.com/xtls/Xray-core/blob/main/proxy/proxy.go",target:"_blank",rel:"noopener noreferrer"},L=e("h3",{id:"传输层",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#传输层"},[e("span",null,"传输层")])],-1),V=e("p",null,"传输层提供一些网络数据传输相关的工具模块。",-1);function v(w,C){const r=t("I18nTip"),s=t("RouterLink"),a=t("ExternalLinkIcon");return c(),i("div",null,[o(r),u,e("ul",null,[x,e("li",null,[n("Router: 路由模块,详见 "),o(s,{to:"/ru/config/routing.html"},{default:h(()=>[n("路由配置")]),_:1}),n(";")]),f,b]),m,g,y,k,e("ul",null,[e("li",null,[n("实现 "),e("a",I,[n("proxy.Inbound"),o(a)]),n(" 接口;")])]),N,e("ul",null,[e("li",null,[n("实现 "),e("a",B,[n("proxy.Outbound"),o(a)]),n(" 接口;")])]),L,V])}const E=l(p,[["render",v],["__file","design.html.vue"]]);export{E as default}; +import{_ as l,r as t,o as c,c as i,a as o,b as e,d as n,w as h,e as d}from"./app-D7uBbsY3.js";const _="/assets/framework-Bf6xCZ4u.png",p={},u=d('

                                      设计目标

                                      • Xray 内核提供了一个平台,支持必要的网络代理功能,在其之上可以进二次开发,以提供更好的用户体验;
                                      • 以跨平台为首要原则,以减少二次开发的成本;

                                      架构

                                      Architecture

                                      内核分为三层:应用层、代理层和传输层。

                                      每一层内包含数个模块,模块间互相独立,同类型的模块可无缝替换。

                                      应用层

                                      应用层包含一些代理层中常用的功能,这些功能被抽象出来,以便在不同的代理模块中复用。

                                      应用层的模块应为纯软件实现,与硬件或平台相关的技术无关。

                                      重要模块列表:

                                      ',10),x=e("li",null,"Dispatcher: 用于把入站代理所接收到的数据,传送给出站代理;",-1),f=e("li",null,"DNS: 内置的 DNS 服务器模块;",-1),b=e("li",null,"Proxy Manager: 代理管理器;",-1),m=e("h3",{id:"代理层",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#代理层"},[e("span",null,"代理层")])],-1),g=e("p",null,"代理层分为两部分:入站代理(Inbound Proxy)和出站代理(Outbound Proxy)。",-1),y=e("p",null,"两部分相互独立,入站代理不依赖于某个特定的出站代理,反之亦然。",-1),k=e("h4",{id:"入站代理",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#入站代理"},[e("span",null,"入站代理")])],-1),I={href:"https://github.com/xtls/Xray-core/blob/main/proxy/proxy.go",target:"_blank",rel:"noopener noreferrer"},N=e("h4",{id:"出站代理",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#出站代理"},[e("span",null,"出站代理")])],-1),B={href:"https://github.com/xtls/Xray-core/blob/main/proxy/proxy.go",target:"_blank",rel:"noopener noreferrer"},L=e("h3",{id:"传输层",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#传输层"},[e("span",null,"传输层")])],-1),V=e("p",null,"传输层提供一些网络数据传输相关的工具模块。",-1);function v(w,C){const r=t("I18nTip"),s=t("RouterLink"),a=t("ExternalLinkIcon");return c(),i("div",null,[o(r),u,e("ul",null,[x,e("li",null,[n("Router: 路由模块,详见 "),o(s,{to:"/ru/config/routing.html"},{default:h(()=>[n("路由配置")]),_:1}),n(";")]),f,b]),m,g,y,k,e("ul",null,[e("li",null,[n("实现 "),e("a",I,[n("proxy.Inbound"),o(a)]),n(" 接口;")])]),N,e("ul",null,[e("li",null,[n("实现 "),e("a",B,[n("proxy.Outbound"),o(a)]),n(" 接口;")])]),L,V])}const E=l(p,[["render",v],["__file","design.html.vue"]]);export{E as default}; diff --git a/assets/design.html-CLTK1zJY.js b/assets/design.html-CPqW5c51.js similarity index 98% rename from assets/design.html-CLTK1zJY.js rename to assets/design.html-CPqW5c51.js index d55bce19f3..8adca58c0d 100644 --- a/assets/design.html-CLTK1zJY.js +++ b/assets/design.html-CPqW5c51.js @@ -1 +1 @@ -import{_ as i,r as t,o as l,c as d,a as n,b as e,d as o,w as p,e as c}from"./app-DBM4OJyw.js";const h="/assets/framework-Bf6xCZ4u.png",u={},y=c('

                                      Design Objectives

                                      • Xray Kernel provides a platform that supports essential network proxy functions and can be developed upon to provide a better user experience.
                                      • Cross-platform is the primary principle to reduce the cost of secondary development.

                                      Architecture

                                      Architecture

                                      The kernel is divided into three layers: the application layer, the proxy layer, and the transport layer.

                                      Each layer contains several modules, which are independent of each other. Modules of the same type can be seamlessly replaced.

                                      Application Layer

                                      The application layer contains some commonly used functions in proxy layers, which are abstracted for reuse in different proxy modules.

                                      The modules at the application layer should be implemented purely in software and should not be dependent on hardware or platform-related technologies.

                                      List of Important Modules:

                                      ',10),_=e("li",null,"Dispatcher: Used to transfer data received by the inbound agent to the outbound agent;",-1),x=e("li",null,"DNS: Built-in DNS server module;",-1),f=e("li",null,"Proxy Manager: Proxy manager;",-1),m=e("h3",{id:"proxy-layer",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#proxy-layer"},[e("span",null,"Proxy Layer")])],-1),b=e("p",null,"The proxy layer is divided into two parts: Inbound Proxy and Outbound Proxy.",-1),g=e("p",null,"The two parts are independent of each other, where the inbound proxy does not rely on a specific outbound proxy, and vice versa.",-1),v=e("h4",{id:"inbound-proxy",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#inbound-proxy"},[e("span",null,"Inbound Proxy")])],-1),k={href:"https://github.com/xtls/Xray-core/blob/main/proxy/proxy.go",target:"_blank",rel:"noopener noreferrer"},w=e("h4",{id:"outbound-proxy",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#outbound-proxy"},[e("span",null,"Outbound Proxy")])],-1),I={href:"https://github.com/xtls/Xray-core/blob/main/proxy/proxy.go",target:"_blank",rel:"noopener noreferrer"},T=e("h3",{id:"transport-layer",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#transport-layer"},[e("span",null,"Transport Layer")])],-1),L=e("p",null,"The transport layer provides a set of tools and modules related to network data transmission.",-1);function P(N,B){const a=t("I18nTip"),s=t("RouterLink"),r=t("ExternalLinkIcon");return l(),d("div",null,[n(a),y,e("ul",null,[_,e("li",null,[o("Router: Routing module, see "),n(s,{to:"/en/config/routing.html"},{default:p(()=>[o("Routing Configuration")]),_:1}),o(" for details;")]),x,f]),m,b,g,v,e("ul",null,[e("li",null,[o("Implement the "),e("a",k,[o("proxy.Inbound"),n(r)]),o(" interface;")])]),w,e("ul",null,[e("li",null,[o("Implement the "),e("a",I,[o("proxy.Outbound"),n(r)]),o(" interface;")])]),T,L])}const R=i(u,[["render",P],["__file","design.html.vue"]]);export{R as default}; +import{_ as i,r as t,o as l,c as d,a as n,b as e,d as o,w as p,e as c}from"./app-D7uBbsY3.js";const h="/assets/framework-Bf6xCZ4u.png",u={},y=c('

                                      Design Objectives

                                      • Xray Kernel provides a platform that supports essential network proxy functions and can be developed upon to provide a better user experience.
                                      • Cross-platform is the primary principle to reduce the cost of secondary development.

                                      Architecture

                                      Architecture

                                      The kernel is divided into three layers: the application layer, the proxy layer, and the transport layer.

                                      Each layer contains several modules, which are independent of each other. Modules of the same type can be seamlessly replaced.

                                      Application Layer

                                      The application layer contains some commonly used functions in proxy layers, which are abstracted for reuse in different proxy modules.

                                      The modules at the application layer should be implemented purely in software and should not be dependent on hardware or platform-related technologies.

                                      List of Important Modules:

                                      ',10),_=e("li",null,"Dispatcher: Used to transfer data received by the inbound agent to the outbound agent;",-1),x=e("li",null,"DNS: Built-in DNS server module;",-1),f=e("li",null,"Proxy Manager: Proxy manager;",-1),m=e("h3",{id:"proxy-layer",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#proxy-layer"},[e("span",null,"Proxy Layer")])],-1),b=e("p",null,"The proxy layer is divided into two parts: Inbound Proxy and Outbound Proxy.",-1),g=e("p",null,"The two parts are independent of each other, where the inbound proxy does not rely on a specific outbound proxy, and vice versa.",-1),v=e("h4",{id:"inbound-proxy",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#inbound-proxy"},[e("span",null,"Inbound Proxy")])],-1),k={href:"https://github.com/xtls/Xray-core/blob/main/proxy/proxy.go",target:"_blank",rel:"noopener noreferrer"},w=e("h4",{id:"outbound-proxy",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#outbound-proxy"},[e("span",null,"Outbound Proxy")])],-1),I={href:"https://github.com/xtls/Xray-core/blob/main/proxy/proxy.go",target:"_blank",rel:"noopener noreferrer"},T=e("h3",{id:"transport-layer",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#transport-layer"},[e("span",null,"Transport Layer")])],-1),L=e("p",null,"The transport layer provides a set of tools and modules related to network data transmission.",-1);function P(N,B){const a=t("I18nTip"),s=t("RouterLink"),r=t("ExternalLinkIcon");return l(),d("div",null,[n(a),y,e("ul",null,[_,e("li",null,[o("Router: Routing module, see "),n(s,{to:"/en/config/routing.html"},{default:p(()=>[o("Routing Configuration")]),_:1}),o(" for details;")]),x,f]),m,b,g,v,e("ul",null,[e("li",null,[o("Implement the "),e("a",k,[o("proxy.Inbound"),n(r)]),o(" interface;")])]),w,e("ul",null,[e("li",null,[o("Implement the "),e("a",I,[o("proxy.Outbound"),n(r)]),o(" interface;")])]),T,L])}const R=i(u,[["render",P],["__file","design.html.vue"]]);export{R as default}; diff --git a/assets/design.html-Cz-hmEoU.js b/assets/design.html-DiDr282f.js similarity index 97% rename from assets/design.html-Cz-hmEoU.js rename to assets/design.html-DiDr282f.js index dc1d3ac6d0..f284bde190 100644 --- a/assets/design.html-Cz-hmEoU.js +++ b/assets/design.html-DiDr282f.js @@ -1 +1 @@ -import{_ as l,r as t,o as c,c as i,a as o,b as e,d as n,w as h,e as d}from"./app-DBM4OJyw.js";const _="/assets/framework-Bf6xCZ4u.png",p={},u=d('

                                      设计目标

                                      • Xray 内核提供了一个平台,支持必要的网络代理功能,在其之上可以进二次开发,以提供更好的用户体验;
                                      • 以跨平台为首要原则,以减少二次开发的成本;

                                      架构

                                      Architecture

                                      内核分为三层:应用层、代理层和传输层。

                                      每一层内包含数个模块,模块间互相独立,同类型的模块可无缝替换。

                                      应用层

                                      应用层包含一些代理层中常用的功能,这些功能被抽象出来,以便在不同的代理模块中复用。

                                      应用层的模块应为纯软件实现,与硬件或平台相关的技术无关。

                                      重要模块列表:

                                      ',10),x=e("li",null,"Dispatcher: 用于把入站代理所接收到的数据,传送给出站代理;",-1),f=e("li",null,"DNS: 内置的 DNS 服务器模块;",-1),b=e("li",null,"Proxy Manager: 代理管理器;",-1),m=e("h3",{id:"代理层",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#代理层"},[e("span",null,"代理层")])],-1),g=e("p",null,"代理层分为两部分:入站代理(Inbound Proxy)和出站代理(Outbound Proxy)。",-1),y=e("p",null,"两部分相互独立,入站代理不依赖于某个特定的出站代理,反之亦然。",-1),k=e("h4",{id:"入站代理",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#入站代理"},[e("span",null,"入站代理")])],-1),I={href:"https://github.com/xtls/Xray-core/blob/main/proxy/proxy.go",target:"_blank",rel:"noopener noreferrer"},N=e("h4",{id:"出站代理",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#出站代理"},[e("span",null,"出站代理")])],-1),B={href:"https://github.com/xtls/Xray-core/blob/main/proxy/proxy.go",target:"_blank",rel:"noopener noreferrer"},L=e("h3",{id:"传输层",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#传输层"},[e("span",null,"传输层")])],-1),V=e("p",null,"传输层提供一些网络数据传输相关的工具模块。",-1);function v(w,C){const s=t("I18nTip"),r=t("RouterLink"),a=t("ExternalLinkIcon");return c(),i("div",null,[o(s),u,e("ul",null,[x,e("li",null,[n("Router: 路由模块,详见 "),o(r,{to:"/config/routing.html"},{default:h(()=>[n("路由配置")]),_:1}),n(";")]),f,b]),m,g,y,k,e("ul",null,[e("li",null,[n("实现 "),e("a",I,[n("proxy.Inbound"),o(a)]),n(" 接口;")])]),N,e("ul",null,[e("li",null,[n("实现 "),e("a",B,[n("proxy.Outbound"),o(a)]),n(" 接口;")])]),L,V])}const E=l(p,[["render",v],["__file","design.html.vue"]]);export{E as default}; +import{_ as l,r as t,o as c,c as i,a as o,b as e,d as n,w as h,e as d}from"./app-D7uBbsY3.js";const _="/assets/framework-Bf6xCZ4u.png",p={},u=d('

                                      设计目标

                                      • Xray 内核提供了一个平台,支持必要的网络代理功能,在其之上可以进二次开发,以提供更好的用户体验;
                                      • 以跨平台为首要原则,以减少二次开发的成本;

                                      架构

                                      Architecture

                                      内核分为三层:应用层、代理层和传输层。

                                      每一层内包含数个模块,模块间互相独立,同类型的模块可无缝替换。

                                      应用层

                                      应用层包含一些代理层中常用的功能,这些功能被抽象出来,以便在不同的代理模块中复用。

                                      应用层的模块应为纯软件实现,与硬件或平台相关的技术无关。

                                      重要模块列表:

                                      ',10),x=e("li",null,"Dispatcher: 用于把入站代理所接收到的数据,传送给出站代理;",-1),f=e("li",null,"DNS: 内置的 DNS 服务器模块;",-1),b=e("li",null,"Proxy Manager: 代理管理器;",-1),m=e("h3",{id:"代理层",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#代理层"},[e("span",null,"代理层")])],-1),g=e("p",null,"代理层分为两部分:入站代理(Inbound Proxy)和出站代理(Outbound Proxy)。",-1),y=e("p",null,"两部分相互独立,入站代理不依赖于某个特定的出站代理,反之亦然。",-1),k=e("h4",{id:"入站代理",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#入站代理"},[e("span",null,"入站代理")])],-1),I={href:"https://github.com/xtls/Xray-core/blob/main/proxy/proxy.go",target:"_blank",rel:"noopener noreferrer"},N=e("h4",{id:"出站代理",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#出站代理"},[e("span",null,"出站代理")])],-1),B={href:"https://github.com/xtls/Xray-core/blob/main/proxy/proxy.go",target:"_blank",rel:"noopener noreferrer"},L=e("h3",{id:"传输层",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#传输层"},[e("span",null,"传输层")])],-1),V=e("p",null,"传输层提供一些网络数据传输相关的工具模块。",-1);function v(w,C){const s=t("I18nTip"),r=t("RouterLink"),a=t("ExternalLinkIcon");return c(),i("div",null,[o(s),u,e("ul",null,[x,e("li",null,[n("Router: 路由模块,详见 "),o(r,{to:"/config/routing.html"},{default:h(()=>[n("路由配置")]),_:1}),n(";")]),f,b]),m,g,y,k,e("ul",null,[e("li",null,[n("实现 "),e("a",I,[n("proxy.Inbound"),o(a)]),n(" 接口;")])]),N,e("ul",null,[e("li",null,[n("实现 "),e("a",B,[n("proxy.Outbound"),o(a)]),n(" 接口;")])]),L,V])}const E=l(p,[["render",v],["__file","design.html.vue"]]);export{E as default}; diff --git a/assets/diagram-KYCGQLJB-BEfwcC9f.js b/assets/diagram-KYCGQLJB-BYpHU2_P.js similarity index 91% rename from assets/diagram-KYCGQLJB-BEfwcC9f.js rename to assets/diagram-KYCGQLJB-BYpHU2_P.js index 403c62ff21..f07e051a6f 100644 --- a/assets/diagram-KYCGQLJB-BEfwcC9f.js +++ b/assets/diagram-KYCGQLJB-BYpHU2_P.js @@ -1,4 +1,4 @@ -import{p as w}from"./chunk-JJENOPKO-CSqkWYi8.js";import{F as B,s as S,g as F,q as z,r as P,b as W,c as T,_ as n,l as v,G as x,H as D,t as _,K as A,k as E}from"./mermaid.core-DapiNGBY.js";import{p as N}from"./gitGraph-F2EDSAW4-IXsRUTzt.js";import"./app-DBM4OJyw.js";import"./baseUniq-ZJgB7efo.js";import"./basePickBy-BXIHjUx3.js";import"./clone-B3i2nD77.js";var C={packet:[]},m=structuredClone(C),L=B.packet,Y=n(()=>{const t=x({...L,...D().packet});return t.showBits&&(t.paddingY+=10),t},"getConfig"),G=n(()=>m.packet,"getPacket"),H=n(t=>{t.length>0&&m.packet.push(t)},"pushWord"),I=n(()=>{_(),m=structuredClone(C)},"clear"),h={pushWord:H,getPacket:G,getConfig:Y,clear:I,setAccTitle:S,getAccTitle:F,setDiagramTitle:z,getDiagramTitle:P,getAccDescription:W,setAccDescription:T},K=1e4,M=n(t=>{w(t,h);let e=-1,o=[],s=1;const{bitsPerRow:i}=h.getConfig();for(let{start:a,end:r,label:p}of t.blocks){if(r&&r{if(t.end===void 0&&(t.end=t.start),t.start>t.end)throw new Error(`Block start ${t.start} is greater than block end ${t.end}.`);return t.end+1<=e*o?[t,void 0]:[{start:t.start,end:e*o-1,label:t.label},{start:e*o,end:t.end,label:t.label}]},"getNextFittingBlock"),q={parse:n(async t=>{const e=await N("packet",t);v.debug(e),M(e)},"parse")},R=n((t,e,o,s)=>{const i=s.db,a=i.getConfig(),{rowHeight:r,paddingY:p,bitWidth:b,bitsPerRow:c}=a,u=i.getPacket(),l=i.getDiagramTitle(),g=r+p,d=g*(u.length+1)-(l?0:r),k=b*c+2,f=A(e);f.attr("viewbox",`0 0 ${k} ${d}`),E(f,d,k,a.useMaxWidth);for(const[$,y]of u.entries())U(f,y,$,a);f.append("text").text(l).attr("x",k/2).attr("y",d-g/2).attr("dominant-baseline","middle").attr("text-anchor","middle").attr("class","packetTitle")},"draw"),U=n((t,e,o,{rowHeight:s,paddingX:i,paddingY:a,bitWidth:r,bitsPerRow:p,showBits:b})=>{const c=t.append("g"),u=o*(s+a)+a;for(const l of e){const g=l.start%p*r+1,d=(l.end-l.start+1)*r-i;if(c.append("rect").attr("x",g).attr("y",u).attr("width",d).attr("height",s).attr("class","packetBlock"),c.append("text").attr("x",g+d/2).attr("y",u+s/2).attr("class","packetLabel").attr("dominant-baseline","middle").attr("text-anchor","middle").text(l.label),!b)continue;const k=l.end===l.start,f=u-2;c.append("text").attr("x",g+(k?d/2:0)).attr("y",f).attr("class","packetByte start").attr("dominant-baseline","auto").attr("text-anchor",k?"middle":"start").text(l.start),k||c.append("text").attr("x",g+d).attr("y",f).attr("class","packetByte end").attr("dominant-baseline","auto").attr("text-anchor","end").text(l.end)}},"drawWord"),X={draw:R},j={byteFontSize:"10px",startByteColor:"black",endByteColor:"black",labelColor:"black",labelFontSize:"12px",titleColor:"black",titleFontSize:"14px",blockStrokeColor:"black",blockStrokeWidth:"1",blockFillColor:"#efefef"},J=n(({packet:t}={})=>{const e=x(j,t);return` +import{p as w}from"./chunk-JJENOPKO-7opA8rsx.js";import{F as B,s as S,g as F,q as z,r as P,b as W,c as T,_ as n,l as v,G as x,H as D,t as _,K as A,k as E}from"./mermaid.core-D8igZDel.js";import{p as N}from"./gitGraph-F2EDSAW4-Df57CYyu.js";import"./app-D7uBbsY3.js";import"./baseUniq-D0lZO5yp.js";import"./basePickBy-DpnmgMOi.js";import"./clone-DWnk59eF.js";var C={packet:[]},m=structuredClone(C),L=B.packet,Y=n(()=>{const t=x({...L,...D().packet});return t.showBits&&(t.paddingY+=10),t},"getConfig"),G=n(()=>m.packet,"getPacket"),H=n(t=>{t.length>0&&m.packet.push(t)},"pushWord"),I=n(()=>{_(),m=structuredClone(C)},"clear"),h={pushWord:H,getPacket:G,getConfig:Y,clear:I,setAccTitle:S,getAccTitle:F,setDiagramTitle:z,getDiagramTitle:P,getAccDescription:W,setAccDescription:T},K=1e4,M=n(t=>{w(t,h);let e=-1,o=[],s=1;const{bitsPerRow:i}=h.getConfig();for(let{start:a,end:r,label:p}of t.blocks){if(r&&r{if(t.end===void 0&&(t.end=t.start),t.start>t.end)throw new Error(`Block start ${t.start} is greater than block end ${t.end}.`);return t.end+1<=e*o?[t,void 0]:[{start:t.start,end:e*o-1,label:t.label},{start:e*o,end:t.end,label:t.label}]},"getNextFittingBlock"),q={parse:n(async t=>{const e=await N("packet",t);v.debug(e),M(e)},"parse")},R=n((t,e,o,s)=>{const i=s.db,a=i.getConfig(),{rowHeight:r,paddingY:p,bitWidth:b,bitsPerRow:c}=a,u=i.getPacket(),l=i.getDiagramTitle(),g=r+p,d=g*(u.length+1)-(l?0:r),k=b*c+2,f=A(e);f.attr("viewbox",`0 0 ${k} ${d}`),E(f,d,k,a.useMaxWidth);for(const[$,y]of u.entries())U(f,y,$,a);f.append("text").text(l).attr("x",k/2).attr("y",d-g/2).attr("dominant-baseline","middle").attr("text-anchor","middle").attr("class","packetTitle")},"draw"),U=n((t,e,o,{rowHeight:s,paddingX:i,paddingY:a,bitWidth:r,bitsPerRow:p,showBits:b})=>{const c=t.append("g"),u=o*(s+a)+a;for(const l of e){const g=l.start%p*r+1,d=(l.end-l.start+1)*r-i;if(c.append("rect").attr("x",g).attr("y",u).attr("width",d).attr("height",s).attr("class","packetBlock"),c.append("text").attr("x",g+d/2).attr("y",u+s/2).attr("class","packetLabel").attr("dominant-baseline","middle").attr("text-anchor","middle").text(l.label),!b)continue;const k=l.end===l.start,f=u-2;c.append("text").attr("x",g+(k?d/2:0)).attr("y",f).attr("class","packetByte start").attr("dominant-baseline","auto").attr("text-anchor",k?"middle":"start").text(l.start),k||c.append("text").attr("x",g+d).attr("y",f).attr("class","packetByte end").attr("dominant-baseline","auto").attr("text-anchor","end").text(l.end)}},"drawWord"),X={draw:R},j={byteFontSize:"10px",startByteColor:"black",endByteColor:"black",labelColor:"black",labelFontSize:"12px",titleColor:"black",titleFontSize:"14px",blockStrokeColor:"black",blockStrokeWidth:"1",blockFillColor:"#efefef"},J=n(({packet:t}={})=>{const e=x(j,t);return` .packetByte { font-size: ${e.byteFontSize}; } diff --git a/assets/dns.html-pLhH-MPA.js b/assets/dns.html-36NnIjPg.js similarity index 98% rename from assets/dns.html-pLhH-MPA.js rename to assets/dns.html-36NnIjPg.js index f03d9efe10..8cf34bb6b8 100644 --- a/assets/dns.html-pLhH-MPA.js +++ b/assets/dns.html-36NnIjPg.js @@ -1,4 +1,4 @@ -import{_ as p,r as e,o as d,c as u,a as s,b as o,d as n,w as r,e as l}from"./app-DBM4OJyw.js";const i={},k=o("h1",{id:"dns",tabindex:"-1"},[o("a",{class:"header-anchor",href:"#dns"},[o("span",null,"DNS")])],-1),q=o("p",null,"DNS 是一个出站协议,主要用于拦截和转发 DNS 查询。",-1),b=o("p",null,"此出站协议只能接收 DNS 流量(包含基于 UDP 和 TCP 协议的查询),其它类型的流量会导致错误。",-1),_=o("code",null,"nonIPQuery",-1),h=l(`

                                      OutboundConfigurationObject

                                      {
                                      +import{_ as p,r as e,o as d,c as u,a as s,b as o,d as n,w as r,e as l}from"./app-D7uBbsY3.js";const i={},k=o("h1",{id:"dns",tabindex:"-1"},[o("a",{class:"header-anchor",href:"#dns"},[o("span",null,"DNS")])],-1),q=o("p",null,"DNS 是一个出站协议,主要用于拦截和转发 DNS 查询。",-1),b=o("p",null,"此出站协议只能接收 DNS 流量(包含基于 UDP 和 TCP 协议的查询),其它类型的流量会导致错误。",-1),_=o("code",null,"nonIPQuery",-1),h=l(`

                                      OutboundConfigurationObject

                                      {
                                         "network": "tcp",
                                         "address": "1.1.1.1",
                                         "port": 53,
                                      diff --git a/assets/dns.html-C9qEefIG.js b/assets/dns.html-DAIzKfOg.js
                                      similarity index 99%
                                      rename from assets/dns.html-C9qEefIG.js
                                      rename to assets/dns.html-DAIzKfOg.js
                                      index 052e630fcf..0b6493afbb 100644
                                      --- a/assets/dns.html-C9qEefIG.js
                                      +++ b/assets/dns.html-DAIzKfOg.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as u,r as p,o as l,c as r,a as o,b as s,d as n,w as t,e}from"./app-DBM4OJyw.js";const d={},i=e(`

                                      Встроенный DNS-сервер

                                      DNS-сервер

                                      Встроенный DNS-модуль Xray имеет два основных назначения:

                                      • Разрешение доменных имен в IP-адреса на этапе маршрутизации и сопоставление правил с полученными IP-адресами для разделения трафика.
                                        Разрешение доменных имен и разделение трафика зависят от значения параметра domainStrategy в модуле конфигурации маршрутизации.
                                        Встроенный DNS-сервер будет использоваться для DNS-запросов только при следующих значениях:

                                        • "IPIfNonMatch": при запросе доменного имени Xray сопоставляет его с доменами, указанными в правилах маршрутизации.
                                          Если совпадение не найдено, встроенный DNS-сервер используется для разрешения доменного имени, а затем полученный IP-адрес снова сопоставляется с правилами маршрутизации на основе IP-адресов.
                                        • "IPOnDemand": при сопоставлении правил, основанных на IP-адресах, доменное имя немедленно разрешается в IP-адрес для сопоставления.
                                      • Разрешение целевого адреса для подключения.

                                        • Например, в исходящем подключении freedom, если параметр domainStrategy установлен в UseIP, исходящие запросы будут сначала разрешать доменное имя в IP-адрес с помощью встроенного DNS-сервера, а затем устанавливать соединение.
                                        • Например, в sockopt, если параметр domainStrategy установлен в UseIP, системные соединения, инициированные этим исходящим подключением, будут сначала разрешать доменное имя в IP-адрес с помощью встроенного DNS-сервера, а затем устанавливать соединение.

                                      Совет 1

                                      DNS-запросы, отправляемые встроенным DNS-сервером, автоматически перенаправляются в соответствии с конфигурацией маршрутизации.

                                      Совет 2

                                      Поддерживаются только базовые запросы IP-адресов (записи A и AAAA). Записи CNAME будут запрашиваться повторно до тех пор, пока не будет возвращена запись A/AAAA. Другие запросы не обрабатываются встроенным DNS-сервером.

                                      Процесс обработки DNS-запросов

                                      Если запрашиваемое доменное имя:

                                      • Соответствует сопоставлению "домен - IP" или "домен - массив IP" в hosts, то этот IP-адрес или массив IP-адресов возвращается в качестве результата DNS-разрешения.
                                      • Соответствует сопоставлению "домен - домен" в hosts, то значение этого сопоставления (другой домен) используется в качестве текущего запрашиваемого доменного имени, и процесс обработки DNS-запросов продолжается до тех пор, пока не будет разрешен IP-адрес или не будет возвращен пустой результат.
                                      • Не соответствует hosts, но соответствует списку доменов domains одного (или нескольких) DNS-серверов, то запросы отправляются на соответствующие DNS-серверы в порядке приоритета.
                                        Если запрос к DNS-серверу завершается неудачей или expectIPs не совпадает, используется следующий подходящий DNS-сервер.
                                        В противном случае возвращается полученный IP-адрес.
                                        Если запросы ко всем подходящим DNS-серверам завершаются неудачей или expectIPs не совпадает, компонент DNS:
                                        • По умолчанию выполняет "резервный (fallback) запрос DNS": запросы отправляются на "DNS-серверы, которые не использовались в предыдущем раунде неудачных запросов и для которых skipFallback имеет значение по умолчанию false".
                                          Если запрос завершается неудачей или expectIPs не совпадает, возвращается пустой результат.
                                          В противном случае возвращается полученный IP-адрес.
                                        • Если disableFallback установлен в true, "резервный (fallback) запрос DNS" не выполняется.
                                      • Не соответствует hosts и не соответствует списку доменов domains ни одного DNS-сервера, то:
                                        • По умолчанию запросы отправляются на "DNS-серверы, для которых skipFallback имеет значение по умолчанию false".
                                          Если запрос к первому выбранному DNS-серверу завершается неудачей или expectIPs не совпадает, используется следующий выбранный DNS-сервер.
                                          В противном случае возвращается полученный IP-адрес.
                                          Если запросы ко всем выбранным DNS-серверам завершаются неудачей или expectIPs не совпадает, возвращается пустой результат.
                                        • Если количество "DNS-серверов, для которых skipFallback имеет значение по умолчанию false", равно 0 или disableFallback установлен в true, используется первый DNS-сервер в конфигурации DNS.
                                          Если запрос завершается неудачей или expectIPs не совпадает, возвращается пустой результат.
                                          В противном случае возвращается полученный IP-адрес.

                                      DnsObject

                                      DnsObject соответствует полю dns в конфигурационном файле.

                                      {
                                      +import{_ as u,r as p,o as l,c as r,a as o,b as s,d as n,w as t,e}from"./app-D7uBbsY3.js";const d={},i=e(`

                                      Встроенный DNS-сервер

                                      DNS-сервер

                                      Встроенный DNS-модуль Xray имеет два основных назначения:

                                      • Разрешение доменных имен в IP-адреса на этапе маршрутизации и сопоставление правил с полученными IP-адресами для разделения трафика.
                                        Разрешение доменных имен и разделение трафика зависят от значения параметра domainStrategy в модуле конфигурации маршрутизации.
                                        Встроенный DNS-сервер будет использоваться для DNS-запросов только при следующих значениях:

                                        • "IPIfNonMatch": при запросе доменного имени Xray сопоставляет его с доменами, указанными в правилах маршрутизации.
                                          Если совпадение не найдено, встроенный DNS-сервер используется для разрешения доменного имени, а затем полученный IP-адрес снова сопоставляется с правилами маршрутизации на основе IP-адресов.
                                        • "IPOnDemand": при сопоставлении правил, основанных на IP-адресах, доменное имя немедленно разрешается в IP-адрес для сопоставления.
                                      • Разрешение целевого адреса для подключения.

                                        • Например, в исходящем подключении freedom, если параметр domainStrategy установлен в UseIP, исходящие запросы будут сначала разрешать доменное имя в IP-адрес с помощью встроенного DNS-сервера, а затем устанавливать соединение.
                                        • Например, в sockopt, если параметр domainStrategy установлен в UseIP, системные соединения, инициированные этим исходящим подключением, будут сначала разрешать доменное имя в IP-адрес с помощью встроенного DNS-сервера, а затем устанавливать соединение.

                                      Совет 1

                                      DNS-запросы, отправляемые встроенным DNS-сервером, автоматически перенаправляются в соответствии с конфигурацией маршрутизации.

                                      Совет 2

                                      Поддерживаются только базовые запросы IP-адресов (записи A и AAAA). Записи CNAME будут запрашиваться повторно до тех пор, пока не будет возвращена запись A/AAAA. Другие запросы не обрабатываются встроенным DNS-сервером.

                                      Процесс обработки DNS-запросов

                                      Если запрашиваемое доменное имя:

                                      • Соответствует сопоставлению "домен - IP" или "домен - массив IP" в hosts, то этот IP-адрес или массив IP-адресов возвращается в качестве результата DNS-разрешения.
                                      • Соответствует сопоставлению "домен - домен" в hosts, то значение этого сопоставления (другой домен) используется в качестве текущего запрашиваемого доменного имени, и процесс обработки DNS-запросов продолжается до тех пор, пока не будет разрешен IP-адрес или не будет возвращен пустой результат.
                                      • Не соответствует hosts, но соответствует списку доменов domains одного (или нескольких) DNS-серверов, то запросы отправляются на соответствующие DNS-серверы в порядке приоритета.
                                        Если запрос к DNS-серверу завершается неудачей или expectIPs не совпадает, используется следующий подходящий DNS-сервер.
                                        В противном случае возвращается полученный IP-адрес.
                                        Если запросы ко всем подходящим DNS-серверам завершаются неудачей или expectIPs не совпадает, компонент DNS:
                                        • По умолчанию выполняет "резервный (fallback) запрос DNS": запросы отправляются на "DNS-серверы, которые не использовались в предыдущем раунде неудачных запросов и для которых skipFallback имеет значение по умолчанию false".
                                          Если запрос завершается неудачей или expectIPs не совпадает, возвращается пустой результат.
                                          В противном случае возвращается полученный IP-адрес.
                                        • Если disableFallback установлен в true, "резервный (fallback) запрос DNS" не выполняется.
                                      • Не соответствует hosts и не соответствует списку доменов domains ни одного DNS-сервера, то:
                                        • По умолчанию запросы отправляются на "DNS-серверы, для которых skipFallback имеет значение по умолчанию false".
                                          Если запрос к первому выбранному DNS-серверу завершается неудачей или expectIPs не совпадает, используется следующий выбранный DNS-сервер.
                                          В противном случае возвращается полученный IP-адрес.
                                          Если запросы ко всем выбранным DNS-серверам завершаются неудачей или expectIPs не совпадает, возвращается пустой результат.
                                        • Если количество "DNS-серверов, для которых skipFallback имеет значение по умолчанию false", равно 0 или disableFallback установлен в true, используется первый DNS-сервер в конфигурации DNS.
                                          Если запрос завершается неудачей или expectIPs не совпадает, возвращается пустой результат.
                                          В противном случае возвращается полученный IP-адрес.

                                      DnsObject

                                      DnsObject соответствует полю dns в конфигурационном файле.

                                      {
                                         "dns": {
                                           "hosts": {
                                             "baidu.com": "127.0.0.1",
                                      diff --git a/assets/dns.html-BZs6b75V.js b/assets/dns.html-DXkA41xv.js
                                      similarity index 99%
                                      rename from assets/dns.html-BZs6b75V.js
                                      rename to assets/dns.html-DXkA41xv.js
                                      index d38702f650..0766d60855 100644
                                      --- a/assets/dns.html-BZs6b75V.js
                                      +++ b/assets/dns.html-DXkA41xv.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as u,r as a,o as c,c as l,a as t,b as e,d as s,w as n,e as i}from"./app-DBM4OJyw.js";const d={},p=i(`

                                      Built-in DNS Server

                                      DNS Server

                                      The DNS module built into Xray has two main purposes:

                                      • During the routing phase, it resolves domain names to IP addresses and performs traffic splitting based on the results of domain name resolution and the value of domainStrategy in the routing configuration module. The built-in DNS server is only used for DNS queries when either of the following values is set:
                                        • "IPIfNonMatch": When a domain name is requested, it first tries to match it against the domain entries in the routing configuration. If no match is found, the built-in DNS server is used to perform a DNS query for the domain name, and the returned IP address is used to perform IP routing matching again.
                                        • "IPOnDemand": When a domain name is matched against any IP-based rule, it is immediately resolved to an IP address for matching.
                                      • It resolves the target address for connection.
                                        • In the freedom outbound setting, if domainStrategy is set to UseIP, requests made through the outbound proxy will first resolve the domain name to an IP address using the built-in server before making the connection.
                                        • In the sockopt setting, if domainStrategy is set to UseIP, system connections initiated through the outbound proxy will first be resolved to an IP address using the built-in server before making the connection.

                                      TIP 1

                                      DNS queries sent by the built-in DNS server are automatically forwarded based on the routing configuration.

                                      TIP 2

                                      Only basic IP queries (A and AAAA records) are supported. CNAME records will be queried repeatedly until an A/AAAA record is returned. Other queries will not enter the built-in DNS server.

                                      DNS Processing Flow

                                      If the domain name to be queried:

                                      • Matches the mapping of "domain name - IP" or "domain name - IP array" in the hosts, then the IP or IP array will be returned as the DNS resolution result.

                                      • Matches the mapping of "domain name - domain name" in the hosts, then the value of this mapping (another domain name) will be used as the domain name to be queried, and enter the DNS processing flow until an IP is resolved and returned, or an empty resolution is returned.

                                      • Does not match hosts, but matches the domains list in one or more DNS servers, then according to the priority of the matching rule, use the DNS server corresponding to the rule to perform the query in sequence. If the DNS server that is hit fails to query or expectIPs does not match, then use the next hit DNS server to perform the query. Otherwise, return the resolved IP. If all hit DNS servers fail to query or expectIPs does not match, then the DNS component:

                                        • By default, it will perform "DNS fallback query": use the "DNS server that has not been used in the last failed query and has a default value of false for skipFallback" to perform the query in sequence. If the query fails or expectIPs does not match, return an empty resolution; otherwise, return the resolved IP.
                                        • If disableFallback is set to true, "DNS fallback query" will not be performed.
                                      • If neither hosts nor the domains list in DNS servers matches, then:

                                        • By default, use the "DNS server that has a default value of false for skipFallback" to perform the query in sequence. If the first selected DNS server fails to query or expectIPs does not match, then use the next selected DNS server to perform the query. Otherwise, return the resolved IP. If all selected DNS servers fail to query or expectIPs does not match, return an empty resolution.
                                        • If the number of "DNS servers that have a default value of false for skipFallback" is 0 or disableFallback is set to true, use the first DNS server in the DNS configuration to perform the query. If the query fails or expectIPs does not match, return an empty resolution; otherwise, return the resolved IP.

                                      DnsObject

                                      DnsObject corresponds to the dns section in the configuration file.

                                      {
                                      +import{_ as u,r as a,o as c,c as l,a as t,b as e,d as s,w as n,e as i}from"./app-D7uBbsY3.js";const d={},p=i(`

                                      Built-in DNS Server

                                      DNS Server

                                      The DNS module built into Xray has two main purposes:

                                      • During the routing phase, it resolves domain names to IP addresses and performs traffic splitting based on the results of domain name resolution and the value of domainStrategy in the routing configuration module. The built-in DNS server is only used for DNS queries when either of the following values is set:
                                        • "IPIfNonMatch": When a domain name is requested, it first tries to match it against the domain entries in the routing configuration. If no match is found, the built-in DNS server is used to perform a DNS query for the domain name, and the returned IP address is used to perform IP routing matching again.
                                        • "IPOnDemand": When a domain name is matched against any IP-based rule, it is immediately resolved to an IP address for matching.
                                      • It resolves the target address for connection.
                                        • In the freedom outbound setting, if domainStrategy is set to UseIP, requests made through the outbound proxy will first resolve the domain name to an IP address using the built-in server before making the connection.
                                        • In the sockopt setting, if domainStrategy is set to UseIP, system connections initiated through the outbound proxy will first be resolved to an IP address using the built-in server before making the connection.

                                      TIP 1

                                      DNS queries sent by the built-in DNS server are automatically forwarded based on the routing configuration.

                                      TIP 2

                                      Only basic IP queries (A and AAAA records) are supported. CNAME records will be queried repeatedly until an A/AAAA record is returned. Other queries will not enter the built-in DNS server.

                                      DNS Processing Flow

                                      If the domain name to be queried:

                                      • Matches the mapping of "domain name - IP" or "domain name - IP array" in the hosts, then the IP or IP array will be returned as the DNS resolution result.

                                      • Matches the mapping of "domain name - domain name" in the hosts, then the value of this mapping (another domain name) will be used as the domain name to be queried, and enter the DNS processing flow until an IP is resolved and returned, or an empty resolution is returned.

                                      • Does not match hosts, but matches the domains list in one or more DNS servers, then according to the priority of the matching rule, use the DNS server corresponding to the rule to perform the query in sequence. If the DNS server that is hit fails to query or expectIPs does not match, then use the next hit DNS server to perform the query. Otherwise, return the resolved IP. If all hit DNS servers fail to query or expectIPs does not match, then the DNS component:

                                        • By default, it will perform "DNS fallback query": use the "DNS server that has not been used in the last failed query and has a default value of false for skipFallback" to perform the query in sequence. If the query fails or expectIPs does not match, return an empty resolution; otherwise, return the resolved IP.
                                        • If disableFallback is set to true, "DNS fallback query" will not be performed.
                                      • If neither hosts nor the domains list in DNS servers matches, then:

                                        • By default, use the "DNS server that has a default value of false for skipFallback" to perform the query in sequence. If the first selected DNS server fails to query or expectIPs does not match, then use the next selected DNS server to perform the query. Otherwise, return the resolved IP. If all selected DNS servers fail to query or expectIPs does not match, return an empty resolution.
                                        • If the number of "DNS servers that have a default value of false for skipFallback" is 0 or disableFallback is set to true, use the first DNS server in the DNS configuration to perform the query. If the query fails or expectIPs does not match, return an empty resolution; otherwise, return the resolved IP.

                                      DnsObject

                                      DnsObject corresponds to the dns section in the configuration file.

                                      {
                                         "dns": {
                                           "hosts": {
                                             "baidu.com": "127.0.0.1",
                                      diff --git a/assets/dns.html-BiECdzTI.js b/assets/dns.html-LlEGGVq6.js
                                      similarity index 99%
                                      rename from assets/dns.html-BiECdzTI.js
                                      rename to assets/dns.html-LlEGGVq6.js
                                      index c8fc38a223..9030d63fdb 100644
                                      --- a/assets/dns.html-BiECdzTI.js
                                      +++ b/assets/dns.html-LlEGGVq6.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as u,r as p,o as l,c as d,a as o,b as s,d as n,w as e,e as t}from"./app-DBM4OJyw.js";const i={},r=t(`

                                      内置 DNS 服务器

                                      DNS 服务器

                                      Xray 内置的 DNS 模块,主要有两大用途:

                                      • 在路由阶段, 解析域名为 IP, 并且根据域名解析得到的 IP 进行规则匹配以分流. 是否解析域名及分流和路由配置模块中 domainStrategy 的值有关, 只有在设置以下两种值时,才会使用内置 DNS 服务器进行 DNS 查询:

                                        • "IPIfNonMatch", 请求一个域名时,进行路由里面的 domain 进行匹配,若无法匹配到结果,则对这个域名使用内置 DNS 服务器进行 DNS 查询,并且使用查询返回的 IP 地址再重新进行 IP 路由匹配。
                                        • "IPOnDemand", 当匹配时碰到任何基于 IP 的规则,将域名立即解析为 IP 进行匹配。
                                      • 解析目标地址进行连接。

                                        • 如 在 freedom 出站中,将 domainStrategy 设置为 UseIP, 由此出站发出的请求, 会先将域名通过内置服务器解析成 IP, 然后进行连接。
                                        • 如 在 sockopt 中,将 domainStrategy 设置为 UseIP, 此出站发起的系统连接,将先由内置服务器解析为 IP, 然后进行连接。

                                      TIP 1

                                      内置 DNS 服务器所发出的 DNS 查询请求,会自动根据路由配置进行转发。

                                      TIP 2

                                      只支持最基本的 IP 查询(A 和 AAAA 记录),CNAME 记录将会重复查询直至返回 A/AAAA 记录为止。其他查询不会进入内置 DNS 服务器。

                                      DNS 处理流程

                                      若当前要查询的域名:

                                      • 命中了 hosts 中的「域名 - IP」、「域名 - IP 数组」映射,则将该 IP 或 IP 数组作为 DNS 解析结果返回。
                                      • 命中了 hosts 中的「域名 - 域名」映射,则该映射的值(另一个域名)将作为当前要查询的域名,进入 DNS 处理流程,直到解析出 IP 后返回,或返回空解析。
                                      • 没有命中 hosts,但命中了某(几)个 DNS 服务器中的 domains 域名列表,则按照命中的规则的优先级,依次使用该规则对应的 DNS 服务器进行查询。若命中的 DNS 服务器查询失败或 expectIPs 不匹配,则使用下一个命中的 DNS 服务器进行查询;否则返回解析得到的 IP。若所有命中的 DNS 服务器均查询失败或 expectIPs 不匹配,此时 DNS 组件:
                                        • 默认会进行 「DNS 回退(fallback)查询」:使用「上一轮失败查询中未被使用的、且 skipFallback 为默认值 false 的 DNS 服务器」依次查询。若查询失败或 expectIPs 不匹配,返回空解析;否则返回解析得到的 IP。
                                        • disableFallback 设置为 true,则不会进行「DNS 回退(fallback)查询」。
                                      • 既没有命中 hosts,又没有命中 DNS 服务器中的 domains 域名列表,则:
                                        • 默认使用「skipFallback 为默认值 false 的 DNS 服务器」依次查询。若第一个被选中的 DNS 服务器查询失败或 expectIPs 不匹配,则使用下一个被选中的 DNS 服务器进行查询;否则返回解析得到的 IP。若所有被选中的 DNS 服务器均查询失败或 expectIPs 不匹配,返回空解析。
                                        • 若「skipFallback 为默认值 false 的 DNS 服务器」数量为 0 或 disableFallback 设置为 true,则使用 DNS 配置中的第一个 DNS 服务器进行查询。查询失败或 expectIPs 不匹配,返回空解析;否则返回解析得到的 IP。

                                      DnsObject

                                      DnsObject 对应配置文件的 dns 项。

                                      {
                                      +import{_ as u,r as p,o as l,c as d,a as o,b as s,d as n,w as e,e as t}from"./app-D7uBbsY3.js";const i={},r=t(`

                                      内置 DNS 服务器

                                      DNS 服务器

                                      Xray 内置的 DNS 模块,主要有两大用途:

                                      • 在路由阶段, 解析域名为 IP, 并且根据域名解析得到的 IP 进行规则匹配以分流. 是否解析域名及分流和路由配置模块中 domainStrategy 的值有关, 只有在设置以下两种值时,才会使用内置 DNS 服务器进行 DNS 查询:

                                        • "IPIfNonMatch", 请求一个域名时,进行路由里面的 domain 进行匹配,若无法匹配到结果,则对这个域名使用内置 DNS 服务器进行 DNS 查询,并且使用查询返回的 IP 地址再重新进行 IP 路由匹配。
                                        • "IPOnDemand", 当匹配时碰到任何基于 IP 的规则,将域名立即解析为 IP 进行匹配。
                                      • 解析目标地址进行连接。

                                        • 如 在 freedom 出站中,将 domainStrategy 设置为 UseIP, 由此出站发出的请求, 会先将域名通过内置服务器解析成 IP, 然后进行连接。
                                        • 如 在 sockopt 中,将 domainStrategy 设置为 UseIP, 此出站发起的系统连接,将先由内置服务器解析为 IP, 然后进行连接。

                                      TIP 1

                                      内置 DNS 服务器所发出的 DNS 查询请求,会自动根据路由配置进行转发。

                                      TIP 2

                                      只支持最基本的 IP 查询(A 和 AAAA 记录),CNAME 记录将会重复查询直至返回 A/AAAA 记录为止。其他查询不会进入内置 DNS 服务器。

                                      DNS 处理流程

                                      若当前要查询的域名:

                                      • 命中了 hosts 中的「域名 - IP」、「域名 - IP 数组」映射,则将该 IP 或 IP 数组作为 DNS 解析结果返回。
                                      • 命中了 hosts 中的「域名 - 域名」映射,则该映射的值(另一个域名)将作为当前要查询的域名,进入 DNS 处理流程,直到解析出 IP 后返回,或返回空解析。
                                      • 没有命中 hosts,但命中了某(几)个 DNS 服务器中的 domains 域名列表,则按照命中的规则的优先级,依次使用该规则对应的 DNS 服务器进行查询。若命中的 DNS 服务器查询失败或 expectIPs 不匹配,则使用下一个命中的 DNS 服务器进行查询;否则返回解析得到的 IP。若所有命中的 DNS 服务器均查询失败或 expectIPs 不匹配,此时 DNS 组件:
                                        • 默认会进行 「DNS 回退(fallback)查询」:使用「上一轮失败查询中未被使用的、且 skipFallback 为默认值 false 的 DNS 服务器」依次查询。若查询失败或 expectIPs 不匹配,返回空解析;否则返回解析得到的 IP。
                                        • disableFallback 设置为 true,则不会进行「DNS 回退(fallback)查询」。
                                      • 既没有命中 hosts,又没有命中 DNS 服务器中的 domains 域名列表,则:
                                        • 默认使用「skipFallback 为默认值 false 的 DNS 服务器」依次查询。若第一个被选中的 DNS 服务器查询失败或 expectIPs 不匹配,则使用下一个被选中的 DNS 服务器进行查询;否则返回解析得到的 IP。若所有被选中的 DNS 服务器均查询失败或 expectIPs 不匹配,返回空解析。
                                        • 若「skipFallback 为默认值 false 的 DNS 服务器」数量为 0 或 disableFallback 设置为 true,则使用 DNS 配置中的第一个 DNS 服务器进行查询。查询失败或 expectIPs 不匹配,返回空解析;否则返回解析得到的 IP。

                                      DnsObject

                                      DnsObject 对应配置文件的 dns 项。

                                      {
                                         "dns": {
                                           "hosts": {
                                             "baidu.com": "127.0.0.1",
                                      diff --git a/assets/dns.html-BqlRMu7q.js b/assets/dns.html-TjxOpc7L.js
                                      similarity index 98%
                                      rename from assets/dns.html-BqlRMu7q.js
                                      rename to assets/dns.html-TjxOpc7L.js
                                      index ec1b473c7e..d27f570724 100644
                                      --- a/assets/dns.html-BqlRMu7q.js
                                      +++ b/assets/dns.html-TjxOpc7L.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as i,r as n,o as d,c,a as t,b as e,d as o,w as p,e as u}from"./app-DBM4OJyw.js";const l={},h=e("h1",{id:"dns",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#dns"},[e("span",null,"DNS")])],-1),q=e("p",null,"DNS is an outbound protocol used for intercepting and forwarding DNS queries.",-1),f=e("p",null,"This outbound protocol can only handle DNS traffic, including queries based on UDP and TCP protocols. Other types of traffic will result in an error.",-1),b=u(`

                                      OutboundConfigurationObject

                                      {
                                      +import{_ as i,r as n,o as d,c,a as t,b as e,d as o,w as p,e as u}from"./app-D7uBbsY3.js";const l={},h=e("h1",{id:"dns",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#dns"},[e("span",null,"DNS")])],-1),q=e("p",null,"DNS is an outbound protocol used for intercepting and forwarding DNS queries.",-1),f=e("p",null,"This outbound protocol can only handle DNS traffic, including queries based on UDP and TCP protocols. Other types of traffic will result in an error.",-1),b=u(`

                                      OutboundConfigurationObject

                                      {
                                         "network": "tcp",
                                         "address": "1.1.1.1",
                                         "port": 53,
                                      diff --git a/assets/dns.html-B4w4YpWq.js b/assets/dns.html-aOkEAe83.js
                                      similarity index 98%
                                      rename from assets/dns.html-B4w4YpWq.js
                                      rename to assets/dns.html-aOkEAe83.js
                                      index f6c71ca7b7..12bda35bc7 100644
                                      --- a/assets/dns.html-B4w4YpWq.js
                                      +++ b/assets/dns.html-aOkEAe83.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as p,r as e,o as d,c as u,a as s,b as o,d as n,w as r,e as l}from"./app-DBM4OJyw.js";const i={},q=o("h1",{id:"dns",tabindex:"-1"},[o("a",{class:"header-anchor",href:"#dns"},[o("span",null,"DNS")])],-1),k=o("p",null,"DNS — это исходящий протокол, который в основном используется для перехвата и пересылки DNS-запросов.",-1),_=o("p",null,"Этот исходящий протокол может принимать только DNS-трафик (включая запросы по протоколам UDP и TCP), другие типы трафика будут вызывать ошибки.",-1),b=l(`

                                      OutboundConfigurationObject

                                      {
                                      +import{_ as p,r as e,o as d,c as u,a as s,b as o,d as n,w as r,e as l}from"./app-D7uBbsY3.js";const i={},q=o("h1",{id:"dns",tabindex:"-1"},[o("a",{class:"header-anchor",href:"#dns"},[o("span",null,"DNS")])],-1),k=o("p",null,"DNS — это исходящий протокол, который в основном используется для перехвата и пересылки DNS-запросов.",-1),_=o("p",null,"Этот исходящий протокол может принимать только DNS-трафик (включая запросы по протоколам UDP и TCP), другие типы трафика будут вызывать ошибки.",-1),b=l(`

                                      OutboundConfigurationObject

                                      {
                                         "network": "tcp",
                                         "address": "1.1.1.1",
                                         "port": 53,
                                      diff --git a/assets/document.html-BI9FxX1n.js b/assets/document.html-CL3-jl55.js
                                      similarity index 98%
                                      rename from assets/document.html-BI9FxX1n.js
                                      rename to assets/document.html-CL3-jl55.js
                                      index 617165d5e7..d2e8c3c5f9 100644
                                      --- a/assets/document.html-BI9FxX1n.js
                                      +++ b/assets/document.html-CL3-jl55.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as s,r as l,o as a,c as i,a as n,b as e,d as t,e as c}from"./app-DBM4OJyw.js";const d={},u=e("h1",{id:"为-project-x-的文档贡献",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#为-project-x-的文档贡献"},[e("span",null,"为 Project X 的文档贡献")])],-1),h=e("p",null,"欢迎您为 Project X 的文档做出贡献,我们感谢每一位 Contributor 的贡献!是你们让 Xray 更加强大!",-1),_=e("h2",{id:"改进文档",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#改进文档"},[e("span",null,"改进文档")])],-1),p={href:"https://github.com/XTLS/Xray-docs-next",target:"_blank",rel:"noopener noreferrer"},g=e("p",null,"您可以通过以下步骤, 提交您对文档的改动:",-1),b={href:"https://github.com/XTLS/Xray-docs-next",target:"_blank",rel:"noopener noreferrer"},m=e("li",null,[e("p",null,"使用任何您喜欢的工具, 从您克隆的仓库获得文档的克隆, 如:")],-1),x=c(`
                                      git clone https://github.com/XTLS/Xray-docs-next.git
                                      +import{_ as s,r as l,o as a,c as i,a as n,b as e,d as t,e as c}from"./app-D7uBbsY3.js";const d={},u=e("h1",{id:"为-project-x-的文档贡献",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#为-project-x-的文档贡献"},[e("span",null,"为 Project X 的文档贡献")])],-1),h=e("p",null,"欢迎您为 Project X 的文档做出贡献,我们感谢每一位 Contributor 的贡献!是你们让 Xray 更加强大!",-1),_=e("h2",{id:"改进文档",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#改进文档"},[e("span",null,"改进文档")])],-1),p={href:"https://github.com/XTLS/Xray-docs-next",target:"_blank",rel:"noopener noreferrer"},g=e("p",null,"您可以通过以下步骤, 提交您对文档的改动:",-1),b={href:"https://github.com/XTLS/Xray-docs-next",target:"_blank",rel:"noopener noreferrer"},m=e("li",null,[e("p",null,"使用任何您喜欢的工具, 从您克隆的仓库获得文档的克隆, 如:")],-1),x=c(`
                                      git clone https://github.com/XTLS/Xray-docs-next.git
                                       
                                      1. 基于 main 分支创建新的分支, 如:
                                      git checkout -b your-branch
                                       
                                      `,3),f={start:"4"},v=e("p",null,"在新分支上做修改。",-1),X={href:"https://github.com/sparanoid/chinese-copywriting-guidelines",target:"_blank",rel:"noopener noreferrer"},k={href:"https://prettier.io/docs/en/install.html",target:"_blank",rel:"noopener noreferrer"},P=e("p",null,"注:存在格式问题的 PR,将有可能被拒绝。",-1),j=e("li",null,[e("p",null,"提交修改,并推送到您的仓库中")],-1),y=e("div",{class:"language-text line-numbers-mode","data-ext":"text","data-title":"text"},[e("pre",{class:"language-text"},[e("code",null,`git push -u origin your-branch `)]),e("div",{class:"line-numbers","aria-hidden":"true"},[e("div",{class:"line-number"})])],-1),T={start:"6"},L={href:"https://github.com/XTLS/Xray-docs-next",target:"_blank",rel:"noopener noreferrer"},I=e("li",null,[e("p",null,"请在 PR 的标题和正文中,概述此次 PR 新增/修改的内容等;")],-1),R={href:"https://xtls.github.io",target:"_blank",rel:"noopener noreferrer"},S=e("h2",{id:"发现问题",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#发现问题"},[e("span",null,"发现问题?")])],-1),N=e("p",null,"如果您发现文档出错,可以改进文档或提交一个 Issue。",-1);function V(B,E){const r=l("I18nTip"),o=l("ExternalLinkIcon");return a(),i("div",null,[n(r),u,h,_,e("p",null,[t("Project X 的文档托管在 "),e("a",p,[t("GitHub"),n(o)]),t(" 上.")]),g,e("ol",null,[e("li",null,[e("p",null,[t("从 "),e("a",b,[t("Project X 文档仓库"),n(o)]),t(" 打开仓库, 点击右上角的 fork, fork 一份文档仓库的镜像到您自己的 github 仓库.")])]),m]),x,e("ol",f,[e("li",null,[v,e("p",null,[t("注:推荐 "),e("a",X,[t("中文文案排版指北"),n(o)])])]),e("li",null,[e("p",null,[t("修改完成后,请使用 "),e("a",k,[t("Prettier"),n(o)]),t(" 格式化您的更改。")]),P]),j]),y,e("ol",T,[e("li",null,[e("p",null,[t("打开 GitHub, 点击 'Pull request' 向 "),e("a",L,[t("Project X 文档仓库"),n(o)]),t(" 提交 PR。")])]),I,e("li",null,[e("p",null,[t("等待回应, 如果 PR 被 merge, 您做的修改将直接呈现在 "),e("a",R,[t("Project X 文档网站"),n(o)]),t("。")])])]),S,N])}const G=s(d,[["render",V],["__file","document.html.vue"]]);export{G as default}; diff --git a/assets/document.html-BU1vIcEy.js b/assets/document.html-XdgZ3aKf.js similarity index 98% rename from assets/document.html-BU1vIcEy.js rename to assets/document.html-XdgZ3aKf.js index 6e0231d1ef..8a46686b90 100644 --- a/assets/document.html-BU1vIcEy.js +++ b/assets/document.html-XdgZ3aKf.js @@ -1,4 +1,4 @@ -import{_ as s,r as o,o as a,c as i,a as n,b as e,d as t,e as c}from"./app-DBM4OJyw.js";const d={},u=e("h1",{id:"вклад-в-документацию-project-x",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#вклад-в-документацию-project-x"},[e("span",null,"Вклад в документацию Project X")])],-1),h=e("p",null,"Мы приветствуем ваш вклад в документацию Project X и благодарим каждого контрибьютора за помощь! Вы делаете Xray лучше!",-1),_=e("h2",{id:"улучшение-документации",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#улучшение-документации"},[e("span",null,"Улучшение документации")])],-1),p={href:"https://github.com/XTLS/Xray-docs-next",target:"_blank",rel:"noopener noreferrer"},b=e("p",null,"Вы можете внести изменения в документацию, выполнив следующие действия:",-1),g={href:"https://github.com/XTLS/Xray-docs-next",target:"_blank",rel:"noopener noreferrer"},x=e("li",null,[e("p",null,"Используйте любой удобный инструмент для клонирования документации из вашего репозитория, например:")],-1),m=c(`
                                      git clone https://github.com/XTLS/Xray-docs-next.git
                                      +import{_ as s,r as o,o as a,c as i,a as n,b as e,d as t,e as c}from"./app-D7uBbsY3.js";const d={},u=e("h1",{id:"вклад-в-документацию-project-x",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#вклад-в-документацию-project-x"},[e("span",null,"Вклад в документацию Project X")])],-1),h=e("p",null,"Мы приветствуем ваш вклад в документацию Project X и благодарим каждого контрибьютора за помощь! Вы делаете Xray лучше!",-1),_=e("h2",{id:"улучшение-документации",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#улучшение-документации"},[e("span",null,"Улучшение документации")])],-1),p={href:"https://github.com/XTLS/Xray-docs-next",target:"_blank",rel:"noopener noreferrer"},b=e("p",null,"Вы можете внести изменения в документацию, выполнив следующие действия:",-1),g={href:"https://github.com/XTLS/Xray-docs-next",target:"_blank",rel:"noopener noreferrer"},x=e("li",null,[e("p",null,"Используйте любой удобный инструмент для клонирования документации из вашего репозитория, например:")],-1),m=c(`
                                      git clone https://github.com/XTLS/Xray-docs-next.git
                                       
                                      1. Создайте новую ветку на основе ветки main, например:
                                      git checkout -b your-branch
                                       
                                      `,3),f={start:"4"},v=e("p",null,"Внесите изменения в новую ветку.",-1),X={href:"https://github.com/sparanoid/chinese-copywriting-guidelines",target:"_blank",rel:"noopener noreferrer"},k={href:"https://prettier.io/docs/en/install.html",target:"_blank",rel:"noopener noreferrer"},P=e("p",null,"Примечание: запросы на включение (PR) с ошибками форматирования могут быть отклонены.",-1),j=e("li",null,[e("p",null,"Зафиксируйте изменения и отправьте их в ваш репозиторий:")],-1),y=e("div",{class:"language-text line-numbers-mode","data-ext":"text","data-title":"text"},[e("pre",{class:"language-text"},[e("code",null,`git push -u origin your-branch `)]),e("div",{class:"line-numbers","aria-hidden":"true"},[e("div",{class:"line-number"})])],-1),T={start:"7"},L={href:"https://github.com/XTLS/Xray-docs-next",target:"_blank",rel:"noopener noreferrer"},I=e("li",null,[e("p",null,"В заголовке и описании PR кратко опишите внесенные изменения.")],-1),S={href:"https://xtls.github.io",target:"_blank",rel:"noopener noreferrer"},N=e("h2",{id:"нашли-ошибку",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#нашли-ошибку"},[e("span",null,"Нашли ошибку?")])],-1),R=e("p",null,"Если вы обнаружили ошибку в документации, вы можете внести исправления или создать задачу (Issue).",-1);function V(B,E){const r=o("I18nTip"),l=o("ExternalLinkIcon");return a(),i("div",null,[n(r),u,h,_,e("p",null,[t("Документация Project X размещена на "),e("a",p,[t("GitHub"),n(l)]),t(".")]),b,e("ol",null,[e("li",null,[e("p",null,[t("Откройте "),e("a",g,[t("репозиторий документации Project X"),n(l)]),t(', нажмите кнопку "Fork" в правом верхнем углу, чтобы создать копию репозитория документации в вашей учетной записи GitHub.')])]),x]),m,e("ol",f,[e("li",null,[v,e("p",null,[t("Примечание: рекомендуем придерживаться "),e("a",X,[t("Руководства по оформлению текстов на китайском языке"),n(l)]),t(" (на китайском).")])]),e("li",null,[e("p",null,[t("После внесения изменений отформатируйте их с помощью "),e("a",k,[t("Prettier"),n(l)]),t(".")]),P]),j]),y,e("ol",T,[e("li",null,[e("p",null,[t('Откройте GitHub, перейдите в раздел "Pull requests" и создайте новый запрос на включение (PR) в '),e("a",L,[t("репозиторий документации Project X"),n(l)]),t(".")])]),I,e("li",null,[e("p",null,[t("Дождитесь ответа. Если ваш PR будет принят, изменения появятся на "),e("a",S,[t("сайте документации Project X"),n(l)]),t(".")])])]),N,R])}const H=s(d,[["render",V],["__file","document.html.vue"]]);export{H as default}; diff --git a/assets/document.html-C8cPqOIW.js b/assets/document.html-djabafZA.js similarity index 98% rename from assets/document.html-C8cPqOIW.js rename to assets/document.html-djabafZA.js index 72a4dab40a..754d25fe41 100644 --- a/assets/document.html-C8cPqOIW.js +++ b/assets/document.html-djabafZA.js @@ -1,4 +1,4 @@ -import{_ as l,r,o as i,c as a,a as o,b as e,d as t,e as c}from"./app-DBM4OJyw.js";const u={},d=e("h1",{id:"contribute-to-project-x-s-document",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#contribute-to-project-x-s-document"},[e("span",null,"Contribute to Project X's Document")])],-1),h=e("p",null,"Contributions to Project X's Document are welcome, and we appreciate every Contributor's contribution! You guys make Xray stronger!",-1),p=e("h2",{id:"improve-document",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#improve-document"},[e("span",null,"Improve Document")])],-1),m={href:"https://github.com/XTLS/Xray-docs-next",target:"_blank",rel:"noopener noreferrer"},_=e("p",null,"You can submit your changes to the Document by following these steps:",-1),b={href:"https://github.com/XTLS/Xray-docs-next",target:"_blank",rel:"noopener noreferrer"},g=e("li",null,[e("p",null,"Get a clone of the docs from the repository you cloned using whatever tool you like, like:")],-1),f=c(`
                                      git clone https://github.com/XTLS/Xray-docs-next.git
                                      +import{_ as l,r,o as i,c as a,a as o,b as e,d as t,e as c}from"./app-D7uBbsY3.js";const u={},d=e("h1",{id:"contribute-to-project-x-s-document",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#contribute-to-project-x-s-document"},[e("span",null,"Contribute to Project X's Document")])],-1),h=e("p",null,"Contributions to Project X's Document are welcome, and we appreciate every Contributor's contribution! You guys make Xray stronger!",-1),p=e("h2",{id:"improve-document",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#improve-document"},[e("span",null,"Improve Document")])],-1),m={href:"https://github.com/XTLS/Xray-docs-next",target:"_blank",rel:"noopener noreferrer"},_=e("p",null,"You can submit your changes to the Document by following these steps:",-1),b={href:"https://github.com/XTLS/Xray-docs-next",target:"_blank",rel:"noopener noreferrer"},g=e("li",null,[e("p",null,"Get a clone of the docs from the repository you cloned using whatever tool you like, like:")],-1),f=c(`
                                      git clone https://github.com/XTLS/Xray-docs-next.git
                                       
                                      1. Create a new branch based on the main branch, such as:
                                      git checkout -b your-branch
                                       
                                      `,3),x={start:"4"},y=e("li",null,[e("p",null,"Make changes on the new branch.")],-1),v={href:"https://prettier.io/docs/en/install.html",target:"_blank",rel:"noopener noreferrer"},k=e("p",null,"Note: Pull requests with formatting issues may be rejected.",-1),X=e("li",null,[e("p",null,"Submit the changes and push them to your repository")],-1),P=e("div",{class:"language-text line-numbers-mode","data-ext":"text","data-title":"text"},[e("pre",{class:"language-text"},[e("code",null,`git push -u origin your-branch `)]),e("div",{class:"line-numbers","aria-hidden":"true"},[e("div",{class:"line-number"})])],-1),w={start:"6"},j={href:"https://github.com/XTLS/Xray-docs-next",target:"_blank",rel:"noopener noreferrer"},D=e("li",null,[e("p",null,"Please outline the new/modified content of this pull request in the title and body of the pull request;")],-1),T={href:"https://xtls.github.io",target:"_blank",rel:"noopener noreferrer"},q=e("h2",{id:"found-problems",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#found-problems"},[e("span",null,"Found Problems?")])],-1),I=e("p",null,"If you find an error in the document, you can improve the documentation or submit an issue.",-1);function L(S,C){const s=r("I18nTip"),n=r("ExternalLinkIcon");return i(),a("div",null,[o(s),d,h,p,e("p",null,[t("Document for Project X is hosted on "),e("a",m,[t("GitHub"),o(n)]),t(".")]),_,e("ol",null,[e("li",null,[e("p",null,[t("Open the repository from "),e("a",b,[t("Project X Document"),o(n)]),t(", click fork in the upper right corner, fork a mirror image of the document repository to your own GitHub repository.")])]),g]),f,e("ol",x,[y,e("li",null,[e("p",null,[t("After modification, please use "),e("a",v,[t("Prettier"),o(n)]),t("Format your changes.")]),k]),X]),P,e("ol",w,[e("li",null,[e("p",null,[t("Open GitHub, click 'Pull request' to submit a pull request to "),e("a",j,[t("Project X Document"),o(n)]),t(".")])]),D,e("li",null,[e("p",null,[t("Waiting for a response, if the pull request is merged, your changes will be directly displayed on "),e("a",T,[t("Project X Document Website"),o(n)]),t(".")])])]),q,I])}const G=l(u,[["render",L],["__file","document.html.vue"]]);export{G as default}; diff --git a/assets/dokodemo.html-B1Zv0rHv.js b/assets/dokodemo.html-BjerEOtA.js similarity index 99% rename from assets/dokodemo.html-B1Zv0rHv.js rename to assets/dokodemo.html-BjerEOtA.js index eba5d2db41..784f9b333f 100644 --- a/assets/dokodemo.html-B1Zv0rHv.js +++ b/assets/dokodemo.html-BjerEOtA.js @@ -1,4 +1,4 @@ -import{_ as c,r as a,o as i,c as l,a as n,b as o,d as e,w as t,e as p}from"./app-DBM4OJyw.js";const d={},u=p(`

                                      Dokodemo-Door

                                      Dokodemo door (Anywhere Door) can listen to a local port and forward all incoming data on this port to a specified server's port, achieving the effect of port mapping.

                                      InboundConfigurationObject

                                      {
                                      +import{_ as c,r as a,o as i,c as l,a as n,b as o,d as e,w as t,e as p}from"./app-D7uBbsY3.js";const d={},u=p(`

                                      Dokodemo-Door

                                      Dokodemo door (Anywhere Door) can listen to a local port and forward all incoming data on this port to a specified server's port, achieving the effect of port mapping.

                                      InboundConfigurationObject

                                      {
                                         "address": "8.8.8.8",
                                         "port": 53,
                                         "network": "tcp",
                                      diff --git a/assets/dokodemo.html-LpEbF-JC.js b/assets/dokodemo.html-DEix7lbM.js
                                      similarity index 99%
                                      rename from assets/dokodemo.html-LpEbF-JC.js
                                      rename to assets/dokodemo.html-DEix7lbM.js
                                      index 1c71af2766..269df668bc 100644
                                      --- a/assets/dokodemo.html-LpEbF-JC.js
                                      +++ b/assets/dokodemo.html-DEix7lbM.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as l,r as t,o as r,c as u,a as o,b as s,d as n,w as e,e as p}from"./app-DBM4OJyw.js";const d={},i=p(`

                                      Dokodemo-Door

                                      Dokodemo door может прослушивать локальный порт и отправлять все данные, поступающие на этот порт, на порт указанного сервера, тем самым реализуя перенаправление портов.

                                      InboundConfigurationObject

                                      {
                                      +import{_ as l,r as t,o as r,c as u,a as o,b as s,d as n,w as e,e as p}from"./app-D7uBbsY3.js";const d={},i=p(`

                                      Dokodemo-Door

                                      Dokodemo door может прослушивать локальный порт и отправлять все данные, поступающие на этот порт, на порт указанного сервера, тем самым реализуя перенаправление портов.

                                      InboundConfigurationObject

                                      {
                                         "address": "8.8.8.8",
                                         "port": 53,
                                         "network": "tcp",
                                      diff --git a/assets/dokodemo.html-LnG90uyS.js b/assets/dokodemo.html-LPhond1Y.js
                                      similarity index 99%
                                      rename from assets/dokodemo.html-LnG90uyS.js
                                      rename to assets/dokodemo.html-LPhond1Y.js
                                      index 0b9fefa97f..15a834c820 100644
                                      --- a/assets/dokodemo.html-LnG90uyS.js
                                      +++ b/assets/dokodemo.html-LPhond1Y.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as l,r as t,o as r,c as u,a as o,b as s,d as n,w as e,e as p}from"./app-DBM4OJyw.js";const d={},i=p(`

                                      Dokodemo-Door

                                      Dokodemo door(任意门)可以监听一个本地端口,并把所有进入此端口的数据发送至指定服务器的一个端口,从而达到端口映射的效果。

                                      InboundConfigurationObject

                                      {
                                      +import{_ as l,r as t,o as r,c as u,a as o,b as s,d as n,w as e,e as p}from"./app-D7uBbsY3.js";const d={},i=p(`

                                      Dokodemo-Door

                                      Dokodemo door(任意门)可以监听一个本地端口,并把所有进入此端口的数据发送至指定服务器的一个端口,从而达到端口映射的效果。

                                      InboundConfigurationObject

                                      {
                                         "address": "8.8.8.8",
                                         "port": 53,
                                         "network": "tcp",
                                      diff --git a/assets/env.html-CnZRKI06.js b/assets/env.html-BJIm3TxY.js
                                      similarity index 98%
                                      rename from assets/env.html-CnZRKI06.js
                                      rename to assets/env.html-BJIm3TxY.js
                                      index 2c88506673..b451badf51 100644
                                      --- a/assets/env.html-CnZRKI06.js
                                      +++ b/assets/env.html-BJIm3TxY.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as d,r as n,o as s,c as l,a as o,b as e,d as a,e as i}from"./app-DBM4OJyw.js";const r={},_=e("h1",{id:"переменные-среды",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#переменные-среды"},[e("span",null,"Переменные среды")])],-1),h=e("p",null,"Xray предоставляет следующие переменные среды для изменения некоторых базовых настроек Xray.",-1),u=e("h2",{id:"путь-к-фаилам-ресурсов",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#путь-к-фаилам-ресурсов"},[e("span",null,"Путь к файлам ресурсов")])],-1),p=e("li",null,[a("Название: "),e("code",null,"xray.location.asset"),a(" или "),e("code",null,"XRAY_LOCATION_ASSET"),a(".")],-1),x={href:"https://en.wikipedia.org/wiki/Filesystem_Hierarchy_Standard",target:"_blank",rel:"noopener noreferrer"},f=i(`

                                      Эта переменная среды указывает расположение папки, которая должна содержать файлы geoip.dat и geosite.dat. Если значение переменной не указано, программа будет искать файлы ресурсов в следующем порядке:

                                      ./
                                      +import{_ as d,r as n,o as s,c as l,a as o,b as e,d as a,e as i}from"./app-D7uBbsY3.js";const r={},_=e("h1",{id:"переменные-среды",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#переменные-среды"},[e("span",null,"Переменные среды")])],-1),h=e("p",null,"Xray предоставляет следующие переменные среды для изменения некоторых базовых настроек Xray.",-1),u=e("h2",{id:"путь-к-фаилам-ресурсов",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#путь-к-фаилам-ресурсов"},[e("span",null,"Путь к файлам ресурсов")])],-1),p=e("li",null,[a("Название: "),e("code",null,"xray.location.asset"),a(" или "),e("code",null,"XRAY_LOCATION_ASSET"),a(".")],-1),x={href:"https://en.wikipedia.org/wiki/Filesystem_Hierarchy_Standard",target:"_blank",rel:"noopener noreferrer"},f=i(`

                                      Эта переменная среды указывает расположение папки, которая должна содержать файлы geoip.dat и geosite.dat. Если значение переменной не указано, программа будет искать файлы ресурсов в следующем порядке:

                                      ./
                                       /usr/local/share/xray
                                       /usr/share/xray
                                       

                                      Расположение файла конфигурации

                                      • Название: xray.location.config или XRAY_LOCATION_CONFIG.
                                      • Значение по умолчанию: Тот же каталог, что и файл Xray.

                                      Эта переменная среды указывает расположение папки, которая должна содержать файл config.json.

                                      Каталог с несколькими конфигурациями

                                      • Название: xray.location.confdir или XRAY_LOCATION_CONFDIR.
                                      • Значение по умолчанию: "".

                                      Файлы .json в этом каталоге будут читаться в порядке имен файлов как параметры конфигурации.

                                      `,8);function m(v,b){const c=n("I18nTip"),t=n("ExternalLinkIcon");return s(),l("div",null,[o(c),_,h,u,e("ul",null,[p,e("li",null,[a("Значение по умолчанию: Определенный каталог "),e("a",x,[a("FHS"),o(t)]),a(" или тот же каталог, что и файл Xray.")])]),f])}const g=d(r,[["render",m],["__file","env.html.vue"]]);export{g as default}; diff --git a/assets/env.html-0B8aFJq0.js b/assets/env.html-CY9_QX-K.js similarity index 97% rename from assets/env.html-0B8aFJq0.js rename to assets/env.html-CY9_QX-K.js index 43b231d629..55b67fd9eb 100644 --- a/assets/env.html-0B8aFJq0.js +++ b/assets/env.html-CY9_QX-K.js @@ -1,4 +1,4 @@ -import{_ as l,r as o,o as r,c as s,a as i,b as e,d as a,e as c}from"./app-DBM4OJyw.js";const d={},u=e("h1",{id:"environment-variables",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#environment-variables"},[e("span",null,"Environment Variables")])],-1),h=e("p",null,"Xray provides the following environment variables for modifying some of its underlying configurations.",-1),f=e("h2",{id:"xray-asset-location",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#xray-asset-location"},[e("span",null,"Xray Asset Location")])],-1),p=e("li",null,[a("Name:"),e("code",null,"xray.location.asset"),a(" or "),e("code",null,"XRAY_LOCATION_ASSET"),a("。")],-1),_={href:"https://en.wikipedia.org/wiki/Filesystem_Hierarchy_Standard",target:"_blank",rel:"noopener noreferrer"},m=c(`

                                      This environment variable specifies a folder location that should contain the geoip.dat and geosite.dat files. If no variable value is specified, the program will search for resource files in the following order:

                                      ./
                                      +import{_ as l,r as o,o as r,c as s,a as i,b as e,d as a,e as c}from"./app-D7uBbsY3.js";const d={},u=e("h1",{id:"environment-variables",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#environment-variables"},[e("span",null,"Environment Variables")])],-1),h=e("p",null,"Xray provides the following environment variables for modifying some of its underlying configurations.",-1),f=e("h2",{id:"xray-asset-location",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#xray-asset-location"},[e("span",null,"Xray Asset Location")])],-1),p=e("li",null,[a("Name:"),e("code",null,"xray.location.asset"),a(" or "),e("code",null,"XRAY_LOCATION_ASSET"),a("。")],-1),_={href:"https://en.wikipedia.org/wiki/Filesystem_Hierarchy_Standard",target:"_blank",rel:"noopener noreferrer"},m=c(`

                                      This environment variable specifies a folder location that should contain the geoip.dat and geosite.dat files. If no variable value is specified, the program will search for resource files in the following order:

                                      ./
                                       /usr/local/share/xray
                                       /usr/share/xray
                                       

                                      Configuration File Location

                                      • Name:xray.location.config or XRAY_LOCATION_CONFIG
                                      • Default value: Same path as the Xray file.

                                      This environment variable specifies a folder location that should contain the config.json file.

                                      Multiple Configuration Directories

                                      • Name:xray.location.confdir or XRAY_LOCATION_CONFDIR
                                      • Default value:""

                                      The .json files in this directory will be read in alphabetical order by filename and used as options for multiple configurations.

                                      `,8);function v(g,x){const n=o("I18nTip"),t=o("ExternalLinkIcon");return r(),s("div",null,[i(n),u,h,f,e("ul",null,[p,e("li",null,[a("Default value:specified "),e("a",_,[a("FHS"),i(t)]),a(" directory or the same path as the Xray file.")])]),m])}const y=l(d,[["render",v],["__file","env.html.vue"]]);export{y as default}; diff --git a/assets/env.html-BGX1tEf1.js b/assets/env.html-D3uMVVBG.js similarity index 97% rename from assets/env.html-BGX1tEf1.js rename to assets/env.html-D3uMVVBG.js index 72726c54e8..0ccee677dd 100644 --- a/assets/env.html-BGX1tEf1.js +++ b/assets/env.html-D3uMVVBG.js @@ -1,4 +1,4 @@ -import{_ as l,r as n,o as c,c as i,a as o,b as e,d as a,e as r}from"./app-DBM4OJyw.js";const d={},_=e("h1",{id:"环境变量",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#环境变量"},[e("span",null,"环境变量")])],-1),h=e("p",null,"Xray 提供以下环境变量以供修改 Xray 的一些底层配置。",-1),u=e("h2",{id:"资源文件路径",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#资源文件路径"},[e("span",null,"资源文件路径")])],-1),p=e("li",null,[a("名称:"),e("code",null,"xray.location.asset"),a(" 或 "),e("code",null,"XRAY_LOCATION_ASSET"),a("。")],-1),x={href:"https://en.wikipedia.org/wiki/Filesystem_Hierarchy_Standard",target:"_blank",rel:"noopener noreferrer"},f=r(`

                                      这个环境变量指定了一个文件夹位置,这个文件夹应当包含 geoip.dat 和 geosite.dat 文件。 若无指定变量值,程序将会按以下顺序寻找资源文件:

                                      ./
                                      +import{_ as l,r as n,o as c,c as i,a as o,b as e,d as a,e as r}from"./app-D7uBbsY3.js";const d={},_=e("h1",{id:"环境变量",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#环境变量"},[e("span",null,"环境变量")])],-1),h=e("p",null,"Xray 提供以下环境变量以供修改 Xray 的一些底层配置。",-1),u=e("h2",{id:"资源文件路径",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#资源文件路径"},[e("span",null,"资源文件路径")])],-1),p=e("li",null,[a("名称:"),e("code",null,"xray.location.asset"),a(" 或 "),e("code",null,"XRAY_LOCATION_ASSET"),a("。")],-1),x={href:"https://en.wikipedia.org/wiki/Filesystem_Hierarchy_Standard",target:"_blank",rel:"noopener noreferrer"},f=r(`

                                      这个环境变量指定了一个文件夹位置,这个文件夹应当包含 geoip.dat 和 geosite.dat 文件。 若无指定变量值,程序将会按以下顺序寻找资源文件:

                                      ./
                                       /usr/local/share/xray
                                       /usr/share/xray
                                       

                                      配置文件位置

                                      • 名称:xray.location.configXRAY_LOCATION_CONFIG
                                      • 默认值:和 Xray 文件同路径。

                                      这个环境变量指定了一个文件夹位置,这个文件夹应当包含 config.json 文件。

                                      多配置目录

                                      • 名称:xray.location.confdirXRAY_LOCATION_CONFDIR
                                      • 默认值:""

                                      这个目录内的 .json 文件会按文件名顺序读取,作为多配置选项。

                                      `,8);function m(v,b){const t=n("I18nTip"),s=n("ExternalLinkIcon");return c(),i("div",null,[o(t),_,h,u,e("ul",null,[p,e("li",null,[a("默认值:特定 "),e("a",x,[a("FHS"),o(s)]),a(" 目录或 Xray 文件同路径。")])]),f])}const g=l(d,[["render",m],["__file","env.html.vue"]]);export{g as default}; diff --git a/assets/erDiagram-762WSSOR-CtIJPNj4.js b/assets/erDiagram-762WSSOR-CqJrM1JX.js similarity index 99% rename from assets/erDiagram-762WSSOR-CtIJPNj4.js rename to assets/erDiagram-762WSSOR-CqJrM1JX.js index 7ae93af4a8..2abdd2ce9d 100644 --- a/assets/erDiagram-762WSSOR-CtIJPNj4.js +++ b/assets/erDiagram-762WSSOR-CqJrM1JX.js @@ -1,4 +1,4 @@ -import{_ as u,d as F,s as kt,g as xt,c as Rt,b as Ot,q as bt,r as Nt,l as X,t as Tt,j as at,u as At,k as Mt,a2 as vt,a8 as St,a9 as wt}from"./mermaid.core-DapiNGBY.js";import{G as It}from"./graph-Oq3lz9SV.js";import{l as Dt}from"./layout-7AWYeW5Q.js";import"./app-DBM4OJyw.js";import"./baseUniq-ZJgB7efo.js";import"./basePickBy-BXIHjUx3.js";const Lt=/^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i;function Bt(t){return typeof t=="string"&&Lt.test(t)}const M=[];for(let t=0;t<256;++t)M.push((t+256).toString(16).slice(1));function Ct(t,e=0){return M[t[e+0]]+M[t[e+1]]+M[t[e+2]]+M[t[e+3]]+"-"+M[t[e+4]]+M[t[e+5]]+"-"+M[t[e+6]]+M[t[e+7]]+"-"+M[t[e+8]]+M[t[e+9]]+"-"+M[t[e+10]]+M[t[e+11]]+M[t[e+12]]+M[t[e+13]]+M[t[e+14]]+M[t[e+15]]}function Pt(t){if(!Bt(t))throw TypeError("Invalid UUID");let e;const r=new Uint8Array(16);return r[0]=(e=parseInt(t.slice(0,8),16))>>>24,r[1]=e>>>16&255,r[2]=e>>>8&255,r[3]=e&255,r[4]=(e=parseInt(t.slice(9,13),16))>>>8,r[5]=e&255,r[6]=(e=parseInt(t.slice(14,18),16))>>>8,r[7]=e&255,r[8]=(e=parseInt(t.slice(19,23),16))>>>8,r[9]=e&255,r[10]=(e=parseInt(t.slice(24,36),16))/1099511627776&255,r[11]=e/4294967296&255,r[12]=e>>>24&255,r[13]=e>>>16&255,r[14]=e>>>8&255,r[15]=e&255,r}function Yt(t){t=unescape(encodeURIComponent(t));const e=[];for(let r=0;r>>32-e}function Ht(t){const e=[1518500249,1859775393,2400959708,3395469782],r=[1732584193,4023233417,2562383102,271733878,3285377520];if(typeof t=="string"){const y=unescape(encodeURIComponent(t));t=[];for(let o=0;o>>0;R=k,k=m,m=it(g,30)>>>0,g=h,h=D}r[0]=r[0]+h>>>0,r[1]=r[1]+g>>>0,r[2]=r[2]+m>>>0,r[3]=r[3]+k>>>0,r[4]=r[4]+R>>>0}return[r[0]>>24&255,r[0]>>16&255,r[0]>>8&255,r[0]&255,r[1]>>24&255,r[1]>>16&255,r[1]>>8&255,r[1]&255,r[2]>>24&255,r[2]>>16&255,r[2]>>8&255,r[2]&255,r[3]>>24&255,r[3]>>16&255,r[3]>>8&255,r[3]&255,r[4]>>24&255,r[4]>>16&255,r[4]>>8&255,r[4]&255]}const zt=Wt("v5",80,Ht);var nt=function(){var t=u(function(S,i,n,l){for(n=n||{},l=S.length;l--;n[S[l]]=i);return n},"o"),e=[6,8,10,20,22,24,26,27,28],r=[1,10],f=[1,11],c=[1,12],_=[1,13],y=[1,14],o=[1,15],h=[1,21],g=[1,22],m=[1,23],k=[1,24],R=[1,25],p=[6,8,10,13,15,18,19,20,22,24,26,27,28,41,42,43,44,45],T=[1,34],D=[27,28,46,47],W=[41,42,43,44,45],U=[17,34],Y=[1,54],A=[1,53],v=[17,34,36,38],O={trace:u(function(){},"trace"),yy:{},symbols_:{error:2,start:3,ER_DIAGRAM:4,document:5,EOF:6,line:7,SPACE:8,statement:9,NEWLINE:10,entityName:11,relSpec:12,":":13,role:14,BLOCK_START:15,attributes:16,BLOCK_STOP:17,SQS:18,SQE:19,title:20,title_value:21,acc_title:22,acc_title_value:23,acc_descr:24,acc_descr_value:25,acc_descr_multiline_value:26,ALPHANUM:27,ENTITY_NAME:28,attribute:29,attributeType:30,attributeName:31,attributeKeyTypeList:32,attributeComment:33,ATTRIBUTE_WORD:34,attributeKeyType:35,COMMA:36,ATTRIBUTE_KEY:37,COMMENT:38,cardinality:39,relType:40,ZERO_OR_ONE:41,ZERO_OR_MORE:42,ONE_OR_MORE:43,ONLY_ONE:44,MD_PARENT:45,NON_IDENTIFYING:46,IDENTIFYING:47,WORD:48,$accept:0,$end:1},terminals_:{2:"error",4:"ER_DIAGRAM",6:"EOF",8:"SPACE",10:"NEWLINE",13:":",15:"BLOCK_START",17:"BLOCK_STOP",18:"SQS",19:"SQE",20:"title",21:"title_value",22:"acc_title",23:"acc_title_value",24:"acc_descr",25:"acc_descr_value",26:"acc_descr_multiline_value",27:"ALPHANUM",28:"ENTITY_NAME",34:"ATTRIBUTE_WORD",36:"COMMA",37:"ATTRIBUTE_KEY",38:"COMMENT",41:"ZERO_OR_ONE",42:"ZERO_OR_MORE",43:"ONE_OR_MORE",44:"ONLY_ONE",45:"MD_PARENT",46:"NON_IDENTIFYING",47:"IDENTIFYING",48:"WORD"},productions_:[0,[3,3],[5,0],[5,2],[7,2],[7,1],[7,1],[7,1],[9,5],[9,4],[9,3],[9,1],[9,7],[9,6],[9,4],[9,2],[9,2],[9,2],[9,1],[11,1],[11,1],[16,1],[16,2],[29,2],[29,3],[29,3],[29,4],[30,1],[31,1],[32,1],[32,3],[35,1],[33,1],[12,3],[39,1],[39,1],[39,1],[39,1],[39,1],[40,1],[40,1],[14,1],[14,1],[14,1]],performAction:u(function(i,n,l,d,E,a,V){var s=a.length-1;switch(E){case 1:break;case 2:this.$=[];break;case 3:a[s-1].push(a[s]),this.$=a[s-1];break;case 4:case 5:this.$=a[s];break;case 6:case 7:this.$=[];break;case 8:d.addEntity(a[s-4]),d.addEntity(a[s-2]),d.addRelationship(a[s-4],a[s],a[s-2],a[s-3]);break;case 9:d.addEntity(a[s-3]),d.addAttributes(a[s-3],a[s-1]);break;case 10:d.addEntity(a[s-2]);break;case 11:d.addEntity(a[s]);break;case 12:d.addEntity(a[s-6],a[s-4]),d.addAttributes(a[s-6],a[s-1]);break;case 13:d.addEntity(a[s-5],a[s-3]);break;case 14:d.addEntity(a[s-3],a[s-1]);break;case 15:case 16:this.$=a[s].trim(),d.setAccTitle(this.$);break;case 17:case 18:this.$=a[s].trim(),d.setAccDescription(this.$);break;case 19:case 43:this.$=a[s];break;case 20:case 41:case 42:this.$=a[s].replace(/"/g,"");break;case 21:case 29:this.$=[a[s]];break;case 22:a[s].push(a[s-1]),this.$=a[s];break;case 23:this.$={attributeType:a[s-1],attributeName:a[s]};break;case 24:this.$={attributeType:a[s-2],attributeName:a[s-1],attributeKeyTypeList:a[s]};break;case 25:this.$={attributeType:a[s-2],attributeName:a[s-1],attributeComment:a[s]};break;case 26:this.$={attributeType:a[s-3],attributeName:a[s-2],attributeKeyTypeList:a[s-1],attributeComment:a[s]};break;case 27:case 28:case 31:this.$=a[s];break;case 30:a[s-2].push(a[s]),this.$=a[s-2];break;case 32:this.$=a[s].replace(/"/g,"");break;case 33:this.$={cardA:a[s],relType:a[s-1],cardB:a[s-2]};break;case 34:this.$=d.Cardinality.ZERO_OR_ONE;break;case 35:this.$=d.Cardinality.ZERO_OR_MORE;break;case 36:this.$=d.Cardinality.ONE_OR_MORE;break;case 37:this.$=d.Cardinality.ONLY_ONE;break;case 38:this.$=d.Cardinality.MD_PARENT;break;case 39:this.$=d.Identification.NON_IDENTIFYING;break;case 40:this.$=d.Identification.IDENTIFYING;break}},"anonymous"),table:[{3:1,4:[1,2]},{1:[3]},t(e,[2,2],{5:3}),{6:[1,4],7:5,8:[1,6],9:7,10:[1,8],11:9,20:r,22:f,24:c,26:_,27:y,28:o},t(e,[2,7],{1:[2,1]}),t(e,[2,3]),{9:16,11:9,20:r,22:f,24:c,26:_,27:y,28:o},t(e,[2,5]),t(e,[2,6]),t(e,[2,11],{12:17,39:20,15:[1,18],18:[1,19],41:h,42:g,43:m,44:k,45:R}),{21:[1,26]},{23:[1,27]},{25:[1,28]},t(e,[2,18]),t(p,[2,19]),t(p,[2,20]),t(e,[2,4]),{11:29,27:y,28:o},{16:30,17:[1,31],29:32,30:33,34:T},{11:35,27:y,28:o},{40:36,46:[1,37],47:[1,38]},t(D,[2,34]),t(D,[2,35]),t(D,[2,36]),t(D,[2,37]),t(D,[2,38]),t(e,[2,15]),t(e,[2,16]),t(e,[2,17]),{13:[1,39]},{17:[1,40]},t(e,[2,10]),{16:41,17:[2,21],29:32,30:33,34:T},{31:42,34:[1,43]},{34:[2,27]},{19:[1,44]},{39:45,41:h,42:g,43:m,44:k,45:R},t(W,[2,39]),t(W,[2,40]),{14:46,27:[1,49],28:[1,48],48:[1,47]},t(e,[2,9]),{17:[2,22]},t(U,[2,23],{32:50,33:51,35:52,37:Y,38:A}),t([17,34,37,38],[2,28]),t(e,[2,14],{15:[1,55]}),t([27,28],[2,33]),t(e,[2,8]),t(e,[2,41]),t(e,[2,42]),t(e,[2,43]),t(U,[2,24],{33:56,36:[1,57],38:A}),t(U,[2,25]),t(v,[2,29]),t(U,[2,32]),t(v,[2,31]),{16:58,17:[1,59],29:32,30:33,34:T},t(U,[2,26]),{35:60,37:Y},{17:[1,61]},t(e,[2,13]),t(v,[2,30]),t(e,[2,12])],defaultActions:{34:[2,27],41:[2,22]},parseError:u(function(i,n){if(n.recoverable)this.trace(i);else{var l=new Error(i);throw l.hash=n,l}},"parseError"),parse:u(function(i){var n=this,l=[0],d=[],E=[null],a=[],V=this.table,s="",j=0,lt=0,_t=2,ct=1,Et=a.slice.call(arguments,1),N=Object.create(this.lexer),H={yy:{}};for(var $ in this.yy)Object.prototype.hasOwnProperty.call(this.yy,$)&&(H.yy[$]=this.yy[$]);N.setInput(i,H.yy),H.yy.lexer=N,H.yy.parser=this,typeof N.yylloc>"u"&&(N.yylloc={});var tt=N.yylloc;a.push(tt);var gt=N.options&&N.options.ranges;typeof H.yy.parseError=="function"?this.parseError=H.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function mt(I){l.length=l.length-2*I,E.length=E.length-I,a.length=a.length-I}u(mt,"popStack");function ht(){var I;return I=d.pop()||N.lex()||ct,typeof I!="number"&&(I instanceof Array&&(d=I,I=d.pop()),I=n.symbols_[I]||I),I}u(ht,"lex");for(var w,z,B,et,K={},q,Z,dt,J;;){if(z=l[l.length-1],this.defaultActions[z]?B=this.defaultActions[z]:((w===null||typeof w>"u")&&(w=ht()),B=V[z]&&V[z][w]),typeof B>"u"||!B.length||!B[0]){var rt="";J=[];for(q in V[z])this.terminals_[q]&&q>_t&&J.push("'"+this.terminals_[q]+"'");N.showPosition?rt="Parse error on line "+(j+1)+`: +import{_ as u,d as F,s as kt,g as xt,c as Rt,b as Ot,q as bt,r as Nt,l as X,t as Tt,j as at,u as At,k as Mt,a2 as vt,a8 as St,a9 as wt}from"./mermaid.core-D8igZDel.js";import{G as It}from"./graph-Cjb-DGHB.js";import{l as Dt}from"./layout-CHeuV-iP.js";import"./app-D7uBbsY3.js";import"./baseUniq-D0lZO5yp.js";import"./basePickBy-DpnmgMOi.js";const Lt=/^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i;function Bt(t){return typeof t=="string"&&Lt.test(t)}const M=[];for(let t=0;t<256;++t)M.push((t+256).toString(16).slice(1));function Ct(t,e=0){return M[t[e+0]]+M[t[e+1]]+M[t[e+2]]+M[t[e+3]]+"-"+M[t[e+4]]+M[t[e+5]]+"-"+M[t[e+6]]+M[t[e+7]]+"-"+M[t[e+8]]+M[t[e+9]]+"-"+M[t[e+10]]+M[t[e+11]]+M[t[e+12]]+M[t[e+13]]+M[t[e+14]]+M[t[e+15]]}function Pt(t){if(!Bt(t))throw TypeError("Invalid UUID");let e;const r=new Uint8Array(16);return r[0]=(e=parseInt(t.slice(0,8),16))>>>24,r[1]=e>>>16&255,r[2]=e>>>8&255,r[3]=e&255,r[4]=(e=parseInt(t.slice(9,13),16))>>>8,r[5]=e&255,r[6]=(e=parseInt(t.slice(14,18),16))>>>8,r[7]=e&255,r[8]=(e=parseInt(t.slice(19,23),16))>>>8,r[9]=e&255,r[10]=(e=parseInt(t.slice(24,36),16))/1099511627776&255,r[11]=e/4294967296&255,r[12]=e>>>24&255,r[13]=e>>>16&255,r[14]=e>>>8&255,r[15]=e&255,r}function Yt(t){t=unescape(encodeURIComponent(t));const e=[];for(let r=0;r>>32-e}function Ht(t){const e=[1518500249,1859775393,2400959708,3395469782],r=[1732584193,4023233417,2562383102,271733878,3285377520];if(typeof t=="string"){const y=unescape(encodeURIComponent(t));t=[];for(let o=0;o>>0;R=k,k=m,m=it(g,30)>>>0,g=h,h=D}r[0]=r[0]+h>>>0,r[1]=r[1]+g>>>0,r[2]=r[2]+m>>>0,r[3]=r[3]+k>>>0,r[4]=r[4]+R>>>0}return[r[0]>>24&255,r[0]>>16&255,r[0]>>8&255,r[0]&255,r[1]>>24&255,r[1]>>16&255,r[1]>>8&255,r[1]&255,r[2]>>24&255,r[2]>>16&255,r[2]>>8&255,r[2]&255,r[3]>>24&255,r[3]>>16&255,r[3]>>8&255,r[3]&255,r[4]>>24&255,r[4]>>16&255,r[4]>>8&255,r[4]&255]}const zt=Wt("v5",80,Ht);var nt=function(){var t=u(function(S,i,n,l){for(n=n||{},l=S.length;l--;n[S[l]]=i);return n},"o"),e=[6,8,10,20,22,24,26,27,28],r=[1,10],f=[1,11],c=[1,12],_=[1,13],y=[1,14],o=[1,15],h=[1,21],g=[1,22],m=[1,23],k=[1,24],R=[1,25],p=[6,8,10,13,15,18,19,20,22,24,26,27,28,41,42,43,44,45],T=[1,34],D=[27,28,46,47],W=[41,42,43,44,45],U=[17,34],Y=[1,54],A=[1,53],v=[17,34,36,38],O={trace:u(function(){},"trace"),yy:{},symbols_:{error:2,start:3,ER_DIAGRAM:4,document:5,EOF:6,line:7,SPACE:8,statement:9,NEWLINE:10,entityName:11,relSpec:12,":":13,role:14,BLOCK_START:15,attributes:16,BLOCK_STOP:17,SQS:18,SQE:19,title:20,title_value:21,acc_title:22,acc_title_value:23,acc_descr:24,acc_descr_value:25,acc_descr_multiline_value:26,ALPHANUM:27,ENTITY_NAME:28,attribute:29,attributeType:30,attributeName:31,attributeKeyTypeList:32,attributeComment:33,ATTRIBUTE_WORD:34,attributeKeyType:35,COMMA:36,ATTRIBUTE_KEY:37,COMMENT:38,cardinality:39,relType:40,ZERO_OR_ONE:41,ZERO_OR_MORE:42,ONE_OR_MORE:43,ONLY_ONE:44,MD_PARENT:45,NON_IDENTIFYING:46,IDENTIFYING:47,WORD:48,$accept:0,$end:1},terminals_:{2:"error",4:"ER_DIAGRAM",6:"EOF",8:"SPACE",10:"NEWLINE",13:":",15:"BLOCK_START",17:"BLOCK_STOP",18:"SQS",19:"SQE",20:"title",21:"title_value",22:"acc_title",23:"acc_title_value",24:"acc_descr",25:"acc_descr_value",26:"acc_descr_multiline_value",27:"ALPHANUM",28:"ENTITY_NAME",34:"ATTRIBUTE_WORD",36:"COMMA",37:"ATTRIBUTE_KEY",38:"COMMENT",41:"ZERO_OR_ONE",42:"ZERO_OR_MORE",43:"ONE_OR_MORE",44:"ONLY_ONE",45:"MD_PARENT",46:"NON_IDENTIFYING",47:"IDENTIFYING",48:"WORD"},productions_:[0,[3,3],[5,0],[5,2],[7,2],[7,1],[7,1],[7,1],[9,5],[9,4],[9,3],[9,1],[9,7],[9,6],[9,4],[9,2],[9,2],[9,2],[9,1],[11,1],[11,1],[16,1],[16,2],[29,2],[29,3],[29,3],[29,4],[30,1],[31,1],[32,1],[32,3],[35,1],[33,1],[12,3],[39,1],[39,1],[39,1],[39,1],[39,1],[40,1],[40,1],[14,1],[14,1],[14,1]],performAction:u(function(i,n,l,d,E,a,V){var s=a.length-1;switch(E){case 1:break;case 2:this.$=[];break;case 3:a[s-1].push(a[s]),this.$=a[s-1];break;case 4:case 5:this.$=a[s];break;case 6:case 7:this.$=[];break;case 8:d.addEntity(a[s-4]),d.addEntity(a[s-2]),d.addRelationship(a[s-4],a[s],a[s-2],a[s-3]);break;case 9:d.addEntity(a[s-3]),d.addAttributes(a[s-3],a[s-1]);break;case 10:d.addEntity(a[s-2]);break;case 11:d.addEntity(a[s]);break;case 12:d.addEntity(a[s-6],a[s-4]),d.addAttributes(a[s-6],a[s-1]);break;case 13:d.addEntity(a[s-5],a[s-3]);break;case 14:d.addEntity(a[s-3],a[s-1]);break;case 15:case 16:this.$=a[s].trim(),d.setAccTitle(this.$);break;case 17:case 18:this.$=a[s].trim(),d.setAccDescription(this.$);break;case 19:case 43:this.$=a[s];break;case 20:case 41:case 42:this.$=a[s].replace(/"/g,"");break;case 21:case 29:this.$=[a[s]];break;case 22:a[s].push(a[s-1]),this.$=a[s];break;case 23:this.$={attributeType:a[s-1],attributeName:a[s]};break;case 24:this.$={attributeType:a[s-2],attributeName:a[s-1],attributeKeyTypeList:a[s]};break;case 25:this.$={attributeType:a[s-2],attributeName:a[s-1],attributeComment:a[s]};break;case 26:this.$={attributeType:a[s-3],attributeName:a[s-2],attributeKeyTypeList:a[s-1],attributeComment:a[s]};break;case 27:case 28:case 31:this.$=a[s];break;case 30:a[s-2].push(a[s]),this.$=a[s-2];break;case 32:this.$=a[s].replace(/"/g,"");break;case 33:this.$={cardA:a[s],relType:a[s-1],cardB:a[s-2]};break;case 34:this.$=d.Cardinality.ZERO_OR_ONE;break;case 35:this.$=d.Cardinality.ZERO_OR_MORE;break;case 36:this.$=d.Cardinality.ONE_OR_MORE;break;case 37:this.$=d.Cardinality.ONLY_ONE;break;case 38:this.$=d.Cardinality.MD_PARENT;break;case 39:this.$=d.Identification.NON_IDENTIFYING;break;case 40:this.$=d.Identification.IDENTIFYING;break}},"anonymous"),table:[{3:1,4:[1,2]},{1:[3]},t(e,[2,2],{5:3}),{6:[1,4],7:5,8:[1,6],9:7,10:[1,8],11:9,20:r,22:f,24:c,26:_,27:y,28:o},t(e,[2,7],{1:[2,1]}),t(e,[2,3]),{9:16,11:9,20:r,22:f,24:c,26:_,27:y,28:o},t(e,[2,5]),t(e,[2,6]),t(e,[2,11],{12:17,39:20,15:[1,18],18:[1,19],41:h,42:g,43:m,44:k,45:R}),{21:[1,26]},{23:[1,27]},{25:[1,28]},t(e,[2,18]),t(p,[2,19]),t(p,[2,20]),t(e,[2,4]),{11:29,27:y,28:o},{16:30,17:[1,31],29:32,30:33,34:T},{11:35,27:y,28:o},{40:36,46:[1,37],47:[1,38]},t(D,[2,34]),t(D,[2,35]),t(D,[2,36]),t(D,[2,37]),t(D,[2,38]),t(e,[2,15]),t(e,[2,16]),t(e,[2,17]),{13:[1,39]},{17:[1,40]},t(e,[2,10]),{16:41,17:[2,21],29:32,30:33,34:T},{31:42,34:[1,43]},{34:[2,27]},{19:[1,44]},{39:45,41:h,42:g,43:m,44:k,45:R},t(W,[2,39]),t(W,[2,40]),{14:46,27:[1,49],28:[1,48],48:[1,47]},t(e,[2,9]),{17:[2,22]},t(U,[2,23],{32:50,33:51,35:52,37:Y,38:A}),t([17,34,37,38],[2,28]),t(e,[2,14],{15:[1,55]}),t([27,28],[2,33]),t(e,[2,8]),t(e,[2,41]),t(e,[2,42]),t(e,[2,43]),t(U,[2,24],{33:56,36:[1,57],38:A}),t(U,[2,25]),t(v,[2,29]),t(U,[2,32]),t(v,[2,31]),{16:58,17:[1,59],29:32,30:33,34:T},t(U,[2,26]),{35:60,37:Y},{17:[1,61]},t(e,[2,13]),t(v,[2,30]),t(e,[2,12])],defaultActions:{34:[2,27],41:[2,22]},parseError:u(function(i,n){if(n.recoverable)this.trace(i);else{var l=new Error(i);throw l.hash=n,l}},"parseError"),parse:u(function(i){var n=this,l=[0],d=[],E=[null],a=[],V=this.table,s="",j=0,lt=0,_t=2,ct=1,Et=a.slice.call(arguments,1),N=Object.create(this.lexer),H={yy:{}};for(var $ in this.yy)Object.prototype.hasOwnProperty.call(this.yy,$)&&(H.yy[$]=this.yy[$]);N.setInput(i,H.yy),H.yy.lexer=N,H.yy.parser=this,typeof N.yylloc>"u"&&(N.yylloc={});var tt=N.yylloc;a.push(tt);var gt=N.options&&N.options.ranges;typeof H.yy.parseError=="function"?this.parseError=H.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function mt(I){l.length=l.length-2*I,E.length=E.length-I,a.length=a.length-I}u(mt,"popStack");function ht(){var I;return I=d.pop()||N.lex()||ct,typeof I!="number"&&(I instanceof Array&&(d=I,I=d.pop()),I=n.symbols_[I]||I),I}u(ht,"lex");for(var w,z,B,et,K={},q,Z,dt,J;;){if(z=l[l.length-1],this.defaultActions[z]?B=this.defaultActions[z]:((w===null||typeof w>"u")&&(w=ht()),B=V[z]&&V[z][w]),typeof B>"u"||!B.length||!B[0]){var rt="";J=[];for(q in V[z])this.terminals_[q]&&q>_t&&J.push("'"+this.terminals_[q]+"'");N.showPosition?rt="Parse error on line "+(j+1)+`: `+N.showPosition()+` Expecting `+J.join(", ")+", got '"+(this.terminals_[w]||w)+"'":rt="Parse error on line "+(j+1)+": Unexpected "+(w==ct?"end of input":"'"+(this.terminals_[w]||w)+"'"),this.parseError(rt,{text:N.match,token:this.terminals_[w]||w,line:N.yylineno,loc:tt,expected:J})}if(B[0]instanceof Array&&B.length>1)throw new Error("Parse Error: multiple actions possible at state: "+z+", token: "+w);switch(B[0]){case 1:l.push(w),E.push(N.yytext),a.push(N.yylloc),l.push(B[1]),w=null,lt=N.yyleng,s=N.yytext,j=N.yylineno,tt=N.yylloc;break;case 2:if(Z=this.productions_[B[1]][1],K.$=E[E.length-Z],K._$={first_line:a[a.length-(Z||1)].first_line,last_line:a[a.length-1].last_line,first_column:a[a.length-(Z||1)].first_column,last_column:a[a.length-1].last_column},gt&&(K._$.range=[a[a.length-(Z||1)].range[0],a[a.length-1].range[1]]),et=this.performAction.apply(K,[s,lt,j,H.yy,B[1],E,a].concat(Et)),typeof et<"u")return et;Z&&(l=l.slice(0,-1*Z*2),E=E.slice(0,-1*Z),a=a.slice(0,-1*Z)),l.push(this.productions_[B[1]][0]),E.push(K.$),a.push(K._$),dt=V[l[l.length-2]][l[l.length-1]],l.push(dt);break;case 3:return!0}}return!0},"parse")},b=function(){var S={EOF:1,parseError:u(function(n,l){if(this.yy.parser)this.yy.parser.parseError(n,l);else throw new Error(n)},"parseError"),setInput:u(function(i,n){return this.yy=n||this.yy||{},this._input=i,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},"setInput"),input:u(function(){var i=this._input[0];this.yytext+=i,this.yyleng++,this.offset++,this.match+=i,this.matched+=i;var n=i.match(/(?:\r\n?|\n).*/g);return n?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),i},"input"),unput:u(function(i){var n=i.length,l=i.split(/(?:\r\n?|\n)/g);this._input=i+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-n),this.offset-=n;var d=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),l.length-1&&(this.yylineno-=l.length-1);var E=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:l?(l.length===d.length?this.yylloc.first_column:0)+d[d.length-l.length].length-l[0].length:this.yylloc.first_column-n},this.options.ranges&&(this.yylloc.range=[E[0],E[0]+this.yyleng-n]),this.yyleng=this.yytext.length,this},"unput"),more:u(function(){return this._more=!0,this},"more"),reject:u(function(){if(this.options.backtrack_lexer)this._backtrack=!0;else return this.parseError("Lexical error on line "+(this.yylineno+1)+`. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true). `+this.showPosition(),{text:"",token:null,line:this.yylineno});return this},"reject"),less:u(function(i){this.unput(this.match.slice(i))},"less"),pastInput:u(function(){var i=this.matched.substr(0,this.matched.length-this.match.length);return(i.length>20?"...":"")+i.substr(-20).replace(/\n/g,"")},"pastInput"),upcomingInput:u(function(){var i=this.match;return i.length<20&&(i+=this._input.substr(0,20-i.length)),(i.substr(0,20)+(i.length>20?"...":"")).replace(/\n/g,"")},"upcomingInput"),showPosition:u(function(){var i=this.pastInput(),n=new Array(i.length+1).join("-");return i+this.upcomingInput()+` diff --git a/assets/fakedns.html-BQH6Y2PN.js b/assets/fakedns.html-CTFi8abb.js similarity index 99% rename from assets/fakedns.html-BQH6Y2PN.js rename to assets/fakedns.html-CTFi8abb.js index db0a0c08b5..f07b6fed1a 100644 --- a/assets/fakedns.html-BQH6Y2PN.js +++ b/assets/fakedns.html-CTFi8abb.js @@ -1,4 +1,4 @@ -import{_ as p,r as s,o as i,c,a,b as l,d as n,w as u,e}from"./app-DBM4OJyw.js";const r={},d=e(`

                                      FakeDNS

                                      FakeDNS is used to obtain target domain names by forging DNS, which can reduce the delay in DNS queries and work with transparent proxies to obtain target domain names.

                                      Warning

                                      FakeDNS may contaminate the local DNS and cause "network unreachable" after Xray is closed.

                                      FakeDNSObject

                                      FakeDNSObject corresponds to the fakedns item in the configuration file.

                                      {
                                      +import{_ as p,r as s,o as i,c,a,b as l,d as n,w as u,e}from"./app-D7uBbsY3.js";const r={},d=e(`

                                      FakeDNS

                                      FakeDNS is used to obtain target domain names by forging DNS, which can reduce the delay in DNS queries and work with transparent proxies to obtain target domain names.

                                      Warning

                                      FakeDNS may contaminate the local DNS and cause "network unreachable" after Xray is closed.

                                      FakeDNSObject

                                      FakeDNSObject corresponds to the fakedns item in the configuration file.

                                      {
                                         "ipPool": "198.18.0.0/16",
                                         "poolSize": 65535
                                       }
                                      diff --git a/assets/fakedns.html-xFYf-feg.js b/assets/fakedns.html-D0qX2V-i.js
                                      similarity index 99%
                                      rename from assets/fakedns.html-xFYf-feg.js
                                      rename to assets/fakedns.html-D0qX2V-i.js
                                      index 41b12003f7..d5a9e00559 100644
                                      --- a/assets/fakedns.html-xFYf-feg.js
                                      +++ b/assets/fakedns.html-D0qX2V-i.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as p,r as s,o as c,c as i,a,b as l,d as n,w as u,e}from"./app-DBM4OJyw.js";const d={},r=e(`

                                      FakeDNS

                                      FakeDNS подменяет DNS-записи, чтобы получить целевое доменное имя, что позволяет сократить время DNS-запросов и получить целевое доменное имя при использовании прозрачного проксирования.

                                      Внимание

                                      FakeDNS может загрязнить локальный DNS-кэш, что может привести к "недоступности сети" после отключения Xray.

                                      FakeDNSObject

                                      FakeDNSObject соответствует полю fakedns в конфигурационном файле.

                                      {
                                      +import{_ as p,r as s,o as c,c as i,a,b as l,d as n,w as u,e}from"./app-D7uBbsY3.js";const d={},r=e(`

                                      FakeDNS

                                      FakeDNS подменяет DNS-записи, чтобы получить целевое доменное имя, что позволяет сократить время DNS-запросов и получить целевое доменное имя при использовании прозрачного проксирования.

                                      Внимание

                                      FakeDNS может загрязнить локальный DNS-кэш, что может привести к "недоступности сети" после отключения Xray.

                                      FakeDNSObject

                                      FakeDNSObject соответствует полю fakedns в конфигурационном файле.

                                      {
                                         "ipPool": "198.18.0.0/16",
                                         "poolSize": 65535
                                       }
                                      diff --git a/assets/fakedns.html-DHh-5fVH.js b/assets/fakedns.html-Dy1ai5db.js
                                      similarity index 99%
                                      rename from assets/fakedns.html-DHh-5fVH.js
                                      rename to assets/fakedns.html-Dy1ai5db.js
                                      index 7de01f8db9..0d70769bfc 100644
                                      --- a/assets/fakedns.html-DHh-5fVH.js
                                      +++ b/assets/fakedns.html-Dy1ai5db.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as p,r as s,o as c,c as i,a,b as l,d as n,w as u,e}from"./app-DBM4OJyw.js";const d={},r=e(`

                                      FakeDNS

                                      FakeDNS 通过伪造 DNS 以获取目标域名,能够降低 DNS 查询时的延迟、配合透明代理获取目标域名。

                                      注意

                                      FakeDNS 有可能会污染本地 DNS,导致 Xray 关闭后“无法访问网络”。

                                      FakeDNSObject

                                      FakeDNSObject 对应配置文件的 fakedns 项。

                                      {
                                      +import{_ as p,r as s,o as c,c as i,a,b as l,d as n,w as u,e}from"./app-D7uBbsY3.js";const d={},r=e(`

                                      FakeDNS

                                      FakeDNS 通过伪造 DNS 以获取目标域名,能够降低 DNS 查询时的延迟、配合透明代理获取目标域名。

                                      注意

                                      FakeDNS 有可能会污染本地 DNS,导致 Xray 关闭后“无法访问网络”。

                                      FakeDNSObject

                                      FakeDNSObject 对应配置文件的 fakedns 项。

                                      {
                                         "ipPool": "198.18.0.0/16",
                                         "poolSize": 65535
                                       }
                                      diff --git a/assets/fallback.html-DHH-5c7i.js b/assets/fallback.html-BEtjGlT0.js
                                      similarity index 99%
                                      rename from assets/fallback.html-DHH-5c7i.js
                                      rename to assets/fallback.html-BEtjGlT0.js
                                      index 6dd928e509..11b9e5e5b3 100644
                                      --- a/assets/fallback.html-DHH-5c7i.js
                                      +++ b/assets/fallback.html-BEtjGlT0.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as r,r as n,o as d,c as p,a as o,b as e,d as t,w as u,e as a}from"./app-DBM4OJyw.js";const h={},f=a(`

                                      Fallback

                                      Fallback is one of the most powerful features of Xray, which can effectively prevent active probing and allows you to use one port for multiple services

                                      Fallback provides Xray with high-strength anti-active probing capabilities and has a unique first-packet fallback mechanism.

                                      Fallback can also divide traffic of different types based on path for multi-service sharing on a single port.

                                      Currently, you can use the fallback feature by configuring fallbacks when using VLESS or Trojan protocols, thus creating an unimaginable combo of services becomes REALITY.

                                      fallbacks configuration

                                        "fallbacks": [
                                      +import{_ as r,r as n,o as d,c as p,a as o,b as e,d as t,w as u,e as a}from"./app-D7uBbsY3.js";const h={},f=a(`

                                      Fallback

                                      Fallback is one of the most powerful features of Xray, which can effectively prevent active probing and allows you to use one port for multiple services

                                      Fallback provides Xray with high-strength anti-active probing capabilities and has a unique first-packet fallback mechanism.

                                      Fallback can also divide traffic of different types based on path for multi-service sharing on a single port.

                                      Currently, you can use the fallback feature by configuring fallbacks when using VLESS or Trojan protocols, thus creating an unimaginable combo of services becomes REALITY.

                                      fallbacks configuration

                                        "fallbacks": [
                                           {
                                             "dest": 80
                                           }
                                      diff --git a/assets/fallback.html-DyfId2wt.js b/assets/fallback.html-CEhYGCcm.js
                                      similarity index 99%
                                      rename from assets/fallback.html-DyfId2wt.js
                                      rename to assets/fallback.html-CEhYGCcm.js
                                      index 98ac1022a0..70c0f29e15 100644
                                      --- a/assets/fallback.html-DyfId2wt.js
                                      +++ b/assets/fallback.html-CEhYGCcm.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as d,r as e,o as i,c as u,a as o,b as n,d as a,w as c,e as t}from"./app-DBM4OJyw.js";const b={},k=t(`

                                      Fallback 回落

                                      Fallback 是 Xray 的最强大功能之一, 可有效防止主动探测, 自由配置常用端口多服务共享

                                      fallback 为 Xray 提供了高强度的防主动探测性, 并且具有独创的首包回落机制.

                                      fallback 也可以将不同类型的流量根据 path 进行分流, 从而实现一个端口, 多种服务共享.

                                      目前您可以在使用 VLESS 或者 trojan 协议时, 通过配置 fallbacks 来使用回落这一特性, 并且创造出非常丰富的组合玩法.

                                      fallbacks 配置

                                        "fallbacks": [
                                      +import{_ as d,r as e,o as i,c as u,a as o,b as n,d as a,w as c,e as t}from"./app-D7uBbsY3.js";const b={},k=t(`

                                      Fallback 回落

                                      Fallback 是 Xray 的最强大功能之一, 可有效防止主动探测, 自由配置常用端口多服务共享

                                      fallback 为 Xray 提供了高强度的防主动探测性, 并且具有独创的首包回落机制.

                                      fallback 也可以将不同类型的流量根据 path 进行分流, 从而实现一个端口, 多种服务共享.

                                      目前您可以在使用 VLESS 或者 trojan 协议时, 通过配置 fallbacks 来使用回落这一特性, 并且创造出非常丰富的组合玩法.

                                      fallbacks 配置

                                        "fallbacks": [
                                           {
                                             "dest": 80
                                           }
                                      diff --git a/assets/fallback.html-BrxCKulv.js b/assets/fallback.html-DhKkR0oG.js
                                      similarity index 99%
                                      rename from assets/fallback.html-BrxCKulv.js
                                      rename to assets/fallback.html-DhKkR0oG.js
                                      index 69eb17608b..5ef0451c14 100644
                                      --- a/assets/fallback.html-BrxCKulv.js
                                      +++ b/assets/fallback.html-DhKkR0oG.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as r,r as e,o as i,c as u,a,b as n,d as o,w as c,e as s}from"./app-DBM4OJyw.js";const b={},k=s(`

                                      Fallback

                                      Fallback - одна из самых мощных функций Xray, эффективно предотвращающая активное зондирование и позволяющая свободно настраивать совместное использование нескольких служб на часто используемых портах.

                                      Fallback обеспечивает Xray высокой степенью защиты от активного зондирования и имеет уникальный механизм резервирования первого пакета.

                                      Fallback также может разделять трафик различных типов по пути, что позволяет совместно использовать один порт для нескольких служб.

                                      В настоящее время вы можете использовать функцию fallback при использовании протоколов VLESS или Trojan, настроив fallbacks, и создавать очень разнообразные комбинации.

                                      Настройка fallbacks

                                        "fallbacks": [
                                      +import{_ as r,r as e,o as i,c as u,a,b as n,d as o,w as c,e as s}from"./app-D7uBbsY3.js";const b={},k=s(`

                                      Fallback

                                      Fallback - одна из самых мощных функций Xray, эффективно предотвращающая активное зондирование и позволяющая свободно настраивать совместное использование нескольких служб на часто используемых портах.

                                      Fallback обеспечивает Xray высокой степенью защиты от активного зондирования и имеет уникальный механизм резервирования первого пакета.

                                      Fallback также может разделять трафик различных типов по пути, что позволяет совместно использовать один порт для нескольких служб.

                                      В настоящее время вы можете использовать функцию fallback при использовании протоколов VLESS или Trojan, настроив fallbacks, и создавать очень разнообразные комбинации.

                                      Настройка fallbacks

                                        "fallbacks": [
                                           {
                                             "dest": 80
                                           }
                                      diff --git a/assets/fallbacks-lv1.html-Dfkic9nm.js b/assets/fallbacks-lv1.html-BJFkz_Io.js
                                      similarity index 99%
                                      rename from assets/fallbacks-lv1.html-Dfkic9nm.js
                                      rename to assets/fallbacks-lv1.html-BJFkz_Io.js
                                      index 6bc44aeaa4..a7330102f9 100644
                                      --- a/assets/fallbacks-lv1.html-Dfkic9nm.js
                                      +++ b/assets/fallbacks-lv1.html-BJFkz_Io.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as u,r as t,o as r,c as d,a,b as n,d as s,w as l,e as o}from"./app-DBM4OJyw.js";const k={},v=n("h1",{id:"回落-fallbacks-功能简析",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#回落-fallbacks-功能简析"},[n("span",null,"回落 (fallbacks) 功能简析")])],-1),m=n("p",null,"在使用 Xray 的过程中,你一定无数次的听说了【回落】这个功能。本文就稍微说明一下这个功能的逻辑以及使用方式。",-1),q=n("h2",{id:"_1-回顾《小小白白话文》中的回落",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#_1-回顾《小小白白话文》中的回落"},[n("span",null,"1. 回顾《小小白白话文》中的回落")])],-1),b=n("code",null,"VLESS",-1),E=o(`
                                      {
                                      +import{_ as u,r as t,o as r,c as d,a,b as n,d as s,w as l,e as o}from"./app-D7uBbsY3.js";const k={},v=n("h1",{id:"回落-fallbacks-功能简析",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#回落-fallbacks-功能简析"},[n("span",null,"回落 (fallbacks) 功能简析")])],-1),m=n("p",null,"在使用 Xray 的过程中,你一定无数次的听说了【回落】这个功能。本文就稍微说明一下这个功能的逻辑以及使用方式。",-1),q=n("h2",{id:"_1-回顾《小小白白话文》中的回落",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#_1-回顾《小小白白话文》中的回落"},[n("span",null,"1. 回顾《小小白白话文》中的回落")])],-1),b=n("code",null,"VLESS",-1),E=o(`
                                      {
                                         "inbounds": [
                                           {
                                             "port": 443,
                                      diff --git a/assets/fallbacks-lv1.html-D0PORcDs.js b/assets/fallbacks-lv1.html-D3I9arTU.js
                                      similarity index 99%
                                      rename from assets/fallbacks-lv1.html-D0PORcDs.js
                                      rename to assets/fallbacks-lv1.html-D3I9arTU.js
                                      index 8a24846ee7..05d13d6eac 100644
                                      --- a/assets/fallbacks-lv1.html-D0PORcDs.js
                                      +++ b/assets/fallbacks-lv1.html-D3I9arTU.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as u,r as t,o as r,c as d,a,b as n,d as s,w as l,e as o}from"./app-DBM4OJyw.js";const k={},v=n("h1",{id:"回落-fallbacks-功能简析",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#回落-fallbacks-功能简析"},[n("span",null,"回落 (fallbacks) 功能简析")])],-1),m=n("p",null,"在使用 Xray 的过程中,你一定无数次的听说了【回落】这个功能。本文就稍微说明一下这个功能的逻辑以及使用方式。",-1),q=n("h2",{id:"_1-回顾《小小白白话文》中的回落",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#_1-回顾《小小白白话文》中的回落"},[n("span",null,"1. 回顾《小小白白话文》中的回落")])],-1),b=n("code",null,"VLESS",-1),E=o(`
                                      {
                                      +import{_ as u,r as t,o as r,c as d,a,b as n,d as s,w as l,e as o}from"./app-D7uBbsY3.js";const k={},v=n("h1",{id:"回落-fallbacks-功能简析",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#回落-fallbacks-功能简析"},[n("span",null,"回落 (fallbacks) 功能简析")])],-1),m=n("p",null,"在使用 Xray 的过程中,你一定无数次的听说了【回落】这个功能。本文就稍微说明一下这个功能的逻辑以及使用方式。",-1),q=n("h2",{id:"_1-回顾《小小白白话文》中的回落",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#_1-回顾《小小白白话文》中的回落"},[n("span",null,"1. 回顾《小小白白话文》中的回落")])],-1),b=n("code",null,"VLESS",-1),E=o(`
                                      {
                                         "inbounds": [
                                           {
                                             "port": 443,
                                      diff --git a/assets/fallbacks-lv1.html-BWGggl2y.js b/assets/fallbacks-lv1.html-djmxllKD.js
                                      similarity index 99%
                                      rename from assets/fallbacks-lv1.html-BWGggl2y.js
                                      rename to assets/fallbacks-lv1.html-djmxllKD.js
                                      index 9ee4acb542..b9cc3f5b08 100644
                                      --- a/assets/fallbacks-lv1.html-BWGggl2y.js
                                      +++ b/assets/fallbacks-lv1.html-djmxllKD.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as r,r as t,o as u,c as d,a,b as n,d as s,w as l,e as o}from"./app-DBM4OJyw.js";const k={},v=n("h1",{id:"обзор-функции-fallback",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#обзор-функции-fallback"},[n("span",null,"Обзор функции Fallback")])],-1),D=n("p",null,[s("При использовании Xray вы наверняка много раз слышали о функции "),n("strong",null,'"fallback"'),s(". В этой статье мы кратко рассмотрим логику этой функции и способы ее применения.")],-1),m=n("h2",{id:"_1-что-такое-fallback-в-простых-словах",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#_1-что-такое-fallback-в-простых-словах"},[n("span",null,"1. Что такое Fallback в простых словах")])],-1),b=n("code",null,"VLESS",-1),q=o(`
                                      {
                                      +import{_ as r,r as t,o as u,c as d,a,b as n,d as s,w as l,e as o}from"./app-D7uBbsY3.js";const k={},v=n("h1",{id:"обзор-функции-fallback",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#обзор-функции-fallback"},[n("span",null,"Обзор функции Fallback")])],-1),D=n("p",null,[s("При использовании Xray вы наверняка много раз слышали о функции "),n("strong",null,'"fallback"'),s(". В этой статье мы кратко рассмотрим логику этой функции и способы ее применения.")],-1),m=n("h2",{id:"_1-что-такое-fallback-в-простых-словах",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#_1-что-такое-fallback-в-простых-словах"},[n("span",null,"1. Что такое Fallback в простых словах")])],-1),b=n("code",null,"VLESS",-1),q=o(`
                                      {
                                         "inbounds": [
                                           {
                                             "port": 443,
                                      diff --git a/assets/fallbacks-with-sni.html-wlH1uh5I.js b/assets/fallbacks-with-sni.html-CV6F-_Vm.js
                                      similarity index 99%
                                      rename from assets/fallbacks-with-sni.html-wlH1uh5I.js
                                      rename to assets/fallbacks-with-sni.html-CV6F-_Vm.js
                                      index 94c837abf3..6f68f53c8e 100644
                                      --- a/assets/fallbacks-with-sni.html-wlH1uh5I.js
                                      +++ b/assets/fallbacks-with-sni.html-CV6F-_Vm.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as l,r as o,o as i,c,a,b as n,d as s,e as t}from"./app-DBM4OJyw.js";const r="/assets/xray-fallbacks-gLm6MqAx.svg",u="/assets/xray-dns-records-lpau4JTO.webp",d="/assets/cf-api-token-permissions-for-acme-BmGfLU86.webp",v={},k=n("h1",{id:"маскировка-и-разделение-трафика-по-доменам-с-помощью-функции-sni-fallback",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#маскировка-и-разделение-трафика-по-доменам-с-помощью-функции-sni-fallback"},[n("span",null,"Маскировка и разделение трафика по доменам с помощью функции SNI Fallback")])],-1),m=t(`

                                      VLESS - это очень легкий протокол, который, как и Trojan, не использует сложного шифрования и обфускации трафика. Вместо этого он, подобно тому, как искусный мастер кунг-фу скрывает свою силу, шифрует трафик с помощью протокола TLS, маскируя его под обычный HTTPS-трафик и позволяя ему беспрепятственно проходить через Великий китайский файрвол. Для лучшей маскировки от активного зондирования вместе с VLESS была представлена функция Fallbacks (резервирование). В этой статье мы рассмотрим, как использовать функцию Fallbacks входящего протокола VLESS в Xray совместно с Nginx или Caddy для реализации разделения трафика по доменам при обеспечении полной маскировки.

                                      Сценарии использования

                                      Из-за XTLS Xray необходимо прослушивать порт 443, что создает проблему, если на сервере уже запущен веб-сайт - сайт либо не сможет работать, либо его придется запускать на другом порту, что нежелательно. Есть три способа решить эту проблему:

                                      • Xray прослушивает другие часто используемые порты (например, 22, 3389, 8443).

                                        Это самое простое решение, но оно не идеально.

                                      • Nginx или HAProxy прослушивает порт 443 и выполняет обратное проксирование на уровне L4 с разделением трафика по SNI, что позволяет использовать один порт для нескольких сервисов.

                                        Этот вариант более сложный и требует определенных знаний Nginx или HAProxy, поэтому мы не будем его здесь подробно рассматривать.

                                      • Xray прослушивает порт 443 и использует функцию Fallbacks для перенаправления трафика веб-сайта на Nginx или Caddy на основе SNI.

                                        Этот вариант имеет среднюю сложность и является тем, который мы рассмотрим в этом руководстве.

                                      Что такое SNI

                                      SNI (Server Name Indication) - это расширение протокола TLS. Те, кто знаком с обратным проксированием, знают, что для правильной маршрутизации трафика по доменному имени необходимо следующее правило:

                                      proxy_set_header Host имя_хоста;
                                      +import{_ as l,r as o,o as i,c,a,b as n,d as s,e as t}from"./app-D7uBbsY3.js";const r="/assets/xray-fallbacks-gLm6MqAx.svg",u="/assets/xray-dns-records-lpau4JTO.webp",d="/assets/cf-api-token-permissions-for-acme-BmGfLU86.webp",v={},k=n("h1",{id:"маскировка-и-разделение-трафика-по-доменам-с-помощью-функции-sni-fallback",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#маскировка-и-разделение-трафика-по-доменам-с-помощью-функции-sni-fallback"},[n("span",null,"Маскировка и разделение трафика по доменам с помощью функции SNI Fallback")])],-1),m=t(`

                                      VLESS - это очень легкий протокол, который, как и Trojan, не использует сложного шифрования и обфускации трафика. Вместо этого он, подобно тому, как искусный мастер кунг-фу скрывает свою силу, шифрует трафик с помощью протокола TLS, маскируя его под обычный HTTPS-трафик и позволяя ему беспрепятственно проходить через Великий китайский файрвол. Для лучшей маскировки от активного зондирования вместе с VLESS была представлена функция Fallbacks (резервирование). В этой статье мы рассмотрим, как использовать функцию Fallbacks входящего протокола VLESS в Xray совместно с Nginx или Caddy для реализации разделения трафика по доменам при обеспечении полной маскировки.

                                      Сценарии использования

                                      Из-за XTLS Xray необходимо прослушивать порт 443, что создает проблему, если на сервере уже запущен веб-сайт - сайт либо не сможет работать, либо его придется запускать на другом порту, что нежелательно. Есть три способа решить эту проблему:

                                      • Xray прослушивает другие часто используемые порты (например, 22, 3389, 8443).

                                        Это самое простое решение, но оно не идеально.

                                      • Nginx или HAProxy прослушивает порт 443 и выполняет обратное проксирование на уровне L4 с разделением трафика по SNI, что позволяет использовать один порт для нескольких сервисов.

                                        Этот вариант более сложный и требует определенных знаний Nginx или HAProxy, поэтому мы не будем его здесь подробно рассматривать.

                                      • Xray прослушивает порт 443 и использует функцию Fallbacks для перенаправления трафика веб-сайта на Nginx или Caddy на основе SNI.

                                        Этот вариант имеет среднюю сложность и является тем, который мы рассмотрим в этом руководстве.

                                      Что такое SNI

                                      SNI (Server Name Indication) - это расширение протокола TLS. Те, кто знаком с обратным проксированием, знают, что для правильной маршрутизации трафика по доменному имени необходимо следующее правило:

                                      proxy_set_header Host имя_хоста;
                                       

                                      Эта строка устанавливает HTTP-заголовок "Host" на определенное имя хоста. Зачем это нужно? Обычно у одного сервера один IP-адрес, но на нем может быть запущено несколько сайтов. Пользователи получают IP-адрес по доменному имени и обращаются к серверу, но как сервер определяет, какой именно сайт запрашивает пользователь? Для этого используются виртуальные хосты, основанные на имени.

                                      Когда веб-сервер получает запрос, он проверяет заголовок "Host" и направляет пользователя на нужный сайт. Однако, когда HTTP-трафик шифруется с помощью TLS, этот простой метод перестает работать. TLS-рукопожатие происходит до того, как сервер увидит какие-либо HTTP-заголовки, поэтому сервер не может использовать информацию из заголовка "Host", чтобы решить, какой сертификат предоставить, и тем более не может определить, к какому сайту обращается пользователь.

                                      SNI решает эту проблему, позволяя клиенту отправлять имя хоста как часть TLS-рукопожатия. Поэтому при использовании Nginx для обратного проксирования HTTPS-трафика необходимо добавить в конфигурацию proxy_ssl_server_name on;. В этом случае Nginx будет отправлять информацию SNI на проксируемый сервер, решая проблему неработающих виртуальных хостов по HTTPS. Кроме того, при использовании SNI можно получить доступ к нужному сайту, даже не указывая заголовок "Host".

                                      Идея

                                      Схема работы Xray Fallbacks

                                      После получения трафика на порт 443 Xray расшифровывает TLS и перенаправляет трафик с длиной первого пакета менее 18 байт, неверной версией протокола или ошибкой аутентификации на адрес, указанный в dest, на основе совпадения name, path или alpn.

                                      Добавление DNS-записей

                                      DNS-записи

                                      Измените домен и IP-адрес в соответствии с вашей ситуацией.

                                      Запрос TLS-сертификата

                                      ',17),b=n("code",null,"*.example.com",-1),h=n("code",null,"example.com",-1),q=n("code",null,"*.*.example.com",-1),f={href:"https://ru.wikipedia.org/wiki/Subject_Alternative_Name",target:"_blank",rel:"noopener noreferrer"},y=n("sup",{class:"footnote-ref"},[n("a",{href:"#fn1",id:"fnref1"},"[1]")],-1),g={href:"https://acme.sh",target:"_blank",rel:"noopener noreferrer"},_={href:"https://github.com/acmesh-official/acme.sh/wiki/dnsapi",target:"_blank",rel:"noopener noreferrer"},x={href:"https://dash.cloudflare.com/profile/api-tokens",target:"_blank",rel:"noopener noreferrer"},w=t('

                                      Настройка прав доступа API-токена

                                      Настройка прав доступа очень важна, остальные параметры можно оставить по умолчанию.

                                      После создания вы получите строку символов - это и есть ваш API-токен (CF_Token). Сохраните его в надежном месте, так как он больше не будет отображаться.

                                      Внимание

                                      Следующие действия необходимо выполнять от имени пользователя root. Использование sudo может привести к ошибкам.

                                      curl https://get.acme.sh | sh # Установка acme.sh
                                       export CF_Token="sdfsdfsdfljlbjkljlkjsdfoiwje" # Установка переменной окружения с API-токеном
                                       acme.sh --issue -d example.com -d *.example.com --dns dns_cf # Запрос сертификата с проверкой DNS-01
                                      diff --git a/assets/fallbacks-with-sni.html-Qo7kexlI.js b/assets/fallbacks-with-sni.html-DtIkqYxV.js
                                      similarity index 99%
                                      rename from assets/fallbacks-with-sni.html-Qo7kexlI.js
                                      rename to assets/fallbacks-with-sni.html-DtIkqYxV.js
                                      index 7fca166aef..8363e99f07 100644
                                      --- a/assets/fallbacks-with-sni.html-Qo7kexlI.js
                                      +++ b/assets/fallbacks-with-sni.html-DtIkqYxV.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as p,r as o,o as l,c as r,a,b as n,d as s,e as t}from"./app-DBM4OJyw.js";const c="/assets/xray-fallbacks-gLm6MqAx.svg",d="/assets/xray-dns-records-lpau4JTO.webp",u="/assets/cf-api-token-permissions-for-acme-BmGfLU86.webp",v={},h=n("h1",{id:"implementing-camouflage-and-domain-based-routing-through-sni-fallback-function",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#implementing-camouflage-and-domain-based-routing-through-sni-fallback-function"},[n("span",null,"Implementing camouflage and domain-based routing through SNI fallback function")])],-1),m=t(`

                                      VLESS is a lightweight protocol that, like Trojan, does not perform complex encryption and obfuscation on traffic. Instead, it is encrypted through the TLS protocol and mixed in with other HTTPS traffic, making it difficult to detect. In order to better disguise itself and respond to active probing, the fallback function appeared with VLESS at the same time. This tutorial will demonstrate how to use the fallback function of VLESS inbound protocol in Xray, combined with Nginx or Caddy, to achieve domain name-based traffic routing while ensuring complete disguise.

                                      Application Scenarios

                                      Due to XTLS, Xray needs to listen on port 443, which means that if there is a website running on the server, it cannot run or needs to run on another port, which is obviously unreasonable. There are three solutions to this problem:

                                      • Xray monitors other commonly used ports (such as 22, 3389, 8443).

                                      This plan is the simplest, but not perfect enough.

                                      • Nginx or HAProxy listens on port 443, uses SNI for L4 load balancing, and achieves port multiplexing through reverse proxy.

                                      This plan is relatively complicated and requires some understanding of using Nginx or HAProxy. We will not explain it in too much detail here.

                                      • Xray listens on port 443, and uses Fallbacks feature to split website traffic based on SNI and fallbacks it to Nginx or Caddy.

                                      This plan has a moderate level of difficulty and is the scheme that this tutorial will demonstrate next.

                                      Introduction to SNI

                                      Server Name Indication (SNI) is an extension protocol of TLS. Friends who are familiar with reverse proxies know that the following configuration is required if you want to proxy traffic to the correct content through a domain name:

                                      proxy_set_header Host hostname;
                                      +import{_ as p,r as o,o as l,c as r,a,b as n,d as s,e as t}from"./app-D7uBbsY3.js";const c="/assets/xray-fallbacks-gLm6MqAx.svg",d="/assets/xray-dns-records-lpau4JTO.webp",u="/assets/cf-api-token-permissions-for-acme-BmGfLU86.webp",v={},h=n("h1",{id:"implementing-camouflage-and-domain-based-routing-through-sni-fallback-function",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#implementing-camouflage-and-domain-based-routing-through-sni-fallback-function"},[n("span",null,"Implementing camouflage and domain-based routing through SNI fallback function")])],-1),m=t(`

                                      VLESS is a lightweight protocol that, like Trojan, does not perform complex encryption and obfuscation on traffic. Instead, it is encrypted through the TLS protocol and mixed in with other HTTPS traffic, making it difficult to detect. In order to better disguise itself and respond to active probing, the fallback function appeared with VLESS at the same time. This tutorial will demonstrate how to use the fallback function of VLESS inbound protocol in Xray, combined with Nginx or Caddy, to achieve domain name-based traffic routing while ensuring complete disguise.

                                      Application Scenarios

                                      Due to XTLS, Xray needs to listen on port 443, which means that if there is a website running on the server, it cannot run or needs to run on another port, which is obviously unreasonable. There are three solutions to this problem:

                                      • Xray monitors other commonly used ports (such as 22, 3389, 8443).

                                      This plan is the simplest, but not perfect enough.

                                      • Nginx or HAProxy listens on port 443, uses SNI for L4 load balancing, and achieves port multiplexing through reverse proxy.

                                      This plan is relatively complicated and requires some understanding of using Nginx or HAProxy. We will not explain it in too much detail here.

                                      • Xray listens on port 443, and uses Fallbacks feature to split website traffic based on SNI and fallbacks it to Nginx or Caddy.

                                      This plan has a moderate level of difficulty and is the scheme that this tutorial will demonstrate next.

                                      Introduction to SNI

                                      Server Name Indication (SNI) is an extension protocol of TLS. Friends who are familiar with reverse proxies know that the following configuration is required if you want to proxy traffic to the correct content through a domain name:

                                      proxy_set_header Host hostname;
                                       

                                      (Note: "hostname" should be replaced with the actual hostname.)

                                      This sentence sets the HTTP Header named "Host" to a certain hostname. Why do we need to do this? Generally, one server corresponds to one IP address, but it runs multiple websites. Visitors access the server by querying the IP address via domain name to visit the website. Then the question arises, how to determine which website the visitor wants to access? This requires "name-based virtual hosting".

                                      When a Web server receives a request, it looks at the host header to direct the visitor to the correct website. However, this simple method cannot be used when HTTP protocol is encrypted by TLS protocol. This is because the TLS handshake occurs before the server sees any HTTP headers, so the server cannot use the information in the HTTP host header to determine which certificate to present or which destination the visitor wants to access.

                                      The principle of SNI is also very simple. It solves the problem by allowing the client to send the hostname as part of the TLS negotiation. Therefore, when using Nginx to reverse proxy the HTTPS protocol, you need to add proxy_ssl_server_name on; to the configuration. At this time, Nginx will send SNI information to the proxied server, solving the problem of virtual host failure under the HTTPS protocol. In addition, when using SNI, even if the host header is not specified, the website can be accessed correctly.

                                      Idea

                                      Xray Fallback Process

                                      After receiving traffic from port 443, Xray will decrypt the TLS and forward the traffic that has a first packet length < 18, invalid protocol version, or failed authentication through matching name, path, and alpn to the address specified by dest.

                                      Adding DNS Records

                                      DNS Records

                                      Please modify the domain name and IP according to the actual situation.

                                      Applying for TLS Certificate

                                      ',23),k=n("code",null,"*.example.com",-1),b=n("code",null,"example.com",-1),f=n("code",null,"*.*.example.com",-1),g={href:"https://en.wikipedia.org/wiki/Subject_Alternative_Name",target:"_blank",rel:"noopener noreferrer"},y={href:"https://acme.sh",target:"_blank",rel:"noopener noreferrer"},q={href:"https://github.com/acmesh-official/acme.sh/wiki/dnsapi",target:"_blank",rel:"noopener noreferrer"},x={href:"https://dash.cloudflare.com/profile/api-tokens",target:"_blank",rel:"noopener noreferrer"},w=t('

                                      API Token permission settings

                                      The permission part is crucial, while other parts are optional.

                                      After creating, you will receive a mysterious string of characters. Please keep it safe in a secure and non-losing place, as it will not be displayed again. This string of characters is the CF_Token that will be used soon.

                                      Note

                                      The following operations need to be performed under the root user. Using sudo will result in errors.

                                      curl https://get.acme.sh | sh # Install acme.sh
                                       export CF_Token="sdfsdfsdfljlbjkljlkjsdfoiwje" # Set API Token variable
                                       acme.sh --issue -d example.com -d *.example.com --dns dns_cf # Apply for a certificate using DNS-01 validation method
                                      diff --git a/assets/fallbacks-with-sni.html-2lm7wLPL.js b/assets/fallbacks-with-sni.html-tnl-ymRI.js
                                      similarity index 99%
                                      rename from assets/fallbacks-with-sni.html-2lm7wLPL.js
                                      rename to assets/fallbacks-with-sni.html-tnl-ymRI.js
                                      index d4eb55f0a8..6d3fe6da41 100644
                                      --- a/assets/fallbacks-with-sni.html-2lm7wLPL.js
                                      +++ b/assets/fallbacks-with-sni.html-tnl-ymRI.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as l,r as o,o as i,c,a,b as n,d as s,e as t}from"./app-DBM4OJyw.js";const r="/assets/xray-fallbacks-gLm6MqAx.svg",u="/assets/xray-dns-records-lpau4JTO.webp",d="/assets/cf-api-token-permissions-for-acme-BmGfLU86.webp",v={},k=n("h1",{id:"通过-sni-回落功能实现伪装与按域名分流",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#通过-sni-回落功能实现伪装与按域名分流"},[n("span",null,"通过 SNI 回落功能实现伪装与按域名分流")])],-1),m=t(`

                                      VLESS 是一种很轻的协议,和 Trojan 一样,不对流量进行复杂的加密和混淆,而是大隐隐于市,通过 TLS 协议加密,混杂在其他 HTTPS 流量中,在墙内外穿进穿出。为了更好的伪装以应对主动探测,Fallbacks 回落功能随 VLESS 同时出现。这篇教程将演示如何使用 Xray 中 VLESS 入站协议的回落功能配合 Nginx 或 Caddy 在保证伪装完全的前提下实现按域名分流。

                                      应用情景

                                      由于 XTLS,Xray 需要监听 443 端口,这导致如果之前有网站运行在服务器上,那么此时网站无法运行或需要运行在其他端口上,这显然是不合理的。有以下三种方案可以解决这个问题:

                                      • Xray 监听其他常用端口(如 22、3389、8443)

                                        这个方案是最简单的,但不够完美。

                                      • Nginx 或 HAProxy 监听 443 端口,通过 SNI 分流做 L4 反向代理,实现端口复用

                                        这个方案比较复杂,需要对 Nginx 或 HAProxy 的使用有一定了解,此处不作过多解释。

                                      • Xray 监听 443 端口,通过 Fallbacks 功能 SNI 分流将网站流量回落到 Nginx 或 Caddy

                                        这个方案难度适中,也是此教程接下来想要演示的方案。

                                      SNI 简介

                                      服务器名称指示(英语:Server Name Indication,缩写:SNI)是 TLS 的一个扩展协议。熟悉反向代理的朋友都知道,如果想要通过域名将流量代理到正确的内容上,需要以下配置:

                                      proxy_set_header Host 主机名;
                                      +import{_ as l,r as o,o as i,c,a,b as n,d as s,e as t}from"./app-D7uBbsY3.js";const r="/assets/xray-fallbacks-gLm6MqAx.svg",u="/assets/xray-dns-records-lpau4JTO.webp",d="/assets/cf-api-token-permissions-for-acme-BmGfLU86.webp",v={},k=n("h1",{id:"通过-sni-回落功能实现伪装与按域名分流",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#通过-sni-回落功能实现伪装与按域名分流"},[n("span",null,"通过 SNI 回落功能实现伪装与按域名分流")])],-1),m=t(`

                                      VLESS 是一种很轻的协议,和 Trojan 一样,不对流量进行复杂的加密和混淆,而是大隐隐于市,通过 TLS 协议加密,混杂在其他 HTTPS 流量中,在墙内外穿进穿出。为了更好的伪装以应对主动探测,Fallbacks 回落功能随 VLESS 同时出现。这篇教程将演示如何使用 Xray 中 VLESS 入站协议的回落功能配合 Nginx 或 Caddy 在保证伪装完全的前提下实现按域名分流。

                                      应用情景

                                      由于 XTLS,Xray 需要监听 443 端口,这导致如果之前有网站运行在服务器上,那么此时网站无法运行或需要运行在其他端口上,这显然是不合理的。有以下三种方案可以解决这个问题:

                                      • Xray 监听其他常用端口(如 22、3389、8443)

                                        这个方案是最简单的,但不够完美。

                                      • Nginx 或 HAProxy 监听 443 端口,通过 SNI 分流做 L4 反向代理,实现端口复用

                                        这个方案比较复杂,需要对 Nginx 或 HAProxy 的使用有一定了解,此处不作过多解释。

                                      • Xray 监听 443 端口,通过 Fallbacks 功能 SNI 分流将网站流量回落到 Nginx 或 Caddy

                                        这个方案难度适中,也是此教程接下来想要演示的方案。

                                      SNI 简介

                                      服务器名称指示(英语:Server Name Indication,缩写:SNI)是 TLS 的一个扩展协议。熟悉反向代理的朋友都知道,如果想要通过域名将流量代理到正确的内容上,需要以下配置:

                                      proxy_set_header Host 主机名;
                                       

                                      这句的作用是将名为 “Host” 的 HTTP Header 设定为某个主机名。为什么要这样做?一般而言,一台服务器对应一个 IP,但却运行多个网站,访问者通过域名查询到 IP 以访问服务器,那么问题来了,如何确定访问者想要访问的是哪一个网站?这需要“基于名称的虚拟主机”。

                                      当 Web 服务器收到访问请求后,它会查看请求的主机头,使访问者访问正确的网站。然而当 HTTP 协议被 TLS 协议加密后,这种简单的方法就无法实现了。因为 TLS 握手发生在服务器看到任何 HTTP 头之前,因此,服务器不可能使用 HTTP 主机头中的信息来决定呈现哪个证书,更无法决定访问者的访问目标。

                                      SNI 的原理也很简单,它通过让客户端发送主机名作为 TLS 协商的一部分来解决此问题。所以在使用 Nginx 对 HTTPS 协议进行反向代理时,需要在配置中加入 proxy_ssl_server_name on;,此时 Nginx 会向被代理的服务器发送 SNI 信息,解决了 HTTPS 协议下虚拟主机失效的问题。另外,使用 SNI 时,即使不指定主机头,也可以正确访问网站。

                                      思路

                                      Xray 回落流程

                                      从 443 端口接收到流量后,Xray 会把 TLS 解密后首包长度 < 18、协议版本无效或身份认证失败的流量通过对 name、path、alpn 的匹配转发到 dest 指定的地址。

                                      添加 DNS 记录

                                      DNS 记录

                                      请按实际情况修改域名和 IP。

                                      申请 TLS 证书

                                      ',17),b=n("code",null,"*.example.com",-1),h=n("code",null,"example.com",-1),q=n("code",null,"*.*.example.com",-1),f={href:"https://zh.wikipedia.org/wiki/%E4%B8%BB%E9%A2%98%E5%A4%87%E7%94%A8%E5%90%8D%E7%A7%B0",target:"_blank",rel:"noopener noreferrer"},y=n("sup",{class:"footnote-ref"},[n("a",{href:"#fn1",id:"fnref1"},"[1]")],-1),g={href:"https://acme.sh",target:"_blank",rel:"noopener noreferrer"},_={href:"https://github.com/acmesh-official/acme.sh/wiki/dnsapi",target:"_blank",rel:"noopener noreferrer"},x={href:"https://dash.cloudflare.com/profile/api-tokens",target:"_blank",rel:"noopener noreferrer"},T=t('

                                      API Token 的权限设置

                                      权限部分至关重要,其他部分任意。

                                      创建完毕后,你会得到一串神秘字符,请将其妥善保管到安全且不会丢失的地方,因为它不再会显示。这串字符就是即将用到的 CF_Token

                                      注意

                                      以下操作需要在 root 用户下进行,使用 sudo 会出现错误。

                                      curl https://get.acme.sh | sh # 安装 acme.sh
                                       export CF_Token="sdfsdfsdfljlbjkljlkjsdfoiwje" # 设定 API Token 变量
                                       acme.sh --issue -d example.com -d *.example.com --dns dns_cf # 使用 DNS-01 验证方式申请证书
                                      diff --git a/assets/flowDiagram-TGP4CI55-B7tCuQuY.js b/assets/flowDiagram-TGP4CI55-c9v2Ypd8.js
                                      similarity index 99%
                                      rename from assets/flowDiagram-TGP4CI55-B7tCuQuY.js
                                      rename to assets/flowDiagram-TGP4CI55-c9v2Ypd8.js
                                      index 8065d253de..8217df6c60 100644
                                      --- a/assets/flowDiagram-TGP4CI55-B7tCuQuY.js
                                      +++ b/assets/flowDiagram-TGP4CI55-c9v2Ypd8.js
                                      @@ -1,4 +1,4 @@
                                      -import{g as pt,s as ft}from"./chunk-FUIDI54P-DcJSRBm9.js";import"./chunk-Z2VRG6XP-DsASRjJ5.js";import{d as O1,_ as l,o as Qe,p as At,s as gt,g as kt,b as bt,c as Et,q as St,r as mt,l as e1,u as Ae,t as Dt,v as xt,j as D1,x as Tt,y as Ct,e as yt,z as Ft}from"./mermaid.core-DapiNGBY.js";import{c as _t}from"./channel-BHWICgEe.js";import"./app-DBM4OJyw.js";var vt="flowchart-",Ze=0,P1=O1(),g1=new Map,W=[],z1=new Map,p1=[],ge=new Map,ke=new Map,ee=0,pe=!0,H,se,re=[],ie=l(e=>yt.sanitizeText(e,P1),"sanitizeText"),ue=l(function(e){for(const r of g1.values())if(r.id===e)return r.domId;return e},"lookUpDomId"),Bt=l(function(e,r,i,u,n,c,f={}){if(!e||e.trim().length===0)return;let k,o=g1.get(e);o===void 0&&(o={id:e,labelType:"text",domId:vt+e+"-"+Ze,styles:[],classes:[]},g1.set(e,o)),Ze++,r!==void 0?(P1=O1(),k=ie(r.text.trim()),o.labelType=r.type,k.startsWith('"')&&k.endsWith('"')&&(k=k.substring(1,k.length-1)),o.text=k):o.text===void 0&&(o.text=e),i!==void 0&&(o.type=i),u!=null&&u.forEach(function(p){o.styles.push(p)}),n!=null&&n.forEach(function(p){o.classes.push(p)}),c!==void 0&&(o.dir=c),o.props===void 0?o.props=f:f!==void 0&&Object.assign(o.props,f)},"addVertex"),Vt=l(function(e,r,i){const c={start:e,end:r,type:void 0,text:"",labelType:"text"};e1.info("abc78 Got edge...",c);const f=i.text;if(f!==void 0&&(c.text=ie(f.text.trim()),c.text.startsWith('"')&&c.text.endsWith('"')&&(c.text=c.text.substring(1,c.text.length-1)),c.labelType=f.type),i!==void 0&&(c.type=i.type,c.stroke=i.stroke,c.length=i.length>10?10:i.length),W.length<(P1.maxEdges??500))e1.info("Pushing edge..."),W.push(c);else throw new Error(`Edge limit exceeded. ${W.length} edges found, but the limit is ${P1.maxEdges}.
                                      +import{g as pt,s as ft}from"./chunk-FUIDI54P-B3wdDwu1.js";import"./chunk-Z2VRG6XP-CV0pyCU1.js";import{d as O1,_ as l,o as Qe,p as At,s as gt,g as kt,b as bt,c as Et,q as St,r as mt,l as e1,u as Ae,t as Dt,v as xt,j as D1,x as Tt,y as Ct,e as yt,z as Ft}from"./mermaid.core-D8igZDel.js";import{c as _t}from"./channel-uApa1cOK.js";import"./app-D7uBbsY3.js";var vt="flowchart-",Ze=0,P1=O1(),g1=new Map,W=[],z1=new Map,p1=[],ge=new Map,ke=new Map,ee=0,pe=!0,H,se,re=[],ie=l(e=>yt.sanitizeText(e,P1),"sanitizeText"),ue=l(function(e){for(const r of g1.values())if(r.id===e)return r.domId;return e},"lookUpDomId"),Bt=l(function(e,r,i,u,n,c,f={}){if(!e||e.trim().length===0)return;let k,o=g1.get(e);o===void 0&&(o={id:e,labelType:"text",domId:vt+e+"-"+Ze,styles:[],classes:[]},g1.set(e,o)),Ze++,r!==void 0?(P1=O1(),k=ie(r.text.trim()),o.labelType=r.type,k.startsWith('"')&&k.endsWith('"')&&(k=k.substring(1,k.length-1)),o.text=k):o.text===void 0&&(o.text=e),i!==void 0&&(o.type=i),u!=null&&u.forEach(function(p){o.styles.push(p)}),n!=null&&n.forEach(function(p){o.classes.push(p)}),c!==void 0&&(o.dir=c),o.props===void 0?o.props=f:f!==void 0&&Object.assign(o.props,f)},"addVertex"),Vt=l(function(e,r,i){const c={start:e,end:r,type:void 0,text:"",labelType:"text"};e1.info("abc78 Got edge...",c);const f=i.text;if(f!==void 0&&(c.text=ie(f.text.trim()),c.text.startsWith('"')&&c.text.endsWith('"')&&(c.text=c.text.substring(1,c.text.length-1)),c.labelType=f.type),i!==void 0&&(c.type=i.type,c.stroke=i.stroke,c.length=i.length>10?10:i.length),W.length<(P1.maxEdges??500))e1.info("Pushing edge..."),W.push(c);else throw new Error(`Edge limit exceeded. ${W.length} edges found, but the limit is ${P1.maxEdges}.
                                       
                                       Initialize mermaid with maxEdges set to a higher number to allow more edges.
                                       You cannot set this config via configuration inside the diagram as it is a secure config.
                                      diff --git a/assets/freedom.html-DJ9fcQEp.js b/assets/freedom.html-B_annG2n.js
                                      similarity index 99%
                                      rename from assets/freedom.html-DJ9fcQEp.js
                                      rename to assets/freedom.html-B_annG2n.js
                                      index 824db6f542..9c4525014e 100644
                                      --- a/assets/freedom.html-DJ9fcQEp.js
                                      +++ b/assets/freedom.html-B_annG2n.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as p,r as c,o as l,c as d,a as t,b as e,d as o,w as n,e as a}from"./app-DBM4OJyw.js";const r={},i=a(`

                                      Freedom(fragment、noises)

                                      Freedom 是一个出站协议,可以用来向任意网络发送(正常的) TCP 或 UDP 数据。

                                      OutboundConfigurationObject

                                      {
                                      +import{_ as p,r as c,o as l,c as d,a as t,b as e,d as o,w as n,e as a}from"./app-D7uBbsY3.js";const r={},i=a(`

                                      Freedom(fragment、noises)

                                      Freedom 是一个出站协议,可以用来向任意网络发送(正常的) TCP 或 UDP 数据。

                                      OutboundConfigurationObject

                                      {
                                         "domainStrategy": "AsIs",
                                         "redirect": "127.0.0.1:3366",
                                         "userLevel": 0,
                                      diff --git a/assets/freedom.html-Bxk1yqEk.js b/assets/freedom.html-C35JVucM.js
                                      similarity index 99%
                                      rename from assets/freedom.html-Bxk1yqEk.js
                                      rename to assets/freedom.html-C35JVucM.js
                                      index b656a57520..0687d5dfc5 100644
                                      --- a/assets/freedom.html-Bxk1yqEk.js
                                      +++ b/assets/freedom.html-C35JVucM.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as i,r as p,o as l,c as u,a as n,b as s,d as e,w as t,e as a}from"./app-DBM4OJyw.js";const r={},d=a(`

                                      Freedom

                                      Freedom is an outbound protocol that can be used to send (normal) TCP or UDP data to any network.

                                      OutboundConfigurationObject

                                      {
                                      +import{_ as i,r as p,o as l,c as u,a as n,b as s,d as e,w as t,e as a}from"./app-D7uBbsY3.js";const r={},d=a(`

                                      Freedom

                                      Freedom is an outbound protocol that can be used to send (normal) TCP or UDP data to any network.

                                      OutboundConfigurationObject

                                      {
                                         "domainStrategy": "AsIs",
                                         "redirect": "127.0.0.1:3366",
                                         "userLevel": 0,
                                      diff --git a/assets/freedom.html--UBGeVII.js b/assets/freedom.html-DxvEh0kc.js
                                      similarity index 99%
                                      rename from assets/freedom.html--UBGeVII.js
                                      rename to assets/freedom.html-DxvEh0kc.js
                                      index 3d6a4e3f08..e46633a302 100644
                                      --- a/assets/freedom.html--UBGeVII.js
                                      +++ b/assets/freedom.html-DxvEh0kc.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as p,r as c,o as l,c as d,a as t,b as e,d as o,w as s,e as a}from"./app-DBM4OJyw.js";const r={},i=a(`

                                      Freedom

                                      Freedom - это исходящий протокол, который можно использовать для отправки (обычных) данных TCP или UDP в любую сеть.

                                      OutboundConfigurationObject

                                      {
                                      +import{_ as p,r as c,o as l,c as d,a as t,b as e,d as o,w as s,e as a}from"./app-D7uBbsY3.js";const r={},i=a(`

                                      Freedom

                                      Freedom - это исходящий протокол, который можно использовать для отправки (обычных) данных TCP или UDP в любую сеть.

                                      OutboundConfigurationObject

                                      {
                                         "domainStrategy": "AsIs",
                                         "redirect": "127.0.0.1:3366",
                                         "userLevel": 0,
                                      diff --git a/assets/ganttDiagram-GAYIUD5S-p-lGuXqL.js b/assets/ganttDiagram-GAYIUD5S-BewWMKoe.js
                                      similarity index 99%
                                      rename from assets/ganttDiagram-GAYIUD5S-p-lGuXqL.js
                                      rename to assets/ganttDiagram-GAYIUD5S-BewWMKoe.js
                                      index 18420cf1e6..1a8612d048 100644
                                      --- a/assets/ganttDiagram-GAYIUD5S-p-lGuXqL.js
                                      +++ b/assets/ganttDiagram-GAYIUD5S-BewWMKoe.js
                                      @@ -1,4 +1,4 @@
                                      -import{aQ as Je,aR as Ke,aS as $e,aT as tn,aU as Yn,aV as re,aW as En,aF as Te,aG as be,_ as d,aX as at,d as Mt,s as Ln,g as An,q as In,r as Wn,c as On,b as Hn,t as Nn,m as Vn,l as Qt,j as Zt,k as zn,e as Pn,u as Rn}from"./mermaid.core-DapiNGBY.js";import{b as Bn,t as Ie,c as Zn,a as qn,l as Xn}from"./linear-D4Bza9R9.js";import{i as Gn}from"./init-Gi6I4Gst.js";import"./app-DBM4OJyw.js";function jn(t,e){let n;if(e===void 0)for(const r of t)r!=null&&(n=r)&&(n=r);else{let r=-1;for(let a of t)(a=e(a,++r,t))!=null&&(n=a)&&(n=a)}return n}function Qn(t,e){let n;if(e===void 0)for(const r of t)r!=null&&(n>r||n===void 0&&r>=r)&&(n=r);else{let r=-1;for(let a of t)(a=e(a,++r,t))!=null&&(n>a||n===void 0&&a>=a)&&(n=a)}return n}function Jn(t){return t}var Xt=1,ae=2,me=3,qt=4,We=1e-6;function Kn(t){return"translate("+t+",0)"}function $n(t){return"translate(0,"+t+")"}function tr(t){return e=>+t(e)}function er(t,e){return e=Math.max(0,t.bandwidth()-e*2)/2,t.round()&&(e=Math.round(e)),n=>+t(n)+e}function nr(){return!this.__axis}function en(t,e){var n=[],r=null,a=null,i=6,s=6,k=3,Y=typeof window<"u"&&window.devicePixelRatio>1?0:.5,g=t===Xt||t===qt?-1:1,w=t===qt||t===ae?"x":"y",S=t===Xt||t===me?Kn:$n;function C(b){var q=r??(e.ticks?e.ticks.apply(e,n):e.domain()),y=a??(e.tickFormat?e.tickFormat.apply(e,n):Jn),I=Math.max(i,0)+k,N=e.range(),H=+N[0]+Y,R=+N[N.length-1]+Y,B=(e.bandwidth?er:tr)(e.copy(),Y),J=b.selection?b.selection():b,D=J.selectAll(".domain").data([null]),W=J.selectAll(".tick").data(q,e).order(),x=W.exit(),U=W.enter().append("g").attr("class","tick"),_=W.select("line"),M=W.select("text");D=D.merge(D.enter().insert("path",".tick").attr("class","domain").attr("stroke","currentColor")),W=W.merge(U),_=_.merge(U.append("line").attr("stroke","currentColor").attr(w+"2",g*i)),M=M.merge(U.append("text").attr("fill","currentColor").attr(w,g*I).attr("dy",t===Xt?"0em":t===me?"0.71em":"0.32em")),b!==J&&(D=D.transition(b),W=W.transition(b),_=_.transition(b),M=M.transition(b),x=x.transition(b).attr("opacity",We).attr("transform",function(p){return isFinite(p=B(p))?S(p+Y):this.getAttribute("transform")}),U.attr("opacity",We).attr("transform",function(p){var E=this.parentNode.__axis;return S((E&&isFinite(E=E(p))?E:B(p))+Y)})),x.remove(),D.attr("d",t===qt||t===ae?s?"M"+g*s+","+H+"H"+Y+"V"+R+"H"+g*s:"M"+Y+","+H+"V"+R:s?"M"+H+","+g*s+"V"+Y+"H"+R+"V"+g*s:"M"+H+","+Y+"H"+R),W.attr("opacity",1).attr("transform",function(p){return S(B(p)+Y)}),_.attr(w+"2",g*i),M.attr(w,g*I).text(y),J.filter(nr).attr("fill","none").attr("font-size",10).attr("font-family","sans-serif").attr("text-anchor",t===ae?"start":t===qt?"end":"middle"),J.each(function(){this.__axis=B})}return C.scale=function(b){return arguments.length?(e=b,C):e},C.ticks=function(){return n=Array.from(arguments),C},C.tickArguments=function(b){return arguments.length?(n=b==null?[]:Array.from(b),C):n.slice()},C.tickValues=function(b){return arguments.length?(r=b==null?null:Array.from(b),C):r&&r.slice()},C.tickFormat=function(b){return arguments.length?(a=b,C):a},C.tickSize=function(b){return arguments.length?(i=s=+b,C):i},C.tickSizeInner=function(b){return arguments.length?(i=+b,C):i},C.tickSizeOuter=function(b){return arguments.length?(s=+b,C):s},C.tickPadding=function(b){return arguments.length?(k=+b,C):k},C.offset=function(b){return arguments.length?(Y=+b,C):Y},C}function rr(t){return en(Xt,t)}function ar(t){return en(me,t)}const ir=Math.PI/180,sr=180/Math.PI,Jt=18,nn=.96422,rn=1,an=.82521,sn=4/29,_t=6/29,on=3*_t*_t,or=_t*_t*_t;function cn(t){if(t instanceof lt)return new lt(t.l,t.a,t.b,t.opacity);if(t instanceof dt)return ln(t);t instanceof $e||(t=Yn(t));var e=ce(t.r),n=ce(t.g),r=ce(t.b),a=ie((.2225045*e+.7168786*n+.0606169*r)/rn),i,s;return e===n&&n===r?i=s=a:(i=ie((.4360747*e+.3850649*n+.1430804*r)/nn),s=ie((.0139322*e+.0971045*n+.7141733*r)/an)),new lt(116*a-16,500*(i-a),200*(a-s),t.opacity)}function cr(t,e,n,r){return arguments.length===1?cn(t):new lt(t,e,n,r??1)}function lt(t,e,n,r){this.l=+t,this.a=+e,this.b=+n,this.opacity=+r}Je(lt,cr,Ke(tn,{brighter(t){return new lt(this.l+Jt*(t??1),this.a,this.b,this.opacity)},darker(t){return new lt(this.l-Jt*(t??1),this.a,this.b,this.opacity)},rgb(){var t=(this.l+16)/116,e=isNaN(this.a)?t:t+this.a/500,n=isNaN(this.b)?t:t-this.b/200;return e=nn*se(e),t=rn*se(t),n=an*se(n),new $e(oe(3.1338561*e-1.6168667*t-.4906146*n),oe(-.9787684*e+1.9161415*t+.033454*n),oe(.0719453*e-.2289914*t+1.4052427*n),this.opacity)}}));function ie(t){return t>or?Math.pow(t,1/3):t/on+sn}function se(t){return t>_t?t*t*t:on*(t-sn)}function oe(t){return 255*(t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055)}function ce(t){return(t/=255)<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4)}function lr(t){if(t instanceof dt)return new dt(t.h,t.c,t.l,t.opacity);if(t instanceof lt||(t=cn(t)),t.a===0&&t.b===0)return new dt(NaN,0(t(i=new Date(+i)),i),a.ceil=i=>(t(i=new Date(i-1)),e(i,1),t(i),i),a.round=i=>{const s=a(i),k=a.ceil(i);return i-s(e(i=new Date(+i),s==null?1:Math.floor(s)),i),a.range=(i,s,k)=>{const Y=[];if(i=a.ceil(i),k=k==null?1:Math.floor(k),!(i0))return Y;let g;do Y.push(g=new Date(+i)),e(i,k),t(i);while(get(s=>{if(s>=s)for(;t(s),!i(s);)s.setTime(s-1)},(s,k)=>{if(s>=s)if(k<0)for(;++k<=0;)for(;e(s,-1),!i(s););else for(;--k>=0;)for(;e(s,1),!i(s););}),n&&(a.count=(i,s)=>(le.setTime(+i),ue.setTime(+s),t(le),t(ue),Math.floor(n(le,ue))),a.every=i=>(i=Math.floor(i),!isFinite(i)||!(i>0)?null:i>1?a.filter(r?s=>r(s)%i===0:s=>a.count(0,s)%i===0):a)),a}const Ut=et(()=>{},(t,e)=>{t.setTime(+t+e)},(t,e)=>e-t);Ut.every=t=>(t=Math.floor(t),!isFinite(t)||!(t>0)?null:t>1?et(e=>{e.setTime(Math.floor(e/t)*t)},(e,n)=>{e.setTime(+e+n*t)},(e,n)=>(n-e)/t):Ut);Ut.range;const mt=1e3,st=mt*60,gt=st*60,yt=gt*24,xe=yt*7,Oe=yt*30,fe=yt*365,pt=et(t=>{t.setTime(t-t.getMilliseconds())},(t,e)=>{t.setTime(+t+e*mt)},(t,e)=>(e-t)/mt,t=>t.getUTCSeconds());pt.range;const It=et(t=>{t.setTime(t-t.getMilliseconds()-t.getSeconds()*mt)},(t,e)=>{t.setTime(+t+e*st)},(t,e)=>(e-t)/st,t=>t.getMinutes());It.range;const dr=et(t=>{t.setUTCSeconds(0,0)},(t,e)=>{t.setTime(+t+e*st)},(t,e)=>(e-t)/st,t=>t.getUTCMinutes());dr.range;const Wt=et(t=>{t.setTime(t-t.getMilliseconds()-t.getSeconds()*mt-t.getMinutes()*st)},(t,e)=>{t.setTime(+t+e*gt)},(t,e)=>(e-t)/gt,t=>t.getHours());Wt.range;const mr=et(t=>{t.setUTCMinutes(0,0,0)},(t,e)=>{t.setTime(+t+e*gt)},(t,e)=>(e-t)/gt,t=>t.getUTCHours());mr.range;const vt=et(t=>t.setHours(0,0,0,0),(t,e)=>t.setDate(t.getDate()+e),(t,e)=>(e-t-(e.getTimezoneOffset()-t.getTimezoneOffset())*st)/yt,t=>t.getDate()-1);vt.range;const we=et(t=>{t.setUTCHours(0,0,0,0)},(t,e)=>{t.setUTCDate(t.getUTCDate()+e)},(t,e)=>(e-t)/yt,t=>t.getUTCDate()-1);we.range;const gr=et(t=>{t.setUTCHours(0,0,0,0)},(t,e)=>{t.setUTCDate(t.getUTCDate()+e)},(t,e)=>(e-t)/yt,t=>Math.floor(t/yt));gr.range;function xt(t){return et(e=>{e.setDate(e.getDate()-(e.getDay()+7-t)%7),e.setHours(0,0,0,0)},(e,n)=>{e.setDate(e.getDate()+n*7)},(e,n)=>(n-e-(n.getTimezoneOffset()-e.getTimezoneOffset())*st)/xe)}const Nt=xt(0),Ot=xt(1),un=xt(2),fn=xt(3),Tt=xt(4),hn=xt(5),dn=xt(6);Nt.range;Ot.range;un.range;fn.range;Tt.range;hn.range;dn.range;function wt(t){return et(e=>{e.setUTCDate(e.getUTCDate()-(e.getUTCDay()+7-t)%7),e.setUTCHours(0,0,0,0)},(e,n)=>{e.setUTCDate(e.getUTCDate()+n*7)},(e,n)=>(n-e)/xe)}const mn=wt(0),Kt=wt(1),yr=wt(2),kr=wt(3),Ft=wt(4),pr=wt(5),vr=wt(6);mn.range;Kt.range;yr.range;kr.range;Ft.range;pr.range;vr.range;const Ht=et(t=>{t.setDate(1),t.setHours(0,0,0,0)},(t,e)=>{t.setMonth(t.getMonth()+e)},(t,e)=>e.getMonth()-t.getMonth()+(e.getFullYear()-t.getFullYear())*12,t=>t.getMonth());Ht.range;const Tr=et(t=>{t.setUTCDate(1),t.setUTCHours(0,0,0,0)},(t,e)=>{t.setUTCMonth(t.getUTCMonth()+e)},(t,e)=>e.getUTCMonth()-t.getUTCMonth()+(e.getUTCFullYear()-t.getUTCFullYear())*12,t=>t.getUTCMonth());Tr.range;const kt=et(t=>{t.setMonth(0,1),t.setHours(0,0,0,0)},(t,e)=>{t.setFullYear(t.getFullYear()+e)},(t,e)=>e.getFullYear()-t.getFullYear(),t=>t.getFullYear());kt.every=t=>!isFinite(t=Math.floor(t))||!(t>0)?null:et(e=>{e.setFullYear(Math.floor(e.getFullYear()/t)*t),e.setMonth(0,1),e.setHours(0,0,0,0)},(e,n)=>{e.setFullYear(e.getFullYear()+n*t)});kt.range;const bt=et(t=>{t.setUTCMonth(0,1),t.setUTCHours(0,0,0,0)},(t,e)=>{t.setUTCFullYear(t.getUTCFullYear()+e)},(t,e)=>e.getUTCFullYear()-t.getUTCFullYear(),t=>t.getUTCFullYear());bt.every=t=>!isFinite(t=Math.floor(t))||!(t>0)?null:et(e=>{e.setUTCFullYear(Math.floor(e.getUTCFullYear()/t)*t),e.setUTCMonth(0,1),e.setUTCHours(0,0,0,0)},(e,n)=>{e.setUTCFullYear(e.getUTCFullYear()+n*t)});bt.range;function br(t,e,n,r,a,i){const s=[[pt,1,mt],[pt,5,5*mt],[pt,15,15*mt],[pt,30,30*mt],[i,1,st],[i,5,5*st],[i,15,15*st],[i,30,30*st],[a,1,gt],[a,3,3*gt],[a,6,6*gt],[a,12,12*gt],[r,1,yt],[r,2,2*yt],[n,1,xe],[e,1,Oe],[e,3,3*Oe],[t,1,fe]];function k(g,w,S){const C=wI).right(s,C);if(b===s.length)return t.every(Ie(g/fe,w/fe,S));if(b===0)return Ut.every(Math.max(Ie(g,w,S),1));const[q,y]=s[C/s[b-1][2]53)return null;"w"in u||(u.w=1),"Z"in u?(L=de(Et(u.y,0,1)),Q=L.getUTCDay(),L=Q>4||Q===0?Kt.ceil(L):Kt(L),L=we.offset(L,(u.V-1)*7),u.y=L.getUTCFullYear(),u.m=L.getUTCMonth(),u.d=L.getUTCDate()+(u.w+6)%7):(L=he(Et(u.y,0,1)),Q=L.getDay(),L=Q>4||Q===0?Ot.ceil(L):Ot(L),L=vt.offset(L,(u.V-1)*7),u.y=L.getFullYear(),u.m=L.getMonth(),u.d=L.getDate()+(u.w+6)%7)}else("W"in u||"U"in u)&&("w"in u||(u.w="u"in u?u.u%7:"W"in u?1:0),Q="Z"in u?de(Et(u.y,0,1)).getUTCDay():he(Et(u.y,0,1)).getDay(),u.m=0,u.d="W"in u?(u.w+6)%7+u.W*7-(Q+5)%7:u.w+u.U*7-(Q+6)%7);return"Z"in u?(u.H+=u.Z/100|0,u.M+=u.Z%100,de(u)):he(u)}}function x(T,A,O,u){for(var K=0,L=A.length,Q=O.length,X,ot;K=Q)return-1;if(X=A.charCodeAt(K++),X===37){if(X=A.charAt(K++),ot=J[X in He?A.charAt(K++):X],!ot||(u=ot(T,O,u))<0)return-1}else if(X!=O.charCodeAt(u++))return-1}return u}function U(T,A,O){var u=g.exec(A.slice(O));return u?(T.p=w.get(u[0].toLowerCase()),O+u[0].length):-1}function _(T,A,O){var u=b.exec(A.slice(O));return u?(T.w=q.get(u[0].toLowerCase()),O+u[0].length):-1}function M(T,A,O){var u=S.exec(A.slice(O));return u?(T.w=C.get(u[0].toLowerCase()),O+u[0].length):-1}function p(T,A,O){var u=N.exec(A.slice(O));return u?(T.m=H.get(u[0].toLowerCase()),O+u[0].length):-1}function E(T,A,O){var u=y.exec(A.slice(O));return u?(T.m=I.get(u[0].toLowerCase()),O+u[0].length):-1}function l(T,A,O){return x(T,e,A,O)}function h(T,A,O){return x(T,n,A,O)}function v(T,A,O){return x(T,r,A,O)}function m(T){return s[T.getDay()]}function F(T){return i[T.getDay()]}function o(T){return Y[T.getMonth()]}function f(T){return k[T.getMonth()]}function c(T){return a[+(T.getHours()>=12)]}function Z(T){return 1+~~(T.getMonth()/3)}function V(T){return s[T.getUTCDay()]}function z(T){return i[T.getUTCDay()]}function $(T){return Y[T.getUTCMonth()]}function G(T){return k[T.getUTCMonth()]}function j(T){return a[+(T.getUTCHours()>=12)]}function rt(T){return 1+~~(T.getUTCMonth()/3)}return{format:function(T){var A=D(T+="",R);return A.toString=function(){return T},A},parse:function(T){var A=W(T+="",!1);return A.toString=function(){return T},A},utcFormat:function(T){var A=D(T+="",B);return A.toString=function(){return T},A},utcParse:function(T){var A=W(T+="",!0);return A.toString=function(){return T},A}}}var He={"-":"",_:" ",0:"0"},nt=/^\s*\d+/,Cr=/^%/,Mr=/[\\^$*+?|[\]().{}]/g;function P(t,e,n){var r=t<0?"-":"",a=(r?-t:t)+"",i=a.length;return r+(i[e.toLowerCase(),n]))}function Sr(t,e,n){var r=nt.exec(e.slice(n,n+1));return r?(t.w=+r[0],n+r[0].length):-1}function Ur(t,e,n){var r=nt.exec(e.slice(n,n+1));return r?(t.u=+r[0],n+r[0].length):-1}function Fr(t,e,n){var r=nt.exec(e.slice(n,n+2));return r?(t.U=+r[0],n+r[0].length):-1}function Yr(t,e,n){var r=nt.exec(e.slice(n,n+2));return r?(t.V=+r[0],n+r[0].length):-1}function Er(t,e,n){var r=nt.exec(e.slice(n,n+2));return r?(t.W=+r[0],n+r[0].length):-1}function Ne(t,e,n){var r=nt.exec(e.slice(n,n+4));return r?(t.y=+r[0],n+r[0].length):-1}function Ve(t,e,n){var r=nt.exec(e.slice(n,n+2));return r?(t.y=+r[0]+(+r[0]>68?1900:2e3),n+r[0].length):-1}function Lr(t,e,n){var r=/^(Z)|([+-]\d\d)(?::?(\d\d))?/.exec(e.slice(n,n+6));return r?(t.Z=r[1]?0:-(r[2]+(r[3]||"00")),n+r[0].length):-1}function Ar(t,e,n){var r=nt.exec(e.slice(n,n+1));return r?(t.q=r[0]*3-3,n+r[0].length):-1}function Ir(t,e,n){var r=nt.exec(e.slice(n,n+2));return r?(t.m=r[0]-1,n+r[0].length):-1}function ze(t,e,n){var r=nt.exec(e.slice(n,n+2));return r?(t.d=+r[0],n+r[0].length):-1}function Wr(t,e,n){var r=nt.exec(e.slice(n,n+3));return r?(t.m=0,t.d=+r[0],n+r[0].length):-1}function Pe(t,e,n){var r=nt.exec(e.slice(n,n+2));return r?(t.H=+r[0],n+r[0].length):-1}function Or(t,e,n){var r=nt.exec(e.slice(n,n+2));return r?(t.M=+r[0],n+r[0].length):-1}function Hr(t,e,n){var r=nt.exec(e.slice(n,n+2));return r?(t.S=+r[0],n+r[0].length):-1}function Nr(t,e,n){var r=nt.exec(e.slice(n,n+3));return r?(t.L=+r[0],n+r[0].length):-1}function Vr(t,e,n){var r=nt.exec(e.slice(n,n+6));return r?(t.L=Math.floor(r[0]/1e3),n+r[0].length):-1}function zr(t,e,n){var r=Cr.exec(e.slice(n,n+1));return r?n+r[0].length:-1}function Pr(t,e,n){var r=nt.exec(e.slice(n));return r?(t.Q=+r[0],n+r[0].length):-1}function Rr(t,e,n){var r=nt.exec(e.slice(n));return r?(t.s=+r[0],n+r[0].length):-1}function Re(t,e){return P(t.getDate(),e,2)}function Br(t,e){return P(t.getHours(),e,2)}function Zr(t,e){return P(t.getHours()%12||12,e,2)}function qr(t,e){return P(1+vt.count(kt(t),t),e,3)}function gn(t,e){return P(t.getMilliseconds(),e,3)}function Xr(t,e){return gn(t,e)+"000"}function Gr(t,e){return P(t.getMonth()+1,e,2)}function jr(t,e){return P(t.getMinutes(),e,2)}function Qr(t,e){return P(t.getSeconds(),e,2)}function Jr(t){var e=t.getDay();return e===0?7:e}function Kr(t,e){return P(Nt.count(kt(t)-1,t),e,2)}function yn(t){var e=t.getDay();return e>=4||e===0?Tt(t):Tt.ceil(t)}function $r(t,e){return t=yn(t),P(Tt.count(kt(t),t)+(kt(t).getDay()===4),e,2)}function ta(t){return t.getDay()}function ea(t,e){return P(Ot.count(kt(t)-1,t),e,2)}function na(t,e){return P(t.getFullYear()%100,e,2)}function ra(t,e){return t=yn(t),P(t.getFullYear()%100,e,2)}function aa(t,e){return P(t.getFullYear()%1e4,e,4)}function ia(t,e){var n=t.getDay();return t=n>=4||n===0?Tt(t):Tt.ceil(t),P(t.getFullYear()%1e4,e,4)}function sa(t){var e=t.getTimezoneOffset();return(e>0?"-":(e*=-1,"+"))+P(e/60|0,"0",2)+P(e%60,"0",2)}function Be(t,e){return P(t.getUTCDate(),e,2)}function oa(t,e){return P(t.getUTCHours(),e,2)}function ca(t,e){return P(t.getUTCHours()%12||12,e,2)}function la(t,e){return P(1+we.count(bt(t),t),e,3)}function kn(t,e){return P(t.getUTCMilliseconds(),e,3)}function ua(t,e){return kn(t,e)+"000"}function fa(t,e){return P(t.getUTCMonth()+1,e,2)}function ha(t,e){return P(t.getUTCMinutes(),e,2)}function da(t,e){return P(t.getUTCSeconds(),e,2)}function ma(t){var e=t.getUTCDay();return e===0?7:e}function ga(t,e){return P(mn.count(bt(t)-1,t),e,2)}function pn(t){var e=t.getUTCDay();return e>=4||e===0?Ft(t):Ft.ceil(t)}function ya(t,e){return t=pn(t),P(Ft.count(bt(t),t)+(bt(t).getUTCDay()===4),e,2)}function ka(t){return t.getUTCDay()}function pa(t,e){return P(Kt.count(bt(t)-1,t),e,2)}function va(t,e){return P(t.getUTCFullYear()%100,e,2)}function Ta(t,e){return t=pn(t),P(t.getUTCFullYear()%100,e,2)}function ba(t,e){return P(t.getUTCFullYear()%1e4,e,4)}function xa(t,e){var n=t.getUTCDay();return t=n>=4||n===0?Ft(t):Ft.ceil(t),P(t.getUTCFullYear()%1e4,e,4)}function wa(){return"+0000"}function Ze(){return"%"}function qe(t){return+t}function Xe(t){return Math.floor(+t/1e3)}var Ct,$t;Da({dateTime:"%x, %X",date:"%-m/%-d/%Y",time:"%-I:%M:%S %p",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});function Da(t){return Ct=Dr(t),$t=Ct.format,Ct.parse,Ct.utcFormat,Ct.utcParse,Ct}function Ca(t){return new Date(t)}function Ma(t){return t instanceof Date?+t:+new Date(+t)}function vn(t,e,n,r,a,i,s,k,Y,g){var w=Zn(),S=w.invert,C=w.domain,b=g(".%L"),q=g(":%S"),y=g("%I:%M"),I=g("%I %p"),N=g("%a %d"),H=g("%b %d"),R=g("%B"),B=g("%Y");function J(D){return(Y(D)4&&(b+=7),C.add(b,n));return q.diff(y,"week")+1},k.isoWeekday=function(g){return this.$utils().u(g)?this.day()||7:this.day(this.day()%7?g:g-7)};var Y=k.startOf;k.startOf=function(g,w){var S=this.$utils(),C=!!S.u(w)||w;return S.p(g)==="isoweek"?C?this.date(this.date()-(this.isoWeekday()-1)).startOf("day"):this.date(this.date()-1-(this.isoWeekday()-1)+7).endOf("day"):Y.bind(this)(g,w)}}})})(Tn);var Sa=Tn.exports;const Ua=be(Sa);var bn={exports:{}};(function(t,e){(function(n,r){t.exports=r()})(Te,function(){var n={LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"},r=/(\[[^[]*\])|([-_:/.,()\s]+)|(A|a|YYYY|YY?|MM?M?M?|Do|DD?|hh?|HH?|mm?|ss?|S{1,3}|z|ZZ?)/g,a=/\d\d/,i=/\d\d?/,s=/\d*[^-_:/,()\s\d]+/,k={},Y=function(y){return(y=+y)+(y>68?1900:2e3)},g=function(y){return function(I){this[y]=+I}},w=[/[+-]\d\d:?(\d\d)?|Z/,function(y){(this.zone||(this.zone={})).offset=function(I){if(!I||I==="Z")return 0;var N=I.match(/([+-]|\d\d)/g),H=60*N[1]+(+N[2]||0);return H===0?0:N[0]==="+"?-H:H}(y)}],S=function(y){var I=k[y];return I&&(I.indexOf?I:I.s.concat(I.f))},C=function(y,I){var N,H=k.meridiem;if(H){for(var R=1;R<=24;R+=1)if(y.indexOf(H(R,0,I))>-1){N=R>12;break}}else N=y===(I?"pm":"PM");return N},b={A:[s,function(y){this.afternoon=C(y,!1)}],a:[s,function(y){this.afternoon=C(y,!0)}],S:[/\d/,function(y){this.milliseconds=100*+y}],SS:[a,function(y){this.milliseconds=10*+y}],SSS:[/\d{3}/,function(y){this.milliseconds=+y}],s:[i,g("seconds")],ss:[i,g("seconds")],m:[i,g("minutes")],mm:[i,g("minutes")],H:[i,g("hours")],h:[i,g("hours")],HH:[i,g("hours")],hh:[i,g("hours")],D:[i,g("day")],DD:[a,g("day")],Do:[s,function(y){var I=k.ordinal,N=y.match(/\d+/);if(this.day=N[0],I)for(var H=1;H<=31;H+=1)I(H).replace(/\[|\]/g,"")===y&&(this.day=H)}],M:[i,g("month")],MM:[a,g("month")],MMM:[s,function(y){var I=S("months"),N=(S("monthsShort")||I.map(function(H){return H.slice(0,3)})).indexOf(y)+1;if(N<1)throw new Error;this.month=N%12||N}],MMMM:[s,function(y){var I=S("months").indexOf(y)+1;if(I<1)throw new Error;this.month=I%12||I}],Y:[/[+-]?\d+/,g("year")],YY:[a,function(y){this.year=Y(y)}],YYYY:[/\d{4}/,g("year")],Z:w,ZZ:w};function q(y){var I,N;I=y,N=k&&k.formats;for(var H=(y=I.replace(/(\[[^\]]+])|(LTS?|l{1,4}|L{1,4})/g,function(U,_,M){var p=M&&M.toUpperCase();return _||N[M]||n[M]||N[p].replace(/(\[[^\]]+])|(MMMM|MM|DD|dddd)/g,function(E,l,h){return l||h.slice(1)})})).match(r),R=H.length,B=0;B-1)return new Date((m==="X"?1e3:1)*v);var o=q(m)(v),f=o.year,c=o.month,Z=o.day,V=o.hours,z=o.minutes,$=o.seconds,G=o.milliseconds,j=o.zone,rt=new Date,T=Z||(f||c?1:rt.getDate()),A=f||rt.getFullYear(),O=0;f&&!c||(O=c>0?c-1:rt.getMonth());var u=V||0,K=z||0,L=$||0,Q=G||0;return j?new Date(Date.UTC(A,O,T,u,K,L,Q+60*j.offset*1e3)):F?new Date(Date.UTC(A,O,T,u,K,L,Q)):new Date(A,O,T,u,K,L,Q)}catch{return new Date("")}}(J,x,D),this.init(),p&&p!==!0&&(this.$L=this.locale(p).$L),M&&J!=this.format(x)&&(this.$d=new Date("")),k={}}else if(x instanceof Array)for(var E=x.length,l=1;l<=E;l+=1){W[1]=x[l-1];var h=N.apply(this,W);if(h.isValid()){this.$d=h.$d,this.$L=h.$L,this.init();break}l===E&&(this.$d=new Date(""))}else R.call(this,B)}}})})(bn);var Fa=bn.exports;const Ya=be(Fa);var xn={exports:{}};(function(t,e){(function(n,r){t.exports=r()})(Te,function(){return function(n,r){var a=r.prototype,i=a.format;a.format=function(s){var k=this,Y=this.$locale();if(!this.isValid())return i.bind(this)(s);var g=this.$utils(),w=(s||"YYYY-MM-DDTHH:mm:ssZ").replace(/\[([^\]]+)]|Q|wo|ww|w|WW|W|zzz|z|gggg|GGGG|Do|X|x|k{1,2}|S/g,function(S){switch(S){case"Q":return Math.ceil((k.$M+1)/3);case"Do":return Y.ordinal(k.$D);case"gggg":return k.weekYear();case"GGGG":return k.isoWeekYear();case"wo":return Y.ordinal(k.week(),"W");case"w":case"ww":return g.s(k.week(),S==="w"?1:2,"0");case"W":case"WW":return g.s(k.isoWeek(),S==="W"?1:2,"0");case"k":case"kk":return g.s(String(k.$H===0?24:k.$H),S==="k"?1:2,"0");case"X":return Math.floor(k.$d.getTime()/1e3);case"x":return k.$d.getTime();case"z":return"["+k.offsetName()+"]";case"zzz":return"["+k.offsetName("long")+"]";default:return S}});return i.bind(this)(w)}}})})(xn);var Ea=xn.exports;const La=be(Ea);var ye=function(){var t=d(function(E,l,h,v){for(h=h||{},v=E.length;v--;h[E[v]]=l);return h},"o"),e=[6,8,10,12,13,14,15,16,17,18,20,21,22,23,24,25,26,27,28,29,30,31,33,35,36,38,40],n=[1,26],r=[1,27],a=[1,28],i=[1,29],s=[1,30],k=[1,31],Y=[1,32],g=[1,33],w=[1,34],S=[1,9],C=[1,10],b=[1,11],q=[1,12],y=[1,13],I=[1,14],N=[1,15],H=[1,16],R=[1,19],B=[1,20],J=[1,21],D=[1,22],W=[1,23],x=[1,25],U=[1,35],_={trace:d(function(){},"trace"),yy:{},symbols_:{error:2,start:3,gantt:4,document:5,EOF:6,line:7,SPACE:8,statement:9,NL:10,weekday:11,weekday_monday:12,weekday_tuesday:13,weekday_wednesday:14,weekday_thursday:15,weekday_friday:16,weekday_saturday:17,weekday_sunday:18,weekend:19,weekend_friday:20,weekend_saturday:21,dateFormat:22,inclusiveEndDates:23,topAxis:24,axisFormat:25,tickInterval:26,excludes:27,includes:28,todayMarker:29,title:30,acc_title:31,acc_title_value:32,acc_descr:33,acc_descr_value:34,acc_descr_multiline_value:35,section:36,clickStatement:37,taskTxt:38,taskData:39,click:40,callbackname:41,callbackargs:42,href:43,clickStatementDebug:44,$accept:0,$end:1},terminals_:{2:"error",4:"gantt",6:"EOF",8:"SPACE",10:"NL",12:"weekday_monday",13:"weekday_tuesday",14:"weekday_wednesday",15:"weekday_thursday",16:"weekday_friday",17:"weekday_saturday",18:"weekday_sunday",20:"weekend_friday",21:"weekend_saturday",22:"dateFormat",23:"inclusiveEndDates",24:"topAxis",25:"axisFormat",26:"tickInterval",27:"excludes",28:"includes",29:"todayMarker",30:"title",31:"acc_title",32:"acc_title_value",33:"acc_descr",34:"acc_descr_value",35:"acc_descr_multiline_value",36:"section",38:"taskTxt",39:"taskData",40:"click",41:"callbackname",42:"callbackargs",43:"href"},productions_:[0,[3,3],[5,0],[5,2],[7,2],[7,1],[7,1],[7,1],[11,1],[11,1],[11,1],[11,1],[11,1],[11,1],[11,1],[19,1],[19,1],[9,1],[9,1],[9,1],[9,1],[9,1],[9,1],[9,1],[9,1],[9,1],[9,1],[9,1],[9,2],[9,2],[9,1],[9,1],[9,1],[9,2],[37,2],[37,3],[37,3],[37,4],[37,3],[37,4],[37,2],[44,2],[44,3],[44,3],[44,4],[44,3],[44,4],[44,2]],performAction:d(function(l,h,v,m,F,o,f){var c=o.length-1;switch(F){case 1:return o[c-1];case 2:this.$=[];break;case 3:o[c-1].push(o[c]),this.$=o[c-1];break;case 4:case 5:this.$=o[c];break;case 6:case 7:this.$=[];break;case 8:m.setWeekday("monday");break;case 9:m.setWeekday("tuesday");break;case 10:m.setWeekday("wednesday");break;case 11:m.setWeekday("thursday");break;case 12:m.setWeekday("friday");break;case 13:m.setWeekday("saturday");break;case 14:m.setWeekday("sunday");break;case 15:m.setWeekend("friday");break;case 16:m.setWeekend("saturday");break;case 17:m.setDateFormat(o[c].substr(11)),this.$=o[c].substr(11);break;case 18:m.enableInclusiveEndDates(),this.$=o[c].substr(18);break;case 19:m.TopAxis(),this.$=o[c].substr(8);break;case 20:m.setAxisFormat(o[c].substr(11)),this.$=o[c].substr(11);break;case 21:m.setTickInterval(o[c].substr(13)),this.$=o[c].substr(13);break;case 22:m.setExcludes(o[c].substr(9)),this.$=o[c].substr(9);break;case 23:m.setIncludes(o[c].substr(9)),this.$=o[c].substr(9);break;case 24:m.setTodayMarker(o[c].substr(12)),this.$=o[c].substr(12);break;case 27:m.setDiagramTitle(o[c].substr(6)),this.$=o[c].substr(6);break;case 28:this.$=o[c].trim(),m.setAccTitle(this.$);break;case 29:case 30:this.$=o[c].trim(),m.setAccDescription(this.$);break;case 31:m.addSection(o[c].substr(8)),this.$=o[c].substr(8);break;case 33:m.addTask(o[c-1],o[c]),this.$="task";break;case 34:this.$=o[c-1],m.setClickEvent(o[c-1],o[c],null);break;case 35:this.$=o[c-2],m.setClickEvent(o[c-2],o[c-1],o[c]);break;case 36:this.$=o[c-2],m.setClickEvent(o[c-2],o[c-1],null),m.setLink(o[c-2],o[c]);break;case 37:this.$=o[c-3],m.setClickEvent(o[c-3],o[c-2],o[c-1]),m.setLink(o[c-3],o[c]);break;case 38:this.$=o[c-2],m.setClickEvent(o[c-2],o[c],null),m.setLink(o[c-2],o[c-1]);break;case 39:this.$=o[c-3],m.setClickEvent(o[c-3],o[c-1],o[c]),m.setLink(o[c-3],o[c-2]);break;case 40:this.$=o[c-1],m.setLink(o[c-1],o[c]);break;case 41:case 47:this.$=o[c-1]+" "+o[c];break;case 42:case 43:case 45:this.$=o[c-2]+" "+o[c-1]+" "+o[c];break;case 44:case 46:this.$=o[c-3]+" "+o[c-2]+" "+o[c-1]+" "+o[c];break}},"anonymous"),table:[{3:1,4:[1,2]},{1:[3]},t(e,[2,2],{5:3}),{6:[1,4],7:5,8:[1,6],9:7,10:[1,8],11:17,12:n,13:r,14:a,15:i,16:s,17:k,18:Y,19:18,20:g,21:w,22:S,23:C,24:b,25:q,26:y,27:I,28:N,29:H,30:R,31:B,33:J,35:D,36:W,37:24,38:x,40:U},t(e,[2,7],{1:[2,1]}),t(e,[2,3]),{9:36,11:17,12:n,13:r,14:a,15:i,16:s,17:k,18:Y,19:18,20:g,21:w,22:S,23:C,24:b,25:q,26:y,27:I,28:N,29:H,30:R,31:B,33:J,35:D,36:W,37:24,38:x,40:U},t(e,[2,5]),t(e,[2,6]),t(e,[2,17]),t(e,[2,18]),t(e,[2,19]),t(e,[2,20]),t(e,[2,21]),t(e,[2,22]),t(e,[2,23]),t(e,[2,24]),t(e,[2,25]),t(e,[2,26]),t(e,[2,27]),{32:[1,37]},{34:[1,38]},t(e,[2,30]),t(e,[2,31]),t(e,[2,32]),{39:[1,39]},t(e,[2,8]),t(e,[2,9]),t(e,[2,10]),t(e,[2,11]),t(e,[2,12]),t(e,[2,13]),t(e,[2,14]),t(e,[2,15]),t(e,[2,16]),{41:[1,40],43:[1,41]},t(e,[2,4]),t(e,[2,28]),t(e,[2,29]),t(e,[2,33]),t(e,[2,34],{42:[1,42],43:[1,43]}),t(e,[2,40],{41:[1,44]}),t(e,[2,35],{43:[1,45]}),t(e,[2,36]),t(e,[2,38],{42:[1,46]}),t(e,[2,37]),t(e,[2,39])],defaultActions:{},parseError:d(function(l,h){if(h.recoverable)this.trace(l);else{var v=new Error(l);throw v.hash=h,v}},"parseError"),parse:d(function(l){var h=this,v=[0],m=[],F=[null],o=[],f=this.table,c="",Z=0,V=0,z=2,$=1,G=o.slice.call(arguments,1),j=Object.create(this.lexer),rt={yy:{}};for(var T in this.yy)Object.prototype.hasOwnProperty.call(this.yy,T)&&(rt.yy[T]=this.yy[T]);j.setInput(l,rt.yy),rt.yy.lexer=j,rt.yy.parser=this,typeof j.yylloc>"u"&&(j.yylloc={});var A=j.yylloc;o.push(A);var O=j.options&&j.options.ranges;typeof rt.yy.parseError=="function"?this.parseError=rt.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function u(it){v.length=v.length-2*it,F.length=F.length-it,o.length=o.length-it}d(u,"popStack");function K(){var it;return it=m.pop()||j.lex()||$,typeof it!="number"&&(it instanceof Array&&(m=it,it=m.pop()),it=h.symbols_[it]||it),it}d(K,"lex");for(var L,Q,X,ot,ut={},Rt,ft,Ae,Bt;;){if(Q=v[v.length-1],this.defaultActions[Q]?X=this.defaultActions[Q]:((L===null||typeof L>"u")&&(L=K()),X=f[Q]&&f[Q][L]),typeof X>"u"||!X.length||!X[0]){var ne="";Bt=[];for(Rt in f[Q])this.terminals_[Rt]&&Rt>z&&Bt.push("'"+this.terminals_[Rt]+"'");j.showPosition?ne="Parse error on line "+(Z+1)+`:
                                      +import{aQ as Je,aR as Ke,aS as $e,aT as tn,aU as Yn,aV as re,aW as En,aF as Te,aG as be,_ as d,aX as at,d as Mt,s as Ln,g as An,q as In,r as Wn,c as On,b as Hn,t as Nn,m as Vn,l as Qt,j as Zt,k as zn,e as Pn,u as Rn}from"./mermaid.core-D8igZDel.js";import{b as Bn,t as Ie,c as Zn,a as qn,l as Xn}from"./linear-hDJDjKgB.js";import{i as Gn}from"./init-Gi6I4Gst.js";import"./app-D7uBbsY3.js";function jn(t,e){let n;if(e===void 0)for(const r of t)r!=null&&(n=r)&&(n=r);else{let r=-1;for(let a of t)(a=e(a,++r,t))!=null&&(n=a)&&(n=a)}return n}function Qn(t,e){let n;if(e===void 0)for(const r of t)r!=null&&(n>r||n===void 0&&r>=r)&&(n=r);else{let r=-1;for(let a of t)(a=e(a,++r,t))!=null&&(n>a||n===void 0&&a>=a)&&(n=a)}return n}function Jn(t){return t}var Xt=1,ae=2,me=3,qt=4,We=1e-6;function Kn(t){return"translate("+t+",0)"}function $n(t){return"translate(0,"+t+")"}function tr(t){return e=>+t(e)}function er(t,e){return e=Math.max(0,t.bandwidth()-e*2)/2,t.round()&&(e=Math.round(e)),n=>+t(n)+e}function nr(){return!this.__axis}function en(t,e){var n=[],r=null,a=null,i=6,s=6,k=3,Y=typeof window<"u"&&window.devicePixelRatio>1?0:.5,g=t===Xt||t===qt?-1:1,w=t===qt||t===ae?"x":"y",S=t===Xt||t===me?Kn:$n;function C(b){var q=r??(e.ticks?e.ticks.apply(e,n):e.domain()),y=a??(e.tickFormat?e.tickFormat.apply(e,n):Jn),I=Math.max(i,0)+k,N=e.range(),H=+N[0]+Y,R=+N[N.length-1]+Y,B=(e.bandwidth?er:tr)(e.copy(),Y),J=b.selection?b.selection():b,D=J.selectAll(".domain").data([null]),W=J.selectAll(".tick").data(q,e).order(),x=W.exit(),U=W.enter().append("g").attr("class","tick"),_=W.select("line"),M=W.select("text");D=D.merge(D.enter().insert("path",".tick").attr("class","domain").attr("stroke","currentColor")),W=W.merge(U),_=_.merge(U.append("line").attr("stroke","currentColor").attr(w+"2",g*i)),M=M.merge(U.append("text").attr("fill","currentColor").attr(w,g*I).attr("dy",t===Xt?"0em":t===me?"0.71em":"0.32em")),b!==J&&(D=D.transition(b),W=W.transition(b),_=_.transition(b),M=M.transition(b),x=x.transition(b).attr("opacity",We).attr("transform",function(p){return isFinite(p=B(p))?S(p+Y):this.getAttribute("transform")}),U.attr("opacity",We).attr("transform",function(p){var E=this.parentNode.__axis;return S((E&&isFinite(E=E(p))?E:B(p))+Y)})),x.remove(),D.attr("d",t===qt||t===ae?s?"M"+g*s+","+H+"H"+Y+"V"+R+"H"+g*s:"M"+Y+","+H+"V"+R:s?"M"+H+","+g*s+"V"+Y+"H"+R+"V"+g*s:"M"+H+","+Y+"H"+R),W.attr("opacity",1).attr("transform",function(p){return S(B(p)+Y)}),_.attr(w+"2",g*i),M.attr(w,g*I).text(y),J.filter(nr).attr("fill","none").attr("font-size",10).attr("font-family","sans-serif").attr("text-anchor",t===ae?"start":t===qt?"end":"middle"),J.each(function(){this.__axis=B})}return C.scale=function(b){return arguments.length?(e=b,C):e},C.ticks=function(){return n=Array.from(arguments),C},C.tickArguments=function(b){return arguments.length?(n=b==null?[]:Array.from(b),C):n.slice()},C.tickValues=function(b){return arguments.length?(r=b==null?null:Array.from(b),C):r&&r.slice()},C.tickFormat=function(b){return arguments.length?(a=b,C):a},C.tickSize=function(b){return arguments.length?(i=s=+b,C):i},C.tickSizeInner=function(b){return arguments.length?(i=+b,C):i},C.tickSizeOuter=function(b){return arguments.length?(s=+b,C):s},C.tickPadding=function(b){return arguments.length?(k=+b,C):k},C.offset=function(b){return arguments.length?(Y=+b,C):Y},C}function rr(t){return en(Xt,t)}function ar(t){return en(me,t)}const ir=Math.PI/180,sr=180/Math.PI,Jt=18,nn=.96422,rn=1,an=.82521,sn=4/29,_t=6/29,on=3*_t*_t,or=_t*_t*_t;function cn(t){if(t instanceof lt)return new lt(t.l,t.a,t.b,t.opacity);if(t instanceof dt)return ln(t);t instanceof $e||(t=Yn(t));var e=ce(t.r),n=ce(t.g),r=ce(t.b),a=ie((.2225045*e+.7168786*n+.0606169*r)/rn),i,s;return e===n&&n===r?i=s=a:(i=ie((.4360747*e+.3850649*n+.1430804*r)/nn),s=ie((.0139322*e+.0971045*n+.7141733*r)/an)),new lt(116*a-16,500*(i-a),200*(a-s),t.opacity)}function cr(t,e,n,r){return arguments.length===1?cn(t):new lt(t,e,n,r??1)}function lt(t,e,n,r){this.l=+t,this.a=+e,this.b=+n,this.opacity=+r}Je(lt,cr,Ke(tn,{brighter(t){return new lt(this.l+Jt*(t??1),this.a,this.b,this.opacity)},darker(t){return new lt(this.l-Jt*(t??1),this.a,this.b,this.opacity)},rgb(){var t=(this.l+16)/116,e=isNaN(this.a)?t:t+this.a/500,n=isNaN(this.b)?t:t-this.b/200;return e=nn*se(e),t=rn*se(t),n=an*se(n),new $e(oe(3.1338561*e-1.6168667*t-.4906146*n),oe(-.9787684*e+1.9161415*t+.033454*n),oe(.0719453*e-.2289914*t+1.4052427*n),this.opacity)}}));function ie(t){return t>or?Math.pow(t,1/3):t/on+sn}function se(t){return t>_t?t*t*t:on*(t-sn)}function oe(t){return 255*(t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055)}function ce(t){return(t/=255)<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4)}function lr(t){if(t instanceof dt)return new dt(t.h,t.c,t.l,t.opacity);if(t instanceof lt||(t=cn(t)),t.a===0&&t.b===0)return new dt(NaN,0(t(i=new Date(+i)),i),a.ceil=i=>(t(i=new Date(i-1)),e(i,1),t(i),i),a.round=i=>{const s=a(i),k=a.ceil(i);return i-s(e(i=new Date(+i),s==null?1:Math.floor(s)),i),a.range=(i,s,k)=>{const Y=[];if(i=a.ceil(i),k=k==null?1:Math.floor(k),!(i0))return Y;let g;do Y.push(g=new Date(+i)),e(i,k),t(i);while(get(s=>{if(s>=s)for(;t(s),!i(s);)s.setTime(s-1)},(s,k)=>{if(s>=s)if(k<0)for(;++k<=0;)for(;e(s,-1),!i(s););else for(;--k>=0;)for(;e(s,1),!i(s););}),n&&(a.count=(i,s)=>(le.setTime(+i),ue.setTime(+s),t(le),t(ue),Math.floor(n(le,ue))),a.every=i=>(i=Math.floor(i),!isFinite(i)||!(i>0)?null:i>1?a.filter(r?s=>r(s)%i===0:s=>a.count(0,s)%i===0):a)),a}const Ut=et(()=>{},(t,e)=>{t.setTime(+t+e)},(t,e)=>e-t);Ut.every=t=>(t=Math.floor(t),!isFinite(t)||!(t>0)?null:t>1?et(e=>{e.setTime(Math.floor(e/t)*t)},(e,n)=>{e.setTime(+e+n*t)},(e,n)=>(n-e)/t):Ut);Ut.range;const mt=1e3,st=mt*60,gt=st*60,yt=gt*24,xe=yt*7,Oe=yt*30,fe=yt*365,pt=et(t=>{t.setTime(t-t.getMilliseconds())},(t,e)=>{t.setTime(+t+e*mt)},(t,e)=>(e-t)/mt,t=>t.getUTCSeconds());pt.range;const It=et(t=>{t.setTime(t-t.getMilliseconds()-t.getSeconds()*mt)},(t,e)=>{t.setTime(+t+e*st)},(t,e)=>(e-t)/st,t=>t.getMinutes());It.range;const dr=et(t=>{t.setUTCSeconds(0,0)},(t,e)=>{t.setTime(+t+e*st)},(t,e)=>(e-t)/st,t=>t.getUTCMinutes());dr.range;const Wt=et(t=>{t.setTime(t-t.getMilliseconds()-t.getSeconds()*mt-t.getMinutes()*st)},(t,e)=>{t.setTime(+t+e*gt)},(t,e)=>(e-t)/gt,t=>t.getHours());Wt.range;const mr=et(t=>{t.setUTCMinutes(0,0,0)},(t,e)=>{t.setTime(+t+e*gt)},(t,e)=>(e-t)/gt,t=>t.getUTCHours());mr.range;const vt=et(t=>t.setHours(0,0,0,0),(t,e)=>t.setDate(t.getDate()+e),(t,e)=>(e-t-(e.getTimezoneOffset()-t.getTimezoneOffset())*st)/yt,t=>t.getDate()-1);vt.range;const we=et(t=>{t.setUTCHours(0,0,0,0)},(t,e)=>{t.setUTCDate(t.getUTCDate()+e)},(t,e)=>(e-t)/yt,t=>t.getUTCDate()-1);we.range;const gr=et(t=>{t.setUTCHours(0,0,0,0)},(t,e)=>{t.setUTCDate(t.getUTCDate()+e)},(t,e)=>(e-t)/yt,t=>Math.floor(t/yt));gr.range;function xt(t){return et(e=>{e.setDate(e.getDate()-(e.getDay()+7-t)%7),e.setHours(0,0,0,0)},(e,n)=>{e.setDate(e.getDate()+n*7)},(e,n)=>(n-e-(n.getTimezoneOffset()-e.getTimezoneOffset())*st)/xe)}const Nt=xt(0),Ot=xt(1),un=xt(2),fn=xt(3),Tt=xt(4),hn=xt(5),dn=xt(6);Nt.range;Ot.range;un.range;fn.range;Tt.range;hn.range;dn.range;function wt(t){return et(e=>{e.setUTCDate(e.getUTCDate()-(e.getUTCDay()+7-t)%7),e.setUTCHours(0,0,0,0)},(e,n)=>{e.setUTCDate(e.getUTCDate()+n*7)},(e,n)=>(n-e)/xe)}const mn=wt(0),Kt=wt(1),yr=wt(2),kr=wt(3),Ft=wt(4),pr=wt(5),vr=wt(6);mn.range;Kt.range;yr.range;kr.range;Ft.range;pr.range;vr.range;const Ht=et(t=>{t.setDate(1),t.setHours(0,0,0,0)},(t,e)=>{t.setMonth(t.getMonth()+e)},(t,e)=>e.getMonth()-t.getMonth()+(e.getFullYear()-t.getFullYear())*12,t=>t.getMonth());Ht.range;const Tr=et(t=>{t.setUTCDate(1),t.setUTCHours(0,0,0,0)},(t,e)=>{t.setUTCMonth(t.getUTCMonth()+e)},(t,e)=>e.getUTCMonth()-t.getUTCMonth()+(e.getUTCFullYear()-t.getUTCFullYear())*12,t=>t.getUTCMonth());Tr.range;const kt=et(t=>{t.setMonth(0,1),t.setHours(0,0,0,0)},(t,e)=>{t.setFullYear(t.getFullYear()+e)},(t,e)=>e.getFullYear()-t.getFullYear(),t=>t.getFullYear());kt.every=t=>!isFinite(t=Math.floor(t))||!(t>0)?null:et(e=>{e.setFullYear(Math.floor(e.getFullYear()/t)*t),e.setMonth(0,1),e.setHours(0,0,0,0)},(e,n)=>{e.setFullYear(e.getFullYear()+n*t)});kt.range;const bt=et(t=>{t.setUTCMonth(0,1),t.setUTCHours(0,0,0,0)},(t,e)=>{t.setUTCFullYear(t.getUTCFullYear()+e)},(t,e)=>e.getUTCFullYear()-t.getUTCFullYear(),t=>t.getUTCFullYear());bt.every=t=>!isFinite(t=Math.floor(t))||!(t>0)?null:et(e=>{e.setUTCFullYear(Math.floor(e.getUTCFullYear()/t)*t),e.setUTCMonth(0,1),e.setUTCHours(0,0,0,0)},(e,n)=>{e.setUTCFullYear(e.getUTCFullYear()+n*t)});bt.range;function br(t,e,n,r,a,i){const s=[[pt,1,mt],[pt,5,5*mt],[pt,15,15*mt],[pt,30,30*mt],[i,1,st],[i,5,5*st],[i,15,15*st],[i,30,30*st],[a,1,gt],[a,3,3*gt],[a,6,6*gt],[a,12,12*gt],[r,1,yt],[r,2,2*yt],[n,1,xe],[e,1,Oe],[e,3,3*Oe],[t,1,fe]];function k(g,w,S){const C=wI).right(s,C);if(b===s.length)return t.every(Ie(g/fe,w/fe,S));if(b===0)return Ut.every(Math.max(Ie(g,w,S),1));const[q,y]=s[C/s[b-1][2]53)return null;"w"in u||(u.w=1),"Z"in u?(L=de(Et(u.y,0,1)),Q=L.getUTCDay(),L=Q>4||Q===0?Kt.ceil(L):Kt(L),L=we.offset(L,(u.V-1)*7),u.y=L.getUTCFullYear(),u.m=L.getUTCMonth(),u.d=L.getUTCDate()+(u.w+6)%7):(L=he(Et(u.y,0,1)),Q=L.getDay(),L=Q>4||Q===0?Ot.ceil(L):Ot(L),L=vt.offset(L,(u.V-1)*7),u.y=L.getFullYear(),u.m=L.getMonth(),u.d=L.getDate()+(u.w+6)%7)}else("W"in u||"U"in u)&&("w"in u||(u.w="u"in u?u.u%7:"W"in u?1:0),Q="Z"in u?de(Et(u.y,0,1)).getUTCDay():he(Et(u.y,0,1)).getDay(),u.m=0,u.d="W"in u?(u.w+6)%7+u.W*7-(Q+5)%7:u.w+u.U*7-(Q+6)%7);return"Z"in u?(u.H+=u.Z/100|0,u.M+=u.Z%100,de(u)):he(u)}}function x(T,A,O,u){for(var K=0,L=A.length,Q=O.length,X,ot;K=Q)return-1;if(X=A.charCodeAt(K++),X===37){if(X=A.charAt(K++),ot=J[X in He?A.charAt(K++):X],!ot||(u=ot(T,O,u))<0)return-1}else if(X!=O.charCodeAt(u++))return-1}return u}function U(T,A,O){var u=g.exec(A.slice(O));return u?(T.p=w.get(u[0].toLowerCase()),O+u[0].length):-1}function _(T,A,O){var u=b.exec(A.slice(O));return u?(T.w=q.get(u[0].toLowerCase()),O+u[0].length):-1}function M(T,A,O){var u=S.exec(A.slice(O));return u?(T.w=C.get(u[0].toLowerCase()),O+u[0].length):-1}function p(T,A,O){var u=N.exec(A.slice(O));return u?(T.m=H.get(u[0].toLowerCase()),O+u[0].length):-1}function E(T,A,O){var u=y.exec(A.slice(O));return u?(T.m=I.get(u[0].toLowerCase()),O+u[0].length):-1}function l(T,A,O){return x(T,e,A,O)}function h(T,A,O){return x(T,n,A,O)}function v(T,A,O){return x(T,r,A,O)}function m(T){return s[T.getDay()]}function F(T){return i[T.getDay()]}function o(T){return Y[T.getMonth()]}function f(T){return k[T.getMonth()]}function c(T){return a[+(T.getHours()>=12)]}function Z(T){return 1+~~(T.getMonth()/3)}function V(T){return s[T.getUTCDay()]}function z(T){return i[T.getUTCDay()]}function $(T){return Y[T.getUTCMonth()]}function G(T){return k[T.getUTCMonth()]}function j(T){return a[+(T.getUTCHours()>=12)]}function rt(T){return 1+~~(T.getUTCMonth()/3)}return{format:function(T){var A=D(T+="",R);return A.toString=function(){return T},A},parse:function(T){var A=W(T+="",!1);return A.toString=function(){return T},A},utcFormat:function(T){var A=D(T+="",B);return A.toString=function(){return T},A},utcParse:function(T){var A=W(T+="",!0);return A.toString=function(){return T},A}}}var He={"-":"",_:" ",0:"0"},nt=/^\s*\d+/,Cr=/^%/,Mr=/[\\^$*+?|[\]().{}]/g;function P(t,e,n){var r=t<0?"-":"",a=(r?-t:t)+"",i=a.length;return r+(i[e.toLowerCase(),n]))}function Sr(t,e,n){var r=nt.exec(e.slice(n,n+1));return r?(t.w=+r[0],n+r[0].length):-1}function Ur(t,e,n){var r=nt.exec(e.slice(n,n+1));return r?(t.u=+r[0],n+r[0].length):-1}function Fr(t,e,n){var r=nt.exec(e.slice(n,n+2));return r?(t.U=+r[0],n+r[0].length):-1}function Yr(t,e,n){var r=nt.exec(e.slice(n,n+2));return r?(t.V=+r[0],n+r[0].length):-1}function Er(t,e,n){var r=nt.exec(e.slice(n,n+2));return r?(t.W=+r[0],n+r[0].length):-1}function Ne(t,e,n){var r=nt.exec(e.slice(n,n+4));return r?(t.y=+r[0],n+r[0].length):-1}function Ve(t,e,n){var r=nt.exec(e.slice(n,n+2));return r?(t.y=+r[0]+(+r[0]>68?1900:2e3),n+r[0].length):-1}function Lr(t,e,n){var r=/^(Z)|([+-]\d\d)(?::?(\d\d))?/.exec(e.slice(n,n+6));return r?(t.Z=r[1]?0:-(r[2]+(r[3]||"00")),n+r[0].length):-1}function Ar(t,e,n){var r=nt.exec(e.slice(n,n+1));return r?(t.q=r[0]*3-3,n+r[0].length):-1}function Ir(t,e,n){var r=nt.exec(e.slice(n,n+2));return r?(t.m=r[0]-1,n+r[0].length):-1}function ze(t,e,n){var r=nt.exec(e.slice(n,n+2));return r?(t.d=+r[0],n+r[0].length):-1}function Wr(t,e,n){var r=nt.exec(e.slice(n,n+3));return r?(t.m=0,t.d=+r[0],n+r[0].length):-1}function Pe(t,e,n){var r=nt.exec(e.slice(n,n+2));return r?(t.H=+r[0],n+r[0].length):-1}function Or(t,e,n){var r=nt.exec(e.slice(n,n+2));return r?(t.M=+r[0],n+r[0].length):-1}function Hr(t,e,n){var r=nt.exec(e.slice(n,n+2));return r?(t.S=+r[0],n+r[0].length):-1}function Nr(t,e,n){var r=nt.exec(e.slice(n,n+3));return r?(t.L=+r[0],n+r[0].length):-1}function Vr(t,e,n){var r=nt.exec(e.slice(n,n+6));return r?(t.L=Math.floor(r[0]/1e3),n+r[0].length):-1}function zr(t,e,n){var r=Cr.exec(e.slice(n,n+1));return r?n+r[0].length:-1}function Pr(t,e,n){var r=nt.exec(e.slice(n));return r?(t.Q=+r[0],n+r[0].length):-1}function Rr(t,e,n){var r=nt.exec(e.slice(n));return r?(t.s=+r[0],n+r[0].length):-1}function Re(t,e){return P(t.getDate(),e,2)}function Br(t,e){return P(t.getHours(),e,2)}function Zr(t,e){return P(t.getHours()%12||12,e,2)}function qr(t,e){return P(1+vt.count(kt(t),t),e,3)}function gn(t,e){return P(t.getMilliseconds(),e,3)}function Xr(t,e){return gn(t,e)+"000"}function Gr(t,e){return P(t.getMonth()+1,e,2)}function jr(t,e){return P(t.getMinutes(),e,2)}function Qr(t,e){return P(t.getSeconds(),e,2)}function Jr(t){var e=t.getDay();return e===0?7:e}function Kr(t,e){return P(Nt.count(kt(t)-1,t),e,2)}function yn(t){var e=t.getDay();return e>=4||e===0?Tt(t):Tt.ceil(t)}function $r(t,e){return t=yn(t),P(Tt.count(kt(t),t)+(kt(t).getDay()===4),e,2)}function ta(t){return t.getDay()}function ea(t,e){return P(Ot.count(kt(t)-1,t),e,2)}function na(t,e){return P(t.getFullYear()%100,e,2)}function ra(t,e){return t=yn(t),P(t.getFullYear()%100,e,2)}function aa(t,e){return P(t.getFullYear()%1e4,e,4)}function ia(t,e){var n=t.getDay();return t=n>=4||n===0?Tt(t):Tt.ceil(t),P(t.getFullYear()%1e4,e,4)}function sa(t){var e=t.getTimezoneOffset();return(e>0?"-":(e*=-1,"+"))+P(e/60|0,"0",2)+P(e%60,"0",2)}function Be(t,e){return P(t.getUTCDate(),e,2)}function oa(t,e){return P(t.getUTCHours(),e,2)}function ca(t,e){return P(t.getUTCHours()%12||12,e,2)}function la(t,e){return P(1+we.count(bt(t),t),e,3)}function kn(t,e){return P(t.getUTCMilliseconds(),e,3)}function ua(t,e){return kn(t,e)+"000"}function fa(t,e){return P(t.getUTCMonth()+1,e,2)}function ha(t,e){return P(t.getUTCMinutes(),e,2)}function da(t,e){return P(t.getUTCSeconds(),e,2)}function ma(t){var e=t.getUTCDay();return e===0?7:e}function ga(t,e){return P(mn.count(bt(t)-1,t),e,2)}function pn(t){var e=t.getUTCDay();return e>=4||e===0?Ft(t):Ft.ceil(t)}function ya(t,e){return t=pn(t),P(Ft.count(bt(t),t)+(bt(t).getUTCDay()===4),e,2)}function ka(t){return t.getUTCDay()}function pa(t,e){return P(Kt.count(bt(t)-1,t),e,2)}function va(t,e){return P(t.getUTCFullYear()%100,e,2)}function Ta(t,e){return t=pn(t),P(t.getUTCFullYear()%100,e,2)}function ba(t,e){return P(t.getUTCFullYear()%1e4,e,4)}function xa(t,e){var n=t.getUTCDay();return t=n>=4||n===0?Ft(t):Ft.ceil(t),P(t.getUTCFullYear()%1e4,e,4)}function wa(){return"+0000"}function Ze(){return"%"}function qe(t){return+t}function Xe(t){return Math.floor(+t/1e3)}var Ct,$t;Da({dateTime:"%x, %X",date:"%-m/%-d/%Y",time:"%-I:%M:%S %p",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});function Da(t){return Ct=Dr(t),$t=Ct.format,Ct.parse,Ct.utcFormat,Ct.utcParse,Ct}function Ca(t){return new Date(t)}function Ma(t){return t instanceof Date?+t:+new Date(+t)}function vn(t,e,n,r,a,i,s,k,Y,g){var w=Zn(),S=w.invert,C=w.domain,b=g(".%L"),q=g(":%S"),y=g("%I:%M"),I=g("%I %p"),N=g("%a %d"),H=g("%b %d"),R=g("%B"),B=g("%Y");function J(D){return(Y(D)4&&(b+=7),C.add(b,n));return q.diff(y,"week")+1},k.isoWeekday=function(g){return this.$utils().u(g)?this.day()||7:this.day(this.day()%7?g:g-7)};var Y=k.startOf;k.startOf=function(g,w){var S=this.$utils(),C=!!S.u(w)||w;return S.p(g)==="isoweek"?C?this.date(this.date()-(this.isoWeekday()-1)).startOf("day"):this.date(this.date()-1-(this.isoWeekday()-1)+7).endOf("day"):Y.bind(this)(g,w)}}})})(Tn);var Sa=Tn.exports;const Ua=be(Sa);var bn={exports:{}};(function(t,e){(function(n,r){t.exports=r()})(Te,function(){var n={LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"},r=/(\[[^[]*\])|([-_:/.,()\s]+)|(A|a|YYYY|YY?|MM?M?M?|Do|DD?|hh?|HH?|mm?|ss?|S{1,3}|z|ZZ?)/g,a=/\d\d/,i=/\d\d?/,s=/\d*[^-_:/,()\s\d]+/,k={},Y=function(y){return(y=+y)+(y>68?1900:2e3)},g=function(y){return function(I){this[y]=+I}},w=[/[+-]\d\d:?(\d\d)?|Z/,function(y){(this.zone||(this.zone={})).offset=function(I){if(!I||I==="Z")return 0;var N=I.match(/([+-]|\d\d)/g),H=60*N[1]+(+N[2]||0);return H===0?0:N[0]==="+"?-H:H}(y)}],S=function(y){var I=k[y];return I&&(I.indexOf?I:I.s.concat(I.f))},C=function(y,I){var N,H=k.meridiem;if(H){for(var R=1;R<=24;R+=1)if(y.indexOf(H(R,0,I))>-1){N=R>12;break}}else N=y===(I?"pm":"PM");return N},b={A:[s,function(y){this.afternoon=C(y,!1)}],a:[s,function(y){this.afternoon=C(y,!0)}],S:[/\d/,function(y){this.milliseconds=100*+y}],SS:[a,function(y){this.milliseconds=10*+y}],SSS:[/\d{3}/,function(y){this.milliseconds=+y}],s:[i,g("seconds")],ss:[i,g("seconds")],m:[i,g("minutes")],mm:[i,g("minutes")],H:[i,g("hours")],h:[i,g("hours")],HH:[i,g("hours")],hh:[i,g("hours")],D:[i,g("day")],DD:[a,g("day")],Do:[s,function(y){var I=k.ordinal,N=y.match(/\d+/);if(this.day=N[0],I)for(var H=1;H<=31;H+=1)I(H).replace(/\[|\]/g,"")===y&&(this.day=H)}],M:[i,g("month")],MM:[a,g("month")],MMM:[s,function(y){var I=S("months"),N=(S("monthsShort")||I.map(function(H){return H.slice(0,3)})).indexOf(y)+1;if(N<1)throw new Error;this.month=N%12||N}],MMMM:[s,function(y){var I=S("months").indexOf(y)+1;if(I<1)throw new Error;this.month=I%12||I}],Y:[/[+-]?\d+/,g("year")],YY:[a,function(y){this.year=Y(y)}],YYYY:[/\d{4}/,g("year")],Z:w,ZZ:w};function q(y){var I,N;I=y,N=k&&k.formats;for(var H=(y=I.replace(/(\[[^\]]+])|(LTS?|l{1,4}|L{1,4})/g,function(U,_,M){var p=M&&M.toUpperCase();return _||N[M]||n[M]||N[p].replace(/(\[[^\]]+])|(MMMM|MM|DD|dddd)/g,function(E,l,h){return l||h.slice(1)})})).match(r),R=H.length,B=0;B-1)return new Date((m==="X"?1e3:1)*v);var o=q(m)(v),f=o.year,c=o.month,Z=o.day,V=o.hours,z=o.minutes,$=o.seconds,G=o.milliseconds,j=o.zone,rt=new Date,T=Z||(f||c?1:rt.getDate()),A=f||rt.getFullYear(),O=0;f&&!c||(O=c>0?c-1:rt.getMonth());var u=V||0,K=z||0,L=$||0,Q=G||0;return j?new Date(Date.UTC(A,O,T,u,K,L,Q+60*j.offset*1e3)):F?new Date(Date.UTC(A,O,T,u,K,L,Q)):new Date(A,O,T,u,K,L,Q)}catch{return new Date("")}}(J,x,D),this.init(),p&&p!==!0&&(this.$L=this.locale(p).$L),M&&J!=this.format(x)&&(this.$d=new Date("")),k={}}else if(x instanceof Array)for(var E=x.length,l=1;l<=E;l+=1){W[1]=x[l-1];var h=N.apply(this,W);if(h.isValid()){this.$d=h.$d,this.$L=h.$L,this.init();break}l===E&&(this.$d=new Date(""))}else R.call(this,B)}}})})(bn);var Fa=bn.exports;const Ya=be(Fa);var xn={exports:{}};(function(t,e){(function(n,r){t.exports=r()})(Te,function(){return function(n,r){var a=r.prototype,i=a.format;a.format=function(s){var k=this,Y=this.$locale();if(!this.isValid())return i.bind(this)(s);var g=this.$utils(),w=(s||"YYYY-MM-DDTHH:mm:ssZ").replace(/\[([^\]]+)]|Q|wo|ww|w|WW|W|zzz|z|gggg|GGGG|Do|X|x|k{1,2}|S/g,function(S){switch(S){case"Q":return Math.ceil((k.$M+1)/3);case"Do":return Y.ordinal(k.$D);case"gggg":return k.weekYear();case"GGGG":return k.isoWeekYear();case"wo":return Y.ordinal(k.week(),"W");case"w":case"ww":return g.s(k.week(),S==="w"?1:2,"0");case"W":case"WW":return g.s(k.isoWeek(),S==="W"?1:2,"0");case"k":case"kk":return g.s(String(k.$H===0?24:k.$H),S==="k"?1:2,"0");case"X":return Math.floor(k.$d.getTime()/1e3);case"x":return k.$d.getTime();case"z":return"["+k.offsetName()+"]";case"zzz":return"["+k.offsetName("long")+"]";default:return S}});return i.bind(this)(w)}}})})(xn);var Ea=xn.exports;const La=be(Ea);var ye=function(){var t=d(function(E,l,h,v){for(h=h||{},v=E.length;v--;h[E[v]]=l);return h},"o"),e=[6,8,10,12,13,14,15,16,17,18,20,21,22,23,24,25,26,27,28,29,30,31,33,35,36,38,40],n=[1,26],r=[1,27],a=[1,28],i=[1,29],s=[1,30],k=[1,31],Y=[1,32],g=[1,33],w=[1,34],S=[1,9],C=[1,10],b=[1,11],q=[1,12],y=[1,13],I=[1,14],N=[1,15],H=[1,16],R=[1,19],B=[1,20],J=[1,21],D=[1,22],W=[1,23],x=[1,25],U=[1,35],_={trace:d(function(){},"trace"),yy:{},symbols_:{error:2,start:3,gantt:4,document:5,EOF:6,line:7,SPACE:8,statement:9,NL:10,weekday:11,weekday_monday:12,weekday_tuesday:13,weekday_wednesday:14,weekday_thursday:15,weekday_friday:16,weekday_saturday:17,weekday_sunday:18,weekend:19,weekend_friday:20,weekend_saturday:21,dateFormat:22,inclusiveEndDates:23,topAxis:24,axisFormat:25,tickInterval:26,excludes:27,includes:28,todayMarker:29,title:30,acc_title:31,acc_title_value:32,acc_descr:33,acc_descr_value:34,acc_descr_multiline_value:35,section:36,clickStatement:37,taskTxt:38,taskData:39,click:40,callbackname:41,callbackargs:42,href:43,clickStatementDebug:44,$accept:0,$end:1},terminals_:{2:"error",4:"gantt",6:"EOF",8:"SPACE",10:"NL",12:"weekday_monday",13:"weekday_tuesday",14:"weekday_wednesday",15:"weekday_thursday",16:"weekday_friday",17:"weekday_saturday",18:"weekday_sunday",20:"weekend_friday",21:"weekend_saturday",22:"dateFormat",23:"inclusiveEndDates",24:"topAxis",25:"axisFormat",26:"tickInterval",27:"excludes",28:"includes",29:"todayMarker",30:"title",31:"acc_title",32:"acc_title_value",33:"acc_descr",34:"acc_descr_value",35:"acc_descr_multiline_value",36:"section",38:"taskTxt",39:"taskData",40:"click",41:"callbackname",42:"callbackargs",43:"href"},productions_:[0,[3,3],[5,0],[5,2],[7,2],[7,1],[7,1],[7,1],[11,1],[11,1],[11,1],[11,1],[11,1],[11,1],[11,1],[19,1],[19,1],[9,1],[9,1],[9,1],[9,1],[9,1],[9,1],[9,1],[9,1],[9,1],[9,1],[9,1],[9,2],[9,2],[9,1],[9,1],[9,1],[9,2],[37,2],[37,3],[37,3],[37,4],[37,3],[37,4],[37,2],[44,2],[44,3],[44,3],[44,4],[44,3],[44,4],[44,2]],performAction:d(function(l,h,v,m,F,o,f){var c=o.length-1;switch(F){case 1:return o[c-1];case 2:this.$=[];break;case 3:o[c-1].push(o[c]),this.$=o[c-1];break;case 4:case 5:this.$=o[c];break;case 6:case 7:this.$=[];break;case 8:m.setWeekday("monday");break;case 9:m.setWeekday("tuesday");break;case 10:m.setWeekday("wednesday");break;case 11:m.setWeekday("thursday");break;case 12:m.setWeekday("friday");break;case 13:m.setWeekday("saturday");break;case 14:m.setWeekday("sunday");break;case 15:m.setWeekend("friday");break;case 16:m.setWeekend("saturday");break;case 17:m.setDateFormat(o[c].substr(11)),this.$=o[c].substr(11);break;case 18:m.enableInclusiveEndDates(),this.$=o[c].substr(18);break;case 19:m.TopAxis(),this.$=o[c].substr(8);break;case 20:m.setAxisFormat(o[c].substr(11)),this.$=o[c].substr(11);break;case 21:m.setTickInterval(o[c].substr(13)),this.$=o[c].substr(13);break;case 22:m.setExcludes(o[c].substr(9)),this.$=o[c].substr(9);break;case 23:m.setIncludes(o[c].substr(9)),this.$=o[c].substr(9);break;case 24:m.setTodayMarker(o[c].substr(12)),this.$=o[c].substr(12);break;case 27:m.setDiagramTitle(o[c].substr(6)),this.$=o[c].substr(6);break;case 28:this.$=o[c].trim(),m.setAccTitle(this.$);break;case 29:case 30:this.$=o[c].trim(),m.setAccDescription(this.$);break;case 31:m.addSection(o[c].substr(8)),this.$=o[c].substr(8);break;case 33:m.addTask(o[c-1],o[c]),this.$="task";break;case 34:this.$=o[c-1],m.setClickEvent(o[c-1],o[c],null);break;case 35:this.$=o[c-2],m.setClickEvent(o[c-2],o[c-1],o[c]);break;case 36:this.$=o[c-2],m.setClickEvent(o[c-2],o[c-1],null),m.setLink(o[c-2],o[c]);break;case 37:this.$=o[c-3],m.setClickEvent(o[c-3],o[c-2],o[c-1]),m.setLink(o[c-3],o[c]);break;case 38:this.$=o[c-2],m.setClickEvent(o[c-2],o[c],null),m.setLink(o[c-2],o[c-1]);break;case 39:this.$=o[c-3],m.setClickEvent(o[c-3],o[c-1],o[c]),m.setLink(o[c-3],o[c-2]);break;case 40:this.$=o[c-1],m.setLink(o[c-1],o[c]);break;case 41:case 47:this.$=o[c-1]+" "+o[c];break;case 42:case 43:case 45:this.$=o[c-2]+" "+o[c-1]+" "+o[c];break;case 44:case 46:this.$=o[c-3]+" "+o[c-2]+" "+o[c-1]+" "+o[c];break}},"anonymous"),table:[{3:1,4:[1,2]},{1:[3]},t(e,[2,2],{5:3}),{6:[1,4],7:5,8:[1,6],9:7,10:[1,8],11:17,12:n,13:r,14:a,15:i,16:s,17:k,18:Y,19:18,20:g,21:w,22:S,23:C,24:b,25:q,26:y,27:I,28:N,29:H,30:R,31:B,33:J,35:D,36:W,37:24,38:x,40:U},t(e,[2,7],{1:[2,1]}),t(e,[2,3]),{9:36,11:17,12:n,13:r,14:a,15:i,16:s,17:k,18:Y,19:18,20:g,21:w,22:S,23:C,24:b,25:q,26:y,27:I,28:N,29:H,30:R,31:B,33:J,35:D,36:W,37:24,38:x,40:U},t(e,[2,5]),t(e,[2,6]),t(e,[2,17]),t(e,[2,18]),t(e,[2,19]),t(e,[2,20]),t(e,[2,21]),t(e,[2,22]),t(e,[2,23]),t(e,[2,24]),t(e,[2,25]),t(e,[2,26]),t(e,[2,27]),{32:[1,37]},{34:[1,38]},t(e,[2,30]),t(e,[2,31]),t(e,[2,32]),{39:[1,39]},t(e,[2,8]),t(e,[2,9]),t(e,[2,10]),t(e,[2,11]),t(e,[2,12]),t(e,[2,13]),t(e,[2,14]),t(e,[2,15]),t(e,[2,16]),{41:[1,40],43:[1,41]},t(e,[2,4]),t(e,[2,28]),t(e,[2,29]),t(e,[2,33]),t(e,[2,34],{42:[1,42],43:[1,43]}),t(e,[2,40],{41:[1,44]}),t(e,[2,35],{43:[1,45]}),t(e,[2,36]),t(e,[2,38],{42:[1,46]}),t(e,[2,37]),t(e,[2,39])],defaultActions:{},parseError:d(function(l,h){if(h.recoverable)this.trace(l);else{var v=new Error(l);throw v.hash=h,v}},"parseError"),parse:d(function(l){var h=this,v=[0],m=[],F=[null],o=[],f=this.table,c="",Z=0,V=0,z=2,$=1,G=o.slice.call(arguments,1),j=Object.create(this.lexer),rt={yy:{}};for(var T in this.yy)Object.prototype.hasOwnProperty.call(this.yy,T)&&(rt.yy[T]=this.yy[T]);j.setInput(l,rt.yy),rt.yy.lexer=j,rt.yy.parser=this,typeof j.yylloc>"u"&&(j.yylloc={});var A=j.yylloc;o.push(A);var O=j.options&&j.options.ranges;typeof rt.yy.parseError=="function"?this.parseError=rt.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function u(it){v.length=v.length-2*it,F.length=F.length-it,o.length=o.length-it}d(u,"popStack");function K(){var it;return it=m.pop()||j.lex()||$,typeof it!="number"&&(it instanceof Array&&(m=it,it=m.pop()),it=h.symbols_[it]||it),it}d(K,"lex");for(var L,Q,X,ot,ut={},Rt,ft,Ae,Bt;;){if(Q=v[v.length-1],this.defaultActions[Q]?X=this.defaultActions[Q]:((L===null||typeof L>"u")&&(L=K()),X=f[Q]&&f[Q][L]),typeof X>"u"||!X.length||!X[0]){var ne="";Bt=[];for(Rt in f[Q])this.terminals_[Rt]&&Rt>z&&Bt.push("'"+this.terminals_[Rt]+"'");j.showPosition?ne="Parse error on line "+(Z+1)+`:
                                       `+j.showPosition()+`
                                       Expecting `+Bt.join(", ")+", got '"+(this.terminals_[L]||L)+"'":ne="Parse error on line "+(Z+1)+": Unexpected "+(L==$?"end of input":"'"+(this.terminals_[L]||L)+"'"),this.parseError(ne,{text:j.match,token:this.terminals_[L]||L,line:j.yylineno,loc:A,expected:Bt})}if(X[0]instanceof Array&&X.length>1)throw new Error("Parse Error: multiple actions possible at state: "+Q+", token: "+L);switch(X[0]){case 1:v.push(L),F.push(j.yytext),o.push(j.yylloc),v.push(X[1]),L=null,V=j.yyleng,c=j.yytext,Z=j.yylineno,A=j.yylloc;break;case 2:if(ft=this.productions_[X[1]][1],ut.$=F[F.length-ft],ut._$={first_line:o[o.length-(ft||1)].first_line,last_line:o[o.length-1].last_line,first_column:o[o.length-(ft||1)].first_column,last_column:o[o.length-1].last_column},O&&(ut._$.range=[o[o.length-(ft||1)].range[0],o[o.length-1].range[1]]),ot=this.performAction.apply(ut,[c,V,Z,rt.yy,X[1],F,o].concat(G)),typeof ot<"u")return ot;ft&&(v=v.slice(0,-1*ft*2),F=F.slice(0,-1*ft),o=o.slice(0,-1*ft)),v.push(this.productions_[X[1]][0]),F.push(ut.$),o.push(ut._$),Ae=f[v[v.length-2]][v[v.length-1]],v.push(Ae);break;case 3:return!0}}return!0},"parse")},M=function(){var E={EOF:1,parseError:d(function(h,v){if(this.yy.parser)this.yy.parser.parseError(h,v);else throw new Error(h)},"parseError"),setInput:d(function(l,h){return this.yy=h||this.yy||{},this._input=l,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},"setInput"),input:d(function(){var l=this._input[0];this.yytext+=l,this.yyleng++,this.offset++,this.match+=l,this.matched+=l;var h=l.match(/(?:\r\n?|\n).*/g);return h?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),l},"input"),unput:d(function(l){var h=l.length,v=l.split(/(?:\r\n?|\n)/g);this._input=l+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-h),this.offset-=h;var m=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),v.length-1&&(this.yylineno-=v.length-1);var F=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:v?(v.length===m.length?this.yylloc.first_column:0)+m[m.length-v.length].length-v[0].length:this.yylloc.first_column-h},this.options.ranges&&(this.yylloc.range=[F[0],F[0]+this.yyleng-h]),this.yyleng=this.yytext.length,this},"unput"),more:d(function(){return this._more=!0,this},"more"),reject:d(function(){if(this.options.backtrack_lexer)this._backtrack=!0;else return this.parseError("Lexical error on line "+(this.yylineno+1)+`. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).
                                       `+this.showPosition(),{text:"",token:null,line:this.yylineno});return this},"reject"),less:d(function(l){this.unput(this.match.slice(l))},"less"),pastInput:d(function(){var l=this.matched.substr(0,this.matched.length-this.match.length);return(l.length>20?"...":"")+l.substr(-20).replace(/\n/g,"")},"pastInput"),upcomingInput:d(function(){var l=this.match;return l.length<20&&(l+=this._input.substr(0,20-l.length)),(l.substr(0,20)+(l.length>20?"...":"")).replace(/\n/g,"")},"upcomingInput"),showPosition:d(function(){var l=this.pastInput(),h=new Array(l.length+1).join("-");return l+this.upcomingInput()+`
                                      diff --git a/assets/gitGraph-F2EDSAW4-IXsRUTzt.js b/assets/gitGraph-F2EDSAW4-Df57CYyu.js
                                      similarity index 99%
                                      rename from assets/gitGraph-F2EDSAW4-IXsRUTzt.js
                                      rename to assets/gitGraph-F2EDSAW4-Df57CYyu.js
                                      index faaec17281..764d088551 100644
                                      --- a/assets/gitGraph-F2EDSAW4-IXsRUTzt.js
                                      +++ b/assets/gitGraph-F2EDSAW4-Df57CYyu.js
                                      @@ -1,4 +1,4 @@
                                      -var Ol=Object.defineProperty;var Pl=(n,e,t)=>e in n?Ol(n,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):n[e]=t;var Je=(n,e,t)=>(Pl(n,typeof e!="symbol"?e+"":e,t),t);import{h as yn}from"./app-DBM4OJyw.js";import{bu as $l,bv as Ml,aL as to,be as Dl,aP as Fl,aM as Z,ay as Ul,az as qi,b4 as Gl,b7 as no,b8 as ro,bj as Yi,b5 as Bl,aB as pt,aC as D,aN as Xi,aH as Wl}from"./mermaid.core-DapiNGBY.js";import{k as kt,l as gi,g as Ot,S as jl,w as Vl,x as Hl,c as io,v as K,y as so,m as Kl,z as zl,A as ql,B as Yl,C as Xl,a as ao,d as x,i as ze,h as C,r as oe,f as Ae,D as q}from"./baseUniq-ZJgB7efo.js";import{i as yi,m as S,d as Jl,f as xe,g as St,h as Ti,l as It,e as Ql}from"./basePickBy-BXIHjUx3.js";import{c as te}from"./clone-B3i2nD77.js";var Zl=Object.prototype,eu=Zl.hasOwnProperty,ve=$l(function(n,e){if(Ml(e)||to(e)){Dl(e,kt(e),n);return}for(var t in e)eu.call(e,t)&&Fl(n,t,e[t])});function oo(n,e,t){var r=-1,i=n.length;e<0&&(e=-e>i?0:i+e),t=t>i?i:t,t<0&&(t+=i),i=e>t?0:t-e>>>0,e>>>=0;for(var s=Array(i);++r=iu&&(s=Hl,a=!1,e=new jl(e));e:for(;++i-1:!!i&&so(n,e,t)>-1}function Ji(n,e,t){var r=n==null?0:n.length;if(!r)return-1;var i=0;return so(n,e,i)}var hu="[object RegExp]";function pu(n){return no(n)&&ro(n)==hu}var Qi=Yi&&Yi.isRegExp,qe=Qi?Bl(Qi):pu,mu="Expected a function";function gu(n){if(typeof n!="function")throw new TypeError(mu);return function(){var e=arguments;switch(e.length){case 0:return!n.call(this);case 1:return!n.call(this,e[0]);case 2:return!n.call(this,e[0],e[1]);case 3:return!n.call(this,e[0],e[1],e[2])}return!n.apply(this,e)}}function Pe(n,e){if(n==null)return{};var t=Kl(zl(n),function(r){return[r]});return e=Ot(e),Jl(n,t,function(r,i){return e(r,i[0])})}function Zn(n,e){var t=Z(n)?ql:Yl;return t(n,gu(Ot(e)))}function yu(n,e){var t;return gi(n,function(r,i,s){return t=e(r,i,s),!t}),!!t}function co(n,e,t){var r=Z(n)?Xl:yu;return r(n,Ot(e))}function Ei(n){return n&&n.length?ao(n):[]}function Tu(n,e){return n&&n.length?ao(n,Ot(e)):[]}function ae(n){return typeof n=="object"&&n!==null&&typeof n.$type=="string"}function De(n){return typeof n=="object"&&n!==null&&typeof n.$refText=="string"}function Eu(n){return typeof n=="object"&&n!==null&&typeof n.name=="string"&&typeof n.type=="string"&&typeof n.path=="string"}function Rn(n){return typeof n=="object"&&n!==null&&ae(n.container)&&De(n.reference)&&typeof n.message=="string"}class lo{constructor(){this.subtypes={},this.allSubtypes={}}isInstance(e,t){return ae(e)&&this.isSubtype(e.$type,t)}isSubtype(e,t){if(e===t)return!0;let r=this.subtypes[e];r||(r=this.subtypes[e]={});const i=r[t];if(i!==void 0)return i;{const s=this.computeIsSubtype(e,t);return r[t]=s,s}}getAllSubTypes(e){const t=this.allSubtypes[e];if(t)return t;{const r=this.getAllTypes(),i=[];for(const s of r)this.isSubtype(s,e)&&i.push(s);return this.allSubtypes[e]=i,i}}}function Nt(n){return typeof n=="object"&&n!==null&&Array.isArray(n.content)}function uo(n){return typeof n=="object"&&n!==null&&typeof n.tokenType=="object"}function fo(n){return Nt(n)&&typeof n.fullText=="string"}class ie{constructor(e,t){this.startFn=e,this.nextFn=t}iterator(){const e={state:this.startFn(),next:()=>this.nextFn(e.state),[Symbol.iterator]:()=>e};return e}[Symbol.iterator](){return this.iterator()}isEmpty(){return!!this.iterator().next().done}count(){const e=this.iterator();let t=0,r=e.next();for(;!r.done;)t++,r=e.next();return t}toArray(){const e=[],t=this.iterator();let r;do r=t.next(),r.value!==void 0&&e.push(r.value);while(!r.done);return e}toSet(){return new Set(this)}toMap(e,t){const r=this.map(i=>[e?e(i):i,t?t(i):i]);return new Map(r)}toString(){return this.join()}concat(e){const t=e[Symbol.iterator]();return new ie(()=>({first:this.startFn(),firstDone:!1}),r=>{let i;if(!r.firstDone){do if(i=this.nextFn(r.first),!i.done)return i;while(!i.done);r.firstDone=!0}do if(i=t.next(),!i.done)return i;while(!i.done);return Ne})}join(e=","){const t=this.iterator();let r="",i,s=!1;do i=t.next(),i.done||(s&&(r+=e),r+=vu(i.value)),s=!0;while(!i.done);return r}indexOf(e,t=0){const r=this.iterator();let i=0,s=r.next();for(;!s.done;){if(i>=t&&s.value===e)return i;s=r.next(),i++}return-1}every(e){const t=this.iterator();let r=t.next();for(;!r.done;){if(!e(r.value))return!1;r=t.next()}return!0}some(e){const t=this.iterator();let r=t.next();for(;!r.done;){if(e(r.value))return!0;r=t.next()}return!1}forEach(e){const t=this.iterator();let r=0,i=t.next();for(;!i.done;)e(i.value,r),i=t.next(),r++}map(e){return new ie(this.startFn,t=>{const{done:r,value:i}=this.nextFn(t);return r?Ne:{done:!1,value:e(i)}})}filter(e){return new ie(this.startFn,t=>{let r;do if(r=this.nextFn(t),!r.done&&e(r.value))return r;while(!r.done);return Ne})}nonNullable(){return this.filter(e=>e!=null)}reduce(e,t){const r=this.iterator();let i=t,s=r.next();for(;!s.done;)i===void 0?i=s.value:i=e(i,s.value),s=r.next();return i}reduceRight(e,t){return this.recursiveReduce(this.iterator(),e,t)}recursiveReduce(e,t,r){const i=e.next();if(i.done)return r;const s=this.recursiveReduce(e,t,r);return s===void 0?i.value:t(s,i.value)}find(e){const t=this.iterator();let r=t.next();for(;!r.done;){if(e(r.value))return r.value;r=t.next()}}findIndex(e){const t=this.iterator();let r=0,i=t.next();for(;!i.done;){if(e(i.value))return r;i=t.next(),r++}return-1}includes(e){const t=this.iterator();let r=t.next();for(;!r.done;){if(r.value===e)return!0;r=t.next()}return!1}flatMap(e){return new ie(()=>({this:this.startFn()}),t=>{do{if(t.iterator){const s=t.iterator.next();if(s.done)t.iterator=void 0;else return s}const{done:r,value:i}=this.nextFn(t.this);if(!r){const s=e(i);if(Cn(s))t.iterator=s[Symbol.iterator]();else return{done:!1,value:s}}}while(t.iterator);return Ne})}flat(e){if(e===void 0&&(e=1),e<=0)return this;const t=e>1?this.flat(e-1):this;return new ie(()=>({this:t.startFn()}),r=>{do{if(r.iterator){const a=r.iterator.next();if(a.done)r.iterator=void 0;else return a}const{done:i,value:s}=t.nextFn(r.this);if(!i)if(Cn(s))r.iterator=s[Symbol.iterator]();else return{done:!1,value:s}}while(r.iterator);return Ne})}head(){const t=this.iterator().next();if(!t.done)return t.value}tail(e=1){return new ie(()=>{const t=this.startFn();for(let r=0;r({size:0,state:this.startFn()}),t=>(t.size++,t.size>e?Ne:this.nextFn(t.state)))}distinct(e){const t=new Set;return this.filter(r=>{const i=e?e(r):r;return t.has(i)?!1:(t.add(i),!0)})}exclude(e,t){const r=new Set;for(const i of e){const s=t?t(i):i;r.add(s)}return this.filter(i=>{const s=t?t(i):i;return!r.has(s)})}}function vu(n){return typeof n=="string"?n:typeof n>"u"?"undefined":typeof n.toString=="function"?n.toString():Object.prototype.toString.call(n)}function Cn(n){return!!n&&typeof n[Symbol.iterator]=="function"}const Au=new ie(()=>{},()=>Ne),Ne=Object.freeze({done:!0,value:void 0});function Q(...n){if(n.length===1){const e=n[0];if(e instanceof ie)return e;if(Cn(e))return new ie(()=>e[Symbol.iterator](),t=>t.next());if(typeof e.length=="number")return new ie(()=>({index:0}),t=>t.index1?new ie(()=>({collIndex:0,arrIndex:0}),e=>{do{if(e.iterator){const t=e.iterator.next();if(!t.done)return t;e.iterator=void 0}if(e.array){if(e.arrIndex({iterators:r!=null&&r.includeRoot?[[e][Symbol.iterator]()]:[t(e)[Symbol.iterator]()],pruned:!1}),i=>{for(i.pruned&&(i.iterators.pop(),i.pruned=!1);i.iterators.length>0;){const a=i.iterators[i.iterators.length-1].next();if(a.done)i.iterators.pop();else return i.iterators.push(t(a.value)[Symbol.iterator]()),a}return Ne})}iterator(){const e={state:this.startFn(),next:()=>this.nextFn(e.state),prune:()=>{e.state.pruned=!0},[Symbol.iterator]:()=>e};return e}}var br;(function(n){function e(s){return s.reduce((a,o)=>a+o,0)}n.sum=e;function t(s){return s.reduce((a,o)=>a*o,0)}n.product=t;function r(s){return s.reduce((a,o)=>Math.min(a,o))}n.min=r;function i(s){return s.reduce((a,o)=>Math.max(a,o))}n.max=i})(br||(br={}));function Or(n){return new vi(n,e=>Nt(e)?e.content:[],{includeRoot:!0})}function Ru(n,e){for(;n.container;)if(n=n.container,n===e)return!0;return!1}function Pr(n){return{start:{character:n.startColumn-1,line:n.startLine-1},end:{character:n.endColumn,line:n.endLine-1}}}function _n(n){if(!n)return;const{offset:e,end:t,range:r}=n;return{range:r,offset:e,end:t,length:t-e}}var Ze;(function(n){n[n.Before=0]="Before",n[n.After=1]="After",n[n.OverlapFront=2]="OverlapFront",n[n.OverlapBack=3]="OverlapBack",n[n.Inside=4]="Inside"})(Ze||(Ze={}));function ku(n,e){if(n.end.linee.end.line||n.start.line===e.end.line&&n.start.character>e.end.character)return Ze.After;const t=n.start.line>e.start.line||n.start.line===e.start.line&&n.start.character>=e.start.character,r=n.end.lineZe.After}const Iu=/^[\w\p{L}]$/u;function Nu(n,e){if(n){const t=xu(n,!0);if(t&&Zi(t,e))return t;if(fo(n)){const r=n.content.findIndex(i=>!i.hidden);for(let i=r-1;i>=0;i--){const s=n.content[i];if(Zi(s,e))return s}}}}function Zi(n,e){return uo(n)&&e.includes(n.tokenType.name)}function xu(n,e=!0){for(;n.container;){const t=n.container;let r=t.content.indexOf(n);for(;r>0;){r--;const i=t.content[r];if(e||!i.hidden)return i}n=t}}class ho extends Error{constructor(e,t){super(e?`${t} at ${e.range.start.line}:${e.range.start.character}`:t)}}function er(n){throw new Error("Error! The input value was not handled.")}const Tr="AbstractRule",Er="AbstractType",es="Condition",Cu="TypeDefinition",ts="ValueLiteral",po="AbstractElement";function _u(n){return M.isInstance(n,po)}const wu="ArrayLiteral",Lu="ArrayType",mo="BooleanLiteral";function bu(n){return M.isInstance(n,mo)}const go="Conjunction";function Ou(n){return M.isInstance(n,go)}const yo="Disjunction";function Pu(n){return M.isInstance(n,yo)}const $u="Grammar",To="InferredType";function Eo(n){return M.isInstance(n,To)}const vo="Interface";function Ao(n){return M.isInstance(n,vo)}const Ro="Negation";function Mu(n){return M.isInstance(n,Ro)}const Du="NumberLiteral",Fu="Parameter",ko="ParameterReference";function Uu(n){return M.isInstance(n,ko)}const So="ParserRule";function Ce(n){return M.isInstance(n,So)}const Gu="ReferenceType",Bu="ReturnType";function Wu(n){return M.isInstance(n,Bu)}const Io="SimpleType";function ju(n){return M.isInstance(n,Io)}const Vu="StringLiteral",$r="TerminalRule";function mt(n){return M.isInstance(n,$r)}const No="Type";function xo(n){return M.isInstance(n,No)}const Hu="UnionType",Co="Action";function tr(n){return M.isInstance(n,Co)}const _o="Alternatives";function wo(n){return M.isInstance(n,_o)}const Lo="Assignment";function lt(n){return M.isInstance(n,Lo)}const bo="CharacterRange";function Ku(n){return M.isInstance(n,bo)}const Oo="CrossReference";function Ai(n){return M.isInstance(n,Oo)}const Po="EndOfFile";function zu(n){return M.isInstance(n,Po)}const $o="Group";function Ri(n){return M.isInstance(n,$o)}const Mo="Keyword";function ut(n){return M.isInstance(n,Mo)}const Do="NegatedToken";function qu(n){return M.isInstance(n,Do)}const Fo="RegexToken";function Yu(n){return M.isInstance(n,Fo)}const Uo="RuleCall";function dt(n){return M.isInstance(n,Uo)}const Go="TerminalAlternatives";function Xu(n){return M.isInstance(n,Go)}const Bo="TerminalGroup";function Ju(n){return M.isInstance(n,Bo)}const Wo="TerminalRuleCall";function Qu(n){return M.isInstance(n,Wo)}const jo="UnorderedGroup";function Vo(n){return M.isInstance(n,jo)}const Ho="UntilToken";function Zu(n){return M.isInstance(n,Ho)}const Ko="Wildcard";function ed(n){return M.isInstance(n,Ko)}class zo extends lo{getAllTypes(){return["AbstractElement","AbstractRule","AbstractType","Action","Alternatives","ArrayLiteral","ArrayType","Assignment","BooleanLiteral","CharacterRange","Condition","Conjunction","CrossReference","Disjunction","EndOfFile","Grammar","GrammarImport","Group","InferredType","Interface","Keyword","NamedArgument","NegatedToken","Negation","NumberLiteral","Parameter","ParameterReference","ParserRule","ReferenceType","RegexToken","ReturnType","RuleCall","SimpleType","StringLiteral","TerminalAlternatives","TerminalGroup","TerminalRule","TerminalRuleCall","Type","TypeAttribute","TypeDefinition","UnionType","UnorderedGroup","UntilToken","ValueLiteral","Wildcard"]}computeIsSubtype(e,t){switch(e){case Co:case _o:case Lo:case bo:case Oo:case Po:case $o:case Mo:case Do:case Fo:case Uo:case Go:case Bo:case Wo:case jo:case Ho:case Ko:return this.isSubtype(po,t);case wu:case Du:case Vu:return this.isSubtype(ts,t);case Lu:case Gu:case Io:case Hu:return this.isSubtype(Cu,t);case mo:return this.isSubtype(es,t)||this.isSubtype(ts,t);case go:case yo:case Ro:case ko:return this.isSubtype(es,t);case To:case vo:case No:return this.isSubtype(Er,t);case So:return this.isSubtype(Tr,t)||this.isSubtype(Er,t);case $r:return this.isSubtype(Tr,t);default:return!1}}getReferenceType(e){const t=`${e.container.$type}:${e.property}`;switch(t){case"Action:type":case"CrossReference:type":case"Interface:superTypes":case"ParserRule:returnType":case"SimpleType:typeRef":return Er;case"Grammar:hiddenTokens":case"ParserRule:hiddenTokens":case"RuleCall:rule":return Tr;case"Grammar:usedGrammars":return $u;case"NamedArgument:parameter":case"ParameterReference:parameter":return Fu;case"TerminalRuleCall:rule":return $r;default:throw new Error(`${t} is not a valid reference id.`)}}getTypeMetaData(e){switch(e){case"AbstractElement":return{name:"AbstractElement",properties:[{name:"cardinality"},{name:"lookahead"}]};case"ArrayLiteral":return{name:"ArrayLiteral",properties:[{name:"elements",defaultValue:[]}]};case"ArrayType":return{name:"ArrayType",properties:[{name:"elementType"}]};case"BooleanLiteral":return{name:"BooleanLiteral",properties:[{name:"true",defaultValue:!1}]};case"Conjunction":return{name:"Conjunction",properties:[{name:"left"},{name:"right"}]};case"Disjunction":return{name:"Disjunction",properties:[{name:"left"},{name:"right"}]};case"Grammar":return{name:"Grammar",properties:[{name:"definesHiddenTokens",defaultValue:!1},{name:"hiddenTokens",defaultValue:[]},{name:"imports",defaultValue:[]},{name:"interfaces",defaultValue:[]},{name:"isDeclared",defaultValue:!1},{name:"name"},{name:"rules",defaultValue:[]},{name:"types",defaultValue:[]},{name:"usedGrammars",defaultValue:[]}]};case"GrammarImport":return{name:"GrammarImport",properties:[{name:"path"}]};case"InferredType":return{name:"InferredType",properties:[{name:"name"}]};case"Interface":return{name:"Interface",properties:[{name:"attributes",defaultValue:[]},{name:"name"},{name:"superTypes",defaultValue:[]}]};case"NamedArgument":return{name:"NamedArgument",properties:[{name:"calledByName",defaultValue:!1},{name:"parameter"},{name:"value"}]};case"Negation":return{name:"Negation",properties:[{name:"value"}]};case"NumberLiteral":return{name:"NumberLiteral",properties:[{name:"value"}]};case"Parameter":return{name:"Parameter",properties:[{name:"name"}]};case"ParameterReference":return{name:"ParameterReference",properties:[{name:"parameter"}]};case"ParserRule":return{name:"ParserRule",properties:[{name:"dataType"},{name:"definesHiddenTokens",defaultValue:!1},{name:"definition"},{name:"entry",defaultValue:!1},{name:"fragment",defaultValue:!1},{name:"hiddenTokens",defaultValue:[]},{name:"inferredType"},{name:"name"},{name:"parameters",defaultValue:[]},{name:"returnType"},{name:"wildcard",defaultValue:!1}]};case"ReferenceType":return{name:"ReferenceType",properties:[{name:"referenceType"}]};case"ReturnType":return{name:"ReturnType",properties:[{name:"name"}]};case"SimpleType":return{name:"SimpleType",properties:[{name:"primitiveType"},{name:"stringType"},{name:"typeRef"}]};case"StringLiteral":return{name:"StringLiteral",properties:[{name:"value"}]};case"TerminalRule":return{name:"TerminalRule",properties:[{name:"definition"},{name:"fragment",defaultValue:!1},{name:"hidden",defaultValue:!1},{name:"name"},{name:"type"}]};case"Type":return{name:"Type",properties:[{name:"name"},{name:"type"}]};case"TypeAttribute":return{name:"TypeAttribute",properties:[{name:"defaultValue"},{name:"isOptional",defaultValue:!1},{name:"name"},{name:"type"}]};case"UnionType":return{name:"UnionType",properties:[{name:"types",defaultValue:[]}]};case"Action":return{name:"Action",properties:[{name:"cardinality"},{name:"feature"},{name:"inferredType"},{name:"lookahead"},{name:"operator"},{name:"type"}]};case"Alternatives":return{name:"Alternatives",properties:[{name:"cardinality"},{name:"elements",defaultValue:[]},{name:"lookahead"}]};case"Assignment":return{name:"Assignment",properties:[{name:"cardinality"},{name:"feature"},{name:"lookahead"},{name:"operator"},{name:"terminal"}]};case"CharacterRange":return{name:"CharacterRange",properties:[{name:"cardinality"},{name:"left"},{name:"lookahead"},{name:"right"}]};case"CrossReference":return{name:"CrossReference",properties:[{name:"cardinality"},{name:"deprecatedSyntax",defaultValue:!1},{name:"lookahead"},{name:"terminal"},{name:"type"}]};case"EndOfFile":return{name:"EndOfFile",properties:[{name:"cardinality"},{name:"lookahead"}]};case"Group":return{name:"Group",properties:[{name:"cardinality"},{name:"elements",defaultValue:[]},{name:"guardCondition"},{name:"lookahead"}]};case"Keyword":return{name:"Keyword",properties:[{name:"cardinality"},{name:"lookahead"},{name:"value"}]};case"NegatedToken":return{name:"NegatedToken",properties:[{name:"cardinality"},{name:"lookahead"},{name:"terminal"}]};case"RegexToken":return{name:"RegexToken",properties:[{name:"cardinality"},{name:"lookahead"},{name:"regex"}]};case"RuleCall":return{name:"RuleCall",properties:[{name:"arguments",defaultValue:[]},{name:"cardinality"},{name:"lookahead"},{name:"rule"}]};case"TerminalAlternatives":return{name:"TerminalAlternatives",properties:[{name:"cardinality"},{name:"elements",defaultValue:[]},{name:"lookahead"}]};case"TerminalGroup":return{name:"TerminalGroup",properties:[{name:"cardinality"},{name:"elements",defaultValue:[]},{name:"lookahead"}]};case"TerminalRuleCall":return{name:"TerminalRuleCall",properties:[{name:"cardinality"},{name:"lookahead"},{name:"rule"}]};case"UnorderedGroup":return{name:"UnorderedGroup",properties:[{name:"cardinality"},{name:"elements",defaultValue:[]},{name:"lookahead"}]};case"UntilToken":return{name:"UntilToken",properties:[{name:"cardinality"},{name:"lookahead"},{name:"terminal"}]};case"Wildcard":return{name:"Wildcard",properties:[{name:"cardinality"},{name:"lookahead"}]};default:return{name:e,properties:[]}}}}const M=new zo;function td(n){for(const[e,t]of Object.entries(n))e.startsWith("$")||(Array.isArray(t)?t.forEach((r,i)=>{ae(r)&&(r.$container=n,r.$containerProperty=e,r.$containerIndex=i)}):ae(t)&&(t.$container=n,t.$containerProperty=e))}function nr(n,e){let t=n;for(;t;){if(e(t))return t;t=t.$container}}function Fe(n){const t=nd(n).$document;if(!t)throw new Error("AST node has no document.");return t}function nd(n){for(;n.$container;)n=n.$container;return n}function ki(n,e){if(!n)throw new Error("Node must be an AstNode.");const t=e==null?void 0:e.range;return new ie(()=>({keys:Object.keys(n),keyIndex:0,arrayIndex:0}),r=>{for(;r.keyIndexki(t,e))}function At(n,e){if(!n)throw new Error("Root node must be an AstNode.");return new vi(n,t=>ki(t,e),{includeRoot:!0})}function ns(n,e){var t;if(!e)return!0;const r=(t=n.$cstNode)===null||t===void 0?void 0:t.range;return r?Su(r,e):!1}function qo(n){return new ie(()=>({keys:Object.keys(n),keyIndex:0,arrayIndex:0}),e=>{for(;e.keyIndexe in n?Ol(n,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):n[e]=t;var Je=(n,e,t)=>(Pl(n,typeof e!="symbol"?e+"":e,t),t);import{h as yn}from"./app-D7uBbsY3.js";import{bu as $l,bv as Ml,aL as to,be as Dl,aP as Fl,aM as Z,ay as Ul,az as qi,b4 as Gl,b7 as no,b8 as ro,bj as Yi,b5 as Bl,aB as pt,aC as D,aN as Xi,aH as Wl}from"./mermaid.core-D8igZDel.js";import{k as kt,l as gi,g as Ot,S as jl,w as Vl,x as Hl,c as io,v as K,y as so,m as Kl,z as zl,A as ql,B as Yl,C as Xl,a as ao,d as x,i as ze,h as C,r as oe,f as Ae,D as q}from"./baseUniq-D0lZO5yp.js";import{i as yi,m as S,d as Jl,f as xe,g as St,h as Ti,l as It,e as Ql}from"./basePickBy-DpnmgMOi.js";import{c as te}from"./clone-DWnk59eF.js";var Zl=Object.prototype,eu=Zl.hasOwnProperty,ve=$l(function(n,e){if(Ml(e)||to(e)){Dl(e,kt(e),n);return}for(var t in e)eu.call(e,t)&&Fl(n,t,e[t])});function oo(n,e,t){var r=-1,i=n.length;e<0&&(e=-e>i?0:i+e),t=t>i?i:t,t<0&&(t+=i),i=e>t?0:t-e>>>0,e>>>=0;for(var s=Array(i);++r=iu&&(s=Hl,a=!1,e=new jl(e));e:for(;++i-1:!!i&&so(n,e,t)>-1}function Ji(n,e,t){var r=n==null?0:n.length;if(!r)return-1;var i=0;return so(n,e,i)}var hu="[object RegExp]";function pu(n){return no(n)&&ro(n)==hu}var Qi=Yi&&Yi.isRegExp,qe=Qi?Bl(Qi):pu,mu="Expected a function";function gu(n){if(typeof n!="function")throw new TypeError(mu);return function(){var e=arguments;switch(e.length){case 0:return!n.call(this);case 1:return!n.call(this,e[0]);case 2:return!n.call(this,e[0],e[1]);case 3:return!n.call(this,e[0],e[1],e[2])}return!n.apply(this,e)}}function Pe(n,e){if(n==null)return{};var t=Kl(zl(n),function(r){return[r]});return e=Ot(e),Jl(n,t,function(r,i){return e(r,i[0])})}function Zn(n,e){var t=Z(n)?ql:Yl;return t(n,gu(Ot(e)))}function yu(n,e){var t;return gi(n,function(r,i,s){return t=e(r,i,s),!t}),!!t}function co(n,e,t){var r=Z(n)?Xl:yu;return r(n,Ot(e))}function Ei(n){return n&&n.length?ao(n):[]}function Tu(n,e){return n&&n.length?ao(n,Ot(e)):[]}function ae(n){return typeof n=="object"&&n!==null&&typeof n.$type=="string"}function De(n){return typeof n=="object"&&n!==null&&typeof n.$refText=="string"}function Eu(n){return typeof n=="object"&&n!==null&&typeof n.name=="string"&&typeof n.type=="string"&&typeof n.path=="string"}function Rn(n){return typeof n=="object"&&n!==null&&ae(n.container)&&De(n.reference)&&typeof n.message=="string"}class lo{constructor(){this.subtypes={},this.allSubtypes={}}isInstance(e,t){return ae(e)&&this.isSubtype(e.$type,t)}isSubtype(e,t){if(e===t)return!0;let r=this.subtypes[e];r||(r=this.subtypes[e]={});const i=r[t];if(i!==void 0)return i;{const s=this.computeIsSubtype(e,t);return r[t]=s,s}}getAllSubTypes(e){const t=this.allSubtypes[e];if(t)return t;{const r=this.getAllTypes(),i=[];for(const s of r)this.isSubtype(s,e)&&i.push(s);return this.allSubtypes[e]=i,i}}}function Nt(n){return typeof n=="object"&&n!==null&&Array.isArray(n.content)}function uo(n){return typeof n=="object"&&n!==null&&typeof n.tokenType=="object"}function fo(n){return Nt(n)&&typeof n.fullText=="string"}class ie{constructor(e,t){this.startFn=e,this.nextFn=t}iterator(){const e={state:this.startFn(),next:()=>this.nextFn(e.state),[Symbol.iterator]:()=>e};return e}[Symbol.iterator](){return this.iterator()}isEmpty(){return!!this.iterator().next().done}count(){const e=this.iterator();let t=0,r=e.next();for(;!r.done;)t++,r=e.next();return t}toArray(){const e=[],t=this.iterator();let r;do r=t.next(),r.value!==void 0&&e.push(r.value);while(!r.done);return e}toSet(){return new Set(this)}toMap(e,t){const r=this.map(i=>[e?e(i):i,t?t(i):i]);return new Map(r)}toString(){return this.join()}concat(e){const t=e[Symbol.iterator]();return new ie(()=>({first:this.startFn(),firstDone:!1}),r=>{let i;if(!r.firstDone){do if(i=this.nextFn(r.first),!i.done)return i;while(!i.done);r.firstDone=!0}do if(i=t.next(),!i.done)return i;while(!i.done);return Ne})}join(e=","){const t=this.iterator();let r="",i,s=!1;do i=t.next(),i.done||(s&&(r+=e),r+=vu(i.value)),s=!0;while(!i.done);return r}indexOf(e,t=0){const r=this.iterator();let i=0,s=r.next();for(;!s.done;){if(i>=t&&s.value===e)return i;s=r.next(),i++}return-1}every(e){const t=this.iterator();let r=t.next();for(;!r.done;){if(!e(r.value))return!1;r=t.next()}return!0}some(e){const t=this.iterator();let r=t.next();for(;!r.done;){if(e(r.value))return!0;r=t.next()}return!1}forEach(e){const t=this.iterator();let r=0,i=t.next();for(;!i.done;)e(i.value,r),i=t.next(),r++}map(e){return new ie(this.startFn,t=>{const{done:r,value:i}=this.nextFn(t);return r?Ne:{done:!1,value:e(i)}})}filter(e){return new ie(this.startFn,t=>{let r;do if(r=this.nextFn(t),!r.done&&e(r.value))return r;while(!r.done);return Ne})}nonNullable(){return this.filter(e=>e!=null)}reduce(e,t){const r=this.iterator();let i=t,s=r.next();for(;!s.done;)i===void 0?i=s.value:i=e(i,s.value),s=r.next();return i}reduceRight(e,t){return this.recursiveReduce(this.iterator(),e,t)}recursiveReduce(e,t,r){const i=e.next();if(i.done)return r;const s=this.recursiveReduce(e,t,r);return s===void 0?i.value:t(s,i.value)}find(e){const t=this.iterator();let r=t.next();for(;!r.done;){if(e(r.value))return r.value;r=t.next()}}findIndex(e){const t=this.iterator();let r=0,i=t.next();for(;!i.done;){if(e(i.value))return r;i=t.next(),r++}return-1}includes(e){const t=this.iterator();let r=t.next();for(;!r.done;){if(r.value===e)return!0;r=t.next()}return!1}flatMap(e){return new ie(()=>({this:this.startFn()}),t=>{do{if(t.iterator){const s=t.iterator.next();if(s.done)t.iterator=void 0;else return s}const{done:r,value:i}=this.nextFn(t.this);if(!r){const s=e(i);if(Cn(s))t.iterator=s[Symbol.iterator]();else return{done:!1,value:s}}}while(t.iterator);return Ne})}flat(e){if(e===void 0&&(e=1),e<=0)return this;const t=e>1?this.flat(e-1):this;return new ie(()=>({this:t.startFn()}),r=>{do{if(r.iterator){const a=r.iterator.next();if(a.done)r.iterator=void 0;else return a}const{done:i,value:s}=t.nextFn(r.this);if(!i)if(Cn(s))r.iterator=s[Symbol.iterator]();else return{done:!1,value:s}}while(r.iterator);return Ne})}head(){const t=this.iterator().next();if(!t.done)return t.value}tail(e=1){return new ie(()=>{const t=this.startFn();for(let r=0;r({size:0,state:this.startFn()}),t=>(t.size++,t.size>e?Ne:this.nextFn(t.state)))}distinct(e){const t=new Set;return this.filter(r=>{const i=e?e(r):r;return t.has(i)?!1:(t.add(i),!0)})}exclude(e,t){const r=new Set;for(const i of e){const s=t?t(i):i;r.add(s)}return this.filter(i=>{const s=t?t(i):i;return!r.has(s)})}}function vu(n){return typeof n=="string"?n:typeof n>"u"?"undefined":typeof n.toString=="function"?n.toString():Object.prototype.toString.call(n)}function Cn(n){return!!n&&typeof n[Symbol.iterator]=="function"}const Au=new ie(()=>{},()=>Ne),Ne=Object.freeze({done:!0,value:void 0});function Q(...n){if(n.length===1){const e=n[0];if(e instanceof ie)return e;if(Cn(e))return new ie(()=>e[Symbol.iterator](),t=>t.next());if(typeof e.length=="number")return new ie(()=>({index:0}),t=>t.index1?new ie(()=>({collIndex:0,arrIndex:0}),e=>{do{if(e.iterator){const t=e.iterator.next();if(!t.done)return t;e.iterator=void 0}if(e.array){if(e.arrIndex({iterators:r!=null&&r.includeRoot?[[e][Symbol.iterator]()]:[t(e)[Symbol.iterator]()],pruned:!1}),i=>{for(i.pruned&&(i.iterators.pop(),i.pruned=!1);i.iterators.length>0;){const a=i.iterators[i.iterators.length-1].next();if(a.done)i.iterators.pop();else return i.iterators.push(t(a.value)[Symbol.iterator]()),a}return Ne})}iterator(){const e={state:this.startFn(),next:()=>this.nextFn(e.state),prune:()=>{e.state.pruned=!0},[Symbol.iterator]:()=>e};return e}}var br;(function(n){function e(s){return s.reduce((a,o)=>a+o,0)}n.sum=e;function t(s){return s.reduce((a,o)=>a*o,0)}n.product=t;function r(s){return s.reduce((a,o)=>Math.min(a,o))}n.min=r;function i(s){return s.reduce((a,o)=>Math.max(a,o))}n.max=i})(br||(br={}));function Or(n){return new vi(n,e=>Nt(e)?e.content:[],{includeRoot:!0})}function Ru(n,e){for(;n.container;)if(n=n.container,n===e)return!0;return!1}function Pr(n){return{start:{character:n.startColumn-1,line:n.startLine-1},end:{character:n.endColumn,line:n.endLine-1}}}function _n(n){if(!n)return;const{offset:e,end:t,range:r}=n;return{range:r,offset:e,end:t,length:t-e}}var Ze;(function(n){n[n.Before=0]="Before",n[n.After=1]="After",n[n.OverlapFront=2]="OverlapFront",n[n.OverlapBack=3]="OverlapBack",n[n.Inside=4]="Inside"})(Ze||(Ze={}));function ku(n,e){if(n.end.linee.end.line||n.start.line===e.end.line&&n.start.character>e.end.character)return Ze.After;const t=n.start.line>e.start.line||n.start.line===e.start.line&&n.start.character>=e.start.character,r=n.end.lineZe.After}const Iu=/^[\w\p{L}]$/u;function Nu(n,e){if(n){const t=xu(n,!0);if(t&&Zi(t,e))return t;if(fo(n)){const r=n.content.findIndex(i=>!i.hidden);for(let i=r-1;i>=0;i--){const s=n.content[i];if(Zi(s,e))return s}}}}function Zi(n,e){return uo(n)&&e.includes(n.tokenType.name)}function xu(n,e=!0){for(;n.container;){const t=n.container;let r=t.content.indexOf(n);for(;r>0;){r--;const i=t.content[r];if(e||!i.hidden)return i}n=t}}class ho extends Error{constructor(e,t){super(e?`${t} at ${e.range.start.line}:${e.range.start.character}`:t)}}function er(n){throw new Error("Error! The input value was not handled.")}const Tr="AbstractRule",Er="AbstractType",es="Condition",Cu="TypeDefinition",ts="ValueLiteral",po="AbstractElement";function _u(n){return M.isInstance(n,po)}const wu="ArrayLiteral",Lu="ArrayType",mo="BooleanLiteral";function bu(n){return M.isInstance(n,mo)}const go="Conjunction";function Ou(n){return M.isInstance(n,go)}const yo="Disjunction";function Pu(n){return M.isInstance(n,yo)}const $u="Grammar",To="InferredType";function Eo(n){return M.isInstance(n,To)}const vo="Interface";function Ao(n){return M.isInstance(n,vo)}const Ro="Negation";function Mu(n){return M.isInstance(n,Ro)}const Du="NumberLiteral",Fu="Parameter",ko="ParameterReference";function Uu(n){return M.isInstance(n,ko)}const So="ParserRule";function Ce(n){return M.isInstance(n,So)}const Gu="ReferenceType",Bu="ReturnType";function Wu(n){return M.isInstance(n,Bu)}const Io="SimpleType";function ju(n){return M.isInstance(n,Io)}const Vu="StringLiteral",$r="TerminalRule";function mt(n){return M.isInstance(n,$r)}const No="Type";function xo(n){return M.isInstance(n,No)}const Hu="UnionType",Co="Action";function tr(n){return M.isInstance(n,Co)}const _o="Alternatives";function wo(n){return M.isInstance(n,_o)}const Lo="Assignment";function lt(n){return M.isInstance(n,Lo)}const bo="CharacterRange";function Ku(n){return M.isInstance(n,bo)}const Oo="CrossReference";function Ai(n){return M.isInstance(n,Oo)}const Po="EndOfFile";function zu(n){return M.isInstance(n,Po)}const $o="Group";function Ri(n){return M.isInstance(n,$o)}const Mo="Keyword";function ut(n){return M.isInstance(n,Mo)}const Do="NegatedToken";function qu(n){return M.isInstance(n,Do)}const Fo="RegexToken";function Yu(n){return M.isInstance(n,Fo)}const Uo="RuleCall";function dt(n){return M.isInstance(n,Uo)}const Go="TerminalAlternatives";function Xu(n){return M.isInstance(n,Go)}const Bo="TerminalGroup";function Ju(n){return M.isInstance(n,Bo)}const Wo="TerminalRuleCall";function Qu(n){return M.isInstance(n,Wo)}const jo="UnorderedGroup";function Vo(n){return M.isInstance(n,jo)}const Ho="UntilToken";function Zu(n){return M.isInstance(n,Ho)}const Ko="Wildcard";function ed(n){return M.isInstance(n,Ko)}class zo extends lo{getAllTypes(){return["AbstractElement","AbstractRule","AbstractType","Action","Alternatives","ArrayLiteral","ArrayType","Assignment","BooleanLiteral","CharacterRange","Condition","Conjunction","CrossReference","Disjunction","EndOfFile","Grammar","GrammarImport","Group","InferredType","Interface","Keyword","NamedArgument","NegatedToken","Negation","NumberLiteral","Parameter","ParameterReference","ParserRule","ReferenceType","RegexToken","ReturnType","RuleCall","SimpleType","StringLiteral","TerminalAlternatives","TerminalGroup","TerminalRule","TerminalRuleCall","Type","TypeAttribute","TypeDefinition","UnionType","UnorderedGroup","UntilToken","ValueLiteral","Wildcard"]}computeIsSubtype(e,t){switch(e){case Co:case _o:case Lo:case bo:case Oo:case Po:case $o:case Mo:case Do:case Fo:case Uo:case Go:case Bo:case Wo:case jo:case Ho:case Ko:return this.isSubtype(po,t);case wu:case Du:case Vu:return this.isSubtype(ts,t);case Lu:case Gu:case Io:case Hu:return this.isSubtype(Cu,t);case mo:return this.isSubtype(es,t)||this.isSubtype(ts,t);case go:case yo:case Ro:case ko:return this.isSubtype(es,t);case To:case vo:case No:return this.isSubtype(Er,t);case So:return this.isSubtype(Tr,t)||this.isSubtype(Er,t);case $r:return this.isSubtype(Tr,t);default:return!1}}getReferenceType(e){const t=`${e.container.$type}:${e.property}`;switch(t){case"Action:type":case"CrossReference:type":case"Interface:superTypes":case"ParserRule:returnType":case"SimpleType:typeRef":return Er;case"Grammar:hiddenTokens":case"ParserRule:hiddenTokens":case"RuleCall:rule":return Tr;case"Grammar:usedGrammars":return $u;case"NamedArgument:parameter":case"ParameterReference:parameter":return Fu;case"TerminalRuleCall:rule":return $r;default:throw new Error(`${t} is not a valid reference id.`)}}getTypeMetaData(e){switch(e){case"AbstractElement":return{name:"AbstractElement",properties:[{name:"cardinality"},{name:"lookahead"}]};case"ArrayLiteral":return{name:"ArrayLiteral",properties:[{name:"elements",defaultValue:[]}]};case"ArrayType":return{name:"ArrayType",properties:[{name:"elementType"}]};case"BooleanLiteral":return{name:"BooleanLiteral",properties:[{name:"true",defaultValue:!1}]};case"Conjunction":return{name:"Conjunction",properties:[{name:"left"},{name:"right"}]};case"Disjunction":return{name:"Disjunction",properties:[{name:"left"},{name:"right"}]};case"Grammar":return{name:"Grammar",properties:[{name:"definesHiddenTokens",defaultValue:!1},{name:"hiddenTokens",defaultValue:[]},{name:"imports",defaultValue:[]},{name:"interfaces",defaultValue:[]},{name:"isDeclared",defaultValue:!1},{name:"name"},{name:"rules",defaultValue:[]},{name:"types",defaultValue:[]},{name:"usedGrammars",defaultValue:[]}]};case"GrammarImport":return{name:"GrammarImport",properties:[{name:"path"}]};case"InferredType":return{name:"InferredType",properties:[{name:"name"}]};case"Interface":return{name:"Interface",properties:[{name:"attributes",defaultValue:[]},{name:"name"},{name:"superTypes",defaultValue:[]}]};case"NamedArgument":return{name:"NamedArgument",properties:[{name:"calledByName",defaultValue:!1},{name:"parameter"},{name:"value"}]};case"Negation":return{name:"Negation",properties:[{name:"value"}]};case"NumberLiteral":return{name:"NumberLiteral",properties:[{name:"value"}]};case"Parameter":return{name:"Parameter",properties:[{name:"name"}]};case"ParameterReference":return{name:"ParameterReference",properties:[{name:"parameter"}]};case"ParserRule":return{name:"ParserRule",properties:[{name:"dataType"},{name:"definesHiddenTokens",defaultValue:!1},{name:"definition"},{name:"entry",defaultValue:!1},{name:"fragment",defaultValue:!1},{name:"hiddenTokens",defaultValue:[]},{name:"inferredType"},{name:"name"},{name:"parameters",defaultValue:[]},{name:"returnType"},{name:"wildcard",defaultValue:!1}]};case"ReferenceType":return{name:"ReferenceType",properties:[{name:"referenceType"}]};case"ReturnType":return{name:"ReturnType",properties:[{name:"name"}]};case"SimpleType":return{name:"SimpleType",properties:[{name:"primitiveType"},{name:"stringType"},{name:"typeRef"}]};case"StringLiteral":return{name:"StringLiteral",properties:[{name:"value"}]};case"TerminalRule":return{name:"TerminalRule",properties:[{name:"definition"},{name:"fragment",defaultValue:!1},{name:"hidden",defaultValue:!1},{name:"name"},{name:"type"}]};case"Type":return{name:"Type",properties:[{name:"name"},{name:"type"}]};case"TypeAttribute":return{name:"TypeAttribute",properties:[{name:"defaultValue"},{name:"isOptional",defaultValue:!1},{name:"name"},{name:"type"}]};case"UnionType":return{name:"UnionType",properties:[{name:"types",defaultValue:[]}]};case"Action":return{name:"Action",properties:[{name:"cardinality"},{name:"feature"},{name:"inferredType"},{name:"lookahead"},{name:"operator"},{name:"type"}]};case"Alternatives":return{name:"Alternatives",properties:[{name:"cardinality"},{name:"elements",defaultValue:[]},{name:"lookahead"}]};case"Assignment":return{name:"Assignment",properties:[{name:"cardinality"},{name:"feature"},{name:"lookahead"},{name:"operator"},{name:"terminal"}]};case"CharacterRange":return{name:"CharacterRange",properties:[{name:"cardinality"},{name:"left"},{name:"lookahead"},{name:"right"}]};case"CrossReference":return{name:"CrossReference",properties:[{name:"cardinality"},{name:"deprecatedSyntax",defaultValue:!1},{name:"lookahead"},{name:"terminal"},{name:"type"}]};case"EndOfFile":return{name:"EndOfFile",properties:[{name:"cardinality"},{name:"lookahead"}]};case"Group":return{name:"Group",properties:[{name:"cardinality"},{name:"elements",defaultValue:[]},{name:"guardCondition"},{name:"lookahead"}]};case"Keyword":return{name:"Keyword",properties:[{name:"cardinality"},{name:"lookahead"},{name:"value"}]};case"NegatedToken":return{name:"NegatedToken",properties:[{name:"cardinality"},{name:"lookahead"},{name:"terminal"}]};case"RegexToken":return{name:"RegexToken",properties:[{name:"cardinality"},{name:"lookahead"},{name:"regex"}]};case"RuleCall":return{name:"RuleCall",properties:[{name:"arguments",defaultValue:[]},{name:"cardinality"},{name:"lookahead"},{name:"rule"}]};case"TerminalAlternatives":return{name:"TerminalAlternatives",properties:[{name:"cardinality"},{name:"elements",defaultValue:[]},{name:"lookahead"}]};case"TerminalGroup":return{name:"TerminalGroup",properties:[{name:"cardinality"},{name:"elements",defaultValue:[]},{name:"lookahead"}]};case"TerminalRuleCall":return{name:"TerminalRuleCall",properties:[{name:"cardinality"},{name:"lookahead"},{name:"rule"}]};case"UnorderedGroup":return{name:"UnorderedGroup",properties:[{name:"cardinality"},{name:"elements",defaultValue:[]},{name:"lookahead"}]};case"UntilToken":return{name:"UntilToken",properties:[{name:"cardinality"},{name:"lookahead"},{name:"terminal"}]};case"Wildcard":return{name:"Wildcard",properties:[{name:"cardinality"},{name:"lookahead"}]};default:return{name:e,properties:[]}}}}const M=new zo;function td(n){for(const[e,t]of Object.entries(n))e.startsWith("$")||(Array.isArray(t)?t.forEach((r,i)=>{ae(r)&&(r.$container=n,r.$containerProperty=e,r.$containerIndex=i)}):ae(t)&&(t.$container=n,t.$containerProperty=e))}function nr(n,e){let t=n;for(;t;){if(e(t))return t;t=t.$container}}function Fe(n){const t=nd(n).$document;if(!t)throw new Error("AST node has no document.");return t}function nd(n){for(;n.$container;)n=n.$container;return n}function ki(n,e){if(!n)throw new Error("Node must be an AstNode.");const t=e==null?void 0:e.range;return new ie(()=>({keys:Object.keys(n),keyIndex:0,arrayIndex:0}),r=>{for(;r.keyIndexki(t,e))}function At(n,e){if(!n)throw new Error("Root node must be an AstNode.");return new vi(n,t=>ki(t,e),{includeRoot:!0})}function ns(n,e){var t;if(!e)return!0;const r=(t=n.$cstNode)===null||t===void 0?void 0:t.range;return r?Su(r,e):!1}function qo(n){return new ie(()=>({keys:Object.keys(n),keyIndex:0,arrayIndex:0}),e=>{for(;e.keyIndexer({...yr,...tr().gitGraph}),"getConfig"),i=new F(()=>{const t=z(),r=t.mainBranchName,a=t.mainBranchOrder;return{mainBranchName:r,commits:new Map,head:null,branchConfig:new Map([[r,{name:r,order:a}]]),branches:new Map([[r,null]]),currBranch:r,direction:"LR",seq:0,options:{}}});function j(){return ar({length:7})}h(j,"getID");function N(t,r){const a=Object.create(null);return t.reduce((s,e)=>{const n=r(e);return a[n]||(a[n]=!0,s.push(e)),s},[])}h(N,"uniqBy");var ur=h(function(t){i.records.direction=t},"setDirection"),xr=h(function(t){w.debug("options str",t),t=t==null?void 0:t.trim(),t=t||"{}";try{i.records.options=JSON.parse(t)}catch(r){w.error("error while parsing gitGraph options",r.message)}},"setOptions"),pr=h(function(){return i.records.options},"getOptions"),br=h(function(t){let r=t.msg,a=t.id;const s=t.type;let e=t.tags;w.info("commit",r,a,s,e),w.debug("Entering commit:",r,a,s,e);const n=z();a=B.sanitizeText(a,n),r=B.sanitizeText(r,n),e=e==null?void 0:e.map(o=>B.sanitizeText(o,n));const c={id:a||i.records.seq+"-"+j(),message:r,seq:i.records.seq++,type:s??x.NORMAL,tags:e??[],parents:i.records.head==null?[]:[i.records.head.id],branch:i.records.currBranch};i.records.head=c,w.info("main branch",n.mainBranchName),i.records.commits.set(c.id,c),i.records.branches.set(i.records.currBranch,c.id),w.debug("in pushCommit "+c.id)},"commit"),mr=h(function(t){let r=t.name;const a=t.order;if(r=B.sanitizeText(r,z()),i.records.branches.has(r))throw new Error(`Trying to create an existing branch. (Help: Either use a new name if you want create a new branch or try using "checkout ${r}")`);i.records.branches.set(r,i.records.head!=null?i.records.head.id:null),i.records.branchConfig.set(r,{name:r,order:a}),_(r),w.debug("in createBranch")},"branch"),wr=h(t=>{let r=t.branch,a=t.id;const s=t.type,e=t.tags,n=z();r=B.sanitizeText(r,n),a&&(a=B.sanitizeText(a,n));const c=i.records.branches.get(i.records.currBranch),o=i.records.branches.get(r),$=c?i.records.commits.get(c):void 0,l=o?i.records.commits.get(o):void 0;if($&&l&&$.branch===r)throw new Error(`Cannot merge branch '${r}' into itself.`);if(i.records.currBranch===r){const d=new Error('Incorrect usage of "merge". Cannot merge a branch to itself');throw d.hash={text:`merge ${r}`,token:`merge ${r}`,expected:["branch abc"]},d}if($===void 0||!$){const d=new Error(`Incorrect usage of "merge". Current branch (${i.records.currBranch})has no commits`);throw d.hash={text:`merge ${r}`,token:`merge ${r}`,expected:["commit"]},d}if(!i.records.branches.has(r)){const d=new Error('Incorrect usage of "merge". Branch to be merged ('+r+") does not exist");throw d.hash={text:`merge ${r}`,token:`merge ${r}`,expected:[`branch ${r}`]},d}if(l===void 0||!l){const d=new Error('Incorrect usage of "merge". Branch to be merged ('+r+") has no commits");throw d.hash={text:`merge ${r}`,token:`merge ${r}`,expected:['"commit"']},d}if($===l){const d=new Error('Incorrect usage of "merge". Both branches have same head');throw d.hash={text:`merge ${r}`,token:`merge ${r}`,expected:["branch abc"]},d}if(a&&i.records.commits.has(a)){const d=new Error('Incorrect usage of "merge". Commit with id:'+a+" already exists, use different custom Id");throw d.hash={text:`merge ${r} ${a} ${s} ${e==null?void 0:e.join(" ")}`,token:`merge ${r} ${a} ${s} ${e==null?void 0:e.join(" ")}`,expected:[`merge ${r} ${a}_UNIQUE ${s} ${e==null?void 0:e.join(" ")}`]},d}const f=o||"",g={id:a||`${i.records.seq}-${j()}`,message:`merged branch ${r} into ${i.records.currBranch}`,seq:i.records.seq++,parents:i.records.head==null?[]:[i.records.head.id,f],branch:i.records.currBranch,type:x.MERGE,customType:s,customId:!!a,tags:e??[]};i.records.head=g,i.records.commits.set(g.id,g),i.records.branches.set(i.records.currBranch,g.id),w.debug(i.records.branches),w.debug("in mergeBranch")},"merge"),vr=h(function(t){let r=t.id,a=t.targetId,s=t.tags,e=t.parent;w.debug("Entering cherryPick:",r,a,s);const n=z();if(r=B.sanitizeText(r,n),a=B.sanitizeText(a,n),s=s==null?void 0:s.map($=>B.sanitizeText($,n)),e=B.sanitizeText(e,n),!r||!i.records.commits.has(r)){const $=new Error('Incorrect usage of "cherryPick". Source commit id should exist and provided');throw $.hash={text:`cherryPick ${r} ${a}`,token:`cherryPick ${r} ${a}`,expected:["cherry-pick abc"]},$}const c=i.records.commits.get(r);if(c===void 0||!c)throw new Error('Incorrect usage of "cherryPick". Source commit id should exist and provided');if(e&&!(Array.isArray(c.parents)&&c.parents.includes(e)))throw new Error("Invalid operation: The specified parent commit is not an immediate parent of the cherry-picked commit.");const o=c.branch;if(c.type===x.MERGE&&!e)throw new Error("Incorrect usage of cherry-pick: If the source commit is a merge commit, an immediate parent commit must be specified.");if(!a||!i.records.commits.has(a)){if(o===i.records.currBranch){const g=new Error('Incorrect usage of "cherryPick". Source commit is already on current branch');throw g.hash={text:`cherryPick ${r} ${a}`,token:`cherryPick ${r} ${a}`,expected:["cherry-pick abc"]},g}const $=i.records.branches.get(i.records.currBranch);if($===void 0||!$){const g=new Error(`Incorrect usage of "cherry-pick". Current branch (${i.records.currBranch})has no commits`);throw g.hash={text:`cherryPick ${r} ${a}`,token:`cherryPick ${r} ${a}`,expected:["cherry-pick abc"]},g}const l=i.records.commits.get($);if(l===void 0||!l){const g=new Error(`Incorrect usage of "cherry-pick". Current branch (${i.records.currBranch})has no commits`);throw g.hash={text:`cherryPick ${r} ${a}`,token:`cherryPick ${r} ${a}`,expected:["cherry-pick abc"]},g}const f={id:i.records.seq+"-"+j(),message:`cherry-picked ${c==null?void 0:c.message} into ${i.records.currBranch}`,seq:i.records.seq++,parents:i.records.head==null?[]:[i.records.head.id,c.id],branch:i.records.currBranch,type:x.CHERRY_PICK,tags:s?s.filter(Boolean):[`cherry-pick:${c.id}${c.type===x.MERGE?`|parent:${e}`:""}`]};i.records.head=f,i.records.commits.set(f.id,f),i.records.branches.set(i.records.currBranch,f.id),w.debug(i.records.branches),w.debug("in cherryPick")}},"cherryPick"),_=h(function(t){if(t=B.sanitizeText(t,z()),i.records.branches.has(t)){i.records.currBranch=t;const r=i.records.branches.get(i.records.currBranch);r===void 0||!r?i.records.head=null:i.records.head=i.records.commits.get(r)??null}else{const r=new Error(`Trying to checkout branch which is not yet created. (Help try using "branch ${t}")`);throw r.hash={text:`checkout ${t}`,token:`checkout ${t}`,expected:[`branch ${t}`]},r}},"checkout");function A(t,r,a){const s=t.indexOf(r);s===-1?t.push(a):t.splice(s,1,a)}h(A,"upsert");function Y(t){const r=t.reduce((e,n)=>e.seq>n.seq?e:n,t[0]);let a="";t.forEach(function(e){e===r?a+="	*":a+="	|"});const s=[a,r.id,r.seq];for(const e in i.records.branches)i.records.branches.get(e)===r.id&&s.push(e);if(w.debug(s.join(" ")),r.parents&&r.parents.length==2&&r.parents[0]&&r.parents[1]){const e=i.records.commits.get(r.parents[0]);A(t,r,e),r.parents[1]&&t.push(i.records.commits.get(r.parents[1]))}else{if(r.parents.length==0)return;if(r.parents[0]){const e=i.records.commits.get(r.parents[0]);A(t,r,e)}}t=N(t,e=>e.id),Y(t)}h(Y,"prettyPrintCommitHistory");var Cr=h(function(){w.debug(i.records.commits);const t=V()[0];Y([t])},"prettyPrint"),Er=h(function(){i.reset(),hr()},"clear"),Br=h(function(){return[...i.records.branchConfig.values()].map((r,a)=>r.order!==null&&r.order!==void 0?r:{...r,order:parseFloat(`0.${a}`)}).sort((r,a)=>(r.order??0)-(a.order??0)).map(({name:r})=>({name:r}))},"getBranchesAsObjArray"),kr=h(function(){return i.records.branches},"getBranches"),Lr=h(function(){return i.records.commits},"getCommits"),V=h(function(){const t=[...i.records.commits.values()];return t.forEach(function(r){w.debug(r.id)}),t.sort((r,a)=>r.seq-a.seq),t},"getCommitsArray"),Tr=h(function(){return i.records.currBranch},"getCurrentBranch"),Mr=h(function(){return i.records.direction},"getDirection"),Rr=h(function(){return i.records.head},"getHead"),J={commitType:x,getConfig:z,setDirection:ur,setOptions:xr,getOptions:pr,commit:br,branch:mr,merge:wr,cherryPick:vr,checkout:_,prettyPrint:Cr,clear:Er,getBranchesAsObjArray:Br,getBranches:kr,getCommits:Lr,getCommitsArray:V,getCurrentBranch:Tr,getDirection:Mr,getHead:Rr,setAccTitle:nr,getAccTitle:sr,getAccDescription:or,setAccDescription:cr,setDiagramTitle:ir,getDiagramTitle:dr},Ir=h((t,r)=>{Z(t,r),t.dir&&r.setDirection(t.dir);for(const a of t.statements)qr(a,r)},"populate"),qr=h((t,r)=>{const s={Commit:h(e=>r.commit(Or(e)),"Commit"),Branch:h(e=>r.branch(zr(e)),"Branch"),Merge:h(e=>r.merge(Gr(e)),"Merge"),Checkout:h(e=>r.checkout(Hr(e)),"Checkout"),CherryPicking:h(e=>r.cherryPick(Pr(e)),"CherryPicking")}[t.$type];s?s(t):w.error(`Unknown statement type: ${t.$type}`)},"parseStatement"),Or=h(t=>({id:t.id,msg:t.message??"",type:t.type!==void 0?x[t.type]:x.NORMAL,tags:t.tags??void 0}),"parseCommit"),zr=h(t=>({name:t.name,order:t.order??0}),"parseBranch"),Gr=h(t=>({branch:t.branch,id:t.id??"",type:t.type!==void 0?x[t.type]:void 0,tags:t.tags??void 0}),"parseMerge"),Hr=h(t=>t.branch,"parseCheckout"),Pr=h(t=>{var a;return{id:t.id,targetId:"",tags:((a=t.tags)==null?void 0:a.length)===0?void 0:t.tags,parent:t.parent}},"parseCherryPicking"),Wr={parse:h(async t=>{const r=await gr("gitGraph",t);w.debug(r),Ir(r,J)},"parse")},S=rr(),b=S==null?void 0:S.gitGraph,R=10,I=40,k=4,L=2,O=8,C=new Map,E=new Map,P=30,G=new Map,W=[],M=0,u="LR",jr=h(()=>{C.clear(),E.clear(),G.clear(),M=0,W=[],u="LR"},"clear"),X=h(t=>{const r=document.createElementNS("http://www.w3.org/2000/svg","text");return(typeof t=="string"?t.split(/\\n|\n|/gi):t).forEach(s=>{const e=document.createElementNS("http://www.w3.org/2000/svg","tspan");e.setAttributeNS("http://www.w3.org/XML/1998/namespace","xml:space","preserve"),e.setAttribute("dy","1em"),e.setAttribute("x","0"),e.setAttribute("class","row"),e.textContent=s.trim(),r.appendChild(e)}),r},"drawText"),Q=h(t=>{let r,a,s;return u==="BT"?(a=h((e,n)=>e<=n,"comparisonFunc"),s=1/0):(a=h((e,n)=>e>=n,"comparisonFunc"),s=0),t.forEach(e=>{var c,o;const n=u==="TB"||u=="BT"?(c=E.get(e))==null?void 0:c.y:(o=E.get(e))==null?void 0:o.x;n!==void 0&&a(n,s)&&(r=e,s=n)}),r},"findClosestParent"),Sr=h(t=>{let r="",a=1/0;return t.forEach(s=>{const e=E.get(s).y;e<=a&&(r=s,a=e)}),r||void 0},"findClosestParentBT"),Ar=h((t,r,a)=>{let s=a,e=a;const n=[];t.forEach(c=>{const o=r.get(c);if(!o)throw new Error(`Commit not found for key ${c}`);o.parents.length?(s=Dr(o),e=Math.max(s,e)):n.push(o),Kr(o,s)}),s=e,n.forEach(c=>{Nr(c,s,a)}),t.forEach(c=>{const o=r.get(c);if(o!=null&&o.parents.length){const $=Sr(o.parents);s=E.get($).y-I,s<=e&&(e=s);const l=C.get(o.branch).pos,f=s-R;E.set(o.id,{x:l,y:f})}})},"setParallelBTPos"),Yr=h(t=>{var s;const r=Q(t.parents.filter(e=>e!==null));if(!r)throw new Error(`Closest parent not found for commit ${t.id}`);const a=(s=E.get(r))==null?void 0:s.y;if(a===void 0)throw new Error(`Closest parent position not found for commit ${t.id}`);return a},"findClosestParentPos"),Dr=h(t=>Yr(t)+I,"calculateCommitPosition"),Kr=h((t,r)=>{const a=C.get(t.branch);if(!a)throw new Error(`Branch not found for commit ${t.id}`);const s=a.pos,e=r+R;return E.set(t.id,{x:s,y:e}),{x:s,y:e}},"setCommitPosition"),Nr=h((t,r,a)=>{const s=C.get(t.branch);if(!s)throw new Error(`Branch not found for commit ${t.id}`);const e=r+a,n=s.pos;E.set(t.id,{x:n,y:e})},"setRootPosition"),_r=h((t,r,a,s,e,n)=>{if(n===x.HIGHLIGHT)t.append("rect").attr("x",a.x-10).attr("y",a.y-10).attr("width",20).attr("height",20).attr("class",`commit ${r.id} commit-highlight${e%O} ${s}-outer`),t.append("rect").attr("x",a.x-6).attr("y",a.y-6).attr("width",12).attr("height",12).attr("class",`commit ${r.id} commit${e%O} ${s}-inner`);else if(n===x.CHERRY_PICK)t.append("circle").attr("cx",a.x).attr("cy",a.y).attr("r",10).attr("class",`commit ${r.id} ${s}`),t.append("circle").attr("cx",a.x-3).attr("cy",a.y+2).attr("r",2.75).attr("fill","#fff").attr("class",`commit ${r.id} ${s}`),t.append("circle").attr("cx",a.x+3).attr("cy",a.y+2).attr("r",2.75).attr("fill","#fff").attr("class",`commit ${r.id} ${s}`),t.append("line").attr("x1",a.x+3).attr("y1",a.y+1).attr("x2",a.x).attr("y2",a.y-5).attr("stroke","#fff").attr("class",`commit ${r.id} ${s}`),t.append("line").attr("x1",a.x-3).attr("y1",a.y+1).attr("x2",a.x).attr("y2",a.y-5).attr("stroke","#fff").attr("class",`commit ${r.id} ${s}`);else{const c=t.append("circle");if(c.attr("cx",a.x),c.attr("cy",a.y),c.attr("r",r.type===x.MERGE?9:10),c.attr("class",`commit ${r.id} commit${e%O}`),n===x.MERGE){const o=t.append("circle");o.attr("cx",a.x),o.attr("cy",a.y),o.attr("r",6),o.attr("class",`commit ${s} ${r.id} commit${e%O}`)}n===x.REVERSE&&t.append("path").attr("d",`M ${a.x-5},${a.y-5}L${a.x+5},${a.y+5}M${a.x-5},${a.y+5}L${a.x+5},${a.y-5}`).attr("class",`commit ${s} ${r.id} commit${e%O}`)}},"drawCommitBullet"),Vr=h((t,r,a,s)=>{var e;if(r.type!==x.CHERRY_PICK&&(r.customId&&r.type===x.MERGE||r.type!==x.MERGE)&&(b!=null&&b.showCommitLabel)){const n=t.append("g"),c=n.insert("rect").attr("class","commit-label-bkg"),o=n.append("text").attr("x",s).attr("y",a.y+25).attr("class","commit-label").text(r.id),$=(e=o.node())==null?void 0:e.getBBox();if($&&(c.attr("x",a.posWithOffset-$.width/2-L).attr("y",a.y+13.5).attr("width",$.width+2*L).attr("height",$.height+2*L),u==="TB"||u==="BT"?(c.attr("x",a.x-($.width+4*k+5)).attr("y",a.y-12),o.attr("x",a.x-($.width+4*k)).attr("y",a.y+$.height-12)):o.attr("x",a.posWithOffset-$.width/2),b.rotateCommitLabel))if(u==="TB"||u==="BT")o.attr("transform","rotate(-45, "+a.x+", "+a.y+")"),c.attr("transform","rotate(-45, "+a.x+", "+a.y+")");else{const l=-7.5-($.width+10)/25*9.5,f=10+$.width/25*8.5;n.attr("transform","translate("+l+", "+f+") rotate(-45, "+s+", "+a.y+")")}}},"drawCommitLabel"),Jr=h((t,r,a,s)=>{var e;if(r.tags.length>0){let n=0,c=0,o=0;const $=[];for(const l of r.tags.reverse()){const f=t.insert("polygon"),g=t.append("circle"),d=t.append("text").attr("y",a.y-16-n).attr("class","tag-label").text(l),y=(e=d.node())==null?void 0:e.getBBox();if(!y)throw new Error("Tag bbox not found");c=Math.max(c,y.width),o=Math.max(o,y.height),d.attr("x",a.posWithOffset-y.width/2),$.push({tag:d,hole:g,rect:f,yOffset:n}),n+=20}for(const{tag:l,hole:f,rect:g,yOffset:d}of $){const y=o/2,p=a.y-19.2-d;if(g.attr("class","tag-label-bkg").attr("points",`
                                      +import{p as Z}from"./chunk-JJENOPKO-7opA8rsx.js";import{I as F}from"./chunk-FBCX6ULS-B99hIK7X.js";import{F as U,_ as h,d as rr,G as er,H as tr,I as ar,l as w,s as nr,g as sr,b as or,c as cr,q as ir,r as dr,e as B,t as hr,j as lr,u as $r,J as fr}from"./mermaid.core-D8igZDel.js";import{p as gr}from"./gitGraph-F2EDSAW4-Df57CYyu.js";import"./app-D7uBbsY3.js";import"./baseUniq-D0lZO5yp.js";import"./basePickBy-DpnmgMOi.js";import"./clone-DWnk59eF.js";var x={NORMAL:0,REVERSE:1,HIGHLIGHT:2,MERGE:3,CHERRY_PICK:4},yr=U.gitGraph,z=h(()=>er({...yr,...tr().gitGraph}),"getConfig"),i=new F(()=>{const t=z(),r=t.mainBranchName,a=t.mainBranchOrder;return{mainBranchName:r,commits:new Map,head:null,branchConfig:new Map([[r,{name:r,order:a}]]),branches:new Map([[r,null]]),currBranch:r,direction:"LR",seq:0,options:{}}});function j(){return ar({length:7})}h(j,"getID");function N(t,r){const a=Object.create(null);return t.reduce((s,e)=>{const n=r(e);return a[n]||(a[n]=!0,s.push(e)),s},[])}h(N,"uniqBy");var ur=h(function(t){i.records.direction=t},"setDirection"),xr=h(function(t){w.debug("options str",t),t=t==null?void 0:t.trim(),t=t||"{}";try{i.records.options=JSON.parse(t)}catch(r){w.error("error while parsing gitGraph options",r.message)}},"setOptions"),pr=h(function(){return i.records.options},"getOptions"),br=h(function(t){let r=t.msg,a=t.id;const s=t.type;let e=t.tags;w.info("commit",r,a,s,e),w.debug("Entering commit:",r,a,s,e);const n=z();a=B.sanitizeText(a,n),r=B.sanitizeText(r,n),e=e==null?void 0:e.map(o=>B.sanitizeText(o,n));const c={id:a||i.records.seq+"-"+j(),message:r,seq:i.records.seq++,type:s??x.NORMAL,tags:e??[],parents:i.records.head==null?[]:[i.records.head.id],branch:i.records.currBranch};i.records.head=c,w.info("main branch",n.mainBranchName),i.records.commits.set(c.id,c),i.records.branches.set(i.records.currBranch,c.id),w.debug("in pushCommit "+c.id)},"commit"),mr=h(function(t){let r=t.name;const a=t.order;if(r=B.sanitizeText(r,z()),i.records.branches.has(r))throw new Error(`Trying to create an existing branch. (Help: Either use a new name if you want create a new branch or try using "checkout ${r}")`);i.records.branches.set(r,i.records.head!=null?i.records.head.id:null),i.records.branchConfig.set(r,{name:r,order:a}),_(r),w.debug("in createBranch")},"branch"),wr=h(t=>{let r=t.branch,a=t.id;const s=t.type,e=t.tags,n=z();r=B.sanitizeText(r,n),a&&(a=B.sanitizeText(a,n));const c=i.records.branches.get(i.records.currBranch),o=i.records.branches.get(r),$=c?i.records.commits.get(c):void 0,l=o?i.records.commits.get(o):void 0;if($&&l&&$.branch===r)throw new Error(`Cannot merge branch '${r}' into itself.`);if(i.records.currBranch===r){const d=new Error('Incorrect usage of "merge". Cannot merge a branch to itself');throw d.hash={text:`merge ${r}`,token:`merge ${r}`,expected:["branch abc"]},d}if($===void 0||!$){const d=new Error(`Incorrect usage of "merge". Current branch (${i.records.currBranch})has no commits`);throw d.hash={text:`merge ${r}`,token:`merge ${r}`,expected:["commit"]},d}if(!i.records.branches.has(r)){const d=new Error('Incorrect usage of "merge". Branch to be merged ('+r+") does not exist");throw d.hash={text:`merge ${r}`,token:`merge ${r}`,expected:[`branch ${r}`]},d}if(l===void 0||!l){const d=new Error('Incorrect usage of "merge". Branch to be merged ('+r+") has no commits");throw d.hash={text:`merge ${r}`,token:`merge ${r}`,expected:['"commit"']},d}if($===l){const d=new Error('Incorrect usage of "merge". Both branches have same head');throw d.hash={text:`merge ${r}`,token:`merge ${r}`,expected:["branch abc"]},d}if(a&&i.records.commits.has(a)){const d=new Error('Incorrect usage of "merge". Commit with id:'+a+" already exists, use different custom Id");throw d.hash={text:`merge ${r} ${a} ${s} ${e==null?void 0:e.join(" ")}`,token:`merge ${r} ${a} ${s} ${e==null?void 0:e.join(" ")}`,expected:[`merge ${r} ${a}_UNIQUE ${s} ${e==null?void 0:e.join(" ")}`]},d}const f=o||"",g={id:a||`${i.records.seq}-${j()}`,message:`merged branch ${r} into ${i.records.currBranch}`,seq:i.records.seq++,parents:i.records.head==null?[]:[i.records.head.id,f],branch:i.records.currBranch,type:x.MERGE,customType:s,customId:!!a,tags:e??[]};i.records.head=g,i.records.commits.set(g.id,g),i.records.branches.set(i.records.currBranch,g.id),w.debug(i.records.branches),w.debug("in mergeBranch")},"merge"),vr=h(function(t){let r=t.id,a=t.targetId,s=t.tags,e=t.parent;w.debug("Entering cherryPick:",r,a,s);const n=z();if(r=B.sanitizeText(r,n),a=B.sanitizeText(a,n),s=s==null?void 0:s.map($=>B.sanitizeText($,n)),e=B.sanitizeText(e,n),!r||!i.records.commits.has(r)){const $=new Error('Incorrect usage of "cherryPick". Source commit id should exist and provided');throw $.hash={text:`cherryPick ${r} ${a}`,token:`cherryPick ${r} ${a}`,expected:["cherry-pick abc"]},$}const c=i.records.commits.get(r);if(c===void 0||!c)throw new Error('Incorrect usage of "cherryPick". Source commit id should exist and provided');if(e&&!(Array.isArray(c.parents)&&c.parents.includes(e)))throw new Error("Invalid operation: The specified parent commit is not an immediate parent of the cherry-picked commit.");const o=c.branch;if(c.type===x.MERGE&&!e)throw new Error("Incorrect usage of cherry-pick: If the source commit is a merge commit, an immediate parent commit must be specified.");if(!a||!i.records.commits.has(a)){if(o===i.records.currBranch){const g=new Error('Incorrect usage of "cherryPick". Source commit is already on current branch');throw g.hash={text:`cherryPick ${r} ${a}`,token:`cherryPick ${r} ${a}`,expected:["cherry-pick abc"]},g}const $=i.records.branches.get(i.records.currBranch);if($===void 0||!$){const g=new Error(`Incorrect usage of "cherry-pick". Current branch (${i.records.currBranch})has no commits`);throw g.hash={text:`cherryPick ${r} ${a}`,token:`cherryPick ${r} ${a}`,expected:["cherry-pick abc"]},g}const l=i.records.commits.get($);if(l===void 0||!l){const g=new Error(`Incorrect usage of "cherry-pick". Current branch (${i.records.currBranch})has no commits`);throw g.hash={text:`cherryPick ${r} ${a}`,token:`cherryPick ${r} ${a}`,expected:["cherry-pick abc"]},g}const f={id:i.records.seq+"-"+j(),message:`cherry-picked ${c==null?void 0:c.message} into ${i.records.currBranch}`,seq:i.records.seq++,parents:i.records.head==null?[]:[i.records.head.id,c.id],branch:i.records.currBranch,type:x.CHERRY_PICK,tags:s?s.filter(Boolean):[`cherry-pick:${c.id}${c.type===x.MERGE?`|parent:${e}`:""}`]};i.records.head=f,i.records.commits.set(f.id,f),i.records.branches.set(i.records.currBranch,f.id),w.debug(i.records.branches),w.debug("in cherryPick")}},"cherryPick"),_=h(function(t){if(t=B.sanitizeText(t,z()),i.records.branches.has(t)){i.records.currBranch=t;const r=i.records.branches.get(i.records.currBranch);r===void 0||!r?i.records.head=null:i.records.head=i.records.commits.get(r)??null}else{const r=new Error(`Trying to checkout branch which is not yet created. (Help try using "branch ${t}")`);throw r.hash={text:`checkout ${t}`,token:`checkout ${t}`,expected:[`branch ${t}`]},r}},"checkout");function A(t,r,a){const s=t.indexOf(r);s===-1?t.push(a):t.splice(s,1,a)}h(A,"upsert");function Y(t){const r=t.reduce((e,n)=>e.seq>n.seq?e:n,t[0]);let a="";t.forEach(function(e){e===r?a+="	*":a+="	|"});const s=[a,r.id,r.seq];for(const e in i.records.branches)i.records.branches.get(e)===r.id&&s.push(e);if(w.debug(s.join(" ")),r.parents&&r.parents.length==2&&r.parents[0]&&r.parents[1]){const e=i.records.commits.get(r.parents[0]);A(t,r,e),r.parents[1]&&t.push(i.records.commits.get(r.parents[1]))}else{if(r.parents.length==0)return;if(r.parents[0]){const e=i.records.commits.get(r.parents[0]);A(t,r,e)}}t=N(t,e=>e.id),Y(t)}h(Y,"prettyPrintCommitHistory");var Cr=h(function(){w.debug(i.records.commits);const t=V()[0];Y([t])},"prettyPrint"),Er=h(function(){i.reset(),hr()},"clear"),Br=h(function(){return[...i.records.branchConfig.values()].map((r,a)=>r.order!==null&&r.order!==void 0?r:{...r,order:parseFloat(`0.${a}`)}).sort((r,a)=>(r.order??0)-(a.order??0)).map(({name:r})=>({name:r}))},"getBranchesAsObjArray"),kr=h(function(){return i.records.branches},"getBranches"),Lr=h(function(){return i.records.commits},"getCommits"),V=h(function(){const t=[...i.records.commits.values()];return t.forEach(function(r){w.debug(r.id)}),t.sort((r,a)=>r.seq-a.seq),t},"getCommitsArray"),Tr=h(function(){return i.records.currBranch},"getCurrentBranch"),Mr=h(function(){return i.records.direction},"getDirection"),Rr=h(function(){return i.records.head},"getHead"),J={commitType:x,getConfig:z,setDirection:ur,setOptions:xr,getOptions:pr,commit:br,branch:mr,merge:wr,cherryPick:vr,checkout:_,prettyPrint:Cr,clear:Er,getBranchesAsObjArray:Br,getBranches:kr,getCommits:Lr,getCommitsArray:V,getCurrentBranch:Tr,getDirection:Mr,getHead:Rr,setAccTitle:nr,getAccTitle:sr,getAccDescription:or,setAccDescription:cr,setDiagramTitle:ir,getDiagramTitle:dr},Ir=h((t,r)=>{Z(t,r),t.dir&&r.setDirection(t.dir);for(const a of t.statements)qr(a,r)},"populate"),qr=h((t,r)=>{const s={Commit:h(e=>r.commit(Or(e)),"Commit"),Branch:h(e=>r.branch(zr(e)),"Branch"),Merge:h(e=>r.merge(Gr(e)),"Merge"),Checkout:h(e=>r.checkout(Hr(e)),"Checkout"),CherryPicking:h(e=>r.cherryPick(Pr(e)),"CherryPicking")}[t.$type];s?s(t):w.error(`Unknown statement type: ${t.$type}`)},"parseStatement"),Or=h(t=>({id:t.id,msg:t.message??"",type:t.type!==void 0?x[t.type]:x.NORMAL,tags:t.tags??void 0}),"parseCommit"),zr=h(t=>({name:t.name,order:t.order??0}),"parseBranch"),Gr=h(t=>({branch:t.branch,id:t.id??"",type:t.type!==void 0?x[t.type]:void 0,tags:t.tags??void 0}),"parseMerge"),Hr=h(t=>t.branch,"parseCheckout"),Pr=h(t=>{var a;return{id:t.id,targetId:"",tags:((a=t.tags)==null?void 0:a.length)===0?void 0:t.tags,parent:t.parent}},"parseCherryPicking"),Wr={parse:h(async t=>{const r=await gr("gitGraph",t);w.debug(r),Ir(r,J)},"parse")},S=rr(),b=S==null?void 0:S.gitGraph,R=10,I=40,k=4,L=2,O=8,C=new Map,E=new Map,P=30,G=new Map,W=[],M=0,u="LR",jr=h(()=>{C.clear(),E.clear(),G.clear(),M=0,W=[],u="LR"},"clear"),X=h(t=>{const r=document.createElementNS("http://www.w3.org/2000/svg","text");return(typeof t=="string"?t.split(/\\n|\n|/gi):t).forEach(s=>{const e=document.createElementNS("http://www.w3.org/2000/svg","tspan");e.setAttributeNS("http://www.w3.org/XML/1998/namespace","xml:space","preserve"),e.setAttribute("dy","1em"),e.setAttribute("x","0"),e.setAttribute("class","row"),e.textContent=s.trim(),r.appendChild(e)}),r},"drawText"),Q=h(t=>{let r,a,s;return u==="BT"?(a=h((e,n)=>e<=n,"comparisonFunc"),s=1/0):(a=h((e,n)=>e>=n,"comparisonFunc"),s=0),t.forEach(e=>{var c,o;const n=u==="TB"||u=="BT"?(c=E.get(e))==null?void 0:c.y:(o=E.get(e))==null?void 0:o.x;n!==void 0&&a(n,s)&&(r=e,s=n)}),r},"findClosestParent"),Sr=h(t=>{let r="",a=1/0;return t.forEach(s=>{const e=E.get(s).y;e<=a&&(r=s,a=e)}),r||void 0},"findClosestParentBT"),Ar=h((t,r,a)=>{let s=a,e=a;const n=[];t.forEach(c=>{const o=r.get(c);if(!o)throw new Error(`Commit not found for key ${c}`);o.parents.length?(s=Dr(o),e=Math.max(s,e)):n.push(o),Kr(o,s)}),s=e,n.forEach(c=>{Nr(c,s,a)}),t.forEach(c=>{const o=r.get(c);if(o!=null&&o.parents.length){const $=Sr(o.parents);s=E.get($).y-I,s<=e&&(e=s);const l=C.get(o.branch).pos,f=s-R;E.set(o.id,{x:l,y:f})}})},"setParallelBTPos"),Yr=h(t=>{var s;const r=Q(t.parents.filter(e=>e!==null));if(!r)throw new Error(`Closest parent not found for commit ${t.id}`);const a=(s=E.get(r))==null?void 0:s.y;if(a===void 0)throw new Error(`Closest parent position not found for commit ${t.id}`);return a},"findClosestParentPos"),Dr=h(t=>Yr(t)+I,"calculateCommitPosition"),Kr=h((t,r)=>{const a=C.get(t.branch);if(!a)throw new Error(`Branch not found for commit ${t.id}`);const s=a.pos,e=r+R;return E.set(t.id,{x:s,y:e}),{x:s,y:e}},"setCommitPosition"),Nr=h((t,r,a)=>{const s=C.get(t.branch);if(!s)throw new Error(`Branch not found for commit ${t.id}`);const e=r+a,n=s.pos;E.set(t.id,{x:n,y:e})},"setRootPosition"),_r=h((t,r,a,s,e,n)=>{if(n===x.HIGHLIGHT)t.append("rect").attr("x",a.x-10).attr("y",a.y-10).attr("width",20).attr("height",20).attr("class",`commit ${r.id} commit-highlight${e%O} ${s}-outer`),t.append("rect").attr("x",a.x-6).attr("y",a.y-6).attr("width",12).attr("height",12).attr("class",`commit ${r.id} commit${e%O} ${s}-inner`);else if(n===x.CHERRY_PICK)t.append("circle").attr("cx",a.x).attr("cy",a.y).attr("r",10).attr("class",`commit ${r.id} ${s}`),t.append("circle").attr("cx",a.x-3).attr("cy",a.y+2).attr("r",2.75).attr("fill","#fff").attr("class",`commit ${r.id} ${s}`),t.append("circle").attr("cx",a.x+3).attr("cy",a.y+2).attr("r",2.75).attr("fill","#fff").attr("class",`commit ${r.id} ${s}`),t.append("line").attr("x1",a.x+3).attr("y1",a.y+1).attr("x2",a.x).attr("y2",a.y-5).attr("stroke","#fff").attr("class",`commit ${r.id} ${s}`),t.append("line").attr("x1",a.x-3).attr("y1",a.y+1).attr("x2",a.x).attr("y2",a.y-5).attr("stroke","#fff").attr("class",`commit ${r.id} ${s}`);else{const c=t.append("circle");if(c.attr("cx",a.x),c.attr("cy",a.y),c.attr("r",r.type===x.MERGE?9:10),c.attr("class",`commit ${r.id} commit${e%O}`),n===x.MERGE){const o=t.append("circle");o.attr("cx",a.x),o.attr("cy",a.y),o.attr("r",6),o.attr("class",`commit ${s} ${r.id} commit${e%O}`)}n===x.REVERSE&&t.append("path").attr("d",`M ${a.x-5},${a.y-5}L${a.x+5},${a.y+5}M${a.x-5},${a.y+5}L${a.x+5},${a.y-5}`).attr("class",`commit ${s} ${r.id} commit${e%O}`)}},"drawCommitBullet"),Vr=h((t,r,a,s)=>{var e;if(r.type!==x.CHERRY_PICK&&(r.customId&&r.type===x.MERGE||r.type!==x.MERGE)&&(b!=null&&b.showCommitLabel)){const n=t.append("g"),c=n.insert("rect").attr("class","commit-label-bkg"),o=n.append("text").attr("x",s).attr("y",a.y+25).attr("class","commit-label").text(r.id),$=(e=o.node())==null?void 0:e.getBBox();if($&&(c.attr("x",a.posWithOffset-$.width/2-L).attr("y",a.y+13.5).attr("width",$.width+2*L).attr("height",$.height+2*L),u==="TB"||u==="BT"?(c.attr("x",a.x-($.width+4*k+5)).attr("y",a.y-12),o.attr("x",a.x-($.width+4*k)).attr("y",a.y+$.height-12)):o.attr("x",a.posWithOffset-$.width/2),b.rotateCommitLabel))if(u==="TB"||u==="BT")o.attr("transform","rotate(-45, "+a.x+", "+a.y+")"),c.attr("transform","rotate(-45, "+a.x+", "+a.y+")");else{const l=-7.5-($.width+10)/25*9.5,f=10+$.width/25*8.5;n.attr("transform","translate("+l+", "+f+") rotate(-45, "+s+", "+a.y+")")}}},"drawCommitLabel"),Jr=h((t,r,a,s)=>{var e;if(r.tags.length>0){let n=0,c=0,o=0;const $=[];for(const l of r.tags.reverse()){const f=t.insert("polygon"),g=t.append("circle"),d=t.append("text").attr("y",a.y-16-n).attr("class","tag-label").text(l),y=(e=d.node())==null?void 0:e.getBBox();if(!y)throw new Error("Tag bbox not found");c=Math.max(c,y.width),o=Math.max(o,y.height),d.attr("x",a.posWithOffset-y.width/2),$.push({tag:d,hole:g,rect:f,yOffset:n}),n+=20}for(const{tag:l,hole:f,rect:g,yOffset:d}of $){const y=o/2,p=a.y-19.2-d;if(g.attr("class","tag-label-bkg").attr("points",`
                                             ${s-c/2-k/2},${p+L}  
                                             ${s-c/2-k/2},${p-L}
                                             ${a.posWithOffset-c/2-k},${p-y-L}
                                      diff --git a/assets/graph-Oq3lz9SV.js b/assets/graph-Cjb-DGHB.js
                                      similarity index 97%
                                      rename from assets/graph-Oq3lz9SV.js
                                      rename to assets/graph-Cjb-DGHB.js
                                      index 0ae80345a8..cd9d14def8 100644
                                      --- a/assets/graph-Oq3lz9SV.js
                                      +++ b/assets/graph-Cjb-DGHB.js
                                      @@ -1 +1 @@
                                      -import{a as O,c as j,h as u,k as l,f as c,d as a,i as f,v as p,r as F}from"./baseUniq-ZJgB7efo.js";import{ay as y,az as P,aA as m,aB as E,aC as C}from"./mermaid.core-DapiNGBY.js";var M=y(function(d){return O(j(d,1,P,!0))}),A="\0",o="\0",L="";class D{constructor(e={}){this._isDirected=u(e,"directed")?e.directed:!0,this._isMultigraph=u(e,"multigraph")?e.multigraph:!1,this._isCompound=u(e,"compound")?e.compound:!1,this._label=void 0,this._defaultNodeLabelFn=m(void 0),this._defaultEdgeLabelFn=m(void 0),this._nodes={},this._isCompound&&(this._parent={},this._children={},this._children[o]={}),this._in={},this._preds={},this._out={},this._sucs={},this._edgeObjs={},this._edgeLabels={}}isDirected(){return this._isDirected}isMultigraph(){return this._isMultigraph}isCompound(){return this._isCompound}setGraph(e){return this._label=e,this}graph(){return this._label}setDefaultNodeLabel(e){return E(e)||(e=m(e)),this._defaultNodeLabelFn=e,this}nodeCount(){return this._nodeCount}nodes(){return l(this._nodes)}sources(){var e=this;return c(this.nodes(),function(t){return C(e._in[t])})}sinks(){var e=this;return c(this.nodes(),function(t){return C(e._out[t])})}setNodes(e,t){var s=arguments,i=this;return a(e,function(r){s.length>1?i.setNode(r,t):i.setNode(r)}),this}setNode(e,t){return u(this._nodes,e)?(arguments.length>1&&(this._nodes[e]=t),this):(this._nodes[e]=arguments.length>1?t:this._defaultNodeLabelFn(e),this._isCompound&&(this._parent[e]=o,this._children[e]={},this._children[o][e]=!0),this._in[e]={},this._preds[e]={},this._out[e]={},this._sucs[e]={},++this._nodeCount,this)}node(e){return this._nodes[e]}hasNode(e){return u(this._nodes,e)}removeNode(e){var t=this;if(u(this._nodes,e)){var s=function(i){t.removeEdge(t._edgeObjs[i])};delete this._nodes[e],this._isCompound&&(this._removeFromParentsChildList(e),delete this._parent[e],a(this.children(e),function(i){t.setParent(i)}),delete this._children[e]),a(l(this._in[e]),s),delete this._in[e],delete this._preds[e],a(l(this._out[e]),s),delete this._out[e],delete this._sucs[e],--this._nodeCount}return this}setParent(e,t){if(!this._isCompound)throw new Error("Cannot set parent in a non-compound graph");if(f(t))t=o;else{t+="";for(var s=t;!f(s);s=this.parent(s))if(s===e)throw new Error("Setting "+t+" as parent of "+e+" would create a cycle");this.setNode(t)}return this.setNode(e),this._removeFromParentsChildList(e),this._parent[e]=t,this._children[t][e]=!0,this}_removeFromParentsChildList(e){delete this._children[this._parent[e]][e]}parent(e){if(this._isCompound){var t=this._parent[e];if(t!==o)return t}}children(e){if(f(e)&&(e=o),this._isCompound){var t=this._children[e];if(t)return l(t)}else{if(e===o)return this.nodes();if(this.hasNode(e))return[]}}predecessors(e){var t=this._preds[e];if(t)return l(t)}successors(e){var t=this._sucs[e];if(t)return l(t)}neighbors(e){var t=this.predecessors(e);if(t)return M(t,this.successors(e))}isLeaf(e){var t;return this.isDirected()?t=this.successors(e):t=this.neighbors(e),t.length===0}filterNodes(e){var t=new this.constructor({directed:this._isDirected,multigraph:this._isMultigraph,compound:this._isCompound});t.setGraph(this.graph());var s=this;a(this._nodes,function(n,h){e(h)&&t.setNode(h,n)}),a(this._edgeObjs,function(n){t.hasNode(n.v)&&t.hasNode(n.w)&&t.setEdge(n,s.edge(n))});var i={};function r(n){var h=s.parent(n);return h===void 0||t.hasNode(h)?(i[n]=h,h):h in i?i[h]:r(h)}return this._isCompound&&a(t.nodes(),function(n){t.setParent(n,r(n))}),t}setDefaultEdgeLabel(e){return E(e)||(e=m(e)),this._defaultEdgeLabelFn=e,this}edgeCount(){return this._edgeCount}edges(){return p(this._edgeObjs)}setPath(e,t){var s=this,i=arguments;return F(e,function(r,n){return i.length>1?s.setEdge(r,n,t):s.setEdge(r,n),n}),this}setEdge(){var e,t,s,i,r=!1,n=arguments[0];typeof n=="object"&&n!==null&&"v"in n?(e=n.v,t=n.w,s=n.name,arguments.length===2&&(i=arguments[1],r=!0)):(e=n,t=arguments[1],s=arguments[3],arguments.length>2&&(i=arguments[2],r=!0)),e=""+e,t=""+t,f(s)||(s=""+s);var h=g(this._isDirected,e,t,s);if(u(this._edgeLabels,h))return r&&(this._edgeLabels[h]=i),this;if(!f(s)&&!this._isMultigraph)throw new Error("Cannot set a named edge when isMultigraph = false");this.setNode(e),this.setNode(t),this._edgeLabels[h]=r?i:this._defaultEdgeLabelFn(e,t,s);var _=G(this._isDirected,e,t,s);return e=_.v,t=_.w,Object.freeze(_),this._edgeObjs[h]=_,N(this._preds[t],e),N(this._sucs[e],t),this._in[t][h]=_,this._out[e][h]=_,this._edgeCount++,this}edge(e,t,s){var i=arguments.length===1?b(this._isDirected,arguments[0]):g(this._isDirected,e,t,s);return this._edgeLabels[i]}hasEdge(e,t,s){var i=arguments.length===1?b(this._isDirected,arguments[0]):g(this._isDirected,e,t,s);return u(this._edgeLabels,i)}removeEdge(e,t,s){var i=arguments.length===1?b(this._isDirected,arguments[0]):g(this._isDirected,e,t,s),r=this._edgeObjs[i];return r&&(e=r.v,t=r.w,delete this._edgeLabels[i],delete this._edgeObjs[i],v(this._preds[t],e),v(this._sucs[e],t),delete this._in[t][i],delete this._out[e][i],this._edgeCount--),this}inEdges(e,t){var s=this._in[e];if(s){var i=p(s);return t?c(i,function(r){return r.v===t}):i}}outEdges(e,t){var s=this._out[e];if(s){var i=p(s);return t?c(i,function(r){return r.w===t}):i}}nodeEdges(e,t){var s=this.inEdges(e,t);if(s)return s.concat(this.outEdges(e,t))}}D.prototype._nodeCount=0;D.prototype._edgeCount=0;function N(d,e){d[e]?d[e]++:d[e]=1}function v(d,e){--d[e]||delete d[e]}function g(d,e,t,s){var i=""+e,r=""+t;if(!d&&i>r){var n=i;i=r,r=n}return i+L+r+L+(f(s)?A:s)}function G(d,e,t,s){var i=""+e,r=""+t;if(!d&&i>r){var n=i;i=r,r=n}var h={v:i,w:r};return s&&(h.name=s),h}function b(d,e){return g(d,e.v,e.w,e.name)}export{D as G};
                                      +import{a as O,c as j,h as u,k as l,f as c,d as a,i as f,v as p,r as F}from"./baseUniq-D0lZO5yp.js";import{ay as y,az as P,aA as m,aB as E,aC as C}from"./mermaid.core-D8igZDel.js";var M=y(function(d){return O(j(d,1,P,!0))}),A="\0",o="\0",L="";class D{constructor(e={}){this._isDirected=u(e,"directed")?e.directed:!0,this._isMultigraph=u(e,"multigraph")?e.multigraph:!1,this._isCompound=u(e,"compound")?e.compound:!1,this._label=void 0,this._defaultNodeLabelFn=m(void 0),this._defaultEdgeLabelFn=m(void 0),this._nodes={},this._isCompound&&(this._parent={},this._children={},this._children[o]={}),this._in={},this._preds={},this._out={},this._sucs={},this._edgeObjs={},this._edgeLabels={}}isDirected(){return this._isDirected}isMultigraph(){return this._isMultigraph}isCompound(){return this._isCompound}setGraph(e){return this._label=e,this}graph(){return this._label}setDefaultNodeLabel(e){return E(e)||(e=m(e)),this._defaultNodeLabelFn=e,this}nodeCount(){return this._nodeCount}nodes(){return l(this._nodes)}sources(){var e=this;return c(this.nodes(),function(t){return C(e._in[t])})}sinks(){var e=this;return c(this.nodes(),function(t){return C(e._out[t])})}setNodes(e,t){var s=arguments,i=this;return a(e,function(r){s.length>1?i.setNode(r,t):i.setNode(r)}),this}setNode(e,t){return u(this._nodes,e)?(arguments.length>1&&(this._nodes[e]=t),this):(this._nodes[e]=arguments.length>1?t:this._defaultNodeLabelFn(e),this._isCompound&&(this._parent[e]=o,this._children[e]={},this._children[o][e]=!0),this._in[e]={},this._preds[e]={},this._out[e]={},this._sucs[e]={},++this._nodeCount,this)}node(e){return this._nodes[e]}hasNode(e){return u(this._nodes,e)}removeNode(e){var t=this;if(u(this._nodes,e)){var s=function(i){t.removeEdge(t._edgeObjs[i])};delete this._nodes[e],this._isCompound&&(this._removeFromParentsChildList(e),delete this._parent[e],a(this.children(e),function(i){t.setParent(i)}),delete this._children[e]),a(l(this._in[e]),s),delete this._in[e],delete this._preds[e],a(l(this._out[e]),s),delete this._out[e],delete this._sucs[e],--this._nodeCount}return this}setParent(e,t){if(!this._isCompound)throw new Error("Cannot set parent in a non-compound graph");if(f(t))t=o;else{t+="";for(var s=t;!f(s);s=this.parent(s))if(s===e)throw new Error("Setting "+t+" as parent of "+e+" would create a cycle");this.setNode(t)}return this.setNode(e),this._removeFromParentsChildList(e),this._parent[e]=t,this._children[t][e]=!0,this}_removeFromParentsChildList(e){delete this._children[this._parent[e]][e]}parent(e){if(this._isCompound){var t=this._parent[e];if(t!==o)return t}}children(e){if(f(e)&&(e=o),this._isCompound){var t=this._children[e];if(t)return l(t)}else{if(e===o)return this.nodes();if(this.hasNode(e))return[]}}predecessors(e){var t=this._preds[e];if(t)return l(t)}successors(e){var t=this._sucs[e];if(t)return l(t)}neighbors(e){var t=this.predecessors(e);if(t)return M(t,this.successors(e))}isLeaf(e){var t;return this.isDirected()?t=this.successors(e):t=this.neighbors(e),t.length===0}filterNodes(e){var t=new this.constructor({directed:this._isDirected,multigraph:this._isMultigraph,compound:this._isCompound});t.setGraph(this.graph());var s=this;a(this._nodes,function(n,h){e(h)&&t.setNode(h,n)}),a(this._edgeObjs,function(n){t.hasNode(n.v)&&t.hasNode(n.w)&&t.setEdge(n,s.edge(n))});var i={};function r(n){var h=s.parent(n);return h===void 0||t.hasNode(h)?(i[n]=h,h):h in i?i[h]:r(h)}return this._isCompound&&a(t.nodes(),function(n){t.setParent(n,r(n))}),t}setDefaultEdgeLabel(e){return E(e)||(e=m(e)),this._defaultEdgeLabelFn=e,this}edgeCount(){return this._edgeCount}edges(){return p(this._edgeObjs)}setPath(e,t){var s=this,i=arguments;return F(e,function(r,n){return i.length>1?s.setEdge(r,n,t):s.setEdge(r,n),n}),this}setEdge(){var e,t,s,i,r=!1,n=arguments[0];typeof n=="object"&&n!==null&&"v"in n?(e=n.v,t=n.w,s=n.name,arguments.length===2&&(i=arguments[1],r=!0)):(e=n,t=arguments[1],s=arguments[3],arguments.length>2&&(i=arguments[2],r=!0)),e=""+e,t=""+t,f(s)||(s=""+s);var h=g(this._isDirected,e,t,s);if(u(this._edgeLabels,h))return r&&(this._edgeLabels[h]=i),this;if(!f(s)&&!this._isMultigraph)throw new Error("Cannot set a named edge when isMultigraph = false");this.setNode(e),this.setNode(t),this._edgeLabels[h]=r?i:this._defaultEdgeLabelFn(e,t,s);var _=G(this._isDirected,e,t,s);return e=_.v,t=_.w,Object.freeze(_),this._edgeObjs[h]=_,N(this._preds[t],e),N(this._sucs[e],t),this._in[t][h]=_,this._out[e][h]=_,this._edgeCount++,this}edge(e,t,s){var i=arguments.length===1?b(this._isDirected,arguments[0]):g(this._isDirected,e,t,s);return this._edgeLabels[i]}hasEdge(e,t,s){var i=arguments.length===1?b(this._isDirected,arguments[0]):g(this._isDirected,e,t,s);return u(this._edgeLabels,i)}removeEdge(e,t,s){var i=arguments.length===1?b(this._isDirected,arguments[0]):g(this._isDirected,e,t,s),r=this._edgeObjs[i];return r&&(e=r.v,t=r.w,delete this._edgeLabels[i],delete this._edgeObjs[i],v(this._preds[t],e),v(this._sucs[e],t),delete this._in[t][i],delete this._out[e][i],this._edgeCount--),this}inEdges(e,t){var s=this._in[e];if(s){var i=p(s);return t?c(i,function(r){return r.v===t}):i}}outEdges(e,t){var s=this._out[e];if(s){var i=p(s);return t?c(i,function(r){return r.w===t}):i}}nodeEdges(e,t){var s=this.inEdges(e,t);if(s)return s.concat(this.outEdges(e,t))}}D.prototype._nodeCount=0;D.prototype._edgeCount=0;function N(d,e){d[e]?d[e]++:d[e]=1}function v(d,e){--d[e]||delete d[e]}function g(d,e,t,s){var i=""+e,r=""+t;if(!d&&i>r){var n=i;i=r,r=n}return i+L+r+L+(f(s)?A:s)}function G(d,e,t,s){var i=""+e,r=""+t;if(!d&&i>r){var n=i;i=r,r=n}var h={v:i,w:r};return s&&(h.name=s),h}function b(d,e){return g(d,e.v,e.w,e.name)}export{D as G};
                                      diff --git a/assets/grpc.html-3jmQQAel.js b/assets/grpc.html-C-k3ZkUy.js
                                      similarity index 99%
                                      rename from assets/grpc.html-3jmQQAel.js
                                      rename to assets/grpc.html-C-k3ZkUy.js
                                      index 14782627d3..ac222581df 100644
                                      --- a/assets/grpc.html-3jmQQAel.js
                                      +++ b/assets/grpc.html-C-k3ZkUy.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as i,r as t,o as c,c as r,a as o,b as e,d as l,e as s}from"./app-DBM4OJyw.js";const p={},d=s(`

                                      gRPC

                                      An modified transport protocol based on gRPC.

                                      gRPC is based on the HTTP/2 protocol and can theoretically be relayed by other servers that support HTTP/2, such as Nginx.

                                      gRPC and HTTP/2 has built-in multiplexing, so it is not recommended to enable mux.cool when using gRPC or HTTP/2.

                                      ⚠⚠⚠

                                      • gRPC doesn't support specifying the Host. Please enter the correct domain name in the outbound proxy address, or fill in ServerName in (x)tlsSettings, otherwise connection cannot be established.
                                      • gRPC doesn't support fallback to other services.
                                      • gRPC services are at risk of being actively probed. It is recommended to use reverse proxy tools such as Caddy or Nginx to perform path-based routing.

                                      Tip

                                      If you are using a reverse proxy such as Caddy or Nginx, please note the following:

                                      • Make sure that the reverse proxy server has enabled HTTP/2.
                                      • Use HTTP/2 or h2c (Caddy), grpc_pass (Nginx) to connect to Xray.
                                      • The path for regular mode is /\${serviceName}/Tun, and for Multi mode it is /\${serviceName}/TunMulti.
                                      • If you need to receive the client IP address, you can use the X-Real-IP header sent by Caddy / Nginx to pass the client IP.

                                      Tip

                                      If you are using fallback, please note the following:

                                      • Fallback to gRPC is not recommended, as there is a risk of being actively probed.
                                      • Please make sure that h2 is the first priority in (x)tlsSettings.alpn, otherwise gRPC (HTTP/2) may not be able to complete TLS handshake.
                                      • gRPC cannot perform path-based routing by Xray.

                                      GRPCObject

                                      GRPCObject corresponds to the grpcSettings item.

                                      {
                                      +import{_ as i,r as t,o as c,c as r,a as o,b as e,d as l,e as s}from"./app-D7uBbsY3.js";const p={},d=s(`

                                      gRPC

                                      An modified transport protocol based on gRPC.

                                      gRPC is based on the HTTP/2 protocol and can theoretically be relayed by other servers that support HTTP/2, such as Nginx.

                                      gRPC and HTTP/2 has built-in multiplexing, so it is not recommended to enable mux.cool when using gRPC or HTTP/2.

                                      ⚠⚠⚠

                                      • gRPC doesn't support specifying the Host. Please enter the correct domain name in the outbound proxy address, or fill in ServerName in (x)tlsSettings, otherwise connection cannot be established.
                                      • gRPC doesn't support fallback to other services.
                                      • gRPC services are at risk of being actively probed. It is recommended to use reverse proxy tools such as Caddy or Nginx to perform path-based routing.

                                      Tip

                                      If you are using a reverse proxy such as Caddy or Nginx, please note the following:

                                      • Make sure that the reverse proxy server has enabled HTTP/2.
                                      • Use HTTP/2 or h2c (Caddy), grpc_pass (Nginx) to connect to Xray.
                                      • The path for regular mode is /\${serviceName}/Tun, and for Multi mode it is /\${serviceName}/TunMulti.
                                      • If you need to receive the client IP address, you can use the X-Real-IP header sent by Caddy / Nginx to pass the client IP.

                                      Tip

                                      If you are using fallback, please note the following:

                                      • Fallback to gRPC is not recommended, as there is a risk of being actively probed.
                                      • Please make sure that h2 is the first priority in (x)tlsSettings.alpn, otherwise gRPC (HTTP/2) may not be able to complete TLS handshake.
                                      • gRPC cannot perform path-based routing by Xray.

                                      GRPCObject

                                      GRPCObject corresponds to the grpcSettings item.

                                      {
                                         "serviceName": "name",
                                         "multiMode": false,
                                         "idle_timeout": 60,
                                      diff --git a/assets/grpc.html-Dw2s9Pxy.js b/assets/grpc.html-D7RhLn8X.js
                                      similarity index 99%
                                      rename from assets/grpc.html-Dw2s9Pxy.js
                                      rename to assets/grpc.html-D7RhLn8X.js
                                      index ddcd4eba4a..c7717e4544 100644
                                      --- a/assets/grpc.html-Dw2s9Pxy.js
                                      +++ b/assets/grpc.html-D7RhLn8X.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as c,r as t,o as p,c as i,a as s,b as o,d as l,e}from"./app-DBM4OJyw.js";const r={},d=e(`

                                      gRPC

                                      Режим передачи данных, основанный на HTTP/2, полностью соответствует стандарту HTTP/2 и может быть ретранслирован другими HTTP-серверами (такими как Nginx).

                                      gRPC (HTTP/2) имеет встроенное мультиплексирование, не рекомендуется включать mux.cool при использовании gRPC и HTTP/2.

                                      ⚠⚠⚠

                                      • gRPC не поддерживает указание Host. Пожалуйста, укажите правильное доменное имя в адресе исходящего прокси или укажите ServerName в (x)tlsSettings, иначе подключение не будет установлено.
                                      • gRPC не поддерживает fallback на другие сервисы.
                                      • Существует риск активного сканирования сервисов gRPC. Рекомендуется использовать обратный прокси-сервер, такой как Caddy или Nginx, для предварительного разделения трафика по пути.

                                      Подсказка

                                      Если вы используете обратный прокси-сервер, такой как Caddy или Nginx, обратите внимание на следующие моменты:

                                      • Убедитесь, что на обратном прокси-сервере включен HTTP/2.
                                      • Используйте HTTP/2 или h2c (Caddy), grpc_pass (Nginx) для подключения к Xray.
                                      • Путь в обычном режиме: /\${serviceName}/Tun, в режиме Multi: /\${serviceName}/TunMulti.
                                      • Если необходимо получать IP-адрес клиента, его можно передать через заголовок X-Real-IP, отправленный Caddy / Nginx.

                                      Подсказка

                                      Если вы используете fallback, обратите внимание на следующие моменты:

                                      • Не рекомендуется использовать fallback на gRPC, так как существует риск активного сканирования.
                                      • Убедитесь, что h2 находится на первом месте в (x)tlsSettings.alpn, иначе gRPC (HTTP/2) может не завершить TLS-рукопожатие.
                                      • gRPC не поддерживает маршрутизацию на основе path с помощью Xray.

                                      GRPCObject

                                      GRPCObject соответствует элементу grpcSettings конфигурации передачи.

                                      {
                                      +import{_ as c,r as t,o as p,c as i,a as s,b as o,d as l,e}from"./app-D7uBbsY3.js";const r={},d=e(`

                                      gRPC

                                      Режим передачи данных, основанный на HTTP/2, полностью соответствует стандарту HTTP/2 и может быть ретранслирован другими HTTP-серверами (такими как Nginx).

                                      gRPC (HTTP/2) имеет встроенное мультиплексирование, не рекомендуется включать mux.cool при использовании gRPC и HTTP/2.

                                      ⚠⚠⚠

                                      • gRPC не поддерживает указание Host. Пожалуйста, укажите правильное доменное имя в адресе исходящего прокси или укажите ServerName в (x)tlsSettings, иначе подключение не будет установлено.
                                      • gRPC не поддерживает fallback на другие сервисы.
                                      • Существует риск активного сканирования сервисов gRPC. Рекомендуется использовать обратный прокси-сервер, такой как Caddy или Nginx, для предварительного разделения трафика по пути.

                                      Подсказка

                                      Если вы используете обратный прокси-сервер, такой как Caddy или Nginx, обратите внимание на следующие моменты:

                                      • Убедитесь, что на обратном прокси-сервере включен HTTP/2.
                                      • Используйте HTTP/2 или h2c (Caddy), grpc_pass (Nginx) для подключения к Xray.
                                      • Путь в обычном режиме: /\${serviceName}/Tun, в режиме Multi: /\${serviceName}/TunMulti.
                                      • Если необходимо получать IP-адрес клиента, его можно передать через заголовок X-Real-IP, отправленный Caddy / Nginx.

                                      Подсказка

                                      Если вы используете fallback, обратите внимание на следующие моменты:

                                      • Не рекомендуется использовать fallback на gRPC, так как существует риск активного сканирования.
                                      • Убедитесь, что h2 находится на первом месте в (x)tlsSettings.alpn, иначе gRPC (HTTP/2) может не завершить TLS-рукопожатие.
                                      • gRPC не поддерживает маршрутизацию на основе path с помощью Xray.

                                      GRPCObject

                                      GRPCObject соответствует элементу grpcSettings конфигурации передачи.

                                      {
                                         "authority": "grpc.example.com",
                                         "serviceName": "name",
                                         "multiMode": false,
                                      diff --git a/assets/grpc.html-3Z809VPJ.js b/assets/grpc.html-DKDNkwiH.js
                                      similarity index 99%
                                      rename from assets/grpc.html-3Z809VPJ.js
                                      rename to assets/grpc.html-DKDNkwiH.js
                                      index e4df004238..ab320f4a36 100644
                                      --- a/assets/grpc.html-3Z809VPJ.js
                                      +++ b/assets/grpc.html-DKDNkwiH.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as c,r as o,o as p,c as i,a as t,b as s,d as r,e}from"./app-DBM4OJyw.js";const l={},d=e(`

                                      gRPC

                                      基于 gRPC 的传输方式。

                                      它基于 HTTP/2 协议,理论上可以通过其它支持 HTTP/2 的服务器(如 Nginx)进行中转。 gRPC(HTTP/2)内置多路复用,不建议使用 gRPC 与 HTTP/2 时启用 mux.cool。

                                      ⚠⚠⚠

                                      • gRPC 不支持指定 Host。请在出站代理地址中填写 正确的域名 ,或在 (x)tlsSettings 中填写 ServerName,否则无法连接。
                                      • gRPC 不支持回落到其他服务。
                                      • gRPC 服务存在被主动探测的风险。建议使用 Caddy 或 Nginx 等反向代理工具,通过 Path 前置分流。

                                      提示

                                      如果您使用 Caddy 或 Nginx 等反向代理,请注意下列事项:

                                      • 请确定反向代理服务器开启了 HTTP/2
                                      • 请使用 HTTP/2 或 h2c (Caddy),grpc_pass (Nginx) 连接到 Xray。
                                      • 普通模式的 Path 为 /\${serviceName}/Tun, Multi 模式为 /\${serviceName}/TunMulti
                                      • 如果需要接收客户端 IP,可以通过由 Caddy / Nginx 发送 X-Real-IP header 来传递客户端 IP。

                                      提示

                                      如果你正在使用回落,请注意下列事项:

                                      • 不建议回落到 gRPC,存在被主动探测的风险。
                                      • 请确认h2 位于 (x)tlsSettings.alpn 中的第一顺位,否则 gRPC(HTTP/2)可能无法完成 TLS 握手。
                                      • gRPC 无法通过进行 Path 分流。

                                      GRPCObject

                                      GRPCObject 对应传输配置的 grpcSettings 项。

                                      {
                                      +import{_ as c,r as o,o as p,c as i,a as t,b as s,d as r,e}from"./app-D7uBbsY3.js";const l={},d=e(`

                                      gRPC

                                      基于 gRPC 的传输方式。

                                      它基于 HTTP/2 协议,理论上可以通过其它支持 HTTP/2 的服务器(如 Nginx)进行中转。 gRPC(HTTP/2)内置多路复用,不建议使用 gRPC 与 HTTP/2 时启用 mux.cool。

                                      ⚠⚠⚠

                                      • gRPC 不支持指定 Host。请在出站代理地址中填写 正确的域名 ,或在 (x)tlsSettings 中填写 ServerName,否则无法连接。
                                      • gRPC 不支持回落到其他服务。
                                      • gRPC 服务存在被主动探测的风险。建议使用 Caddy 或 Nginx 等反向代理工具,通过 Path 前置分流。

                                      提示

                                      如果您使用 Caddy 或 Nginx 等反向代理,请注意下列事项:

                                      • 请确定反向代理服务器开启了 HTTP/2
                                      • 请使用 HTTP/2 或 h2c (Caddy),grpc_pass (Nginx) 连接到 Xray。
                                      • 普通模式的 Path 为 /\${serviceName}/Tun, Multi 模式为 /\${serviceName}/TunMulti
                                      • 如果需要接收客户端 IP,可以通过由 Caddy / Nginx 发送 X-Real-IP header 来传递客户端 IP。

                                      提示

                                      如果你正在使用回落,请注意下列事项:

                                      • 不建议回落到 gRPC,存在被主动探测的风险。
                                      • 请确认h2 位于 (x)tlsSettings.alpn 中的第一顺位,否则 gRPC(HTTP/2)可能无法完成 TLS 握手。
                                      • gRPC 无法通过进行 Path 分流。

                                      GRPCObject

                                      GRPCObject 对应传输配置的 grpcSettings 项。

                                      {
                                         "authority": "grpc.example.com",
                                         "serviceName": "name",
                                         "multiMode": false,
                                      diff --git a/assets/guide.html-CzsX8pED.js b/assets/guide.html-BFvmPsJG.js
                                      similarity index 99%
                                      rename from assets/guide.html-CzsX8pED.js
                                      rename to assets/guide.html-BFvmPsJG.js
                                      index 3f660c08b9..24c133dffa 100644
                                      --- a/assets/guide.html-CzsX8pED.js
                                      +++ b/assets/guide.html-BFvmPsJG.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as t,r as o,o as c,c as d,a as n,b as e,d as l,e as i}from"./app-DBM4OJyw.js";const h={},u=i('

                                      开发规范

                                      基本

                                      版本控制

                                      Project X 的代码被托管在 github 上:

                                      ',4),p={href:"https://github.com/XTLS/Xray-core",target:"_blank",rel:"noopener noreferrer"},_={href:"https://github.com/XTLS/Xray-install",target:"_blank",rel:"noopener noreferrer"},g={href:"https://github.com/XTLS/Xray-examples",target:"_blank",rel:"noopener noreferrer"},b={href:"https://github.com/XTLS/Xray-docs-next",target:"_blank",rel:"noopener noreferrer"},m={href:"https://git-scm.com/",target:"_blank",rel:"noopener noreferrer"},f=e("h3",{id:"分支-branch",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#分支-branch"},[e("span",null,"分支(Branch)")])],-1),x=e("ul",null,[e("li",null,"本项目的主干分支为 main,"),e("li",null,"本项目的发布主分支同为 main,"),e("li",null,"需要确保 main 在任一时刻都是可编译,且可正常使用的。"),e("li",null,"如果需要开发新的功能,请新建分支进行开发,在开发完成并且经过充分测试后,合并回主干分支。"),e("li",null,"已经合并入主干且没有必要存在的分支,请删除。")],-1),v=e("h3",{id:"发布-release",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#发布-release"},[e("span",null,"发布(Release)")])],-1),X=e("ul",null,[e("li",null,[l("建立尝鲜版本和稳定版本两个发布通道 "),e("ul",null,[e("li",null,"尝鲜版本,可以为 daily build,主要用于特定情况的测试,尝鲜和获得即时反馈和再改进。"),e("li",null,"稳定版本,为定时更新(比如月更),合并稳定的修改并发布。")])])],-1),y=e("h3",{id:"引用其它项目",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#引用其它项目"},[e("span",null,"引用其它项目")])],-1),k={href:"https://pkg.go.dev/search?limit=25&m=package&q=golang.org%2Fx",target:"_blank",rel:"noopener noreferrer"},P=e("li",null,"如需引用其它项目,请事先创建 issue 讨论;",-1),T=e("li",null,[l("其它 "),e("ul",null,[e("li",null,"不违反双方的协议,且对项目有帮助的工具,都可以使用。")])],-1),B=e("h2",{id:"开发流程",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#开发流程"},[e("span",null,"开发流程")])],-1),L=e("h3",{id:"写代码之前",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#写代码之前"},[e("span",null,"写代码之前")])],-1),E={href:"https://github.com/XTLS/Xray-core/issues",target:"_blank",rel:"noopener noreferrer"},G=e("h3",{id:"修改代码",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#修改代码"},[e("span",null,"修改代码")])],-1),R={href:"https://golang.org/doc/effective_go.html",target:"_blank",rel:"noopener noreferrer"},S=e("li",null,[l("每一次 push 之前,请运行:"),e("code",null,"go generate core/format.go"),l(";")],-1),q=e("li",null,[l("如果需要修改 protobuf,例如增加新配置项,请运行:"),e("code",null,"go generate core/proto.go"),l(";")],-1),A=e("li",null,[l("提交 pull request 之前,建议测试通过:"),e("code",null,"go test ./..."),l(";")],-1),F=e("li",null,"提交 pull request 之前,建议新增代码有超过 70% 的代码覆盖率(code coverage);",-1),I=e("li",null,[l("其它 "),e("ul",null,[e("li",null,"请注意代码的可读性。")])],-1),w=i(`

                                      Pull Request

                                      • 提交 PR 之前,请先运行 git pull https://github.com/XTLS/Xray-core.git 以确保 merge 可顺利进行;
                                      • 一个 PR 只做一件事,如有对多个 bug 的修复,请对每一个 bug 提交一个 PR;
                                      • 由于 Golang 的特殊需求(Package path),Go 项目的 PR 流程和其它项目有所不同,建议流程如下:
                                        1. 先 Fork 本项目,创建你自己的 github.com/<your_name>/Xray-core.git 仓库;
                                        2. 克隆你自己的 Xray 仓库到本地:git clone https://github.com/<your_name>/Xray-core.git
                                        3. 基于 main 分支创建新的分支,例如 git branch issue24 main
                                        4. 在新创建的分支上作修改并提交修改(commit);
                                        5. 在推送(push)修改完成的分支到自己的仓库前,先切换到 main 分支,运行 git pull https://github.com/XTLS/Xray-core.git 拉取最新的远端代码;
                                        6. 如果上一步拉取得到了新的远端代码,则切换到之前自己创建的分支,运行 git rebase main 执行分支合并操作。如遇到文件冲突,则需要解决冲突;
                                        7. 上一步处理完毕后,就可以把自己创建的分支推送到自己的仓库:git push -u origin your-branch
                                        8. 最后,把自己仓库的新推送的分支往 XTLS/Xray-coremain 分支发 PR 即可;
                                        9. 请在 PR 的标题和正文中,完整表述此次 PR 解决的问题 / 新增的功能 / 代码所做的修改的用意等;
                                        10. 耐心等待开发者的回应。

                                      对代码的修改

                                      功能性问题

                                      请提交至少一个测试用例(Test Case)来验证对现有功能的改动。

                                      性能相关

                                      请提交必要的测试数据来证明现有代码的性能缺陷,或是新增代码的性能提升。

                                      新功能

                                      • 如果新增功能对已有功能不影响,请提供可以开启/关闭的开关(如 flag),并使新功能保持默认关闭的状态;
                                      • 大型新功能(比如增加一个新的协议)开发之前,请先提交一个 issue,讨论完毕之后再进行开发。

                                      其它

                                      视具体情况而定。

                                      Xray 编码规范

                                      以下内容适用于 Xray 中的 Golang 代码。

                                      代码结构

                                      Xray-core
                                      +import{_ as t,r as o,o as c,c as d,a as n,b as e,d as l,e as i}from"./app-D7uBbsY3.js";const h={},u=i('

                                      开发规范

                                      基本

                                      版本控制

                                      Project X 的代码被托管在 github 上:

                                      ',4),p={href:"https://github.com/XTLS/Xray-core",target:"_blank",rel:"noopener noreferrer"},_={href:"https://github.com/XTLS/Xray-install",target:"_blank",rel:"noopener noreferrer"},g={href:"https://github.com/XTLS/Xray-examples",target:"_blank",rel:"noopener noreferrer"},b={href:"https://github.com/XTLS/Xray-docs-next",target:"_blank",rel:"noopener noreferrer"},m={href:"https://git-scm.com/",target:"_blank",rel:"noopener noreferrer"},f=e("h3",{id:"分支-branch",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#分支-branch"},[e("span",null,"分支(Branch)")])],-1),x=e("ul",null,[e("li",null,"本项目的主干分支为 main,"),e("li",null,"本项目的发布主分支同为 main,"),e("li",null,"需要确保 main 在任一时刻都是可编译,且可正常使用的。"),e("li",null,"如果需要开发新的功能,请新建分支进行开发,在开发完成并且经过充分测试后,合并回主干分支。"),e("li",null,"已经合并入主干且没有必要存在的分支,请删除。")],-1),v=e("h3",{id:"发布-release",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#发布-release"},[e("span",null,"发布(Release)")])],-1),X=e("ul",null,[e("li",null,[l("建立尝鲜版本和稳定版本两个发布通道 "),e("ul",null,[e("li",null,"尝鲜版本,可以为 daily build,主要用于特定情况的测试,尝鲜和获得即时反馈和再改进。"),e("li",null,"稳定版本,为定时更新(比如月更),合并稳定的修改并发布。")])])],-1),y=e("h3",{id:"引用其它项目",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#引用其它项目"},[e("span",null,"引用其它项目")])],-1),k={href:"https://pkg.go.dev/search?limit=25&m=package&q=golang.org%2Fx",target:"_blank",rel:"noopener noreferrer"},P=e("li",null,"如需引用其它项目,请事先创建 issue 讨论;",-1),T=e("li",null,[l("其它 "),e("ul",null,[e("li",null,"不违反双方的协议,且对项目有帮助的工具,都可以使用。")])],-1),B=e("h2",{id:"开发流程",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#开发流程"},[e("span",null,"开发流程")])],-1),L=e("h3",{id:"写代码之前",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#写代码之前"},[e("span",null,"写代码之前")])],-1),E={href:"https://github.com/XTLS/Xray-core/issues",target:"_blank",rel:"noopener noreferrer"},G=e("h3",{id:"修改代码",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#修改代码"},[e("span",null,"修改代码")])],-1),R={href:"https://golang.org/doc/effective_go.html",target:"_blank",rel:"noopener noreferrer"},S=e("li",null,[l("每一次 push 之前,请运行:"),e("code",null,"go generate core/format.go"),l(";")],-1),q=e("li",null,[l("如果需要修改 protobuf,例如增加新配置项,请运行:"),e("code",null,"go generate core/proto.go"),l(";")],-1),A=e("li",null,[l("提交 pull request 之前,建议测试通过:"),e("code",null,"go test ./..."),l(";")],-1),F=e("li",null,"提交 pull request 之前,建议新增代码有超过 70% 的代码覆盖率(code coverage);",-1),I=e("li",null,[l("其它 "),e("ul",null,[e("li",null,"请注意代码的可读性。")])],-1),w=i(`

                                      Pull Request

                                      • 提交 PR 之前,请先运行 git pull https://github.com/XTLS/Xray-core.git 以确保 merge 可顺利进行;
                                      • 一个 PR 只做一件事,如有对多个 bug 的修复,请对每一个 bug 提交一个 PR;
                                      • 由于 Golang 的特殊需求(Package path),Go 项目的 PR 流程和其它项目有所不同,建议流程如下:
                                        1. 先 Fork 本项目,创建你自己的 github.com/<your_name>/Xray-core.git 仓库;
                                        2. 克隆你自己的 Xray 仓库到本地:git clone https://github.com/<your_name>/Xray-core.git
                                        3. 基于 main 分支创建新的分支,例如 git branch issue24 main
                                        4. 在新创建的分支上作修改并提交修改(commit);
                                        5. 在推送(push)修改完成的分支到自己的仓库前,先切换到 main 分支,运行 git pull https://github.com/XTLS/Xray-core.git 拉取最新的远端代码;
                                        6. 如果上一步拉取得到了新的远端代码,则切换到之前自己创建的分支,运行 git rebase main 执行分支合并操作。如遇到文件冲突,则需要解决冲突;
                                        7. 上一步处理完毕后,就可以把自己创建的分支推送到自己的仓库:git push -u origin your-branch
                                        8. 最后,把自己仓库的新推送的分支往 XTLS/Xray-coremain 分支发 PR 即可;
                                        9. 请在 PR 的标题和正文中,完整表述此次 PR 解决的问题 / 新增的功能 / 代码所做的修改的用意等;
                                        10. 耐心等待开发者的回应。

                                      对代码的修改

                                      功能性问题

                                      请提交至少一个测试用例(Test Case)来验证对现有功能的改动。

                                      性能相关

                                      请提交必要的测试数据来证明现有代码的性能缺陷,或是新增代码的性能提升。

                                      新功能

                                      • 如果新增功能对已有功能不影响,请提供可以开启/关闭的开关(如 flag),并使新功能保持默认关闭的状态;
                                      • 大型新功能(比如增加一个新的协议)开发之前,请先提交一个 issue,讨论完毕之后再进行开发。

                                      其它

                                      视具体情况而定。

                                      Xray 编码规范

                                      以下内容适用于 Xray 中的 Golang 代码。

                                      代码结构

                                      Xray-core
                                       ├── app        // 应用模块
                                       │   ├── router // 路由
                                       ├── common     // 公用代码
                                      diff --git a/assets/guide.html-BmyZZjJ4.js b/assets/guide.html-Ce6Zjox0.js
                                      similarity index 99%
                                      rename from assets/guide.html-BmyZZjJ4.js
                                      rename to assets/guide.html-Ce6Zjox0.js
                                      index 3f660c08b9..24c133dffa 100644
                                      --- a/assets/guide.html-BmyZZjJ4.js
                                      +++ b/assets/guide.html-Ce6Zjox0.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as t,r as o,o as c,c as d,a as n,b as e,d as l,e as i}from"./app-DBM4OJyw.js";const h={},u=i('

                                      开发规范

                                      基本

                                      版本控制

                                      Project X 的代码被托管在 github 上:

                                      ',4),p={href:"https://github.com/XTLS/Xray-core",target:"_blank",rel:"noopener noreferrer"},_={href:"https://github.com/XTLS/Xray-install",target:"_blank",rel:"noopener noreferrer"},g={href:"https://github.com/XTLS/Xray-examples",target:"_blank",rel:"noopener noreferrer"},b={href:"https://github.com/XTLS/Xray-docs-next",target:"_blank",rel:"noopener noreferrer"},m={href:"https://git-scm.com/",target:"_blank",rel:"noopener noreferrer"},f=e("h3",{id:"分支-branch",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#分支-branch"},[e("span",null,"分支(Branch)")])],-1),x=e("ul",null,[e("li",null,"本项目的主干分支为 main,"),e("li",null,"本项目的发布主分支同为 main,"),e("li",null,"需要确保 main 在任一时刻都是可编译,且可正常使用的。"),e("li",null,"如果需要开发新的功能,请新建分支进行开发,在开发完成并且经过充分测试后,合并回主干分支。"),e("li",null,"已经合并入主干且没有必要存在的分支,请删除。")],-1),v=e("h3",{id:"发布-release",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#发布-release"},[e("span",null,"发布(Release)")])],-1),X=e("ul",null,[e("li",null,[l("建立尝鲜版本和稳定版本两个发布通道 "),e("ul",null,[e("li",null,"尝鲜版本,可以为 daily build,主要用于特定情况的测试,尝鲜和获得即时反馈和再改进。"),e("li",null,"稳定版本,为定时更新(比如月更),合并稳定的修改并发布。")])])],-1),y=e("h3",{id:"引用其它项目",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#引用其它项目"},[e("span",null,"引用其它项目")])],-1),k={href:"https://pkg.go.dev/search?limit=25&m=package&q=golang.org%2Fx",target:"_blank",rel:"noopener noreferrer"},P=e("li",null,"如需引用其它项目,请事先创建 issue 讨论;",-1),T=e("li",null,[l("其它 "),e("ul",null,[e("li",null,"不违反双方的协议,且对项目有帮助的工具,都可以使用。")])],-1),B=e("h2",{id:"开发流程",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#开发流程"},[e("span",null,"开发流程")])],-1),L=e("h3",{id:"写代码之前",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#写代码之前"},[e("span",null,"写代码之前")])],-1),E={href:"https://github.com/XTLS/Xray-core/issues",target:"_blank",rel:"noopener noreferrer"},G=e("h3",{id:"修改代码",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#修改代码"},[e("span",null,"修改代码")])],-1),R={href:"https://golang.org/doc/effective_go.html",target:"_blank",rel:"noopener noreferrer"},S=e("li",null,[l("每一次 push 之前,请运行:"),e("code",null,"go generate core/format.go"),l(";")],-1),q=e("li",null,[l("如果需要修改 protobuf,例如增加新配置项,请运行:"),e("code",null,"go generate core/proto.go"),l(";")],-1),A=e("li",null,[l("提交 pull request 之前,建议测试通过:"),e("code",null,"go test ./..."),l(";")],-1),F=e("li",null,"提交 pull request 之前,建议新增代码有超过 70% 的代码覆盖率(code coverage);",-1),I=e("li",null,[l("其它 "),e("ul",null,[e("li",null,"请注意代码的可读性。")])],-1),w=i(`

                                      Pull Request

                                      • 提交 PR 之前,请先运行 git pull https://github.com/XTLS/Xray-core.git 以确保 merge 可顺利进行;
                                      • 一个 PR 只做一件事,如有对多个 bug 的修复,请对每一个 bug 提交一个 PR;
                                      • 由于 Golang 的特殊需求(Package path),Go 项目的 PR 流程和其它项目有所不同,建议流程如下:
                                        1. 先 Fork 本项目,创建你自己的 github.com/<your_name>/Xray-core.git 仓库;
                                        2. 克隆你自己的 Xray 仓库到本地:git clone https://github.com/<your_name>/Xray-core.git
                                        3. 基于 main 分支创建新的分支,例如 git branch issue24 main
                                        4. 在新创建的分支上作修改并提交修改(commit);
                                        5. 在推送(push)修改完成的分支到自己的仓库前,先切换到 main 分支,运行 git pull https://github.com/XTLS/Xray-core.git 拉取最新的远端代码;
                                        6. 如果上一步拉取得到了新的远端代码,则切换到之前自己创建的分支,运行 git rebase main 执行分支合并操作。如遇到文件冲突,则需要解决冲突;
                                        7. 上一步处理完毕后,就可以把自己创建的分支推送到自己的仓库:git push -u origin your-branch
                                        8. 最后,把自己仓库的新推送的分支往 XTLS/Xray-coremain 分支发 PR 即可;
                                        9. 请在 PR 的标题和正文中,完整表述此次 PR 解决的问题 / 新增的功能 / 代码所做的修改的用意等;
                                        10. 耐心等待开发者的回应。

                                      对代码的修改

                                      功能性问题

                                      请提交至少一个测试用例(Test Case)来验证对现有功能的改动。

                                      性能相关

                                      请提交必要的测试数据来证明现有代码的性能缺陷,或是新增代码的性能提升。

                                      新功能

                                      • 如果新增功能对已有功能不影响,请提供可以开启/关闭的开关(如 flag),并使新功能保持默认关闭的状态;
                                      • 大型新功能(比如增加一个新的协议)开发之前,请先提交一个 issue,讨论完毕之后再进行开发。

                                      其它

                                      视具体情况而定。

                                      Xray 编码规范

                                      以下内容适用于 Xray 中的 Golang 代码。

                                      代码结构

                                      Xray-core
                                      +import{_ as t,r as o,o as c,c as d,a as n,b as e,d as l,e as i}from"./app-D7uBbsY3.js";const h={},u=i('

                                      开发规范

                                      基本

                                      版本控制

                                      Project X 的代码被托管在 github 上:

                                      ',4),p={href:"https://github.com/XTLS/Xray-core",target:"_blank",rel:"noopener noreferrer"},_={href:"https://github.com/XTLS/Xray-install",target:"_blank",rel:"noopener noreferrer"},g={href:"https://github.com/XTLS/Xray-examples",target:"_blank",rel:"noopener noreferrer"},b={href:"https://github.com/XTLS/Xray-docs-next",target:"_blank",rel:"noopener noreferrer"},m={href:"https://git-scm.com/",target:"_blank",rel:"noopener noreferrer"},f=e("h3",{id:"分支-branch",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#分支-branch"},[e("span",null,"分支(Branch)")])],-1),x=e("ul",null,[e("li",null,"本项目的主干分支为 main,"),e("li",null,"本项目的发布主分支同为 main,"),e("li",null,"需要确保 main 在任一时刻都是可编译,且可正常使用的。"),e("li",null,"如果需要开发新的功能,请新建分支进行开发,在开发完成并且经过充分测试后,合并回主干分支。"),e("li",null,"已经合并入主干且没有必要存在的分支,请删除。")],-1),v=e("h3",{id:"发布-release",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#发布-release"},[e("span",null,"发布(Release)")])],-1),X=e("ul",null,[e("li",null,[l("建立尝鲜版本和稳定版本两个发布通道 "),e("ul",null,[e("li",null,"尝鲜版本,可以为 daily build,主要用于特定情况的测试,尝鲜和获得即时反馈和再改进。"),e("li",null,"稳定版本,为定时更新(比如月更),合并稳定的修改并发布。")])])],-1),y=e("h3",{id:"引用其它项目",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#引用其它项目"},[e("span",null,"引用其它项目")])],-1),k={href:"https://pkg.go.dev/search?limit=25&m=package&q=golang.org%2Fx",target:"_blank",rel:"noopener noreferrer"},P=e("li",null,"如需引用其它项目,请事先创建 issue 讨论;",-1),T=e("li",null,[l("其它 "),e("ul",null,[e("li",null,"不违反双方的协议,且对项目有帮助的工具,都可以使用。")])],-1),B=e("h2",{id:"开发流程",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#开发流程"},[e("span",null,"开发流程")])],-1),L=e("h3",{id:"写代码之前",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#写代码之前"},[e("span",null,"写代码之前")])],-1),E={href:"https://github.com/XTLS/Xray-core/issues",target:"_blank",rel:"noopener noreferrer"},G=e("h3",{id:"修改代码",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#修改代码"},[e("span",null,"修改代码")])],-1),R={href:"https://golang.org/doc/effective_go.html",target:"_blank",rel:"noopener noreferrer"},S=e("li",null,[l("每一次 push 之前,请运行:"),e("code",null,"go generate core/format.go"),l(";")],-1),q=e("li",null,[l("如果需要修改 protobuf,例如增加新配置项,请运行:"),e("code",null,"go generate core/proto.go"),l(";")],-1),A=e("li",null,[l("提交 pull request 之前,建议测试通过:"),e("code",null,"go test ./..."),l(";")],-1),F=e("li",null,"提交 pull request 之前,建议新增代码有超过 70% 的代码覆盖率(code coverage);",-1),I=e("li",null,[l("其它 "),e("ul",null,[e("li",null,"请注意代码的可读性。")])],-1),w=i(`

                                      Pull Request

                                      • 提交 PR 之前,请先运行 git pull https://github.com/XTLS/Xray-core.git 以确保 merge 可顺利进行;
                                      • 一个 PR 只做一件事,如有对多个 bug 的修复,请对每一个 bug 提交一个 PR;
                                      • 由于 Golang 的特殊需求(Package path),Go 项目的 PR 流程和其它项目有所不同,建议流程如下:
                                        1. 先 Fork 本项目,创建你自己的 github.com/<your_name>/Xray-core.git 仓库;
                                        2. 克隆你自己的 Xray 仓库到本地:git clone https://github.com/<your_name>/Xray-core.git
                                        3. 基于 main 分支创建新的分支,例如 git branch issue24 main
                                        4. 在新创建的分支上作修改并提交修改(commit);
                                        5. 在推送(push)修改完成的分支到自己的仓库前,先切换到 main 分支,运行 git pull https://github.com/XTLS/Xray-core.git 拉取最新的远端代码;
                                        6. 如果上一步拉取得到了新的远端代码,则切换到之前自己创建的分支,运行 git rebase main 执行分支合并操作。如遇到文件冲突,则需要解决冲突;
                                        7. 上一步处理完毕后,就可以把自己创建的分支推送到自己的仓库:git push -u origin your-branch
                                        8. 最后,把自己仓库的新推送的分支往 XTLS/Xray-coremain 分支发 PR 即可;
                                        9. 请在 PR 的标题和正文中,完整表述此次 PR 解决的问题 / 新增的功能 / 代码所做的修改的用意等;
                                        10. 耐心等待开发者的回应。

                                      对代码的修改

                                      功能性问题

                                      请提交至少一个测试用例(Test Case)来验证对现有功能的改动。

                                      性能相关

                                      请提交必要的测试数据来证明现有代码的性能缺陷,或是新增代码的性能提升。

                                      新功能

                                      • 如果新增功能对已有功能不影响,请提供可以开启/关闭的开关(如 flag),并使新功能保持默认关闭的状态;
                                      • 大型新功能(比如增加一个新的协议)开发之前,请先提交一个 issue,讨论完毕之后再进行开发。

                                      其它

                                      视具体情况而定。

                                      Xray 编码规范

                                      以下内容适用于 Xray 中的 Golang 代码。

                                      代码结构

                                      Xray-core
                                       ├── app        // 应用模块
                                       │   ├── router // 路由
                                       ├── common     // 公用代码
                                      diff --git a/assets/guide.html-DwQuBDQN.js b/assets/guide.html-CumYazlz.js
                                      similarity index 99%
                                      rename from assets/guide.html-DwQuBDQN.js
                                      rename to assets/guide.html-CumYazlz.js
                                      index fa945048c3..a8acbeff11 100644
                                      --- a/assets/guide.html-DwQuBDQN.js
                                      +++ b/assets/guide.html-CumYazlz.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as l,r as t,o as c,c as d,a as n,b as e,d as o,e as r}from"./app-DBM4OJyw.js";const h={},u=r('

                                      Development Standards

                                      Basic

                                      Version Control

                                      Project X's code is hosted on GitHub:

                                      ',4),p={href:"https://github.com/XTLS/Xray-core",target:"_blank",rel:"noopener noreferrer"},f={href:"https://github.com/XTLS/Xray-install",target:"_blank",rel:"noopener noreferrer"},m={href:"https://github.com/XTLS/Xray-examples",target:"_blank",rel:"noopener noreferrer"},g={href:"https://github.com/XTLS/Xray-docs-next",target:"_blank",rel:"noopener noreferrer"},b={href:"https://git-scm.com/",target:"_blank",rel:"noopener noreferrer"},y=e("h3",{id:"branch",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#branch"},[e("span",null,"Branch")])],-1),_=e("ul",null,[e("li",null,"The main branch is the backbone of this project."),e("li",null,"The main branch is also the release branch of this project."),e("li",null,"It is necessary to ensure that main can be compiled and used normally at any time."),e("li",null,"If you need to develop new features, please create a new branch for development. After development and sufficient testing, merge it back to the main branch."),e("li",null,"Please delete branches that have been merged into the main branch and are no longer necessary.")],-1),v=e("h3",{id:"release",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#release"},[e("span",null,"Release")])],-1),x=e("ul",null,[e("li",null,[o("Create two release channels: one for the beta version and another for the stable version. "),e("ul",null,[e("li",null,"The beta version, also known as the daily build, is mainly used for specific testing, experimentation, and instant feedback and improvement."),e("li",null,"The stable version, updated regularly (e.g. monthly), merges stable modifications and releases them.")])])],-1),w=e("h3",{id:"citing-other-projects",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#citing-other-projects"},[e("span",null,"Citing other projects")])],-1),k={href:"https://pkg.go.dev/search?q=golang.org%2Fx",target:"_blank",rel:"noopener noreferrer"},P=e("li",null,"If you need to reference other projects, please create an issue for discussion beforehand;",-1),X=e("li",null,[o("Other "),e("ul",null,[e("li",null,"Tools that do not violate the agreement of both parties and are helpful to the project can be used.")])],-1),C=e("h2",{id:"development-process",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#development-process"},[e("span",null,"Development Process")])],-1),I=e("h3",{id:"before-writing-code",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#before-writing-code"},[e("span",null,"Before Writing Code")])],-1),T={href:"https://github.com/XTLS/Xray-core/issues",target:"_blank",rel:"noopener noreferrer"},j=e("h3",{id:"modify-the-code",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#modify-the-code"},[e("span",null,"Modify the code")])],-1),G={href:"https://golang.org/doc/effective_go.html",target:"_blank",rel:"noopener noreferrer"},R=e("li",null,[o("Run "),e("code",null,"go generate core/format.go"),o(" before each push;")],-1),B=e("li",null,[o("If you need to modify protobuf, such as adding new configuration items, please run: "),e("code",null,"go generate core/proto.go"),o(";")],-1),S=e("li",null,[o("It is recommended to pass the test before submitting a pull request: "),e("code",null,"go test ./..."),o(";")],-1),L=e("li",null,"It is recommended to have more than 70% code coverage for newly added code before submitting pull requests.",-1),q=e("li",null,[o("Other "),e("ul",null,[e("li",null,"Please pay attention to the readability of the code.")])],-1),F=r(`

                                      Pull Request

                                      • Before submitting a PR, please run git pull https://github.com/xray/xray-core.git to ensure that the merge can proceed smoothly;
                                      • One PR only does one thing. If there are fixes for multiple bugs, please submit a PR for each bug;
                                      • Due to Golang's special requirements (Package path), the PR process for Go projects is different from other projects. The recommended process is as follows:
                                        1. Fork this project first and create your own github.com/<your_name>/Xray-core.git repository;
                                        2. Clone your own Xray repository to your local machine: git clone https://github.com/<your_name>/Xray-core.git;
                                        3. Create a new branch based on the main branch, for example git branch issue24 main;
                                        4. Make changes on the new branch and commit the changes;
                                        5. Before pushing the modified branch to your own repository, switch to the main branch, and run git pull https://github.com/xray/xray-core.git to pull the latest remote code;
                                        6. If new remote code is obtained in the previous step, switch to the branch you created earlier and run git rebase main to perform branch merging. If there is a file conflict, you need to resolve the conflict;
                                        7. After the previous step is completed, you can push the branch you created to your own repository: git push -u origin your-branch
                                        8. Finally, send a PR from your new pushed branch in your own repository to the main branch of xtls/Xray-core;
                                        9. Please fully describe the purpose of this PR, including the problem solved, the new feature added, or the modifications made in the title and body of the PR;
                                        10. Please be patient and wait for the developer's response.

                                      Modifying Code

                                      Functional issue

                                      Please submit at least one test case to verify changes to existing functionality.

                                      Please provide the necessary test data to demonstrate performance issues in existing code or performance improvements in new code.

                                      New Feature

                                      • If the new feature does not affect the existing functionality, please provide a toggle (such as a flag) that can be turned on/off, and keep the new feature disabled by default.
                                      • For major new features (such as adding a new protocol), please submit an issue for discussion before development.

                                      Other

                                      It depends on the specific situation.

                                      Xray Coding Guidelines

                                      The following content is applicable to Golang code in Xray.

                                      Code Structure

                                      Xray-core
                                      +import{_ as l,r as t,o as c,c as d,a as n,b as e,d as o,e as r}from"./app-D7uBbsY3.js";const h={},u=r('

                                      Development Standards

                                      Basic

                                      Version Control

                                      Project X's code is hosted on GitHub:

                                      ',4),p={href:"https://github.com/XTLS/Xray-core",target:"_blank",rel:"noopener noreferrer"},f={href:"https://github.com/XTLS/Xray-install",target:"_blank",rel:"noopener noreferrer"},m={href:"https://github.com/XTLS/Xray-examples",target:"_blank",rel:"noopener noreferrer"},g={href:"https://github.com/XTLS/Xray-docs-next",target:"_blank",rel:"noopener noreferrer"},b={href:"https://git-scm.com/",target:"_blank",rel:"noopener noreferrer"},y=e("h3",{id:"branch",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#branch"},[e("span",null,"Branch")])],-1),_=e("ul",null,[e("li",null,"The main branch is the backbone of this project."),e("li",null,"The main branch is also the release branch of this project."),e("li",null,"It is necessary to ensure that main can be compiled and used normally at any time."),e("li",null,"If you need to develop new features, please create a new branch for development. After development and sufficient testing, merge it back to the main branch."),e("li",null,"Please delete branches that have been merged into the main branch and are no longer necessary.")],-1),v=e("h3",{id:"release",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#release"},[e("span",null,"Release")])],-1),x=e("ul",null,[e("li",null,[o("Create two release channels: one for the beta version and another for the stable version. "),e("ul",null,[e("li",null,"The beta version, also known as the daily build, is mainly used for specific testing, experimentation, and instant feedback and improvement."),e("li",null,"The stable version, updated regularly (e.g. monthly), merges stable modifications and releases them.")])])],-1),w=e("h3",{id:"citing-other-projects",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#citing-other-projects"},[e("span",null,"Citing other projects")])],-1),k={href:"https://pkg.go.dev/search?q=golang.org%2Fx",target:"_blank",rel:"noopener noreferrer"},P=e("li",null,"If you need to reference other projects, please create an issue for discussion beforehand;",-1),X=e("li",null,[o("Other "),e("ul",null,[e("li",null,"Tools that do not violate the agreement of both parties and are helpful to the project can be used.")])],-1),C=e("h2",{id:"development-process",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#development-process"},[e("span",null,"Development Process")])],-1),I=e("h3",{id:"before-writing-code",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#before-writing-code"},[e("span",null,"Before Writing Code")])],-1),T={href:"https://github.com/XTLS/Xray-core/issues",target:"_blank",rel:"noopener noreferrer"},j=e("h3",{id:"modify-the-code",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#modify-the-code"},[e("span",null,"Modify the code")])],-1),G={href:"https://golang.org/doc/effective_go.html",target:"_blank",rel:"noopener noreferrer"},R=e("li",null,[o("Run "),e("code",null,"go generate core/format.go"),o(" before each push;")],-1),B=e("li",null,[o("If you need to modify protobuf, such as adding new configuration items, please run: "),e("code",null,"go generate core/proto.go"),o(";")],-1),S=e("li",null,[o("It is recommended to pass the test before submitting a pull request: "),e("code",null,"go test ./..."),o(";")],-1),L=e("li",null,"It is recommended to have more than 70% code coverage for newly added code before submitting pull requests.",-1),q=e("li",null,[o("Other "),e("ul",null,[e("li",null,"Please pay attention to the readability of the code.")])],-1),F=r(`

                                      Pull Request

                                      • Before submitting a PR, please run git pull https://github.com/xray/xray-core.git to ensure that the merge can proceed smoothly;
                                      • One PR only does one thing. If there are fixes for multiple bugs, please submit a PR for each bug;
                                      • Due to Golang's special requirements (Package path), the PR process for Go projects is different from other projects. The recommended process is as follows:
                                        1. Fork this project first and create your own github.com/<your_name>/Xray-core.git repository;
                                        2. Clone your own Xray repository to your local machine: git clone https://github.com/<your_name>/Xray-core.git;
                                        3. Create a new branch based on the main branch, for example git branch issue24 main;
                                        4. Make changes on the new branch and commit the changes;
                                        5. Before pushing the modified branch to your own repository, switch to the main branch, and run git pull https://github.com/xray/xray-core.git to pull the latest remote code;
                                        6. If new remote code is obtained in the previous step, switch to the branch you created earlier and run git rebase main to perform branch merging. If there is a file conflict, you need to resolve the conflict;
                                        7. After the previous step is completed, you can push the branch you created to your own repository: git push -u origin your-branch
                                        8. Finally, send a PR from your new pushed branch in your own repository to the main branch of xtls/Xray-core;
                                        9. Please fully describe the purpose of this PR, including the problem solved, the new feature added, or the modifications made in the title and body of the PR;
                                        10. Please be patient and wait for the developer's response.

                                      Modifying Code

                                      Functional issue

                                      Please submit at least one test case to verify changes to existing functionality.

                                      Please provide the necessary test data to demonstrate performance issues in existing code or performance improvements in new code.

                                      New Feature

                                      • If the new feature does not affect the existing functionality, please provide a toggle (such as a flag) that can be turned on/off, and keep the new feature disabled by default.
                                      • For major new features (such as adding a new protocol), please submit an issue for discussion before development.

                                      Other

                                      It depends on the specific situation.

                                      Xray Coding Guidelines

                                      The following content is applicable to Golang code in Xray.

                                      Code Structure

                                      Xray-core
                                       ├── app        // Application module
                                       │   ├── router // Router
                                       ├── common     // Common code
                                      diff --git a/assets/h2.html-DH2CM7PJ.js b/assets/h2.html-BBDDvcJa.js
                                      similarity index 99%
                                      rename from assets/h2.html-DH2CM7PJ.js
                                      rename to assets/h2.html-BBDDvcJa.js
                                      index 37ecf4d388..40a49e98c0 100644
                                      --- a/assets/h2.html-DH2CM7PJ.js
                                      +++ b/assets/h2.html-BBDDvcJa.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as p,r as o,o as c,c as l,a as s,b as t,d as n,e as r}from"./app-DBM4OJyw.js";const i={},u=r(`

                                      HTTP/2

                                      Способ передачи данных на основе HTTP/2.

                                      Он полностью реализован в соответствии со стандартом HTTP/2 и может быть перенаправлен через другие HTTP-серверы (например, Nginx).

                                      В соответствии с рекомендациями HTTP/2, клиент и сервер должны одновременно включать TLS для нормальной работы этого способа передачи.

                                      HTTP/2 имеет встроенное мультиплексирование, не рекомендуется включать mux.cool при использовании HTTP/2.

                                      Подсказка

                                      Текущая версия способа передачи HTTP/2 не требует, чтобы входящее соединение (сервер) имело конфигурацию TLS. Это позволяет в среде развертывания с разделением трафика для специальных целей использовать внешний шлюз для обработки TLS-соединения, в то время как Xray будет использоваться в качестве серверного приложения, а связь между шлюзом и Xray будет осуществляться по незашифрованному протоколу http/2, который называется h2c.

                                      Внимание

                                      ⚠️ Если вы используете fallback, обратите внимание на следующие моменты:

                                      • Убедитесь, что (x)tlsSettings.alpn содержит h2, иначе HTTP/2 не сможет завершить TLS-рукопожатие.
                                      • HTTP/2 не может быть разделен по пути, рекомендуется использовать SNI-разделение.

                                      HttpObject

                                      HttpObject соответствует элементу httpSettings конфигурации передачи.

                                      {
                                      +import{_ as p,r as o,o as c,c as l,a as s,b as t,d as n,e as r}from"./app-D7uBbsY3.js";const i={},u=r(`

                                      HTTP/2

                                      Способ передачи данных на основе HTTP/2.

                                      Он полностью реализован в соответствии со стандартом HTTP/2 и может быть перенаправлен через другие HTTP-серверы (например, Nginx).

                                      В соответствии с рекомендациями HTTP/2, клиент и сервер должны одновременно включать TLS для нормальной работы этого способа передачи.

                                      HTTP/2 имеет встроенное мультиплексирование, не рекомендуется включать mux.cool при использовании HTTP/2.

                                      Подсказка

                                      Текущая версия способа передачи HTTP/2 не требует, чтобы входящее соединение (сервер) имело конфигурацию TLS. Это позволяет в среде развертывания с разделением трафика для специальных целей использовать внешний шлюз для обработки TLS-соединения, в то время как Xray будет использоваться в качестве серверного приложения, а связь между шлюзом и Xray будет осуществляться по незашифрованному протоколу http/2, который называется h2c.

                                      Внимание

                                      ⚠️ Если вы используете fallback, обратите внимание на следующие моменты:

                                      • Убедитесь, что (x)tlsSettings.alpn содержит h2, иначе HTTP/2 не сможет завершить TLS-рукопожатие.
                                      • HTTP/2 не может быть разделен по пути, рекомендуется использовать SNI-разделение.

                                      HttpObject

                                      HttpObject соответствует элементу httpSettings конфигурации передачи.

                                      {
                                         "host": ["xray.com"],
                                         "path": "/random/path",
                                         "read_idle_timeout": 10,
                                      diff --git a/assets/h2.html-xtI0nSPz.js b/assets/h2.html-DKeq75z1.js
                                      similarity index 98%
                                      rename from assets/h2.html-xtI0nSPz.js
                                      rename to assets/h2.html-DKeq75z1.js
                                      index 4728829748..7c06f81e27 100644
                                      --- a/assets/h2.html-xtI0nSPz.js
                                      +++ b/assets/h2.html-DKeq75z1.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as p,r as s,o as c,c as l,a as o,b as t,d as n,e as r}from"./app-DBM4OJyw.js";const i={},u=r(`

                                      HTTP/2

                                      基于 HTTP/2 的传输方式。

                                      它完整按照 HTTP/2 标准实现,可以通过其它的 HTTP 服务器(如 Nginx)进行中转。

                                      由 HTTP/2 的建议,客户端和服务器必须同时开启 TLS 才可以正常使用这个传输方式。

                                      HTTP/2 内置多路复用,不建议使用 HTTP/2 时启用 mux.cool。

                                      提示

                                      当前版本的 HTTP/2 的传输方式并不强制要求入站服务端)有 TLS 配置. 这使得可以在特殊用途的分流部署环境中,由外部网关组件完成 TLS 层对话,Xray 作为后端应用,网关和 Xray 间使用称为 h2c 的明文 http/2 进行通讯。

                                      注意

                                      ⚠️ 如果你正在使用回落,请注意下列事项:

                                      • 请确认 (x)tlsSettings.alpn 中包含 h2,否则 HTTP/2 无法完成 TLS 握手。
                                      • HTTP/2 无法通过 Path 进行分流,建议使用 SNI 分流。

                                      HttpObject

                                      HttpObject 对应传输配置的 httpSettings 项。

                                      {
                                      +import{_ as p,r as s,o as c,c as l,a as o,b as t,d as n,e as r}from"./app-D7uBbsY3.js";const i={},u=r(`

                                      HTTP/2

                                      基于 HTTP/2 的传输方式。

                                      它完整按照 HTTP/2 标准实现,可以通过其它的 HTTP 服务器(如 Nginx)进行中转。

                                      由 HTTP/2 的建议,客户端和服务器必须同时开启 TLS 才可以正常使用这个传输方式。

                                      HTTP/2 内置多路复用,不建议使用 HTTP/2 时启用 mux.cool。

                                      提示

                                      当前版本的 HTTP/2 的传输方式并不强制要求入站服务端)有 TLS 配置. 这使得可以在特殊用途的分流部署环境中,由外部网关组件完成 TLS 层对话,Xray 作为后端应用,网关和 Xray 间使用称为 h2c 的明文 http/2 进行通讯。

                                      注意

                                      ⚠️ 如果你正在使用回落,请注意下列事项:

                                      • 请确认 (x)tlsSettings.alpn 中包含 h2,否则 HTTP/2 无法完成 TLS 握手。
                                      • HTTP/2 无法通过 Path 进行分流,建议使用 SNI 分流。

                                      HttpObject

                                      HttpObject 对应传输配置的 httpSettings 项。

                                      {
                                         "host": ["xray.com"],
                                         "path": "/random/path",
                                         "read_idle_timeout": 10,
                                      diff --git a/assets/h2.html-C9hnsppv.js b/assets/h2.html-DfcDyfAy.js
                                      similarity index 98%
                                      rename from assets/h2.html-C9hnsppv.js
                                      rename to assets/h2.html-DfcDyfAy.js
                                      index caf5ef7f0e..d3d72c3ac2 100644
                                      --- a/assets/h2.html-C9hnsppv.js
                                      +++ b/assets/h2.html-DfcDyfAy.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as p,r as t,o as r,c as l,a as s,b as e,d as n,w as d,e as o}from"./app-DBM4OJyw.js";const u={},h=o('

                                      HTTP/2

                                      The transmission mode based on HTTP/2 fully implements the HTTP/2 standard and can be relayed by other HTTP servers (such as Nginx).

                                      Based on the recommendations of HTTP/2, both the client and server must enable TLS to use this transmission mode normally.

                                      HTTP/2 has built-in multiplexing, so it is not recommended to enable mux.cool when using HTTP/2.

                                      Tip

                                      The current version of the transmission mode based on HTTP/2 does not require TLS configuration for inbound (server-side).

                                      This makes it possible to use a plaintext HTTP/2 protocol called h2c for communication between the gateway and Xray, with external gateway components handling the TLS layer conversation in special-purpose load-balancing deployment environments.

                                      Warning

                                      ⚠️ If you are using fallback, please note the following:

                                      • Please make sure that h2 is included in (x)tlsSettings.alpn, otherwise HTTP/2 cannot complete TLS handshake.
                                      • HTTP/2 cannot perform path-based routing, so it is recommended to use SNI-based routing.

                                      HttpObject

                                      ',7),m=e("code",null,"HttpObject",-1),k=e("code",null,"httpSettings",-1),b=o(`
                                      {
                                      +import{_ as p,r as t,o as r,c as l,a as s,b as e,d as n,w as d,e as o}from"./app-D7uBbsY3.js";const u={},h=o('

                                      HTTP/2

                                      The transmission mode based on HTTP/2 fully implements the HTTP/2 standard and can be relayed by other HTTP servers (such as Nginx).

                                      Based on the recommendations of HTTP/2, both the client and server must enable TLS to use this transmission mode normally.

                                      HTTP/2 has built-in multiplexing, so it is not recommended to enable mux.cool when using HTTP/2.

                                      Tip

                                      The current version of the transmission mode based on HTTP/2 does not require TLS configuration for inbound (server-side).

                                      This makes it possible to use a plaintext HTTP/2 protocol called h2c for communication between the gateway and Xray, with external gateway components handling the TLS layer conversation in special-purpose load-balancing deployment environments.

                                      Warning

                                      ⚠️ If you are using fallback, please note the following:

                                      • Please make sure that h2 is included in (x)tlsSettings.alpn, otherwise HTTP/2 cannot complete TLS handshake.
                                      • HTTP/2 cannot perform path-based routing, so it is recommended to use SNI-based routing.

                                      HttpObject

                                      ',7),m=e("code",null,"HttpObject",-1),k=e("code",null,"httpSettings",-1),b=o(`
                                      {
                                         "host": ["xray.com"],
                                         "path": "/random/path",
                                         "read_idle_timeout": 10,
                                      diff --git a/assets/http.html-Cv9NIFOF.js b/assets/http.html-BST5YIxM.js
                                      similarity index 98%
                                      rename from assets/http.html-Cv9NIFOF.js
                                      rename to assets/http.html-BST5YIxM.js
                                      index 1c63e7205c..9b4302a264 100644
                                      --- a/assets/http.html-Cv9NIFOF.js
                                      +++ b/assets/http.html-BST5YIxM.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as n,r as a,o as e,c as t,a as o,e as p}from"./app-DBM4OJyw.js";const r={},c=p(`

                                      HTTP

                                      HTTP is a protocol that is used for communication over the internet. Please note that HTTP does not provide encryption for data transmission and is not suitable for transmitting sensitive information over public networks, as it can be easily targeted for attacks.

                                      Danger

                                      The HTTP protocol does not provide encryption for transmission, making it unsuitable for transmitting over public networks and more susceptible to being used as a compromised host for attacks.

                                      Tip

                                      HTTP can only proxy TCP protocols, and cannot handle UDP-based protocols.

                                      OutboundConfigurationObject

                                      {
                                      +import{_ as n,r as a,o as e,c as t,a as o,e as p}from"./app-D7uBbsY3.js";const r={},c=p(`

                                      HTTP

                                      HTTP is a protocol that is used for communication over the internet. Please note that HTTP does not provide encryption for data transmission and is not suitable for transmitting sensitive information over public networks, as it can be easily targeted for attacks.

                                      Danger

                                      The HTTP protocol does not provide encryption for transmission, making it unsuitable for transmitting over public networks and more susceptible to being used as a compromised host for attacks.

                                      Tip

                                      HTTP can only proxy TCP protocols, and cannot handle UDP-based protocols.

                                      OutboundConfigurationObject

                                      {
                                         "servers": [
                                           {
                                             "address": "192.168.108.1",
                                      diff --git a/assets/http.html-Do070lJz.js b/assets/http.html-BV-A6WLZ.js
                                      similarity index 99%
                                      rename from assets/http.html-Do070lJz.js
                                      rename to assets/http.html-BV-A6WLZ.js
                                      index 365ad82dad..3c833d91b3 100644
                                      --- a/assets/http.html-Do070lJz.js
                                      +++ b/assets/http.html-BV-A6WLZ.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as l,r as t,o as i,c as u,a as s,b as a,d as n,w as o,e as c}from"./app-DBM4OJyw.js";const r={},d=c(`

                                      HTTP

                                      Протокол HTTP.

                                      Предупреждение

                                      Протокол HTTP не обеспечивает шифрования передачи данных, поэтому он не подходит для передачи данных через общедоступные сети и более уязвим для использования в качестве ботнета.

                                      Использование входящих соединений http более целесообразно в локальной сети или локальной среде, где он может быть использован для прослушивания входящих подключений и предоставления локальных сервисов другим программам.

                                      СОВЕТ 1

                                      http proxy может проксировать только протокол tcp, протоколы семейства udp не поддерживаются.

                                      СОВЕТ 2

                                      Используйте следующие переменные среды в Linux, чтобы использовать глобальный HTTP-прокси в текущем сеансе (эта настройка поддерживается многими программами, но не всеми).

                                      • export http_proxy=http://127.0.0.1:8080/ (замените адрес на адрес вашего настроенного входящего HTTP-прокси)
                                      • export https_proxy=$http_proxy

                                      InboundConfigurationObject

                                      {
                                      +import{_ as l,r as t,o as i,c as u,a as s,b as a,d as n,w as o,e as c}from"./app-D7uBbsY3.js";const r={},d=c(`

                                      HTTP

                                      Протокол HTTP.

                                      Предупреждение

                                      Протокол HTTP не обеспечивает шифрования передачи данных, поэтому он не подходит для передачи данных через общедоступные сети и более уязвим для использования в качестве ботнета.

                                      Использование входящих соединений http более целесообразно в локальной сети или локальной среде, где он может быть использован для прослушивания входящих подключений и предоставления локальных сервисов другим программам.

                                      СОВЕТ 1

                                      http proxy может проксировать только протокол tcp, протоколы семейства udp не поддерживаются.

                                      СОВЕТ 2

                                      Используйте следующие переменные среды в Linux, чтобы использовать глобальный HTTP-прокси в текущем сеансе (эта настройка поддерживается многими программами, но не всеми).

                                      • export http_proxy=http://127.0.0.1:8080/ (замените адрес на адрес вашего настроенного входящего HTTP-прокси)
                                      • export https_proxy=$http_proxy

                                      InboundConfigurationObject

                                      {
                                         "accounts": [
                                           {
                                             "user": "my-username",
                                      diff --git a/assets/http.html-CXn_nB9h.js b/assets/http.html-BiHwk-wd.js
                                      similarity index 98%
                                      rename from assets/http.html-CXn_nB9h.js
                                      rename to assets/http.html-BiHwk-wd.js
                                      index 5b1f273db0..e45e670fe7 100644
                                      --- a/assets/http.html-CXn_nB9h.js
                                      +++ b/assets/http.html-BiHwk-wd.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as l,r as t,o as i,c as u,a as s,b as e,d as n,w as o,e as c}from"./app-DBM4OJyw.js";const r={},d=c(`

                                      HTTP

                                      HTTP 协议。

                                      警告

                                      http 协议没有对传输加密,不适宜经公网中传输,更容易成为被人用作攻击的肉鸡。

                                      http 入站更有意义的用法是在局域网或本机环境下监听,为其他程序提供本地服务。

                                      TIP 1

                                      http proxy 只能代理 tcp 协议,udp 系的协议均不能通过。

                                      TIP 2

                                      在 Linux 中使用以下环境变量即可在当前 session 使用全局 HTTP 代理(很多软件都支持这一设置,也有不支持的)。

                                      • export http_proxy=http://127.0.0.1:8080/ (地址须改成你配置的 HTTP 入站代理地址)
                                      • export https_proxy=$http_proxy

                                      InboundConfigurationObject

                                      {
                                      +import{_ as l,r as t,o as i,c as u,a as s,b as e,d as n,w as o,e as c}from"./app-D7uBbsY3.js";const r={},d=c(`

                                      HTTP

                                      HTTP 协议。

                                      警告

                                      http 协议没有对传输加密,不适宜经公网中传输,更容易成为被人用作攻击的肉鸡。

                                      http 入站更有意义的用法是在局域网或本机环境下监听,为其他程序提供本地服务。

                                      TIP 1

                                      http proxy 只能代理 tcp 协议,udp 系的协议均不能通过。

                                      TIP 2

                                      在 Linux 中使用以下环境变量即可在当前 session 使用全局 HTTP 代理(很多软件都支持这一设置,也有不支持的)。

                                      • export http_proxy=http://127.0.0.1:8080/ (地址须改成你配置的 HTTP 入站代理地址)
                                      • export https_proxy=$http_proxy

                                      InboundConfigurationObject

                                      {
                                         "accounts": [
                                           {
                                             "user": "my-username",
                                      diff --git a/assets/http.html-DKb1_aBq.js b/assets/http.html-CwukuwGj.js
                                      similarity index 98%
                                      rename from assets/http.html-DKb1_aBq.js
                                      rename to assets/http.html-CwukuwGj.js
                                      index 2db8fe3560..9de4950bae 100644
                                      --- a/assets/http.html-DKb1_aBq.js
                                      +++ b/assets/http.html-CwukuwGj.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as n,r as a,o as e,c as t,a as o,e as p}from"./app-DBM4OJyw.js";const c={},i=p(`

                                      HTTP

                                      Протокол HTTP.

                                      Предупреждение

                                      Протокол HTTP не обеспечивает шифрования передачи, что делает его непригодным для передачи по общедоступным сетям и более уязвимым для использования в качестве скомпрометированного хоста для атак.

                                      Подсказка

                                      HTTP может проксировать только протоколы TCP и не может обрабатывать протоколы на основе UDP.

                                      OutboundConfigurationObject

                                      {
                                      +import{_ as n,r as a,o as e,c as t,a as o,e as p}from"./app-D7uBbsY3.js";const c={},i=p(`

                                      HTTP

                                      Протокол HTTP.

                                      Предупреждение

                                      Протокол HTTP не обеспечивает шифрования передачи, что делает его непригодным для передачи по общедоступным сетям и более уязвимым для использования в качестве скомпрометированного хоста для атак.

                                      Подсказка

                                      HTTP может проксировать только протоколы TCP и не может обрабатывать протоколы на основе UDP.

                                      OutboundConfigurationObject

                                      {
                                         "servers": [
                                           {
                                             "address": "192.168.108.1",
                                      diff --git a/assets/http.html-DSD926Zv.js b/assets/http.html-DopHzb3b.js
                                      similarity index 98%
                                      rename from assets/http.html-DSD926Zv.js
                                      rename to assets/http.html-DopHzb3b.js
                                      index 8682303370..8971977973 100644
                                      --- a/assets/http.html-DSD926Zv.js
                                      +++ b/assets/http.html-DopHzb3b.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as i,r as t,o as r,c as l,a as s,b as e,d as n,w as a,e as c}from"./app-DBM4OJyw.js";const u={},d=c(`

                                      HTTP

                                      HTTP protocol.

                                      Warning

                                      The HTTP protocol does not provide encryption for transmission and is not suitable for transmission over public networks, as it can easily be used as a target for attacks.

                                      The more meaningful use of http inbound is to listen in a local network or on the local machine to provide local services for other programs.

                                      TIP 1

                                      http proxy can only proxy the TCP protocol and cannot handle protocols based on UDP.

                                      TIP 2

                                      In Linux, you can use the following environment variables to enable global HTTP proxy for the current session (many software support this setting, but some may not).

                                      • export http_proxy=http://127.0.0.1:8080/ (Change the address to the configured inbound HTTP proxy address)
                                      • export https_proxy=$http_proxy
                                      • :::

                                      InboundConfigurationObject

                                      {
                                      +import{_ as i,r as t,o as r,c as l,a as s,b as e,d as n,w as a,e as c}from"./app-D7uBbsY3.js";const u={},d=c(`

                                      HTTP

                                      HTTP protocol.

                                      Warning

                                      The HTTP protocol does not provide encryption for transmission and is not suitable for transmission over public networks, as it can easily be used as a target for attacks.

                                      The more meaningful use of http inbound is to listen in a local network or on the local machine to provide local services for other programs.

                                      TIP 1

                                      http proxy can only proxy the TCP protocol and cannot handle protocols based on UDP.

                                      TIP 2

                                      In Linux, you can use the following environment variables to enable global HTTP proxy for the current session (many software support this setting, but some may not).

                                      • export http_proxy=http://127.0.0.1:8080/ (Change the address to the configured inbound HTTP proxy address)
                                      • export https_proxy=$http_proxy
                                      • :::

                                      InboundConfigurationObject

                                      {
                                         "accounts": [
                                           {
                                             "user": "my-username",
                                      diff --git a/assets/http.html-DgkiVHJm.js b/assets/http.html-Y4HdDC5h.js
                                      similarity index 98%
                                      rename from assets/http.html-DgkiVHJm.js
                                      rename to assets/http.html-Y4HdDC5h.js
                                      index 07949090b4..b785fdb34b 100644
                                      --- a/assets/http.html-DgkiVHJm.js
                                      +++ b/assets/http.html-Y4HdDC5h.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as n,r as a,o as e,c as t,a as o,e as p}from"./app-DBM4OJyw.js";const c={},i=p(`

                                      HTTP

                                      HTTP 协议。

                                      警告

                                      http 协议没有对传输加密,不适宜经公网中传输,更容易成为被人用作攻击的肉鸡。

                                      提示

                                      http 只能代理 tcp 协议,udp 系的协议均不能通过。

                                      OutboundConfigurationObject

                                      {
                                      +import{_ as n,r as a,o as e,c as t,a as o,e as p}from"./app-D7uBbsY3.js";const c={},i=p(`

                                      HTTP

                                      HTTP 协议。

                                      警告

                                      http 协议没有对传输加密,不适宜经公网中传输,更容易成为被人用作攻击的肉鸡。

                                      提示

                                      http 只能代理 tcp 协议,udp 系的协议均不能通过。

                                      OutboundConfigurationObject

                                      {
                                         "servers": [
                                           {
                                             "address": "192.168.108.1",
                                      diff --git a/assets/httpupgrade.html-mAe7j4MC.js b/assets/httpupgrade.html-BD23lJKx.js
                                      similarity index 98%
                                      rename from assets/httpupgrade.html-mAe7j4MC.js
                                      rename to assets/httpupgrade.html-BD23lJKx.js
                                      index 4628479800..d31b432a2c 100644
                                      --- a/assets/httpupgrade.html-mAe7j4MC.js
                                      +++ b/assets/httpupgrade.html-BD23lJKx.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as p,r as o,o as c,c as d,a as n,b as t,d as e,e as s}from"./app-DBM4OJyw.js";const i={},l=s(`

                                      HTTPUpgrade

                                      A WebSocket-like transport protocol implementing the HTTP/1.1 upgrade and response, allowing it to be reverse proxied by web servers or CDNs just like WebSocket, but without the need to implement the remaining portions of the WebSocket protocol, yielding better performance.

                                      Standalone usage is not recommended, but rather in conjunction with other security protocols like TLS.

                                      HttpUpgradeObject

                                      The HttpUpgradeObject corresponds to the httpupgradeSettings section under transport configurations.

                                      {
                                      +import{_ as p,r as o,o as c,c as d,a as n,b as t,d as e,e as s}from"./app-D7uBbsY3.js";const i={},l=s(`

                                      HTTPUpgrade

                                      A WebSocket-like transport protocol implementing the HTTP/1.1 upgrade and response, allowing it to be reverse proxied by web servers or CDNs just like WebSocket, but without the need to implement the remaining portions of the WebSocket protocol, yielding better performance.

                                      Standalone usage is not recommended, but rather in conjunction with other security protocols like TLS.

                                      HttpUpgradeObject

                                      The HttpUpgradeObject corresponds to the httpupgradeSettings section under transport configurations.

                                      {
                                         "acceptProxyProtocol": false,
                                         "path": "/",
                                         "host": "xray.com",
                                      diff --git a/assets/httpupgrade.html-DBZL0AAW.js b/assets/httpupgrade.html-BP4DQ20m.js
                                      similarity index 98%
                                      rename from assets/httpupgrade.html-DBZL0AAW.js
                                      rename to assets/httpupgrade.html-BP4DQ20m.js
                                      index e04ce8f79e..e762474ea5 100644
                                      --- a/assets/httpupgrade.html-DBZL0AAW.js
                                      +++ b/assets/httpupgrade.html-BP4DQ20m.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as c,r as t,o as r,c as d,a,b as o,d as e,e as s}from"./app-DBM4OJyw.js";const l={},u=s(`

                                      HTTPUpgrade

                                      一个实现了类似于 WebSocket 进行 HTTP 1.1 升级请求和响应的协议,这使得它可以像 WebSocket 一样可以被CDN或者Nginx进行反代,但无需实现 WebSocket 协议的其他部分,所以具有更高的效率。 其设计不推荐单独使用,而是和TLS等安全协议一起工作。

                                      HttpUpgradeObject

                                      HttpUpgradeObject 对应传输配置的 httpupgradeSettings 项。

                                      {
                                      +import{_ as c,r as t,o as r,c as d,a,b as o,d as e,e as s}from"./app-D7uBbsY3.js";const l={},u=s(`

                                      HTTPUpgrade

                                      一个实现了类似于 WebSocket 进行 HTTP 1.1 升级请求和响应的协议,这使得它可以像 WebSocket 一样可以被CDN或者Nginx进行反代,但无需实现 WebSocket 协议的其他部分,所以具有更高的效率。 其设计不推荐单独使用,而是和TLS等安全协议一起工作。

                                      HttpUpgradeObject

                                      HttpUpgradeObject 对应传输配置的 httpupgradeSettings 项。

                                      {
                                         "acceptProxyProtocol": false,
                                         "path": "/",
                                         "host": "xray.com",
                                      diff --git a/assets/httpupgrade.html-DCnMDttv.js b/assets/httpupgrade.html-BlNHRqh5.js
                                      similarity index 98%
                                      rename from assets/httpupgrade.html-DCnMDttv.js
                                      rename to assets/httpupgrade.html-BlNHRqh5.js
                                      index a83ee2fe3e..517fab94d0 100644
                                      --- a/assets/httpupgrade.html-DCnMDttv.js
                                      +++ b/assets/httpupgrade.html-BlNHRqh5.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as c,r as o,o as r,c as d,a,b as e,d as t,e as n}from"./app-DBM4OJyw.js";const l={},u=n(`

                                      HTTPUpgrade

                                      Это протокол, реализующий запросы и ответы на обновление HTTP 1.1, подобно WebSocket. Это позволяет ему, как и WebSocket, быть проксируемым CDN или Nginx, но без необходимости реализации других частей протокола WebSocket, что делает его более эффективным.

                                      Его дизайн не рекомендуется для самостоятельного использования, а лучше всего работает в сочетании с TLS.

                                      HttpUpgradeObject

                                      HttpUpgradeObject соответствует пункту httpupgradeSettings в настройках передачи.

                                      {
                                      +import{_ as c,r as o,o as r,c as d,a,b as e,d as t,e as n}from"./app-D7uBbsY3.js";const l={},u=n(`

                                      HTTPUpgrade

                                      Это протокол, реализующий запросы и ответы на обновление HTTP 1.1, подобно WebSocket. Это позволяет ему, как и WebSocket, быть проксируемым CDN или Nginx, но без необходимости реализации других частей протокола WebSocket, что делает его более эффективным.

                                      Его дизайн не рекомендуется для самостоятельного использования, а лучше всего работает в сочетании с TLS.

                                      HttpUpgradeObject

                                      HttpUpgradeObject соответствует пункту httpupgradeSettings в настройках передачи.

                                      {
                                         "acceptProxyProtocol": false,
                                         "path": "/",
                                         "host": "xray.com",
                                      diff --git a/assets/inbound.html-BPQMtrP7.js b/assets/inbound.html-7zvu4h9X.js
                                      similarity index 99%
                                      rename from assets/inbound.html-BPQMtrP7.js
                                      rename to assets/inbound.html-7zvu4h9X.js
                                      index f832ebc899..bf90f70fb7 100644
                                      --- a/assets/inbound.html-BPQMtrP7.js
                                      +++ b/assets/inbound.html-7zvu4h9X.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as l,r as t,o as d,c as u,a as o,b as e,d as n,w as c,e as s}from"./app-DBM4OJyw.js";const h={},b=e("h1",{id:"inbound-proxy",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#inbound-proxy"},[e("span",null,"Inbound Proxy")])],-1),m=s(`

                                      InboundObject

                                      The InboundObject corresponds to a subelement of the inbounds item in the configuration file.

                                      {
                                      +import{_ as l,r as t,o as d,c as u,a as o,b as e,d as n,w as c,e as s}from"./app-D7uBbsY3.js";const h={},b=e("h1",{id:"inbound-proxy",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#inbound-proxy"},[e("span",null,"Inbound Proxy")])],-1),m=s(`

                                      InboundObject

                                      The InboundObject corresponds to a subelement of the inbounds item in the configuration file.

                                      {
                                         "inbounds": [
                                           {
                                             "listen": "127.0.0.1",
                                      diff --git a/assets/inbound.html-Bl2le8Jm.js b/assets/inbound.html-BU0rgh7R.js
                                      similarity index 99%
                                      rename from assets/inbound.html-Bl2le8Jm.js
                                      rename to assets/inbound.html-BU0rgh7R.js
                                      index 7cbababf6a..db8cd83676 100644
                                      --- a/assets/inbound.html-Bl2le8Jm.js
                                      +++ b/assets/inbound.html-BU0rgh7R.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as d,r as e,o as i,c as r,a as s,b as n,d as o,w as c,e as a}from"./app-DBM4OJyw.js";const k={},q=n("h1",{id:"入站代理",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#入站代理"},[n("span",null,"入站代理")])],-1),b=a(`

                                      InboundObject

                                      InboundObject 对应配置文件中 inbounds 项的一个子元素。

                                      {
                                      +import{_ as d,r as e,o as i,c as r,a as s,b as n,d as o,w as c,e as a}from"./app-D7uBbsY3.js";const k={},q=n("h1",{id:"入站代理",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#入站代理"},[n("span",null,"入站代理")])],-1),b=a(`

                                      InboundObject

                                      InboundObject 对应配置文件中 inbounds 项的一个子元素。

                                      {
                                         "inbounds": [
                                           {
                                             "listen": "127.0.0.1",
                                      diff --git a/assets/inbound.html-B_YBnicn.js b/assets/inbound.html-CPFBK2Je.js
                                      similarity index 99%
                                      rename from assets/inbound.html-B_YBnicn.js
                                      rename to assets/inbound.html-CPFBK2Je.js
                                      index 7dc60a2750..c583b41420 100644
                                      --- a/assets/inbound.html-B_YBnicn.js
                                      +++ b/assets/inbound.html-CPFBK2Je.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as i,r as e,o as d,c as r,a as o,b as n,d as s,w as c,e as a}from"./app-DBM4OJyw.js";const b={},k=n("h1",{id:"входящие-подключения",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#входящие-подключения"},[n("span",null,"Входящие подключения")])],-1),q=a(`

                                      InboundObject

                                      InboundObject соответствует дочернему элементу поля inbounds в конфигурационном файле.

                                      {
                                      +import{_ as i,r as e,o as d,c as r,a as o,b as n,d as s,w as c,e as a}from"./app-D7uBbsY3.js";const b={},k=n("h1",{id:"входящие-подключения",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#входящие-подключения"},[n("span",null,"Входящие подключения")])],-1),q=a(`

                                      InboundObject

                                      InboundObject соответствует дочернему элементу поля inbounds в конфигурационном файле.

                                      {
                                         "inbounds": [
                                           {
                                             "listen": "127.0.0.1",
                                      diff --git a/assets/index.html-BvSm0ea0.js b/assets/index.html-1dnJ9JdM.js
                                      similarity index 97%
                                      rename from assets/index.html-BvSm0ea0.js
                                      rename to assets/index.html-1dnJ9JdM.js
                                      index 8322a881d4..99d960c2cb 100644
                                      --- a/assets/index.html-BvSm0ea0.js
                                      +++ b/assets/index.html-1dnJ9JdM.js
                                      @@ -1 +1 @@
                                      -import{_ as s,r as c,o as u,c as d,a as l,b as t,d as e,w as o}from"./app-DBM4OJyw.js";const h={},_=t("h1",{id:"小小白白话文",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#小小白白话文"},[t("span",null,"小小白白话文")])],-1),i=t("p",null,[t("strong",null,"这个章节是【从零开始】的基础课,新来的同学好好看好好学哦")],-1),p={class:"custom-container tip"},m=t("p",{class:"custom-container-title"},"提示",-1),f={href:"https://github.com/ricuhkaen",target:"_blank",rel:"noopener noreferrer"};function v(x,k){const a=c("I18nTip"),r=c("ExternalLinkIcon"),n=c("RouterLink");return u(),d("div",null,[l(a),_,i,t("div",p,[m,t("p",null,[e("Made with ❤️ by "),t("a",f,[e("@ricuhkaen"),l(r)])])]),t("p",null,[l(n,{to:"/document/level-0/ch01-preface.html"},{default:o(()=>[e("【第 1 章】 前言罗嗦篇")]),_:1}),e(" - 机场还是自建?这是个问题")]),t("p",null,[l(n,{to:"/document/level-0/ch02-preparation.html"},{default:o(()=>[e("【第 2 章】 原料准备篇")]),_:1}),e(" - 工欲善其事,必先利其器")]),t("p",null,[l(n,{to:"/document/level-0/ch03-ssh.html"},{default:o(()=>[e("【第 3 章】 远程登录篇")]),_:1}),e(" - 一桥飞架南北,天堑变通途")]),t("p",null,[l(n,{to:"/document/level-0/ch04-security.html"},{default:o(()=>[e("【第 4 章】 安全防护篇")]),_:1}),e(" - 安全不注意,亲人两行泪")]),t("p",null,[l(n,{to:"/document/level-0/ch05-webpage.html"},{default:o(()=>[e("【第 5 章】 网站建设篇")]),_:1}),e(" - 秀出你的美")]),t("p",null,[l(n,{to:"/document/level-0/ch06-certificates.html"},{default:o(()=>[e("【第 6 章】 证书管理篇")]),_:1}),e(" - 领证的才是合法的")]),t("p",null,[l(n,{to:"/document/level-0/ch07-xray-server.html"},{default:o(()=>[e("【第 7 章】 Xray 服务器篇")]),_:1}),e(" - 终于等到你")]),t("p",null,[l(n,{to:"/document/level-0/ch08-xray-clients.html"},{default:o(()=>[e("【第 8 章】 Xray 客户端篇")]),_:1}),e(" - 新的开始")]),t("p",null,[l(n,{to:"/document/level-0/ch09-appendix.html"},{default:o(()=>[e("【第 9 章】 附录")]),_:1}),e(" - 考点都在这里")])])}const y=s(h,[["render",v],["__file","index.html.vue"]]);export{y as default};
                                      +import{_ as s,r as c,o as u,c as d,a as l,b as t,d as e,w as o}from"./app-D7uBbsY3.js";const h={},_=t("h1",{id:"小小白白话文",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#小小白白话文"},[t("span",null,"小小白白话文")])],-1),i=t("p",null,[t("strong",null,"这个章节是【从零开始】的基础课,新来的同学好好看好好学哦")],-1),p={class:"custom-container tip"},m=t("p",{class:"custom-container-title"},"提示",-1),f={href:"https://github.com/ricuhkaen",target:"_blank",rel:"noopener noreferrer"};function v(x,k){const a=c("I18nTip"),r=c("ExternalLinkIcon"),n=c("RouterLink");return u(),d("div",null,[l(a),_,i,t("div",p,[m,t("p",null,[e("Made with ❤️ by "),t("a",f,[e("@ricuhkaen"),l(r)])])]),t("p",null,[l(n,{to:"/document/level-0/ch01-preface.html"},{default:o(()=>[e("【第 1 章】 前言罗嗦篇")]),_:1}),e(" - 机场还是自建?这是个问题")]),t("p",null,[l(n,{to:"/document/level-0/ch02-preparation.html"},{default:o(()=>[e("【第 2 章】 原料准备篇")]),_:1}),e(" - 工欲善其事,必先利其器")]),t("p",null,[l(n,{to:"/document/level-0/ch03-ssh.html"},{default:o(()=>[e("【第 3 章】 远程登录篇")]),_:1}),e(" - 一桥飞架南北,天堑变通途")]),t("p",null,[l(n,{to:"/document/level-0/ch04-security.html"},{default:o(()=>[e("【第 4 章】 安全防护篇")]),_:1}),e(" - 安全不注意,亲人两行泪")]),t("p",null,[l(n,{to:"/document/level-0/ch05-webpage.html"},{default:o(()=>[e("【第 5 章】 网站建设篇")]),_:1}),e(" - 秀出你的美")]),t("p",null,[l(n,{to:"/document/level-0/ch06-certificates.html"},{default:o(()=>[e("【第 6 章】 证书管理篇")]),_:1}),e(" - 领证的才是合法的")]),t("p",null,[l(n,{to:"/document/level-0/ch07-xray-server.html"},{default:o(()=>[e("【第 7 章】 Xray 服务器篇")]),_:1}),e(" - 终于等到你")]),t("p",null,[l(n,{to:"/document/level-0/ch08-xray-clients.html"},{default:o(()=>[e("【第 8 章】 Xray 客户端篇")]),_:1}),e(" - 新的开始")]),t("p",null,[l(n,{to:"/document/level-0/ch09-appendix.html"},{default:o(()=>[e("【第 9 章】 附录")]),_:1}),e(" - 考点都在这里")])])}const y=s(h,[["render",v],["__file","index.html.vue"]]);export{y as default};
                                      diff --git a/assets/index.html-D_B2zS6C.js b/assets/index.html-BWQkkF3k.js
                                      similarity index 98%
                                      rename from assets/index.html-D_B2zS6C.js
                                      rename to assets/index.html-BWQkkF3k.js
                                      index 0f5e37eb1e..efd0b5ee77 100644
                                      --- a/assets/index.html-D_B2zS6C.js
                                      +++ b/assets/index.html-BWQkkF3k.js
                                      @@ -1 +1 @@
                                      -import{_ as i,r as a,o as h,c as u,a as n,b as t,w as s,d as e}from"./app-DBM4OJyw.js";const _={},c=t("h1",{id:"продвинутая-документация",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#продвинутая-документация"},[t("span",null,"Продвинутая документация")])],-1),p=t("p",null,[t("strong",null,"В этом разделе представлены советы и рекомендации по использованию Xray для продвинутых пользователей. Если вы уже знакомы с Xray, то информация, представленная здесь, поможет вам использовать Xray по максимуму.")],-1),d=t("img",{src:"https://avatars2.githubusercontent.com/u/57820613?s=32",width:"32",height:"32",alt:"a"},null,-1),m={href:"https://github.com/kirin10000",target:"_blank",rel:"noopener noreferrer"},g=t("p",null,"Вводная статья о прозрачном проксировании.",-1),f=t("img",{src:"https://avatars2.githubusercontent.com/u/41363844?s=32",width:"32",height:"32",alt:"a"},null,-1),b={href:"https://github.com/BioniCosmos",target:"_blank",rel:"noopener noreferrer"},y=t("p",null,"Полное руководство по настройке прозрачного проксирования (TProxy) на основе Xray.",-1),v=t("img",{src:"https://avatars.githubusercontent.com/u/110686480?s=32",width:"32",height:"32",alt:"a"},null,-1),x={href:"https://github.com/SQLimit",target:"_blank",rel:"noopener noreferrer"},k=t("p",null,"Руководство по настройке прозрачного проксирования TProxy (ipv4 и ipv6) на основе Xray.",-1),w=t("img",{src:"https://avatars.githubusercontent.com/u/110686480?s=32",width:"32",height:"32",alt:"a"},null,-1),X={href:"https://github.com/SQLimit",target:"_blank",rel:"noopener noreferrer"},L=t("p",null,"Создание TLS-туннеля с помощью Nginx или Haproxy на стороне клиента и сервера для скрытия отпечатков.",-1),T=t("img",{src:"https://avatars2.githubusercontent.com/u/57820613?s=32",width:"32",height:"32",alt:"a"},null,-1),S={href:"https://github.com/kirin10000",target:"_blank",rel:"noopener noreferrer"},B=t("p",null,"Новый способ исключения трафика Xray при реализации прозрачного проксирования с помощью iptables/nftables.",-1),C=t("img",{src:"https://avatars.githubusercontent.com/u/28607089?s=32",width:"32",height:"32",alt:"a"},null,-1),I={href:"https://github.com/Zzz3m",target:"_blank",rel:"noopener noreferrer"},N=t("p",null,'Использование Xray по максимуму: реализация "разделения" трафика на основе fwmark, sendThrough или sockopt.interface.',-1),z=t("img",{src:"https://avatars.githubusercontent.com/u/1588741?s=32",width:"32",height:"32",alt:"a"},null,-1),P={href:"https://github.com/yuhan6665",target:"_blank",rel:"noopener noreferrer"},Q=t("p",null,"Введение в использование исходящего подключения WireGuard, добавленного в Xray v1.6.5.",-1),E=t("img",{src:"https://avatars.githubusercontent.com/u/1588741?s=32",width:"32",height:"32",alt:"a"},null,-1),V={href:"https://github.com/yuhan6665",target:"_blank",rel:"noopener noreferrer"},G=t("p",null,"Статистика трафика и скрипты для Xray.",-1);function H(R,W){const l=a("I18nTip"),o=a("RouterLink"),r=a("ExternalLinkIcon");return h(),u("div",null,[n(l),c,p,t("p",null,[n(o,{to:"/ru/document/level-2/transparent_proxy/transparent_proxy.html"},{default:s(()=>[e("Введение в прозрачное проксирование")]),_:1}),e(" от "),d,e(),t("a",m,[e("@kirin"),n(r)])]),g,t("p",null,[n(o,{to:"/ru/document/level-2/tproxy.html"},{default:s(()=>[e("Руководство по настройке прозрачного проксирования (TProxy) ")]),_:1}),e(" от "),f,e(),t("a",b,[e("@BioniCosmos"),n(r)])]),y,t("p",null,[n(o,{to:"/ru/document/level-2/tproxy_ipv4_and_ipv6.html"},{default:s(()=>[e("Руководство по настройке прозрачного проксирования TProxy (ipv4 и ipv6)")]),_:1}),e(" от "),v,e(),t("a",x,[e("@SQLimit"),n(r)])]),k,t("p",null,[n(o,{to:"/ru/document/level-2/nginx_or_haproxy_tls_tunnel.html"},{default:s(()=>[e("Создание TLS-туннеля с помощью Nginx или Haproxy для скрытия отпечатков")]),_:1}),e(" от "),w,e(),t("a",X,[e("@SQLimit"),n(r)])]),L,t("p",null,[n(o,{to:"/ru/document/level-2/iptables_gid.html"},{default:s(()=>[e("[Прозрачное проксирование] Исключение трафика Xray с помощью GID")]),_:1}),e(" от "),T,e(),t("a",S,[e("@kirin"),n(r)])]),B,t("p",null,[n(o,{to:"/ru/document/level-2/redirect.html"},{default:s(()=>[e('Направление определенного трафика через определенный выходной узел с помощью Xray для реализации "разделения" глобальной маршрутизации')]),_:1}),e(" от "),C,e(),t("a",I,[e("@Zzz3m"),n(r)])]),N,t("p",null,[n(o,{to:"/ru/document/level-2/warp.html"},{default:s(()=>[e("Повышение безопасности проксирования с помощью Cloudflare Warp")]),_:1}),e(" от "),z,e(),t("a",P,[e("@yuhan6665"),n(r)])]),Q,t("p",null,[n(o,{to:"/ru/document/level-2/traffic_stats.html"},{default:s(()=>[e("Статистика трафика Xray")]),_:1}),e(" от "),E,e(),t("a",V,[e("@yuhan6665"),n(r)])]),G])}const D=i(_,[["render",H],["__file","index.html.vue"]]);export{D as default};
                                      +import{_ as i,r as a,o as h,c as u,a as n,b as t,w as s,d as e}from"./app-D7uBbsY3.js";const _={},c=t("h1",{id:"продвинутая-документация",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#продвинутая-документация"},[t("span",null,"Продвинутая документация")])],-1),p=t("p",null,[t("strong",null,"В этом разделе представлены советы и рекомендации по использованию Xray для продвинутых пользователей. Если вы уже знакомы с Xray, то информация, представленная здесь, поможет вам использовать Xray по максимуму.")],-1),d=t("img",{src:"https://avatars2.githubusercontent.com/u/57820613?s=32",width:"32",height:"32",alt:"a"},null,-1),m={href:"https://github.com/kirin10000",target:"_blank",rel:"noopener noreferrer"},g=t("p",null,"Вводная статья о прозрачном проксировании.",-1),f=t("img",{src:"https://avatars2.githubusercontent.com/u/41363844?s=32",width:"32",height:"32",alt:"a"},null,-1),b={href:"https://github.com/BioniCosmos",target:"_blank",rel:"noopener noreferrer"},y=t("p",null,"Полное руководство по настройке прозрачного проксирования (TProxy) на основе Xray.",-1),v=t("img",{src:"https://avatars.githubusercontent.com/u/110686480?s=32",width:"32",height:"32",alt:"a"},null,-1),x={href:"https://github.com/SQLimit",target:"_blank",rel:"noopener noreferrer"},k=t("p",null,"Руководство по настройке прозрачного проксирования TProxy (ipv4 и ipv6) на основе Xray.",-1),w=t("img",{src:"https://avatars.githubusercontent.com/u/110686480?s=32",width:"32",height:"32",alt:"a"},null,-1),X={href:"https://github.com/SQLimit",target:"_blank",rel:"noopener noreferrer"},L=t("p",null,"Создание TLS-туннеля с помощью Nginx или Haproxy на стороне клиента и сервера для скрытия отпечатков.",-1),T=t("img",{src:"https://avatars2.githubusercontent.com/u/57820613?s=32",width:"32",height:"32",alt:"a"},null,-1),S={href:"https://github.com/kirin10000",target:"_blank",rel:"noopener noreferrer"},B=t("p",null,"Новый способ исключения трафика Xray при реализации прозрачного проксирования с помощью iptables/nftables.",-1),C=t("img",{src:"https://avatars.githubusercontent.com/u/28607089?s=32",width:"32",height:"32",alt:"a"},null,-1),I={href:"https://github.com/Zzz3m",target:"_blank",rel:"noopener noreferrer"},N=t("p",null,'Использование Xray по максимуму: реализация "разделения" трафика на основе fwmark, sendThrough или sockopt.interface.',-1),z=t("img",{src:"https://avatars.githubusercontent.com/u/1588741?s=32",width:"32",height:"32",alt:"a"},null,-1),P={href:"https://github.com/yuhan6665",target:"_blank",rel:"noopener noreferrer"},Q=t("p",null,"Введение в использование исходящего подключения WireGuard, добавленного в Xray v1.6.5.",-1),E=t("img",{src:"https://avatars.githubusercontent.com/u/1588741?s=32",width:"32",height:"32",alt:"a"},null,-1),V={href:"https://github.com/yuhan6665",target:"_blank",rel:"noopener noreferrer"},G=t("p",null,"Статистика трафика и скрипты для Xray.",-1);function H(R,W){const l=a("I18nTip"),o=a("RouterLink"),r=a("ExternalLinkIcon");return h(),u("div",null,[n(l),c,p,t("p",null,[n(o,{to:"/ru/document/level-2/transparent_proxy/transparent_proxy.html"},{default:s(()=>[e("Введение в прозрачное проксирование")]),_:1}),e(" от "),d,e(),t("a",m,[e("@kirin"),n(r)])]),g,t("p",null,[n(o,{to:"/ru/document/level-2/tproxy.html"},{default:s(()=>[e("Руководство по настройке прозрачного проксирования (TProxy) ")]),_:1}),e(" от "),f,e(),t("a",b,[e("@BioniCosmos"),n(r)])]),y,t("p",null,[n(o,{to:"/ru/document/level-2/tproxy_ipv4_and_ipv6.html"},{default:s(()=>[e("Руководство по настройке прозрачного проксирования TProxy (ipv4 и ipv6)")]),_:1}),e(" от "),v,e(),t("a",x,[e("@SQLimit"),n(r)])]),k,t("p",null,[n(o,{to:"/ru/document/level-2/nginx_or_haproxy_tls_tunnel.html"},{default:s(()=>[e("Создание TLS-туннеля с помощью Nginx или Haproxy для скрытия отпечатков")]),_:1}),e(" от "),w,e(),t("a",X,[e("@SQLimit"),n(r)])]),L,t("p",null,[n(o,{to:"/ru/document/level-2/iptables_gid.html"},{default:s(()=>[e("[Прозрачное проксирование] Исключение трафика Xray с помощью GID")]),_:1}),e(" от "),T,e(),t("a",S,[e("@kirin"),n(r)])]),B,t("p",null,[n(o,{to:"/ru/document/level-2/redirect.html"},{default:s(()=>[e('Направление определенного трафика через определенный выходной узел с помощью Xray для реализации "разделения" глобальной маршрутизации')]),_:1}),e(" от "),C,e(),t("a",I,[e("@Zzz3m"),n(r)])]),N,t("p",null,[n(o,{to:"/ru/document/level-2/warp.html"},{default:s(()=>[e("Повышение безопасности проксирования с помощью Cloudflare Warp")]),_:1}),e(" от "),z,e(),t("a",P,[e("@yuhan6665"),n(r)])]),Q,t("p",null,[n(o,{to:"/ru/document/level-2/traffic_stats.html"},{default:s(()=>[e("Статистика трафика Xray")]),_:1}),e(" от "),E,e(),t("a",V,[e("@yuhan6665"),n(r)])]),G])}const D=i(_,[["render",H],["__file","index.html.vue"]]);export{D as default};
                                      diff --git a/assets/index.html-EU8APivD.js b/assets/index.html-BWRtCA19.js
                                      similarity index 96%
                                      rename from assets/index.html-EU8APivD.js
                                      rename to assets/index.html-BWRtCA19.js
                                      index fe6e026226..91088e0eed 100644
                                      --- a/assets/index.html-EU8APivD.js
                                      +++ b/assets/index.html-BWRtCA19.js
                                      @@ -1 +1 @@
                                      -import{_ as u,r as a,o as c,c as s,a as t,b as e,w as n,d as o}from"./app-DBM4OJyw.js";const d={},_=e("h1",{id:"советы-для-начинающих",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#советы-для-начинающих"},[e("span",null,"Советы для начинающих")])],-1),i=e("p",null,[e("strong",null,"В этой главе вы найдете советы по использованию Xray для начинающих, в основном с описанием принципов работы часто используемых модулей Xray.")],-1);function m(p,h){const r=a("I18nTip"),l=a("RouterLink");return c(),s("div",null,[t(r),_,i,e("p",null,[t(l,{to:"/ru/document/level-1/fallbacks-lv1.html"},{default:n(()=>[o("Обзор функции Fallback")]),_:1})]),e("p",null,[t(l,{to:"/ru/document/level-1/routing-lv1-part1.html"},{default:n(()=>[o("Обзор функции маршрутизации (routing) (часть 1)")]),_:1})]),e("p",null,[t(l,{to:"/ru/document/level-1/routing-lv1-part2.html"},{default:n(()=>[o("Обзор функции маршрутизации (routing) (часть 2)")]),_:1})]),e("p",null,[t(l,{to:"/ru/document/level-1/work.html"},{default:n(()=>[o("Обзор режимов работы Xray")]),_:1})]),e("p",null,[t(l,{to:"/ru/document/level-1/fallbacks-with-sni.html"},{default:n(()=>[o("Маскировка и разделение трафика по доменам с помощью функции SNI Fallback")]),_:1})])])}const v=u(d,[["render",m],["__file","index.html.vue"]]);export{v as default};
                                      +import{_ as u,r as a,o as c,c as s,a as t,b as e,w as n,d as o}from"./app-D7uBbsY3.js";const d={},_=e("h1",{id:"советы-для-начинающих",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#советы-для-начинающих"},[e("span",null,"Советы для начинающих")])],-1),i=e("p",null,[e("strong",null,"В этой главе вы найдете советы по использованию Xray для начинающих, в основном с описанием принципов работы часто используемых модулей Xray.")],-1);function m(p,h){const r=a("I18nTip"),l=a("RouterLink");return c(),s("div",null,[t(r),_,i,e("p",null,[t(l,{to:"/ru/document/level-1/fallbacks-lv1.html"},{default:n(()=>[o("Обзор функции Fallback")]),_:1})]),e("p",null,[t(l,{to:"/ru/document/level-1/routing-lv1-part1.html"},{default:n(()=>[o("Обзор функции маршрутизации (routing) (часть 1)")]),_:1})]),e("p",null,[t(l,{to:"/ru/document/level-1/routing-lv1-part2.html"},{default:n(()=>[o("Обзор функции маршрутизации (routing) (часть 2)")]),_:1})]),e("p",null,[t(l,{to:"/ru/document/level-1/work.html"},{default:n(()=>[o("Обзор режимов работы Xray")]),_:1})]),e("p",null,[t(l,{to:"/ru/document/level-1/fallbacks-with-sni.html"},{default:n(()=>[o("Маскировка и разделение трафика по доменам с помощью функции SNI Fallback")]),_:1})])])}const v=u(d,[["render",m],["__file","index.html.vue"]]);export{v as default};
                                      diff --git a/assets/index.html-Cprk0yv3.js b/assets/index.html-BjEZWu-b.js
                                      similarity index 99%
                                      rename from assets/index.html-Cprk0yv3.js
                                      rename to assets/index.html-BjEZWu-b.js
                                      index e984e6edde..21e89a23b4 100644
                                      --- a/assets/index.html-Cprk0yv3.js
                                      +++ b/assets/index.html-BjEZWu-b.js
                                      @@ -1 +1 @@
                                      -import{_ as s,r as l,o as i,c,a as t,b as e,d as r,w as h,e as u}from"./app-DBM4OJyw.js";const _={},d=u('

                                      XTLS? Xray? V2Ray?

                                      XTLS — это блестящая идея для TLS, которую мы изучаем, в то время как Xray — это лучшая практика, которую мы поддерживаем.

                                      • Xray-core - это расширенная версия v2ray-core с улучшенной общей производительностью, включающая XTLS и другие улучшения. Xray-core полностью совместим с функциональностью и конфигурацией v2ray-core.
                                        • Только один исполняемый файл, включающий функциональность ctl, команда run используется по умолчанию.
                                        • Конфигурация полностью совместима, переменные среды и вызовы API должны начинаться с XRAY_
                                        • Открытый raw протокол ReadV на всех платформах.
                                        • Обеспечивает полную поддержку VLESS и Trojan XTLS, обе с ReadV.
                                        • Предоставляет несколько режимов управления потоком XTLS, непревзойденная производительность!

                                      Конфигурация без изменений, результат — значительно лучше.

                                      Кто мы?

                                      Неважно, кто мы. Важно то, что мы будем продолжать двигаться вперед и никогда не оглядываться назад.

                                      Помогите Xray стать сильнее

                                      Мы будем рады вашей помощи в развитии Xray!

                                      ',8),p=e("li",null,"🖥️ Помогите в разработке и тестировании Xray, отправляйте качественные запросы на включение (Pull Request).",-1),X={href:"https://github.com/XTLS/Xray-core/issues",target:"_blank",rel:"noopener noreferrer"},f={href:"https://github.com/XTLS/Xray-core/discussions",target:"_blank",rel:"noopener noreferrer"},b={href:"https://github.com/XTLS/Xray-docs-next",target:"_blank",rel:"noopener noreferrer"},g=e("li",null,"💬 Помогите участникам группы / общайтесь в группе Telegram.",-1),m=e("li",null,[e("strong",null,"... На самом деле, любая поддержка Xray сделает его сильнее.")],-1),y=e("h3",{id:"telegram",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#telegram"},[e("span",null,"Telegram")])],-1),x={href:"https://t.me/projectXray",target:"_blank",rel:"noopener noreferrer"},k=e("ul",null,[e("li",null,"В группе обсуждения можно свободно общаться, не допускаются оскорбления и злоупотребления."),e("li",null,"Не стесняйтесь задавать вопросы, а если знаете ответ - помогите другим."),e("li",null,"Запрещены политика и контент для взрослых (NSFW).")],-1),T={href:"https://t.me/projectVless",target:"_blank",rel:"noopener noreferrer"},S={href:"https://t.me/projectXray",target:"_blank",rel:"noopener noreferrer"},L=e("li",null,"No advertising, No insults, No politics.",-1),j={href:"https://t.me/projectXtls",target:"_blank",rel:"noopener noreferrer"},P=e("ul",null,[e("li",null,"Публикация последних новостей о Project X.")],-1),N=e("h3",{id:"благодарности",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#благодарности"},[e("span",null,"Благодарности")])],-1),v=e("ul",null,[e("li",null,"Спасибо всем за вашу поддержку!"),e("li",null,"Спасибо создателям всевозможных скриптов, образов Docker, клиентам... Спасибо всем, кто помогает улучшать экосистему!"),e("li",null,"Спасибо всем, кто вносит свой вклад в веб-сайт и документацию Xray."),e("li",null,"Спасибо всем, кто высказывает ценные предложения и замечания."),e("li",null,"Спасибо каждому участнику группы Telegram, который помогает другим.")],-1),V=e("h3",{id:"подробнее-о-project-x",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#подробнее-о-project-x"},[e("span",null,"Подробнее о Project X")])],-1),I={href:"https://github.com/XTLS/Xray-core/discussions/3633#discussioncomment-10231076",target:"_blank",rel:"noopener noreferrer"},w=e("h3",{id:"лицензия",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#лицензия"},[e("span",null,"Лицензия")])],-1),E={href:"https://github.com/XTLS/Xray-core/blob/main/LICENSE",target:"_blank",rel:"noopener noreferrer"},R=e("h3",{id:"динамика-звезд-на-github",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#динамика-звезд-на-github"},[e("span",null,"Динамика звезд на GitHub")])],-1),q={href:"https://starchart.cc/XTLS/Xray-core",target:"_blank",rel:"noopener noreferrer"},C=e("img",{src:"https://starchart.cc/XTLS/Xray-core.svg",alt:"Stargazers over time"},null,-1);function B(F,G){const n=l("I18nTip"),o=l("ExternalLinkIcon"),a=l("RouterLink");return i(),c("div",null,[t(n),d,e("ul",null,[p,e("li",null,[r("📩 Создавайте конструктивные или важные задачи и обсуждения в "),e("a",X,[r("GitHub Issues"),t(o)]),r(" или "),e("a",f,[r("Discussion area"),t(o)]),r(".")]),e("li",null,[r("📝 Поделитесь своим опытом использования и отправьте его на "),e("a",b,[r("сайт документации"),t(o)]),r(" Xray.")]),g,m]),y,e("ul",null,[e("li",null,[e("p",null,[e("a",x,[r("Группа обсуждения Project X"),t(o)])]),k]),e("li",null,[e("p",null,[e("a",T,[r("Project VLESS Group"),t(o)])]),e("ul",null,[e("li",null,[r("The official Xray-core group for non-Chinese participants. Sister group of "),e("a",S,[r("Project X"),t(o)])]),L])]),e("li",null,[e("p",null,[e("a",j,[r("Канал Project X"),t(o)])]),P])]),N,v,V,e("ul",null,[e("li",null,[r("Если вы хотите узнать больше об истории и развитии Project X, нажмите "),t(a,{to:"/ru/about/news.html"},{default:h(()=>[r("здесь")]),_:1})]),e("li",null,[r("Now Project X releases NFTs! If you would like to have one Project X NFT, or want to donate to or sponsoring Project X, please click "),e("a",I,[r("here"),t(o)])])]),w,e("p",null,[e("a",E,[r("Mozilla Public License Version 2.0"),t(o)])]),R,e("p",null,[e("a",q,[C,t(o)])])])}const A=s(_,[["render",B],["__file","index.html.vue"]]);export{A as default}; +import{_ as s,r as l,o as i,c,a as t,b as e,d as r,w as h,e as u}from"./app-D7uBbsY3.js";const _={},d=u('

                                      XTLS? Xray? V2Ray?

                                      XTLS — это блестящая идея для TLS, которую мы изучаем, в то время как Xray — это лучшая практика, которую мы поддерживаем.

                                      • Xray-core - это расширенная версия v2ray-core с улучшенной общей производительностью, включающая XTLS и другие улучшения. Xray-core полностью совместим с функциональностью и конфигурацией v2ray-core.
                                        • Только один исполняемый файл, включающий функциональность ctl, команда run используется по умолчанию.
                                        • Конфигурация полностью совместима, переменные среды и вызовы API должны начинаться с XRAY_
                                        • Открытый raw протокол ReadV на всех платформах.
                                        • Обеспечивает полную поддержку VLESS и Trojan XTLS, обе с ReadV.
                                        • Предоставляет несколько режимов управления потоком XTLS, непревзойденная производительность!

                                      Конфигурация без изменений, результат — значительно лучше.

                                      Кто мы?

                                      Неважно, кто мы. Важно то, что мы будем продолжать двигаться вперед и никогда не оглядываться назад.

                                      Помогите Xray стать сильнее

                                      Мы будем рады вашей помощи в развитии Xray!

                                      ',8),p=e("li",null,"🖥️ Помогите в разработке и тестировании Xray, отправляйте качественные запросы на включение (Pull Request).",-1),X={href:"https://github.com/XTLS/Xray-core/issues",target:"_blank",rel:"noopener noreferrer"},f={href:"https://github.com/XTLS/Xray-core/discussions",target:"_blank",rel:"noopener noreferrer"},b={href:"https://github.com/XTLS/Xray-docs-next",target:"_blank",rel:"noopener noreferrer"},g=e("li",null,"💬 Помогите участникам группы / общайтесь в группе Telegram.",-1),m=e("li",null,[e("strong",null,"... На самом деле, любая поддержка Xray сделает его сильнее.")],-1),y=e("h3",{id:"telegram",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#telegram"},[e("span",null,"Telegram")])],-1),x={href:"https://t.me/projectXray",target:"_blank",rel:"noopener noreferrer"},k=e("ul",null,[e("li",null,"В группе обсуждения можно свободно общаться, не допускаются оскорбления и злоупотребления."),e("li",null,"Не стесняйтесь задавать вопросы, а если знаете ответ - помогите другим."),e("li",null,"Запрещены политика и контент для взрослых (NSFW).")],-1),T={href:"https://t.me/projectVless",target:"_blank",rel:"noopener noreferrer"},S={href:"https://t.me/projectXray",target:"_blank",rel:"noopener noreferrer"},L=e("li",null,"No advertising, No insults, No politics.",-1),j={href:"https://t.me/projectXtls",target:"_blank",rel:"noopener noreferrer"},P=e("ul",null,[e("li",null,"Публикация последних новостей о Project X.")],-1),N=e("h3",{id:"благодарности",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#благодарности"},[e("span",null,"Благодарности")])],-1),v=e("ul",null,[e("li",null,"Спасибо всем за вашу поддержку!"),e("li",null,"Спасибо создателям всевозможных скриптов, образов Docker, клиентам... Спасибо всем, кто помогает улучшать экосистему!"),e("li",null,"Спасибо всем, кто вносит свой вклад в веб-сайт и документацию Xray."),e("li",null,"Спасибо всем, кто высказывает ценные предложения и замечания."),e("li",null,"Спасибо каждому участнику группы Telegram, который помогает другим.")],-1),V=e("h3",{id:"подробнее-о-project-x",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#подробнее-о-project-x"},[e("span",null,"Подробнее о Project X")])],-1),I={href:"https://github.com/XTLS/Xray-core/discussions/3633#discussioncomment-10231076",target:"_blank",rel:"noopener noreferrer"},w=e("h3",{id:"лицензия",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#лицензия"},[e("span",null,"Лицензия")])],-1),E={href:"https://github.com/XTLS/Xray-core/blob/main/LICENSE",target:"_blank",rel:"noopener noreferrer"},R=e("h3",{id:"динамика-звезд-на-github",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#динамика-звезд-на-github"},[e("span",null,"Динамика звезд на GitHub")])],-1),q={href:"https://starchart.cc/XTLS/Xray-core",target:"_blank",rel:"noopener noreferrer"},C=e("img",{src:"https://starchart.cc/XTLS/Xray-core.svg",alt:"Stargazers over time"},null,-1);function B(F,G){const n=l("I18nTip"),o=l("ExternalLinkIcon"),a=l("RouterLink");return i(),c("div",null,[t(n),d,e("ul",null,[p,e("li",null,[r("📩 Создавайте конструктивные или важные задачи и обсуждения в "),e("a",X,[r("GitHub Issues"),t(o)]),r(" или "),e("a",f,[r("Discussion area"),t(o)]),r(".")]),e("li",null,[r("📝 Поделитесь своим опытом использования и отправьте его на "),e("a",b,[r("сайт документации"),t(o)]),r(" Xray.")]),g,m]),y,e("ul",null,[e("li",null,[e("p",null,[e("a",x,[r("Группа обсуждения Project X"),t(o)])]),k]),e("li",null,[e("p",null,[e("a",T,[r("Project VLESS Group"),t(o)])]),e("ul",null,[e("li",null,[r("The official Xray-core group for non-Chinese participants. Sister group of "),e("a",S,[r("Project X"),t(o)])]),L])]),e("li",null,[e("p",null,[e("a",j,[r("Канал Project X"),t(o)])]),P])]),N,v,V,e("ul",null,[e("li",null,[r("Если вы хотите узнать больше об истории и развитии Project X, нажмите "),t(a,{to:"/ru/about/news.html"},{default:h(()=>[r("здесь")]),_:1})]),e("li",null,[r("Now Project X releases NFTs! If you would like to have one Project X NFT, or want to donate to or sponsoring Project X, please click "),e("a",I,[r("here"),t(o)])])]),w,e("p",null,[e("a",E,[r("Mozilla Public License Version 2.0"),t(o)])]),R,e("p",null,[e("a",q,[C,t(o)])])])}const A=s(_,[["render",B],["__file","index.html.vue"]]);export{A as default}; diff --git a/assets/index.html-DcKrVYG-.js b/assets/index.html-C4GmwqWT.js similarity index 99% rename from assets/index.html-DcKrVYG-.js rename to assets/index.html-C4GmwqWT.js index 48d5526080..4075911945 100644 --- a/assets/index.html-DcKrVYG-.js +++ b/assets/index.html-C4GmwqWT.js @@ -1,4 +1,4 @@ -import{_ as l,r as e,o as u,c,a as t,b as n,d as s,w as o,e as r}from"./app-DBM4OJyw.js";const i={},d=r(`

                                      В этом разделе вы узнаете все детали настройки Xray. Овладев этими знаниями, вы сможете раскрыть весь потенциал Xray.

                                      Обзор

                                      Конфигурационный файл Xray имеет формат JSON. Формат конфигурации одинаков для клиента и сервера, но фактическое содержимое отличается.
                                      Он выглядит следующим образом:

                                      {
                                      +import{_ as l,r as e,o as u,c,a as t,b as n,d as s,w as o,e as r}from"./app-D7uBbsY3.js";const i={},d=r(`

                                      В этом разделе вы узнаете все детали настройки Xray. Овладев этими знаниями, вы сможете раскрыть весь потенциал Xray.

                                      Обзор

                                      Конфигурационный файл Xray имеет формат JSON. Формат конфигурации одинаков для клиента и сервера, но фактическое содержимое отличается.
                                      Он выглядит следующим образом:

                                      {
                                         "log": {},
                                         "api": {},
                                         "dns": {},
                                      diff --git a/assets/index.html-BYpCGpl_.js b/assets/index.html-C7UV3jAp.js
                                      similarity index 94%
                                      rename from assets/index.html-BYpCGpl_.js
                                      rename to assets/index.html-C7UV3jAp.js
                                      index 0938279994..7cb88f4fc1 100644
                                      --- a/assets/index.html-BYpCGpl_.js
                                      +++ b/assets/index.html-C7UV3jAp.js
                                      @@ -1 +1 @@
                                      -import{_ as i,r as s,o as r,c,a as e,b as n,w as l,d as o}from"./app-DBM4OJyw.js";const u={},d=n("h1",{id:"beginner-s-tips",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#beginner-s-tips"},[n("span",null,"Beginner's Tips")])],-1),m=n("p",null,[n("strong",null,"This chapter is an introductory level guide on using Xray, mainly sharing the principles of some commonly used functional modules in Xray.")],-1);function _(p,f){const a=s("I18nTip"),t=s("RouterLink");return r(),c("div",null,[e(a),d,m,n("p",null,[e(t,{to:"/en/document/level-1/fallbacks-lv1.html"},{default:l(()=>[o("Analysis of Fallbacks Function")]),_:1})]),n("p",null,[e(t,{to:"/en/document/level-1/routing-lv1-part1.html"},{default:l(()=>[o("Analysis of Routing Function (Part 1)")]),_:1})]),n("p",null,[e(t,{to:"/en/document/level-1/routing-lv1-part2.html"},{default:l(()=>[o("Analysis of Routing Function (Part 2)")]),_:1})]),n("p",null,[e(t,{to:"/en/document/level-1/work.html"},{default:l(()=>[o("Analysis of Xray's Working Mode")]),_:1})]),n("p",null,[e(t,{to:"/en/document/level-1/fallbacks-with-sni.html"},{default:l(()=>[o("Fallbacks with SNI for Disguising and Domain-based Routing")]),_:1})])])}const g=i(u,[["render",_],["__file","index.html.vue"]]);export{g as default};
                                      +import{_ as i,r as s,o as r,c,a as e,b as n,w as l,d as o}from"./app-D7uBbsY3.js";const u={},d=n("h1",{id:"beginner-s-tips",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#beginner-s-tips"},[n("span",null,"Beginner's Tips")])],-1),m=n("p",null,[n("strong",null,"This chapter is an introductory level guide on using Xray, mainly sharing the principles of some commonly used functional modules in Xray.")],-1);function _(p,f){const a=s("I18nTip"),t=s("RouterLink");return r(),c("div",null,[e(a),d,m,n("p",null,[e(t,{to:"/en/document/level-1/fallbacks-lv1.html"},{default:l(()=>[o("Analysis of Fallbacks Function")]),_:1})]),n("p",null,[e(t,{to:"/en/document/level-1/routing-lv1-part1.html"},{default:l(()=>[o("Analysis of Routing Function (Part 1)")]),_:1})]),n("p",null,[e(t,{to:"/en/document/level-1/routing-lv1-part2.html"},{default:l(()=>[o("Analysis of Routing Function (Part 2)")]),_:1})]),n("p",null,[e(t,{to:"/en/document/level-1/work.html"},{default:l(()=>[o("Analysis of Xray's Working Mode")]),_:1})]),n("p",null,[e(t,{to:"/en/document/level-1/fallbacks-with-sni.html"},{default:l(()=>[o("Fallbacks with SNI for Disguising and Domain-based Routing")]),_:1})])])}const g=i(u,[["render",_],["__file","index.html.vue"]]);export{g as default};
                                      diff --git a/assets/index.html-BZQpQc5L.js b/assets/index.html-CEGHaj0m.js
                                      similarity index 98%
                                      rename from assets/index.html-BZQpQc5L.js
                                      rename to assets/index.html-CEGHaj0m.js
                                      index a774388ff4..733edbba80 100644
                                      --- a/assets/index.html-BZQpQc5L.js
                                      +++ b/assets/index.html-CEGHaj0m.js
                                      @@ -1 +1 @@
                                      -import{_ as r,r as l,o as d,c as h,a as t,b as e,d as o,w as s}from"./app-DBM4OJyw.js";const _={},i=e("h1",{id:"开发指南",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#开发指南"},[e("span",null,"开发指南")])],-1),p=e("h2",{id:"编译文档",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#编译文档"},[e("span",null,"编译文档")])],-1),u=e("p",null,"Xray 支持各种平台, 您可以在多种平台上自行进行交叉编译。",-1),m=e("h2",{id:"设计思路",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#设计思路"},[e("span",null,"设计思路")])],-1),f=e("p",null,"Xray 内核提供了一个平台,在其之上可以进二次开发。",-1),x=e("p",null,"这个章节阐述了 Xray 的设计目标和架构。",-1),v=e("h2",{id:"开发规范",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#开发规范"},[e("span",null,"开发规范")])],-1),b=e("p",null,"这个章节阐述了获取代码,进行开发,提交 PR 的流程中需要遵循的准则, 以及相关的编码规范。",-1),k=e("h2",{id:"协议详解",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#协议详解"},[e("span",null,"协议详解")])],-1),y=e("p",null,"Xray 用到了很多种协议, 您可以通过各种途径获得协议的详细描述。",-1),X={id:"vless-协议",tabindex:"-1"},C={class:"header-anchor",href:"#vless-协议"},V=e("p",null,"VLESS 是一个无状态的轻量传输协议,可以作为 Xray 客户端和服务器之间的桥梁。",-1),L={id:"vmess-协议",tabindex:"-1"},E={class:"header-anchor",href:"#vmess-协议"},g=e("p",null,"VMess 是一个加密传输协议,可以作为 Xray 客户端和服务器之间的桥梁。",-1),I={id:"mux-cool-协议",tabindex:"-1"},M={class:"header-anchor",href:"#mux-cool-协议"},P=e("p",null,"Mux.Cool 协议是一个多路复用传输协议,用于在一条已建立的数据流中传输多个各自独立的数据流。",-1),S={id:"mkcp-协议",tabindex:"-1"},w={class:"header-anchor",href:"#mkcp-协议"},B={href:"https://github.com/skywind3000/kcp",target:"_blank",rel:"noopener noreferrer"};function K(N,R){const a=l("I18nTip"),n=l("RouterLink"),c=l("ExternalLinkIcon");return d(),h("div",null,[t(a),i,p,u,e("p",null,[o("请点击"),t(n,{to:"/ru/development/intro/compile.html"},{default:s(()=>[o("编译文档")]),_:1}),o("以查看具体编译相关内容。")]),m,f,x,e("p",null,[o("请点击"),t(n,{to:"/ru/development/intro/design.html"},{default:s(()=>[o("设计思路")]),_:1}),o("以了解 Xray 的设计目标和架构。")]),v,b,e("p",null,[o("请点击"),t(n,{to:"/ru/development/intro/guide.html"},{default:s(()=>[o("开发规范")]),_:1}),o("查看 Xray 开发中应遵循的准则。")]),k,y,e("h3",X,[e("a",C,[e("span",null,[t(n,{to:"/ru/development/protocols/vless.html"},{default:s(()=>[o("VLESS 协议")]),_:1})])])]),V,e("h3",L,[e("a",E,[e("span",null,[t(n,{to:"/ru/development/protocols/vmess.html"},{default:s(()=>[o("VMess 协议")]),_:1})])])]),g,e("h3",I,[e("a",M,[e("span",null,[t(n,{to:"/ru/development/protocols/muxcool.html"},{default:s(()=>[o("Mux.Cool 协议")]),_:1})])])]),P,e("h3",S,[e("a",w,[e("span",null,[t(n,{to:"/ru/development/protocols/mkcp.html"},{default:s(()=>[o("mKCP 协议")]),_:1})])])]),e("p",null,[o("mKCP 是流式传输协议,由 "),e("a",B,[o("KCP 协议"),t(c)]),o("修改而来,可以按顺序传输任意的数据流。")])])}const j=r(_,[["render",K],["__file","index.html.vue"]]);export{j as default};
                                      +import{_ as r,r as l,o as d,c as h,a as t,b as e,d as o,w as s}from"./app-D7uBbsY3.js";const _={},i=e("h1",{id:"开发指南",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#开发指南"},[e("span",null,"开发指南")])],-1),p=e("h2",{id:"编译文档",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#编译文档"},[e("span",null,"编译文档")])],-1),u=e("p",null,"Xray 支持各种平台, 您可以在多种平台上自行进行交叉编译。",-1),m=e("h2",{id:"设计思路",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#设计思路"},[e("span",null,"设计思路")])],-1),f=e("p",null,"Xray 内核提供了一个平台,在其之上可以进二次开发。",-1),x=e("p",null,"这个章节阐述了 Xray 的设计目标和架构。",-1),v=e("h2",{id:"开发规范",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#开发规范"},[e("span",null,"开发规范")])],-1),b=e("p",null,"这个章节阐述了获取代码,进行开发,提交 PR 的流程中需要遵循的准则, 以及相关的编码规范。",-1),k=e("h2",{id:"协议详解",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#协议详解"},[e("span",null,"协议详解")])],-1),y=e("p",null,"Xray 用到了很多种协议, 您可以通过各种途径获得协议的详细描述。",-1),X={id:"vless-协议",tabindex:"-1"},C={class:"header-anchor",href:"#vless-协议"},V=e("p",null,"VLESS 是一个无状态的轻量传输协议,可以作为 Xray 客户端和服务器之间的桥梁。",-1),L={id:"vmess-协议",tabindex:"-1"},E={class:"header-anchor",href:"#vmess-协议"},g=e("p",null,"VMess 是一个加密传输协议,可以作为 Xray 客户端和服务器之间的桥梁。",-1),I={id:"mux-cool-协议",tabindex:"-1"},M={class:"header-anchor",href:"#mux-cool-协议"},P=e("p",null,"Mux.Cool 协议是一个多路复用传输协议,用于在一条已建立的数据流中传输多个各自独立的数据流。",-1),S={id:"mkcp-协议",tabindex:"-1"},w={class:"header-anchor",href:"#mkcp-协议"},B={href:"https://github.com/skywind3000/kcp",target:"_blank",rel:"noopener noreferrer"};function K(N,R){const a=l("I18nTip"),n=l("RouterLink"),c=l("ExternalLinkIcon");return d(),h("div",null,[t(a),i,p,u,e("p",null,[o("请点击"),t(n,{to:"/ru/development/intro/compile.html"},{default:s(()=>[o("编译文档")]),_:1}),o("以查看具体编译相关内容。")]),m,f,x,e("p",null,[o("请点击"),t(n,{to:"/ru/development/intro/design.html"},{default:s(()=>[o("设计思路")]),_:1}),o("以了解 Xray 的设计目标和架构。")]),v,b,e("p",null,[o("请点击"),t(n,{to:"/ru/development/intro/guide.html"},{default:s(()=>[o("开发规范")]),_:1}),o("查看 Xray 开发中应遵循的准则。")]),k,y,e("h3",X,[e("a",C,[e("span",null,[t(n,{to:"/ru/development/protocols/vless.html"},{default:s(()=>[o("VLESS 协议")]),_:1})])])]),V,e("h3",L,[e("a",E,[e("span",null,[t(n,{to:"/ru/development/protocols/vmess.html"},{default:s(()=>[o("VMess 协议")]),_:1})])])]),g,e("h3",I,[e("a",M,[e("span",null,[t(n,{to:"/ru/development/protocols/muxcool.html"},{default:s(()=>[o("Mux.Cool 协议")]),_:1})])])]),P,e("h3",S,[e("a",w,[e("span",null,[t(n,{to:"/ru/development/protocols/mkcp.html"},{default:s(()=>[o("mKCP 协议")]),_:1})])])]),e("p",null,[o("mKCP 是流式传输协议,由 "),e("a",B,[o("KCP 协议"),t(c)]),o("修改而来,可以按顺序传输任意的数据流。")])])}const j=r(_,[["render",K],["__file","index.html.vue"]]);export{j as default};
                                      diff --git a/assets/index.html-BS27sHaP.js b/assets/index.html-CZxj-MAp.js
                                      similarity index 98%
                                      rename from assets/index.html-BS27sHaP.js
                                      rename to assets/index.html-CZxj-MAp.js
                                      index 8d71657512..05b1079392 100644
                                      --- a/assets/index.html-BS27sHaP.js
                                      +++ b/assets/index.html-CZxj-MAp.js
                                      @@ -1 +1 @@
                                      -import{_ as l,r as s,o as i,c as d,a as t,b as e,d as n,w as o}from"./app-DBM4OJyw.js";const c={},u=e("h1",{id:"quick-start",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#quick-start"},[e("span",null,"Quick Start")])],-1),h=e("blockquote",null,[e("p",null,[e("strong",null,"This chapter will tell you how to get Xray in the easiest way and start using Xray.")])],-1),m=e("h2",{id:"download-and-install",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#download-and-install"},[e("span",null,"Download and Install")])],-1),p=e("p",null,"Xray supports various platforms, and you can get various versions of Xray from various sources and methods.",-1),_=e("h2",{id:"configure-and-run",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#configure-and-run"},[e("span",null,"Configure and Run")])],-1),f=e("p",null,"After downloading and installing Xray, you need to configure it.",-1),g=e("h2",{id:"command-parameters",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#command-parameters"},[e("span",null,"Command Parameters")])],-1),v=e("p",null,"Xray has a variety of commands and parameters available, making it flexible and powerful.",-1),y=e("h2",{id:"improve-documents",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#improve-documents"},[e("span",null,"Improve Documents")])],-1),k=e("code",null,"Help us improve this page!",-1),w=e("p",null,"We are very grateful to every Contributor for their contribution! You guys make Project X even stronger!",-1),b=e("h2",{id:"beginner-tutorial",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#beginner-tutorial"},[e("span",null,"Beginner Tutorial")])],-1),x=e("p",null,"An easy tutorial for beginner.",-1),X=e("h2",{id:"getting-started-tips",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#getting-started-tips"},[e("span",null,"Getting Started Tips")])],-1),T=e("h2",{id:"advanced-documentation",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#advanced-documentation"},[e("span",null,"Advanced Documentation")])],-1),C=e("p",null,"Tips for advanced user guidance",-1),P=e("div",{class:"custom-container tip"},[e("p",{class:"custom-container-title"},"Appreciations"),e("p",null,"Thank you very much for your selfless sharing of usage skills and experience, which makes Xray more and more powerful.")],-1);function A(D,I){const r=s("I18nTip"),a=s("RouterLink");return i(),d("div",null,[u,t(r),h,m,p,e("p",null,[n("Please click "),t(a,{to:"/en/document/install.html"},{default:o(()=>[n("How to Download and Install Xray")]),_:1}),n(" to get Xray.")]),_,f,e("p",null,[n("Please click "),t(a,{to:"/en/document/config.html"},{default:o(()=>[n("How to Configure and Run Xray")]),_:1}),n(" to learn the easiest way to configure Xray.")]),g,v,e("p",null,[n("Please click "),t(a,{to:"/en/document/command.html"},{default:o(()=>[n("Command Parameters for Xray")]),_:1}),n(" to view more commands and parameters usages.")]),y,e("p",null,[n("If you're interested, please click "),t(a,{to:"/en/document/document.html"},{default:o(()=>[n("Documents")]),_:1}),n(" to help us improve the documents, or click the "),k]),w,b,x,e("p",null,[n("Please click "),t(a,{to:"/en/document/level-0/"},{default:o(()=>[n("Beginner Tutorial")]),_:1}),n(" to view it.")]),X,e("p",null,[n("After you have the basics, you can explore more ways to use them through "),t(a,{to:"/en/document/level-1/"},{default:o(()=>[n("Getting Started Tips")]),_:1}),n(".")]),T,C,e("p",null,[n("Click on "),t(a,{to:"/en/document/level-2/"},{default:o(()=>[n("Advanced Documentation")]),_:1}),n(" to view it")]),P])}const R=l(c,[["render",A],["__file","index.html.vue"]]);export{R as default};
                                      +import{_ as l,r as s,o as i,c as d,a as t,b as e,d as n,w as o}from"./app-D7uBbsY3.js";const c={},u=e("h1",{id:"quick-start",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#quick-start"},[e("span",null,"Quick Start")])],-1),h=e("blockquote",null,[e("p",null,[e("strong",null,"This chapter will tell you how to get Xray in the easiest way and start using Xray.")])],-1),m=e("h2",{id:"download-and-install",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#download-and-install"},[e("span",null,"Download and Install")])],-1),p=e("p",null,"Xray supports various platforms, and you can get various versions of Xray from various sources and methods.",-1),_=e("h2",{id:"configure-and-run",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#configure-and-run"},[e("span",null,"Configure and Run")])],-1),f=e("p",null,"After downloading and installing Xray, you need to configure it.",-1),g=e("h2",{id:"command-parameters",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#command-parameters"},[e("span",null,"Command Parameters")])],-1),v=e("p",null,"Xray has a variety of commands and parameters available, making it flexible and powerful.",-1),y=e("h2",{id:"improve-documents",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#improve-documents"},[e("span",null,"Improve Documents")])],-1),k=e("code",null,"Help us improve this page!",-1),w=e("p",null,"We are very grateful to every Contributor for their contribution! You guys make Project X even stronger!",-1),b=e("h2",{id:"beginner-tutorial",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#beginner-tutorial"},[e("span",null,"Beginner Tutorial")])],-1),x=e("p",null,"An easy tutorial for beginner.",-1),X=e("h2",{id:"getting-started-tips",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#getting-started-tips"},[e("span",null,"Getting Started Tips")])],-1),T=e("h2",{id:"advanced-documentation",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#advanced-documentation"},[e("span",null,"Advanced Documentation")])],-1),C=e("p",null,"Tips for advanced user guidance",-1),P=e("div",{class:"custom-container tip"},[e("p",{class:"custom-container-title"},"Appreciations"),e("p",null,"Thank you very much for your selfless sharing of usage skills and experience, which makes Xray more and more powerful.")],-1);function A(D,I){const r=s("I18nTip"),a=s("RouterLink");return i(),d("div",null,[u,t(r),h,m,p,e("p",null,[n("Please click "),t(a,{to:"/en/document/install.html"},{default:o(()=>[n("How to Download and Install Xray")]),_:1}),n(" to get Xray.")]),_,f,e("p",null,[n("Please click "),t(a,{to:"/en/document/config.html"},{default:o(()=>[n("How to Configure and Run Xray")]),_:1}),n(" to learn the easiest way to configure Xray.")]),g,v,e("p",null,[n("Please click "),t(a,{to:"/en/document/command.html"},{default:o(()=>[n("Command Parameters for Xray")]),_:1}),n(" to view more commands and parameters usages.")]),y,e("p",null,[n("If you're interested, please click "),t(a,{to:"/en/document/document.html"},{default:o(()=>[n("Documents")]),_:1}),n(" to help us improve the documents, or click the "),k]),w,b,x,e("p",null,[n("Please click "),t(a,{to:"/en/document/level-0/"},{default:o(()=>[n("Beginner Tutorial")]),_:1}),n(" to view it.")]),X,e("p",null,[n("After you have the basics, you can explore more ways to use them through "),t(a,{to:"/en/document/level-1/"},{default:o(()=>[n("Getting Started Tips")]),_:1}),n(".")]),T,C,e("p",null,[n("Click on "),t(a,{to:"/en/document/level-2/"},{default:o(()=>[n("Advanced Documentation")]),_:1}),n(" to view it")]),P])}const R=l(c,[["render",A],["__file","index.html.vue"]]);export{R as default};
                                      diff --git a/assets/index.html-DRWQxS_s.js b/assets/index.html-CbpQ50tV.js
                                      similarity index 98%
                                      rename from assets/index.html-DRWQxS_s.js
                                      rename to assets/index.html-CbpQ50tV.js
                                      index 4b35d6aac6..bb35cb14d9 100644
                                      --- a/assets/index.html-DRWQxS_s.js
                                      +++ b/assets/index.html-CbpQ50tV.js
                                      @@ -1 +1 @@
                                      -import{_ as c,r as a,o as d,c as h,a as t,b as e,d as n,w as l}from"./app-DBM4OJyw.js";const r={},_=e("h1",{id:"快速入门",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#快速入门"},[e("span",null,"快速入门")])],-1),i=e("blockquote",null,[e("p",null,[e("strong",null,"这个章节将告诉您如何用最简单的方式获得 Xray,并且开始使用 Xray。")])],-1),u=e("h2",{id:"下载安装",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#下载安装"},[e("span",null,"下载安装")])],-1),p=e("p",null,"Xray 支持各种平台,并且您可以从多种渠道和方式获得 Xray 的各种版本。",-1),m=e("h2",{id:"配置运行",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#配置运行"},[e("span",null,"配置运行")])],-1),f=e("p",null,"下载并安装 Xray 后,只需对他进行配置即可使用。",-1),x=e("h2",{id:"命令参数",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#命令参数"},[e("span",null,"命令参数")])],-1),b=e("p",null,"Xray 有多种命令和参数可用,因此变得灵活和强大。",-1),X=e("h2",{id:"改进文档",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#改进文档"},[e("span",null,"改进文档")])],-1),y=e("code",null,"帮助我们改善此页面!",-1),v=e("p",null,"我们十分感谢每一位 Contributor 作出的贡献!是你们让 Project X 变得更加强大!",-1),k=e("h2",{id:"小小白白话文",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#小小白白话文"},[e("span",null,"小小白白话文")])],-1),B=e("p",null,"给予新手指导的使用心得",-1),C=e("h2",{id:"入门技巧",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#入门技巧"},[e("span",null,"入门技巧")])],-1),N=e("h2",{id:"进阶文档",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#进阶文档"},[e("span",null,"进阶文档")])],-1),T=e("p",null,"给予进阶用户指导的使用技巧",-1),V=e("div",{class:"custom-container tip"},[e("p",{class:"custom-container-title"},"感谢"),e("p",null,"非常感谢大家无私分享使用技巧和心得, 使得 Xray 日益强大。")],-1);function g(w,I){const s=a("I18nTip"),o=a("RouterLink");return d(),h("div",null,[t(s),_,i,u,p,e("p",null,[n("请点击 "),t(o,{to:"/document/install.html"},{default:l(()=>[n("下载安装")]),_:1}),n(" 以获取 Xray")]),m,f,e("p",null,[n("请点击 "),t(o,{to:"/document/config.html"},{default:l(()=>[n("配置运行")]),_:1}),n(" 以学习最简单的配置方式。")]),x,b,e("p",null,[n("请点击 "),t(o,{to:"/document/command.html"},{default:l(()=>[n("命令参数")]),_:1}),n(" 查看 Xray 的更多命令和参数用法。")]),X,e("p",null,[n("如果你有兴趣,请点击 "),t(o,{to:"/document/document.html"},{default:l(()=>[n("使用文档")]),_:1}),n(" 帮助我们改进文档,或者点击页面下方的 "),y]),v,k,B,e("p",null,[n("请点击 "),t(o,{to:"/document/level-0/"},{default:l(()=>[n("小小白白话文")]),_:1}),n(" 以进行查看。")]),C,e("p",null,[n("具备了基础之后,你就可以通过 "),t(o,{to:"/document/level-1/"},{default:l(()=>[n("入门技巧")]),_:1}),n(" 来探索更多的使用方式了。")]),N,T,e("p",null,[n("点击 "),t(o,{to:"/document/level-2/"},{default:l(()=>[n("进阶文档")]),_:1}),n(" 以进行查看")]),V])}const R=c(r,[["render",g],["__file","index.html.vue"]]);export{R as default};
                                      +import{_ as c,r as a,o as d,c as h,a as t,b as e,d as n,w as l}from"./app-D7uBbsY3.js";const r={},_=e("h1",{id:"快速入门",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#快速入门"},[e("span",null,"快速入门")])],-1),i=e("blockquote",null,[e("p",null,[e("strong",null,"这个章节将告诉您如何用最简单的方式获得 Xray,并且开始使用 Xray。")])],-1),u=e("h2",{id:"下载安装",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#下载安装"},[e("span",null,"下载安装")])],-1),p=e("p",null,"Xray 支持各种平台,并且您可以从多种渠道和方式获得 Xray 的各种版本。",-1),m=e("h2",{id:"配置运行",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#配置运行"},[e("span",null,"配置运行")])],-1),f=e("p",null,"下载并安装 Xray 后,只需对他进行配置即可使用。",-1),x=e("h2",{id:"命令参数",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#命令参数"},[e("span",null,"命令参数")])],-1),b=e("p",null,"Xray 有多种命令和参数可用,因此变得灵活和强大。",-1),X=e("h2",{id:"改进文档",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#改进文档"},[e("span",null,"改进文档")])],-1),y=e("code",null,"帮助我们改善此页面!",-1),v=e("p",null,"我们十分感谢每一位 Contributor 作出的贡献!是你们让 Project X 变得更加强大!",-1),k=e("h2",{id:"小小白白话文",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#小小白白话文"},[e("span",null,"小小白白话文")])],-1),B=e("p",null,"给予新手指导的使用心得",-1),C=e("h2",{id:"入门技巧",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#入门技巧"},[e("span",null,"入门技巧")])],-1),N=e("h2",{id:"进阶文档",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#进阶文档"},[e("span",null,"进阶文档")])],-1),T=e("p",null,"给予进阶用户指导的使用技巧",-1),V=e("div",{class:"custom-container tip"},[e("p",{class:"custom-container-title"},"感谢"),e("p",null,"非常感谢大家无私分享使用技巧和心得, 使得 Xray 日益强大。")],-1);function g(w,I){const s=a("I18nTip"),o=a("RouterLink");return d(),h("div",null,[t(s),_,i,u,p,e("p",null,[n("请点击 "),t(o,{to:"/document/install.html"},{default:l(()=>[n("下载安装")]),_:1}),n(" 以获取 Xray")]),m,f,e("p",null,[n("请点击 "),t(o,{to:"/document/config.html"},{default:l(()=>[n("配置运行")]),_:1}),n(" 以学习最简单的配置方式。")]),x,b,e("p",null,[n("请点击 "),t(o,{to:"/document/command.html"},{default:l(()=>[n("命令参数")]),_:1}),n(" 查看 Xray 的更多命令和参数用法。")]),X,e("p",null,[n("如果你有兴趣,请点击 "),t(o,{to:"/document/document.html"},{default:l(()=>[n("使用文档")]),_:1}),n(" 帮助我们改进文档,或者点击页面下方的 "),y]),v,k,B,e("p",null,[n("请点击 "),t(o,{to:"/document/level-0/"},{default:l(()=>[n("小小白白话文")]),_:1}),n(" 以进行查看。")]),C,e("p",null,[n("具备了基础之后,你就可以通过 "),t(o,{to:"/document/level-1/"},{default:l(()=>[n("入门技巧")]),_:1}),n(" 来探索更多的使用方式了。")]),N,T,e("p",null,[n("点击 "),t(o,{to:"/document/level-2/"},{default:l(()=>[n("进阶文档")]),_:1}),n(" 以进行查看")]),V])}const R=c(r,[["render",g],["__file","index.html.vue"]]);export{R as default};
                                      diff --git a/assets/index.html-BiUJ4Vho.js b/assets/index.html-CoQcU5ho.js
                                      similarity index 97%
                                      rename from assets/index.html-BiUJ4Vho.js
                                      rename to assets/index.html-CoQcU5ho.js
                                      index 352ffc693b..943c7df2f8 100644
                                      --- a/assets/index.html-BiUJ4Vho.js
                                      +++ b/assets/index.html-CoQcU5ho.js
                                      @@ -1 +1 @@
                                      -import{_ as c,r as l,o as s,c as h,a as n,b as e,d as t,w as o}from"./app-DBM4OJyw.js";const u={},p=e("h1",{id:"plain-and-simple-language",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#plain-and-simple-language"},[e("span",null,"Plain and Simple Language")])],-1),d=e("p",null,[e("strong",null,"This chapter is a basic lesson of [Starting from Scratch]. New students, please watch and learn carefully.")],-1),_={class:"custom-container tip"},m=e("p",{class:"custom-container-title"},"Tip",-1),f={href:"https://github.com/ricuhkaen",target:"_blank",rel:"noopener noreferrer"},g=e("p",null,"[【Chapter 5】Website Construction] - Show Your Beauty (Link to webpage.md file)",-1),y=e("p",null,"[Chapter 9] Appendix - All the exam points are here.",-1);function b(v,x){const r=l("I18nTip"),i=l("ExternalLinkIcon"),a=l("RouterLink");return s(),h("div",null,[n(r),p,d,e("div",_,[m,e("p",null,[t("Made with ❤️ by "),e("a",f,[t("@ricuhkaen"),n(i)])])]),e("p",null,[n(a,{to:"/en/document/level-0/ch01-preface.html"},{default:o(()=>[t("【Chapter 1】 Preface: Rambling")]),_:1}),t(" - Airport or Self-built? That is the question.")]),e("p",null,[n(a,{to:"/en/document/level-0/ch02-preparation.html"},{default:o(()=>[t("Chapter 2: Preparation of Raw Materials")]),_:1}),t(" - Tools must be sharpened before they can be used proficiently.")]),e("p",null,[n(a,{to:"/en/document/level-0/ch03-ssh.html"},{default:o(()=>[t("Chapter 3: Remote Login")]),_:1}),t(" - A bridge connecting the north and south, turning a natural obstacle into a thoroughfare.")]),e("p",null,[n(a,{to:"/en/document/level-0/ch04-security.html"},{default:o(()=>[t("【Chapter 4】Security Protection")]),_:1}),t(" - If you don't pay attention to security, you will shed tears for your loved ones.")]),g,e("p",null,[n(a,{to:"/en/document/level-0/ch06-certificates.html"},{default:o(()=>[t("Chapter 6: Certificate Management")]),_:1}),t(" - Only those who obtain certificates are considered legitimate.")]),e("p",null,[n(a,{to:"/en/document/level-0/ch07-xray-server.html"},{default:o(()=>[t("Chapter 7: Xray Server")]),_:1}),t(" - Finally, waited for you.")]),e("p",null,[n(a,{to:"/en/document/level-0/ch08-xray-clients.html"},{default:o(()=>[t("Chapter 8: Xray Client")]),_:1}),t(" - A New Beginning.")]),y])}const w=c(u,[["render",b],["__file","index.html.vue"]]);export{w as default};
                                      +import{_ as c,r as l,o as s,c as h,a as n,b as e,d as t,w as o}from"./app-D7uBbsY3.js";const u={},p=e("h1",{id:"plain-and-simple-language",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#plain-and-simple-language"},[e("span",null,"Plain and Simple Language")])],-1),d=e("p",null,[e("strong",null,"This chapter is a basic lesson of [Starting from Scratch]. New students, please watch and learn carefully.")],-1),_={class:"custom-container tip"},m=e("p",{class:"custom-container-title"},"Tip",-1),f={href:"https://github.com/ricuhkaen",target:"_blank",rel:"noopener noreferrer"},g=e("p",null,"[【Chapter 5】Website Construction] - Show Your Beauty (Link to webpage.md file)",-1),y=e("p",null,"[Chapter 9] Appendix - All the exam points are here.",-1);function b(v,x){const r=l("I18nTip"),i=l("ExternalLinkIcon"),a=l("RouterLink");return s(),h("div",null,[n(r),p,d,e("div",_,[m,e("p",null,[t("Made with ❤️ by "),e("a",f,[t("@ricuhkaen"),n(i)])])]),e("p",null,[n(a,{to:"/en/document/level-0/ch01-preface.html"},{default:o(()=>[t("【Chapter 1】 Preface: Rambling")]),_:1}),t(" - Airport or Self-built? That is the question.")]),e("p",null,[n(a,{to:"/en/document/level-0/ch02-preparation.html"},{default:o(()=>[t("Chapter 2: Preparation of Raw Materials")]),_:1}),t(" - Tools must be sharpened before they can be used proficiently.")]),e("p",null,[n(a,{to:"/en/document/level-0/ch03-ssh.html"},{default:o(()=>[t("Chapter 3: Remote Login")]),_:1}),t(" - A bridge connecting the north and south, turning a natural obstacle into a thoroughfare.")]),e("p",null,[n(a,{to:"/en/document/level-0/ch04-security.html"},{default:o(()=>[t("【Chapter 4】Security Protection")]),_:1}),t(" - If you don't pay attention to security, you will shed tears for your loved ones.")]),g,e("p",null,[n(a,{to:"/en/document/level-0/ch06-certificates.html"},{default:o(()=>[t("Chapter 6: Certificate Management")]),_:1}),t(" - Only those who obtain certificates are considered legitimate.")]),e("p",null,[n(a,{to:"/en/document/level-0/ch07-xray-server.html"},{default:o(()=>[t("Chapter 7: Xray Server")]),_:1}),t(" - Finally, waited for you.")]),e("p",null,[n(a,{to:"/en/document/level-0/ch08-xray-clients.html"},{default:o(()=>[t("Chapter 8: Xray Client")]),_:1}),t(" - A New Beginning.")]),y])}const w=c(u,[["render",b],["__file","index.html.vue"]]);export{w as default};
                                      diff --git a/assets/index.html-qOpCoWzE.js b/assets/index.html-D8JovJUC.js
                                      similarity index 98%
                                      rename from assets/index.html-qOpCoWzE.js
                                      rename to assets/index.html-D8JovJUC.js
                                      index 81300bf86f..f7803843a9 100644
                                      --- a/assets/index.html-qOpCoWzE.js
                                      +++ b/assets/index.html-D8JovJUC.js
                                      @@ -1 +1 @@
                                      -import{_ as l,r as i,o as h,c,a as n,b as t,w as a,d as e}from"./app-DBM4OJyw.js";const u={},d=t("h1",{id:"advanced-documentation",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#advanced-documentation"},[t("span",null,"Advanced Documentation")])],-1),_=t("p",null,[t("strong",null,"This chapter contains experience sharing of using Xray at an advanced level. If you are already familiar with Xray, the experience shared here can help you unleash the full power of Xray.")],-1),p=t("img",{src:"https://avatars2.githubusercontent.com/u/57820613?s=32",width:"32",height:"32",alt:"a"},null,-1),m={href:"https://github.com/kirin10000",target:"_blank",rel:"noopener noreferrer"},g=t("p",null,"An Introduction to Transparent Proxies.",-1),f=t("img",{src:"https://avatars2.githubusercontent.com/u/41363844?s=32",width:"32",height:"32",alt:"a"},null,-1),y={href:"https://github.com/BioniCosmos",target:"_blank",rel:"noopener noreferrer"},b=t("p",null,"Complete tutorial on configuring transparent proxy (TProxy) based on Xray.",-1),v=t("img",{src:"https://avatars.githubusercontent.com/u/110686480?s=32",width:"32",height:"32",alt:"a"},null,-1),x={href:"https://github.com/SQLimit",target:"_blank",rel:"noopener noreferrer"},T=t("p",null,"Xray-based TProxy Transparent Proxy (IPv4 and IPv6) Configuration Tutorial",-1),k=t("img",{src:"https://avatars.githubusercontent.com/u/110686480?s=32",width:"32",height:"32",alt:"a"},null,-1),w={href:"https://github.com/SQLimit",target:"_blank",rel:"noopener noreferrer"},P=t("p",null,"Use Nginx_TLS tunnel on both ends to hide the fingerprint.",-1),I=t("img",{src:"https://avatars2.githubusercontent.com/u/57820613?s=32",width:"32",height:"32",alt:"a"},null,-1),X={href:"https://github.com/kirin10000",target:"_blank",rel:"noopener noreferrer"},L=t("p",null,"A new way of bypassing Xray traffic in transparent proxy implemented by iptables/nftables.",-1),S=t("img",{src:"https://avatars.githubusercontent.com/u/28607089?s=32",width:"32",height:"32",alt:"a"},null,-1),C={href:"https://github.com/Zzz3m",target:"_blank",rel:"noopener noreferrer"},B=t("p",null,'Play Xray to the fullest: Implement "load balancing" based on fwmark or sendThrough.',-1),A=t("img",{src:"https://avatars.githubusercontent.com/u/1588741?s=32",width:"32",height:"32",alt:"a"},null,-1),N={href:"https://github.com/yuhan6665",target:"_blank",rel:"noopener noreferrer"},z=t("p",null,"Introduction to using WireGuard for outbound traffic added in Xray v1.6.5.",-1),E=t("img",{src:"https://avatars.githubusercontent.com/u/1588741?s=32",width:"32",height:"32",alt:"a"},null,-1),G={href:"https://github.com/yuhan6665",target:"_blank",rel:"noopener noreferrer"},Q=t("p",null,"Adapt traffic statistics and scripts compatible with Xray.",-1);function R(V,W){const s=i("I18nTip"),o=i("RouterLink"),r=i("ExternalLinkIcon");return h(),c("div",null,[n(s),d,_,t("p",null,[n(o,{to:"/en/document/level-2/transparent_proxy/transparent_proxy.html"},{default:a(()=>[e("Beginner's Guide to Transparent Proxies")]),_:1}),e(" by "),p,e(),t("a",m,[e("@kirin"),n(r)])]),g,t("p",null,[n(o,{to:"/en/document/level-2/tproxy.html"},{default:a(()=>[e("TProxy Configuration Tutorial")]),_:1}),e(" by "),f,e(),t("a",y,[e("@BioniCosmos"),n(r)])]),b,t("p",null,[n(o,{to:"/en/document/level-2/tproxy_ipv4_and_ipv6.html"},{default:a(()=>[e("TProxy Transparent Proxy (IPv4 and IPv6) Configuration Tutorial")]),_:1}),e(" by "),v,e(),t("a",x,[e("@SQLimit"),n(r)])]),T,t("p",null,[n(o,{to:"/en/document/level-2/nginx_or_haproxy_tls_tunnel.html"},{default:a(()=>[e("Nginx_TLS Tunnel Hidden Fingerprint")]),_:1}),e(" by "),k,e(),t("a",w,[e("@SQLimit"),n(r)])]),P,t("p",null,[n(o,{to:"/en/document/level-2/iptables_gid.html"},{default:a(()=>[e("[Transparent Proxy] Avoiding Xray Traffic Through gid")]),_:1}),e(" by "),I,e(),t("a",X,[e("@kirin"),n(r)])]),L,t("p",null,[n(o,{to:"/en/document/level-2/redirect.html"},{default:a(()=>[e('Redirect Specific Traffic to Specific Gateway using Xray to Achieve Global Routing "Load Balancing"')]),_:1}),e(" by "),S,e(),t("a",C,[e("@Zzz3m"),n(r)])]),B,t("p",null,[n(o,{to:"/en/document/level-2/warp.html"},{default:a(()=>[e("Enhancing Proxy Security with Cloudflare Warp")]),_:1}),e(" by "),A,e(),t("a",N,[e("@yuhan6665"),n(r)])]),z,t("p",null,[n(o,{to:"/en/document/level-2/traffic_stats.html"},{default:a(()=>[e("Xray Traffic Statistics")]),_:1}),e(" by "),E,e(),t("a",G,[e("@yuhan6665"),n(r)])]),Q])}const D=l(u,[["render",R],["__file","index.html.vue"]]);export{D as default};
                                      +import{_ as l,r as i,o as h,c,a as n,b as t,w as a,d as e}from"./app-D7uBbsY3.js";const u={},d=t("h1",{id:"advanced-documentation",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#advanced-documentation"},[t("span",null,"Advanced Documentation")])],-1),_=t("p",null,[t("strong",null,"This chapter contains experience sharing of using Xray at an advanced level. If you are already familiar with Xray, the experience shared here can help you unleash the full power of Xray.")],-1),p=t("img",{src:"https://avatars2.githubusercontent.com/u/57820613?s=32",width:"32",height:"32",alt:"a"},null,-1),m={href:"https://github.com/kirin10000",target:"_blank",rel:"noopener noreferrer"},g=t("p",null,"An Introduction to Transparent Proxies.",-1),f=t("img",{src:"https://avatars2.githubusercontent.com/u/41363844?s=32",width:"32",height:"32",alt:"a"},null,-1),y={href:"https://github.com/BioniCosmos",target:"_blank",rel:"noopener noreferrer"},b=t("p",null,"Complete tutorial on configuring transparent proxy (TProxy) based on Xray.",-1),v=t("img",{src:"https://avatars.githubusercontent.com/u/110686480?s=32",width:"32",height:"32",alt:"a"},null,-1),x={href:"https://github.com/SQLimit",target:"_blank",rel:"noopener noreferrer"},T=t("p",null,"Xray-based TProxy Transparent Proxy (IPv4 and IPv6) Configuration Tutorial",-1),k=t("img",{src:"https://avatars.githubusercontent.com/u/110686480?s=32",width:"32",height:"32",alt:"a"},null,-1),w={href:"https://github.com/SQLimit",target:"_blank",rel:"noopener noreferrer"},P=t("p",null,"Use Nginx_TLS tunnel on both ends to hide the fingerprint.",-1),I=t("img",{src:"https://avatars2.githubusercontent.com/u/57820613?s=32",width:"32",height:"32",alt:"a"},null,-1),X={href:"https://github.com/kirin10000",target:"_blank",rel:"noopener noreferrer"},L=t("p",null,"A new way of bypassing Xray traffic in transparent proxy implemented by iptables/nftables.",-1),S=t("img",{src:"https://avatars.githubusercontent.com/u/28607089?s=32",width:"32",height:"32",alt:"a"},null,-1),C={href:"https://github.com/Zzz3m",target:"_blank",rel:"noopener noreferrer"},B=t("p",null,'Play Xray to the fullest: Implement "load balancing" based on fwmark or sendThrough.',-1),A=t("img",{src:"https://avatars.githubusercontent.com/u/1588741?s=32",width:"32",height:"32",alt:"a"},null,-1),N={href:"https://github.com/yuhan6665",target:"_blank",rel:"noopener noreferrer"},z=t("p",null,"Introduction to using WireGuard for outbound traffic added in Xray v1.6.5.",-1),E=t("img",{src:"https://avatars.githubusercontent.com/u/1588741?s=32",width:"32",height:"32",alt:"a"},null,-1),G={href:"https://github.com/yuhan6665",target:"_blank",rel:"noopener noreferrer"},Q=t("p",null,"Adapt traffic statistics and scripts compatible with Xray.",-1);function R(V,W){const s=i("I18nTip"),o=i("RouterLink"),r=i("ExternalLinkIcon");return h(),c("div",null,[n(s),d,_,t("p",null,[n(o,{to:"/en/document/level-2/transparent_proxy/transparent_proxy.html"},{default:a(()=>[e("Beginner's Guide to Transparent Proxies")]),_:1}),e(" by "),p,e(),t("a",m,[e("@kirin"),n(r)])]),g,t("p",null,[n(o,{to:"/en/document/level-2/tproxy.html"},{default:a(()=>[e("TProxy Configuration Tutorial")]),_:1}),e(" by "),f,e(),t("a",y,[e("@BioniCosmos"),n(r)])]),b,t("p",null,[n(o,{to:"/en/document/level-2/tproxy_ipv4_and_ipv6.html"},{default:a(()=>[e("TProxy Transparent Proxy (IPv4 and IPv6) Configuration Tutorial")]),_:1}),e(" by "),v,e(),t("a",x,[e("@SQLimit"),n(r)])]),T,t("p",null,[n(o,{to:"/en/document/level-2/nginx_or_haproxy_tls_tunnel.html"},{default:a(()=>[e("Nginx_TLS Tunnel Hidden Fingerprint")]),_:1}),e(" by "),k,e(),t("a",w,[e("@SQLimit"),n(r)])]),P,t("p",null,[n(o,{to:"/en/document/level-2/iptables_gid.html"},{default:a(()=>[e("[Transparent Proxy] Avoiding Xray Traffic Through gid")]),_:1}),e(" by "),I,e(),t("a",X,[e("@kirin"),n(r)])]),L,t("p",null,[n(o,{to:"/en/document/level-2/redirect.html"},{default:a(()=>[e('Redirect Specific Traffic to Specific Gateway using Xray to Achieve Global Routing "Load Balancing"')]),_:1}),e(" by "),S,e(),t("a",C,[e("@Zzz3m"),n(r)])]),B,t("p",null,[n(o,{to:"/en/document/level-2/warp.html"},{default:a(()=>[e("Enhancing Proxy Security with Cloudflare Warp")]),_:1}),e(" by "),A,e(),t("a",N,[e("@yuhan6665"),n(r)])]),z,t("p",null,[n(o,{to:"/en/document/level-2/traffic_stats.html"},{default:a(()=>[e("Xray Traffic Statistics")]),_:1}),e(" by "),E,e(),t("a",G,[e("@yuhan6665"),n(r)])]),Q])}const D=l(u,[["render",R],["__file","index.html.vue"]]);export{D as default};
                                      diff --git a/assets/index.html-DD2Y-q71.js b/assets/index.html-D8QPUz8j.js
                                      similarity index 94%
                                      rename from assets/index.html-DD2Y-q71.js
                                      rename to assets/index.html-D8QPUz8j.js
                                      index bc5d0024e4..b6e78325d7 100644
                                      --- a/assets/index.html-DD2Y-q71.js
                                      +++ b/assets/index.html-D8QPUz8j.js
                                      @@ -1 +1 @@
                                      -import{_ as r,r as a,o as s,c as u,a as t,b as e,w as n,d as o}from"./app-DBM4OJyw.js";const d={},_=e("h1",{id:"入门技巧",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#入门技巧"},[e("span",null,"入门技巧")])],-1),i=e("p",null,[e("strong",null,"这个章节是入门级的 Xray 使用心得分享,主要分享一些 Xray 常用功能模块的原理说明。")],-1);function m(p,f){const c=a("I18nTip"),l=a("RouterLink");return s(),u("div",null,[t(c),_,i,e("p",null,[t(l,{to:"/document/level-1/fallbacks-lv1.html"},{default:n(()=>[o("回落 (fallbacks) 功能简析")]),_:1})]),e("p",null,[t(l,{to:"/document/level-1/routing-lv1-part1.html"},{default:n(()=>[o("路由 (routing) 功能简析(上)")]),_:1})]),e("p",null,[t(l,{to:"/document/level-1/routing-lv1-part2.html"},{default:n(()=>[o("路由 (routing) 功能简析(下)")]),_:1})]),e("p",null,[t(l,{to:"/document/level-1/work.html"},{default:n(()=>[o("Xray 的工作模式简析")]),_:1})]),e("p",null,[t(l,{to:"/document/level-1/fallbacks-with-sni.html"},{default:n(()=>[o("通过 SNI 回落功能实现伪装与按域名分流")]),_:1})])])}const v=r(d,[["render",m],["__file","index.html.vue"]]);export{v as default};
                                      +import{_ as r,r as a,o as s,c as u,a as t,b as e,w as n,d as o}from"./app-D7uBbsY3.js";const d={},_=e("h1",{id:"入门技巧",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#入门技巧"},[e("span",null,"入门技巧")])],-1),i=e("p",null,[e("strong",null,"这个章节是入门级的 Xray 使用心得分享,主要分享一些 Xray 常用功能模块的原理说明。")],-1);function m(p,f){const c=a("I18nTip"),l=a("RouterLink");return s(),u("div",null,[t(c),_,i,e("p",null,[t(l,{to:"/document/level-1/fallbacks-lv1.html"},{default:n(()=>[o("回落 (fallbacks) 功能简析")]),_:1})]),e("p",null,[t(l,{to:"/document/level-1/routing-lv1-part1.html"},{default:n(()=>[o("路由 (routing) 功能简析(上)")]),_:1})]),e("p",null,[t(l,{to:"/document/level-1/routing-lv1-part2.html"},{default:n(()=>[o("路由 (routing) 功能简析(下)")]),_:1})]),e("p",null,[t(l,{to:"/document/level-1/work.html"},{default:n(()=>[o("Xray 的工作模式简析")]),_:1})]),e("p",null,[t(l,{to:"/document/level-1/fallbacks-with-sni.html"},{default:n(()=>[o("通过 SNI 回落功能实现伪装与按域名分流")]),_:1})])])}const v=r(d,[["render",m],["__file","index.html.vue"]]);export{v as default};
                                      diff --git a/assets/index.html-Ba-V9K2O.js b/assets/index.html-DKW9Z_BK.js
                                      similarity index 98%
                                      rename from assets/index.html-Ba-V9K2O.js
                                      rename to assets/index.html-DKW9Z_BK.js
                                      index 8858171e36..0f188e1f24 100644
                                      --- a/assets/index.html-Ba-V9K2O.js
                                      +++ b/assets/index.html-DKW9Z_BK.js
                                      @@ -1 +1 @@
                                      -import{_ as r,r as a,o as c,c as d,a as t,b as e,d as o,w as s}from"./app-DBM4OJyw.js";const p={},h=e("h1",{id:"development-guide",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#development-guide"},[e("span",null,"Development Guide")])],-1),m=e("h2",{id:"compile-documentation",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#compile-documentation"},[e("span",null,"Compile Documentation")])],-1),u=e("p",null,"Xray supports multiple platforms, and you can perform cross-compilation on various platforms by yourself.",-1),_=e("h2",{id:"design-concept",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#design-concept"},[e("span",null,"Design Concept")])],-1),f=e("p",null,"Xray kernel provides a platform for secondary development.",-1),v=e("p",null,"This section explains the design goals and architecture of Xray.",-1),g=e("h2",{id:"development-standards",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#development-standards"},[e("span",null,"Development Standards")])],-1),x=e("p",null,"This section outlines the guidelines to follow when obtaining code, developing, submitting PRs, as well as the relevant coding standards.",-1),b=e("h2",{id:"protocol-details",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#protocol-details"},[e("span",null,"Protocol Details")])],-1),y=e("p",null,"Xray uses many protocols, and you can obtain a detailed description of each protocol through various means.",-1),k={id:"vless-protocol",tabindex:"-1"},w={class:"header-anchor",href:"#vless-protocol"},P=e("p",null,"VLESS is a stateless lightweight transport protocol that can serve as a bridge between Xray clients and servers.",-1),C={id:"vmess-protocol",tabindex:"-1"},D={class:"header-anchor",href:"#vmess-protocol"},X=e("p",null,"VMess is an encrypted transport protocol that can act as a bridge between Xray clients and servers.",-1),V={id:"mux-cool-protocol",tabindex:"-1"},L={class:"header-anchor",href:"#mux-cool-protocol"},S=e("p",null,"Mux.Cool protocol is a multiplexing transport protocol used to transmit multiple independent data streams within an established data stream.",-1),E={id:"mkcp-protocol",tabindex:"-1"},T={class:"header-anchor",href:"#mkcp-protocol"},I={href:"https://github.com/skywind3000/kcp",target:"_blank",rel:"noopener noreferrer"};function M(B,K){const l=a("I18nTip"),n=a("RouterLink"),i=a("ExternalLinkIcon");return c(),d("div",null,[t(l),h,m,u,e("p",null,[o("Please click "),t(n,{to:"/en/development/intro/compile.html"},{default:s(()=>[o("Compile Documentation")]),_:1}),o(" to view specific compile-related content.")]),_,f,v,e("p",null,[o("Please click "),t(n,{to:"/en/development/intro/design.html"},{default:s(()=>[o("Design Principles")]),_:1}),o(" to learn about the design goals and architecture of Xray.")]),g,x,e("p",null,[o("Please click "),t(n,{to:"/en/development/intro/guide.html"},{default:s(()=>[o("Development Specification")]),_:1}),o(" to view the guidelines that should be followed during Xray development.")]),b,y,e("h3",k,[e("a",w,[e("span",null,[t(n,{to:"/en/development/protocols/vless.html"},{default:s(()=>[o("VLESS Protocol")]),_:1})])])]),P,e("h3",C,[e("a",D,[e("span",null,[t(n,{to:"/en/development/protocols/vmess.html"},{default:s(()=>[o("VMess Protocol")]),_:1})])])]),X,e("h3",V,[e("a",L,[e("span",null,[t(n,{to:"/en/development/protocols/muxcool.html"},{default:s(()=>[o("Mux.Cool Protocol")]),_:1})])])]),S,e("h3",E,[e("a",T,[e("span",null,[t(n,{to:"/en/development/protocols/mkcp.html"},{default:s(()=>[o("mKCP Protocol")]),_:1})])])]),e("p",null,[o("mKCP is a stream transmission protocol modified from the "),e("a",I,[o("KCP protocol"),t(i)]),o(" that can transmit arbitrary data streams in order.")])])}const R=r(p,[["render",M],["__file","index.html.vue"]]);export{R as default};
                                      +import{_ as r,r as a,o as c,c as d,a as t,b as e,d as o,w as s}from"./app-D7uBbsY3.js";const p={},h=e("h1",{id:"development-guide",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#development-guide"},[e("span",null,"Development Guide")])],-1),m=e("h2",{id:"compile-documentation",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#compile-documentation"},[e("span",null,"Compile Documentation")])],-1),u=e("p",null,"Xray supports multiple platforms, and you can perform cross-compilation on various platforms by yourself.",-1),_=e("h2",{id:"design-concept",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#design-concept"},[e("span",null,"Design Concept")])],-1),f=e("p",null,"Xray kernel provides a platform for secondary development.",-1),v=e("p",null,"This section explains the design goals and architecture of Xray.",-1),g=e("h2",{id:"development-standards",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#development-standards"},[e("span",null,"Development Standards")])],-1),x=e("p",null,"This section outlines the guidelines to follow when obtaining code, developing, submitting PRs, as well as the relevant coding standards.",-1),b=e("h2",{id:"protocol-details",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#protocol-details"},[e("span",null,"Protocol Details")])],-1),y=e("p",null,"Xray uses many protocols, and you can obtain a detailed description of each protocol through various means.",-1),k={id:"vless-protocol",tabindex:"-1"},w={class:"header-anchor",href:"#vless-protocol"},P=e("p",null,"VLESS is a stateless lightweight transport protocol that can serve as a bridge between Xray clients and servers.",-1),C={id:"vmess-protocol",tabindex:"-1"},D={class:"header-anchor",href:"#vmess-protocol"},X=e("p",null,"VMess is an encrypted transport protocol that can act as a bridge between Xray clients and servers.",-1),V={id:"mux-cool-protocol",tabindex:"-1"},L={class:"header-anchor",href:"#mux-cool-protocol"},S=e("p",null,"Mux.Cool protocol is a multiplexing transport protocol used to transmit multiple independent data streams within an established data stream.",-1),E={id:"mkcp-protocol",tabindex:"-1"},T={class:"header-anchor",href:"#mkcp-protocol"},I={href:"https://github.com/skywind3000/kcp",target:"_blank",rel:"noopener noreferrer"};function M(B,K){const l=a("I18nTip"),n=a("RouterLink"),i=a("ExternalLinkIcon");return c(),d("div",null,[t(l),h,m,u,e("p",null,[o("Please click "),t(n,{to:"/en/development/intro/compile.html"},{default:s(()=>[o("Compile Documentation")]),_:1}),o(" to view specific compile-related content.")]),_,f,v,e("p",null,[o("Please click "),t(n,{to:"/en/development/intro/design.html"},{default:s(()=>[o("Design Principles")]),_:1}),o(" to learn about the design goals and architecture of Xray.")]),g,x,e("p",null,[o("Please click "),t(n,{to:"/en/development/intro/guide.html"},{default:s(()=>[o("Development Specification")]),_:1}),o(" to view the guidelines that should be followed during Xray development.")]),b,y,e("h3",k,[e("a",w,[e("span",null,[t(n,{to:"/en/development/protocols/vless.html"},{default:s(()=>[o("VLESS Protocol")]),_:1})])])]),P,e("h3",C,[e("a",D,[e("span",null,[t(n,{to:"/en/development/protocols/vmess.html"},{default:s(()=>[o("VMess Protocol")]),_:1})])])]),X,e("h3",V,[e("a",L,[e("span",null,[t(n,{to:"/en/development/protocols/muxcool.html"},{default:s(()=>[o("Mux.Cool Protocol")]),_:1})])])]),S,e("h3",E,[e("a",T,[e("span",null,[t(n,{to:"/en/development/protocols/mkcp.html"},{default:s(()=>[o("mKCP Protocol")]),_:1})])])]),e("p",null,[o("mKCP is a stream transmission protocol modified from the "),e("a",I,[o("KCP protocol"),t(i)]),o(" that can transmit arbitrary data streams in order.")])])}const R=r(p,[["render",M],["__file","index.html.vue"]]);export{R as default};
                                      diff --git a/assets/index.html-CLXQYZCk.js b/assets/index.html-DOOHsyE6.js
                                      similarity index 98%
                                      rename from assets/index.html-CLXQYZCk.js
                                      rename to assets/index.html-DOOHsyE6.js
                                      index a90c069fc4..e917f869c7 100644
                                      --- a/assets/index.html-CLXQYZCk.js
                                      +++ b/assets/index.html-DOOHsyE6.js
                                      @@ -1 +1 @@
                                      -import{_ as s,r as n,o as i,c,a as t,b as e,d as r,w as h,e as u}from"./app-DBM4OJyw.js";const _={},d=u('

                                      XTLS ? Xray ? V2Ray ?

                                      XTLS are brilliant ideas for TLS we study, while Xray is the best practice we maintain.

                                      • Xray-core 是 v2ray-core 的超集,含更好的整体性能和 XTLS 等一系列增强,且完全兼容 v2ray-core 的功能及配置。
                                        • 只有一个可执行文件,含 ctl 的功能,run 为默认指令
                                        • 配置上完全兼容,环境变量和 API 对应要改为以 XRAY_ 开头
                                        • 全平台开放了裸协议的 ReadV
                                        • 提供完整的 VLESS & Trojan XTLS 支持,均有 ReadV
                                        • 提供了 XTLS 多种流控模式, 性能一骑绝尘!

                                      “配置兼容,整体更好”

                                      我们是谁?

                                      It doesn't matter who we are. What matters is that we will keep riding and never look back.

                                      帮助 Xray 变得更强

                                      欢迎帮助 Xray 变得更强!

                                      ',8),p=e("li",null,"🖥️ 帮助开发和测试 Xray, 提交高质量的 Pull request.",-1),X={href:"https://github.com/XTLS/Xray-core/issues",target:"_blank",rel:"noopener noreferrer"},f={href:"https://github.com/XTLS/Xray-core/discussions",target:"_blank",rel:"noopener noreferrer"},b={href:"https://github.com/XTLS/Xray-docs-next",target:"_blank",rel:"noopener noreferrer"},m=e("li",null,"💬 在 Telegram 群帮助群友/灌水.",-1),g=e("li",null,[e("strong",null,"...事实上,每一份对 Xray 的支持都会让 Xray 变得更强大")],-1),y=e("h3",{id:"telegram",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#telegram"},[e("span",null,"Telegram")])],-1),x={href:"https://t.me/projectXray",target:"_blank",rel:"noopener noreferrer"},k=e("ul",null,[e("li",null,"交流群可在底线之上随便水,不要撕逼,没有滥权。"),e("li",null,"有问题尽管随便问,知道的尽量回答。"),e("li",null,"禁政治,禁 NSFW")],-1),L={href:"https://t.me/projectVless",target:"_blank",rel:"noopener noreferrer"},S={href:"https://t.me/projectXray",target:"_blank",rel:"noopener noreferrer"},T=e("li",null,"禁广告,禁人身攻击,禁政治。",-1),j={href:"https://t.me/projectXtls",target:"_blank",rel:"noopener noreferrer"},v=e("ul",null,[e("li",null,"发布 Project X 的最新资讯")],-1),P=e("h3",{id:"致谢",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#致谢"},[e("span",null,"致谢")])],-1),V=e("ul",null,[e("li",null,"感谢所有人的支持!"),e("li",null,"感谢各类脚本、Docker 镜像、客户端支持...感谢所有帮忙完善生态的大佬们!"),e("li",null,"感谢为 Xray 网站和文档添砖加瓦的朋友们."),e("li",null,"感谢提出有意义的建议和意见的朋友们."),e("li",null,"感谢 Telegram 群每一位帮助群友的朋友.")],-1),w=e("h3",{id:"更多关于-project-x",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#更多关于-project-x"},[e("span",null,"更多关于 Project X")])],-1),I={href:"https://github.com/XTLS/Xray-core/discussions/3633",target:"_blank",rel:"noopener noreferrer"},N=e("h3",{id:"license",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#license"},[e("span",null,"License")])],-1),E={href:"https://github.com/XTLS/Xray-core/blob/main/LICENSE",target:"_blank",rel:"noopener noreferrer"},R=e("h3",{id:"stargazers-over-time",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#stargazers-over-time"},[e("span",null,"Stargazers over time")])],-1),q={href:"https://starchart.cc/XTLS/Xray-core",target:"_blank",rel:"noopener noreferrer"},z=e("img",{src:"https://starchart.cc/XTLS/Xray-core.svg",alt:"Stargazers over time"},null,-1);function B(C,F){const o=n("I18nTip"),l=n("ExternalLinkIcon"),a=n("RouterLink");return i(),c("div",null,[t(o),d,e("ul",null,[p,e("li",null,[r("📩 在 "),e("a",X,[r("GitHub Issues"),t(l)]),r(" 或 "),e("a",f,[r("讨论区"),t(l)]),r("发起建设性或有意义的 issue 与 discussion.")]),e("li",null,[r("📝 写下您的使用心得并提交至 Xray 的 "),e("a",b,[r("文档网站"),t(l)]),r(".")]),m,g]),y,e("ul",null,[e("li",null,[e("p",null,[e("a",x,[r("Project X 交流群"),t(l)])]),k]),e("li",null,[e("p",null,[e("a",L,[r("Project VLESS Group"),t(l)])]),e("ul",null,[e("li",null,[r("对非中文参与的官方用户群。 "),e("a",S,[r("Project X"),t(l)]),r(" 的姊妹群。")]),T])]),e("li",null,[e("p",null,[e("a",j,[r("Project X 频道"),t(l)])]),v])]),P,V,w,e("ul",null,[e("li",null,[r("如果你想知道更多关于 Project X 的足迹与成长, 请点击"),t(a,{to:"/about/news.html"},{default:h(()=>[r("这里")]),_:1})]),e("li",null,[r("现在 Project X 也发行 NFT 了!如果想拥有一枚 Project X NFT 或者想捐赠或者赞助 Project X,请点击"),e("a",I,[r("这里"),t(l)])])]),N,e("p",null,[e("a",E,[r("Mozilla Public License Version 2.0"),t(l)])]),R,e("p",null,[e("a",q,[z,t(l)])])])}const G=s(_,[["render",B],["__file","index.html.vue"]]);export{G as default}; +import{_ as s,r as n,o as i,c,a as t,b as e,d as r,w as h,e as u}from"./app-D7uBbsY3.js";const _={},d=u('

                                      XTLS ? Xray ? V2Ray ?

                                      XTLS are brilliant ideas for TLS we study, while Xray is the best practice we maintain.

                                      • Xray-core 是 v2ray-core 的超集,含更好的整体性能和 XTLS 等一系列增强,且完全兼容 v2ray-core 的功能及配置。
                                        • 只有一个可执行文件,含 ctl 的功能,run 为默认指令
                                        • 配置上完全兼容,环境变量和 API 对应要改为以 XRAY_ 开头
                                        • 全平台开放了裸协议的 ReadV
                                        • 提供完整的 VLESS & Trojan XTLS 支持,均有 ReadV
                                        • 提供了 XTLS 多种流控模式, 性能一骑绝尘!

                                      “配置兼容,整体更好”

                                      我们是谁?

                                      It doesn't matter who we are. What matters is that we will keep riding and never look back.

                                      帮助 Xray 变得更强

                                      欢迎帮助 Xray 变得更强!

                                      ',8),p=e("li",null,"🖥️ 帮助开发和测试 Xray, 提交高质量的 Pull request.",-1),X={href:"https://github.com/XTLS/Xray-core/issues",target:"_blank",rel:"noopener noreferrer"},f={href:"https://github.com/XTLS/Xray-core/discussions",target:"_blank",rel:"noopener noreferrer"},b={href:"https://github.com/XTLS/Xray-docs-next",target:"_blank",rel:"noopener noreferrer"},m=e("li",null,"💬 在 Telegram 群帮助群友/灌水.",-1),g=e("li",null,[e("strong",null,"...事实上,每一份对 Xray 的支持都会让 Xray 变得更强大")],-1),y=e("h3",{id:"telegram",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#telegram"},[e("span",null,"Telegram")])],-1),x={href:"https://t.me/projectXray",target:"_blank",rel:"noopener noreferrer"},k=e("ul",null,[e("li",null,"交流群可在底线之上随便水,不要撕逼,没有滥权。"),e("li",null,"有问题尽管随便问,知道的尽量回答。"),e("li",null,"禁政治,禁 NSFW")],-1),L={href:"https://t.me/projectVless",target:"_blank",rel:"noopener noreferrer"},S={href:"https://t.me/projectXray",target:"_blank",rel:"noopener noreferrer"},T=e("li",null,"禁广告,禁人身攻击,禁政治。",-1),j={href:"https://t.me/projectXtls",target:"_blank",rel:"noopener noreferrer"},v=e("ul",null,[e("li",null,"发布 Project X 的最新资讯")],-1),P=e("h3",{id:"致谢",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#致谢"},[e("span",null,"致谢")])],-1),V=e("ul",null,[e("li",null,"感谢所有人的支持!"),e("li",null,"感谢各类脚本、Docker 镜像、客户端支持...感谢所有帮忙完善生态的大佬们!"),e("li",null,"感谢为 Xray 网站和文档添砖加瓦的朋友们."),e("li",null,"感谢提出有意义的建议和意见的朋友们."),e("li",null,"感谢 Telegram 群每一位帮助群友的朋友.")],-1),w=e("h3",{id:"更多关于-project-x",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#更多关于-project-x"},[e("span",null,"更多关于 Project X")])],-1),I={href:"https://github.com/XTLS/Xray-core/discussions/3633",target:"_blank",rel:"noopener noreferrer"},N=e("h3",{id:"license",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#license"},[e("span",null,"License")])],-1),E={href:"https://github.com/XTLS/Xray-core/blob/main/LICENSE",target:"_blank",rel:"noopener noreferrer"},R=e("h3",{id:"stargazers-over-time",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#stargazers-over-time"},[e("span",null,"Stargazers over time")])],-1),q={href:"https://starchart.cc/XTLS/Xray-core",target:"_blank",rel:"noopener noreferrer"},z=e("img",{src:"https://starchart.cc/XTLS/Xray-core.svg",alt:"Stargazers over time"},null,-1);function B(C,F){const o=n("I18nTip"),l=n("ExternalLinkIcon"),a=n("RouterLink");return i(),c("div",null,[t(o),d,e("ul",null,[p,e("li",null,[r("📩 在 "),e("a",X,[r("GitHub Issues"),t(l)]),r(" 或 "),e("a",f,[r("讨论区"),t(l)]),r("发起建设性或有意义的 issue 与 discussion.")]),e("li",null,[r("📝 写下您的使用心得并提交至 Xray 的 "),e("a",b,[r("文档网站"),t(l)]),r(".")]),m,g]),y,e("ul",null,[e("li",null,[e("p",null,[e("a",x,[r("Project X 交流群"),t(l)])]),k]),e("li",null,[e("p",null,[e("a",L,[r("Project VLESS Group"),t(l)])]),e("ul",null,[e("li",null,[r("对非中文参与的官方用户群。 "),e("a",S,[r("Project X"),t(l)]),r(" 的姊妹群。")]),T])]),e("li",null,[e("p",null,[e("a",j,[r("Project X 频道"),t(l)])]),v])]),P,V,w,e("ul",null,[e("li",null,[r("如果你想知道更多关于 Project X 的足迹与成长, 请点击"),t(a,{to:"/about/news.html"},{default:h(()=>[r("这里")]),_:1})]),e("li",null,[r("现在 Project X 也发行 NFT 了!如果想拥有一枚 Project X NFT 或者想捐赠或者赞助 Project X,请点击"),e("a",I,[r("这里"),t(l)])])]),N,e("p",null,[e("a",E,[r("Mozilla Public License Version 2.0"),t(l)])]),R,e("p",null,[e("a",q,[z,t(l)])])])}const G=s(_,[["render",B],["__file","index.html.vue"]]);export{G as default}; diff --git a/assets/index.html-DamtlSYx.js b/assets/index.html-DZCwNSUw.js similarity index 99% rename from assets/index.html-DamtlSYx.js rename to assets/index.html-DZCwNSUw.js index bcc654ecf8..eabf9f8c80 100644 --- a/assets/index.html-DamtlSYx.js +++ b/assets/index.html-DZCwNSUw.js @@ -1,4 +1,4 @@ -import{_ as l,r as e,o as u,c,a as t,b as n,d as s,w as o,e as i}from"./app-DBM4OJyw.js";const r={},d=i(`

                                      这个章节将告诉您所有的 Xray 配置细节,掌握这些内容,在您手中 Xray 将发挥更大威力。

                                      概述

                                      Xray 的配置文件为 json 格式, 客户端和服务端的配置格式没有区别, 只是实际的配置内容不一样。
                                      形式如下:

                                      {
                                      +import{_ as l,r as e,o as u,c,a as t,b as n,d as s,w as o,e as i}from"./app-D7uBbsY3.js";const r={},d=i(`

                                      这个章节将告诉您所有的 Xray 配置细节,掌握这些内容,在您手中 Xray 将发挥更大威力。

                                      概述

                                      Xray 的配置文件为 json 格式, 客户端和服务端的配置格式没有区别, 只是实际的配置内容不一样。
                                      形式如下:

                                      {
                                         "log": {},
                                         "api": {},
                                         "dns": {},
                                      diff --git a/assets/index.html-DrIaJd6V.js b/assets/index.html-DaFDB0pu.js
                                      similarity index 98%
                                      rename from assets/index.html-DrIaJd6V.js
                                      rename to assets/index.html-DaFDB0pu.js
                                      index e21e739f4f..965ae80787 100644
                                      --- a/assets/index.html-DrIaJd6V.js
                                      +++ b/assets/index.html-DaFDB0pu.js
                                      @@ -1 +1 @@
                                      -import{_ as d,r as l,o as h,c as r,a as t,b as e,d as o,w as s}from"./app-DBM4OJyw.js";const _={},i=e("h1",{id:"开发指南",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#开发指南"},[e("span",null,"开发指南")])],-1),p=e("h2",{id:"编译文档",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#编译文档"},[e("span",null,"编译文档")])],-1),u=e("p",null,"Xray 支持各种平台, 您可以在多种平台上自行进行交叉编译。",-1),m=e("h2",{id:"设计思路",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#设计思路"},[e("span",null,"设计思路")])],-1),f=e("p",null,"Xray 内核提供了一个平台,在其之上可以进二次开发。",-1),x=e("p",null,"这个章节阐述了 Xray 的设计目标和架构。",-1),v=e("h2",{id:"开发规范",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#开发规范"},[e("span",null,"开发规范")])],-1),b=e("p",null,"这个章节阐述了获取代码,进行开发,提交 PR 的流程中需要遵循的准则, 以及相关的编码规范。",-1),k=e("h2",{id:"协议详解",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#协议详解"},[e("span",null,"协议详解")])],-1),y=e("p",null,"Xray 用到了很多种协议, 您可以通过各种途径获得协议的详细描述。",-1),X={id:"vless-协议",tabindex:"-1"},C={class:"header-anchor",href:"#vless-协议"},V=e("p",null,"VLESS 是一个无状态的轻量传输协议,可以作为 Xray 客户端和服务器之间的桥梁。",-1),L={id:"vmess-协议",tabindex:"-1"},E={class:"header-anchor",href:"#vmess-协议"},g=e("p",null,"VMess 是一个加密传输协议,可以作为 Xray 客户端和服务器之间的桥梁。",-1),I={id:"mux-cool-协议",tabindex:"-1"},M={class:"header-anchor",href:"#mux-cool-协议"},P=e("p",null,"Mux.Cool 协议是一个多路复用传输协议,用于在一条已建立的数据流中传输多个各自独立的数据流。",-1),S={id:"mkcp-协议",tabindex:"-1"},w={class:"header-anchor",href:"#mkcp-协议"},B={href:"https://github.com/skywind3000/kcp",target:"_blank",rel:"noopener noreferrer"};function K(N,R){const a=l("I18nTip"),n=l("RouterLink"),c=l("ExternalLinkIcon");return h(),r("div",null,[t(a),i,p,u,e("p",null,[o("请点击"),t(n,{to:"/development/intro/compile.html"},{default:s(()=>[o("编译文档")]),_:1}),o("以查看具体编译相关内容。")]),m,f,x,e("p",null,[o("请点击"),t(n,{to:"/development/intro/design.html"},{default:s(()=>[o("设计思路")]),_:1}),o("以了解 Xray 的设计目标和架构。")]),v,b,e("p",null,[o("请点击"),t(n,{to:"/development/intro/guide.html"},{default:s(()=>[o("开发规范")]),_:1}),o("查看 Xray 开发中应遵循的准则。")]),k,y,e("h3",X,[e("a",C,[e("span",null,[t(n,{to:"/development/protocols/vless.html"},{default:s(()=>[o("VLESS 协议")]),_:1})])])]),V,e("h3",L,[e("a",E,[e("span",null,[t(n,{to:"/development/protocols/vmess.html"},{default:s(()=>[o("VMess 协议")]),_:1})])])]),g,e("h3",I,[e("a",M,[e("span",null,[t(n,{to:"/development/protocols/muxcool.html"},{default:s(()=>[o("Mux.Cool 协议")]),_:1})])])]),P,e("h3",S,[e("a",w,[e("span",null,[t(n,{to:"/development/protocols/mkcp.html"},{default:s(()=>[o("mKCP 协议")]),_:1})])])]),e("p",null,[o("mKCP 是流式传输协议,由 "),e("a",B,[o("KCP 协议"),t(c)]),o("修改而来,可以按顺序传输任意的数据流。")])])}const j=d(_,[["render",K],["__file","index.html.vue"]]);export{j as default};
                                      +import{_ as d,r as l,o as h,c as r,a as t,b as e,d as o,w as s}from"./app-D7uBbsY3.js";const _={},i=e("h1",{id:"开发指南",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#开发指南"},[e("span",null,"开发指南")])],-1),p=e("h2",{id:"编译文档",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#编译文档"},[e("span",null,"编译文档")])],-1),u=e("p",null,"Xray 支持各种平台, 您可以在多种平台上自行进行交叉编译。",-1),m=e("h2",{id:"设计思路",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#设计思路"},[e("span",null,"设计思路")])],-1),f=e("p",null,"Xray 内核提供了一个平台,在其之上可以进二次开发。",-1),x=e("p",null,"这个章节阐述了 Xray 的设计目标和架构。",-1),v=e("h2",{id:"开发规范",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#开发规范"},[e("span",null,"开发规范")])],-1),b=e("p",null,"这个章节阐述了获取代码,进行开发,提交 PR 的流程中需要遵循的准则, 以及相关的编码规范。",-1),k=e("h2",{id:"协议详解",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#协议详解"},[e("span",null,"协议详解")])],-1),y=e("p",null,"Xray 用到了很多种协议, 您可以通过各种途径获得协议的详细描述。",-1),X={id:"vless-协议",tabindex:"-1"},C={class:"header-anchor",href:"#vless-协议"},V=e("p",null,"VLESS 是一个无状态的轻量传输协议,可以作为 Xray 客户端和服务器之间的桥梁。",-1),L={id:"vmess-协议",tabindex:"-1"},E={class:"header-anchor",href:"#vmess-协议"},g=e("p",null,"VMess 是一个加密传输协议,可以作为 Xray 客户端和服务器之间的桥梁。",-1),I={id:"mux-cool-协议",tabindex:"-1"},M={class:"header-anchor",href:"#mux-cool-协议"},P=e("p",null,"Mux.Cool 协议是一个多路复用传输协议,用于在一条已建立的数据流中传输多个各自独立的数据流。",-1),S={id:"mkcp-协议",tabindex:"-1"},w={class:"header-anchor",href:"#mkcp-协议"},B={href:"https://github.com/skywind3000/kcp",target:"_blank",rel:"noopener noreferrer"};function K(N,R){const a=l("I18nTip"),n=l("RouterLink"),c=l("ExternalLinkIcon");return h(),r("div",null,[t(a),i,p,u,e("p",null,[o("请点击"),t(n,{to:"/development/intro/compile.html"},{default:s(()=>[o("编译文档")]),_:1}),o("以查看具体编译相关内容。")]),m,f,x,e("p",null,[o("请点击"),t(n,{to:"/development/intro/design.html"},{default:s(()=>[o("设计思路")]),_:1}),o("以了解 Xray 的设计目标和架构。")]),v,b,e("p",null,[o("请点击"),t(n,{to:"/development/intro/guide.html"},{default:s(()=>[o("开发规范")]),_:1}),o("查看 Xray 开发中应遵循的准则。")]),k,y,e("h3",X,[e("a",C,[e("span",null,[t(n,{to:"/development/protocols/vless.html"},{default:s(()=>[o("VLESS 协议")]),_:1})])])]),V,e("h3",L,[e("a",E,[e("span",null,[t(n,{to:"/development/protocols/vmess.html"},{default:s(()=>[o("VMess 协议")]),_:1})])])]),g,e("h3",I,[e("a",M,[e("span",null,[t(n,{to:"/development/protocols/muxcool.html"},{default:s(()=>[o("Mux.Cool 协议")]),_:1})])])]),P,e("h3",S,[e("a",w,[e("span",null,[t(n,{to:"/development/protocols/mkcp.html"},{default:s(()=>[o("mKCP 协议")]),_:1})])])]),e("p",null,[o("mKCP 是流式传输协议,由 "),e("a",B,[o("KCP 协议"),t(c)]),o("修改而来,可以按顺序传输任意的数据流。")])])}const j=d(_,[["render",K],["__file","index.html.vue"]]);export{j as default};
                                      diff --git a/assets/index.html-Cl2CfXNF.js b/assets/index.html-DdCQTcSZ.js
                                      similarity index 98%
                                      rename from assets/index.html-Cl2CfXNF.js
                                      rename to assets/index.html-DdCQTcSZ.js
                                      index 304c31ea35..f1e0aa6b67 100644
                                      --- a/assets/index.html-Cl2CfXNF.js
                                      +++ b/assets/index.html-DdCQTcSZ.js
                                      @@ -1 +1 @@
                                      -import{_ as c,r as a,o as d,c as r,a as t,b as e,d as n,w as o}from"./app-DBM4OJyw.js";const u={},h=e("h1",{id:"быстрыи-старт",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#быстрыи-старт"},[e("span",null,"Быстрый старт")])],-1),_=e("blockquote",null,[e("p",null,[e("strong",null,"В этой главе вы узнаете, как максимально просто получить Xray и начать его использовать.")])],-1),i=e("h2",{id:"загрузка-и-установка",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#загрузка-и-установка"},[e("span",null,"Загрузка и установка")])],-1),p=e("p",null,"Xray поддерживает разнообразные платформы, и вы можете получить разные версии Xray из множества источников и различными способами.",-1),m=e("h2",{id:"настроика-и-запуск",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#настроика-и-запуск"},[e("span",null,"Настройка и запуск")])],-1),f=e("p",null,"После загрузки и установки Xray вам нужно всего лишь настроить его, чтобы начать использование.",-1),x=e("h2",{id:"команды-и-аргументы",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#команды-и-аргументы"},[e("span",null,"Команды и аргументы")])],-1),b=e("p",null,"Xray обладает множеством команд и аргументов, что делает его гибким и мощным.",-1),X=e("h2",{id:"улучшение-документации",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#улучшение-документации"},[e("span",null,"Улучшение документации")])],-1),y=e("code",null,"Помогите нам улучшить эту страницу!",-1),v=e("p",null,"Мы очень благодарны каждому участнику за вклад! Вы делаете Project X сильнее!",-1),k=e("h2",{id:"простыми-словами",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#простыми-словами"},[e("span",null,"Простыми словами")])],-1),B=e("p",null,"Практические советы для новичков.",-1),N=e("h2",{id:"базовые-навыки",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#базовые-навыки"},[e("span",null,"Базовые навыки")])],-1),T=e("h2",{id:"продвинутая-документация",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#продвинутая-документация"},[e("span",null,"Продвинутая документация")])],-1),V=e("p",null,"Практические советы для опытных пользователей.",-1),g=e("div",{class:"custom-container tip"},[e("p",{class:"custom-container-title"},"Благодарность"),e("p",null,"Огромное спасибо всем за то, что делитесь своими навыками и опытом, которые делают Xray с каждым днем ​​лучше.")],-1);function w(C,I){const s=a("I18nTip"),l=a("RouterLink");return d(),r("div",null,[h,t(s),_,i,p,e("p",null,[n("Перейдите в раздел "),t(l,{to:"/ru/document/install.html"},{default:o(()=>[n("Загрузка и установка")]),_:1}),n(", чтобы загрузить Xray.")]),m,f,e("p",null,[n("Перейдите в раздел "),t(l,{to:"/ru/document/config.html"},{default:o(()=>[n("Настройка и запуск")]),_:1}),n(", чтобы изучить самый простой способ настройки.")]),x,b,e("p",null,[n("Перейдите в раздел "),t(l,{to:"/ru/document/command.html"},{default:o(()=>[n("Команды и аргументы")]),_:1}),n(", чтобы узнать больше о командах и аргументах Xray.")]),X,e("p",null,[n("Если вы заинтересованы, перейдите в раздел "),t(l,{to:"/ru/document/document.html"},{default:o(()=>[n("Использование документации")]),_:1}),n(", чтобы помочь нам улучшить документацию, или нажмите кнопку "),y,n(" внизу страницы.")]),v,k,B,e("p",null,[n("Перейдите в раздел "),t(l,{to:"/ru/document/level-0/"},{default:o(()=>[n("Простыми словами")]),_:1}),n(" для просмотра.")]),N,e("p",null,[n("Освоив основы, вы можете перейти к разделу "),t(l,{to:"/ru/document/level-1/"},{default:o(()=>[n("Базовые навыки")]),_:1}),n(", чтобы узнать о других способах использования.")]),T,V,e("p",null,[n("Перейдите в раздел "),t(l,{to:"/ru/document/level-2/"},{default:o(()=>[n("Продвинутая документация")]),_:1}),n(" для просмотра.")]),g])}const R=c(u,[["render",w],["__file","index.html.vue"]]);export{R as default};
                                      +import{_ as c,r as a,o as d,c as r,a as t,b as e,d as n,w as o}from"./app-D7uBbsY3.js";const u={},h=e("h1",{id:"быстрыи-старт",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#быстрыи-старт"},[e("span",null,"Быстрый старт")])],-1),_=e("blockquote",null,[e("p",null,[e("strong",null,"В этой главе вы узнаете, как максимально просто получить Xray и начать его использовать.")])],-1),i=e("h2",{id:"загрузка-и-установка",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#загрузка-и-установка"},[e("span",null,"Загрузка и установка")])],-1),p=e("p",null,"Xray поддерживает разнообразные платформы, и вы можете получить разные версии Xray из множества источников и различными способами.",-1),m=e("h2",{id:"настроика-и-запуск",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#настроика-и-запуск"},[e("span",null,"Настройка и запуск")])],-1),f=e("p",null,"После загрузки и установки Xray вам нужно всего лишь настроить его, чтобы начать использование.",-1),x=e("h2",{id:"команды-и-аргументы",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#команды-и-аргументы"},[e("span",null,"Команды и аргументы")])],-1),b=e("p",null,"Xray обладает множеством команд и аргументов, что делает его гибким и мощным.",-1),X=e("h2",{id:"улучшение-документации",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#улучшение-документации"},[e("span",null,"Улучшение документации")])],-1),y=e("code",null,"Помогите нам улучшить эту страницу!",-1),v=e("p",null,"Мы очень благодарны каждому участнику за вклад! Вы делаете Project X сильнее!",-1),k=e("h2",{id:"простыми-словами",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#простыми-словами"},[e("span",null,"Простыми словами")])],-1),B=e("p",null,"Практические советы для новичков.",-1),N=e("h2",{id:"базовые-навыки",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#базовые-навыки"},[e("span",null,"Базовые навыки")])],-1),T=e("h2",{id:"продвинутая-документация",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#продвинутая-документация"},[e("span",null,"Продвинутая документация")])],-1),V=e("p",null,"Практические советы для опытных пользователей.",-1),g=e("div",{class:"custom-container tip"},[e("p",{class:"custom-container-title"},"Благодарность"),e("p",null,"Огромное спасибо всем за то, что делитесь своими навыками и опытом, которые делают Xray с каждым днем ​​лучше.")],-1);function w(C,I){const s=a("I18nTip"),l=a("RouterLink");return d(),r("div",null,[h,t(s),_,i,p,e("p",null,[n("Перейдите в раздел "),t(l,{to:"/ru/document/install.html"},{default:o(()=>[n("Загрузка и установка")]),_:1}),n(", чтобы загрузить Xray.")]),m,f,e("p",null,[n("Перейдите в раздел "),t(l,{to:"/ru/document/config.html"},{default:o(()=>[n("Настройка и запуск")]),_:1}),n(", чтобы изучить самый простой способ настройки.")]),x,b,e("p",null,[n("Перейдите в раздел "),t(l,{to:"/ru/document/command.html"},{default:o(()=>[n("Команды и аргументы")]),_:1}),n(", чтобы узнать больше о командах и аргументах Xray.")]),X,e("p",null,[n("Если вы заинтересованы, перейдите в раздел "),t(l,{to:"/ru/document/document.html"},{default:o(()=>[n("Использование документации")]),_:1}),n(", чтобы помочь нам улучшить документацию, или нажмите кнопку "),y,n(" внизу страницы.")]),v,k,B,e("p",null,[n("Перейдите в раздел "),t(l,{to:"/ru/document/level-0/"},{default:o(()=>[n("Простыми словами")]),_:1}),n(" для просмотра.")]),N,e("p",null,[n("Освоив основы, вы можете перейти к разделу "),t(l,{to:"/ru/document/level-1/"},{default:o(()=>[n("Базовые навыки")]),_:1}),n(", чтобы узнать о других способах использования.")]),T,V,e("p",null,[n("Перейдите в раздел "),t(l,{to:"/ru/document/level-2/"},{default:o(()=>[n("Продвинутая документация")]),_:1}),n(" для просмотра.")]),g])}const R=c(u,[["render",w],["__file","index.html.vue"]]);export{R as default};
                                      diff --git a/assets/index.html-BKL86b_Z.js b/assets/index.html-DgnGOa7Z.js
                                      similarity index 98%
                                      rename from assets/index.html-BKL86b_Z.js
                                      rename to assets/index.html-DgnGOa7Z.js
                                      index ab2900782e..c447fe6d48 100644
                                      --- a/assets/index.html-BKL86b_Z.js
                                      +++ b/assets/index.html-DgnGOa7Z.js
                                      @@ -1 +1 @@
                                      -import{_ as s,r as n,o as i,c,a as t,b as e,d as o,w as h,e as u}from"./app-DBM4OJyw.js";const p={},d=u('

                                      XTLS? Xray? V2Ray?

                                      XTLS are brilliant ideas for TLS we study, while Xray is the best practice we maintain.

                                      • Xray-core is a superset of v2ray-core, with better overall performance and enhancements such as XTLS, and it'scompletelycompatible with v2ray-core functionality and configuration.
                                        • Only one executable file, including ctl functionality, run is the default command
                                        • Configuration iscompletelycompatible, environment variables and API calls need to be changed to start with XRAY_
                                        • Exposed raw protocol's ReadV on all platforms
                                        • Provides complete VLESS & Trojan XTLS support, both with ReadV
                                        • Provides multiple XTLS flow control modes, unrivaled performance!

                                      "Configuration compatible, overall better"

                                      Who are we?

                                      It doesn't matter who we are. What matters is that we will keep riding and never look back.

                                      Help Xray become stronger

                                      Welcome to help Xray become stronger!

                                      ',8),_=e("li",null,"🖥️ Help develop and test Xray, submit high-quality Pull requests.",-1),m={href:"https://github.com/XTLS/Xray-core/issues",target:"_blank",rel:"noopener noreferrer"},f={href:"https://github.com/XTLS/Xray-core/discussions",target:"_blank",rel:"noopener noreferrer"},b={href:"https://github.com/XTLS/Xray-docs-next",target:"_blank",rel:"noopener noreferrer"},g=e("li",null,"💬 Help group members/chat in Telegram group.",-1),y=e("li",null,[e("strong",null,"...In fact, every support for Xray will make Xray stronger")],-1),X=e("h3",{id:"telegram",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#telegram"},[e("span",null,"Telegram")])],-1),k={href:"https://t.me/projectXray",target:"_blank",rel:"noopener noreferrer"},w=e("ul",null,[e("li",null,"You can chat freely above the bottom line in the discussion group, don't fight, no abuse of power."),e("li",null,"Feel free to ask questions, and try to answer those you know."),e("li",null,"No politics, No NSFW")],-1),v={href:"https://t.me/projectVless",target:"_blank",rel:"noopener noreferrer"},T={href:"https://t.me/projectXray",target:"_blank",rel:"noopener noreferrer"},x=e("li",null,"No advertising, No insults, No politics.",-1),S={href:"https://t.me/projectXtls",target:"_blank",rel:"noopener noreferrer"},L=e("ul",null,[e("li",null,"Publish the latest news of Project X")],-1),j=e("h3",{id:"thanks",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#thanks"},[e("span",null,"Thanks")])],-1),N=e("ul",null,[e("li",null,"Thanks to everyone for their support!"),e("li",null,"Thanks to all kinds of scripts, Docker images, client support... Thanks to all the big guys who helped improve the ecosystem!"),e("li",null,"Thanks to friends who have contributed to the Xray website and documentation."),e("li",null,"Thanks to friends who have made meaningful suggestions and comments."),e("li",null,"Thanks to every friend in the Telegram group who helps others.")],-1),P=e("h3",{id:"more-about-project-x",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#more-about-project-x"},[e("span",null,"More about project X")])],-1),I={href:"https://github.com/XTLS/Xray-core/discussions/3633#discussioncomment-10240940",target:"_blank",rel:"noopener noreferrer"},V=e("h3",{id:"license",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#license"},[e("span",null,"License")])],-1),q={href:"https://github.com/XTLS/Xray-core/blob/main/LICENSE",target:"_blank",rel:"noopener noreferrer"},E=e("h3",{id:"stargazers-over-time",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#stargazers-over-time"},[e("span",null,"Stargazers over time")])],-1),C={href:"https://starchart.cc/XTLS/Xray-core",target:"_blank",rel:"noopener noreferrer"},R=e("img",{src:"https://starchart.cc/XTLS/Xray-core.svg",alt:"Stargazers over time"},null,-1);function z(W,F){const a=n("I18nTip"),r=n("ExternalLinkIcon"),l=n("RouterLink");return i(),c("div",null,[t(a),d,e("ul",null,[_,e("li",null,[o("📩 Initiate constructive or meaningful issues and discussions in "),e("a",m,[o("GitHub Issues"),t(r)]),o(" or "),e("a",f,[o("Discussion area"),t(r)]),o(".")]),e("li",null,[o("📝 Write down your usage experience and submit it to Xray's "),e("a",b,[o("documentation website"),t(r)]),o(".")]),g,y]),X,e("ul",null,[e("li",null,[e("p",null,[e("a",k,[o("Project X Discussion Group"),t(r)])]),w]),e("li",null,[e("p",null,[e("a",v,[o("Project VLESS Group"),t(r)])]),e("ul",null,[e("li",null,[o("The official Xray-core group for non-Chinese participants. Sister group of "),e("a",T,[o("Project X"),t(r)])]),x])]),e("li",null,[e("p",null,[e("a",S,[o("Project X Channel"),t(r)])]),L])]),j,N,P,e("ul",null,[e("li",null,[o("If you would like to learn more about project X's history and growth, please click "),t(l,{to:"/en/about/news.html"},{default:h(()=>[o("here")]),_:1})]),e("li",null,[o("Now Project X releases NFTs! If you would like to have one Project X NFT, or want to donate to or sponsoring Project X, please click "),e("a",I,[o("here"),t(r)])])]),V,e("p",null,[e("a",q,[o("Mozilla Public License Version 2.0"),t(r)])]),E,e("p",null,[e("a",C,[R,t(r)])])])}const B=s(p,[["render",z],["__file","index.html.vue"]]);export{B as default}; +import{_ as s,r as n,o as i,c,a as t,b as e,d as o,w as h,e as u}from"./app-D7uBbsY3.js";const p={},d=u('

                                      XTLS? Xray? V2Ray?

                                      XTLS are brilliant ideas for TLS we study, while Xray is the best practice we maintain.

                                      • Xray-core is a superset of v2ray-core, with better overall performance and enhancements such as XTLS, and it'scompletelycompatible with v2ray-core functionality and configuration.
                                        • Only one executable file, including ctl functionality, run is the default command
                                        • Configuration iscompletelycompatible, environment variables and API calls need to be changed to start with XRAY_
                                        • Exposed raw protocol's ReadV on all platforms
                                        • Provides complete VLESS & Trojan XTLS support, both with ReadV
                                        • Provides multiple XTLS flow control modes, unrivaled performance!

                                      "Configuration compatible, overall better"

                                      Who are we?

                                      It doesn't matter who we are. What matters is that we will keep riding and never look back.

                                      Help Xray become stronger

                                      Welcome to help Xray become stronger!

                                      ',8),_=e("li",null,"🖥️ Help develop and test Xray, submit high-quality Pull requests.",-1),m={href:"https://github.com/XTLS/Xray-core/issues",target:"_blank",rel:"noopener noreferrer"},f={href:"https://github.com/XTLS/Xray-core/discussions",target:"_blank",rel:"noopener noreferrer"},b={href:"https://github.com/XTLS/Xray-docs-next",target:"_blank",rel:"noopener noreferrer"},g=e("li",null,"💬 Help group members/chat in Telegram group.",-1),y=e("li",null,[e("strong",null,"...In fact, every support for Xray will make Xray stronger")],-1),X=e("h3",{id:"telegram",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#telegram"},[e("span",null,"Telegram")])],-1),k={href:"https://t.me/projectXray",target:"_blank",rel:"noopener noreferrer"},w=e("ul",null,[e("li",null,"You can chat freely above the bottom line in the discussion group, don't fight, no abuse of power."),e("li",null,"Feel free to ask questions, and try to answer those you know."),e("li",null,"No politics, No NSFW")],-1),v={href:"https://t.me/projectVless",target:"_blank",rel:"noopener noreferrer"},T={href:"https://t.me/projectXray",target:"_blank",rel:"noopener noreferrer"},x=e("li",null,"No advertising, No insults, No politics.",-1),S={href:"https://t.me/projectXtls",target:"_blank",rel:"noopener noreferrer"},L=e("ul",null,[e("li",null,"Publish the latest news of Project X")],-1),j=e("h3",{id:"thanks",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#thanks"},[e("span",null,"Thanks")])],-1),N=e("ul",null,[e("li",null,"Thanks to everyone for their support!"),e("li",null,"Thanks to all kinds of scripts, Docker images, client support... Thanks to all the big guys who helped improve the ecosystem!"),e("li",null,"Thanks to friends who have contributed to the Xray website and documentation."),e("li",null,"Thanks to friends who have made meaningful suggestions and comments."),e("li",null,"Thanks to every friend in the Telegram group who helps others.")],-1),P=e("h3",{id:"more-about-project-x",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#more-about-project-x"},[e("span",null,"More about project X")])],-1),I={href:"https://github.com/XTLS/Xray-core/discussions/3633#discussioncomment-10240940",target:"_blank",rel:"noopener noreferrer"},V=e("h3",{id:"license",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#license"},[e("span",null,"License")])],-1),q={href:"https://github.com/XTLS/Xray-core/blob/main/LICENSE",target:"_blank",rel:"noopener noreferrer"},E=e("h3",{id:"stargazers-over-time",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#stargazers-over-time"},[e("span",null,"Stargazers over time")])],-1),C={href:"https://starchart.cc/XTLS/Xray-core",target:"_blank",rel:"noopener noreferrer"},R=e("img",{src:"https://starchart.cc/XTLS/Xray-core.svg",alt:"Stargazers over time"},null,-1);function z(W,F){const a=n("I18nTip"),r=n("ExternalLinkIcon"),l=n("RouterLink");return i(),c("div",null,[t(a),d,e("ul",null,[_,e("li",null,[o("📩 Initiate constructive or meaningful issues and discussions in "),e("a",m,[o("GitHub Issues"),t(r)]),o(" or "),e("a",f,[o("Discussion area"),t(r)]),o(".")]),e("li",null,[o("📝 Write down your usage experience and submit it to Xray's "),e("a",b,[o("documentation website"),t(r)]),o(".")]),g,y]),X,e("ul",null,[e("li",null,[e("p",null,[e("a",k,[o("Project X Discussion Group"),t(r)])]),w]),e("li",null,[e("p",null,[e("a",v,[o("Project VLESS Group"),t(r)])]),e("ul",null,[e("li",null,[o("The official Xray-core group for non-Chinese participants. Sister group of "),e("a",T,[o("Project X"),t(r)])]),x])]),e("li",null,[e("p",null,[e("a",S,[o("Project X Channel"),t(r)])]),L])]),j,N,P,e("ul",null,[e("li",null,[o("If you would like to learn more about project X's history and growth, please click "),t(l,{to:"/en/about/news.html"},{default:h(()=>[o("here")]),_:1})]),e("li",null,[o("Now Project X releases NFTs! If you would like to have one Project X NFT, or want to donate to or sponsoring Project X, please click "),e("a",I,[o("here"),t(r)])])]),V,e("p",null,[e("a",q,[o("Mozilla Public License Version 2.0"),t(r)])]),E,e("p",null,[e("a",C,[R,t(r)])])])}const B=s(p,[["render",z],["__file","index.html.vue"]]);export{B as default}; diff --git a/assets/index.html-BYuUObTq.js b/assets/index.html-Dvi2iZCq.js similarity index 99% rename from assets/index.html-BYuUObTq.js rename to assets/index.html-Dvi2iZCq.js index bab8b07c0b..b85884fc76 100644 --- a/assets/index.html-BYuUObTq.js +++ b/assets/index.html-Dvi2iZCq.js @@ -1,4 +1,4 @@ -import{_ as c,r as e,o as p,c as u,a as s,b as n,d as t,w as a,e as i}from"./app-DBM4OJyw.js";const r={},d=i(`

                                      This section will tell you all the details of Xray configuration. By mastering these contents, Xray will unleash its full power in your hands.

                                      Overview

                                      The configuration file of Xray is in JSON format, and the configuration format for the client and server is the same, except for the actual configuration content. It takes the following form:

                                      {
                                      +import{_ as c,r as e,o as p,c as u,a as s,b as n,d as t,w as a,e as i}from"./app-D7uBbsY3.js";const r={},d=i(`

                                      This section will tell you all the details of Xray configuration. By mastering these contents, Xray will unleash its full power in your hands.

                                      Overview

                                      The configuration file of Xray is in JSON format, and the configuration format for the client and server is the same, except for the actual configuration content. It takes the following form:

                                      {
                                         "log": {},
                                         "api": {},
                                         "dns": {},
                                      diff --git a/assets/index.html-Nkob2LGl.js b/assets/index.html-Dw7aezrN.js
                                      similarity index 98%
                                      rename from assets/index.html-Nkob2LGl.js
                                      rename to assets/index.html-Dw7aezrN.js
                                      index 10ae88a7b5..4fbe5eadc2 100644
                                      --- a/assets/index.html-Nkob2LGl.js
                                      +++ b/assets/index.html-Dw7aezrN.js
                                      @@ -1 +1 @@
                                      -import{_ as i,r as a,o as h,c as _,a as n,b as t,w as s,d as e}from"./app-DBM4OJyw.js";const c={},u=t("h1",{id:"进阶文档",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#进阶文档"},[t("span",null,"进阶文档")])],-1),d=t("p",null,[t("strong",null,"这个章节包含进阶级的 Xray 使用心得分享, 如果您已经熟悉 Xray, 那么这里的经验可以让您更加发挥 Xray 的威力")],-1),p=t("img",{src:"https://avatars2.githubusercontent.com/u/57820613?s=32",width:"32",height:"32",alt:"a"},null,-1),m={href:"https://github.com/kirin10000",target:"_blank",rel:"noopener noreferrer"},g=t("p",null,"透明代理的入门篇章。",-1),f=t("img",{src:"https://avatars2.githubusercontent.com/u/41363844?s=32",width:"32",height:"32",alt:"a"},null,-1),b={href:"https://github.com/BioniCosmos",target:"_blank",rel:"noopener noreferrer"},y=t("p",null,"基于 Xray 的透明代理(TProxy)配置完整教程。",-1),v=t("img",{src:"https://avatars.githubusercontent.com/u/110686480?s=32",width:"32",height:"32",alt:"a"},null,-1),x={href:"https://github.com/SQLimit",target:"_blank",rel:"noopener noreferrer"},k=t("p",null,"基于 Xray 的 TProxy 透明代理(ipv4 and ipv6)配置教程",-1),w=t("img",{src:"https://avatars.githubusercontent.com/u/110686480?s=32",width:"32",height:"32",alt:"a"},null,-1),X={href:"https://github.com/SQLimit",target:"_blank",rel:"noopener noreferrer"},L=t("p",null,"双端使用 Nginx 或 Haproxy 搭建 TLS 隧道隐藏指纹",-1),T=t("img",{src:"https://avatars2.githubusercontent.com/u/57820613?s=32",width:"32",height:"32",alt:"a"},null,-1),S={href:"https://github.com/kirin10000",target:"_blank",rel:"noopener noreferrer"},B=t("p",null,"在 iptables/nftables 实现的透明代理中,一种新的规避 Xray 流量的方式。",-1),C=t("img",{src:"https://avatars.githubusercontent.com/u/28607089?s=32",width:"32",height:"32",alt:"a"},null,-1),N={href:"https://github.com/Zzz3m",target:"_blank",rel:"noopener noreferrer"},z=t("p",null,"将 Xray 玩出花:基于 fwmark 、 sendThrough 或 sockopt.interface 方式实现“分流”。",-1),I=t("img",{src:"https://avatars.githubusercontent.com/u/1588741?s=32",width:"32",height:"32",alt:"a"},null,-1),P={href:"https://github.com/yuhan6665",target:"_blank",rel:"noopener noreferrer"},Q=t("p",null,"Xray v1.6.5 新增 WireGuard 出站的使用介绍。",-1),E=t("img",{src:"https://avatars.githubusercontent.com/u/1588741?s=32",width:"32",height:"32",alt:"a"},null,-1),V={href:"https://github.com/yuhan6665",target:"_blank",rel:"noopener noreferrer"},H=t("p",null,"适配 Xray 的流量统计和脚本。",-1);function R(W,Z){const l=a("I18nTip"),o=a("RouterLink"),r=a("ExternalLinkIcon");return h(),_("div",null,[n(l),u,d,t("p",null,[n(o,{to:"/document/level-2/transparent_proxy/transparent_proxy.html"},{default:s(()=>[e("透明代理入门")]),_:1}),e(" by "),p,e(),t("a",m,[e("@kirin"),n(r)])]),g,t("p",null,[n(o,{to:"/document/level-2/tproxy.html"},{default:s(()=>[e("透明代理(TProxy)配置教程 ")]),_:1}),e(" by "),f,e(),t("a",b,[e("@BioniCosmos"),n(r)])]),y,t("p",null,[n(o,{to:"/document/level-2/tproxy_ipv4_and_ipv6.html"},{default:s(()=>[e("TProxy 透明代理(ipv4 and ipv6)配置教程")]),_:1}),e(" by "),v,e(),t("a",x,[e("@SQLimit"),n(r)])]),k,t("p",null,[n(o,{to:"/document/level-2/nginx_or_haproxy_tls_tunnel.html"},{default:s(()=>[e("Nginx 或 Haproxy 搭建 TLS 隧道隐藏指纹")]),_:1}),e(" by "),w,e(),t("a",X,[e("@SQLimit"),n(r)])]),L,t("p",null,[n(o,{to:"/document/level-2/iptables_gid.html"},{default:s(()=>[e("[透明代理]通过 gid 规避 Xray 流量")]),_:1}),e(" by "),T,e(),t("a",S,[e("@kirin"),n(r)])]),B,t("p",null,[n(o,{to:"/document/level-2/redirect.html"},{default:s(()=>[e("通过 Xray 将特定的流量指向特定出口,实现全局路由“分流”")]),_:1}),e(" by "),C,e(),t("a",N,[e("@Zzz3m"),n(r)])]),z,t("p",null,[n(o,{to:"/document/level-2/warp.html"},{default:s(()=>[e("通过 Cloudflare Warp 增强代理安全性")]),_:1}),e(" by "),I,e(),t("a",P,[e("@yuhan6665"),n(r)])]),Q,t("p",null,[n(o,{to:"/document/level-2/traffic_stats.html"},{default:s(()=>[e("Xray 流量统计")]),_:1}),e(" by "),E,e(),t("a",V,[e("@yuhan6665"),n(r)])]),H])}const j=i(c,[["render",R],["__file","index.html.vue"]]);export{j as default};
                                      +import{_ as i,r as a,o as h,c as _,a as n,b as t,w as s,d as e}from"./app-D7uBbsY3.js";const c={},u=t("h1",{id:"进阶文档",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#进阶文档"},[t("span",null,"进阶文档")])],-1),d=t("p",null,[t("strong",null,"这个章节包含进阶级的 Xray 使用心得分享, 如果您已经熟悉 Xray, 那么这里的经验可以让您更加发挥 Xray 的威力")],-1),p=t("img",{src:"https://avatars2.githubusercontent.com/u/57820613?s=32",width:"32",height:"32",alt:"a"},null,-1),m={href:"https://github.com/kirin10000",target:"_blank",rel:"noopener noreferrer"},g=t("p",null,"透明代理的入门篇章。",-1),f=t("img",{src:"https://avatars2.githubusercontent.com/u/41363844?s=32",width:"32",height:"32",alt:"a"},null,-1),b={href:"https://github.com/BioniCosmos",target:"_blank",rel:"noopener noreferrer"},y=t("p",null,"基于 Xray 的透明代理(TProxy)配置完整教程。",-1),v=t("img",{src:"https://avatars.githubusercontent.com/u/110686480?s=32",width:"32",height:"32",alt:"a"},null,-1),x={href:"https://github.com/SQLimit",target:"_blank",rel:"noopener noreferrer"},k=t("p",null,"基于 Xray 的 TProxy 透明代理(ipv4 and ipv6)配置教程",-1),w=t("img",{src:"https://avatars.githubusercontent.com/u/110686480?s=32",width:"32",height:"32",alt:"a"},null,-1),X={href:"https://github.com/SQLimit",target:"_blank",rel:"noopener noreferrer"},L=t("p",null,"双端使用 Nginx 或 Haproxy 搭建 TLS 隧道隐藏指纹",-1),T=t("img",{src:"https://avatars2.githubusercontent.com/u/57820613?s=32",width:"32",height:"32",alt:"a"},null,-1),S={href:"https://github.com/kirin10000",target:"_blank",rel:"noopener noreferrer"},B=t("p",null,"在 iptables/nftables 实现的透明代理中,一种新的规避 Xray 流量的方式。",-1),C=t("img",{src:"https://avatars.githubusercontent.com/u/28607089?s=32",width:"32",height:"32",alt:"a"},null,-1),N={href:"https://github.com/Zzz3m",target:"_blank",rel:"noopener noreferrer"},z=t("p",null,"将 Xray 玩出花:基于 fwmark 、 sendThrough 或 sockopt.interface 方式实现“分流”。",-1),I=t("img",{src:"https://avatars.githubusercontent.com/u/1588741?s=32",width:"32",height:"32",alt:"a"},null,-1),P={href:"https://github.com/yuhan6665",target:"_blank",rel:"noopener noreferrer"},Q=t("p",null,"Xray v1.6.5 新增 WireGuard 出站的使用介绍。",-1),E=t("img",{src:"https://avatars.githubusercontent.com/u/1588741?s=32",width:"32",height:"32",alt:"a"},null,-1),V={href:"https://github.com/yuhan6665",target:"_blank",rel:"noopener noreferrer"},H=t("p",null,"适配 Xray 的流量统计和脚本。",-1);function R(W,Z){const l=a("I18nTip"),o=a("RouterLink"),r=a("ExternalLinkIcon");return h(),_("div",null,[n(l),u,d,t("p",null,[n(o,{to:"/document/level-2/transparent_proxy/transparent_proxy.html"},{default:s(()=>[e("透明代理入门")]),_:1}),e(" by "),p,e(),t("a",m,[e("@kirin"),n(r)])]),g,t("p",null,[n(o,{to:"/document/level-2/tproxy.html"},{default:s(()=>[e("透明代理(TProxy)配置教程 ")]),_:1}),e(" by "),f,e(),t("a",b,[e("@BioniCosmos"),n(r)])]),y,t("p",null,[n(o,{to:"/document/level-2/tproxy_ipv4_and_ipv6.html"},{default:s(()=>[e("TProxy 透明代理(ipv4 and ipv6)配置教程")]),_:1}),e(" by "),v,e(),t("a",x,[e("@SQLimit"),n(r)])]),k,t("p",null,[n(o,{to:"/document/level-2/nginx_or_haproxy_tls_tunnel.html"},{default:s(()=>[e("Nginx 或 Haproxy 搭建 TLS 隧道隐藏指纹")]),_:1}),e(" by "),w,e(),t("a",X,[e("@SQLimit"),n(r)])]),L,t("p",null,[n(o,{to:"/document/level-2/iptables_gid.html"},{default:s(()=>[e("[透明代理]通过 gid 规避 Xray 流量")]),_:1}),e(" by "),T,e(),t("a",S,[e("@kirin"),n(r)])]),B,t("p",null,[n(o,{to:"/document/level-2/redirect.html"},{default:s(()=>[e("通过 Xray 将特定的流量指向特定出口,实现全局路由“分流”")]),_:1}),e(" by "),C,e(),t("a",N,[e("@Zzz3m"),n(r)])]),z,t("p",null,[n(o,{to:"/document/level-2/warp.html"},{default:s(()=>[e("通过 Cloudflare Warp 增强代理安全性")]),_:1}),e(" by "),I,e(),t("a",P,[e("@yuhan6665"),n(r)])]),Q,t("p",null,[n(o,{to:"/document/level-2/traffic_stats.html"},{default:s(()=>[e("Xray 流量统计")]),_:1}),e(" by "),E,e(),t("a",V,[e("@yuhan6665"),n(r)])]),H])}const j=i(c,[["render",R],["__file","index.html.vue"]]);export{j as default};
                                      diff --git a/assets/index.html-BBL6nyUH.js b/assets/index.html-SiiWkWVt.js
                                      similarity index 97%
                                      rename from assets/index.html-BBL6nyUH.js
                                      rename to assets/index.html-SiiWkWVt.js
                                      index fe7485b57b..019a5e9b2f 100644
                                      --- a/assets/index.html-BBL6nyUH.js
                                      +++ b/assets/index.html-SiiWkWVt.js
                                      @@ -1 +1 @@
                                      -import{_ as u,r as c,o as s,c as d,a as l,b as t,d as e,w as o}from"./app-DBM4OJyw.js";const _={},h=t("h1",{id:"простые-разговоры-о-сложном",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#простые-разговоры-о-сложном"},[t("span",null,"Простые разговоры о сложном")])],-1),i=t("p",null,[t("strong",null,"Эта глава - базовый курс «С нуля», новичкам читать и учить обязательно")],-1),p={class:"custom-container tip"},m=t("p",{class:"custom-container-title"},"Подсказка",-1),f={href:"https://github.com/ricuhkaen",target:"_blank",rel:"noopener noreferrer"};function v(x,k){const r=c("I18nTip"),a=c("ExternalLinkIcon"),n=c("RouterLink");return s(),d("div",null,[l(r),h,i,t("div",p,[m,t("p",null,[e("Сделано с ❤️ "),t("a",f,[e("@ricuhkaen"),l(a)])])]),t("p",null,[l(n,{to:"/ru/document/level-0/ch01-preface.html"},{default:o(()=>[e("【Глава 1】 Введение")]),_:1}),e(" - Чужой или свой сервер? Вот в чём вопрос")]),t("p",null,[l(n,{to:"/ru/document/level-0/ch02-preparation.html"},{default:o(()=>[e("【Глава 2】 Подготовка")]),_:1}),e(" - Прежде чем браться за дело, заготовь средства")]),t("p",null,[l(n,{to:"/ru/document/level-0/ch03-ssh.html"},{default:o(()=>[e("【Глава 3】 Удалённое подключение")]),_:1}),e(" - Мост между севером и югом, пропасть превращается в путь")]),t("p",null,[l(n,{to:"/ru/document/level-0/ch04-security.html"},{default:o(()=>[e("【Глава 4】 Безопасность")]),_:1}),e(" - Небрежность в безопасности, и родные будут лить слёзы")]),t("p",null,[l(n,{to:"/ru/document/level-0/ch05-webpage.html"},{default:o(()=>[e("【Глава 5】 Создание сайта")]),_:1}),e(" - Покажи свою красоту")]),t("p",null,[l(n,{to:"/ru/document/level-0/ch06-certificates.html"},{default:o(()=>[e("【Глава 6】 Управление сертификатами")]),_:1}),e(" - Законно то, что с лицензией")]),t("p",null,[l(n,{to:"/ru/document/level-0/ch07-xray-server.html"},{default:o(()=>[e("【Глава 7】 Xray сервер")]),_:1}),e(" - Наконец-то дождались")]),t("p",null,[l(n,{to:"/ru/document/level-0/ch08-xray-clients.html"},{default:o(()=>[e("【Глава 8】 Xray клиенты")]),_:1}),e(" - Новое начало")]),t("p",null,[l(n,{to:"/ru/document/level-0/ch09-appendix.html"},{default:o(()=>[e("【Глава 9】 Приложение")]),_:1}),e(" - Все контрольные точки здесь")])])}const y=u(_,[["render",v],["__file","index.html.vue"]]);export{y as default};
                                      +import{_ as u,r as c,o as s,c as d,a as l,b as t,d as e,w as o}from"./app-D7uBbsY3.js";const _={},h=t("h1",{id:"простые-разговоры-о-сложном",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#простые-разговоры-о-сложном"},[t("span",null,"Простые разговоры о сложном")])],-1),i=t("p",null,[t("strong",null,"Эта глава - базовый курс «С нуля», новичкам читать и учить обязательно")],-1),p={class:"custom-container tip"},m=t("p",{class:"custom-container-title"},"Подсказка",-1),f={href:"https://github.com/ricuhkaen",target:"_blank",rel:"noopener noreferrer"};function v(x,k){const r=c("I18nTip"),a=c("ExternalLinkIcon"),n=c("RouterLink");return s(),d("div",null,[l(r),h,i,t("div",p,[m,t("p",null,[e("Сделано с ❤️ "),t("a",f,[e("@ricuhkaen"),l(a)])])]),t("p",null,[l(n,{to:"/ru/document/level-0/ch01-preface.html"},{default:o(()=>[e("【Глава 1】 Введение")]),_:1}),e(" - Чужой или свой сервер? Вот в чём вопрос")]),t("p",null,[l(n,{to:"/ru/document/level-0/ch02-preparation.html"},{default:o(()=>[e("【Глава 2】 Подготовка")]),_:1}),e(" - Прежде чем браться за дело, заготовь средства")]),t("p",null,[l(n,{to:"/ru/document/level-0/ch03-ssh.html"},{default:o(()=>[e("【Глава 3】 Удалённое подключение")]),_:1}),e(" - Мост между севером и югом, пропасть превращается в путь")]),t("p",null,[l(n,{to:"/ru/document/level-0/ch04-security.html"},{default:o(()=>[e("【Глава 4】 Безопасность")]),_:1}),e(" - Небрежность в безопасности, и родные будут лить слёзы")]),t("p",null,[l(n,{to:"/ru/document/level-0/ch05-webpage.html"},{default:o(()=>[e("【Глава 5】 Создание сайта")]),_:1}),e(" - Покажи свою красоту")]),t("p",null,[l(n,{to:"/ru/document/level-0/ch06-certificates.html"},{default:o(()=>[e("【Глава 6】 Управление сертификатами")]),_:1}),e(" - Законно то, что с лицензией")]),t("p",null,[l(n,{to:"/ru/document/level-0/ch07-xray-server.html"},{default:o(()=>[e("【Глава 7】 Xray сервер")]),_:1}),e(" - Наконец-то дождались")]),t("p",null,[l(n,{to:"/ru/document/level-0/ch08-xray-clients.html"},{default:o(()=>[e("【Глава 8】 Xray клиенты")]),_:1}),e(" - Новое начало")]),t("p",null,[l(n,{to:"/ru/document/level-0/ch09-appendix.html"},{default:o(()=>[e("【Глава 9】 Приложение")]),_:1}),e(" - Все контрольные точки здесь")])])}const y=u(_,[["render",v],["__file","index.html.vue"]]);export{y as default};
                                      diff --git a/assets/infoDiagram-GSXZ5C4N-BldMtTiD.js b/assets/infoDiagram-GSXZ5C4N-Dq_SIlpy.js
                                      similarity index 62%
                                      rename from assets/infoDiagram-GSXZ5C4N-BldMtTiD.js
                                      rename to assets/infoDiagram-GSXZ5C4N-Dq_SIlpy.js
                                      index a495dea2d4..52c33f7584 100644
                                      --- a/assets/infoDiagram-GSXZ5C4N-BldMtTiD.js
                                      +++ b/assets/infoDiagram-GSXZ5C4N-Dq_SIlpy.js
                                      @@ -1,2 +1,2 @@
                                      -import{_ as e,l as s,K as n,k as i,L as p}from"./mermaid.core-DapiNGBY.js";import{p as g}from"./gitGraph-F2EDSAW4-IXsRUTzt.js";import"./app-DBM4OJyw.js";import"./baseUniq-ZJgB7efo.js";import"./basePickBy-BXIHjUx3.js";import"./clone-B3i2nD77.js";var v={parse:e(async r=>{const a=await g("info",r);s.debug(a)},"parse")},d={version:p},m=e(()=>d.version,"getVersion"),c={getVersion:m},l=e((r,a,o)=>{s.debug(`rendering info diagram
                                      +import{_ as e,l as s,K as n,k as i,L as p}from"./mermaid.core-D8igZDel.js";import{p as g}from"./gitGraph-F2EDSAW4-Df57CYyu.js";import"./app-D7uBbsY3.js";import"./baseUniq-D0lZO5yp.js";import"./basePickBy-DpnmgMOi.js";import"./clone-DWnk59eF.js";var v={parse:e(async r=>{const a=await g("info",r);s.debug(a)},"parse")},d={version:p},m=e(()=>d.version,"getVersion"),c={getVersion:m},l=e((r,a,o)=>{s.debug(`rendering info diagram
                                       `+r);const t=n(a);i(t,100,400,!0),t.append("g").append("text").attr("x",100).attr("y",40).attr("class","version").attr("font-size",32).style("text-anchor","middle").text(`v${o}`)},"draw"),f={draw:l},z={parser:v,db:c,renderer:f};export{z as diagram};
                                      diff --git a/assets/install.html-BGuTjt8M.js b/assets/install.html-6LqhKuK1.js
                                      similarity index 99%
                                      rename from assets/install.html-BGuTjt8M.js
                                      rename to assets/install.html-6LqhKuK1.js
                                      index 7d85313fb3..4b515559ad 100644
                                      --- a/assets/install.html-BGuTjt8M.js
                                      +++ b/assets/install.html-6LqhKuK1.js
                                      @@ -1 +1 @@
                                      -import{_ as c,r as o,o as u,c as _,a as n,b as e,d as r,w as l,e as s}from"./app-DBM4OJyw.js";const d={},p=s('

                                      Загрузка и установка

                                      Поддерживаемые платформы

                                      Xray доступен на следующих платформах:

                                      • Windows 7 и выше (x86 / amd64 / arm32 / arm64);
                                        • If you need to use these version (1.8.18 and later marked with win7, 1.8.6, 1.8.4) in Windows 7, operating system update KB4474419 is required. For better Internet security, it is recommended to install KB4490628 to acquire later operating system updates from Windows Update.
                                      • macOS 10.10 Yosemite и выше (amd64 / arm64);
                                      • Linux 2.6.23 и выше (x86 / amd64 / arm / arm64 / mips64 / mips / ppc64 / s390x / riscv64);
                                        • Включая, но не ограничиваясь: Debian 7 / 8, Ubuntu 12.04 / 14.04 и выше, CentOS 7 / 8, Arch Linux и др.;
                                      • FreeBSD (x86 / amd64);
                                      • OpenBSD (x86 / amd64);

                                      Загрузка Xray

                                      ',5),b={href:"https://github.com/xtls/Xray-core/releases",target:"_blank",rel:"noopener noreferrer"},f=e("p",null,"Скачайте архив для своей платформы, распакуйте его и можете использовать.",-1),g=e("h2",{id:"проверка-установочного-пакета",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#проверка-установочного-пакета"},[e("span",null,"Проверка установочного пакета")])],-1),m=e("p",null,"Xray предлагает два способа проверки:",-1),y=e("li",null,"SHA1 / SHA256 хэш-сумма ZIP-архива;",-1),x=e("h2",{id:"установка-на-windows",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#установка-на-windows"},[e("span",null,"Установка на Windows")])],-1),k={href:"https://github.com/xtls/Xray-core/releases",target:"_blank",rel:"noopener noreferrer"},w=e("code",null,"xray.exe",-1),X=e("a",{href:"./command"},"запустите его из командной строки с параметрами",-1),S={href:"https://scoop.sh",target:"_blank",rel:"noopener noreferrer"},v={href:"https://github.com/Qv2ray/mochi",target:"_blank",rel:"noopener noreferrer"},L=e("h2",{id:"установка-на-macos",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#установка-на-macos"},[e("span",null,"Установка на macOS")])],-1),A={href:"https://github.com/xtls/Xray-core/releases",target:"_blank",rel:"noopener noreferrer"},I=e("code",null,"xray",-1),R={href:"https://brew.sh",target:"_blank",rel:"noopener noreferrer"},C=e("code",null,"brew install xray",-1),F={href:"https://github.com/N4FA/homebrew-xray",target:"_blank",rel:"noopener noreferrer"},N={href:"https://github.com/N4FA",target:"_blank",rel:"noopener noreferrer"},O=e("h2",{id:"установка-на-linux",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#установка-на-linux"},[e("span",null,"Установка на Linux")])],-1),P=e("h3",{id:"установочные-скрипты",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#установочные-скрипты"},[e("span",null,"Установочные скрипты")])],-1),U=e("p",null,"Linux Script",-1),D={href:"https://github.com/XTLS/Xray-install",target:"_blank",rel:"noopener noreferrer"},M=e("strong",null,"Офисиант",-1),W={href:"https://github.com/team-cloudchaser/tempest",target:"_blank",rel:"noopener noreferrer"},z={href:"https://systemd.io",target:"_blank",rel:"noopener noreferrer"},B=e("code",null,"systemd",-1),T={href:"https://github.com/OpenRC/openrc",target:"_blank",rel:"noopener noreferrer"},V=e("p",null,"One Click",-1),E={href:"https://github.com/zxcvos/Xray-script",target:"_blank",rel:"noopener noreferrer"},G={href:"https://github.com/sajjaddg/xray-reality",target:"_blank",rel:"noopener noreferrer"},j={href:"https://github.com/aleskxyz/reality-ezpz",target:"_blank",rel:"noopener noreferrer"},H={href:"https://github.com/hello-yunshu/Xray_bash_onekey",target:"_blank",rel:"noopener noreferrer"},Z={href:"https://github.com/LordPenguin666/XTool",target:"_blank",rel:"noopener noreferrer"},J={href:"https://github.com/mack-a/v2ray-agent",target:"_blank",rel:"noopener noreferrer"},K={href:"https://github.com/wulabing/Xray_onekey",target:"_blank",rel:"noopener noreferrer"},q={href:"https://github.com/proxysu/ProxySU",target:"_blank",rel:"noopener noreferrer"},Y=e("p",null,"Magisk",-1),Q={href:"https://github.com/Asterisk4Magisk/Xray4Magisk",target:"_blank",rel:"noopener noreferrer"},$={href:"https://github.com/E7KMbb/Xray_For_Magisk",target:"_blank",rel:"noopener noreferrer"},ee=e("h3",{id:"arch-linux",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#arch-linux"},[e("span",null,"Arch Linux")])],-1),re=e("h4",{id:"arch-user-repository",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#arch-user-repository"},[e("span",null,"Arch User Repository")])],-1),ne={href:"https://wiki.archlinux.org/index.php/AUR_helpers",target:"_blank",rel:"noopener noreferrer"},te={href:"https://github.com/Jguer/yay",target:"_blank",rel:"noopener noreferrer"},oe=e("code",null,"yay -S xray",-1),ae=e("h4",{id:"arch-linux-cn",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#arch-linux-cn"},[e("span",null,"Arch Linux CN")])],-1),le={href:"https://www.archlinuxcn.org/archlinux-cn-repo-and-mirror/",target:"_blank",rel:"noopener noreferrer"},se=e("code",null,"pacman -S xray",-1),ie=e("h3",{id:"linuxbrew",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#linuxbrew"},[e("span",null,"Linuxbrew")])],-1),he=e("p",null,[r("Использование менеджера пакетов Linuxbrew аналогично Homebrew: "),e("code",null,"brew install xray"),r(".")],-1),ce={id:"debian",tabindex:"-1"},ue={class:"header-anchor",href:"#debian"},_e=e("h3",{id:"gentoo",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#gentoo"},[e("span",null,"Gentoo")])],-1),de=e("p",null,"В настоящее время существует три оверлея сторонних разработчиков, которые предоставляют сценарии установки Portage:",-1),pe={href:"https://github.com/gentoo-mirror/touchfish-os/tree/master/net-proxy/Xray",target:"_blank",rel:"noopener noreferrer"},be={href:"https://github.com/microcai/gentoo-zh",target:"_blank",rel:"noopener noreferrer"},fe={href:"https://github.com/JuanCldCmt/Xray-Overlay",target:"_blank",rel:"noopener noreferrer"},ge=e("p",null,"Добавьте оверлей в локальную систему с помощью layman или eselect-repository, а затем выполните установку.",-1),me=e("h2",{id:"установка-с-помощью-docker",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#установка-с-помощью-docker"},[e("span",null,"Установка с помощью Docker")])],-1),ye={href:"https://hub.docker.com/r/teddysun/xray",target:"_blank",rel:"noopener noreferrer"},xe=s('

                                      Файловая структура образа Docker

                                      • /etc/xray/config.json: файл конфигурации;
                                      • /usr/bin/xray: основная программа Xray;
                                      • /usr/share/xray/geoip.dat: файл данных IP;
                                      • /usr/share/xray/geosite.dat: файл данных доменных имен.

                                      Графические клиенты

                                      ',3),ke={href:"https://github.com/xiaorouji/openwrt-passwall",target:"_blank",rel:"noopener noreferrer"},we={href:"https://github.com/xiaorouji/openwrt-passwall2",target:"_blank",rel:"noopener noreferrer"},Xe={href:"https://github.com/fw876/helloworld",target:"_blank",rel:"noopener noreferrer"},Se={href:"https://github.com/yichya/luci-app-xray",target:"_blank",rel:"noopener noreferrer"},ve={href:"https://github.com/yichya/openwrt-xray",target:"_blank",rel:"noopener noreferrer"},Le={href:"https://github.com/2dust/v2rayN",target:"_blank",rel:"noopener noreferrer"},Ae={href:"https://github.com/LorenEteval/Furious",target:"_blank",rel:"noopener noreferrer"},Ie={href:"https://github.com/InvisibleManVPN/InvisibleMan-XRayClient",target:"_blank",rel:"noopener noreferrer"},Re={href:"https://github.com/2dust/v2rayNG",target:"_blank",rel:"noopener noreferrer"},Ce={href:"https://github.com/XTLS/X-flutter",target:"_blank",rel:"noopener noreferrer"},Fe={href:"https://github.com/SaeedDev94/Xray",target:"_blank",rel:"noopener noreferrer"},Ne={href:"https://apps.apple.com/app/foxray/id6448898396",target:"_blank",rel:"noopener noreferrer"},Oe={href:"https://apps.apple.com/app/streisand/id6450534064",target:"_blank",rel:"noopener noreferrer"},Pe={href:"https://github.com/yanue/V2rayU",target:"_blank",rel:"noopener noreferrer"},Ue={href:"https://github.com/tzmax/V2RayXS",target:"_blank",rel:"noopener noreferrer"},De={href:"https://github.com/LorenEteval/Furious",target:"_blank",rel:"noopener noreferrer"},Me={href:"https://apps.apple.com/app/foxray/id6448898396",target:"_blank",rel:"noopener noreferrer"},We={href:"https://github.com/v2rayA/v2rayA",target:"_blank",rel:"noopener noreferrer"},ze={href:"https://github.com/LorenEteval/Furious",target:"_blank",rel:"noopener noreferrer"},Be=e("h1",{id:"генератор-uuid",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#генератор-uuid"},[e("span",null,"Генератор UUID")])],-1),Te={href:"https://www.uuidgenerator.net",target:"_blank",rel:"noopener noreferrer"};function Ve(Ee,Ge){const i=o("I18nTip"),t=o("ExternalLinkIcon"),a=o("RouterLink"),h=o("Badge");return u(),_("div",null,[n(i),p,e("p",null,[r("Предварительно скомпилированные ZIP-архивы с двоичными файлами можно найти в "),e("a",b,[r("Github Releases"),n(t)]),r(".")]),f,g,m,e("ul",null,[y,e("li",null,[r("Воспроизводимая сборка: см. "),n(a,{to:"/ru/development/intro/compile.html"},{default:l(()=>[r("Сборка Xray")]),_:1}),r(".")])]),x,e("ul",null,[e("li",null,[r("Скачайте ZIP-архив для Windows на "),e("a",k,[r("Github Releases"),n(t)]),r(", распакуйте его, чтобы получить исполняемый файл "),w,r(", а затем "),X,r(".")]),e("li",null,[r("Установите с помощью менеджера пакетов "),e("a",S,[r("Scoop"),n(t)]),r(": Xray был добавлен в "),e("a",v,[r("Mochi"),n(t)]),r(".")])]),L,e("ul",null,[e("li",null,[r("Скачайте ZIP-архив для macOS на "),e("a",A,[r("Github Releases"),n(t)]),r(", распакуйте его, чтобы получить исполняемый файл "),I,r(", а затем "),n(a,{to:"/ru/document/command.html"},{default:l(()=>[r("запустите его из командной строки с параметрами")]),_:1}),r(".")]),e("li",null,[r("Установите с помощью менеджера пакетов "),e("a",R,[r("Homebrew"),n(t)]),r(": "),C,r(".")]),e("li",null,[e("a",F,[r("homebrew-xray"),n(t)]),r(" Спасибо, "),e("a",N,[r("@N4FA"),n(t)]),r("!")])]),O,P,e("ul",null,[e("li",null,[U,e("ul",null,[e("li",null,[e("a",D,[r("XTLS/Xray-install"),n(t)]),r(" ("),M,r(")")]),e("li",null,[e("a",W,[r("tempest"),n(t)]),r(" (supports "),e("a",z,[B,n(t)]),r(" and "),e("a",T,[r("OpenRC"),n(t)]),r("; Linux-only)")])])])]),e("ul",null,[e("li",null,[V,e("ul",null,[e("li",null,[e("a",E,[r("Xray-REALITY"),n(t)]),r(", "),e("a",G,[r("xray-reality"),n(t)]),r(", "),e("a",j,[r("reality-ezpz"),n(t)])]),e("li",null,[e("a",H,[r("Xray_bash_onekey"),n(t)]),r(", "),e("a",Z,[r("XTool"),n(t)])]),e("li",null,[e("a",J,[r("v2ray-agent"),n(t)]),r(", "),e("a",K,[r("Xray_onekey"),n(t)]),r(", "),e("a",q,[r("ProxySU"),n(t)])])])]),e("li",null,[Y,e("ul",null,[e("li",null,[e("a",Q,[r("Xray4Magisk"),n(t)])]),e("li",null,[e("a",$,[r("Xray_For_Magisk"),n(t)])])])])]),ee,re,e("p",null,[r("Требуется "),e("a",ne,[r("помощник AUR"),n(t)]),r(", например, "),e("a",te,[r("yay"),n(t)]),r(", установка с помощью команды "),oe,r(".")]),ae,e("p",null,[r("Сначала добавьте "),e("a",le,[r("репозиторий Arch Linux CN"),n(t)]),r(", затем установите от имени пользователя root с помощью команды "),se,r(".")]),ie,he,e("h3",ce,[e("a",ue,[e("span",null,[r("Debian "),n(h,{text:"WIP",type:"warning"})])])]),_e,de,e("ul",null,[e("li",null,[e("a",pe,[r("CHN-beta/touchfish-os"),n(t)]),r(": Поддерживается отдельным пользователем, подходит для систем с systemD.")]),e("li",null,[e("a",be,[r("Gentoo-zh"),n(t)]),r(": Поддерживается сообществом, подходит для систем с systemD.")]),e("li",null,[e("a",fe,[r("JuanCldCmt/Xray-Overlay"),n(t)]),r(": Поддерживается отдельным пользователем, подходит для систем с openRC, использует группу пользователей xray для повышения безопасности.")])]),ge,me,e("ul",null,[e("li",null,[e("a",ye,[r("teddysun/xray"),n(t)])])]),xe,e("ul",null,[e("li",null,[r("OpenWrt "),e("ul",null,[e("li",null,[e("a",ke,[r("PassWall"),n(t)]),r(", "),e("a",we,[r("PassWall 2"),n(t)])]),e("li",null,[e("a",Xe,[r("ShadowSocksR Plus+"),n(t)])]),e("li",null,[e("a",Se,[r("luci-app-xray"),n(t)]),r(" ("),e("a",ve,[r("openwrt-xray"),n(t)]),r(")")])])]),e("li",null,[r("Windows "),e("ul",null,[e("li",null,[e("a",Le,[r("v2rayN"),n(t)])]),e("li",null,[e("a",Ae,[r("Furious"),n(t)])]),e("li",null,[e("a",Ie,[r("Invisible Man - Xray"),n(t)])])])]),e("li",null,[r("Android "),e("ul",null,[e("li",null,[e("a",Re,[r("v2rayNG"),n(t)])]),e("li",null,[e("a",Ce,[r("X-flutter"),n(t)])]),e("li",null,[e("a",Fe,[r("SaeedDev94/Xray"),n(t)])])])]),e("li",null,[r("iOS & macOS arm64 "),e("ul",null,[e("li",null,[e("a",Ne,[r("FoXray"),n(t)])]),e("li",null,[e("a",Oe,[r("Streisand"),n(t)])])])]),e("li",null,[r("macOS arm64 & x64 "),e("ul",null,[e("li",null,[e("a",Pe,[r("V2rayU"),n(t)])]),e("li",null,[e("a",Ue,[r("V2RayXS"),n(t)])]),e("li",null,[e("a",De,[r("Furious"),n(t)])]),e("li",null,[e("a",Me,[r("FoXray"),n(t)])])])]),e("li",null,[r("Linux "),e("ul",null,[e("li",null,[e("a",We,[r("v2rayA"),n(t)])]),e("li",null,[e("a",ze,[r("Furious"),n(t)])])])])]),Be,e("p",null,[r("Генератор UUID от сторонних разработчиков: "),e("a",Te,[r("uuidgenerator.net"),n(t)])])])}const He=c(d,[["render",Ve],["__file","install.html.vue"]]);export{He as default}; +import{_ as c,r as o,o as u,c as _,a as n,b as e,d as r,w as l,e as s}from"./app-D7uBbsY3.js";const d={},p=s('

                                      Загрузка и установка

                                      Поддерживаемые платформы

                                      Xray доступен на следующих платформах:

                                      • Windows 7 и выше (x86 / amd64 / arm32 / arm64);
                                        • If you need to use these version (1.8.18 and later marked with win7, 1.8.6, 1.8.4) in Windows 7, operating system update KB4474419 is required. For better Internet security, it is recommended to install KB4490628 to acquire later operating system updates from Windows Update.
                                      • macOS 10.10 Yosemite и выше (amd64 / arm64);
                                      • Linux 2.6.23 и выше (x86 / amd64 / arm / arm64 / mips64 / mips / ppc64 / s390x / riscv64);
                                        • Включая, но не ограничиваясь: Debian 7 / 8, Ubuntu 12.04 / 14.04 и выше, CentOS 7 / 8, Arch Linux и др.;
                                      • FreeBSD (x86 / amd64);
                                      • OpenBSD (x86 / amd64);

                                      Загрузка Xray

                                      ',5),b={href:"https://github.com/xtls/Xray-core/releases",target:"_blank",rel:"noopener noreferrer"},f=e("p",null,"Скачайте архив для своей платформы, распакуйте его и можете использовать.",-1),g=e("h2",{id:"проверка-установочного-пакета",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#проверка-установочного-пакета"},[e("span",null,"Проверка установочного пакета")])],-1),m=e("p",null,"Xray предлагает два способа проверки:",-1),y=e("li",null,"SHA1 / SHA256 хэш-сумма ZIP-архива;",-1),x=e("h2",{id:"установка-на-windows",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#установка-на-windows"},[e("span",null,"Установка на Windows")])],-1),k={href:"https://github.com/xtls/Xray-core/releases",target:"_blank",rel:"noopener noreferrer"},w=e("code",null,"xray.exe",-1),X=e("a",{href:"./command"},"запустите его из командной строки с параметрами",-1),S={href:"https://scoop.sh",target:"_blank",rel:"noopener noreferrer"},v={href:"https://github.com/Qv2ray/mochi",target:"_blank",rel:"noopener noreferrer"},L=e("h2",{id:"установка-на-macos",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#установка-на-macos"},[e("span",null,"Установка на macOS")])],-1),A={href:"https://github.com/xtls/Xray-core/releases",target:"_blank",rel:"noopener noreferrer"},I=e("code",null,"xray",-1),R={href:"https://brew.sh",target:"_blank",rel:"noopener noreferrer"},C=e("code",null,"brew install xray",-1),F={href:"https://github.com/N4FA/homebrew-xray",target:"_blank",rel:"noopener noreferrer"},N={href:"https://github.com/N4FA",target:"_blank",rel:"noopener noreferrer"},O=e("h2",{id:"установка-на-linux",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#установка-на-linux"},[e("span",null,"Установка на Linux")])],-1),P=e("h3",{id:"установочные-скрипты",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#установочные-скрипты"},[e("span",null,"Установочные скрипты")])],-1),U=e("p",null,"Linux Script",-1),D={href:"https://github.com/XTLS/Xray-install",target:"_blank",rel:"noopener noreferrer"},M=e("strong",null,"Офисиант",-1),W={href:"https://github.com/team-cloudchaser/tempest",target:"_blank",rel:"noopener noreferrer"},z={href:"https://systemd.io",target:"_blank",rel:"noopener noreferrer"},B=e("code",null,"systemd",-1),T={href:"https://github.com/OpenRC/openrc",target:"_blank",rel:"noopener noreferrer"},V=e("p",null,"One Click",-1),E={href:"https://github.com/zxcvos/Xray-script",target:"_blank",rel:"noopener noreferrer"},G={href:"https://github.com/sajjaddg/xray-reality",target:"_blank",rel:"noopener noreferrer"},j={href:"https://github.com/aleskxyz/reality-ezpz",target:"_blank",rel:"noopener noreferrer"},H={href:"https://github.com/hello-yunshu/Xray_bash_onekey",target:"_blank",rel:"noopener noreferrer"},Z={href:"https://github.com/LordPenguin666/XTool",target:"_blank",rel:"noopener noreferrer"},J={href:"https://github.com/mack-a/v2ray-agent",target:"_blank",rel:"noopener noreferrer"},K={href:"https://github.com/wulabing/Xray_onekey",target:"_blank",rel:"noopener noreferrer"},q={href:"https://github.com/proxysu/ProxySU",target:"_blank",rel:"noopener noreferrer"},Y=e("p",null,"Magisk",-1),Q={href:"https://github.com/Asterisk4Magisk/Xray4Magisk",target:"_blank",rel:"noopener noreferrer"},$={href:"https://github.com/E7KMbb/Xray_For_Magisk",target:"_blank",rel:"noopener noreferrer"},ee=e("h3",{id:"arch-linux",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#arch-linux"},[e("span",null,"Arch Linux")])],-1),re=e("h4",{id:"arch-user-repository",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#arch-user-repository"},[e("span",null,"Arch User Repository")])],-1),ne={href:"https://wiki.archlinux.org/index.php/AUR_helpers",target:"_blank",rel:"noopener noreferrer"},te={href:"https://github.com/Jguer/yay",target:"_blank",rel:"noopener noreferrer"},oe=e("code",null,"yay -S xray",-1),ae=e("h4",{id:"arch-linux-cn",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#arch-linux-cn"},[e("span",null,"Arch Linux CN")])],-1),le={href:"https://www.archlinuxcn.org/archlinux-cn-repo-and-mirror/",target:"_blank",rel:"noopener noreferrer"},se=e("code",null,"pacman -S xray",-1),ie=e("h3",{id:"linuxbrew",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#linuxbrew"},[e("span",null,"Linuxbrew")])],-1),he=e("p",null,[r("Использование менеджера пакетов Linuxbrew аналогично Homebrew: "),e("code",null,"brew install xray"),r(".")],-1),ce={id:"debian",tabindex:"-1"},ue={class:"header-anchor",href:"#debian"},_e=e("h3",{id:"gentoo",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#gentoo"},[e("span",null,"Gentoo")])],-1),de=e("p",null,"В настоящее время существует три оверлея сторонних разработчиков, которые предоставляют сценарии установки Portage:",-1),pe={href:"https://github.com/gentoo-mirror/touchfish-os/tree/master/net-proxy/Xray",target:"_blank",rel:"noopener noreferrer"},be={href:"https://github.com/microcai/gentoo-zh",target:"_blank",rel:"noopener noreferrer"},fe={href:"https://github.com/JuanCldCmt/Xray-Overlay",target:"_blank",rel:"noopener noreferrer"},ge=e("p",null,"Добавьте оверлей в локальную систему с помощью layman или eselect-repository, а затем выполните установку.",-1),me=e("h2",{id:"установка-с-помощью-docker",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#установка-с-помощью-docker"},[e("span",null,"Установка с помощью Docker")])],-1),ye={href:"https://hub.docker.com/r/teddysun/xray",target:"_blank",rel:"noopener noreferrer"},xe=s('

                                      Файловая структура образа Docker

                                      • /etc/xray/config.json: файл конфигурации;
                                      • /usr/bin/xray: основная программа Xray;
                                      • /usr/share/xray/geoip.dat: файл данных IP;
                                      • /usr/share/xray/geosite.dat: файл данных доменных имен.

                                      Графические клиенты

                                      ',3),ke={href:"https://github.com/xiaorouji/openwrt-passwall",target:"_blank",rel:"noopener noreferrer"},we={href:"https://github.com/xiaorouji/openwrt-passwall2",target:"_blank",rel:"noopener noreferrer"},Xe={href:"https://github.com/fw876/helloworld",target:"_blank",rel:"noopener noreferrer"},Se={href:"https://github.com/yichya/luci-app-xray",target:"_blank",rel:"noopener noreferrer"},ve={href:"https://github.com/yichya/openwrt-xray",target:"_blank",rel:"noopener noreferrer"},Le={href:"https://github.com/2dust/v2rayN",target:"_blank",rel:"noopener noreferrer"},Ae={href:"https://github.com/LorenEteval/Furious",target:"_blank",rel:"noopener noreferrer"},Ie={href:"https://github.com/InvisibleManVPN/InvisibleMan-XRayClient",target:"_blank",rel:"noopener noreferrer"},Re={href:"https://github.com/2dust/v2rayNG",target:"_blank",rel:"noopener noreferrer"},Ce={href:"https://github.com/XTLS/X-flutter",target:"_blank",rel:"noopener noreferrer"},Fe={href:"https://github.com/SaeedDev94/Xray",target:"_blank",rel:"noopener noreferrer"},Ne={href:"https://apps.apple.com/app/foxray/id6448898396",target:"_blank",rel:"noopener noreferrer"},Oe={href:"https://apps.apple.com/app/streisand/id6450534064",target:"_blank",rel:"noopener noreferrer"},Pe={href:"https://github.com/yanue/V2rayU",target:"_blank",rel:"noopener noreferrer"},Ue={href:"https://github.com/tzmax/V2RayXS",target:"_blank",rel:"noopener noreferrer"},De={href:"https://github.com/LorenEteval/Furious",target:"_blank",rel:"noopener noreferrer"},Me={href:"https://apps.apple.com/app/foxray/id6448898396",target:"_blank",rel:"noopener noreferrer"},We={href:"https://github.com/v2rayA/v2rayA",target:"_blank",rel:"noopener noreferrer"},ze={href:"https://github.com/LorenEteval/Furious",target:"_blank",rel:"noopener noreferrer"},Be=e("h1",{id:"генератор-uuid",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#генератор-uuid"},[e("span",null,"Генератор UUID")])],-1),Te={href:"https://www.uuidgenerator.net",target:"_blank",rel:"noopener noreferrer"};function Ve(Ee,Ge){const i=o("I18nTip"),t=o("ExternalLinkIcon"),a=o("RouterLink"),h=o("Badge");return u(),_("div",null,[n(i),p,e("p",null,[r("Предварительно скомпилированные ZIP-архивы с двоичными файлами можно найти в "),e("a",b,[r("Github Releases"),n(t)]),r(".")]),f,g,m,e("ul",null,[y,e("li",null,[r("Воспроизводимая сборка: см. "),n(a,{to:"/ru/development/intro/compile.html"},{default:l(()=>[r("Сборка Xray")]),_:1}),r(".")])]),x,e("ul",null,[e("li",null,[r("Скачайте ZIP-архив для Windows на "),e("a",k,[r("Github Releases"),n(t)]),r(", распакуйте его, чтобы получить исполняемый файл "),w,r(", а затем "),X,r(".")]),e("li",null,[r("Установите с помощью менеджера пакетов "),e("a",S,[r("Scoop"),n(t)]),r(": Xray был добавлен в "),e("a",v,[r("Mochi"),n(t)]),r(".")])]),L,e("ul",null,[e("li",null,[r("Скачайте ZIP-архив для macOS на "),e("a",A,[r("Github Releases"),n(t)]),r(", распакуйте его, чтобы получить исполняемый файл "),I,r(", а затем "),n(a,{to:"/ru/document/command.html"},{default:l(()=>[r("запустите его из командной строки с параметрами")]),_:1}),r(".")]),e("li",null,[r("Установите с помощью менеджера пакетов "),e("a",R,[r("Homebrew"),n(t)]),r(": "),C,r(".")]),e("li",null,[e("a",F,[r("homebrew-xray"),n(t)]),r(" Спасибо, "),e("a",N,[r("@N4FA"),n(t)]),r("!")])]),O,P,e("ul",null,[e("li",null,[U,e("ul",null,[e("li",null,[e("a",D,[r("XTLS/Xray-install"),n(t)]),r(" ("),M,r(")")]),e("li",null,[e("a",W,[r("tempest"),n(t)]),r(" (supports "),e("a",z,[B,n(t)]),r(" and "),e("a",T,[r("OpenRC"),n(t)]),r("; Linux-only)")])])])]),e("ul",null,[e("li",null,[V,e("ul",null,[e("li",null,[e("a",E,[r("Xray-REALITY"),n(t)]),r(", "),e("a",G,[r("xray-reality"),n(t)]),r(", "),e("a",j,[r("reality-ezpz"),n(t)])]),e("li",null,[e("a",H,[r("Xray_bash_onekey"),n(t)]),r(", "),e("a",Z,[r("XTool"),n(t)])]),e("li",null,[e("a",J,[r("v2ray-agent"),n(t)]),r(", "),e("a",K,[r("Xray_onekey"),n(t)]),r(", "),e("a",q,[r("ProxySU"),n(t)])])])]),e("li",null,[Y,e("ul",null,[e("li",null,[e("a",Q,[r("Xray4Magisk"),n(t)])]),e("li",null,[e("a",$,[r("Xray_For_Magisk"),n(t)])])])])]),ee,re,e("p",null,[r("Требуется "),e("a",ne,[r("помощник AUR"),n(t)]),r(", например, "),e("a",te,[r("yay"),n(t)]),r(", установка с помощью команды "),oe,r(".")]),ae,e("p",null,[r("Сначала добавьте "),e("a",le,[r("репозиторий Arch Linux CN"),n(t)]),r(", затем установите от имени пользователя root с помощью команды "),se,r(".")]),ie,he,e("h3",ce,[e("a",ue,[e("span",null,[r("Debian "),n(h,{text:"WIP",type:"warning"})])])]),_e,de,e("ul",null,[e("li",null,[e("a",pe,[r("CHN-beta/touchfish-os"),n(t)]),r(": Поддерживается отдельным пользователем, подходит для систем с systemD.")]),e("li",null,[e("a",be,[r("Gentoo-zh"),n(t)]),r(": Поддерживается сообществом, подходит для систем с systemD.")]),e("li",null,[e("a",fe,[r("JuanCldCmt/Xray-Overlay"),n(t)]),r(": Поддерживается отдельным пользователем, подходит для систем с openRC, использует группу пользователей xray для повышения безопасности.")])]),ge,me,e("ul",null,[e("li",null,[e("a",ye,[r("teddysun/xray"),n(t)])])]),xe,e("ul",null,[e("li",null,[r("OpenWrt "),e("ul",null,[e("li",null,[e("a",ke,[r("PassWall"),n(t)]),r(", "),e("a",we,[r("PassWall 2"),n(t)])]),e("li",null,[e("a",Xe,[r("ShadowSocksR Plus+"),n(t)])]),e("li",null,[e("a",Se,[r("luci-app-xray"),n(t)]),r(" ("),e("a",ve,[r("openwrt-xray"),n(t)]),r(")")])])]),e("li",null,[r("Windows "),e("ul",null,[e("li",null,[e("a",Le,[r("v2rayN"),n(t)])]),e("li",null,[e("a",Ae,[r("Furious"),n(t)])]),e("li",null,[e("a",Ie,[r("Invisible Man - Xray"),n(t)])])])]),e("li",null,[r("Android "),e("ul",null,[e("li",null,[e("a",Re,[r("v2rayNG"),n(t)])]),e("li",null,[e("a",Ce,[r("X-flutter"),n(t)])]),e("li",null,[e("a",Fe,[r("SaeedDev94/Xray"),n(t)])])])]),e("li",null,[r("iOS & macOS arm64 "),e("ul",null,[e("li",null,[e("a",Ne,[r("FoXray"),n(t)])]),e("li",null,[e("a",Oe,[r("Streisand"),n(t)])])])]),e("li",null,[r("macOS arm64 & x64 "),e("ul",null,[e("li",null,[e("a",Pe,[r("V2rayU"),n(t)])]),e("li",null,[e("a",Ue,[r("V2RayXS"),n(t)])]),e("li",null,[e("a",De,[r("Furious"),n(t)])]),e("li",null,[e("a",Me,[r("FoXray"),n(t)])])])]),e("li",null,[r("Linux "),e("ul",null,[e("li",null,[e("a",We,[r("v2rayA"),n(t)])]),e("li",null,[e("a",ze,[r("Furious"),n(t)])])])])]),Be,e("p",null,[r("Генератор UUID от сторонних разработчиков: "),e("a",Te,[r("uuidgenerator.net"),n(t)])])])}const He=c(d,[["render",Ve],["__file","install.html.vue"]]);export{He as default}; diff --git a/assets/install.html-f4BUU2Xm.js b/assets/install.html-CDzfP6zr.js similarity index 99% rename from assets/install.html-f4BUU2Xm.js rename to assets/install.html-CDzfP6zr.js index 00986de644..1aa46dc69f 100644 --- a/assets/install.html-f4BUU2Xm.js +++ b/assets/install.html-CDzfP6zr.js @@ -1 +1 @@ -import{_ as c,r as t,o as _,c as u,a as n,b as e,d as r,w as l,e as s}from"./app-DBM4OJyw.js";const d={},p=s('

                                      下载安装

                                      平台支持

                                      Xray 在以下平台中可用:

                                      • Windows 7 及之后版本(x86 / amd64 / arm32 / arm64);
                                        • Windows 7 中使用 1.8.4、1.8.6 的常规版本以及 1.8.18 以后的 win7 版本需要系统安装有 KB4474419 更新方可使用;推荐同时安装 KB4490628 以便联网后接受后续的操作系统安全更新。
                                      • macOS 10.10 Yosemite 及之后版本(amd64 / arm64);
                                      • Linux 2.6.23 及之后版本(x86 / amd64 / arm / arm64 / mips64 / mips / ppc64 / s390x / riscv64);
                                        • 包括但不限于 Debian 7 / 8、Ubuntu 12.04 / 14.04 及后续版本、CentOS 7 / 8、Arch Linux 等;
                                      • FreeBSD (x86 / amd64);
                                      • OpenBSD (x86 / amd64);

                                      下载 Xray

                                      ',5),b={href:"https://github.com/xtls/Xray-core/releases",target:"_blank",rel:"noopener noreferrer"},f=e("p",null,"下载对应平台的压缩包,解压后即可使用。",-1),g=e("h2",{id:"验证安装包",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#验证安装包"},[e("span",null,"验证安装包")])],-1),m=e("p",null,"Xray 提供两种验证方式:",-1),y=e("li",null,"ZIP 压缩包的 SHA1 / SHA256 摘要",-1),x=e("h2",{id:"windows-安装方式",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#windows-安装方式"},[e("span",null,"Windows 安装方式")])],-1),k={href:"https://github.com/xtls/Xray-core/releases",target:"_blank",rel:"noopener noreferrer"},w=e("code",null,"xray.exe",-1),X=e("a",{href:"./command"},"通过命令行带参数运行",-1),v={href:"https://scoop.sh",target:"_blank",rel:"noopener noreferrer"},S={href:"https://github.com/Qv2ray/mochi",target:"_blank",rel:"noopener noreferrer"},L=e("h2",{id:"macos-安装方式",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#macos-安装方式"},[e("span",null,"macOS 安装方式")])],-1),A={href:"https://github.com/xtls/Xray-core/releases",target:"_blank",rel:"noopener noreferrer"},I=e("code",null,"xray",-1),O={href:"https://brew.sh",target:"_blank",rel:"noopener noreferrer"},R=e("code",null,"brew install xray",-1),C={href:"https://github.com/N4FA/homebrew-xray",target:"_blank",rel:"noopener noreferrer"},N={href:"https://github.com/N4FA",target:"_blank",rel:"noopener noreferrer"},F=e("h2",{id:"linux-安装方式",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#linux-安装方式"},[e("span",null,"Linux 安装方式")])],-1),P=e("h3",{id:"安装脚本",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#安装脚本"},[e("span",null,"安装脚本")])],-1),D=e("p",null,"Linux Script",-1),U={href:"https://github.com/XTLS/Xray-install",target:"_blank",rel:"noopener noreferrer"},M=e("strong",null,"官方脚本",-1),z={href:"https://github.com/team-cloudchaser/tempest",target:"_blank",rel:"noopener noreferrer"},B={href:"https://systemd.io",target:"_blank",rel:"noopener noreferrer"},T=e("code",null,"systemd",-1),V={href:"https://github.com/OpenRC/openrc",target:"_blank",rel:"noopener noreferrer"},W=e("p",null,"One Click",-1),E={href:"https://github.com/zxcvos/Xray-script",target:"_blank",rel:"noopener noreferrer"},G={href:"https://github.com/sajjaddg/xray-reality",target:"_blank",rel:"noopener noreferrer"},j={href:"https://github.com/aleskxyz/reality-ezpz",target:"_blank",rel:"noopener noreferrer"},H={href:"https://github.com/hello-yunshu/Xray_bash_onekey",target:"_blank",rel:"noopener noreferrer"},Z={href:"https://github.com/LordPenguin666/XTool",target:"_blank",rel:"noopener noreferrer"},J={href:"https://github.com/mack-a/v2ray-agent",target:"_blank",rel:"noopener noreferrer"},K={href:"https://github.com/wulabing/Xray_onekey",target:"_blank",rel:"noopener noreferrer"},Y={href:"https://github.com/proxysu/ProxySU",target:"_blank",rel:"noopener noreferrer"},Q=e("p",null,"Magisk",-1),q={href:"https://github.com/Asterisk4Magisk/Xray4Magisk",target:"_blank",rel:"noopener noreferrer"},$={href:"https://github.com/E7KMbb/Xray_For_Magisk",target:"_blank",rel:"noopener noreferrer"},ee=e("h3",{id:"arch-linux",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#arch-linux"},[e("span",null,"Arch Linux")])],-1),re=e("h4",{id:"arch-user-repository",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#arch-user-repository"},[e("span",null,"Arch User Repository")])],-1),ne={href:"https://wiki.archlinux.org/index.php/AUR_helpers",target:"_blank",rel:"noopener noreferrer"},oe={href:"https://github.com/Jguer/yay",target:"_blank",rel:"noopener noreferrer"},te=e("code",null,"yay -S xray",-1),ae=e("h4",{id:"arch-linux-cn",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#arch-linux-cn"},[e("span",null,"Arch Linux CN")])],-1),le={href:"https://www.archlinuxcn.org/archlinux-cn-repo-and-mirror/",target:"_blank",rel:"noopener noreferrer"},se=e("code",null,"pacman -S xray",-1),ie=e("h3",{id:"linuxbrew",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#linuxbrew"},[e("span",null,"Linuxbrew")])],-1),he=e("p",null,[r("Linuxbrew 包管理器的使用方式与 Homebrew 一致:"),e("code",null,"brew install xray")],-1),ce={id:"debian",tabindex:"-1"},_e={class:"header-anchor",href:"#debian"},ue=e("h3",{id:"gentoo",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#gentoo"},[e("span",null,"Gentoo")])],-1),de=e("p",null,"目前有三个第三方 Overlay 提供 Portage 安装脚本:",-1),pe={href:"https://github.com/gentoo-mirror/touchfish-os/tree/master/net-proxy/Xray",target:"_blank",rel:"noopener noreferrer"},be={href:"https://github.com/microcai/gentoo-zh",target:"_blank",rel:"noopener noreferrer"},fe={href:"https://github.com/JuanCldCmt/Xray-Overlay",target:"_blank",rel:"noopener noreferrer"},ge=e("p",null,"使用 layman 或 eselect-repository 添加 Overlay 至本地,然后即可安装。",-1),me=e("h2",{id:"docker-安装方式",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#docker-安装方式"},[e("span",null,"Docker 安装方式")])],-1),ye={href:"https://hub.docker.com/r/teddysun/xray",target:"_blank",rel:"noopener noreferrer"},xe=s('

                                      Docker image 的文件结构

                                      • /etc/xray/config.json:配置文件
                                      • /usr/bin/xray:Xray 主程序
                                      • /usr/share/xray/geoip.dat:IP 数据文件
                                      • /usr/share/xray/geosite.dat:域名数据文件

                                      图形化客户端

                                      ',3),ke={href:"https://github.com/xiaorouji/openwrt-passwall",target:"_blank",rel:"noopener noreferrer"},we={href:"https://github.com/xiaorouji/openwrt-passwall2",target:"_blank",rel:"noopener noreferrer"},Xe={href:"https://github.com/fw876/helloworld",target:"_blank",rel:"noopener noreferrer"},ve={href:"https://github.com/yichya/luci-app-xray",target:"_blank",rel:"noopener noreferrer"},Se={href:"https://github.com/yichya/openwrt-xray",target:"_blank",rel:"noopener noreferrer"},Le={href:"https://github.com/2dust/v2rayN",target:"_blank",rel:"noopener noreferrer"},Ae={href:"https://github.com/LorenEteval/Furious",target:"_blank",rel:"noopener noreferrer"},Ie={href:"https://github.com/InvisibleManVPN/InvisibleMan-XRayClient",target:"_blank",rel:"noopener noreferrer"},Oe={href:"https://github.com/2dust/v2rayNG",target:"_blank",rel:"noopener noreferrer"},Re={href:"https://github.com/XTLS/X-flutter",target:"_blank",rel:"noopener noreferrer"},Ce={href:"https://github.com/SaeedDev94/Xray",target:"_blank",rel:"noopener noreferrer"},Ne={href:"https://apps.apple.com/app/foxray/id6448898396",target:"_blank",rel:"noopener noreferrer"},Fe={href:"https://apps.apple.com/app/streisand/id6450534064",target:"_blank",rel:"noopener noreferrer"},Pe={href:"https://github.com/yanue/V2rayU",target:"_blank",rel:"noopener noreferrer"},De={href:"https://github.com/tzmax/V2RayXS",target:"_blank",rel:"noopener noreferrer"},Ue={href:"https://github.com/LorenEteval/Furious",target:"_blank",rel:"noopener noreferrer"},Me={href:"https://apps.apple.com/app/foxray/id6448898396",target:"_blank",rel:"noopener noreferrer"},ze={href:"https://github.com/v2rayA/v2rayA",target:"_blank",rel:"noopener noreferrer"},Be={href:"https://github.com/LorenEteval/Furious",target:"_blank",rel:"noopener noreferrer"},Te=e("h1",{id:"uuid-生成器",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#uuid-生成器"},[e("span",null,"UUID 生成器")])],-1),Ve={href:"https://www.uuidgenerator.net",target:"_blank",rel:"noopener noreferrer"};function We(Ee,Ge){const i=t("I18nTip"),o=t("ExternalLinkIcon"),a=t("RouterLink"),h=t("Badge");return _(),u("div",null,[n(i),p,e("p",null,[r("预编译的二进制 ZIP 格式压缩包可在 "),e("a",b,[r("Github Releases"),n(o)]),r(" 中找到。")]),f,g,m,e("ul",null,[y,e("li",null,[r("可复现构建:请参照 "),n(a,{to:"/development/intro/compile.html"},{default:l(()=>[r("编译 Xray")]),_:1})])]),x,e("ul",null,[e("li",null,[r("在 "),e("a",k,[r("Github Releases"),n(o)]),r(" 下载适用于 Windows 平台的 ZIP 压缩包,解压后可得到可执行文件 "),w,r(" ,然后"),X,r(" 即可")]),e("li",null,[r("通过 "),e("a",v,[r("Scoop"),n(o)]),r(" 包管理器安装:Xray 已经被添加到 "),e("a",S,[r("Mochi"),n(o)]),r("。")])]),L,e("ul",null,[e("li",null,[r("在 "),e("a",A,[r("Github Releases"),n(o)]),r(" 下载适用于 macOS 平台的 ZIP 压缩包,解压后可得到可执行文件 "),I,r(" ,然后"),n(a,{to:"/document/command.html"},{default:l(()=>[r("通过命令行带参数运行")]),_:1}),r(" 即可")]),e("li",null,[r("通过 "),e("a",O,[r("Homebrew"),n(o)]),r(" 包管理器安装:"),R]),e("li",null,[e("a",C,[r("homebrew-xray"),n(o)]),r(" 感谢"),e("a",N,[r("@N4FA"),n(o)])])]),F,P,e("ul",null,[e("li",null,[D,e("ul",null,[e("li",null,[e("a",U,[r("XTLS/Xray-install"),n(o)]),r(" ("),M,r(")")]),e("li",null,[e("a",z,[r("tempest"),n(o)]),r(" (支持 "),e("a",B,[T,n(o)]),r(" 以及 "),e("a",V,[r("OpenRC"),n(o)]),r("; 仅限 Linux 下使用)")])])])]),e("ul",null,[e("li",null,[W,e("ul",null,[e("li",null,[e("a",E,[r("Xray-REALITY"),n(o)]),r(", "),e("a",G,[r("xray-reality"),n(o)]),r(", "),e("a",j,[r("reality-ezpz"),n(o)])]),e("li",null,[e("a",H,[r("Xray_bash_onekey"),n(o)]),r(", "),e("a",Z,[r("XTool"),n(o)])]),e("li",null,[e("a",J,[r("v2ray-agent"),n(o)]),r(", "),e("a",K,[r("Xray_onekey"),n(o)]),r(", "),e("a",Y,[r("ProxySU"),n(o)])])])]),e("li",null,[Q,e("ul",null,[e("li",null,[e("a",q,[r("Xray4Magisk"),n(o)])]),e("li",null,[e("a",$,[r("Xray_For_Magisk"),n(o)])])])])]),ee,re,e("p",null,[r("需要使用 "),e("a",ne,[r("AUR helpers"),n(o)]),r(",以 "),e("a",oe,[r("yay"),n(o)]),r(" 为例,可通过 "),te,r(" 安装。")]),ae,e("p",null,[r("首先添加 "),e("a",le,[r("Arch Linux CN 仓库"),n(o)]),r(",然后在 root 用户下使用 "),se,r(" 安装。")]),ie,he,e("h3",ce,[e("a",_e,[e("span",null,[r("Debian "),n(h,{text:"WIP",type:"warning"})])])]),ue,de,e("ul",null,[e("li",null,[e("a",pe,[r("CHN-beta/touchfish-os"),n(o)]),r(": 个人维护,适用于 systemD 系统")]),e("li",null,[e("a",be,[r("Gentoo-zh"),n(o)]),r(": 社区维护,适用于 systemD 系统")]),e("li",null,[e("a",fe,[r("JuanCldCmt/Xray-Overlay"),n(o)]),r(":个人维护,适用于 openRC 系统,同时使用 xray 用户组运行以提高安全性")])]),ge,me,e("ul",null,[e("li",null,[e("a",ye,[r("teddysun/xray"),n(o)])])]),xe,e("ul",null,[e("li",null,[r("OpenWrt "),e("ul",null,[e("li",null,[e("a",ke,[r("PassWall"),n(o)]),r(", "),e("a",we,[r("PassWall 2"),n(o)])]),e("li",null,[e("a",Xe,[r("ShadowSocksR Plus+"),n(o)])]),e("li",null,[e("a",ve,[r("luci-app-xray"),n(o)]),r(" ("),e("a",Se,[r("openwrt-xray"),n(o)]),r(")")])])]),e("li",null,[r("Windows "),e("ul",null,[e("li",null,[e("a",Le,[r("v2rayN"),n(o)])]),e("li",null,[e("a",Ae,[r("Furious"),n(o)])]),e("li",null,[e("a",Ie,[r("Invisible Man - Xray"),n(o)])])])]),e("li",null,[r("Android "),e("ul",null,[e("li",null,[e("a",Oe,[r("v2rayNG"),n(o)])]),e("li",null,[e("a",Re,[r("X-flutter"),n(o)])]),e("li",null,[e("a",Ce,[r("SaeedDev94/Xray"),n(o)])])])]),e("li",null,[r("iOS & macOS arm64 "),e("ul",null,[e("li",null,[e("a",Ne,[r("FoXray"),n(o)])]),e("li",null,[e("a",Fe,[r("Streisand"),n(o)])])])]),e("li",null,[r("macOS arm64 & x64 "),e("ul",null,[e("li",null,[e("a",Pe,[r("V2rayU"),n(o)])]),e("li",null,[e("a",De,[r("V2RayXS"),n(o)])]),e("li",null,[e("a",Ue,[r("Furious"),n(o)])]),e("li",null,[e("a",Me,[r("FoXray"),n(o)])])])]),e("li",null,[r("Linux "),e("ul",null,[e("li",null,[e("a",ze,[r("v2rayA"),n(o)])]),e("li",null,[e("a",Be,[r("Furious"),n(o)])])])])]),Te,e("p",null,[r("第三方的 UUID 生成器 "),e("a",Ve,[r("uuidgenerator.net"),n(o)])])])}const He=c(d,[["render",We],["__file","install.html.vue"]]);export{He as default}; +import{_ as c,r as t,o as _,c as u,a as n,b as e,d as r,w as l,e as s}from"./app-D7uBbsY3.js";const d={},p=s('

                                      下载安装

                                      平台支持

                                      Xray 在以下平台中可用:

                                      • Windows 7 及之后版本(x86 / amd64 / arm32 / arm64);
                                        • Windows 7 中使用 1.8.4、1.8.6 的常规版本以及 1.8.18 以后的 win7 版本需要系统安装有 KB4474419 更新方可使用;推荐同时安装 KB4490628 以便联网后接受后续的操作系统安全更新。
                                      • macOS 10.10 Yosemite 及之后版本(amd64 / arm64);
                                      • Linux 2.6.23 及之后版本(x86 / amd64 / arm / arm64 / mips64 / mips / ppc64 / s390x / riscv64);
                                        • 包括但不限于 Debian 7 / 8、Ubuntu 12.04 / 14.04 及后续版本、CentOS 7 / 8、Arch Linux 等;
                                      • FreeBSD (x86 / amd64);
                                      • OpenBSD (x86 / amd64);

                                      下载 Xray

                                      ',5),b={href:"https://github.com/xtls/Xray-core/releases",target:"_blank",rel:"noopener noreferrer"},f=e("p",null,"下载对应平台的压缩包,解压后即可使用。",-1),g=e("h2",{id:"验证安装包",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#验证安装包"},[e("span",null,"验证安装包")])],-1),m=e("p",null,"Xray 提供两种验证方式:",-1),y=e("li",null,"ZIP 压缩包的 SHA1 / SHA256 摘要",-1),x=e("h2",{id:"windows-安装方式",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#windows-安装方式"},[e("span",null,"Windows 安装方式")])],-1),k={href:"https://github.com/xtls/Xray-core/releases",target:"_blank",rel:"noopener noreferrer"},w=e("code",null,"xray.exe",-1),X=e("a",{href:"./command"},"通过命令行带参数运行",-1),v={href:"https://scoop.sh",target:"_blank",rel:"noopener noreferrer"},S={href:"https://github.com/Qv2ray/mochi",target:"_blank",rel:"noopener noreferrer"},L=e("h2",{id:"macos-安装方式",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#macos-安装方式"},[e("span",null,"macOS 安装方式")])],-1),A={href:"https://github.com/xtls/Xray-core/releases",target:"_blank",rel:"noopener noreferrer"},I=e("code",null,"xray",-1),O={href:"https://brew.sh",target:"_blank",rel:"noopener noreferrer"},R=e("code",null,"brew install xray",-1),C={href:"https://github.com/N4FA/homebrew-xray",target:"_blank",rel:"noopener noreferrer"},N={href:"https://github.com/N4FA",target:"_blank",rel:"noopener noreferrer"},F=e("h2",{id:"linux-安装方式",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#linux-安装方式"},[e("span",null,"Linux 安装方式")])],-1),P=e("h3",{id:"安装脚本",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#安装脚本"},[e("span",null,"安装脚本")])],-1),D=e("p",null,"Linux Script",-1),U={href:"https://github.com/XTLS/Xray-install",target:"_blank",rel:"noopener noreferrer"},M=e("strong",null,"官方脚本",-1),z={href:"https://github.com/team-cloudchaser/tempest",target:"_blank",rel:"noopener noreferrer"},B={href:"https://systemd.io",target:"_blank",rel:"noopener noreferrer"},T=e("code",null,"systemd",-1),V={href:"https://github.com/OpenRC/openrc",target:"_blank",rel:"noopener noreferrer"},W=e("p",null,"One Click",-1),E={href:"https://github.com/zxcvos/Xray-script",target:"_blank",rel:"noopener noreferrer"},G={href:"https://github.com/sajjaddg/xray-reality",target:"_blank",rel:"noopener noreferrer"},j={href:"https://github.com/aleskxyz/reality-ezpz",target:"_blank",rel:"noopener noreferrer"},H={href:"https://github.com/hello-yunshu/Xray_bash_onekey",target:"_blank",rel:"noopener noreferrer"},Z={href:"https://github.com/LordPenguin666/XTool",target:"_blank",rel:"noopener noreferrer"},J={href:"https://github.com/mack-a/v2ray-agent",target:"_blank",rel:"noopener noreferrer"},K={href:"https://github.com/wulabing/Xray_onekey",target:"_blank",rel:"noopener noreferrer"},Y={href:"https://github.com/proxysu/ProxySU",target:"_blank",rel:"noopener noreferrer"},Q=e("p",null,"Magisk",-1),q={href:"https://github.com/Asterisk4Magisk/Xray4Magisk",target:"_blank",rel:"noopener noreferrer"},$={href:"https://github.com/E7KMbb/Xray_For_Magisk",target:"_blank",rel:"noopener noreferrer"},ee=e("h3",{id:"arch-linux",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#arch-linux"},[e("span",null,"Arch Linux")])],-1),re=e("h4",{id:"arch-user-repository",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#arch-user-repository"},[e("span",null,"Arch User Repository")])],-1),ne={href:"https://wiki.archlinux.org/index.php/AUR_helpers",target:"_blank",rel:"noopener noreferrer"},oe={href:"https://github.com/Jguer/yay",target:"_blank",rel:"noopener noreferrer"},te=e("code",null,"yay -S xray",-1),ae=e("h4",{id:"arch-linux-cn",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#arch-linux-cn"},[e("span",null,"Arch Linux CN")])],-1),le={href:"https://www.archlinuxcn.org/archlinux-cn-repo-and-mirror/",target:"_blank",rel:"noopener noreferrer"},se=e("code",null,"pacman -S xray",-1),ie=e("h3",{id:"linuxbrew",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#linuxbrew"},[e("span",null,"Linuxbrew")])],-1),he=e("p",null,[r("Linuxbrew 包管理器的使用方式与 Homebrew 一致:"),e("code",null,"brew install xray")],-1),ce={id:"debian",tabindex:"-1"},_e={class:"header-anchor",href:"#debian"},ue=e("h3",{id:"gentoo",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#gentoo"},[e("span",null,"Gentoo")])],-1),de=e("p",null,"目前有三个第三方 Overlay 提供 Portage 安装脚本:",-1),pe={href:"https://github.com/gentoo-mirror/touchfish-os/tree/master/net-proxy/Xray",target:"_blank",rel:"noopener noreferrer"},be={href:"https://github.com/microcai/gentoo-zh",target:"_blank",rel:"noopener noreferrer"},fe={href:"https://github.com/JuanCldCmt/Xray-Overlay",target:"_blank",rel:"noopener noreferrer"},ge=e("p",null,"使用 layman 或 eselect-repository 添加 Overlay 至本地,然后即可安装。",-1),me=e("h2",{id:"docker-安装方式",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#docker-安装方式"},[e("span",null,"Docker 安装方式")])],-1),ye={href:"https://hub.docker.com/r/teddysun/xray",target:"_blank",rel:"noopener noreferrer"},xe=s('

                                      Docker image 的文件结构

                                      • /etc/xray/config.json:配置文件
                                      • /usr/bin/xray:Xray 主程序
                                      • /usr/share/xray/geoip.dat:IP 数据文件
                                      • /usr/share/xray/geosite.dat:域名数据文件

                                      图形化客户端

                                      ',3),ke={href:"https://github.com/xiaorouji/openwrt-passwall",target:"_blank",rel:"noopener noreferrer"},we={href:"https://github.com/xiaorouji/openwrt-passwall2",target:"_blank",rel:"noopener noreferrer"},Xe={href:"https://github.com/fw876/helloworld",target:"_blank",rel:"noopener noreferrer"},ve={href:"https://github.com/yichya/luci-app-xray",target:"_blank",rel:"noopener noreferrer"},Se={href:"https://github.com/yichya/openwrt-xray",target:"_blank",rel:"noopener noreferrer"},Le={href:"https://github.com/2dust/v2rayN",target:"_blank",rel:"noopener noreferrer"},Ae={href:"https://github.com/LorenEteval/Furious",target:"_blank",rel:"noopener noreferrer"},Ie={href:"https://github.com/InvisibleManVPN/InvisibleMan-XRayClient",target:"_blank",rel:"noopener noreferrer"},Oe={href:"https://github.com/2dust/v2rayNG",target:"_blank",rel:"noopener noreferrer"},Re={href:"https://github.com/XTLS/X-flutter",target:"_blank",rel:"noopener noreferrer"},Ce={href:"https://github.com/SaeedDev94/Xray",target:"_blank",rel:"noopener noreferrer"},Ne={href:"https://apps.apple.com/app/foxray/id6448898396",target:"_blank",rel:"noopener noreferrer"},Fe={href:"https://apps.apple.com/app/streisand/id6450534064",target:"_blank",rel:"noopener noreferrer"},Pe={href:"https://github.com/yanue/V2rayU",target:"_blank",rel:"noopener noreferrer"},De={href:"https://github.com/tzmax/V2RayXS",target:"_blank",rel:"noopener noreferrer"},Ue={href:"https://github.com/LorenEteval/Furious",target:"_blank",rel:"noopener noreferrer"},Me={href:"https://apps.apple.com/app/foxray/id6448898396",target:"_blank",rel:"noopener noreferrer"},ze={href:"https://github.com/v2rayA/v2rayA",target:"_blank",rel:"noopener noreferrer"},Be={href:"https://github.com/LorenEteval/Furious",target:"_blank",rel:"noopener noreferrer"},Te=e("h1",{id:"uuid-生成器",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#uuid-生成器"},[e("span",null,"UUID 生成器")])],-1),Ve={href:"https://www.uuidgenerator.net",target:"_blank",rel:"noopener noreferrer"};function We(Ee,Ge){const i=t("I18nTip"),o=t("ExternalLinkIcon"),a=t("RouterLink"),h=t("Badge");return _(),u("div",null,[n(i),p,e("p",null,[r("预编译的二进制 ZIP 格式压缩包可在 "),e("a",b,[r("Github Releases"),n(o)]),r(" 中找到。")]),f,g,m,e("ul",null,[y,e("li",null,[r("可复现构建:请参照 "),n(a,{to:"/development/intro/compile.html"},{default:l(()=>[r("编译 Xray")]),_:1})])]),x,e("ul",null,[e("li",null,[r("在 "),e("a",k,[r("Github Releases"),n(o)]),r(" 下载适用于 Windows 平台的 ZIP 压缩包,解压后可得到可执行文件 "),w,r(" ,然后"),X,r(" 即可")]),e("li",null,[r("通过 "),e("a",v,[r("Scoop"),n(o)]),r(" 包管理器安装:Xray 已经被添加到 "),e("a",S,[r("Mochi"),n(o)]),r("。")])]),L,e("ul",null,[e("li",null,[r("在 "),e("a",A,[r("Github Releases"),n(o)]),r(" 下载适用于 macOS 平台的 ZIP 压缩包,解压后可得到可执行文件 "),I,r(" ,然后"),n(a,{to:"/document/command.html"},{default:l(()=>[r("通过命令行带参数运行")]),_:1}),r(" 即可")]),e("li",null,[r("通过 "),e("a",O,[r("Homebrew"),n(o)]),r(" 包管理器安装:"),R]),e("li",null,[e("a",C,[r("homebrew-xray"),n(o)]),r(" 感谢"),e("a",N,[r("@N4FA"),n(o)])])]),F,P,e("ul",null,[e("li",null,[D,e("ul",null,[e("li",null,[e("a",U,[r("XTLS/Xray-install"),n(o)]),r(" ("),M,r(")")]),e("li",null,[e("a",z,[r("tempest"),n(o)]),r(" (支持 "),e("a",B,[T,n(o)]),r(" 以及 "),e("a",V,[r("OpenRC"),n(o)]),r("; 仅限 Linux 下使用)")])])])]),e("ul",null,[e("li",null,[W,e("ul",null,[e("li",null,[e("a",E,[r("Xray-REALITY"),n(o)]),r(", "),e("a",G,[r("xray-reality"),n(o)]),r(", "),e("a",j,[r("reality-ezpz"),n(o)])]),e("li",null,[e("a",H,[r("Xray_bash_onekey"),n(o)]),r(", "),e("a",Z,[r("XTool"),n(o)])]),e("li",null,[e("a",J,[r("v2ray-agent"),n(o)]),r(", "),e("a",K,[r("Xray_onekey"),n(o)]),r(", "),e("a",Y,[r("ProxySU"),n(o)])])])]),e("li",null,[Q,e("ul",null,[e("li",null,[e("a",q,[r("Xray4Magisk"),n(o)])]),e("li",null,[e("a",$,[r("Xray_For_Magisk"),n(o)])])])])]),ee,re,e("p",null,[r("需要使用 "),e("a",ne,[r("AUR helpers"),n(o)]),r(",以 "),e("a",oe,[r("yay"),n(o)]),r(" 为例,可通过 "),te,r(" 安装。")]),ae,e("p",null,[r("首先添加 "),e("a",le,[r("Arch Linux CN 仓库"),n(o)]),r(",然后在 root 用户下使用 "),se,r(" 安装。")]),ie,he,e("h3",ce,[e("a",_e,[e("span",null,[r("Debian "),n(h,{text:"WIP",type:"warning"})])])]),ue,de,e("ul",null,[e("li",null,[e("a",pe,[r("CHN-beta/touchfish-os"),n(o)]),r(": 个人维护,适用于 systemD 系统")]),e("li",null,[e("a",be,[r("Gentoo-zh"),n(o)]),r(": 社区维护,适用于 systemD 系统")]),e("li",null,[e("a",fe,[r("JuanCldCmt/Xray-Overlay"),n(o)]),r(":个人维护,适用于 openRC 系统,同时使用 xray 用户组运行以提高安全性")])]),ge,me,e("ul",null,[e("li",null,[e("a",ye,[r("teddysun/xray"),n(o)])])]),xe,e("ul",null,[e("li",null,[r("OpenWrt "),e("ul",null,[e("li",null,[e("a",ke,[r("PassWall"),n(o)]),r(", "),e("a",we,[r("PassWall 2"),n(o)])]),e("li",null,[e("a",Xe,[r("ShadowSocksR Plus+"),n(o)])]),e("li",null,[e("a",ve,[r("luci-app-xray"),n(o)]),r(" ("),e("a",Se,[r("openwrt-xray"),n(o)]),r(")")])])]),e("li",null,[r("Windows "),e("ul",null,[e("li",null,[e("a",Le,[r("v2rayN"),n(o)])]),e("li",null,[e("a",Ae,[r("Furious"),n(o)])]),e("li",null,[e("a",Ie,[r("Invisible Man - Xray"),n(o)])])])]),e("li",null,[r("Android "),e("ul",null,[e("li",null,[e("a",Oe,[r("v2rayNG"),n(o)])]),e("li",null,[e("a",Re,[r("X-flutter"),n(o)])]),e("li",null,[e("a",Ce,[r("SaeedDev94/Xray"),n(o)])])])]),e("li",null,[r("iOS & macOS arm64 "),e("ul",null,[e("li",null,[e("a",Ne,[r("FoXray"),n(o)])]),e("li",null,[e("a",Fe,[r("Streisand"),n(o)])])])]),e("li",null,[r("macOS arm64 & x64 "),e("ul",null,[e("li",null,[e("a",Pe,[r("V2rayU"),n(o)])]),e("li",null,[e("a",De,[r("V2RayXS"),n(o)])]),e("li",null,[e("a",Ue,[r("Furious"),n(o)])]),e("li",null,[e("a",Me,[r("FoXray"),n(o)])])])]),e("li",null,[r("Linux "),e("ul",null,[e("li",null,[e("a",ze,[r("v2rayA"),n(o)])]),e("li",null,[e("a",Be,[r("Furious"),n(o)])])])])]),Te,e("p",null,[r("第三方的 UUID 生成器 "),e("a",Ve,[r("uuidgenerator.net"),n(o)])])])}const He=c(d,[["render",We],["__file","install.html.vue"]]);export{He as default}; diff --git a/assets/install.html-CdOf2M5I.js b/assets/install.html-DrULhBgt.js similarity index 99% rename from assets/install.html-CdOf2M5I.js rename to assets/install.html-DrULhBgt.js index 64faeb80d5..f2d69a759c 100644 --- a/assets/install.html-CdOf2M5I.js +++ b/assets/install.html-DrULhBgt.js @@ -1 +1 @@ -import{_ as h,r as a,o as c,c as d,a as n,b as e,d as r,w as u,e as o}from"./app-DBM4OJyw.js";const p={},_=o('

                                      Download and Install

                                      Platform Support

                                      • Xray is available on the following platforms:
                                        • Windows 7 and later (x86 / amd64 / arm32 / arm64);
                                          • If you need to use these version (1.8.18 and later marked with win7, 1.8.6, 1.8.4) in Windows 7, operating system update KB4474419 is required. For better Internet security, it is recommended to install KB4490628 to acquire later operating system updates from Windows Update.
                                        • macOS 10.10 Yosemite and later (amd64 / arm64);
                                        • Linux 2.6.23 and later (x86 / amd64 / arm / arm64 / mips64 / mips / ppc64 / s390x / riscv64);
                                          • Including but not limited to Debian 7 / 8, Ubuntu 12.04 / 14.04 and subsequent versions, CentOS 7 / 8, Arch Linux, etc.;
                                        • FreeBSD (x86 / amd64);
                                        • OpenBSD (x86 / amd64);

                                      Download Xray

                                      ',4),f={href:"https://github.com/xtls/Xray-core/releases",target:"_blank",rel:"noopener noreferrer"},b=e("p",null,"Download the compressed package of the corresponding platform, and use it after decompression.",-1),g=e("h2",{id:"verify-the-installation-package",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#verify-the-installation-package"},[e("span",null,"Verify the Installation Package")])],-1),m=e("p",null,"Xray provides two verification methods:",-1),y=e("li",null,"SHA1/SHA256 digest of the ZIP archive",-1),x=e("h2",{id:"install-on-windows",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#install-on-windows"},[e("span",null,"Install on Windows")])],-1),k={href:"https://github.com/xtls/Xray-core/releases",target:"_blank",rel:"noopener noreferrer"},w=e("code",null,"xray.exe",-1),v=e("a",{href:"./command"},"parameters",-1),X={href:"https://scoop.sh/",target:"_blank",rel:"noopener noreferrer"},S={href:"https://github.com/Qv2ray/mochi",target:"_blank",rel:"noopener noreferrer"},I=e("h2",{id:"install-on-macos",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#install-on-macos"},[e("span",null,"Install on macOS")])],-1),L={href:"https://github.com/xtls/Xray-core/releases",target:"_blank",rel:"noopener noreferrer"},A=e("code",null,"xray",-1),P=e("a",{href:"./command"},"parameters",-1),F={href:"https://brew.sh/",target:"_blank",rel:"noopener noreferrer"},R=e("code",null,"brew install xray",-1),D={href:"https://github.com/N4FA/homebrew-xray",target:"_blank",rel:"noopener noreferrer"},N={href:"https://github.com/N4FA",target:"_blank",rel:"noopener noreferrer"},U=e("h2",{id:"install-on-linux",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#install-on-linux"},[e("span",null,"Install on Linux")])],-1),O=e("h3",{id:"install-script",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#install-script"},[e("span",null,"Install Script")])],-1),T=e("p",null,"Linux Script",-1),B={href:"https://github.com/XTLS/Xray-install",target:"_blank",rel:"noopener noreferrer"},C=e("strong",null,"Official",-1),M={href:"https://github.com/team-cloudchaser/tempest",target:"_blank",rel:"noopener noreferrer"},V={href:"https://systemd.io",target:"_blank",rel:"noopener noreferrer"},W=e("code",null,"systemd",-1),E={href:"https://github.com/OpenRC/openrc",target:"_blank",rel:"noopener noreferrer"},z=e("p",null,"One Click",-1),G={href:"https://github.com/zxcvos/Xray-script",target:"_blank",rel:"noopener noreferrer"},j={href:"https://github.com/sajjaddg/xray-reality",target:"_blank",rel:"noopener noreferrer"},H={href:"https://github.com/aleskxyz/reality-ezpz",target:"_blank",rel:"noopener noreferrer"},Z={href:"https://github.com/hello-yunshu/Xray_bash_onekey",target:"_blank",rel:"noopener noreferrer"},q={href:"https://github.com/LordPenguin666/XTool",target:"_blank",rel:"noopener noreferrer"},K={href:"https://github.com/mack-a/v2ray-agent",target:"_blank",rel:"noopener noreferrer"},Y={href:"https://github.com/wulabing/Xray_onekey",target:"_blank",rel:"noopener noreferrer"},J={href:"https://github.com/proxysu/ProxySU",target:"_blank",rel:"noopener noreferrer"},Q=e("p",null,"Magisk",-1),$={href:"https://github.com/Asterisk4Magisk/Xray4Magisk",target:"_blank",rel:"noopener noreferrer"},ee={href:"https://github.com/E7KMbb/Xray_For_Magisk",target:"_blank",rel:"noopener noreferrer"},re=e("h3",{id:"arch-linux",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#arch-linux"},[e("span",null,"Arch Linux")])],-1),ne=e("h4",{id:"arch-user-repository",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#arch-user-repository"},[e("span",null,"Arch User Repository")])],-1),te={href:"https://wiki.archlinux.org/index.php/AUR_helpers",target:"_blank",rel:"noopener noreferrer"},ae={href:"https://github.com/Jguer/yay",target:"_blank",rel:"noopener noreferrer"},oe=e("code",null,"yay -S xray",-1),le=e("h4",{id:"arch-linux-cn",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#arch-linux-cn"},[e("span",null,"Arch Linux CN")])],-1),se={href:"https://www.archlinuxcn.org/archlinux-cn-repo-and-mirror/",target:"_blank",rel:"noopener noreferrer"},ie=e("code",null,"pacman -S xray",-1),he=e("h3",{id:"linuxbrew",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#linuxbrew"},[e("span",null,"Linuxbrew")])],-1),ce=e("p",null,[r("The Linuxbrew package manager is used in the same way as Homebrew: "),e("code",null,"brew install xray")],-1),de={id:"debian",tabindex:"-1"},ue={class:"header-anchor",href:"#debian"},pe=e("h2",{id:"install-via-docker",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#install-via-docker"},[e("span",null,"Install via Docker")])],-1),_e={href:"https://hub.docker.com/r/teddysun/xray",target:"_blank",rel:"noopener noreferrer"},fe=o('

                                      The File Structure of the Docker Image

                                      • /etc/xray/config.json: configuration file
                                      • /usr/bin/xray: Xray main program
                                      • /usr/local/share/xray/geoip.dat: IP data file
                                      • /usr/local/share/xray/geosite.dat: domain name data file

                                      GUI Client

                                      ',3),be={href:"https://github.com/xiaorouji/openwrt-passwall",target:"_blank",rel:"noopener noreferrer"},ge={href:"https://github.com/xiaorouji/openwrt-passwall2",target:"_blank",rel:"noopener noreferrer"},me={href:"https://github.com/fw876/helloworld",target:"_blank",rel:"noopener noreferrer"},ye={href:"https://github.com/yichya/luci-app-xray",target:"_blank",rel:"noopener noreferrer"},xe={href:"https://github.com/yichya/openwrt-xray",target:"_blank",rel:"noopener noreferrer"},ke={href:"https://github.com/2dust/v2rayN",target:"_blank",rel:"noopener noreferrer"},we={href:"https://github.com/LorenEteval/Furious",target:"_blank",rel:"noopener noreferrer"},ve={href:"https://github.com/InvisibleManVPN/InvisibleMan-XRayClient",target:"_blank",rel:"noopener noreferrer"},Xe={href:"https://github.com/2dust/v2rayNG",target:"_blank",rel:"noopener noreferrer"},Se={href:"https://github.com/XTLS/X-flutter",target:"_blank",rel:"noopener noreferrer"},Ie={href:"https://github.com/SaeedDev94/Xray",target:"_blank",rel:"noopener noreferrer"},Le={href:"https://apps.apple.com/app/foxray/id6448898396",target:"_blank",rel:"noopener noreferrer"},Ae={href:"https://apps.apple.com/app/streisand/id6450534064",target:"_blank",rel:"noopener noreferrer"},Pe={href:"https://github.com/yanue/V2rayU",target:"_blank",rel:"noopener noreferrer"},Fe={href:"https://github.com/tzmax/V2RayXS",target:"_blank",rel:"noopener noreferrer"},Re={href:"https://github.com/LorenEteval/Furious",target:"_blank",rel:"noopener noreferrer"},De={href:"https://apps.apple.com/app/foxray/id6448898396",target:"_blank",rel:"noopener noreferrer"},Ne={href:"https://github.com/v2rayA/v2rayA",target:"_blank",rel:"noopener noreferrer"},Ue={href:"https://github.com/LorenEteval/Furious",target:"_blank",rel:"noopener noreferrer"},Oe=e("h1",{id:"uuid-generator",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#uuid-generator"},[e("span",null,"UUID Generator")])],-1),Te={href:"https://www.uuidgenerator.net",target:"_blank",rel:"noopener noreferrer"};function Be(Ce,Me){const l=a("I18nTip"),t=a("ExternalLinkIcon"),s=a("RouterLink"),i=a("Badge");return c(),d("div",null,[n(l),_,e("p",null,[r("Precompiled binaries in ZIP format are available at "),e("a",f,[r("GitHub Releases"),n(t)]),r(" found in.")]),b,g,m,e("ul",null,[y,e("li",null,[r("Reproducible build: Please refer to "),n(s,{to:"/en/development/intro/compile.html"},{default:u(()=>[r("Compile Xray")]),_:1})])]),x,e("ul",null,[e("li",null,[r("Download the ZIP archive suitable for the Windows platform on "),e("a",k,[r("Github Releases"),n(t)]),r(". After decompression, you can get an executable file "),w,r(", and then run it with "),v,r(" through the command line.")]),e("li",null,[r("By "),e("a",X,[r("Scoop"),n(t)]),r(" Package manager installation: Xray has been added to "),e("a",S,[r("Mochi"),n(t)]),r(".")])]),I,e("ul",null,[e("li",null,[r("Download the ZIP archive suitable for the macOS platform on "),e("a",L,[r("Github Releases"),n(t)]),r(". After decompression, you can get an executable file "),A,r(", and then run it with "),P,r(" through the command line.")]),e("li",null,[r("By "),e("a",F,[r("Homebrew"),n(t)]),r(" Package manager installation: "),R]),e("li",null,[e("a",D,[r("homebrew-xray"),n(t)]),r(": Thanks "),e("a",N,[r("@N4FA"),n(t)])])]),U,O,e("ul",null,[e("li",null,[T,e("ul",null,[e("li",null,[e("a",B,[r("XTLS/Xray-install"),n(t)]),r(" ("),C,r(")")]),e("li",null,[e("a",M,[r("tempest"),n(t)]),r(" (supports "),e("a",V,[W,n(t)]),r(" and "),e("a",E,[r("OpenRC"),n(t)]),r("; Linux-only)")])])])]),e("ul",null,[e("li",null,[z,e("ul",null,[e("li",null,[e("a",G,[r("Xray-REALITY"),n(t)]),r(", "),e("a",j,[r("xray-reality"),n(t)]),r(", "),e("a",H,[r("reality-ezpz"),n(t)])]),e("li",null,[e("a",Z,[r("Xray_bash_onekey"),n(t)]),r(", "),e("a",q,[r("XTool"),n(t)])]),e("li",null,[e("a",K,[r("v2ray-agent"),n(t)]),r(", "),e("a",Y,[r("Xray_onekey"),n(t)]),r(", "),e("a",J,[r("ProxySU"),n(t)])])])]),e("li",null,[Q,e("ul",null,[e("li",null,[e("a",$,[r("Xray4Magisk"),n(t)])]),e("li",null,[e("a",ee,[r("Xray_For_Magisk"),n(t)])])])])]),re,ne,e("p",null,[r("Need to use "),e("a",te,[r("AUR helpers"),n(t)]),r(", "),e("a",ae,[r("yay"),n(t)]),r(" as an example, it can be installed via "),oe,r(".")]),le,e("p",null,[r("First add "),e("a",se,[r("Arch Linux CN"),n(t)]),r(" repository, and then use the root user "),ie,r("to install.")]),he,ce,e("h3",de,[e("a",ue,[e("span",null,[r("Debian "),n(i,{text:"WIP",type:"warning"})])])]),pe,e("ul",null,[e("li",null,[e("a",_e,[r("teddysun/xray"),n(t)])])]),fe,e("ul",null,[e("li",null,[r("OpenWrt "),e("ul",null,[e("li",null,[e("a",be,[r("PassWall"),n(t)]),r(", "),e("a",ge,[r("PassWall 2"),n(t)])]),e("li",null,[e("a",me,[r("ShadowSocksR Plus+"),n(t)])]),e("li",null,[e("a",ye,[r("luci-app-xray"),n(t)]),r(" ("),e("a",xe,[r("openwrt-xray"),n(t)]),r(")")])])]),e("li",null,[r("Windows "),e("ul",null,[e("li",null,[e("a",ke,[r("v2rayN"),n(t)])]),e("li",null,[e("a",we,[r("Furious"),n(t)])]),e("li",null,[e("a",ve,[r("Invisible Man - Xray"),n(t)])])])]),e("li",null,[r("Android "),e("ul",null,[e("li",null,[e("a",Xe,[r("v2rayNG"),n(t)])]),e("li",null,[e("a",Se,[r("X-flutter"),n(t)])]),e("li",null,[e("a",Ie,[r("SaeedDev94/Xray"),n(t)])])])]),e("li",null,[r("iOS & macOS arm64 "),e("ul",null,[e("li",null,[e("a",Le,[r("FoXray"),n(t)])]),e("li",null,[e("a",Ae,[r("Streisand"),n(t)])])])]),e("li",null,[r("macOS arm64 & x64 "),e("ul",null,[e("li",null,[e("a",Pe,[r("V2rayU"),n(t)])]),e("li",null,[e("a",Fe,[r("V2RayXS"),n(t)])]),e("li",null,[e("a",Re,[r("Furious"),n(t)])]),e("li",null,[e("a",De,[r("FoXray"),n(t)])])])]),e("li",null,[r("Linux "),e("ul",null,[e("li",null,[e("a",Ne,[r("v2rayA"),n(t)])]),e("li",null,[e("a",Ue,[r("Furious"),n(t)])])])])]),Oe,e("p",null,[r("Third-party UUID generator "),e("a",Te,[r("uuidgenerator.net"),n(t)])])])}const We=h(p,[["render",Be],["__file","install.html.vue"]]);export{We as default}; +import{_ as h,r as a,o as c,c as d,a as n,b as e,d as r,w as u,e as o}from"./app-D7uBbsY3.js";const p={},_=o('

                                      Download and Install

                                      Platform Support

                                      • Xray is available on the following platforms:
                                        • Windows 7 and later (x86 / amd64 / arm32 / arm64);
                                          • If you need to use these version (1.8.18 and later marked with win7, 1.8.6, 1.8.4) in Windows 7, operating system update KB4474419 is required. For better Internet security, it is recommended to install KB4490628 to acquire later operating system updates from Windows Update.
                                        • macOS 10.10 Yosemite and later (amd64 / arm64);
                                        • Linux 2.6.23 and later (x86 / amd64 / arm / arm64 / mips64 / mips / ppc64 / s390x / riscv64);
                                          • Including but not limited to Debian 7 / 8, Ubuntu 12.04 / 14.04 and subsequent versions, CentOS 7 / 8, Arch Linux, etc.;
                                        • FreeBSD (x86 / amd64);
                                        • OpenBSD (x86 / amd64);

                                      Download Xray

                                      ',4),f={href:"https://github.com/xtls/Xray-core/releases",target:"_blank",rel:"noopener noreferrer"},b=e("p",null,"Download the compressed package of the corresponding platform, and use it after decompression.",-1),g=e("h2",{id:"verify-the-installation-package",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#verify-the-installation-package"},[e("span",null,"Verify the Installation Package")])],-1),m=e("p",null,"Xray provides two verification methods:",-1),y=e("li",null,"SHA1/SHA256 digest of the ZIP archive",-1),x=e("h2",{id:"install-on-windows",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#install-on-windows"},[e("span",null,"Install on Windows")])],-1),k={href:"https://github.com/xtls/Xray-core/releases",target:"_blank",rel:"noopener noreferrer"},w=e("code",null,"xray.exe",-1),v=e("a",{href:"./command"},"parameters",-1),X={href:"https://scoop.sh/",target:"_blank",rel:"noopener noreferrer"},S={href:"https://github.com/Qv2ray/mochi",target:"_blank",rel:"noopener noreferrer"},I=e("h2",{id:"install-on-macos",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#install-on-macos"},[e("span",null,"Install on macOS")])],-1),L={href:"https://github.com/xtls/Xray-core/releases",target:"_blank",rel:"noopener noreferrer"},A=e("code",null,"xray",-1),P=e("a",{href:"./command"},"parameters",-1),F={href:"https://brew.sh/",target:"_blank",rel:"noopener noreferrer"},R=e("code",null,"brew install xray",-1),D={href:"https://github.com/N4FA/homebrew-xray",target:"_blank",rel:"noopener noreferrer"},N={href:"https://github.com/N4FA",target:"_blank",rel:"noopener noreferrer"},U=e("h2",{id:"install-on-linux",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#install-on-linux"},[e("span",null,"Install on Linux")])],-1),O=e("h3",{id:"install-script",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#install-script"},[e("span",null,"Install Script")])],-1),T=e("p",null,"Linux Script",-1),B={href:"https://github.com/XTLS/Xray-install",target:"_blank",rel:"noopener noreferrer"},C=e("strong",null,"Official",-1),M={href:"https://github.com/team-cloudchaser/tempest",target:"_blank",rel:"noopener noreferrer"},V={href:"https://systemd.io",target:"_blank",rel:"noopener noreferrer"},W=e("code",null,"systemd",-1),E={href:"https://github.com/OpenRC/openrc",target:"_blank",rel:"noopener noreferrer"},z=e("p",null,"One Click",-1),G={href:"https://github.com/zxcvos/Xray-script",target:"_blank",rel:"noopener noreferrer"},j={href:"https://github.com/sajjaddg/xray-reality",target:"_blank",rel:"noopener noreferrer"},H={href:"https://github.com/aleskxyz/reality-ezpz",target:"_blank",rel:"noopener noreferrer"},Z={href:"https://github.com/hello-yunshu/Xray_bash_onekey",target:"_blank",rel:"noopener noreferrer"},q={href:"https://github.com/LordPenguin666/XTool",target:"_blank",rel:"noopener noreferrer"},K={href:"https://github.com/mack-a/v2ray-agent",target:"_blank",rel:"noopener noreferrer"},Y={href:"https://github.com/wulabing/Xray_onekey",target:"_blank",rel:"noopener noreferrer"},J={href:"https://github.com/proxysu/ProxySU",target:"_blank",rel:"noopener noreferrer"},Q=e("p",null,"Magisk",-1),$={href:"https://github.com/Asterisk4Magisk/Xray4Magisk",target:"_blank",rel:"noopener noreferrer"},ee={href:"https://github.com/E7KMbb/Xray_For_Magisk",target:"_blank",rel:"noopener noreferrer"},re=e("h3",{id:"arch-linux",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#arch-linux"},[e("span",null,"Arch Linux")])],-1),ne=e("h4",{id:"arch-user-repository",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#arch-user-repository"},[e("span",null,"Arch User Repository")])],-1),te={href:"https://wiki.archlinux.org/index.php/AUR_helpers",target:"_blank",rel:"noopener noreferrer"},ae={href:"https://github.com/Jguer/yay",target:"_blank",rel:"noopener noreferrer"},oe=e("code",null,"yay -S xray",-1),le=e("h4",{id:"arch-linux-cn",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#arch-linux-cn"},[e("span",null,"Arch Linux CN")])],-1),se={href:"https://www.archlinuxcn.org/archlinux-cn-repo-and-mirror/",target:"_blank",rel:"noopener noreferrer"},ie=e("code",null,"pacman -S xray",-1),he=e("h3",{id:"linuxbrew",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#linuxbrew"},[e("span",null,"Linuxbrew")])],-1),ce=e("p",null,[r("The Linuxbrew package manager is used in the same way as Homebrew: "),e("code",null,"brew install xray")],-1),de={id:"debian",tabindex:"-1"},ue={class:"header-anchor",href:"#debian"},pe=e("h2",{id:"install-via-docker",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#install-via-docker"},[e("span",null,"Install via Docker")])],-1),_e={href:"https://hub.docker.com/r/teddysun/xray",target:"_blank",rel:"noopener noreferrer"},fe=o('

                                      The File Structure of the Docker Image

                                      • /etc/xray/config.json: configuration file
                                      • /usr/bin/xray: Xray main program
                                      • /usr/local/share/xray/geoip.dat: IP data file
                                      • /usr/local/share/xray/geosite.dat: domain name data file

                                      GUI Client

                                      ',3),be={href:"https://github.com/xiaorouji/openwrt-passwall",target:"_blank",rel:"noopener noreferrer"},ge={href:"https://github.com/xiaorouji/openwrt-passwall2",target:"_blank",rel:"noopener noreferrer"},me={href:"https://github.com/fw876/helloworld",target:"_blank",rel:"noopener noreferrer"},ye={href:"https://github.com/yichya/luci-app-xray",target:"_blank",rel:"noopener noreferrer"},xe={href:"https://github.com/yichya/openwrt-xray",target:"_blank",rel:"noopener noreferrer"},ke={href:"https://github.com/2dust/v2rayN",target:"_blank",rel:"noopener noreferrer"},we={href:"https://github.com/LorenEteval/Furious",target:"_blank",rel:"noopener noreferrer"},ve={href:"https://github.com/InvisibleManVPN/InvisibleMan-XRayClient",target:"_blank",rel:"noopener noreferrer"},Xe={href:"https://github.com/2dust/v2rayNG",target:"_blank",rel:"noopener noreferrer"},Se={href:"https://github.com/XTLS/X-flutter",target:"_blank",rel:"noopener noreferrer"},Ie={href:"https://github.com/SaeedDev94/Xray",target:"_blank",rel:"noopener noreferrer"},Le={href:"https://apps.apple.com/app/foxray/id6448898396",target:"_blank",rel:"noopener noreferrer"},Ae={href:"https://apps.apple.com/app/streisand/id6450534064",target:"_blank",rel:"noopener noreferrer"},Pe={href:"https://github.com/yanue/V2rayU",target:"_blank",rel:"noopener noreferrer"},Fe={href:"https://github.com/tzmax/V2RayXS",target:"_blank",rel:"noopener noreferrer"},Re={href:"https://github.com/LorenEteval/Furious",target:"_blank",rel:"noopener noreferrer"},De={href:"https://apps.apple.com/app/foxray/id6448898396",target:"_blank",rel:"noopener noreferrer"},Ne={href:"https://github.com/v2rayA/v2rayA",target:"_blank",rel:"noopener noreferrer"},Ue={href:"https://github.com/LorenEteval/Furious",target:"_blank",rel:"noopener noreferrer"},Oe=e("h1",{id:"uuid-generator",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#uuid-generator"},[e("span",null,"UUID Generator")])],-1),Te={href:"https://www.uuidgenerator.net",target:"_blank",rel:"noopener noreferrer"};function Be(Ce,Me){const l=a("I18nTip"),t=a("ExternalLinkIcon"),s=a("RouterLink"),i=a("Badge");return c(),d("div",null,[n(l),_,e("p",null,[r("Precompiled binaries in ZIP format are available at "),e("a",f,[r("GitHub Releases"),n(t)]),r(" found in.")]),b,g,m,e("ul",null,[y,e("li",null,[r("Reproducible build: Please refer to "),n(s,{to:"/en/development/intro/compile.html"},{default:u(()=>[r("Compile Xray")]),_:1})])]),x,e("ul",null,[e("li",null,[r("Download the ZIP archive suitable for the Windows platform on "),e("a",k,[r("Github Releases"),n(t)]),r(". After decompression, you can get an executable file "),w,r(", and then run it with "),v,r(" through the command line.")]),e("li",null,[r("By "),e("a",X,[r("Scoop"),n(t)]),r(" Package manager installation: Xray has been added to "),e("a",S,[r("Mochi"),n(t)]),r(".")])]),I,e("ul",null,[e("li",null,[r("Download the ZIP archive suitable for the macOS platform on "),e("a",L,[r("Github Releases"),n(t)]),r(". After decompression, you can get an executable file "),A,r(", and then run it with "),P,r(" through the command line.")]),e("li",null,[r("By "),e("a",F,[r("Homebrew"),n(t)]),r(" Package manager installation: "),R]),e("li",null,[e("a",D,[r("homebrew-xray"),n(t)]),r(": Thanks "),e("a",N,[r("@N4FA"),n(t)])])]),U,O,e("ul",null,[e("li",null,[T,e("ul",null,[e("li",null,[e("a",B,[r("XTLS/Xray-install"),n(t)]),r(" ("),C,r(")")]),e("li",null,[e("a",M,[r("tempest"),n(t)]),r(" (supports "),e("a",V,[W,n(t)]),r(" and "),e("a",E,[r("OpenRC"),n(t)]),r("; Linux-only)")])])])]),e("ul",null,[e("li",null,[z,e("ul",null,[e("li",null,[e("a",G,[r("Xray-REALITY"),n(t)]),r(", "),e("a",j,[r("xray-reality"),n(t)]),r(", "),e("a",H,[r("reality-ezpz"),n(t)])]),e("li",null,[e("a",Z,[r("Xray_bash_onekey"),n(t)]),r(", "),e("a",q,[r("XTool"),n(t)])]),e("li",null,[e("a",K,[r("v2ray-agent"),n(t)]),r(", "),e("a",Y,[r("Xray_onekey"),n(t)]),r(", "),e("a",J,[r("ProxySU"),n(t)])])])]),e("li",null,[Q,e("ul",null,[e("li",null,[e("a",$,[r("Xray4Magisk"),n(t)])]),e("li",null,[e("a",ee,[r("Xray_For_Magisk"),n(t)])])])])]),re,ne,e("p",null,[r("Need to use "),e("a",te,[r("AUR helpers"),n(t)]),r(", "),e("a",ae,[r("yay"),n(t)]),r(" as an example, it can be installed via "),oe,r(".")]),le,e("p",null,[r("First add "),e("a",se,[r("Arch Linux CN"),n(t)]),r(" repository, and then use the root user "),ie,r("to install.")]),he,ce,e("h3",de,[e("a",ue,[e("span",null,[r("Debian "),n(i,{text:"WIP",type:"warning"})])])]),pe,e("ul",null,[e("li",null,[e("a",_e,[r("teddysun/xray"),n(t)])])]),fe,e("ul",null,[e("li",null,[r("OpenWrt "),e("ul",null,[e("li",null,[e("a",be,[r("PassWall"),n(t)]),r(", "),e("a",ge,[r("PassWall 2"),n(t)])]),e("li",null,[e("a",me,[r("ShadowSocksR Plus+"),n(t)])]),e("li",null,[e("a",ye,[r("luci-app-xray"),n(t)]),r(" ("),e("a",xe,[r("openwrt-xray"),n(t)]),r(")")])])]),e("li",null,[r("Windows "),e("ul",null,[e("li",null,[e("a",ke,[r("v2rayN"),n(t)])]),e("li",null,[e("a",we,[r("Furious"),n(t)])]),e("li",null,[e("a",ve,[r("Invisible Man - Xray"),n(t)])])])]),e("li",null,[r("Android "),e("ul",null,[e("li",null,[e("a",Xe,[r("v2rayNG"),n(t)])]),e("li",null,[e("a",Se,[r("X-flutter"),n(t)])]),e("li",null,[e("a",Ie,[r("SaeedDev94/Xray"),n(t)])])])]),e("li",null,[r("iOS & macOS arm64 "),e("ul",null,[e("li",null,[e("a",Le,[r("FoXray"),n(t)])]),e("li",null,[e("a",Ae,[r("Streisand"),n(t)])])])]),e("li",null,[r("macOS arm64 & x64 "),e("ul",null,[e("li",null,[e("a",Pe,[r("V2rayU"),n(t)])]),e("li",null,[e("a",Fe,[r("V2RayXS"),n(t)])]),e("li",null,[e("a",Re,[r("Furious"),n(t)])]),e("li",null,[e("a",De,[r("FoXray"),n(t)])])])]),e("li",null,[r("Linux "),e("ul",null,[e("li",null,[e("a",Ne,[r("v2rayA"),n(t)])]),e("li",null,[e("a",Ue,[r("Furious"),n(t)])])])])]),Oe,e("p",null,[r("Third-party UUID generator "),e("a",Te,[r("uuidgenerator.net"),n(t)])])])}const We=h(p,[["render",Be],["__file","install.html.vue"]]);export{We as default}; diff --git a/assets/iptables_gid.html-BaYh0Fhk.js b/assets/iptables_gid.html-CA7RPeCB.js similarity index 99% rename from assets/iptables_gid.html-BaYh0Fhk.js rename to assets/iptables_gid.html-CA7RPeCB.js index 930ddfe1fd..8f5d4dbfae 100644 --- a/assets/iptables_gid.html-BaYh0Fhk.js +++ b/assets/iptables_gid.html-CA7RPeCB.js @@ -1,4 +1,4 @@ -import{_ as o,r,o as l,c,a as n,b as a,d as e,w as d,e as t}from"./app-DBM4OJyw.js";const u={},m=a("h1",{id:"transparent-proxy-to-circumvent-xray-traffic-via-gid",tabindex:"-1"},[a("a",{class:"header-anchor",href:"#transparent-proxy-to-circumvent-xray-traffic-via-gid"},[a("span",null,"Transparent proxy to circumvent Xray traffic via GID")])],-1),b={href:"https://guide.v2fly.org/app/transparent_proxy.html",target:"_blank",rel:"noopener noreferrer"},v={href:"https://guide.v2fly.org/app/tproxy.html",target:"_blank",rel:"noopener noreferrer"},h=a("p",null,"There are several problems with this method:",-1),k={href:"https://github.com/v2ray/v2ray-core/issues/2621",target:"_blank",rel:"noopener noreferrer"},g=a("li",null,[a("p",null,"Android has its own mark mechanism and this solution is not available on Android")],-1),f=t('

                                      The solution in this tutorial does not require a mark setting and has a higher theoretical performance, as well as not having the problems mentioned above.

                                      Ideas

                                      TProxy traffic can only be received by users with root privileges (uid==0) or other users with CAP_NET_ADMIN privileges.

                                      The iptables rules can separate network traffic by uid (user id) and gid (user group id). Let Xray run on a user with uid==0 but gid!=0. Set the iptables rule to not proxy traffic for that gid to circumvent Xray traffic.

                                      Configuration Procedure

                                      1. Preliminary preparation

                                      Android

                                      ',7),y=a("li",null,[a("p",null,"System has root privilege.")],-1),x={href:"https://play.google.com/store/apps/details?id=stericson.busybox",target:"_blank",rel:"noopener noreferrer"},_=a("li",null,[a("p",null,"There is a terminal that can execute commands, you can use adb shell, termux etc.")],-1),w=t(`

                                      Other Linux system

                                      Need sudo, iptables-tproxy module and iptables-extra module。

                                      Usually the system comes with these functions. If you are using openwrt, you will need to run the following command:

                                      opkg install sudo iptables-mod-tproxy iptables-mod-extra
                                      +import{_ as o,r,o as l,c,a as n,b as a,d as e,w as d,e as t}from"./app-D7uBbsY3.js";const u={},m=a("h1",{id:"transparent-proxy-to-circumvent-xray-traffic-via-gid",tabindex:"-1"},[a("a",{class:"header-anchor",href:"#transparent-proxy-to-circumvent-xray-traffic-via-gid"},[a("span",null,"Transparent proxy to circumvent Xray traffic via GID")])],-1),b={href:"https://guide.v2fly.org/app/transparent_proxy.html",target:"_blank",rel:"noopener noreferrer"},v={href:"https://guide.v2fly.org/app/tproxy.html",target:"_blank",rel:"noopener noreferrer"},h=a("p",null,"There are several problems with this method:",-1),k={href:"https://github.com/v2ray/v2ray-core/issues/2621",target:"_blank",rel:"noopener noreferrer"},g=a("li",null,[a("p",null,"Android has its own mark mechanism and this solution is not available on Android")],-1),f=t('

                                      The solution in this tutorial does not require a mark setting and has a higher theoretical performance, as well as not having the problems mentioned above.

                                      Ideas

                                      TProxy traffic can only be received by users with root privileges (uid==0) or other users with CAP_NET_ADMIN privileges.

                                      The iptables rules can separate network traffic by uid (user id) and gid (user group id). Let Xray run on a user with uid==0 but gid!=0. Set the iptables rule to not proxy traffic for that gid to circumvent Xray traffic.

                                      Configuration Procedure

                                      1. Preliminary preparation

                                      Android

                                      ',7),y=a("li",null,[a("p",null,"System has root privilege.")],-1),x={href:"https://play.google.com/store/apps/details?id=stericson.busybox",target:"_blank",rel:"noopener noreferrer"},_=a("li",null,[a("p",null,"There is a terminal that can execute commands, you can use adb shell, termux etc.")],-1),w=t(`

                                      Other Linux system

                                      Need sudo, iptables-tproxy module and iptables-extra module。

                                      Usually the system comes with these functions. If you are using openwrt, you will need to run the following command:

                                      opkg install sudo iptables-mod-tproxy iptables-mod-extra
                                       

                                      Also attached are some common dependencies for openwrt, the lack of which may prevent Xray from running

                                      opkg install libopenssl ca-certificates
                                       

                                      2. Add user (Android users please ignore this section)

                                      Android does not support managing users by modifying the /etc/passwd file, please ignore it and go straight to the next step.

                                      grep -qw xray_tproxy /etc/passwd || echo "xray_tproxy:x:0:23333:::" >> /etc/passwd
                                       

                                      where xray_tproxy is the username, 0 is the uid and 23333 is the gid, the username and gid can be set by yourself, the uid must be 0. To check if the user was added successfully, run

                                      sudo -u xray_tproxy id
                                      diff --git a/assets/iptables_gid.html-CszhZSj9.js b/assets/iptables_gid.html-CD1EfJBO.js
                                      similarity index 99%
                                      rename from assets/iptables_gid.html-CszhZSj9.js
                                      rename to assets/iptables_gid.html-CD1EfJBO.js
                                      index ff9a9dc91f..24b5028ad8 100644
                                      --- a/assets/iptables_gid.html-CszhZSj9.js
                                      +++ b/assets/iptables_gid.html-CD1EfJBO.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as l,r as t,o as i,c as o,a as n,b as a,d as s,e as p}from"./app-DBM4OJyw.js";const c={},d=a("h1",{id:"透明代理通过-gid-规避-xray-流量",tabindex:"-1"},[a("a",{class:"header-anchor",href:"#透明代理通过-gid-规避-xray-流量"},[a("span",null,"透明代理通过 gid 规避 Xray 流量")])],-1),m={href:"https://guide.v2fly.org/app/transparent_proxy.html",target:"_blank",rel:"noopener noreferrer"},v={href:"https://guide.v2fly.org/app/tproxy.html",target:"_blank",rel:"noopener noreferrer"},u=a("strong",null,[a("a",{href:"./tproxy"},"透明代理(TProxy)配置教程")],-1),b=a("p",null,"这么做有以下几个问题:",-1),k={href:"https://github.com/v2ray/v2ray-core/issues/2621",target:"_blank",rel:"noopener noreferrer"},g=a("li",null,[a("p",null,"安卓系统有自己的 mark 机制,该方案在安卓上不可用")],-1),h=p('

                                      本教程的方案不需要设置 mark,理论性能更高,同时也不存在上述问题。

                                      思路

                                      tproxy 流量只能被 root 权限用户(uid==0)或其他有 CAP_NET_ADMIN 权限的用户接收。

                                      iptables 规则可以通过 uid(用户 id)和 gid(用户组 id)分流。

                                      让 Xray 运行在一个 uid==0 但 gid!=0 的用户上,设置 iptables 规则不代理该 gid 的流量来规避 Xray 流量。

                                      配置过程

                                      1. 前期准备

                                      安卓系统

                                      ',8),_=a("li",null,[a("p",null,"系统已 root")],-1),A={href:"https://play.google.com/store/apps/details?id=stericson.busybox",target:"_blank",rel:"noopener noreferrer"},y=a("li",null,[a("p",null,"有一个可以执行命令的终端,可以使用 adb shell,termux 等。")],-1),x=p(`

                                      其它 Linux 系统

                                      需要依赖 sudo,iptables 的 tproxy 模块和 extra 模块。

                                      一般系统都有自带,openwrt 运行:

                                      opkg install sudo iptables-mod-tproxy iptables-mod-extra
                                      +import{_ as l,r as t,o as i,c as o,a as n,b as a,d as s,e as p}from"./app-D7uBbsY3.js";const c={},d=a("h1",{id:"透明代理通过-gid-规避-xray-流量",tabindex:"-1"},[a("a",{class:"header-anchor",href:"#透明代理通过-gid-规避-xray-流量"},[a("span",null,"透明代理通过 gid 规避 Xray 流量")])],-1),m={href:"https://guide.v2fly.org/app/transparent_proxy.html",target:"_blank",rel:"noopener noreferrer"},v={href:"https://guide.v2fly.org/app/tproxy.html",target:"_blank",rel:"noopener noreferrer"},u=a("strong",null,[a("a",{href:"./tproxy"},"透明代理(TProxy)配置教程")],-1),b=a("p",null,"这么做有以下几个问题:",-1),k={href:"https://github.com/v2ray/v2ray-core/issues/2621",target:"_blank",rel:"noopener noreferrer"},g=a("li",null,[a("p",null,"安卓系统有自己的 mark 机制,该方案在安卓上不可用")],-1),h=p('

                                      本教程的方案不需要设置 mark,理论性能更高,同时也不存在上述问题。

                                      思路

                                      tproxy 流量只能被 root 权限用户(uid==0)或其他有 CAP_NET_ADMIN 权限的用户接收。

                                      iptables 规则可以通过 uid(用户 id)和 gid(用户组 id)分流。

                                      让 Xray 运行在一个 uid==0 但 gid!=0 的用户上,设置 iptables 规则不代理该 gid 的流量来规避 Xray 流量。

                                      配置过程

                                      1. 前期准备

                                      安卓系统

                                      ',8),_=a("li",null,[a("p",null,"系统已 root")],-1),A={href:"https://play.google.com/store/apps/details?id=stericson.busybox",target:"_blank",rel:"noopener noreferrer"},y=a("li",null,[a("p",null,"有一个可以执行命令的终端,可以使用 adb shell,termux 等。")],-1),x=p(`

                                      其它 Linux 系统

                                      需要依赖 sudo,iptables 的 tproxy 模块和 extra 模块。

                                      一般系统都有自带,openwrt 运行:

                                      opkg install sudo iptables-mod-tproxy iptables-mod-extra
                                       

                                      另附上一些 openwrt 常用的依赖,缺少可能导致 Xray 无法运行

                                      opkg install libopenssl ca-certificates
                                       

                                      2. 添加用户(安卓用户请忽略)

                                      安卓系统不支持/etc/passwd 文件来管理用户,请忽略,直接下一步。

                                      grep -qw xray_tproxy /etc/passwd || echo "xray_tproxy:x:0:23333:::" >> /etc/passwd
                                       

                                      其中 xray_tproxy 是用户名,0 是 uid,23333 是 gid,用户名和 gid 可以自己定,uid 必须为 0。 检查用户是否添加成功,运行

                                      sudo -u xray_tproxy id
                                      diff --git a/assets/iptables_gid.html-CNg7E9Pm.js b/assets/iptables_gid.html-DHq3P8hi.js
                                      similarity index 99%
                                      rename from assets/iptables_gid.html-CNg7E9Pm.js
                                      rename to assets/iptables_gid.html-DHq3P8hi.js
                                      index b1a5ff3e5f..c96b0fd4c6 100644
                                      --- a/assets/iptables_gid.html-CNg7E9Pm.js
                                      +++ b/assets/iptables_gid.html-DHq3P8hi.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as l,r as t,o as i,c as o,a as n,b as a,d as s,e as p}from"./app-DBM4OJyw.js";const c={},d=a("h1",{id:"прозрачное-проксирование-исключение-трафика-xray-с-помощью-gid",tabindex:"-1"},[a("a",{class:"header-anchor",href:"#прозрачное-проксирование-исключение-трафика-xray-с-помощью-gid"},[a("span",null,"Прозрачное проксирование: Исключение трафика Xray с помощью GID")])],-1),m={href:"https://guide.v2fly.org/app/transparent_proxy.html",target:"_blank",rel:"noopener noreferrer"},v={href:"https://guide.v2fly.org/app/tproxy.html",target:"_blank",rel:"noopener noreferrer"},b=a("strong",null,[a("a",{href:"./tproxy"},"Руководство по настройке прозрачного проксирования (TProxy)")],-1),u=a("p",null,"У такого подхода есть несколько недостатков:",-1),k={href:"https://github.com/v2ray/v2ray-core/issues/2621",target:"_blank",rel:"noopener noreferrer"},h=a("li",null,[a("p",null,"Android использует собственный механизм меток, поэтому данный метод не применим к Android")],-1),g=p('

                                      Предлагаемый в данном руководстве подход не требует использования меток, теоретически обеспечивая более высокую производительность и избегая описанных выше проблем.

                                      Идея

                                      Tproxy трафик может приниматься только пользователями с правами root (uid==0) или CAP_NET_ADMIN.

                                      Правила iptables позволяют разделять трафик на основе UID (идентификатор пользователя) и GID (идентификатор группы).

                                      Запустим Xray от имени пользователя с uid==0 и gid!=0 и настроим правила iptables, чтобы исключить трафик с этим GID, избегая проксирования трафика Xray.

                                      Настройка

                                      1. Предварительная подготовка

                                      Android

                                      ',8),D=a("li",null,"На устройстве должны быть получены root-права.",-1),B={href:"https://play.google.com/store/apps/details?id=stericson.busybox",target:"_blank",rel:"noopener noreferrer"},_=a("li",null,"Наличие терминала для выполнения команд, например, adb shell, Termux и т.д.",-1),A=p(`

                                      Другие Linux системы

                                      Необходимо наличие sudo, модуля tproxy для iptables и модуля extra.

                                      Обычно все это уже установлено в системе, для OpenWRT выполните:

                                      opkg install sudo iptables-mod-tproxy iptables-mod-extra
                                      +import{_ as l,r as t,o as i,c as o,a as n,b as a,d as s,e as p}from"./app-D7uBbsY3.js";const c={},d=a("h1",{id:"прозрачное-проксирование-исключение-трафика-xray-с-помощью-gid",tabindex:"-1"},[a("a",{class:"header-anchor",href:"#прозрачное-проксирование-исключение-трафика-xray-с-помощью-gid"},[a("span",null,"Прозрачное проксирование: Исключение трафика Xray с помощью GID")])],-1),m={href:"https://guide.v2fly.org/app/transparent_proxy.html",target:"_blank",rel:"noopener noreferrer"},v={href:"https://guide.v2fly.org/app/tproxy.html",target:"_blank",rel:"noopener noreferrer"},b=a("strong",null,[a("a",{href:"./tproxy"},"Руководство по настройке прозрачного проксирования (TProxy)")],-1),u=a("p",null,"У такого подхода есть несколько недостатков:",-1),k={href:"https://github.com/v2ray/v2ray-core/issues/2621",target:"_blank",rel:"noopener noreferrer"},h=a("li",null,[a("p",null,"Android использует собственный механизм меток, поэтому данный метод не применим к Android")],-1),g=p('

                                      Предлагаемый в данном руководстве подход не требует использования меток, теоретически обеспечивая более высокую производительность и избегая описанных выше проблем.

                                      Идея

                                      Tproxy трафик может приниматься только пользователями с правами root (uid==0) или CAP_NET_ADMIN.

                                      Правила iptables позволяют разделять трафик на основе UID (идентификатор пользователя) и GID (идентификатор группы).

                                      Запустим Xray от имени пользователя с uid==0 и gid!=0 и настроим правила iptables, чтобы исключить трафик с этим GID, избегая проксирования трафика Xray.

                                      Настройка

                                      1. Предварительная подготовка

                                      Android

                                      ',8),D=a("li",null,"На устройстве должны быть получены root-права.",-1),B={href:"https://play.google.com/store/apps/details?id=stericson.busybox",target:"_blank",rel:"noopener noreferrer"},_=a("li",null,"Наличие терминала для выполнения команд, например, adb shell, Termux и т.д.",-1),A=p(`

                                      Другие Linux системы

                                      Необходимо наличие sudo, модуля tproxy для iptables и модуля extra.

                                      Обычно все это уже установлено в системе, для OpenWRT выполните:

                                      opkg install sudo iptables-mod-tproxy iptables-mod-extra
                                       

                                      Также могут понадобиться следующие зависимости для OpenWRT, их отсутствие может помешать запуску Xray:

                                      opkg install libopenssl ca-certificates
                                       

                                      2. Добавление пользователя (пропустите для Android)

                                      Android не поддерживает файл /etc/passwd для управления пользователями, пропустите этот шаг и перейдите к следующему.

                                      grep -qw xray_tproxy /etc/passwd || echo "xray_tproxy:x:0:23333:::" >> /etc/passwd
                                       

                                      Где xray_tproxy - имя пользователя, 0 - UID, 23333 - GID. Имя пользователя и GID можно задать произвольно, UID должен быть равен 0. Проверьте, успешно ли добавлен пользователь, выполнив:

                                      sudo -u xray_tproxy id
                                      diff --git a/assets/journeyDiagram-35ZZFJAM-BivG2OsD.js b/assets/journeyDiagram-35ZZFJAM-CX8IC_rs.js
                                      similarity index 98%
                                      rename from assets/journeyDiagram-35ZZFJAM-BivG2OsD.js
                                      rename to assets/journeyDiagram-35ZZFJAM-CX8IC_rs.js
                                      index c9c5401eb2..fae9d177d5 100644
                                      --- a/assets/journeyDiagram-35ZZFJAM-BivG2OsD.js
                                      +++ b/assets/journeyDiagram-35ZZFJAM-CX8IC_rs.js
                                      @@ -1,4 +1,4 @@
                                      -import{d as ft,f as gt,g as at,b as mt}from"./chunk-AIUMCIBP-g55d6rFj.js";import{_ as i,d as A,q as xt,r as kt,s as _t,g as vt,c as bt,b as wt,t as Tt,j as W,k as St}from"./mermaid.core-DapiNGBY.js";import{d as tt}from"./arc-CO2v8jBL.js";import"./app-DBM4OJyw.js";var H=function(){var t=i(function(g,r,a,l){for(a=a||{},l=g.length;l--;a[g[l]]=r);return a},"o"),e=[6,8,10,11,12,14,16,17,18],n=[1,9],c=[1,10],s=[1,11],u=[1,12],h=[1,13],p=[1,14],d={trace:i(function(){},"trace"),yy:{},symbols_:{error:2,start:3,journey:4,document:5,EOF:6,line:7,SPACE:8,statement:9,NEWLINE:10,title:11,acc_title:12,acc_title_value:13,acc_descr:14,acc_descr_value:15,acc_descr_multiline_value:16,section:17,taskName:18,taskData:19,$accept:0,$end:1},terminals_:{2:"error",4:"journey",6:"EOF",8:"SPACE",10:"NEWLINE",11:"title",12:"acc_title",13:"acc_title_value",14:"acc_descr",15:"acc_descr_value",16:"acc_descr_multiline_value",17:"section",18:"taskName",19:"taskData"},productions_:[0,[3,3],[5,0],[5,2],[7,2],[7,1],[7,1],[7,1],[9,1],[9,2],[9,2],[9,1],[9,1],[9,2]],performAction:i(function(r,a,l,y,f,o,S){var _=o.length-1;switch(f){case 1:return o[_-1];case 2:this.$=[];break;case 3:o[_-1].push(o[_]),this.$=o[_-1];break;case 4:case 5:this.$=o[_];break;case 6:case 7:this.$=[];break;case 8:y.setDiagramTitle(o[_].substr(6)),this.$=o[_].substr(6);break;case 9:this.$=o[_].trim(),y.setAccTitle(this.$);break;case 10:case 11:this.$=o[_].trim(),y.setAccDescription(this.$);break;case 12:y.addSection(o[_].substr(8)),this.$=o[_].substr(8);break;case 13:y.addTask(o[_-1],o[_]),this.$="task";break}},"anonymous"),table:[{3:1,4:[1,2]},{1:[3]},t(e,[2,2],{5:3}),{6:[1,4],7:5,8:[1,6],9:7,10:[1,8],11:n,12:c,14:s,16:u,17:h,18:p},t(e,[2,7],{1:[2,1]}),t(e,[2,3]),{9:15,11:n,12:c,14:s,16:u,17:h,18:p},t(e,[2,5]),t(e,[2,6]),t(e,[2,8]),{13:[1,16]},{15:[1,17]},t(e,[2,11]),t(e,[2,12]),{19:[1,18]},t(e,[2,4]),t(e,[2,9]),t(e,[2,10]),t(e,[2,13])],defaultActions:{},parseError:i(function(r,a){if(a.recoverable)this.trace(r);else{var l=new Error(r);throw l.hash=a,l}},"parseError"),parse:i(function(r){var a=this,l=[0],y=[],f=[null],o=[],S=this.table,_="",B=0,J=0,ut=2,K=1,yt=o.slice.call(arguments,1),k=Object.create(this.lexer),E={yy:{}};for(var O in this.yy)Object.prototype.hasOwnProperty.call(this.yy,O)&&(E.yy[O]=this.yy[O]);k.setInput(r,E.yy),E.yy.lexer=k,E.yy.parser=this,typeof k.yylloc>"u"&&(k.yylloc={});var Y=k.yylloc;o.push(Y);var dt=k.options&&k.options.ranges;typeof E.yy.parseError=="function"?this.parseError=E.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function pt(b){l.length=l.length-2*b,f.length=f.length-b,o.length=o.length-b}i(pt,"popStack");function Q(){var b;return b=y.pop()||k.lex()||K,typeof b!="number"&&(b instanceof Array&&(y=b,b=y.pop()),b=a.symbols_[b]||b),b}i(Q,"lex");for(var v,P,w,q,C={},j,M,D,N;;){if(P=l[l.length-1],this.defaultActions[P]?w=this.defaultActions[P]:((v===null||typeof v>"u")&&(v=Q()),w=S[P]&&S[P][v]),typeof w>"u"||!w.length||!w[0]){var G="";N=[];for(j in S[P])this.terminals_[j]&&j>ut&&N.push("'"+this.terminals_[j]+"'");k.showPosition?G="Parse error on line "+(B+1)+`:
                                      +import{d as ft,f as gt,g as at,b as mt}from"./chunk-AIUMCIBP-v8d5o65o.js";import{_ as i,d as A,q as xt,r as kt,s as _t,g as vt,c as bt,b as wt,t as Tt,j as W,k as St}from"./mermaid.core-D8igZDel.js";import{d as tt}from"./arc-9Itq1iXl.js";import"./app-D7uBbsY3.js";var H=function(){var t=i(function(g,r,a,l){for(a=a||{},l=g.length;l--;a[g[l]]=r);return a},"o"),e=[6,8,10,11,12,14,16,17,18],n=[1,9],c=[1,10],s=[1,11],u=[1,12],h=[1,13],p=[1,14],d={trace:i(function(){},"trace"),yy:{},symbols_:{error:2,start:3,journey:4,document:5,EOF:6,line:7,SPACE:8,statement:9,NEWLINE:10,title:11,acc_title:12,acc_title_value:13,acc_descr:14,acc_descr_value:15,acc_descr_multiline_value:16,section:17,taskName:18,taskData:19,$accept:0,$end:1},terminals_:{2:"error",4:"journey",6:"EOF",8:"SPACE",10:"NEWLINE",11:"title",12:"acc_title",13:"acc_title_value",14:"acc_descr",15:"acc_descr_value",16:"acc_descr_multiline_value",17:"section",18:"taskName",19:"taskData"},productions_:[0,[3,3],[5,0],[5,2],[7,2],[7,1],[7,1],[7,1],[9,1],[9,2],[9,2],[9,1],[9,1],[9,2]],performAction:i(function(r,a,l,y,f,o,S){var _=o.length-1;switch(f){case 1:return o[_-1];case 2:this.$=[];break;case 3:o[_-1].push(o[_]),this.$=o[_-1];break;case 4:case 5:this.$=o[_];break;case 6:case 7:this.$=[];break;case 8:y.setDiagramTitle(o[_].substr(6)),this.$=o[_].substr(6);break;case 9:this.$=o[_].trim(),y.setAccTitle(this.$);break;case 10:case 11:this.$=o[_].trim(),y.setAccDescription(this.$);break;case 12:y.addSection(o[_].substr(8)),this.$=o[_].substr(8);break;case 13:y.addTask(o[_-1],o[_]),this.$="task";break}},"anonymous"),table:[{3:1,4:[1,2]},{1:[3]},t(e,[2,2],{5:3}),{6:[1,4],7:5,8:[1,6],9:7,10:[1,8],11:n,12:c,14:s,16:u,17:h,18:p},t(e,[2,7],{1:[2,1]}),t(e,[2,3]),{9:15,11:n,12:c,14:s,16:u,17:h,18:p},t(e,[2,5]),t(e,[2,6]),t(e,[2,8]),{13:[1,16]},{15:[1,17]},t(e,[2,11]),t(e,[2,12]),{19:[1,18]},t(e,[2,4]),t(e,[2,9]),t(e,[2,10]),t(e,[2,13])],defaultActions:{},parseError:i(function(r,a){if(a.recoverable)this.trace(r);else{var l=new Error(r);throw l.hash=a,l}},"parseError"),parse:i(function(r){var a=this,l=[0],y=[],f=[null],o=[],S=this.table,_="",B=0,J=0,ut=2,K=1,yt=o.slice.call(arguments,1),k=Object.create(this.lexer),E={yy:{}};for(var O in this.yy)Object.prototype.hasOwnProperty.call(this.yy,O)&&(E.yy[O]=this.yy[O]);k.setInput(r,E.yy),E.yy.lexer=k,E.yy.parser=this,typeof k.yylloc>"u"&&(k.yylloc={});var Y=k.yylloc;o.push(Y);var dt=k.options&&k.options.ranges;typeof E.yy.parseError=="function"?this.parseError=E.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function pt(b){l.length=l.length-2*b,f.length=f.length-b,o.length=o.length-b}i(pt,"popStack");function Q(){var b;return b=y.pop()||k.lex()||K,typeof b!="number"&&(b instanceof Array&&(y=b,b=y.pop()),b=a.symbols_[b]||b),b}i(Q,"lex");for(var v,P,w,q,C={},j,M,D,N;;){if(P=l[l.length-1],this.defaultActions[P]?w=this.defaultActions[P]:((v===null||typeof v>"u")&&(v=Q()),w=S[P]&&S[P][v]),typeof w>"u"||!w.length||!w[0]){var G="";N=[];for(j in S[P])this.terminals_[j]&&j>ut&&N.push("'"+this.terminals_[j]+"'");k.showPosition?G="Parse error on line "+(B+1)+`:
                                       `+k.showPosition()+`
                                       Expecting `+N.join(", ")+", got '"+(this.terminals_[v]||v)+"'":G="Parse error on line "+(B+1)+": Unexpected "+(v==K?"end of input":"'"+(this.terminals_[v]||v)+"'"),this.parseError(G,{text:k.match,token:this.terminals_[v]||v,line:k.yylineno,loc:Y,expected:N})}if(w[0]instanceof Array&&w.length>1)throw new Error("Parse Error: multiple actions possible at state: "+P+", token: "+v);switch(w[0]){case 1:l.push(v),f.push(k.yytext),o.push(k.yylloc),l.push(w[1]),v=null,J=k.yyleng,_=k.yytext,B=k.yylineno,Y=k.yylloc;break;case 2:if(M=this.productions_[w[1]][1],C.$=f[f.length-M],C._$={first_line:o[o.length-(M||1)].first_line,last_line:o[o.length-1].last_line,first_column:o[o.length-(M||1)].first_column,last_column:o[o.length-1].last_column},dt&&(C._$.range=[o[o.length-(M||1)].range[0],o[o.length-1].range[1]]),q=this.performAction.apply(C,[_,J,B,E.yy,w[1],f,o].concat(yt)),typeof q<"u")return q;M&&(l=l.slice(0,-1*M*2),f=f.slice(0,-1*M),o=o.slice(0,-1*M)),l.push(this.productions_[w[1]][0]),f.push(C.$),o.push(C._$),D=S[l[l.length-2]][l[l.length-1]],l.push(D);break;case 3:return!0}}return!0},"parse")},x=function(){var g={EOF:1,parseError:i(function(a,l){if(this.yy.parser)this.yy.parser.parseError(a,l);else throw new Error(a)},"parseError"),setInput:i(function(r,a){return this.yy=a||this.yy||{},this._input=r,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},"setInput"),input:i(function(){var r=this._input[0];this.yytext+=r,this.yyleng++,this.offset++,this.match+=r,this.matched+=r;var a=r.match(/(?:\r\n?|\n).*/g);return a?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),r},"input"),unput:i(function(r){var a=r.length,l=r.split(/(?:\r\n?|\n)/g);this._input=r+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-a),this.offset-=a;var y=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),l.length-1&&(this.yylineno-=l.length-1);var f=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:l?(l.length===y.length?this.yylloc.first_column:0)+y[y.length-l.length].length-l[0].length:this.yylloc.first_column-a},this.options.ranges&&(this.yylloc.range=[f[0],f[0]+this.yyleng-a]),this.yyleng=this.yytext.length,this},"unput"),more:i(function(){return this._more=!0,this},"more"),reject:i(function(){if(this.options.backtrack_lexer)this._backtrack=!0;else return this.parseError("Lexical error on line "+(this.yylineno+1)+`. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).
                                       `+this.showPosition(),{text:"",token:null,line:this.yylineno});return this},"reject"),less:i(function(r){this.unput(this.match.slice(r))},"less"),pastInput:i(function(){var r=this.matched.substr(0,this.matched.length-this.match.length);return(r.length>20?"...":"")+r.substr(-20).replace(/\n/g,"")},"pastInput"),upcomingInput:i(function(){var r=this.match;return r.length<20&&(r+=this._input.substr(0,20-r.length)),(r.substr(0,20)+(r.length>20?"...":"")).replace(/\n/g,"")},"upcomingInput"),showPosition:i(function(){var r=this.pastInput(),a=new Array(r.length+1).join("-");return r+this.upcomingInput()+`
                                      diff --git a/assets/json-BFhFIfeY.js b/assets/json-31kD9U7J.js
                                      similarity index 68%
                                      rename from assets/json-BFhFIfeY.js
                                      rename to assets/json-31kD9U7J.js
                                      index 73388761ba..0fc5b63606 100644
                                      --- a/assets/json-BFhFIfeY.js
                                      +++ b/assets/json-31kD9U7J.js
                                      @@ -1 +1 @@
                                      -import"./graph-Oq3lz9SV.js";import{i as o}from"./baseUniq-ZJgB7efo.js";import{c as d}from"./clone-B3i2nD77.js";import{m as t}from"./basePickBy-BXIHjUx3.js";function v(e){var r={options:{directed:e.isDirected(),multigraph:e.isMultigraph(),compound:e.isCompound()},nodes:u(e),edges:p(e)};return o(e.graph())||(r.value=d(e.graph())),r}function u(e){return t(e.nodes(),function(r){var i=e.node(r),n=e.parent(r),a={v:r};return o(i)||(a.value=i),o(n)||(a.parent=n),a})}function p(e){return t(e.edges(),function(r){var i=e.edge(r),n={v:r.v,w:r.w};return o(r.name)||(n.name=r.name),o(i)||(n.value=i),n})}export{v as w};
                                      +import"./graph-Cjb-DGHB.js";import{i as o}from"./baseUniq-D0lZO5yp.js";import{c as d}from"./clone-DWnk59eF.js";import{m as t}from"./basePickBy-DpnmgMOi.js";function v(e){var r={options:{directed:e.isDirected(),multigraph:e.isMultigraph(),compound:e.isCompound()},nodes:u(e),edges:p(e)};return o(e.graph())||(r.value=d(e.graph())),r}function u(e){return t(e.nodes(),function(r){var i=e.node(r),n=e.parent(r),a={v:r};return o(i)||(a.value=i),o(n)||(a.parent=n),a})}function p(e){return t(e.edges(),function(r){var i=e.edge(r),n={v:r.v,w:r.w};return o(r.name)||(n.name=r.name),o(i)||(n.value=i),n})}export{v as w};
                                      diff --git a/assets/layout-7AWYeW5Q.js b/assets/layout-CHeuV-iP.js
                                      similarity index 99%
                                      rename from assets/layout-7AWYeW5Q.js
                                      rename to assets/layout-CHeuV-iP.js
                                      index d87a4251d1..8eeb0abded 100644
                                      --- a/assets/layout-7AWYeW5Q.js
                                      +++ b/assets/layout-CHeuV-iP.js
                                      @@ -1 +1 @@
                                      -import{G as k}from"./graph-Oq3lz9SV.js";import{b as Pn,p as ln,q as vn,g as X,e as en,m as A,o as Sn,s as On,c as Fn,u as Vn,d as s,h as m,i as g,f as I,v as y,r as O}from"./baseUniq-ZJgB7efo.js";import{f as N,b as pn,a as An,c as Bn,d as Gn,t as B,m as w,e as R,g as U,l as P,h as Yn}from"./basePickBy-BXIHjUx3.js";import{b1 as Dn,b2 as qn,b3 as $n,aJ as Wn,b4 as jn,aN as mn,aM as wn,b5 as zn,aI as W,ay as Xn,aP as Un,aA as Hn,b6 as j}from"./mermaid.core-DapiNGBY.js";function Jn(n){return Dn(qn(n,void 0,N),n+"")}var Zn=1,Kn=4;function Qn(n){return Pn(n,Zn|Kn)}function ne(n,e){return n==null?n:$n(n,ln(e),Wn)}function ee(n,e){return n&&vn(n,ln(e))}function re(n,e){return n>e}function F(n,e){var r={};return e=X(e),vn(n,function(i,t,a){jn(r,t,e(i,t,a))}),r}function x(n){return n&&n.length?pn(n,mn,re):void 0}function H(n,e){return n&&n.length?pn(n,X(e),An):void 0}function ie(n,e){var r=n.length;for(n.sort(e);r--;)n[r]=n[r].value;return n}function te(n,e){if(n!==e){var r=n!==void 0,i=n===null,t=n===n,a=en(n),o=e!==void 0,u=e===null,d=e===e,f=en(e);if(!u&&!f&&!a&&n>e||a&&o&&d&&!u&&!f||i&&o&&d||!r&&d||!t)return 1;if(!i&&!a&&!f&&n=u)return d;var f=r[i];return d*(f=="desc"?-1:1)}}return n.index-e.index}function oe(n,e,r){e.length?e=A(e,function(a){return wn(a)?function(o){return Sn(o,a.length===1?a[0]:a)}:a}):e=[mn];var i=-1;e=A(e,zn(X));var t=Bn(n,function(a,o,u){var d=A(e,function(f){return f(a)});return{criteria:d,index:++i,value:a}});return ie(t,function(a,o){return ae(a,o,r)})}function ue(n,e){return Gn(n,e,function(r,i){return On(n,i)})}var S=Jn(function(n,e){return n==null?{}:ue(n,e)}),de=Math.ceil,fe=Math.max;function se(n,e,r,i){for(var t=-1,a=fe(de((e-n)/(r||1)),0),o=Array(a);a--;)o[++t]=n,n+=r;return o}function ce(n){return function(e,r,i){return i&&typeof i!="number"&&W(e,r,i)&&(r=i=void 0),e=B(e),r===void 0?(r=e,e=0):r=B(r),i=i===void 0?e1&&W(n,e[0],e[1])?e=[]:r>2&&W(e[0],e[1],e[2])&&(e=[e[0]]),oe(n,Fn(e),[])}),he=0;function J(n){var e=++he;return Vn(n)+e}function le(n,e,r){for(var i=-1,t=n.length,a=e.length,o={};++i0;--u)if(o=e[u].dequeue(),o){i=i.concat(G(n,e,r,o,!0));break}}}return i}function G(n,e,r,i,t){var a=t?[]:void 0;return s(n.inEdges(i.v),function(o){var u=n.edge(o),d=n.node(o.v);t&&a.push({v:o.v,w:o.w}),d.out-=u,z(e,r,d)}),s(n.outEdges(i.v),function(o){var u=n.edge(o),d=o.w,f=n.node(d);f.in-=u,z(e,r,f)}),n.removeNode(i.v),a}function ke(n,e){var r=new k,i=0,t=0;s(n.nodes(),function(u){r.setNode(u,{v:u,in:0,out:0})}),s(n.edges(),function(u){var d=r.edge(u.v,u.w)||0,f=e(u),c=d+f;r.setEdge(u.v,u.w,c),t=Math.max(t,r.node(u.v).out+=f),i=Math.max(i,r.node(u.w).in+=f)});var a=L(t+i+3).map(function(){return new pe}),o=i+1;return s(r.nodes(),function(u){z(a,o,r.node(u))}),{graph:r,buckets:a,zeroIdx:o}}function z(n,e,r){r.out?r.in?n[r.out-r.in+e].enqueue(r):n[n.length-1].enqueue(r):n[0].enqueue(r)}function xe(n){var e=n.graph().acyclicer==="greedy"?be(n,r(n)):Ee(n);s(e,function(i){var t=n.edge(i);n.removeEdge(i),t.forwardName=i.name,t.reversed=!0,n.setEdge(i.w,i.v,t,J("rev"))});function r(i){return function(t){return i.edge(t).weight}}}function Ee(n){var e=[],r={},i={};function t(a){m(i,a)||(i[a]=!0,r[a]=!0,s(n.outEdges(a),function(o){m(r,o.w)?e.push(o):t(o.w)}),delete r[a])}return s(n.nodes(),t),e}function ye(n){s(n.edges(),function(e){var r=n.edge(e);if(r.reversed){n.removeEdge(e);var i=r.forwardName;delete r.reversed,delete r.forwardName,n.setEdge(e.w,e.v,r,i)}})}function C(n,e,r,i){var t;do t=J(i);while(n.hasNode(t));return r.dummy=e,n.setNode(t,r),t}function Le(n){var e=new k().setGraph(n.graph());return s(n.nodes(),function(r){e.setNode(r,n.node(r))}),s(n.edges(),function(r){var i=e.edge(r.v,r.w)||{weight:0,minlen:1},t=n.edge(r);e.setEdge(r.v,r.w,{weight:i.weight+t.weight,minlen:Math.max(i.minlen,t.minlen)})}),e}function bn(n){var e=new k({multigraph:n.isMultigraph()}).setGraph(n.graph());return s(n.nodes(),function(r){n.children(r).length||e.setNode(r,n.node(r))}),s(n.edges(),function(r){e.setEdge(r,n.edge(r))}),e}function tn(n,e){var r=n.x,i=n.y,t=e.x-r,a=e.y-i,o=n.width/2,u=n.height/2;if(!t&&!a)throw new Error("Not possible to find intersection inside of the rectangle");var d,f;return Math.abs(a)*o>Math.abs(t)*u?(a<0&&(u=-u),d=u*t/a,f=u):(t<0&&(o=-o),d=o,f=o*a/t),{x:r+d,y:i+f}}function V(n){var e=w(L(gn(n)+1),function(){return[]});return s(n.nodes(),function(r){var i=n.node(r),t=i.rank;g(t)||(e[t][i.order]=r)}),e}function Ne(n){var e=R(w(n.nodes(),function(r){return n.node(r).rank}));s(n.nodes(),function(r){var i=n.node(r);m(i,"rank")&&(i.rank-=e)})}function Ce(n){var e=R(w(n.nodes(),function(a){return n.node(a).rank})),r=[];s(n.nodes(),function(a){var o=n.node(a).rank-e;r[o]||(r[o]=[]),r[o].push(a)});var i=0,t=n.graph().nodeRankFactor;s(r,function(a,o){g(a)&&o%t!==0?--i:i&&s(a,function(u){n.node(u).rank+=i})})}function an(n,e,r,i){var t={width:0,height:0};return arguments.length>=4&&(t.rank=r,t.order=i),C(n,"border",t,e)}function gn(n){return x(w(n.nodes(),function(e){var r=n.node(e).rank;if(!g(r))return r}))}function _e(n,e){var r={lhs:[],rhs:[]};return s(n,function(i){e(i)?r.lhs.push(i):r.rhs.push(i)}),r}function Re(n,e){return e()}function Te(n){function e(r){var i=n.children(r),t=n.node(r);if(i.length&&s(i,e),m(t,"minRank")){t.borderLeft=[],t.borderRight=[];for(var a=t.minRank,o=t.maxRank+1;ao.lim&&(u=o,d=!0);var f=I(e.edges(),function(c){return d===dn(n,n.node(c.v),u)&&d!==dn(n,n.node(c.w),u)});return H(f,function(c){return T(e,c)})}function Rn(n,e,r,i){var t=r.v,a=r.w;n.removeEdge(t,a),n.setEdge(i.v,i.w,{}),Q(n),K(n,e),We(n,e)}function We(n,e){var r=U(n.nodes(),function(t){return!e.node(t).parent}),i=qe(n,r);i=i.slice(1),s(i,function(t){var a=n.node(t).parent,o=e.edge(t,a),u=!1;o||(o=e.edge(a,t),u=!0),e.node(t).rank=e.node(a).rank+(u?o.minlen:-o.minlen)})}function je(n,e,r){return n.hasEdge(e,r)}function dn(n,e,r){return r.low<=e.lim&&e.lim<=r.lim}function ze(n){switch(n.graph().ranker){case"network-simplex":fn(n);break;case"tight-tree":Ue(n);break;case"longest-path":Xe(n);break;default:fn(n)}}var Xe=Z;function Ue(n){Z(n),xn(n)}function fn(n){E(n)}function He(n){var e=C(n,"root",{},"_root"),r=Je(n),i=x(y(r))-1,t=2*i+1;n.graph().nestingRoot=e,s(n.edges(),function(o){n.edge(o).minlen*=t});var a=Ze(n)+1;s(n.children(),function(o){Tn(n,e,t,a,i,r,o)}),n.graph().nodeRankFactor=t}function Tn(n,e,r,i,t,a,o){var u=n.children(o);if(!u.length){o!==e&&n.setEdge(e,o,{weight:0,minlen:r});return}var d=an(n,"_bt"),f=an(n,"_bb"),c=n.node(o);n.setParent(d,o),c.borderTop=d,n.setParent(f,o),c.borderBottom=f,s(u,function(h){Tn(n,e,r,i,t,a,h);var l=n.node(h),v=l.borderTop?l.borderTop:h,p=l.borderBottom?l.borderBottom:h,b=l.borderTop?i:2*i,_=v!==p?1:t-a[o]+1;n.setEdge(d,v,{weight:b,minlen:_,nestingEdge:!0}),n.setEdge(p,f,{weight:b,minlen:_,nestingEdge:!0})}),n.parent(o)||n.setEdge(e,d,{weight:0,minlen:t+a[o]})}function Je(n){var e={};function r(i,t){var a=n.children(i);a&&a.length&&s(a,function(o){r(o,t+1)}),e[i]=t}return s(n.children(),function(i){r(i,1)}),e}function Ze(n){return O(n.edges(),function(e,r){return e+n.edge(r).weight},0)}function Ke(n){var e=n.graph();n.removeNode(e.nestingRoot),delete e.nestingRoot,s(n.edges(),function(r){var i=n.edge(r);i.nestingEdge&&n.removeEdge(r)})}function Qe(n,e,r){var i={},t;s(r,function(a){for(var o=n.parent(a),u,d;o;){if(u=n.parent(o),u?(d=i[u],i[u]=o):(d=t,t=o),d&&d!==o){e.setEdge(d,o);return}o=u}})}function nr(n,e,r){var i=er(n),t=new k({compound:!0}).setGraph({root:i}).setDefaultNodeLabel(function(a){return n.node(a)});return s(n.nodes(),function(a){var o=n.node(a),u=n.parent(a);(o.rank===e||o.minRank<=e&&e<=o.maxRank)&&(t.setNode(a),t.setParent(a,u||i),s(n[r](a),function(d){var f=d.v===a?d.w:d.v,c=t.edge(f,a),h=g(c)?0:c.weight;t.setEdge(f,a,{weight:n.edge(d).weight+h})}),m(o,"minRank")&&t.setNode(a,{borderLeft:o.borderLeft[e],borderRight:o.borderRight[e]}))}),t}function er(n){for(var e;n.hasNode(e=J("_root")););return e}function rr(n,e){for(var r=0,i=1;i0;)c%2&&(h+=u[c+1]),c=c-1>>1,u[c]+=f.weight;d+=f.weight*h})),d}function tr(n){var e={},r=I(n.nodes(),function(u){return!n.children(u).length}),i=x(w(r,function(u){return n.node(u).rank})),t=w(L(i+1),function(){return[]});function a(u){if(!m(e,u)){e[u]=!0;var d=n.node(u);t[d.rank].push(u),s(n.successors(u),a)}}var o=M(r,function(u){return n.node(u).rank});return s(o,a),t}function ar(n,e){return w(e,function(r){var i=n.inEdges(r);if(i.length){var t=O(i,function(a,o){var u=n.edge(o),d=n.node(o.v);return{sum:a.sum+u.weight*d.order,weight:a.weight+u.weight}},{sum:0,weight:0});return{v:r,barycenter:t.sum/t.weight,weight:t.weight}}else return{v:r}})}function or(n,e){var r={};s(n,function(t,a){var o=r[t.v]={indegree:0,in:[],out:[],vs:[t.v],i:a};g(t.barycenter)||(o.barycenter=t.barycenter,o.weight=t.weight)}),s(e.edges(),function(t){var a=r[t.v],o=r[t.w];!g(a)&&!g(o)&&(o.indegree++,a.out.push(r[t.w]))});var i=I(r,function(t){return!t.indegree});return ur(i)}function ur(n){var e=[];function r(a){return function(o){o.merged||(g(o.barycenter)||g(a.barycenter)||o.barycenter>=a.barycenter)&&dr(a,o)}}function i(a){return function(o){o.in.push(a),--o.indegree===0&&n.push(o)}}for(;n.length;){var t=n.pop();e.push(t),s(t.in.reverse(),r(t)),s(t.out,i(t))}return w(I(e,function(a){return!a.merged}),function(a){return S(a,["vs","i","barycenter","weight"])})}function dr(n,e){var r=0,i=0;n.weight&&(r+=n.barycenter*n.weight,i+=n.weight),e.weight&&(r+=e.barycenter*e.weight,i+=e.weight),n.vs=e.vs.concat(n.vs),n.barycenter=r/i,n.weight=i,n.i=Math.min(e.i,n.i),e.merged=!0}function fr(n,e){var r=_e(n,function(c){return m(c,"barycenter")}),i=r.lhs,t=M(r.rhs,function(c){return-c.i}),a=[],o=0,u=0,d=0;i.sort(sr(!!e)),d=sn(a,t,d),s(i,function(c){d+=c.vs.length,a.push(c.vs),o+=c.barycenter*c.weight,u+=c.weight,d=sn(a,t,d)});var f={vs:N(a)};return u&&(f.barycenter=o/u,f.weight=u),f}function sn(n,e,r){for(var i;e.length&&(i=P(e)).i<=r;)e.pop(),n.push(i.vs),r++;return r}function sr(n){return function(e,r){return e.barycenterr.barycenter?1:n?r.i-e.i:e.i-r.i}}function In(n,e,r,i){var t=n.children(e),a=n.node(e),o=a?a.borderLeft:void 0,u=a?a.borderRight:void 0,d={};o&&(t=I(t,function(p){return p!==o&&p!==u}));var f=ar(n,t);s(f,function(p){if(n.children(p.v).length){var b=In(n,p.v,r,i);d[p.v]=b,m(b,"barycenter")&&hr(p,b)}});var c=or(f,r);cr(c,d);var h=fr(c,i);if(o&&(h.vs=N([o,h.vs,u]),n.predecessors(o).length)){var l=n.node(n.predecessors(o)[0]),v=n.node(n.predecessors(u)[0]);m(h,"barycenter")||(h.barycenter=0,h.weight=0),h.barycenter=(h.barycenter*h.weight+l.order+v.order)/(h.weight+2),h.weight+=2}return h}function cr(n,e){s(n,function(r){r.vs=N(r.vs.map(function(i){return e[i]?e[i].vs:i}))})}function hr(n,e){g(n.barycenter)?(n.barycenter=e.barycenter,n.weight=e.weight):(n.barycenter=(n.barycenter*n.weight+e.barycenter*e.weight)/(n.weight+e.weight),n.weight+=e.weight)}function lr(n){var e=gn(n),r=cn(n,L(1,e+1),"inEdges"),i=cn(n,L(e-1,-1,-1),"outEdges"),t=tr(n);hn(n,t);for(var a=Number.POSITIVE_INFINITY,o,u=0,d=0;d<4;++u,++d){vr(u%2?r:i,u%4>=2),t=V(n);var f=rr(n,t);fo||u>e[d].lim));for(f=d,d=i;(d=n.parent(d))!==f;)a.push(d);return{path:t.concat(a.reverse()),lca:f}}function wr(n){var e={},r=0;function i(t){var a=r;s(n.children(t),i),e[t]={low:a,lim:r++}}return s(n.children(),i),e}function br(n,e){var r={};function i(t,a){var o=0,u=0,d=t.length,f=P(a);return s(a,function(c,h){var l=kr(n,c),v=l?n.node(l).order:d;(l||c===f)&&(s(a.slice(u,h+1),function(p){s(n.predecessors(p),function(b){var _=n.node(b),nn=_.order;(nnf)&&Mn(r,l,c)})})}function t(a,o){var u=-1,d,f=0;return s(o,function(c,h){if(n.node(c).dummy==="border"){var l=n.predecessors(c);l.length&&(d=n.node(l[0]).order,i(o,f,h,u,d),f=h,u=d)}i(o,f,o.length,d,a.length)}),o}return O(e,t),r}function kr(n,e){if(n.node(e).dummy)return U(n.predecessors(e),function(r){return n.node(r).dummy})}function Mn(n,e,r){if(e>r){var i=e;e=r,r=i}var t=n[e];t||(n[e]=t={}),t[r]=!0}function xr(n,e,r){if(e>r){var i=e;e=r,r=i}return m(n[e],r)}function Er(n,e,r,i){var t={},a={},o={};return s(e,function(u){s(u,function(d,f){t[d]=d,a[d]=d,o[d]=f})}),s(e,function(u){var d=-1;s(u,function(f){var c=i(f);if(c.length){c=M(c,function(b){return o[b]});for(var h=(c.length-1)/2,l=Math.floor(h),v=Math.ceil(h);l<=v;++l){var p=c[l];a[f]===f&&de}function F(n,e){var r={};return e=X(e),vn(n,function(i,t,a){jn(r,t,e(i,t,a))}),r}function x(n){return n&&n.length?pn(n,mn,re):void 0}function H(n,e){return n&&n.length?pn(n,X(e),An):void 0}function ie(n,e){var r=n.length;for(n.sort(e);r--;)n[r]=n[r].value;return n}function te(n,e){if(n!==e){var r=n!==void 0,i=n===null,t=n===n,a=en(n),o=e!==void 0,u=e===null,d=e===e,f=en(e);if(!u&&!f&&!a&&n>e||a&&o&&d&&!u&&!f||i&&o&&d||!r&&d||!t)return 1;if(!i&&!a&&!f&&n=u)return d;var f=r[i];return d*(f=="desc"?-1:1)}}return n.index-e.index}function oe(n,e,r){e.length?e=A(e,function(a){return wn(a)?function(o){return Sn(o,a.length===1?a[0]:a)}:a}):e=[mn];var i=-1;e=A(e,zn(X));var t=Bn(n,function(a,o,u){var d=A(e,function(f){return f(a)});return{criteria:d,index:++i,value:a}});return ie(t,function(a,o){return ae(a,o,r)})}function ue(n,e){return Gn(n,e,function(r,i){return On(n,i)})}var S=Jn(function(n,e){return n==null?{}:ue(n,e)}),de=Math.ceil,fe=Math.max;function se(n,e,r,i){for(var t=-1,a=fe(de((e-n)/(r||1)),0),o=Array(a);a--;)o[++t]=n,n+=r;return o}function ce(n){return function(e,r,i){return i&&typeof i!="number"&&W(e,r,i)&&(r=i=void 0),e=B(e),r===void 0?(r=e,e=0):r=B(r),i=i===void 0?e1&&W(n,e[0],e[1])?e=[]:r>2&&W(e[0],e[1],e[2])&&(e=[e[0]]),oe(n,Fn(e),[])}),he=0;function J(n){var e=++he;return Vn(n)+e}function le(n,e,r){for(var i=-1,t=n.length,a=e.length,o={};++i0;--u)if(o=e[u].dequeue(),o){i=i.concat(G(n,e,r,o,!0));break}}}return i}function G(n,e,r,i,t){var a=t?[]:void 0;return s(n.inEdges(i.v),function(o){var u=n.edge(o),d=n.node(o.v);t&&a.push({v:o.v,w:o.w}),d.out-=u,z(e,r,d)}),s(n.outEdges(i.v),function(o){var u=n.edge(o),d=o.w,f=n.node(d);f.in-=u,z(e,r,f)}),n.removeNode(i.v),a}function ke(n,e){var r=new k,i=0,t=0;s(n.nodes(),function(u){r.setNode(u,{v:u,in:0,out:0})}),s(n.edges(),function(u){var d=r.edge(u.v,u.w)||0,f=e(u),c=d+f;r.setEdge(u.v,u.w,c),t=Math.max(t,r.node(u.v).out+=f),i=Math.max(i,r.node(u.w).in+=f)});var a=L(t+i+3).map(function(){return new pe}),o=i+1;return s(r.nodes(),function(u){z(a,o,r.node(u))}),{graph:r,buckets:a,zeroIdx:o}}function z(n,e,r){r.out?r.in?n[r.out-r.in+e].enqueue(r):n[n.length-1].enqueue(r):n[0].enqueue(r)}function xe(n){var e=n.graph().acyclicer==="greedy"?be(n,r(n)):Ee(n);s(e,function(i){var t=n.edge(i);n.removeEdge(i),t.forwardName=i.name,t.reversed=!0,n.setEdge(i.w,i.v,t,J("rev"))});function r(i){return function(t){return i.edge(t).weight}}}function Ee(n){var e=[],r={},i={};function t(a){m(i,a)||(i[a]=!0,r[a]=!0,s(n.outEdges(a),function(o){m(r,o.w)?e.push(o):t(o.w)}),delete r[a])}return s(n.nodes(),t),e}function ye(n){s(n.edges(),function(e){var r=n.edge(e);if(r.reversed){n.removeEdge(e);var i=r.forwardName;delete r.reversed,delete r.forwardName,n.setEdge(e.w,e.v,r,i)}})}function C(n,e,r,i){var t;do t=J(i);while(n.hasNode(t));return r.dummy=e,n.setNode(t,r),t}function Le(n){var e=new k().setGraph(n.graph());return s(n.nodes(),function(r){e.setNode(r,n.node(r))}),s(n.edges(),function(r){var i=e.edge(r.v,r.w)||{weight:0,minlen:1},t=n.edge(r);e.setEdge(r.v,r.w,{weight:i.weight+t.weight,minlen:Math.max(i.minlen,t.minlen)})}),e}function bn(n){var e=new k({multigraph:n.isMultigraph()}).setGraph(n.graph());return s(n.nodes(),function(r){n.children(r).length||e.setNode(r,n.node(r))}),s(n.edges(),function(r){e.setEdge(r,n.edge(r))}),e}function tn(n,e){var r=n.x,i=n.y,t=e.x-r,a=e.y-i,o=n.width/2,u=n.height/2;if(!t&&!a)throw new Error("Not possible to find intersection inside of the rectangle");var d,f;return Math.abs(a)*o>Math.abs(t)*u?(a<0&&(u=-u),d=u*t/a,f=u):(t<0&&(o=-o),d=o,f=o*a/t),{x:r+d,y:i+f}}function V(n){var e=w(L(gn(n)+1),function(){return[]});return s(n.nodes(),function(r){var i=n.node(r),t=i.rank;g(t)||(e[t][i.order]=r)}),e}function Ne(n){var e=R(w(n.nodes(),function(r){return n.node(r).rank}));s(n.nodes(),function(r){var i=n.node(r);m(i,"rank")&&(i.rank-=e)})}function Ce(n){var e=R(w(n.nodes(),function(a){return n.node(a).rank})),r=[];s(n.nodes(),function(a){var o=n.node(a).rank-e;r[o]||(r[o]=[]),r[o].push(a)});var i=0,t=n.graph().nodeRankFactor;s(r,function(a,o){g(a)&&o%t!==0?--i:i&&s(a,function(u){n.node(u).rank+=i})})}function an(n,e,r,i){var t={width:0,height:0};return arguments.length>=4&&(t.rank=r,t.order=i),C(n,"border",t,e)}function gn(n){return x(w(n.nodes(),function(e){var r=n.node(e).rank;if(!g(r))return r}))}function _e(n,e){var r={lhs:[],rhs:[]};return s(n,function(i){e(i)?r.lhs.push(i):r.rhs.push(i)}),r}function Re(n,e){return e()}function Te(n){function e(r){var i=n.children(r),t=n.node(r);if(i.length&&s(i,e),m(t,"minRank")){t.borderLeft=[],t.borderRight=[];for(var a=t.minRank,o=t.maxRank+1;ao.lim&&(u=o,d=!0);var f=I(e.edges(),function(c){return d===dn(n,n.node(c.v),u)&&d!==dn(n,n.node(c.w),u)});return H(f,function(c){return T(e,c)})}function Rn(n,e,r,i){var t=r.v,a=r.w;n.removeEdge(t,a),n.setEdge(i.v,i.w,{}),Q(n),K(n,e),We(n,e)}function We(n,e){var r=U(n.nodes(),function(t){return!e.node(t).parent}),i=qe(n,r);i=i.slice(1),s(i,function(t){var a=n.node(t).parent,o=e.edge(t,a),u=!1;o||(o=e.edge(a,t),u=!0),e.node(t).rank=e.node(a).rank+(u?o.minlen:-o.minlen)})}function je(n,e,r){return n.hasEdge(e,r)}function dn(n,e,r){return r.low<=e.lim&&e.lim<=r.lim}function ze(n){switch(n.graph().ranker){case"network-simplex":fn(n);break;case"tight-tree":Ue(n);break;case"longest-path":Xe(n);break;default:fn(n)}}var Xe=Z;function Ue(n){Z(n),xn(n)}function fn(n){E(n)}function He(n){var e=C(n,"root",{},"_root"),r=Je(n),i=x(y(r))-1,t=2*i+1;n.graph().nestingRoot=e,s(n.edges(),function(o){n.edge(o).minlen*=t});var a=Ze(n)+1;s(n.children(),function(o){Tn(n,e,t,a,i,r,o)}),n.graph().nodeRankFactor=t}function Tn(n,e,r,i,t,a,o){var u=n.children(o);if(!u.length){o!==e&&n.setEdge(e,o,{weight:0,minlen:r});return}var d=an(n,"_bt"),f=an(n,"_bb"),c=n.node(o);n.setParent(d,o),c.borderTop=d,n.setParent(f,o),c.borderBottom=f,s(u,function(h){Tn(n,e,r,i,t,a,h);var l=n.node(h),v=l.borderTop?l.borderTop:h,p=l.borderBottom?l.borderBottom:h,b=l.borderTop?i:2*i,_=v!==p?1:t-a[o]+1;n.setEdge(d,v,{weight:b,minlen:_,nestingEdge:!0}),n.setEdge(p,f,{weight:b,minlen:_,nestingEdge:!0})}),n.parent(o)||n.setEdge(e,d,{weight:0,minlen:t+a[o]})}function Je(n){var e={};function r(i,t){var a=n.children(i);a&&a.length&&s(a,function(o){r(o,t+1)}),e[i]=t}return s(n.children(),function(i){r(i,1)}),e}function Ze(n){return O(n.edges(),function(e,r){return e+n.edge(r).weight},0)}function Ke(n){var e=n.graph();n.removeNode(e.nestingRoot),delete e.nestingRoot,s(n.edges(),function(r){var i=n.edge(r);i.nestingEdge&&n.removeEdge(r)})}function Qe(n,e,r){var i={},t;s(r,function(a){for(var o=n.parent(a),u,d;o;){if(u=n.parent(o),u?(d=i[u],i[u]=o):(d=t,t=o),d&&d!==o){e.setEdge(d,o);return}o=u}})}function nr(n,e,r){var i=er(n),t=new k({compound:!0}).setGraph({root:i}).setDefaultNodeLabel(function(a){return n.node(a)});return s(n.nodes(),function(a){var o=n.node(a),u=n.parent(a);(o.rank===e||o.minRank<=e&&e<=o.maxRank)&&(t.setNode(a),t.setParent(a,u||i),s(n[r](a),function(d){var f=d.v===a?d.w:d.v,c=t.edge(f,a),h=g(c)?0:c.weight;t.setEdge(f,a,{weight:n.edge(d).weight+h})}),m(o,"minRank")&&t.setNode(a,{borderLeft:o.borderLeft[e],borderRight:o.borderRight[e]}))}),t}function er(n){for(var e;n.hasNode(e=J("_root")););return e}function rr(n,e){for(var r=0,i=1;i0;)c%2&&(h+=u[c+1]),c=c-1>>1,u[c]+=f.weight;d+=f.weight*h})),d}function tr(n){var e={},r=I(n.nodes(),function(u){return!n.children(u).length}),i=x(w(r,function(u){return n.node(u).rank})),t=w(L(i+1),function(){return[]});function a(u){if(!m(e,u)){e[u]=!0;var d=n.node(u);t[d.rank].push(u),s(n.successors(u),a)}}var o=M(r,function(u){return n.node(u).rank});return s(o,a),t}function ar(n,e){return w(e,function(r){var i=n.inEdges(r);if(i.length){var t=O(i,function(a,o){var u=n.edge(o),d=n.node(o.v);return{sum:a.sum+u.weight*d.order,weight:a.weight+u.weight}},{sum:0,weight:0});return{v:r,barycenter:t.sum/t.weight,weight:t.weight}}else return{v:r}})}function or(n,e){var r={};s(n,function(t,a){var o=r[t.v]={indegree:0,in:[],out:[],vs:[t.v],i:a};g(t.barycenter)||(o.barycenter=t.barycenter,o.weight=t.weight)}),s(e.edges(),function(t){var a=r[t.v],o=r[t.w];!g(a)&&!g(o)&&(o.indegree++,a.out.push(r[t.w]))});var i=I(r,function(t){return!t.indegree});return ur(i)}function ur(n){var e=[];function r(a){return function(o){o.merged||(g(o.barycenter)||g(a.barycenter)||o.barycenter>=a.barycenter)&&dr(a,o)}}function i(a){return function(o){o.in.push(a),--o.indegree===0&&n.push(o)}}for(;n.length;){var t=n.pop();e.push(t),s(t.in.reverse(),r(t)),s(t.out,i(t))}return w(I(e,function(a){return!a.merged}),function(a){return S(a,["vs","i","barycenter","weight"])})}function dr(n,e){var r=0,i=0;n.weight&&(r+=n.barycenter*n.weight,i+=n.weight),e.weight&&(r+=e.barycenter*e.weight,i+=e.weight),n.vs=e.vs.concat(n.vs),n.barycenter=r/i,n.weight=i,n.i=Math.min(e.i,n.i),e.merged=!0}function fr(n,e){var r=_e(n,function(c){return m(c,"barycenter")}),i=r.lhs,t=M(r.rhs,function(c){return-c.i}),a=[],o=0,u=0,d=0;i.sort(sr(!!e)),d=sn(a,t,d),s(i,function(c){d+=c.vs.length,a.push(c.vs),o+=c.barycenter*c.weight,u+=c.weight,d=sn(a,t,d)});var f={vs:N(a)};return u&&(f.barycenter=o/u,f.weight=u),f}function sn(n,e,r){for(var i;e.length&&(i=P(e)).i<=r;)e.pop(),n.push(i.vs),r++;return r}function sr(n){return function(e,r){return e.barycenterr.barycenter?1:n?r.i-e.i:e.i-r.i}}function In(n,e,r,i){var t=n.children(e),a=n.node(e),o=a?a.borderLeft:void 0,u=a?a.borderRight:void 0,d={};o&&(t=I(t,function(p){return p!==o&&p!==u}));var f=ar(n,t);s(f,function(p){if(n.children(p.v).length){var b=In(n,p.v,r,i);d[p.v]=b,m(b,"barycenter")&&hr(p,b)}});var c=or(f,r);cr(c,d);var h=fr(c,i);if(o&&(h.vs=N([o,h.vs,u]),n.predecessors(o).length)){var l=n.node(n.predecessors(o)[0]),v=n.node(n.predecessors(u)[0]);m(h,"barycenter")||(h.barycenter=0,h.weight=0),h.barycenter=(h.barycenter*h.weight+l.order+v.order)/(h.weight+2),h.weight+=2}return h}function cr(n,e){s(n,function(r){r.vs=N(r.vs.map(function(i){return e[i]?e[i].vs:i}))})}function hr(n,e){g(n.barycenter)?(n.barycenter=e.barycenter,n.weight=e.weight):(n.barycenter=(n.barycenter*n.weight+e.barycenter*e.weight)/(n.weight+e.weight),n.weight+=e.weight)}function lr(n){var e=gn(n),r=cn(n,L(1,e+1),"inEdges"),i=cn(n,L(e-1,-1,-1),"outEdges"),t=tr(n);hn(n,t);for(var a=Number.POSITIVE_INFINITY,o,u=0,d=0;d<4;++u,++d){vr(u%2?r:i,u%4>=2),t=V(n);var f=rr(n,t);fo||u>e[d].lim));for(f=d,d=i;(d=n.parent(d))!==f;)a.push(d);return{path:t.concat(a.reverse()),lca:f}}function wr(n){var e={},r=0;function i(t){var a=r;s(n.children(t),i),e[t]={low:a,lim:r++}}return s(n.children(),i),e}function br(n,e){var r={};function i(t,a){var o=0,u=0,d=t.length,f=P(a);return s(a,function(c,h){var l=kr(n,c),v=l?n.node(l).order:d;(l||c===f)&&(s(a.slice(u,h+1),function(p){s(n.predecessors(p),function(b){var _=n.node(b),nn=_.order;(nnf)&&Mn(r,l,c)})})}function t(a,o){var u=-1,d,f=0;return s(o,function(c,h){if(n.node(c).dummy==="border"){var l=n.predecessors(c);l.length&&(d=n.node(l[0]).order,i(o,f,h,u,d),f=h,u=d)}i(o,f,o.length,d,a.length)}),o}return O(e,t),r}function kr(n,e){if(n.node(e).dummy)return U(n.predecessors(e),function(r){return n.node(r).dummy})}function Mn(n,e,r){if(e>r){var i=e;e=r,r=i}var t=n[e];t||(n[e]=t={}),t[r]=!0}function xr(n,e,r){if(e>r){var i=e;e=r,r=i}return m(n[e],r)}function Er(n,e,r,i){var t={},a={},o={};return s(e,function(u){s(u,function(d,f){t[d]=d,a[d]=d,o[d]=f})}),s(e,function(u){var d=-1;s(u,function(f){var c=i(f);if(c.length){c=M(c,function(b){return o[b]});for(var h=(c.length-1)/2,l=Math.floor(h),v=Math.ceil(h);l<=v;++l){var p=c[l];a[f]===f&&dt?1:n>=t?0:NaN}function hn(n,t){return n==null||t==null?NaN:tn?1:t>=n?0:NaN}function W(n){let t,e,r;n.length!==2?(t=F,e=(u,c)=>F(n(u),c),r=(u,c)=>n(u)-c):(t=n===F||n===hn?n:mn,e=n,r=n);function i(u,c,o=0,s=u.length){if(o>>1;e(u[h],c)<0?o=h+1:s=h}while(o>>1;e(u[h],c)<=0?o=h+1:s=h}while(oo&&r(u[h-1],c)>-r(u[h],c)?h-1:h}return{left:i,center:a,right:f}}function mn(){return 0}function ln(n){return n===null?NaN:+n}const sn=W(F),dn=sn.right;W(ln).center;const gn=Math.sqrt(50),yn=Math.sqrt(10),Mn=Math.sqrt(2);function R(n,t,e){const r=(t-n)/Math.max(0,e),i=Math.floor(Math.log10(r)),f=r/Math.pow(10,i),a=f>=gn?10:f>=yn?5:f>=Mn?2:1;let u,c,o;return i<0?(o=Math.pow(10,-i)/a,u=Math.round(n*o),c=Math.round(t*o),u/ot&&--c,o=-o):(o=Math.pow(10,i)*a,u=Math.round(n/o),c=Math.round(t/o),u*ot&&--c),c0))return[];if(n===t)return[n];const r=t=i))return[];const u=f-i+1,c=new Array(u);if(r)if(a<0)for(let o=0;o=1e21?n.toLocaleString("en").replace(/,/g,""):n.toString(10)}function E(n,t){if((e=(n=t?n.toExponential(t-1):n.toExponential()).indexOf("e"))<0)return null;var e,r=n.slice(0,e);return[r.length>1?r[0]+r.slice(2):r,+n.slice(e+1)]}function v(n){return n=E(Math.abs(n)),n?n[1]:NaN}function jn(n,t){return function(e,r){for(var i=e.length,f=[],a=0,u=n[0],c=0;i>0&&u>0&&(c+u+1>r&&(u=Math.max(1,r-c)),f.push(e.substring(i-=u,i+u)),!((c+=u+1)>r));)u=n[a=(a+1)%n.length];return f.reverse().join(t)}}function Pn(n){return function(t){return t.replace(/[0-9]/g,function(e){return n[+e]})}}var zn=/^(?:(.)?([<>=^]))?([+\-( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?(~)?([a-z%])?$/i;function D(n){if(!(t=zn.exec(n)))throw new Error("invalid format: "+n);var t;return new B({fill:t[1],align:t[2],sign:t[3],symbol:t[4],zero:t[5],width:t[6],comma:t[7],precision:t[8]&&t[8].slice(1),trim:t[9],type:t[10]})}D.prototype=B.prototype;function B(n){this.fill=n.fill===void 0?" ":n.fill+"",this.align=n.align===void 0?">":n.align+"",this.sign=n.sign===void 0?"-":n.sign+"",this.symbol=n.symbol===void 0?"":n.symbol+"",this.zero=!!n.zero,this.width=n.width===void 0?void 0:+n.width,this.comma=!!n.comma,this.precision=n.precision===void 0?void 0:+n.precision,this.trim=!!n.trim,this.type=n.type===void 0?"":n.type+""}B.prototype.toString=function(){return this.fill+this.align+this.sign+this.symbol+(this.zero?"0":"")+(this.width===void 0?"":Math.max(1,this.width|0))+(this.comma?",":"")+(this.precision===void 0?"":"."+Math.max(0,this.precision|0))+(this.trim?"~":"")+this.type};function $n(n){n:for(var t=n.length,e=1,r=-1,i;e0&&(r=0);break}return r>0?n.slice(0,r)+n.slice(i+1):n}var nn;function Fn(n,t){var e=E(n,t);if(!e)return n+"";var r=e[0],i=e[1],f=i-(nn=Math.max(-8,Math.min(8,Math.floor(i/3)))*3)+1,a=r.length;return f===a?r:f>a?r+new Array(f-a+1).join("0"):f>0?r.slice(0,f)+"."+r.slice(f):"0."+new Array(1-f).join("0")+E(n,Math.max(0,t+f-1))[0]}function U(n,t){var e=E(n,t);if(!e)return n+"";var r=e[0],i=e[1];return i<0?"0."+new Array(-i).join("0")+r:r.length>i+1?r.slice(0,i+1)+"."+r.slice(i+1):r+new Array(i-r.length+2).join("0")}const _={"%":(n,t)=>(n*100).toFixed(t),b:n=>Math.round(n).toString(2),c:n=>n+"",d:bn,e:(n,t)=>n.toExponential(t),f:(n,t)=>n.toFixed(t),g:(n,t)=>n.toPrecision(t),o:n=>Math.round(n).toString(8),p:(n,t)=>U(n*100,t),r:U,s:Fn,X:n=>Math.round(n).toString(16).toUpperCase(),x:n=>Math.round(n).toString(16)};function H(n){return n}var J=Array.prototype.map,K=["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"];function Rn(n){var t=n.grouping===void 0||n.thousands===void 0?H:jn(J.call(n.grouping,Number),n.thousands+""),e=n.currency===void 0?"":n.currency[0]+"",r=n.currency===void 0?"":n.currency[1]+"",i=n.decimal===void 0?".":n.decimal+"",f=n.numerals===void 0?H:Pn(J.call(n.numerals,String)),a=n.percent===void 0?"%":n.percent+"",u=n.minus===void 0?"−":n.minus+"",c=n.nan===void 0?"NaN":n.nan+"";function o(h){h=D(h);var l=h.fill,p=h.align,y=h.sign,S=h.symbol,k=h.zero,b=h.width,T=h.comma,w=h.precision,G=h.trim,d=h.type;d==="n"?(T=!0,d="g"):_[d]||(w===void 0&&(w=12),G=!0,d="g"),(k||l==="0"&&p==="=")&&(k=!0,l="0",p="=");var en=S==="$"?e:S==="#"&&/[boxX]/.test(d)?"0"+d.toLowerCase():"",on=S==="$"?r:/[%p]/.test(d)?a:"",O=_[d],an=/[defgprs%]/.test(d);w=w===void 0?6:/[gprs]/.test(d)?Math.max(1,Math.min(21,w)):Math.max(0,Math.min(20,w));function V(m){var N=en,g=on,x,X,j;if(d==="c")g=O(m)+g,m="";else{m=+m;var P=m<0||1/m<0;if(m=isNaN(m)?c:O(Math.abs(m),w),G&&(m=$n(m)),P&&+m==0&&y!=="+"&&(P=!1),N=(P?y==="("?y:u:y==="-"||y==="("?"":y)+N,g=(d==="s"?K[8+nn/3]:"")+g+(P&&y==="("?")":""),an){for(x=-1,X=m.length;++xj||j>57){g=(j===46?i+m.slice(x+1):m.slice(x))+g,m=m.slice(0,x);break}}}T&&!k&&(m=t(m,1/0));var z=N.length+m.length+g.length,M=z>1)+N+m+g+M.slice(z);break;default:m=M+N+m+g;break}return f(m)}return V.toString=function(){return h+""},V}function s(h,l){var p=o((h=D(h),h.type="f",h)),y=Math.max(-8,Math.min(8,Math.floor(v(l)/3)))*3,S=Math.pow(10,-y),k=K[8+y/3];return function(b){return p(S*b)+k}}return{format:o,formatPrefix:s}}var $,tn,rn;En({thousands:",",grouping:[3],currency:["$",""]});function En(n){return $=Rn(n),tn=$.format,rn=$.formatPrefix,$}function Dn(n){return Math.max(0,-v(Math.abs(n)))}function Tn(n,t){return Math.max(0,Math.max(-8,Math.min(8,Math.floor(v(t)/3)))*3-v(Math.abs(n)))}function In(n,t){return n=Math.abs(n),t=Math.abs(t)-n,Math.max(0,v(t)-v(n))+1}function Ln(n){return function(){return n}}function qn(n){return+n}var Q=[0,1];function A(n){return n}function q(n,t){return(t-=n=+n)?function(e){return(e-n)/t}:Ln(isNaN(t)?NaN:.5)}function Cn(n,t){var e;return n>t&&(e=n,n=t,t=e),function(r){return Math.max(n,Math.min(t,r))}}function Bn(n,t,e){var r=n[0],i=n[1],f=t[0],a=t[1];return i2?Gn:Bn,c=o=null,h}function h(l){return l==null||isNaN(l=+l)?f:(c||(c=u(n.map(r),t,e)))(r(a(l)))}return h.invert=function(l){return a(i((o||(o=u(t,n.map(r),I)))(l)))},h.domain=function(l){return arguments.length?(n=Array.from(l,qn),s()):n.slice()},h.range=function(l){return arguments.length?(t=Array.from(l),s()):t.slice()},h.rangeRound=function(l){return t=Array.from(l),e=Sn,s()},h.clamp=function(l){return arguments.length?(a=l?!0:A,s()):a!==A},h.interpolate=function(l){return arguments.length?(e=l,s()):e},h.unknown=function(l){return arguments.length?(f=l,h):f},function(l,p){return r=l,i=p,s()}}function Xn(){return Vn()(A,A)}function Yn(n,t,e,r){var i=wn(n,t,e),f;switch(r=D(r??",f"),r.type){case"s":{var a=Math.max(Math.abs(n),Math.abs(t));return r.precision==null&&!isNaN(f=Tn(i,a))&&(r.precision=f),rn(r,a)}case"":case"e":case"g":case"p":case"r":{r.precision==null&&!isNaN(f=In(i,Math.max(Math.abs(n),Math.abs(t))))&&(r.precision=f-(r.type==="e"));break}case"f":case"%":{r.precision==null&&!isNaN(f=Dn(i))&&(r.precision=f-(r.type==="%")*2);break}}return tn(r)}function Zn(n){var t=n.domain;return n.ticks=function(e){var r=t();return pn(r[0],r[r.length-1],e??10)},n.tickFormat=function(e,r){var i=t();return Yn(i[0],i[i.length-1],e??10,r)},n.nice=function(e){e==null&&(e=10);var r=t(),i=0,f=r.length-1,a=r[i],u=r[f],c,o,s=10;for(u0;){if(o=L(a,u,e),o===c)return r[i]=a,r[f]=u,t(r);if(o>0)a=Math.floor(a/o)*o,u=Math.ceil(u/o)*o;else if(o<0)a=Math.ceil(a*o)/o,u=Math.floor(u*o)/o;else break;c=o}return n},n}function Un(){var n=Xn();return n.copy=function(){return On(n,Un())},cn.apply(n,arguments),Zn(n)}export{On as a,W as b,Xn as c,Un as l,wn as t};
                                      +import{aY as un,aZ as I,a_ as Y,a$ as Z,b0 as fn}from"./mermaid.core-D8igZDel.js";import{i as cn}from"./init-Gi6I4Gst.js";function F(n,t){return n==null||t==null?NaN:nt?1:n>=t?0:NaN}function hn(n,t){return n==null||t==null?NaN:tn?1:t>=n?0:NaN}function W(n){let t,e,r;n.length!==2?(t=F,e=(u,c)=>F(n(u),c),r=(u,c)=>n(u)-c):(t=n===F||n===hn?n:mn,e=n,r=n);function i(u,c,o=0,s=u.length){if(o>>1;e(u[h],c)<0?o=h+1:s=h}while(o>>1;e(u[h],c)<=0?o=h+1:s=h}while(oo&&r(u[h-1],c)>-r(u[h],c)?h-1:h}return{left:i,center:a,right:f}}function mn(){return 0}function ln(n){return n===null?NaN:+n}const sn=W(F),dn=sn.right;W(ln).center;const gn=Math.sqrt(50),yn=Math.sqrt(10),Mn=Math.sqrt(2);function R(n,t,e){const r=(t-n)/Math.max(0,e),i=Math.floor(Math.log10(r)),f=r/Math.pow(10,i),a=f>=gn?10:f>=yn?5:f>=Mn?2:1;let u,c,o;return i<0?(o=Math.pow(10,-i)/a,u=Math.round(n*o),c=Math.round(t*o),u/ot&&--c,o=-o):(o=Math.pow(10,i)*a,u=Math.round(n/o),c=Math.round(t/o),u*ot&&--c),c0))return[];if(n===t)return[n];const r=t=i))return[];const u=f-i+1,c=new Array(u);if(r)if(a<0)for(let o=0;o=1e21?n.toLocaleString("en").replace(/,/g,""):n.toString(10)}function E(n,t){if((e=(n=t?n.toExponential(t-1):n.toExponential()).indexOf("e"))<0)return null;var e,r=n.slice(0,e);return[r.length>1?r[0]+r.slice(2):r,+n.slice(e+1)]}function v(n){return n=E(Math.abs(n)),n?n[1]:NaN}function jn(n,t){return function(e,r){for(var i=e.length,f=[],a=0,u=n[0],c=0;i>0&&u>0&&(c+u+1>r&&(u=Math.max(1,r-c)),f.push(e.substring(i-=u,i+u)),!((c+=u+1)>r));)u=n[a=(a+1)%n.length];return f.reverse().join(t)}}function Pn(n){return function(t){return t.replace(/[0-9]/g,function(e){return n[+e]})}}var zn=/^(?:(.)?([<>=^]))?([+\-( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?(~)?([a-z%])?$/i;function D(n){if(!(t=zn.exec(n)))throw new Error("invalid format: "+n);var t;return new B({fill:t[1],align:t[2],sign:t[3],symbol:t[4],zero:t[5],width:t[6],comma:t[7],precision:t[8]&&t[8].slice(1),trim:t[9],type:t[10]})}D.prototype=B.prototype;function B(n){this.fill=n.fill===void 0?" ":n.fill+"",this.align=n.align===void 0?">":n.align+"",this.sign=n.sign===void 0?"-":n.sign+"",this.symbol=n.symbol===void 0?"":n.symbol+"",this.zero=!!n.zero,this.width=n.width===void 0?void 0:+n.width,this.comma=!!n.comma,this.precision=n.precision===void 0?void 0:+n.precision,this.trim=!!n.trim,this.type=n.type===void 0?"":n.type+""}B.prototype.toString=function(){return this.fill+this.align+this.sign+this.symbol+(this.zero?"0":"")+(this.width===void 0?"":Math.max(1,this.width|0))+(this.comma?",":"")+(this.precision===void 0?"":"."+Math.max(0,this.precision|0))+(this.trim?"~":"")+this.type};function $n(n){n:for(var t=n.length,e=1,r=-1,i;e0&&(r=0);break}return r>0?n.slice(0,r)+n.slice(i+1):n}var nn;function Fn(n,t){var e=E(n,t);if(!e)return n+"";var r=e[0],i=e[1],f=i-(nn=Math.max(-8,Math.min(8,Math.floor(i/3)))*3)+1,a=r.length;return f===a?r:f>a?r+new Array(f-a+1).join("0"):f>0?r.slice(0,f)+"."+r.slice(f):"0."+new Array(1-f).join("0")+E(n,Math.max(0,t+f-1))[0]}function U(n,t){var e=E(n,t);if(!e)return n+"";var r=e[0],i=e[1];return i<0?"0."+new Array(-i).join("0")+r:r.length>i+1?r.slice(0,i+1)+"."+r.slice(i+1):r+new Array(i-r.length+2).join("0")}const _={"%":(n,t)=>(n*100).toFixed(t),b:n=>Math.round(n).toString(2),c:n=>n+"",d:bn,e:(n,t)=>n.toExponential(t),f:(n,t)=>n.toFixed(t),g:(n,t)=>n.toPrecision(t),o:n=>Math.round(n).toString(8),p:(n,t)=>U(n*100,t),r:U,s:Fn,X:n=>Math.round(n).toString(16).toUpperCase(),x:n=>Math.round(n).toString(16)};function H(n){return n}var J=Array.prototype.map,K=["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"];function Rn(n){var t=n.grouping===void 0||n.thousands===void 0?H:jn(J.call(n.grouping,Number),n.thousands+""),e=n.currency===void 0?"":n.currency[0]+"",r=n.currency===void 0?"":n.currency[1]+"",i=n.decimal===void 0?".":n.decimal+"",f=n.numerals===void 0?H:Pn(J.call(n.numerals,String)),a=n.percent===void 0?"%":n.percent+"",u=n.minus===void 0?"−":n.minus+"",c=n.nan===void 0?"NaN":n.nan+"";function o(h){h=D(h);var l=h.fill,p=h.align,y=h.sign,S=h.symbol,k=h.zero,b=h.width,T=h.comma,w=h.precision,G=h.trim,d=h.type;d==="n"?(T=!0,d="g"):_[d]||(w===void 0&&(w=12),G=!0,d="g"),(k||l==="0"&&p==="=")&&(k=!0,l="0",p="=");var en=S==="$"?e:S==="#"&&/[boxX]/.test(d)?"0"+d.toLowerCase():"",on=S==="$"?r:/[%p]/.test(d)?a:"",O=_[d],an=/[defgprs%]/.test(d);w=w===void 0?6:/[gprs]/.test(d)?Math.max(1,Math.min(21,w)):Math.max(0,Math.min(20,w));function V(m){var N=en,g=on,x,X,j;if(d==="c")g=O(m)+g,m="";else{m=+m;var P=m<0||1/m<0;if(m=isNaN(m)?c:O(Math.abs(m),w),G&&(m=$n(m)),P&&+m==0&&y!=="+"&&(P=!1),N=(P?y==="("?y:u:y==="-"||y==="("?"":y)+N,g=(d==="s"?K[8+nn/3]:"")+g+(P&&y==="("?")":""),an){for(x=-1,X=m.length;++xj||j>57){g=(j===46?i+m.slice(x+1):m.slice(x))+g,m=m.slice(0,x);break}}}T&&!k&&(m=t(m,1/0));var z=N.length+m.length+g.length,M=z>1)+N+m+g+M.slice(z);break;default:m=M+N+m+g;break}return f(m)}return V.toString=function(){return h+""},V}function s(h,l){var p=o((h=D(h),h.type="f",h)),y=Math.max(-8,Math.min(8,Math.floor(v(l)/3)))*3,S=Math.pow(10,-y),k=K[8+y/3];return function(b){return p(S*b)+k}}return{format:o,formatPrefix:s}}var $,tn,rn;En({thousands:",",grouping:[3],currency:["$",""]});function En(n){return $=Rn(n),tn=$.format,rn=$.formatPrefix,$}function Dn(n){return Math.max(0,-v(Math.abs(n)))}function Tn(n,t){return Math.max(0,Math.max(-8,Math.min(8,Math.floor(v(t)/3)))*3-v(Math.abs(n)))}function In(n,t){return n=Math.abs(n),t=Math.abs(t)-n,Math.max(0,v(t)-v(n))+1}function Ln(n){return function(){return n}}function qn(n){return+n}var Q=[0,1];function A(n){return n}function q(n,t){return(t-=n=+n)?function(e){return(e-n)/t}:Ln(isNaN(t)?NaN:.5)}function Cn(n,t){var e;return n>t&&(e=n,n=t,t=e),function(r){return Math.max(n,Math.min(t,r))}}function Bn(n,t,e){var r=n[0],i=n[1],f=t[0],a=t[1];return i2?Gn:Bn,c=o=null,h}function h(l){return l==null||isNaN(l=+l)?f:(c||(c=u(n.map(r),t,e)))(r(a(l)))}return h.invert=function(l){return a(i((o||(o=u(t,n.map(r),I)))(l)))},h.domain=function(l){return arguments.length?(n=Array.from(l,qn),s()):n.slice()},h.range=function(l){return arguments.length?(t=Array.from(l),s()):t.slice()},h.rangeRound=function(l){return t=Array.from(l),e=Sn,s()},h.clamp=function(l){return arguments.length?(a=l?!0:A,s()):a!==A},h.interpolate=function(l){return arguments.length?(e=l,s()):e},h.unknown=function(l){return arguments.length?(f=l,h):f},function(l,p){return r=l,i=p,s()}}function Xn(){return Vn()(A,A)}function Yn(n,t,e,r){var i=wn(n,t,e),f;switch(r=D(r??",f"),r.type){case"s":{var a=Math.max(Math.abs(n),Math.abs(t));return r.precision==null&&!isNaN(f=Tn(i,a))&&(r.precision=f),rn(r,a)}case"":case"e":case"g":case"p":case"r":{r.precision==null&&!isNaN(f=In(i,Math.max(Math.abs(n),Math.abs(t))))&&(r.precision=f-(r.type==="e"));break}case"f":case"%":{r.precision==null&&!isNaN(f=Dn(i))&&(r.precision=f-(r.type==="%")*2);break}}return tn(r)}function Zn(n){var t=n.domain;return n.ticks=function(e){var r=t();return pn(r[0],r[r.length-1],e??10)},n.tickFormat=function(e,r){var i=t();return Yn(i[0],i[i.length-1],e??10,r)},n.nice=function(e){e==null&&(e=10);var r=t(),i=0,f=r.length-1,a=r[i],u=r[f],c,o,s=10;for(u0;){if(o=L(a,u,e),o===c)return r[i]=a,r[f]=u,t(r);if(o>0)a=Math.floor(a/o)*o,u=Math.ceil(u/o)*o;else if(o<0)a=Math.ceil(a*o)/o,u=Math.floor(u*o)/o;else break;c=o}return n},n}function Un(){var n=Xn();return n.copy=function(){return On(n,Un())},cn.apply(n,arguments),Zn(n)}export{On as a,W as b,Xn as c,Un as l,wn as t};
                                      diff --git a/assets/log.html-CWv0qLIE.js b/assets/log.html-D-t8wlxQ.js
                                      similarity index 98%
                                      rename from assets/log.html-CWv0qLIE.js
                                      rename to assets/log.html-D-t8wlxQ.js
                                      index ec25441ccc..20aa14f3e3 100644
                                      --- a/assets/log.html-CWv0qLIE.js
                                      +++ b/assets/log.html-D-t8wlxQ.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as e,r as n,o as s,c as t,a,e as c}from"./app-DBM4OJyw.js";const r={},l=c(`

                                      Настройка журнала

                                      Настройка журнала управляет тем, как Xray выводит журналы.

                                      Xray имеет два типа журналов: журнал доступа и журнал ошибок.
                                      Вы можете настроить способ вывода каждого типа журнала отдельно.

                                      LogObject

                                      LogObject соответствует полю log в конфигурационном файле.

                                      {
                                      +import{_ as e,r as n,o as s,c as t,a,e as c}from"./app-D7uBbsY3.js";const r={},l=c(`

                                      Настройка журнала

                                      Настройка журнала управляет тем, как Xray выводит журналы.

                                      Xray имеет два типа журналов: журнал доступа и журнал ошибок.
                                      Вы можете настроить способ вывода каждого типа журнала отдельно.

                                      LogObject

                                      LogObject соответствует полю log в конфигурационном файле.

                                      {
                                         "log": {
                                           "access": "путь к файлу",
                                           "error": "путь к файлу",
                                      diff --git a/assets/log.html-CA6mG-aB.js b/assets/log.html-DnBUJw34.js
                                      similarity index 96%
                                      rename from assets/log.html-CA6mG-aB.js
                                      rename to assets/log.html-DnBUJw34.js
                                      index 2832d91f4d..83089ffc83 100644
                                      --- a/assets/log.html-CA6mG-aB.js
                                      +++ b/assets/log.html-DnBUJw34.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as e,r as t,o as n,c as a,a as s,e as c}from"./app-DBM4OJyw.js";const l={},r=c(`

                                      Log Configuration

                                      Log configuration controls how Xray outputs logs.

                                      Xray has two types of logs: access logs and error logs. You can configure the output method for each type of log separately.

                                      LogObject

                                      LogObject corresponds to the log item in the configuration file.

                                      {
                                      +import{_ as e,r as t,o as n,c as a,a as s,e as c}from"./app-D7uBbsY3.js";const l={},r=c(`

                                      Log Configuration

                                      Log configuration controls how Xray outputs logs.

                                      Xray has two types of logs: access logs and error logs. You can configure the output method for each type of log separately.

                                      LogObject

                                      LogObject corresponds to the log item in the configuration file.

                                      {
                                         "log": {
                                           "access": "file_path",
                                           "error": "file_path",
                                      diff --git a/assets/log.html-CTirYPei.js b/assets/log.html-WdHz5f6a.js
                                      similarity index 97%
                                      rename from assets/log.html-CTirYPei.js
                                      rename to assets/log.html-WdHz5f6a.js
                                      index 2be3bae7c4..9afd09f9c8 100644
                                      --- a/assets/log.html-CTirYPei.js
                                      +++ b/assets/log.html-WdHz5f6a.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as e,r as n,o as s,c as a,a as t,e as c}from"./app-DBM4OJyw.js";const l={},p=c(`

                                      日志配置

                                      日志配置,控制 Xray 输出日志的方式.

                                      Xray 有两种日志, 访问日志和错误日志, 你可以分别配置两种日志的输出方式.

                                      LogObject

                                      LogObject 对应配置文件的 log 项。

                                      {
                                      +import{_ as e,r as n,o as s,c as a,a as t,e as c}from"./app-D7uBbsY3.js";const l={},p=c(`

                                      日志配置

                                      日志配置,控制 Xray 输出日志的方式.

                                      Xray 有两种日志, 访问日志和错误日志, 你可以分别配置两种日志的输出方式.

                                      LogObject

                                      LogObject 对应配置文件的 log 项。

                                      {
                                         "log": {
                                           "access": "文件地址",
                                           "error": "文件地址",
                                      diff --git a/assets/loopback.html-CyxLLiRu.js b/assets/loopback.html-CBRQTJB4.js
                                      similarity index 96%
                                      rename from assets/loopback.html-CyxLLiRu.js
                                      rename to assets/loopback.html-CBRQTJB4.js
                                      index f551d1186c..8f22f79774 100644
                                      --- a/assets/loopback.html-CyxLLiRu.js
                                      +++ b/assets/loopback.html-CBRQTJB4.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as o,r as t,o as e,c as i,a as s,e as u}from"./app-DBM4OJyw.js";const a={},d=u(`

                                      Loopback

                                      Loopback is an outbound protocol. It can send traffics through corresponding outbound to routing inbound, thus rerouting traffics to other routing rules without leaving Xray-core.

                                      OutboundConfigurationObject

                                      {
                                      +import{_ as o,r as t,o as e,c as i,a as s,e as u}from"./app-D7uBbsY3.js";const a={},d=u(`

                                      Loopback

                                      Loopback is an outbound protocol. It can send traffics through corresponding outbound to routing inbound, thus rerouting traffics to other routing rules without leaving Xray-core.

                                      OutboundConfigurationObject

                                      {
                                         "inboundTag": "TagUseAsInbound"
                                       }
                                       

                                      inboundTag: string

                                      Use as an inbound tag for routing.

                                      This tag can be used as inboundTag in routing rules, all traffics going through this outbound can be rerouted with routing rules with corresponding inbound tag.

                                      How to use?

                                      If you need to do some more detailed routing for traffics that have been routed by routing rules, like splitting routed traffics to TCP traffics and UDP traffics and send them to different outbounds, this can be done with loopback outbound.

                                      {
                                      diff --git a/assets/loopback.html-EJfWzfAq.js b/assets/loopback.html-DKif3g9A.js
                                      similarity index 99%
                                      rename from assets/loopback.html-EJfWzfAq.js
                                      rename to assets/loopback.html-DKif3g9A.js
                                      index 2aaa7365e7..ab5305c659 100644
                                      --- a/assets/loopback.html-EJfWzfAq.js
                                      +++ b/assets/loopback.html-DKif3g9A.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as s,r as a,o as t,c as o,a as p,e}from"./app-DBM4OJyw.js";const c={},u=e(`

                                      Loopback

                                      Loopback - это исходящий протокол данных, который перенаправляет данные, прошедшие через это исходящее соединение, обратно на вход маршрутизатора, что позволяет повторно обработать данные по правилам маршрутизации, не покидая Xray-core.

                                      OutboundConfigurationObject

                                      {
                                      +import{_ as s,r as a,o as t,c as o,a as p,e}from"./app-D7uBbsY3.js";const c={},u=e(`

                                      Loopback

                                      Loopback - это исходящий протокол данных, который перенаправляет данные, прошедшие через это исходящее соединение, обратно на вход маршрутизатора, что позволяет повторно обработать данные по правилам маршрутизации, не покидая Xray-core.

                                      OutboundConfigurationObject

                                      {
                                         "inboundTag": "TagUseAsInbound"
                                       }
                                       

                                      inboundTag: string

                                      Идентификатор входящего протокола, используемый для повторной маршрутизации.

                                      Этот идентификатор может использоваться в маршрутизации для inboundTag, указывая, что данные из этого исходящего соединения могут быть повторно обработаны соответствующими правилами маршрутизации.

                                      Как использовать?

                                      Если необходимо, чтобы трафик, уже разделенный по правилам маршрутизации, был перенаправлен другими правилами маршрутизации (например, трафик TCP и UDP, разделенный одними и теми же правилами маршрутизации, должен идти через разные исходящие соединения), можно использовать исходящее соединение loopback.

                                      {
                                      diff --git a/assets/loopback.html-_BhTQZ0O.js b/assets/loopback.html-o32NwpT2.js
                                      similarity index 99%
                                      rename from assets/loopback.html-_BhTQZ0O.js
                                      rename to assets/loopback.html-o32NwpT2.js
                                      index ba3075e425..91de23b542 100644
                                      --- a/assets/loopback.html-_BhTQZ0O.js
                                      +++ b/assets/loopback.html-o32NwpT2.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as s,r as a,o as t,c as o,a as p,e}from"./app-DBM4OJyw.js";const c={},u=e(`

                                      Loopback

                                      Loopback 是个出站数据协议,其作用为将经该出站传出的数据重新送入路由入站,以达到数据无需离开 Xray-core 即可再次被路由处理的效果。

                                      OutboundConfigurationObject

                                      {
                                      +import{_ as s,r as a,o as t,c as o,a as p,e}from"./app-D7uBbsY3.js";const c={},u=e(`

                                      Loopback

                                      Loopback 是个出站数据协议,其作用为将经该出站传出的数据重新送入路由入站,以达到数据无需离开 Xray-core 即可再次被路由处理的效果。

                                      OutboundConfigurationObject

                                      {
                                         "inboundTag": "TagUseAsInbound"
                                       }
                                       

                                      inboundTag: string

                                      用于重新路由的入站协议标识。

                                      该标识可以在路由中用于 inboundTag ,表示该出站中的数据可以被对应的路由规则再次处理。

                                      如何使用?

                                      如果需要将已经通过路由规则分流过的流量再由其它路由规则做更细致的分流,比如由同一组路由规则分流后的 TCP 流量和 UDP 要走不同的出站,则可以使用 loopback 出站完成。

                                      {
                                      diff --git a/assets/mermaid.core-DapiNGBY.js b/assets/mermaid.core-D8igZDel.js
                                      similarity index 99%
                                      rename from assets/mermaid.core-DapiNGBY.js
                                      rename to assets/mermaid.core-D8igZDel.js
                                      index 3bfa3eab08..3531090c14 100644
                                      --- a/assets/mermaid.core-DapiNGBY.js
                                      +++ b/assets/mermaid.core-D8igZDel.js
                                      @@ -1,4 +1,4 @@
                                      -var Gp=Object.defineProperty;var Vp=(t,e,r)=>e in t?Gp(t,e,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[e]=r;var rt=(t,e,r)=>(Vp(t,typeof e!="symbol"?e+"":e,r),r),Xp=(t,e,r)=>{if(!e.has(t))throw TypeError("Cannot "+r)};var Vi=(t,e,r)=>{if(e.has(t))throw TypeError("Cannot add the same private member more than once");e instanceof WeakSet?e.add(t):e.set(t,r)};var Ir=(t,e,r)=>(Xp(t,e,"access private method"),r);import{h as at}from"./app-DBM4OJyw.js";var Zp=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{};function Kp(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}var Hc={exports:{}};(function(t,e){(function(r,i){t.exports=i()})(Zp,function(){var r=1e3,i=6e4,n=36e5,a="millisecond",s="second",o="minute",l="hour",c="day",h="week",f="month",u="quarter",p="year",g="date",m="Invalid Date",_=/^(\d{4})[-/]?(\d{1,2})?[-/]?(\d{0,2})[Tt\s]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?[.:]?(\d+)?$/,C=/\[([^\]]+)]|Y{1,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g,x={name:"en",weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),ordinal:function(M){var L=["th","st","nd","rd"],T=M%100;return"["+M+(L[(T-20)%10]||L[T]||L[0])+"]"}},v=function(M,L,T){var F=String(M);return!F||F.length>=L?M:""+Array(L+1-F.length).join(T)+M},B={s:v,z:function(M){var L=-M.utcOffset(),T=Math.abs(L),F=Math.floor(T/60),S=T%60;return(L<=0?"+":"-")+v(F,2,"0")+":"+v(S,2,"0")},m:function M(L,T){if(L.date()1)return M(I[0])}else{var J=L.name;O[J]=L,S=J}return!F&&S&&($=S),S||!F&&$},R=function(M,L){if(G(M))return M.clone();var T=typeof L=="object"?L:{};return T.date=M,T.args=arguments,new lt(T)},D=B;D.l=Z,D.i=G,D.w=function(M,L){return R(M,{locale:L.$L,utc:L.$u,x:L.$x,$offset:L.$offset})};var lt=function(){function M(T){this.$L=Z(T.locale,null,!0),this.parse(T),this.$x=this.$x||T.x||{},this[E]=!0}var L=M.prototype;return L.parse=function(T){this.$d=function(F){var S=F.date,H=F.utc;if(S===null)return new Date(NaN);if(D.u(S))return new Date;if(S instanceof Date)return new Date(S);if(typeof S=="string"&&!/Z$/i.test(S)){var I=S.match(_);if(I){var J=I[2]-1||0,Y=(I[7]||"0").substring(0,3);return H?new Date(Date.UTC(I[1],J,I[3]||1,I[4]||0,I[5]||0,I[6]||0,Y)):new Date(I[1],J,I[3]||1,I[4]||0,I[5]||0,I[6]||0,Y)}}return new Date(S)}(T),this.init()},L.init=function(){var T=this.$d;this.$y=T.getFullYear(),this.$M=T.getMonth(),this.$D=T.getDate(),this.$W=T.getDay(),this.$H=T.getHours(),this.$m=T.getMinutes(),this.$s=T.getSeconds(),this.$ms=T.getMilliseconds()},L.$utils=function(){return D},L.isValid=function(){return this.$d.toString()!==m},L.isSame=function(T,F){var S=R(T);return this.startOf(F)<=S&&S<=this.endOf(F)},L.isAfter=function(T,F){return R(T)t>=255?255:t<0?0:t,g:t=>t>=255?255:t<0?0:t,b:t=>t>=255?255:t<0?0:t,h:t=>t%360,s:t=>t>=100?100:t<0?0:t,l:t=>t>=100?100:t<0?0:t,a:t=>t>=1?1:t<0?0:t},toLinear:t=>{const e=t/255;return t>.03928?Math.pow((e+.055)/1.055,2.4):e/12.92},hue2rgb:(t,e,r)=>(r<0&&(r+=1),r>1&&(r-=1),r<1/6?t+(e-t)*6*r:r<1/2?e:r<2/3?t+(e-t)*(2/3-r)*6:t),hsl2rgb:({h:t,s:e,l:r},i)=>{if(!e)return r*2.55;t/=360,e/=100,r/=100;const n=r<.5?r*(1+e):r+e-r*e,a=2*r-n;switch(i){case"r":return ln.hue2rgb(a,n,t+1/3)*255;case"g":return ln.hue2rgb(a,n,t)*255;case"b":return ln.hue2rgb(a,n,t-1/3)*255}},rgb2hsl:({r:t,g:e,b:r},i)=>{t/=255,e/=255,r/=255;const n=Math.max(t,e,r),a=Math.min(t,e,r),s=(n+a)/2;if(i==="l")return s*100;if(n===a)return 0;const o=n-a,l=s>.5?o/(2-n-a):o/(n+a);if(i==="s")return l*100;switch(n){case t:return((e-r)/o+(ee>r?Math.min(e,Math.max(r,t)):Math.min(r,Math.max(e,t)),round:t=>Math.round(t*1e10)/1e10},eg={dec2hex:t=>{const e=Math.round(t).toString(16);return e.length>1?e:`0${e}`}},U={channel:ln,lang:tg,unit:eg},Me={};for(let t=0;t<=255;t++)Me[t]=U.unit.dec2hex(t);const wt={ALL:0,RGB:1,HSL:2};class rg{constructor(){this.type=wt.ALL}get(){return this.type}set(e){if(this.type&&this.type!==e)throw new Error("Cannot change both RGB and HSL channels at the same time");this.type=e}reset(){this.type=wt.ALL}is(e){return this.type===e}}class ig{constructor(e,r){this.color=r,this.changed=!1,this.data=e,this.type=new rg}set(e,r){return this.color=r,this.changed=!1,this.data=e,this.type.type=wt.ALL,this}_ensureHSL(){const e=this.data,{h:r,s:i,l:n}=e;r===void 0&&(e.h=U.channel.rgb2hsl(e,"h")),i===void 0&&(e.s=U.channel.rgb2hsl(e,"s")),n===void 0&&(e.l=U.channel.rgb2hsl(e,"l"))}_ensureRGB(){const e=this.data,{r,g:i,b:n}=e;r===void 0&&(e.r=U.channel.hsl2rgb(e,"r")),i===void 0&&(e.g=U.channel.hsl2rgb(e,"g")),n===void 0&&(e.b=U.channel.hsl2rgb(e,"b"))}get r(){const e=this.data,r=e.r;return!this.type.is(wt.HSL)&&r!==void 0?r:(this._ensureHSL(),U.channel.hsl2rgb(e,"r"))}get g(){const e=this.data,r=e.g;return!this.type.is(wt.HSL)&&r!==void 0?r:(this._ensureHSL(),U.channel.hsl2rgb(e,"g"))}get b(){const e=this.data,r=e.b;return!this.type.is(wt.HSL)&&r!==void 0?r:(this._ensureHSL(),U.channel.hsl2rgb(e,"b"))}get h(){const e=this.data,r=e.h;return!this.type.is(wt.RGB)&&r!==void 0?r:(this._ensureRGB(),U.channel.rgb2hsl(e,"h"))}get s(){const e=this.data,r=e.s;return!this.type.is(wt.RGB)&&r!==void 0?r:(this._ensureRGB(),U.channel.rgb2hsl(e,"s"))}get l(){const e=this.data,r=e.l;return!this.type.is(wt.RGB)&&r!==void 0?r:(this._ensureRGB(),U.channel.rgb2hsl(e,"l"))}get a(){return this.data.a}set r(e){this.type.set(wt.RGB),this.changed=!0,this.data.r=e}set g(e){this.type.set(wt.RGB),this.changed=!0,this.data.g=e}set b(e){this.type.set(wt.RGB),this.changed=!0,this.data.b=e}set h(e){this.type.set(wt.HSL),this.changed=!0,this.data.h=e}set s(e){this.type.set(wt.HSL),this.changed=!0,this.data.s=e}set l(e){this.type.set(wt.HSL),this.changed=!0,this.data.l=e}set a(e){this.changed=!0,this.data.a=e}}const ia=new ig({r:0,g:0,b:0,a:0},"transparent"),pr={re:/^#((?:[a-f0-9]{2}){2,4}|[a-f0-9]{3})$/i,parse:t=>{if(t.charCodeAt(0)!==35)return;const e=t.match(pr.re);if(!e)return;const r=e[1],i=parseInt(r,16),n=r.length,a=n%4===0,s=n>4,o=s?1:17,l=s?8:4,c=a?0:-1,h=s?255:15;return ia.set({r:(i>>l*(c+3)&h)*o,g:(i>>l*(c+2)&h)*o,b:(i>>l*(c+1)&h)*o,a:a?(i&h)*o/255:1},t)},stringify:t=>{const{r:e,g:r,b:i,a:n}=t;return n<1?`#${Me[Math.round(e)]}${Me[Math.round(r)]}${Me[Math.round(i)]}${Me[Math.round(n*255)]}`:`#${Me[Math.round(e)]}${Me[Math.round(r)]}${Me[Math.round(i)]}`}},He={re:/^hsla?\(\s*?(-?(?:\d+(?:\.\d+)?|(?:\.\d+))(?:e-?\d+)?(?:deg|grad|rad|turn)?)\s*?(?:,|\s)\s*?(-?(?:\d+(?:\.\d+)?|(?:\.\d+))(?:e-?\d+)?%)\s*?(?:,|\s)\s*?(-?(?:\d+(?:\.\d+)?|(?:\.\d+))(?:e-?\d+)?%)(?:\s*?(?:,|\/)\s*?\+?(-?(?:\d+(?:\.\d+)?|(?:\.\d+))(?:e-?\d+)?(%)?))?\s*?\)$/i,hueRe:/^(.+?)(deg|grad|rad|turn)$/i,_hue2deg:t=>{const e=t.match(He.hueRe);if(e){const[,r,i]=e;switch(i){case"grad":return U.channel.clamp.h(parseFloat(r)*.9);case"rad":return U.channel.clamp.h(parseFloat(r)*180/Math.PI);case"turn":return U.channel.clamp.h(parseFloat(r)*360)}}return U.channel.clamp.h(parseFloat(t))},parse:t=>{const e=t.charCodeAt(0);if(e!==104&&e!==72)return;const r=t.match(He.re);if(!r)return;const[,i,n,a,s,o]=r;return ia.set({h:He._hue2deg(i),s:U.channel.clamp.s(parseFloat(n)),l:U.channel.clamp.l(parseFloat(a)),a:s?U.channel.clamp.a(o?parseFloat(s)/100:parseFloat(s)):1},t)},stringify:t=>{const{h:e,s:r,l:i,a:n}=t;return n<1?`hsla(${U.lang.round(e)}, ${U.lang.round(r)}%, ${U.lang.round(i)}%, ${n})`:`hsl(${U.lang.round(e)}, ${U.lang.round(r)}%, ${U.lang.round(i)}%)`}},Jr={colors:{aliceblue:"#f0f8ff",antiquewhite:"#faebd7",aqua:"#00ffff",aquamarine:"#7fffd4",azure:"#f0ffff",beige:"#f5f5dc",bisque:"#ffe4c4",black:"#000000",blanchedalmond:"#ffebcd",blue:"#0000ff",blueviolet:"#8a2be2",brown:"#a52a2a",burlywood:"#deb887",cadetblue:"#5f9ea0",chartreuse:"#7fff00",chocolate:"#d2691e",coral:"#ff7f50",cornflowerblue:"#6495ed",cornsilk:"#fff8dc",crimson:"#dc143c",cyanaqua:"#00ffff",darkblue:"#00008b",darkcyan:"#008b8b",darkgoldenrod:"#b8860b",darkgray:"#a9a9a9",darkgreen:"#006400",darkgrey:"#a9a9a9",darkkhaki:"#bdb76b",darkmagenta:"#8b008b",darkolivegreen:"#556b2f",darkorange:"#ff8c00",darkorchid:"#9932cc",darkred:"#8b0000",darksalmon:"#e9967a",darkseagreen:"#8fbc8f",darkslateblue:"#483d8b",darkslategray:"#2f4f4f",darkslategrey:"#2f4f4f",darkturquoise:"#00ced1",darkviolet:"#9400d3",deeppink:"#ff1493",deepskyblue:"#00bfff",dimgray:"#696969",dimgrey:"#696969",dodgerblue:"#1e90ff",firebrick:"#b22222",floralwhite:"#fffaf0",forestgreen:"#228b22",fuchsia:"#ff00ff",gainsboro:"#dcdcdc",ghostwhite:"#f8f8ff",gold:"#ffd700",goldenrod:"#daa520",gray:"#808080",green:"#008000",greenyellow:"#adff2f",grey:"#808080",honeydew:"#f0fff0",hotpink:"#ff69b4",indianred:"#cd5c5c",indigo:"#4b0082",ivory:"#fffff0",khaki:"#f0e68c",lavender:"#e6e6fa",lavenderblush:"#fff0f5",lawngreen:"#7cfc00",lemonchiffon:"#fffacd",lightblue:"#add8e6",lightcoral:"#f08080",lightcyan:"#e0ffff",lightgoldenrodyellow:"#fafad2",lightgray:"#d3d3d3",lightgreen:"#90ee90",lightgrey:"#d3d3d3",lightpink:"#ffb6c1",lightsalmon:"#ffa07a",lightseagreen:"#20b2aa",lightskyblue:"#87cefa",lightslategray:"#778899",lightslategrey:"#778899",lightsteelblue:"#b0c4de",lightyellow:"#ffffe0",lime:"#00ff00",limegreen:"#32cd32",linen:"#faf0e6",magenta:"#ff00ff",maroon:"#800000",mediumaquamarine:"#66cdaa",mediumblue:"#0000cd",mediumorchid:"#ba55d3",mediumpurple:"#9370db",mediumseagreen:"#3cb371",mediumslateblue:"#7b68ee",mediumspringgreen:"#00fa9a",mediumturquoise:"#48d1cc",mediumvioletred:"#c71585",midnightblue:"#191970",mintcream:"#f5fffa",mistyrose:"#ffe4e1",moccasin:"#ffe4b5",navajowhite:"#ffdead",navy:"#000080",oldlace:"#fdf5e6",olive:"#808000",olivedrab:"#6b8e23",orange:"#ffa500",orangered:"#ff4500",orchid:"#da70d6",palegoldenrod:"#eee8aa",palegreen:"#98fb98",paleturquoise:"#afeeee",palevioletred:"#db7093",papayawhip:"#ffefd5",peachpuff:"#ffdab9",peru:"#cd853f",pink:"#ffc0cb",plum:"#dda0dd",powderblue:"#b0e0e6",purple:"#800080",rebeccapurple:"#663399",red:"#ff0000",rosybrown:"#bc8f8f",royalblue:"#4169e1",saddlebrown:"#8b4513",salmon:"#fa8072",sandybrown:"#f4a460",seagreen:"#2e8b57",seashell:"#fff5ee",sienna:"#a0522d",silver:"#c0c0c0",skyblue:"#87ceeb",slateblue:"#6a5acd",slategray:"#708090",slategrey:"#708090",snow:"#fffafa",springgreen:"#00ff7f",tan:"#d2b48c",teal:"#008080",thistle:"#d8bfd8",transparent:"#00000000",turquoise:"#40e0d0",violet:"#ee82ee",wheat:"#f5deb3",white:"#ffffff",whitesmoke:"#f5f5f5",yellow:"#ffff00",yellowgreen:"#9acd32"},parse:t=>{t=t.toLowerCase();const e=Jr.colors[t];if(e)return pr.parse(e)},stringify:t=>{const e=pr.stringify(t);for(const r in Jr.colors)if(Jr.colors[r]===e)return r}},Gr={re:/^rgba?\(\s*?(-?(?:\d+(?:\.\d+)?|(?:\.\d+))(?:e\d+)?(%?))\s*?(?:,|\s)\s*?(-?(?:\d+(?:\.\d+)?|(?:\.\d+))(?:e\d+)?(%?))\s*?(?:,|\s)\s*?(-?(?:\d+(?:\.\d+)?|(?:\.\d+))(?:e\d+)?(%?))(?:\s*?(?:,|\/)\s*?\+?(-?(?:\d+(?:\.\d+)?|(?:\.\d+))(?:e\d+)?(%?)))?\s*?\)$/i,parse:t=>{const e=t.charCodeAt(0);if(e!==114&&e!==82)return;const r=t.match(Gr.re);if(!r)return;const[,i,n,a,s,o,l,c,h]=r;return ia.set({r:U.channel.clamp.r(n?parseFloat(i)*2.55:parseFloat(i)),g:U.channel.clamp.g(s?parseFloat(a)*2.55:parseFloat(a)),b:U.channel.clamp.b(l?parseFloat(o)*2.55:parseFloat(o)),a:c?U.channel.clamp.a(h?parseFloat(c)/100:parseFloat(c)):1},t)},stringify:t=>{const{r:e,g:r,b:i,a:n}=t;return n<1?`rgba(${U.lang.round(e)}, ${U.lang.round(r)}, ${U.lang.round(i)}, ${U.lang.round(n)})`:`rgb(${U.lang.round(e)}, ${U.lang.round(r)}, ${U.lang.round(i)})`}},fe={format:{keyword:Jr,hex:pr,rgb:Gr,rgba:Gr,hsl:He,hsla:He},parse:t=>{if(typeof t!="string")return t;const e=pr.parse(t)||Gr.parse(t)||He.parse(t)||Jr.parse(t);if(e)return e;throw new Error(`Unsupported color format: "${t}"`)},stringify:t=>!t.changed&&t.color?t.color:t.type.is(wt.HSL)||t.data.r===void 0?He.stringify(t):t.a<1||!Number.isInteger(t.r)||!Number.isInteger(t.g)||!Number.isInteger(t.b)?Gr.stringify(t):pr.stringify(t)},jc=(t,e)=>{const r=fe.parse(t);for(const i in e)r[i]=U.channel.clamp[i](e[i]);return fe.stringify(r)},ti=(t,e,r=0,i=1)=>{if(typeof t!="number")return jc(t,{a:e});const n=ia.set({r:U.channel.clamp.r(t),g:U.channel.clamp.g(e),b:U.channel.clamp.b(r),a:U.channel.clamp.a(i)});return fe.stringify(n)},ng=t=>{const{r:e,g:r,b:i}=fe.parse(t),n=.2126*U.channel.toLinear(e)+.7152*U.channel.toLinear(r)+.0722*U.channel.toLinear(i);return U.lang.round(n)},ag=t=>ng(t)>=.5,Mi=t=>!ag(t),Uc=(t,e,r)=>{const i=fe.parse(t),n=i[e],a=U.channel.clamp[e](n+r);return n!==a&&(i[e]=a),fe.stringify(i)},q=(t,e)=>Uc(t,"l",e),W=(t,e)=>Uc(t,"l",-e),b=(t,e)=>{const r=fe.parse(t),i={};for(const n in e)e[n]&&(i[n]=r[n]+e[n]);return jc(t,i)},sg=(t,e,r=50)=>{const{r:i,g:n,b:a,a:s}=fe.parse(t),{r:o,g:l,b:c,a:h}=fe.parse(e),f=r/100,u=f*2-1,p=s-h,m=((u*p===-1?u:(u+p)/(1+u*p))+1)/2,_=1-m,C=i*m+o*_,x=n*m+l*_,v=a*m+c*_,B=s*f+h*(1-f);return ti(C,x,v,B)},A=(t,e=100)=>{const r=fe.parse(t);return r.r=255-r.r,r.g=255-r.g,r.b=255-r.b,sg(r,t,e)};/*! @license DOMPurify 3.1.5 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.1.5/LICENSE */const{entries:Yc,setPrototypeOf:pl,isFrozen:og,getPrototypeOf:lg,getOwnPropertyDescriptor:cg}=Object;let{freeze:It,seal:Xt,create:Gc}=Object,{apply:Qa,construct:Ja}=typeof Reflect<"u"&&Reflect;It||(It=function(e){return e});Xt||(Xt=function(e){return e});Qa||(Qa=function(e,r,i){return e.apply(r,i)});Ja||(Ja=function(e,r){return new e(...r)});const Xi=jt(Array.prototype.forEach),gl=jt(Array.prototype.pop),Rr=jt(Array.prototype.push),cn=jt(String.prototype.toLowerCase),Oa=jt(String.prototype.toString),ml=jt(String.prototype.match),Dr=jt(String.prototype.replace),hg=jt(String.prototype.indexOf),ug=jt(String.prototype.trim),Kt=jt(Object.prototype.hasOwnProperty),Ft=jt(RegExp.prototype.test),Pr=fg(TypeError);function jt(t){return function(e){for(var r=arguments.length,i=new Array(r>1?r-1:0),n=1;n2&&arguments[2]!==void 0?arguments[2]:cn;pl&&pl(t,null);let i=e.length;for(;i--;){let n=e[i];if(typeof n=="string"){const a=r(n);a!==n&&(og(e)||(e[i]=a),n=a)}t[n]=!0}return t}function dg(t){for(let e=0;e/gm),xg=Xt(/\${[\w\W]*}/gm),bg=Xt(/^data-[\-\w.\u00B7-\uFFFF]/),_g=Xt(/^aria-[\-\w]+$/),Vc=Xt(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i),Cg=Xt(/^(?:\w+script|data):/i),vg=Xt(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g),Xc=Xt(/^html$/i),kg=Xt(/^[a-z][.\w]*(-[.\w]+)+$/i);var Cl=Object.freeze({__proto__:null,MUSTACHE_EXPR:mg,ERB_EXPR:yg,TMPLIT_EXPR:xg,DATA_ATTR:bg,ARIA_ATTR:_g,IS_ALLOWED_URI:Vc,IS_SCRIPT_OR_DATA:Cg,ATTR_WHITESPACE:vg,DOCTYPE_NAME:Xc,CUSTOM_ELEMENT:kg});const Nr={element:1,attribute:2,text:3,cdataSection:4,entityReference:5,entityNode:6,progressingInstruction:7,comment:8,document:9,documentType:10,documentFragment:11,notation:12},wg=function(){return typeof window>"u"?null:window},Tg=function(e,r){if(typeof e!="object"||typeof e.createPolicy!="function")return null;let i=null;const n="data-tt-policy-suffix";r&&r.hasAttribute(n)&&(i=r.getAttribute(n));const a="dompurify"+(i?"#"+i:"");try{return e.createPolicy(a,{createHTML(s){return s},createScriptURL(s){return s}})}catch{return console.warn("TrustedTypes policy "+a+" could not be created."),null}};function Zc(){let t=arguments.length>0&&arguments[0]!==void 0?arguments[0]:wg();const e=z=>Zc(z);if(e.version="3.1.5",e.removed=[],!t||!t.document||t.document.nodeType!==Nr.document)return e.isSupported=!1,e;let{document:r}=t;const i=r,n=i.currentScript,{DocumentFragment:a,HTMLTemplateElement:s,Node:o,Element:l,NodeFilter:c,NamedNodeMap:h=t.NamedNodeMap||t.MozNamedAttrMap,HTMLFormElement:f,DOMParser:u,trustedTypes:p}=t,g=l.prototype,m=Zi(g,"cloneNode"),_=Zi(g,"nextSibling"),C=Zi(g,"childNodes"),x=Zi(g,"parentNode");if(typeof s=="function"){const z=r.createElement("template");z.content&&z.content.ownerDocument&&(r=z.content.ownerDocument)}let v,B="";const{implementation:$,createNodeIterator:O,createDocumentFragment:E,getElementsByTagName:G}=r,{importNode:Z}=i;let R={};e.isSupported=typeof Yc=="function"&&typeof x=="function"&&$&&$.createHTMLDocument!==void 0;const{MUSTACHE_EXPR:D,ERB_EXPR:lt,TMPLIT_EXPR:st,DATA_ATTR:M,ARIA_ATTR:L,IS_SCRIPT_OR_DATA:T,ATTR_WHITESPACE:F,CUSTOM_ELEMENT:S}=Cl;let{IS_ALLOWED_URI:H}=Cl,I=null;const J=X({},[...yl,...Ia,...Ra,...Da,...xl]);let Y=null;const ct=X({},[...bl,...Pa,..._l,...Ki]);let V=Object.seal(Gc(null,{tagNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},attributeNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},allowCustomizedBuiltInElements:{writable:!0,configurable:!1,enumerable:!0,value:!1}})),gt=null,ie=null,ne=!0,me=!0,ae=!1,xt=!0,Et=!1,ye=!0,Gt=!1,La=!1,Aa=!1,ar=!1,Hi=!1,ji=!1,Go=!0,Vo=!1;const Np="user-content-";let Ba=!0,Fr=!1,sr={},or=null;const Xo=X({},["annotation-xml","audio","colgroup","desc","foreignobject","head","iframe","math","mi","mn","mo","ms","mtext","noembed","noframes","noscript","plaintext","script","style","svg","template","thead","title","video","xmp"]);let Zo=null;const Ko=X({},["audio","video","img","source","image","track"]);let Ea=null;const Qo=X({},["alt","class","for","id","label","name","pattern","placeholder","role","summary","title","value","style","xmlns"]),Ui="http://www.w3.org/1998/Math/MathML",Yi="http://www.w3.org/2000/svg",xe="http://www.w3.org/1999/xhtml";let lr=xe,Ma=!1,Fa=null;const zp=X({},[Ui,Yi,xe],Oa);let $r=null;const qp=["application/xhtml+xml","text/html"],Wp="text/html";let mt=null,cr=null;const Hp=r.createElement("form"),Jo=function(y){return y instanceof RegExp||y instanceof Function},$a=function(){let y=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{};if(!(cr&&cr===y)){if((!y||typeof y!="object")&&(y={}),y=Ne(y),$r=qp.indexOf(y.PARSER_MEDIA_TYPE)===-1?Wp:y.PARSER_MEDIA_TYPE,mt=$r==="application/xhtml+xml"?Oa:cn,I=Kt(y,"ALLOWED_TAGS")?X({},y.ALLOWED_TAGS,mt):J,Y=Kt(y,"ALLOWED_ATTR")?X({},y.ALLOWED_ATTR,mt):ct,Fa=Kt(y,"ALLOWED_NAMESPACES")?X({},y.ALLOWED_NAMESPACES,Oa):zp,Ea=Kt(y,"ADD_URI_SAFE_ATTR")?X(Ne(Qo),y.ADD_URI_SAFE_ATTR,mt):Qo,Zo=Kt(y,"ADD_DATA_URI_TAGS")?X(Ne(Ko),y.ADD_DATA_URI_TAGS,mt):Ko,or=Kt(y,"FORBID_CONTENTS")?X({},y.FORBID_CONTENTS,mt):Xo,gt=Kt(y,"FORBID_TAGS")?X({},y.FORBID_TAGS,mt):{},ie=Kt(y,"FORBID_ATTR")?X({},y.FORBID_ATTR,mt):{},sr=Kt(y,"USE_PROFILES")?y.USE_PROFILES:!1,ne=y.ALLOW_ARIA_ATTR!==!1,me=y.ALLOW_DATA_ATTR!==!1,ae=y.ALLOW_UNKNOWN_PROTOCOLS||!1,xt=y.ALLOW_SELF_CLOSE_IN_ATTR!==!1,Et=y.SAFE_FOR_TEMPLATES||!1,ye=y.SAFE_FOR_XML!==!1,Gt=y.WHOLE_DOCUMENT||!1,ar=y.RETURN_DOM||!1,Hi=y.RETURN_DOM_FRAGMENT||!1,ji=y.RETURN_TRUSTED_TYPE||!1,Aa=y.FORCE_BODY||!1,Go=y.SANITIZE_DOM!==!1,Vo=y.SANITIZE_NAMED_PROPS||!1,Ba=y.KEEP_CONTENT!==!1,Fr=y.IN_PLACE||!1,H=y.ALLOWED_URI_REGEXP||Vc,lr=y.NAMESPACE||xe,V=y.CUSTOM_ELEMENT_HANDLING||{},y.CUSTOM_ELEMENT_HANDLING&&Jo(y.CUSTOM_ELEMENT_HANDLING.tagNameCheck)&&(V.tagNameCheck=y.CUSTOM_ELEMENT_HANDLING.tagNameCheck),y.CUSTOM_ELEMENT_HANDLING&&Jo(y.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)&&(V.attributeNameCheck=y.CUSTOM_ELEMENT_HANDLING.attributeNameCheck),y.CUSTOM_ELEMENT_HANDLING&&typeof y.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements=="boolean"&&(V.allowCustomizedBuiltInElements=y.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements),Et&&(me=!1),Hi&&(ar=!0),sr&&(I=X({},xl),Y=[],sr.html===!0&&(X(I,yl),X(Y,bl)),sr.svg===!0&&(X(I,Ia),X(Y,Pa),X(Y,Ki)),sr.svgFilters===!0&&(X(I,Ra),X(Y,Pa),X(Y,Ki)),sr.mathMl===!0&&(X(I,Da),X(Y,_l),X(Y,Ki))),y.ADD_TAGS&&(I===J&&(I=Ne(I)),X(I,y.ADD_TAGS,mt)),y.ADD_ATTR&&(Y===ct&&(Y=Ne(Y)),X(Y,y.ADD_ATTR,mt)),y.ADD_URI_SAFE_ATTR&&X(Ea,y.ADD_URI_SAFE_ATTR,mt),y.FORBID_CONTENTS&&(or===Xo&&(or=Ne(or)),X(or,y.FORBID_CONTENTS,mt)),Ba&&(I["#text"]=!0),Gt&&X(I,["html","head","body"]),I.table&&(X(I,["tbody"]),delete gt.tbody),y.TRUSTED_TYPES_POLICY){if(typeof y.TRUSTED_TYPES_POLICY.createHTML!="function")throw Pr('TRUSTED_TYPES_POLICY configuration option must provide a "createHTML" hook.');if(typeof y.TRUSTED_TYPES_POLICY.createScriptURL!="function")throw Pr('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.');v=y.TRUSTED_TYPES_POLICY,B=v.createHTML("")}else v===void 0&&(v=Tg(p,n)),v!==null&&typeof B=="string"&&(B=v.createHTML(""));It&&It(y),cr=y}},tl=X({},["mi","mo","mn","ms","mtext"]),el=X({},["foreignobject","annotation-xml"]),jp=X({},["title","style","font","a","script"]),rl=X({},[...Ia,...Ra,...pg]),il=X({},[...Da,...gg]),Up=function(y){let w=x(y);(!w||!w.tagName)&&(w={namespaceURI:lr,tagName:"template"});const P=cn(y.tagName),et=cn(w.tagName);return Fa[y.namespaceURI]?y.namespaceURI===Yi?w.namespaceURI===xe?P==="svg":w.namespaceURI===Ui?P==="svg"&&(et==="annotation-xml"||tl[et]):!!rl[P]:y.namespaceURI===Ui?w.namespaceURI===xe?P==="math":w.namespaceURI===Yi?P==="math"&&el[et]:!!il[P]:y.namespaceURI===xe?w.namespaceURI===Yi&&!el[et]||w.namespaceURI===Ui&&!tl[et]?!1:!il[P]&&(jp[P]||!rl[P]):!!($r==="application/xhtml+xml"&&Fa[y.namespaceURI]):!1},se=function(y){Rr(e.removed,{element:y});try{y.parentNode.removeChild(y)}catch{y.remove()}},Gi=function(y,w){try{Rr(e.removed,{attribute:w.getAttributeNode(y),from:w})}catch{Rr(e.removed,{attribute:null,from:w})}if(w.removeAttribute(y),y==="is"&&!Y[y])if(ar||Hi)try{se(w)}catch{}else try{w.setAttribute(y,"")}catch{}},nl=function(y){let w=null,P=null;if(Aa)y=""+y;else{const bt=ml(y,/^[\r\n\t ]+/);P=bt&&bt[0]}$r==="application/xhtml+xml"&&lr===xe&&(y=''+y+"");const et=v?v.createHTML(y):y;if(lr===xe)try{w=new u().parseFromString(et,$r)}catch{}if(!w||!w.documentElement){w=$.createDocument(lr,"template",null);try{w.documentElement.innerHTML=Ma?B:et}catch{}}const kt=w.body||w.documentElement;return y&&P&&kt.insertBefore(r.createTextNode(P),kt.childNodes[0]||null),lr===xe?G.call(w,Gt?"html":"body")[0]:Gt?w.documentElement:kt},al=function(y){return O.call(y.ownerDocument||y,y,c.SHOW_ELEMENT|c.SHOW_COMMENT|c.SHOW_TEXT|c.SHOW_PROCESSING_INSTRUCTION|c.SHOW_CDATA_SECTION,null)},sl=function(y){return y instanceof f&&(typeof y.nodeName!="string"||typeof y.textContent!="string"||typeof y.removeChild!="function"||!(y.attributes instanceof h)||typeof y.removeAttribute!="function"||typeof y.setAttribute!="function"||typeof y.namespaceURI!="string"||typeof y.insertBefore!="function"||typeof y.hasChildNodes!="function")},ol=function(y){return typeof o=="function"&&y instanceof o},be=function(y,w,P){R[y]&&Xi(R[y],et=>{et.call(e,w,P,cr)})},ll=function(y){let w=null;if(be("beforeSanitizeElements",y,null),sl(y))return se(y),!0;const P=mt(y.nodeName);if(be("uponSanitizeElement",y,{tagName:P,allowedTags:I}),y.hasChildNodes()&&!ol(y.firstElementChild)&&Ft(/<[/\w]/g,y.innerHTML)&&Ft(/<[/\w]/g,y.textContent)||y.nodeType===Nr.progressingInstruction||ye&&y.nodeType===Nr.comment&&Ft(/<[/\w]/g,y.data))return se(y),!0;if(!I[P]||gt[P]){if(!gt[P]&&hl(P)&&(V.tagNameCheck instanceof RegExp&&Ft(V.tagNameCheck,P)||V.tagNameCheck instanceof Function&&V.tagNameCheck(P)))return!1;if(Ba&&!or[P]){const et=x(y)||y.parentNode,kt=C(y)||y.childNodes;if(kt&&et){const bt=kt.length;for(let Rt=bt-1;Rt>=0;--Rt){const oe=m(kt[Rt],!0);oe.__removalCount=(y.__removalCount||0)+1,et.insertBefore(oe,_(y))}}}return se(y),!0}return y instanceof l&&!Up(y)||(P==="noscript"||P==="noembed"||P==="noframes")&&Ft(/<\/no(script|embed|frames)/i,y.innerHTML)?(se(y),!0):(Et&&y.nodeType===Nr.text&&(w=y.textContent,Xi([D,lt,st],et=>{w=Dr(w,et," ")}),y.textContent!==w&&(Rr(e.removed,{element:y.cloneNode()}),y.textContent=w)),be("afterSanitizeElements",y,null),!1)},cl=function(y,w,P){if(Go&&(w==="id"||w==="name")&&(P in r||P in Hp))return!1;if(!(me&&!ie[w]&&Ft(M,w))){if(!(ne&&Ft(L,w))){if(!Y[w]||ie[w]){if(!(hl(y)&&(V.tagNameCheck instanceof RegExp&&Ft(V.tagNameCheck,y)||V.tagNameCheck instanceof Function&&V.tagNameCheck(y))&&(V.attributeNameCheck instanceof RegExp&&Ft(V.attributeNameCheck,w)||V.attributeNameCheck instanceof Function&&V.attributeNameCheck(w))||w==="is"&&V.allowCustomizedBuiltInElements&&(V.tagNameCheck instanceof RegExp&&Ft(V.tagNameCheck,P)||V.tagNameCheck instanceof Function&&V.tagNameCheck(P))))return!1}else if(!Ea[w]){if(!Ft(H,Dr(P,F,""))){if(!((w==="src"||w==="xlink:href"||w==="href")&&y!=="script"&&hg(P,"data:")===0&&Zo[y])){if(!(ae&&!Ft(T,Dr(P,F,"")))){if(P)return!1}}}}}}return!0},hl=function(y){return y!=="annotation-xml"&&ml(y,S)},ul=function(y){be("beforeSanitizeAttributes",y,null);const{attributes:w}=y;if(!w)return;const P={attrName:"",attrValue:"",keepAttr:!0,allowedAttributes:Y};let et=w.length;for(;et--;){const kt=w[et],{name:bt,namespaceURI:Rt,value:oe}=kt,Or=mt(bt);let Mt=bt==="value"?oe:ug(oe);if(P.attrName=Or,P.attrValue=Mt,P.keepAttr=!0,P.forceKeepAttr=void 0,be("uponSanitizeAttribute",y,P),Mt=P.attrValue,P.forceKeepAttr||(Gi(bt,y),!P.keepAttr))continue;if(!xt&&Ft(/\/>/i,Mt)){Gi(bt,y);continue}if(ye&&Ft(/((--!?|])>)|<\/(style|title)/i,Mt)){Gi(bt,y);continue}Et&&Xi([D,lt,st],dl=>{Mt=Dr(Mt,dl," ")});const fl=mt(y.nodeName);if(cl(fl,Or,Mt)){if(Vo&&(Or==="id"||Or==="name")&&(Gi(bt,y),Mt=Np+Mt),v&&typeof p=="object"&&typeof p.getAttributeType=="function"&&!Rt)switch(p.getAttributeType(fl,Or)){case"TrustedHTML":{Mt=v.createHTML(Mt);break}case"TrustedScriptURL":{Mt=v.createScriptURL(Mt);break}}try{Rt?y.setAttributeNS(Rt,bt,Mt):y.setAttribute(bt,Mt),sl(y)?se(y):gl(e.removed)}catch{}}}be("afterSanitizeAttributes",y,null)},Yp=function z(y){let w=null;const P=al(y);for(be("beforeSanitizeShadowDOM",y,null);w=P.nextNode();)be("uponSanitizeShadowNode",w,null),!ll(w)&&(w.content instanceof a&&z(w.content),ul(w));be("afterSanitizeShadowDOM",y,null)};return e.sanitize=function(z){let y=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{},w=null,P=null,et=null,kt=null;if(Ma=!z,Ma&&(z=""),typeof z!="string"&&!ol(z))if(typeof z.toString=="function"){if(z=z.toString(),typeof z!="string")throw Pr("dirty is not a string, aborting")}else throw Pr("toString is not a function");if(!e.isSupported)return z;if(La||$a(y),e.removed=[],typeof z=="string"&&(Fr=!1),Fr){if(z.nodeName){const oe=mt(z.nodeName);if(!I[oe]||gt[oe])throw Pr("root node is forbidden and cannot be sanitized in-place")}}else if(z instanceof o)w=nl(""),P=w.ownerDocument.importNode(z,!0),P.nodeType===Nr.element&&P.nodeName==="BODY"||P.nodeName==="HTML"?w=P:w.appendChild(P);else{if(!ar&&!Et&&!Gt&&z.indexOf("<")===-1)return v&&ji?v.createHTML(z):z;if(w=nl(z),!w)return ar?null:ji?B:""}w&&Aa&&se(w.firstChild);const bt=al(Fr?z:w);for(;et=bt.nextNode();)ll(et)||(et.content instanceof a&&Yp(et.content),ul(et));if(Fr)return z;if(ar){if(Hi)for(kt=E.call(w.ownerDocument);w.firstChild;)kt.appendChild(w.firstChild);else kt=w;return(Y.shadowroot||Y.shadowrootmode)&&(kt=Z.call(i,kt,!0)),kt}let Rt=Gt?w.outerHTML:w.innerHTML;return Gt&&I["!doctype"]&&w.ownerDocument&&w.ownerDocument.doctype&&w.ownerDocument.doctype.name&&Ft(Xc,w.ownerDocument.doctype.name)&&(Rt="
                                      +var Gp=Object.defineProperty;var Vp=(t,e,r)=>e in t?Gp(t,e,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[e]=r;var rt=(t,e,r)=>(Vp(t,typeof e!="symbol"?e+"":e,r),r),Xp=(t,e,r)=>{if(!e.has(t))throw TypeError("Cannot "+r)};var Vi=(t,e,r)=>{if(e.has(t))throw TypeError("Cannot add the same private member more than once");e instanceof WeakSet?e.add(t):e.set(t,r)};var Ir=(t,e,r)=>(Xp(t,e,"access private method"),r);import{h as at}from"./app-D7uBbsY3.js";var Zp=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{};function Kp(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}var Hc={exports:{}};(function(t,e){(function(r,i){t.exports=i()})(Zp,function(){var r=1e3,i=6e4,n=36e5,a="millisecond",s="second",o="minute",l="hour",c="day",h="week",f="month",u="quarter",p="year",g="date",m="Invalid Date",_=/^(\d{4})[-/]?(\d{1,2})?[-/]?(\d{0,2})[Tt\s]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?[.:]?(\d+)?$/,C=/\[([^\]]+)]|Y{1,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g,x={name:"en",weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),ordinal:function(M){var L=["th","st","nd","rd"],T=M%100;return"["+M+(L[(T-20)%10]||L[T]||L[0])+"]"}},v=function(M,L,T){var F=String(M);return!F||F.length>=L?M:""+Array(L+1-F.length).join(T)+M},B={s:v,z:function(M){var L=-M.utcOffset(),T=Math.abs(L),F=Math.floor(T/60),S=T%60;return(L<=0?"+":"-")+v(F,2,"0")+":"+v(S,2,"0")},m:function M(L,T){if(L.date()1)return M(I[0])}else{var J=L.name;O[J]=L,S=J}return!F&&S&&($=S),S||!F&&$},R=function(M,L){if(G(M))return M.clone();var T=typeof L=="object"?L:{};return T.date=M,T.args=arguments,new lt(T)},D=B;D.l=Z,D.i=G,D.w=function(M,L){return R(M,{locale:L.$L,utc:L.$u,x:L.$x,$offset:L.$offset})};var lt=function(){function M(T){this.$L=Z(T.locale,null,!0),this.parse(T),this.$x=this.$x||T.x||{},this[E]=!0}var L=M.prototype;return L.parse=function(T){this.$d=function(F){var S=F.date,H=F.utc;if(S===null)return new Date(NaN);if(D.u(S))return new Date;if(S instanceof Date)return new Date(S);if(typeof S=="string"&&!/Z$/i.test(S)){var I=S.match(_);if(I){var J=I[2]-1||0,Y=(I[7]||"0").substring(0,3);return H?new Date(Date.UTC(I[1],J,I[3]||1,I[4]||0,I[5]||0,I[6]||0,Y)):new Date(I[1],J,I[3]||1,I[4]||0,I[5]||0,I[6]||0,Y)}}return new Date(S)}(T),this.init()},L.init=function(){var T=this.$d;this.$y=T.getFullYear(),this.$M=T.getMonth(),this.$D=T.getDate(),this.$W=T.getDay(),this.$H=T.getHours(),this.$m=T.getMinutes(),this.$s=T.getSeconds(),this.$ms=T.getMilliseconds()},L.$utils=function(){return D},L.isValid=function(){return this.$d.toString()!==m},L.isSame=function(T,F){var S=R(T);return this.startOf(F)<=S&&S<=this.endOf(F)},L.isAfter=function(T,F){return R(T)t>=255?255:t<0?0:t,g:t=>t>=255?255:t<0?0:t,b:t=>t>=255?255:t<0?0:t,h:t=>t%360,s:t=>t>=100?100:t<0?0:t,l:t=>t>=100?100:t<0?0:t,a:t=>t>=1?1:t<0?0:t},toLinear:t=>{const e=t/255;return t>.03928?Math.pow((e+.055)/1.055,2.4):e/12.92},hue2rgb:(t,e,r)=>(r<0&&(r+=1),r>1&&(r-=1),r<1/6?t+(e-t)*6*r:r<1/2?e:r<2/3?t+(e-t)*(2/3-r)*6:t),hsl2rgb:({h:t,s:e,l:r},i)=>{if(!e)return r*2.55;t/=360,e/=100,r/=100;const n=r<.5?r*(1+e):r+e-r*e,a=2*r-n;switch(i){case"r":return ln.hue2rgb(a,n,t+1/3)*255;case"g":return ln.hue2rgb(a,n,t)*255;case"b":return ln.hue2rgb(a,n,t-1/3)*255}},rgb2hsl:({r:t,g:e,b:r},i)=>{t/=255,e/=255,r/=255;const n=Math.max(t,e,r),a=Math.min(t,e,r),s=(n+a)/2;if(i==="l")return s*100;if(n===a)return 0;const o=n-a,l=s>.5?o/(2-n-a):o/(n+a);if(i==="s")return l*100;switch(n){case t:return((e-r)/o+(ee>r?Math.min(e,Math.max(r,t)):Math.min(r,Math.max(e,t)),round:t=>Math.round(t*1e10)/1e10},eg={dec2hex:t=>{const e=Math.round(t).toString(16);return e.length>1?e:`0${e}`}},U={channel:ln,lang:tg,unit:eg},Me={};for(let t=0;t<=255;t++)Me[t]=U.unit.dec2hex(t);const wt={ALL:0,RGB:1,HSL:2};class rg{constructor(){this.type=wt.ALL}get(){return this.type}set(e){if(this.type&&this.type!==e)throw new Error("Cannot change both RGB and HSL channels at the same time");this.type=e}reset(){this.type=wt.ALL}is(e){return this.type===e}}class ig{constructor(e,r){this.color=r,this.changed=!1,this.data=e,this.type=new rg}set(e,r){return this.color=r,this.changed=!1,this.data=e,this.type.type=wt.ALL,this}_ensureHSL(){const e=this.data,{h:r,s:i,l:n}=e;r===void 0&&(e.h=U.channel.rgb2hsl(e,"h")),i===void 0&&(e.s=U.channel.rgb2hsl(e,"s")),n===void 0&&(e.l=U.channel.rgb2hsl(e,"l"))}_ensureRGB(){const e=this.data,{r,g:i,b:n}=e;r===void 0&&(e.r=U.channel.hsl2rgb(e,"r")),i===void 0&&(e.g=U.channel.hsl2rgb(e,"g")),n===void 0&&(e.b=U.channel.hsl2rgb(e,"b"))}get r(){const e=this.data,r=e.r;return!this.type.is(wt.HSL)&&r!==void 0?r:(this._ensureHSL(),U.channel.hsl2rgb(e,"r"))}get g(){const e=this.data,r=e.g;return!this.type.is(wt.HSL)&&r!==void 0?r:(this._ensureHSL(),U.channel.hsl2rgb(e,"g"))}get b(){const e=this.data,r=e.b;return!this.type.is(wt.HSL)&&r!==void 0?r:(this._ensureHSL(),U.channel.hsl2rgb(e,"b"))}get h(){const e=this.data,r=e.h;return!this.type.is(wt.RGB)&&r!==void 0?r:(this._ensureRGB(),U.channel.rgb2hsl(e,"h"))}get s(){const e=this.data,r=e.s;return!this.type.is(wt.RGB)&&r!==void 0?r:(this._ensureRGB(),U.channel.rgb2hsl(e,"s"))}get l(){const e=this.data,r=e.l;return!this.type.is(wt.RGB)&&r!==void 0?r:(this._ensureRGB(),U.channel.rgb2hsl(e,"l"))}get a(){return this.data.a}set r(e){this.type.set(wt.RGB),this.changed=!0,this.data.r=e}set g(e){this.type.set(wt.RGB),this.changed=!0,this.data.g=e}set b(e){this.type.set(wt.RGB),this.changed=!0,this.data.b=e}set h(e){this.type.set(wt.HSL),this.changed=!0,this.data.h=e}set s(e){this.type.set(wt.HSL),this.changed=!0,this.data.s=e}set l(e){this.type.set(wt.HSL),this.changed=!0,this.data.l=e}set a(e){this.changed=!0,this.data.a=e}}const ia=new ig({r:0,g:0,b:0,a:0},"transparent"),pr={re:/^#((?:[a-f0-9]{2}){2,4}|[a-f0-9]{3})$/i,parse:t=>{if(t.charCodeAt(0)!==35)return;const e=t.match(pr.re);if(!e)return;const r=e[1],i=parseInt(r,16),n=r.length,a=n%4===0,s=n>4,o=s?1:17,l=s?8:4,c=a?0:-1,h=s?255:15;return ia.set({r:(i>>l*(c+3)&h)*o,g:(i>>l*(c+2)&h)*o,b:(i>>l*(c+1)&h)*o,a:a?(i&h)*o/255:1},t)},stringify:t=>{const{r:e,g:r,b:i,a:n}=t;return n<1?`#${Me[Math.round(e)]}${Me[Math.round(r)]}${Me[Math.round(i)]}${Me[Math.round(n*255)]}`:`#${Me[Math.round(e)]}${Me[Math.round(r)]}${Me[Math.round(i)]}`}},He={re:/^hsla?\(\s*?(-?(?:\d+(?:\.\d+)?|(?:\.\d+))(?:e-?\d+)?(?:deg|grad|rad|turn)?)\s*?(?:,|\s)\s*?(-?(?:\d+(?:\.\d+)?|(?:\.\d+))(?:e-?\d+)?%)\s*?(?:,|\s)\s*?(-?(?:\d+(?:\.\d+)?|(?:\.\d+))(?:e-?\d+)?%)(?:\s*?(?:,|\/)\s*?\+?(-?(?:\d+(?:\.\d+)?|(?:\.\d+))(?:e-?\d+)?(%)?))?\s*?\)$/i,hueRe:/^(.+?)(deg|grad|rad|turn)$/i,_hue2deg:t=>{const e=t.match(He.hueRe);if(e){const[,r,i]=e;switch(i){case"grad":return U.channel.clamp.h(parseFloat(r)*.9);case"rad":return U.channel.clamp.h(parseFloat(r)*180/Math.PI);case"turn":return U.channel.clamp.h(parseFloat(r)*360)}}return U.channel.clamp.h(parseFloat(t))},parse:t=>{const e=t.charCodeAt(0);if(e!==104&&e!==72)return;const r=t.match(He.re);if(!r)return;const[,i,n,a,s,o]=r;return ia.set({h:He._hue2deg(i),s:U.channel.clamp.s(parseFloat(n)),l:U.channel.clamp.l(parseFloat(a)),a:s?U.channel.clamp.a(o?parseFloat(s)/100:parseFloat(s)):1},t)},stringify:t=>{const{h:e,s:r,l:i,a:n}=t;return n<1?`hsla(${U.lang.round(e)}, ${U.lang.round(r)}%, ${U.lang.round(i)}%, ${n})`:`hsl(${U.lang.round(e)}, ${U.lang.round(r)}%, ${U.lang.round(i)}%)`}},Jr={colors:{aliceblue:"#f0f8ff",antiquewhite:"#faebd7",aqua:"#00ffff",aquamarine:"#7fffd4",azure:"#f0ffff",beige:"#f5f5dc",bisque:"#ffe4c4",black:"#000000",blanchedalmond:"#ffebcd",blue:"#0000ff",blueviolet:"#8a2be2",brown:"#a52a2a",burlywood:"#deb887",cadetblue:"#5f9ea0",chartreuse:"#7fff00",chocolate:"#d2691e",coral:"#ff7f50",cornflowerblue:"#6495ed",cornsilk:"#fff8dc",crimson:"#dc143c",cyanaqua:"#00ffff",darkblue:"#00008b",darkcyan:"#008b8b",darkgoldenrod:"#b8860b",darkgray:"#a9a9a9",darkgreen:"#006400",darkgrey:"#a9a9a9",darkkhaki:"#bdb76b",darkmagenta:"#8b008b",darkolivegreen:"#556b2f",darkorange:"#ff8c00",darkorchid:"#9932cc",darkred:"#8b0000",darksalmon:"#e9967a",darkseagreen:"#8fbc8f",darkslateblue:"#483d8b",darkslategray:"#2f4f4f",darkslategrey:"#2f4f4f",darkturquoise:"#00ced1",darkviolet:"#9400d3",deeppink:"#ff1493",deepskyblue:"#00bfff",dimgray:"#696969",dimgrey:"#696969",dodgerblue:"#1e90ff",firebrick:"#b22222",floralwhite:"#fffaf0",forestgreen:"#228b22",fuchsia:"#ff00ff",gainsboro:"#dcdcdc",ghostwhite:"#f8f8ff",gold:"#ffd700",goldenrod:"#daa520",gray:"#808080",green:"#008000",greenyellow:"#adff2f",grey:"#808080",honeydew:"#f0fff0",hotpink:"#ff69b4",indianred:"#cd5c5c",indigo:"#4b0082",ivory:"#fffff0",khaki:"#f0e68c",lavender:"#e6e6fa",lavenderblush:"#fff0f5",lawngreen:"#7cfc00",lemonchiffon:"#fffacd",lightblue:"#add8e6",lightcoral:"#f08080",lightcyan:"#e0ffff",lightgoldenrodyellow:"#fafad2",lightgray:"#d3d3d3",lightgreen:"#90ee90",lightgrey:"#d3d3d3",lightpink:"#ffb6c1",lightsalmon:"#ffa07a",lightseagreen:"#20b2aa",lightskyblue:"#87cefa",lightslategray:"#778899",lightslategrey:"#778899",lightsteelblue:"#b0c4de",lightyellow:"#ffffe0",lime:"#00ff00",limegreen:"#32cd32",linen:"#faf0e6",magenta:"#ff00ff",maroon:"#800000",mediumaquamarine:"#66cdaa",mediumblue:"#0000cd",mediumorchid:"#ba55d3",mediumpurple:"#9370db",mediumseagreen:"#3cb371",mediumslateblue:"#7b68ee",mediumspringgreen:"#00fa9a",mediumturquoise:"#48d1cc",mediumvioletred:"#c71585",midnightblue:"#191970",mintcream:"#f5fffa",mistyrose:"#ffe4e1",moccasin:"#ffe4b5",navajowhite:"#ffdead",navy:"#000080",oldlace:"#fdf5e6",olive:"#808000",olivedrab:"#6b8e23",orange:"#ffa500",orangered:"#ff4500",orchid:"#da70d6",palegoldenrod:"#eee8aa",palegreen:"#98fb98",paleturquoise:"#afeeee",palevioletred:"#db7093",papayawhip:"#ffefd5",peachpuff:"#ffdab9",peru:"#cd853f",pink:"#ffc0cb",plum:"#dda0dd",powderblue:"#b0e0e6",purple:"#800080",rebeccapurple:"#663399",red:"#ff0000",rosybrown:"#bc8f8f",royalblue:"#4169e1",saddlebrown:"#8b4513",salmon:"#fa8072",sandybrown:"#f4a460",seagreen:"#2e8b57",seashell:"#fff5ee",sienna:"#a0522d",silver:"#c0c0c0",skyblue:"#87ceeb",slateblue:"#6a5acd",slategray:"#708090",slategrey:"#708090",snow:"#fffafa",springgreen:"#00ff7f",tan:"#d2b48c",teal:"#008080",thistle:"#d8bfd8",transparent:"#00000000",turquoise:"#40e0d0",violet:"#ee82ee",wheat:"#f5deb3",white:"#ffffff",whitesmoke:"#f5f5f5",yellow:"#ffff00",yellowgreen:"#9acd32"},parse:t=>{t=t.toLowerCase();const e=Jr.colors[t];if(e)return pr.parse(e)},stringify:t=>{const e=pr.stringify(t);for(const r in Jr.colors)if(Jr.colors[r]===e)return r}},Gr={re:/^rgba?\(\s*?(-?(?:\d+(?:\.\d+)?|(?:\.\d+))(?:e\d+)?(%?))\s*?(?:,|\s)\s*?(-?(?:\d+(?:\.\d+)?|(?:\.\d+))(?:e\d+)?(%?))\s*?(?:,|\s)\s*?(-?(?:\d+(?:\.\d+)?|(?:\.\d+))(?:e\d+)?(%?))(?:\s*?(?:,|\/)\s*?\+?(-?(?:\d+(?:\.\d+)?|(?:\.\d+))(?:e\d+)?(%?)))?\s*?\)$/i,parse:t=>{const e=t.charCodeAt(0);if(e!==114&&e!==82)return;const r=t.match(Gr.re);if(!r)return;const[,i,n,a,s,o,l,c,h]=r;return ia.set({r:U.channel.clamp.r(n?parseFloat(i)*2.55:parseFloat(i)),g:U.channel.clamp.g(s?parseFloat(a)*2.55:parseFloat(a)),b:U.channel.clamp.b(l?parseFloat(o)*2.55:parseFloat(o)),a:c?U.channel.clamp.a(h?parseFloat(c)/100:parseFloat(c)):1},t)},stringify:t=>{const{r:e,g:r,b:i,a:n}=t;return n<1?`rgba(${U.lang.round(e)}, ${U.lang.round(r)}, ${U.lang.round(i)}, ${U.lang.round(n)})`:`rgb(${U.lang.round(e)}, ${U.lang.round(r)}, ${U.lang.round(i)})`}},fe={format:{keyword:Jr,hex:pr,rgb:Gr,rgba:Gr,hsl:He,hsla:He},parse:t=>{if(typeof t!="string")return t;const e=pr.parse(t)||Gr.parse(t)||He.parse(t)||Jr.parse(t);if(e)return e;throw new Error(`Unsupported color format: "${t}"`)},stringify:t=>!t.changed&&t.color?t.color:t.type.is(wt.HSL)||t.data.r===void 0?He.stringify(t):t.a<1||!Number.isInteger(t.r)||!Number.isInteger(t.g)||!Number.isInteger(t.b)?Gr.stringify(t):pr.stringify(t)},jc=(t,e)=>{const r=fe.parse(t);for(const i in e)r[i]=U.channel.clamp[i](e[i]);return fe.stringify(r)},ti=(t,e,r=0,i=1)=>{if(typeof t!="number")return jc(t,{a:e});const n=ia.set({r:U.channel.clamp.r(t),g:U.channel.clamp.g(e),b:U.channel.clamp.b(r),a:U.channel.clamp.a(i)});return fe.stringify(n)},ng=t=>{const{r:e,g:r,b:i}=fe.parse(t),n=.2126*U.channel.toLinear(e)+.7152*U.channel.toLinear(r)+.0722*U.channel.toLinear(i);return U.lang.round(n)},ag=t=>ng(t)>=.5,Mi=t=>!ag(t),Uc=(t,e,r)=>{const i=fe.parse(t),n=i[e],a=U.channel.clamp[e](n+r);return n!==a&&(i[e]=a),fe.stringify(i)},q=(t,e)=>Uc(t,"l",e),W=(t,e)=>Uc(t,"l",-e),b=(t,e)=>{const r=fe.parse(t),i={};for(const n in e)e[n]&&(i[n]=r[n]+e[n]);return jc(t,i)},sg=(t,e,r=50)=>{const{r:i,g:n,b:a,a:s}=fe.parse(t),{r:o,g:l,b:c,a:h}=fe.parse(e),f=r/100,u=f*2-1,p=s-h,m=((u*p===-1?u:(u+p)/(1+u*p))+1)/2,_=1-m,C=i*m+o*_,x=n*m+l*_,v=a*m+c*_,B=s*f+h*(1-f);return ti(C,x,v,B)},A=(t,e=100)=>{const r=fe.parse(t);return r.r=255-r.r,r.g=255-r.g,r.b=255-r.b,sg(r,t,e)};/*! @license DOMPurify 3.1.5 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.1.5/LICENSE */const{entries:Yc,setPrototypeOf:pl,isFrozen:og,getPrototypeOf:lg,getOwnPropertyDescriptor:cg}=Object;let{freeze:It,seal:Xt,create:Gc}=Object,{apply:Qa,construct:Ja}=typeof Reflect<"u"&&Reflect;It||(It=function(e){return e});Xt||(Xt=function(e){return e});Qa||(Qa=function(e,r,i){return e.apply(r,i)});Ja||(Ja=function(e,r){return new e(...r)});const Xi=jt(Array.prototype.forEach),gl=jt(Array.prototype.pop),Rr=jt(Array.prototype.push),cn=jt(String.prototype.toLowerCase),Oa=jt(String.prototype.toString),ml=jt(String.prototype.match),Dr=jt(String.prototype.replace),hg=jt(String.prototype.indexOf),ug=jt(String.prototype.trim),Kt=jt(Object.prototype.hasOwnProperty),Ft=jt(RegExp.prototype.test),Pr=fg(TypeError);function jt(t){return function(e){for(var r=arguments.length,i=new Array(r>1?r-1:0),n=1;n2&&arguments[2]!==void 0?arguments[2]:cn;pl&&pl(t,null);let i=e.length;for(;i--;){let n=e[i];if(typeof n=="string"){const a=r(n);a!==n&&(og(e)||(e[i]=a),n=a)}t[n]=!0}return t}function dg(t){for(let e=0;e/gm),xg=Xt(/\${[\w\W]*}/gm),bg=Xt(/^data-[\-\w.\u00B7-\uFFFF]/),_g=Xt(/^aria-[\-\w]+$/),Vc=Xt(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i),Cg=Xt(/^(?:\w+script|data):/i),vg=Xt(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g),Xc=Xt(/^html$/i),kg=Xt(/^[a-z][.\w]*(-[.\w]+)+$/i);var Cl=Object.freeze({__proto__:null,MUSTACHE_EXPR:mg,ERB_EXPR:yg,TMPLIT_EXPR:xg,DATA_ATTR:bg,ARIA_ATTR:_g,IS_ALLOWED_URI:Vc,IS_SCRIPT_OR_DATA:Cg,ATTR_WHITESPACE:vg,DOCTYPE_NAME:Xc,CUSTOM_ELEMENT:kg});const Nr={element:1,attribute:2,text:3,cdataSection:4,entityReference:5,entityNode:6,progressingInstruction:7,comment:8,document:9,documentType:10,documentFragment:11,notation:12},wg=function(){return typeof window>"u"?null:window},Tg=function(e,r){if(typeof e!="object"||typeof e.createPolicy!="function")return null;let i=null;const n="data-tt-policy-suffix";r&&r.hasAttribute(n)&&(i=r.getAttribute(n));const a="dompurify"+(i?"#"+i:"");try{return e.createPolicy(a,{createHTML(s){return s},createScriptURL(s){return s}})}catch{return console.warn("TrustedTypes policy "+a+" could not be created."),null}};function Zc(){let t=arguments.length>0&&arguments[0]!==void 0?arguments[0]:wg();const e=z=>Zc(z);if(e.version="3.1.5",e.removed=[],!t||!t.document||t.document.nodeType!==Nr.document)return e.isSupported=!1,e;let{document:r}=t;const i=r,n=i.currentScript,{DocumentFragment:a,HTMLTemplateElement:s,Node:o,Element:l,NodeFilter:c,NamedNodeMap:h=t.NamedNodeMap||t.MozNamedAttrMap,HTMLFormElement:f,DOMParser:u,trustedTypes:p}=t,g=l.prototype,m=Zi(g,"cloneNode"),_=Zi(g,"nextSibling"),C=Zi(g,"childNodes"),x=Zi(g,"parentNode");if(typeof s=="function"){const z=r.createElement("template");z.content&&z.content.ownerDocument&&(r=z.content.ownerDocument)}let v,B="";const{implementation:$,createNodeIterator:O,createDocumentFragment:E,getElementsByTagName:G}=r,{importNode:Z}=i;let R={};e.isSupported=typeof Yc=="function"&&typeof x=="function"&&$&&$.createHTMLDocument!==void 0;const{MUSTACHE_EXPR:D,ERB_EXPR:lt,TMPLIT_EXPR:st,DATA_ATTR:M,ARIA_ATTR:L,IS_SCRIPT_OR_DATA:T,ATTR_WHITESPACE:F,CUSTOM_ELEMENT:S}=Cl;let{IS_ALLOWED_URI:H}=Cl,I=null;const J=X({},[...yl,...Ia,...Ra,...Da,...xl]);let Y=null;const ct=X({},[...bl,...Pa,..._l,...Ki]);let V=Object.seal(Gc(null,{tagNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},attributeNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},allowCustomizedBuiltInElements:{writable:!0,configurable:!1,enumerable:!0,value:!1}})),gt=null,ie=null,ne=!0,me=!0,ae=!1,xt=!0,Et=!1,ye=!0,Gt=!1,La=!1,Aa=!1,ar=!1,Hi=!1,ji=!1,Go=!0,Vo=!1;const Np="user-content-";let Ba=!0,Fr=!1,sr={},or=null;const Xo=X({},["annotation-xml","audio","colgroup","desc","foreignobject","head","iframe","math","mi","mn","mo","ms","mtext","noembed","noframes","noscript","plaintext","script","style","svg","template","thead","title","video","xmp"]);let Zo=null;const Ko=X({},["audio","video","img","source","image","track"]);let Ea=null;const Qo=X({},["alt","class","for","id","label","name","pattern","placeholder","role","summary","title","value","style","xmlns"]),Ui="http://www.w3.org/1998/Math/MathML",Yi="http://www.w3.org/2000/svg",xe="http://www.w3.org/1999/xhtml";let lr=xe,Ma=!1,Fa=null;const zp=X({},[Ui,Yi,xe],Oa);let $r=null;const qp=["application/xhtml+xml","text/html"],Wp="text/html";let mt=null,cr=null;const Hp=r.createElement("form"),Jo=function(y){return y instanceof RegExp||y instanceof Function},$a=function(){let y=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{};if(!(cr&&cr===y)){if((!y||typeof y!="object")&&(y={}),y=Ne(y),$r=qp.indexOf(y.PARSER_MEDIA_TYPE)===-1?Wp:y.PARSER_MEDIA_TYPE,mt=$r==="application/xhtml+xml"?Oa:cn,I=Kt(y,"ALLOWED_TAGS")?X({},y.ALLOWED_TAGS,mt):J,Y=Kt(y,"ALLOWED_ATTR")?X({},y.ALLOWED_ATTR,mt):ct,Fa=Kt(y,"ALLOWED_NAMESPACES")?X({},y.ALLOWED_NAMESPACES,Oa):zp,Ea=Kt(y,"ADD_URI_SAFE_ATTR")?X(Ne(Qo),y.ADD_URI_SAFE_ATTR,mt):Qo,Zo=Kt(y,"ADD_DATA_URI_TAGS")?X(Ne(Ko),y.ADD_DATA_URI_TAGS,mt):Ko,or=Kt(y,"FORBID_CONTENTS")?X({},y.FORBID_CONTENTS,mt):Xo,gt=Kt(y,"FORBID_TAGS")?X({},y.FORBID_TAGS,mt):{},ie=Kt(y,"FORBID_ATTR")?X({},y.FORBID_ATTR,mt):{},sr=Kt(y,"USE_PROFILES")?y.USE_PROFILES:!1,ne=y.ALLOW_ARIA_ATTR!==!1,me=y.ALLOW_DATA_ATTR!==!1,ae=y.ALLOW_UNKNOWN_PROTOCOLS||!1,xt=y.ALLOW_SELF_CLOSE_IN_ATTR!==!1,Et=y.SAFE_FOR_TEMPLATES||!1,ye=y.SAFE_FOR_XML!==!1,Gt=y.WHOLE_DOCUMENT||!1,ar=y.RETURN_DOM||!1,Hi=y.RETURN_DOM_FRAGMENT||!1,ji=y.RETURN_TRUSTED_TYPE||!1,Aa=y.FORCE_BODY||!1,Go=y.SANITIZE_DOM!==!1,Vo=y.SANITIZE_NAMED_PROPS||!1,Ba=y.KEEP_CONTENT!==!1,Fr=y.IN_PLACE||!1,H=y.ALLOWED_URI_REGEXP||Vc,lr=y.NAMESPACE||xe,V=y.CUSTOM_ELEMENT_HANDLING||{},y.CUSTOM_ELEMENT_HANDLING&&Jo(y.CUSTOM_ELEMENT_HANDLING.tagNameCheck)&&(V.tagNameCheck=y.CUSTOM_ELEMENT_HANDLING.tagNameCheck),y.CUSTOM_ELEMENT_HANDLING&&Jo(y.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)&&(V.attributeNameCheck=y.CUSTOM_ELEMENT_HANDLING.attributeNameCheck),y.CUSTOM_ELEMENT_HANDLING&&typeof y.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements=="boolean"&&(V.allowCustomizedBuiltInElements=y.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements),Et&&(me=!1),Hi&&(ar=!0),sr&&(I=X({},xl),Y=[],sr.html===!0&&(X(I,yl),X(Y,bl)),sr.svg===!0&&(X(I,Ia),X(Y,Pa),X(Y,Ki)),sr.svgFilters===!0&&(X(I,Ra),X(Y,Pa),X(Y,Ki)),sr.mathMl===!0&&(X(I,Da),X(Y,_l),X(Y,Ki))),y.ADD_TAGS&&(I===J&&(I=Ne(I)),X(I,y.ADD_TAGS,mt)),y.ADD_ATTR&&(Y===ct&&(Y=Ne(Y)),X(Y,y.ADD_ATTR,mt)),y.ADD_URI_SAFE_ATTR&&X(Ea,y.ADD_URI_SAFE_ATTR,mt),y.FORBID_CONTENTS&&(or===Xo&&(or=Ne(or)),X(or,y.FORBID_CONTENTS,mt)),Ba&&(I["#text"]=!0),Gt&&X(I,["html","head","body"]),I.table&&(X(I,["tbody"]),delete gt.tbody),y.TRUSTED_TYPES_POLICY){if(typeof y.TRUSTED_TYPES_POLICY.createHTML!="function")throw Pr('TRUSTED_TYPES_POLICY configuration option must provide a "createHTML" hook.');if(typeof y.TRUSTED_TYPES_POLICY.createScriptURL!="function")throw Pr('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.');v=y.TRUSTED_TYPES_POLICY,B=v.createHTML("")}else v===void 0&&(v=Tg(p,n)),v!==null&&typeof B=="string"&&(B=v.createHTML(""));It&&It(y),cr=y}},tl=X({},["mi","mo","mn","ms","mtext"]),el=X({},["foreignobject","annotation-xml"]),jp=X({},["title","style","font","a","script"]),rl=X({},[...Ia,...Ra,...pg]),il=X({},[...Da,...gg]),Up=function(y){let w=x(y);(!w||!w.tagName)&&(w={namespaceURI:lr,tagName:"template"});const P=cn(y.tagName),et=cn(w.tagName);return Fa[y.namespaceURI]?y.namespaceURI===Yi?w.namespaceURI===xe?P==="svg":w.namespaceURI===Ui?P==="svg"&&(et==="annotation-xml"||tl[et]):!!rl[P]:y.namespaceURI===Ui?w.namespaceURI===xe?P==="math":w.namespaceURI===Yi?P==="math"&&el[et]:!!il[P]:y.namespaceURI===xe?w.namespaceURI===Yi&&!el[et]||w.namespaceURI===Ui&&!tl[et]?!1:!il[P]&&(jp[P]||!rl[P]):!!($r==="application/xhtml+xml"&&Fa[y.namespaceURI]):!1},se=function(y){Rr(e.removed,{element:y});try{y.parentNode.removeChild(y)}catch{y.remove()}},Gi=function(y,w){try{Rr(e.removed,{attribute:w.getAttributeNode(y),from:w})}catch{Rr(e.removed,{attribute:null,from:w})}if(w.removeAttribute(y),y==="is"&&!Y[y])if(ar||Hi)try{se(w)}catch{}else try{w.setAttribute(y,"")}catch{}},nl=function(y){let w=null,P=null;if(Aa)y=""+y;else{const bt=ml(y,/^[\r\n\t ]+/);P=bt&&bt[0]}$r==="application/xhtml+xml"&&lr===xe&&(y=''+y+"");const et=v?v.createHTML(y):y;if(lr===xe)try{w=new u().parseFromString(et,$r)}catch{}if(!w||!w.documentElement){w=$.createDocument(lr,"template",null);try{w.documentElement.innerHTML=Ma?B:et}catch{}}const kt=w.body||w.documentElement;return y&&P&&kt.insertBefore(r.createTextNode(P),kt.childNodes[0]||null),lr===xe?G.call(w,Gt?"html":"body")[0]:Gt?w.documentElement:kt},al=function(y){return O.call(y.ownerDocument||y,y,c.SHOW_ELEMENT|c.SHOW_COMMENT|c.SHOW_TEXT|c.SHOW_PROCESSING_INSTRUCTION|c.SHOW_CDATA_SECTION,null)},sl=function(y){return y instanceof f&&(typeof y.nodeName!="string"||typeof y.textContent!="string"||typeof y.removeChild!="function"||!(y.attributes instanceof h)||typeof y.removeAttribute!="function"||typeof y.setAttribute!="function"||typeof y.namespaceURI!="string"||typeof y.insertBefore!="function"||typeof y.hasChildNodes!="function")},ol=function(y){return typeof o=="function"&&y instanceof o},be=function(y,w,P){R[y]&&Xi(R[y],et=>{et.call(e,w,P,cr)})},ll=function(y){let w=null;if(be("beforeSanitizeElements",y,null),sl(y))return se(y),!0;const P=mt(y.nodeName);if(be("uponSanitizeElement",y,{tagName:P,allowedTags:I}),y.hasChildNodes()&&!ol(y.firstElementChild)&&Ft(/<[/\w]/g,y.innerHTML)&&Ft(/<[/\w]/g,y.textContent)||y.nodeType===Nr.progressingInstruction||ye&&y.nodeType===Nr.comment&&Ft(/<[/\w]/g,y.data))return se(y),!0;if(!I[P]||gt[P]){if(!gt[P]&&hl(P)&&(V.tagNameCheck instanceof RegExp&&Ft(V.tagNameCheck,P)||V.tagNameCheck instanceof Function&&V.tagNameCheck(P)))return!1;if(Ba&&!or[P]){const et=x(y)||y.parentNode,kt=C(y)||y.childNodes;if(kt&&et){const bt=kt.length;for(let Rt=bt-1;Rt>=0;--Rt){const oe=m(kt[Rt],!0);oe.__removalCount=(y.__removalCount||0)+1,et.insertBefore(oe,_(y))}}}return se(y),!0}return y instanceof l&&!Up(y)||(P==="noscript"||P==="noembed"||P==="noframes")&&Ft(/<\/no(script|embed|frames)/i,y.innerHTML)?(se(y),!0):(Et&&y.nodeType===Nr.text&&(w=y.textContent,Xi([D,lt,st],et=>{w=Dr(w,et," ")}),y.textContent!==w&&(Rr(e.removed,{element:y.cloneNode()}),y.textContent=w)),be("afterSanitizeElements",y,null),!1)},cl=function(y,w,P){if(Go&&(w==="id"||w==="name")&&(P in r||P in Hp))return!1;if(!(me&&!ie[w]&&Ft(M,w))){if(!(ne&&Ft(L,w))){if(!Y[w]||ie[w]){if(!(hl(y)&&(V.tagNameCheck instanceof RegExp&&Ft(V.tagNameCheck,y)||V.tagNameCheck instanceof Function&&V.tagNameCheck(y))&&(V.attributeNameCheck instanceof RegExp&&Ft(V.attributeNameCheck,w)||V.attributeNameCheck instanceof Function&&V.attributeNameCheck(w))||w==="is"&&V.allowCustomizedBuiltInElements&&(V.tagNameCheck instanceof RegExp&&Ft(V.tagNameCheck,P)||V.tagNameCheck instanceof Function&&V.tagNameCheck(P))))return!1}else if(!Ea[w]){if(!Ft(H,Dr(P,F,""))){if(!((w==="src"||w==="xlink:href"||w==="href")&&y!=="script"&&hg(P,"data:")===0&&Zo[y])){if(!(ae&&!Ft(T,Dr(P,F,"")))){if(P)return!1}}}}}}return!0},hl=function(y){return y!=="annotation-xml"&&ml(y,S)},ul=function(y){be("beforeSanitizeAttributes",y,null);const{attributes:w}=y;if(!w)return;const P={attrName:"",attrValue:"",keepAttr:!0,allowedAttributes:Y};let et=w.length;for(;et--;){const kt=w[et],{name:bt,namespaceURI:Rt,value:oe}=kt,Or=mt(bt);let Mt=bt==="value"?oe:ug(oe);if(P.attrName=Or,P.attrValue=Mt,P.keepAttr=!0,P.forceKeepAttr=void 0,be("uponSanitizeAttribute",y,P),Mt=P.attrValue,P.forceKeepAttr||(Gi(bt,y),!P.keepAttr))continue;if(!xt&&Ft(/\/>/i,Mt)){Gi(bt,y);continue}if(ye&&Ft(/((--!?|])>)|<\/(style|title)/i,Mt)){Gi(bt,y);continue}Et&&Xi([D,lt,st],dl=>{Mt=Dr(Mt,dl," ")});const fl=mt(y.nodeName);if(cl(fl,Or,Mt)){if(Vo&&(Or==="id"||Or==="name")&&(Gi(bt,y),Mt=Np+Mt),v&&typeof p=="object"&&typeof p.getAttributeType=="function"&&!Rt)switch(p.getAttributeType(fl,Or)){case"TrustedHTML":{Mt=v.createHTML(Mt);break}case"TrustedScriptURL":{Mt=v.createScriptURL(Mt);break}}try{Rt?y.setAttributeNS(Rt,bt,Mt):y.setAttribute(bt,Mt),sl(y)?se(y):gl(e.removed)}catch{}}}be("afterSanitizeAttributes",y,null)},Yp=function z(y){let w=null;const P=al(y);for(be("beforeSanitizeShadowDOM",y,null);w=P.nextNode();)be("uponSanitizeShadowNode",w,null),!ll(w)&&(w.content instanceof a&&z(w.content),ul(w));be("afterSanitizeShadowDOM",y,null)};return e.sanitize=function(z){let y=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{},w=null,P=null,et=null,kt=null;if(Ma=!z,Ma&&(z=""),typeof z!="string"&&!ol(z))if(typeof z.toString=="function"){if(z=z.toString(),typeof z!="string")throw Pr("dirty is not a string, aborting")}else throw Pr("toString is not a function");if(!e.isSupported)return z;if(La||$a(y),e.removed=[],typeof z=="string"&&(Fr=!1),Fr){if(z.nodeName){const oe=mt(z.nodeName);if(!I[oe]||gt[oe])throw Pr("root node is forbidden and cannot be sanitized in-place")}}else if(z instanceof o)w=nl(""),P=w.ownerDocument.importNode(z,!0),P.nodeType===Nr.element&&P.nodeName==="BODY"||P.nodeName==="HTML"?w=P:w.appendChild(P);else{if(!ar&&!Et&&!Gt&&z.indexOf("<")===-1)return v&&ji?v.createHTML(z):z;if(w=nl(z),!w)return ar?null:ji?B:""}w&&Aa&&se(w.firstChild);const bt=al(Fr?z:w);for(;et=bt.nextNode();)ll(et)||(et.content instanceof a&&Yp(et.content),ul(et));if(Fr)return z;if(ar){if(Hi)for(kt=E.call(w.ownerDocument);w.firstChild;)kt.appendChild(w.firstChild);else kt=w;return(Y.shadowroot||Y.shadowrootmode)&&(kt=Z.call(i,kt,!0)),kt}let Rt=Gt?w.outerHTML:w.innerHTML;return Gt&&I["!doctype"]&&w.ownerDocument&&w.ownerDocument.doctype&&w.ownerDocument.doctype.name&&Ft(Xc,w.ownerDocument.doctype.name)&&(Rt="
                                       `+Rt),Et&&Xi([D,lt,st],oe=>{Rt=Dr(Rt,oe," ")}),v&&ji?v.createHTML(Rt):Rt},e.setConfig=function(){let z=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{};$a(z),La=!0},e.clearConfig=function(){cr=null,La=!1},e.isValidAttribute=function(z,y,w){cr||$a({});const P=mt(z),et=mt(y);return cl(P,et,w)},e.addHook=function(z,y){typeof y=="function"&&(R[z]=R[z]||[],Rr(R[z],y))},e.removeHook=function(z){if(R[z])return gl(R[z])},e.removeHooks=function(z){R[z]&&(R[z]=[])},e.removeAllHooks=function(){R={}},e}var yr=Zc(),Kc=Object.defineProperty,d=(t,e)=>Kc(t,"name",{value:e,configurable:!0}),Sg=(t,e)=>{for(var r in e)Kc(t,r,{get:e[r],enumerable:!0})},_e={trace:0,debug:1,info:2,warn:3,error:4,fatal:5},k={trace:d((...t)=>{},"trace"),debug:d((...t)=>{},"debug"),info:d((...t)=>{},"info"),warn:d((...t)=>{},"warn"),error:d((...t)=>{},"error"),fatal:d((...t)=>{},"fatal")},Ys=d(function(t="fatal"){let e=_e.fatal;typeof t=="string"?t.toLowerCase()in _e&&(e=_e[t]):typeof t=="number"&&(e=t),k.trace=()=>{},k.debug=()=>{},k.info=()=>{},k.warn=()=>{},k.error=()=>{},k.fatal=()=>{},e<=_e.fatal&&(k.fatal=console.error?console.error.bind(console,Vt("FATAL"),"color: orange"):console.log.bind(console,"\x1B[35m",Vt("FATAL"))),e<=_e.error&&(k.error=console.error?console.error.bind(console,Vt("ERROR"),"color: orange"):console.log.bind(console,"\x1B[31m",Vt("ERROR"))),e<=_e.warn&&(k.warn=console.warn?console.warn.bind(console,Vt("WARN"),"color: orange"):console.log.bind(console,"\x1B[33m",Vt("WARN"))),e<=_e.info&&(k.info=console.info?console.info.bind(console,Vt("INFO"),"color: lightblue"):console.log.bind(console,"\x1B[34m",Vt("INFO"))),e<=_e.debug&&(k.debug=console.debug?console.debug.bind(console,Vt("DEBUG"),"color: lightgreen"):console.log.bind(console,"\x1B[32m",Vt("DEBUG"))),e<=_e.trace&&(k.trace=console.debug?console.debug.bind(console,Vt("TRACE"),"color: lightgreen"):console.log.bind(console,"\x1B[32m",Vt("TRACE")))},"setLogLevel"),Vt=d(t=>`%c${Jp().format("ss.SSS")} : ${t} : `,"format"),Qc=/^-{3}\s*[\n\r](.*?)[\n\r]-{3}\s*[\n\r]+/s,ei=/%{2}{\s*(?:(\w+)\s*:|(\w+))\s*(?:(\w+)|((?:(?!}%{2}).|\r?\n)*))?\s*(?:}%{2})?/gi,Lg=/\s*%%.*\n/gm,vi,Jc=(vi=class extends Error{constructor(e){super(e),this.name="UnknownDiagramError"}},d(vi,"UnknownDiagramError"),vi),xr={},Gs=d(function(t,e){t=t.replace(Qc,"").replace(ei,"").replace(Lg,`
                                       `);for(const[r,{detector:i}]of Object.entries(xr))if(i(t,e))return r;throw new Jc(`No diagram type detected matching given configuration for text: ${t}`)},"detectType"),th=d((...t)=>{for(const{id:e,detector:r,loader:i}of t)eh(e,r,i)},"registerLazyLoadedDiagrams"),eh=d((t,e,r)=>{xr[t]&&k.warn(`Detector with key ${t} already exists. Overwriting.`),xr[t]={detector:e,loader:r},k.debug(`Detector with key ${t} added${r?" with loader":""}`)},"addDetector"),Ag=d(t=>xr[t].loader,"getDiagramLoader"),ts=d((t,e,{depth:r=2,clobber:i=!1}={})=>{const n={depth:r,clobber:i};return Array.isArray(e)&&!Array.isArray(t)?(e.forEach(a=>ts(t,a,n)),t):Array.isArray(e)&&Array.isArray(t)?(e.forEach(a=>{t.includes(a)||t.push(a)}),t):t===void 0||r<=0?t!=null&&typeof t=="object"&&typeof e=="object"?Object.assign(t,e):e:(e!==void 0&&typeof t=="object"&&typeof e=="object"&&Object.keys(e).forEach(a=>{typeof e[a]=="object"&&(t[a]===void 0||typeof t[a]=="object")?(t[a]===void 0&&(t[a]=Array.isArray(e[a])?[]:{}),t[a]=ts(t[a],e[a],{depth:r-1,clobber:i})):(i||typeof t[a]!="object"&&typeof e[a]!="object")&&(t[a]=e[a])}),t)},"assignWithDepth"),Ct=ts,na="#ffffff",aa="#f2f2f2",$t=d((t,e)=>e?b(t,{s:-40,l:10}):b(t,{s:-40,l:-10}),"mkBorder"),ki,Bg=(ki=class{constructor(){this.background="#f4f4f4",this.primaryColor="#fff4dd",this.noteBkgColor="#fff5ad",this.noteTextColor="#333",this.THEME_COLOR_LIMIT=12,this.fontFamily='"trebuchet ms", verdana, arial, sans-serif',this.fontSize="16px"}updateColors(){var r,i,n,a,s,o,l,c,h,f,u;if(this.primaryTextColor=this.primaryTextColor||(this.darkMode?"#eee":"#333"),this.secondaryColor=this.secondaryColor||b(this.primaryColor,{h:-120}),this.tertiaryColor=this.tertiaryColor||b(this.primaryColor,{h:180,l:5}),this.primaryBorderColor=this.primaryBorderColor||$t(this.primaryColor,this.darkMode),this.secondaryBorderColor=this.secondaryBorderColor||$t(this.secondaryColor,this.darkMode),this.tertiaryBorderColor=this.tertiaryBorderColor||$t(this.tertiaryColor,this.darkMode),this.noteBorderColor=this.noteBorderColor||$t(this.noteBkgColor,this.darkMode),this.noteBkgColor=this.noteBkgColor||"#fff5ad",this.noteTextColor=this.noteTextColor||"#333",this.secondaryTextColor=this.secondaryTextColor||A(this.secondaryColor),this.tertiaryTextColor=this.tertiaryTextColor||A(this.tertiaryColor),this.lineColor=this.lineColor||A(this.background),this.arrowheadColor=this.arrowheadColor||A(this.background),this.textColor=this.textColor||this.primaryTextColor,this.border2=this.border2||this.tertiaryBorderColor,this.nodeBkg=this.nodeBkg||this.primaryColor,this.mainBkg=this.mainBkg||this.primaryColor,this.nodeBorder=this.nodeBorder||this.primaryBorderColor,this.clusterBkg=this.clusterBkg||this.tertiaryColor,this.clusterBorder=this.clusterBorder||this.tertiaryBorderColor,this.defaultLinkColor=this.defaultLinkColor||this.lineColor,this.titleColor=this.titleColor||this.tertiaryTextColor,this.edgeLabelBackground=this.edgeLabelBackground||(this.darkMode?W(this.secondaryColor,30):this.secondaryColor),this.nodeTextColor=this.nodeTextColor||this.primaryTextColor,this.actorBorder=this.actorBorder||this.primaryBorderColor,this.actorBkg=this.actorBkg||this.mainBkg,this.actorTextColor=this.actorTextColor||this.primaryTextColor,this.actorLineColor=this.actorLineColor||this.actorBorder,this.labelBoxBkgColor=this.labelBoxBkgColor||this.actorBkg,this.signalColor=this.signalColor||this.textColor,this.signalTextColor=this.signalTextColor||this.textColor,this.labelBoxBorderColor=this.labelBoxBorderColor||this.actorBorder,this.labelTextColor=this.labelTextColor||this.actorTextColor,this.loopTextColor=this.loopTextColor||this.actorTextColor,this.activationBorderColor=this.activationBorderColor||W(this.secondaryColor,10),this.activationBkgColor=this.activationBkgColor||this.secondaryColor,this.sequenceNumberColor=this.sequenceNumberColor||A(this.lineColor),this.sectionBkgColor=this.sectionBkgColor||this.tertiaryColor,this.altSectionBkgColor=this.altSectionBkgColor||"white",this.sectionBkgColor=this.sectionBkgColor||this.secondaryColor,this.sectionBkgColor2=this.sectionBkgColor2||this.primaryColor,this.excludeBkgColor=this.excludeBkgColor||"#eeeeee",this.taskBorderColor=this.taskBorderColor||this.primaryBorderColor,this.taskBkgColor=this.taskBkgColor||this.primaryColor,this.activeTaskBorderColor=this.activeTaskBorderColor||this.primaryColor,this.activeTaskBkgColor=this.activeTaskBkgColor||q(this.primaryColor,23),this.gridColor=this.gridColor||"lightgrey",this.doneTaskBkgColor=this.doneTaskBkgColor||"lightgrey",this.doneTaskBorderColor=this.doneTaskBorderColor||"grey",this.critBorderColor=this.critBorderColor||"#ff8888",this.critBkgColor=this.critBkgColor||"red",this.todayLineColor=this.todayLineColor||"red",this.taskTextColor=this.taskTextColor||this.textColor,this.taskTextOutsideColor=this.taskTextOutsideColor||this.textColor,this.taskTextLightColor=this.taskTextLightColor||this.textColor,this.taskTextColor=this.taskTextColor||this.primaryTextColor,this.taskTextDarkColor=this.taskTextDarkColor||this.textColor,this.taskTextClickableColor=this.taskTextClickableColor||"#003163",this.personBorder=this.personBorder||this.primaryBorderColor,this.personBkg=this.personBkg||this.mainBkg,this.transitionColor=this.transitionColor||this.lineColor,this.transitionLabelColor=this.transitionLabelColor||this.textColor,this.stateLabelColor=this.stateLabelColor||this.stateBkg||this.primaryTextColor,this.stateBkg=this.stateBkg||this.mainBkg,this.labelBackgroundColor=this.labelBackgroundColor||this.stateBkg,this.compositeBackground=this.compositeBackground||this.background||this.tertiaryColor,this.altBackground=this.altBackground||this.tertiaryColor,this.compositeTitleBackground=this.compositeTitleBackground||this.mainBkg,this.compositeBorder=this.compositeBorder||this.nodeBorder,this.innerEndBackground=this.nodeBorder,this.errorBkgColor=this.errorBkgColor||this.tertiaryColor,this.errorTextColor=this.errorTextColor||this.tertiaryTextColor,this.transitionColor=this.transitionColor||this.lineColor,this.specialStateColor=this.lineColor,this.cScale0=this.cScale0||this.primaryColor,this.cScale1=this.cScale1||this.secondaryColor,this.cScale2=this.cScale2||this.tertiaryColor,this.cScale3=this.cScale3||b(this.primaryColor,{h:30}),this.cScale4=this.cScale4||b(this.primaryColor,{h:60}),this.cScale5=this.cScale5||b(this.primaryColor,{h:90}),this.cScale6=this.cScale6||b(this.primaryColor,{h:120}),this.cScale7=this.cScale7||b(this.primaryColor,{h:150}),this.cScale8=this.cScale8||b(this.primaryColor,{h:210,l:150}),this.cScale9=this.cScale9||b(this.primaryColor,{h:270}),this.cScale10=this.cScale10||b(this.primaryColor,{h:300}),this.cScale11=this.cScale11||b(this.primaryColor,{h:330}),this.darkMode)for(let p=0;p{this[i]=e[i]}),this.updateColors(),r.forEach(i=>{this[i]=e[i]})}},d(ki,"Theme"),ki),Eg=d(t=>{const e=new Bg;return e.calculate(t),e},"getThemeVariables"),wi,Mg=(wi=class{constructor(){this.background="#333",this.primaryColor="#1f2020",this.secondaryColor=q(this.primaryColor,16),this.tertiaryColor=b(this.primaryColor,{h:-160}),this.primaryBorderColor=A(this.background),this.secondaryBorderColor=$t(this.secondaryColor,this.darkMode),this.tertiaryBorderColor=$t(this.tertiaryColor,this.darkMode),this.primaryTextColor=A(this.primaryColor),this.secondaryTextColor=A(this.secondaryColor),this.tertiaryTextColor=A(this.tertiaryColor),this.lineColor=A(this.background),this.textColor=A(this.background),this.mainBkg="#1f2020",this.secondBkg="calculated",this.mainContrastColor="lightgrey",this.darkTextColor=q(A("#323D47"),10),this.lineColor="calculated",this.border1="#ccc",this.border2=ti(255,255,255,.25),this.arrowheadColor="calculated",this.fontFamily='"trebuchet ms", verdana, arial, sans-serif',this.fontSize="16px",this.labelBackground="#181818",this.textColor="#ccc",this.THEME_COLOR_LIMIT=12,this.nodeBkg="calculated",this.nodeBorder="calculated",this.clusterBkg="calculated",this.clusterBorder="calculated",this.defaultLinkColor="calculated",this.titleColor="#F9FFFE",this.edgeLabelBackground="calculated",this.actorBorder="calculated",this.actorBkg="calculated",this.actorTextColor="calculated",this.actorLineColor="calculated",this.signalColor="calculated",this.signalTextColor="calculated",this.labelBoxBkgColor="calculated",this.labelBoxBorderColor="calculated",this.labelTextColor="calculated",this.loopTextColor="calculated",this.noteBorderColor="calculated",this.noteBkgColor="#fff5ad",this.noteTextColor="calculated",this.activationBorderColor="calculated",this.activationBkgColor="calculated",this.sequenceNumberColor="black",this.sectionBkgColor=W("#EAE8D9",30),this.altSectionBkgColor="calculated",this.sectionBkgColor2="#EAE8D9",this.excludeBkgColor=W(this.sectionBkgColor,10),this.taskBorderColor=ti(255,255,255,70),this.taskBkgColor="calculated",this.taskTextColor="calculated",this.taskTextLightColor="calculated",this.taskTextOutsideColor="calculated",this.taskTextClickableColor="#003163",this.activeTaskBorderColor=ti(255,255,255,50),this.activeTaskBkgColor="#81B1DB",this.gridColor="calculated",this.doneTaskBkgColor="calculated",this.doneTaskBorderColor="grey",this.critBorderColor="#E83737",this.critBkgColor="#E83737",this.taskTextDarkColor="calculated",this.todayLineColor="#DB5757",this.personBorder=this.primaryBorderColor,this.personBkg=this.mainBkg,this.labelColor="calculated",this.errorBkgColor="#a44141",this.errorTextColor="#ddd"}updateColors(){var e,r,i,n,a,s,o,l,c,h,f;this.secondBkg=q(this.mainBkg,16),this.lineColor=this.mainContrastColor,this.arrowheadColor=this.mainContrastColor,this.nodeBkg=this.mainBkg,this.nodeBorder=this.border1,this.clusterBkg=this.secondBkg,this.clusterBorder=this.border2,this.defaultLinkColor=this.lineColor,this.edgeLabelBackground=q(this.labelBackground,25),this.actorBorder=this.border1,this.actorBkg=this.mainBkg,this.actorTextColor=this.mainContrastColor,this.actorLineColor=this.actorBorder,this.signalColor=this.mainContrastColor,this.signalTextColor=this.mainContrastColor,this.labelBoxBkgColor=this.actorBkg,this.labelBoxBorderColor=this.actorBorder,this.labelTextColor=this.mainContrastColor,this.loopTextColor=this.mainContrastColor,this.noteBorderColor=this.secondaryBorderColor,this.noteBkgColor=this.secondBkg,this.noteTextColor=this.secondaryTextColor,this.activationBorderColor=this.border1,this.activationBkgColor=this.secondBkg,this.altSectionBkgColor=this.background,this.taskBkgColor=q(this.mainBkg,23),this.taskTextColor=this.darkTextColor,this.taskTextLightColor=this.mainContrastColor,this.taskTextOutsideColor=this.taskTextLightColor,this.gridColor=this.mainContrastColor,this.doneTaskBkgColor=this.mainContrastColor,this.taskTextDarkColor=this.darkTextColor,this.transitionColor=this.transitionColor||this.lineColor,this.transitionLabelColor=this.transitionLabelColor||this.textColor,this.stateLabelColor=this.stateLabelColor||this.stateBkg||this.primaryTextColor,this.stateBkg=this.stateBkg||this.mainBkg,this.labelBackgroundColor=this.labelBackgroundColor||this.stateBkg,this.compositeBackground=this.compositeBackground||this.background||this.tertiaryColor,this.altBackground=this.altBackground||"#555",this.compositeTitleBackground=this.compositeTitleBackground||this.mainBkg,this.compositeBorder=this.compositeBorder||this.nodeBorder,this.innerEndBackground=this.primaryBorderColor,this.specialStateColor="#f4f4f4",this.errorBkgColor=this.errorBkgColor||this.tertiaryColor,this.errorTextColor=this.errorTextColor||this.tertiaryTextColor,this.fillType0=this.primaryColor,this.fillType1=this.secondaryColor,this.fillType2=b(this.primaryColor,{h:64}),this.fillType3=b(this.secondaryColor,{h:64}),this.fillType4=b(this.primaryColor,{h:-64}),this.fillType5=b(this.secondaryColor,{h:-64}),this.fillType6=b(this.primaryColor,{h:128}),this.fillType7=b(this.secondaryColor,{h:128}),this.cScale1=this.cScale1||"#0b0000",this.cScale2=this.cScale2||"#4d1037",this.cScale3=this.cScale3||"#3f5258",this.cScale4=this.cScale4||"#4f2f1b",this.cScale5=this.cScale5||"#6e0a0a",this.cScale6=this.cScale6||"#3b0048",this.cScale7=this.cScale7||"#995a01",this.cScale8=this.cScale8||"#154706",this.cScale9=this.cScale9||"#161722",this.cScale10=this.cScale10||"#00296f",this.cScale11=this.cScale11||"#01629c",this.cScale12=this.cScale12||"#010029",this.cScale0=this.cScale0||this.primaryColor,this.cScale1=this.cScale1||this.secondaryColor,this.cScale2=this.cScale2||this.tertiaryColor,this.cScale3=this.cScale3||b(this.primaryColor,{h:30}),this.cScale4=this.cScale4||b(this.primaryColor,{h:60}),this.cScale5=this.cScale5||b(this.primaryColor,{h:90}),this.cScale6=this.cScale6||b(this.primaryColor,{h:120}),this.cScale7=this.cScale7||b(this.primaryColor,{h:150}),this.cScale8=this.cScale8||b(this.primaryColor,{h:210}),this.cScale9=this.cScale9||b(this.primaryColor,{h:270}),this.cScale10=this.cScale10||b(this.primaryColor,{h:300}),this.cScale11=this.cScale11||b(this.primaryColor,{h:330});for(let u=0;u{this[i]=e[i]}),this.updateColors(),r.forEach(i=>{this[i]=e[i]})}},d(wi,"Theme"),wi),Fg=d(t=>{const e=new Mg;return e.calculate(t),e},"getThemeVariables"),Ti,$g=(Ti=class{constructor(){this.background="#f4f4f4",this.primaryColor="#ECECFF",this.secondaryColor=b(this.primaryColor,{h:120}),this.secondaryColor="#ffffde",this.tertiaryColor=b(this.primaryColor,{h:-160}),this.primaryBorderColor=$t(this.primaryColor,this.darkMode),this.secondaryBorderColor=$t(this.secondaryColor,this.darkMode),this.tertiaryBorderColor=$t(this.tertiaryColor,this.darkMode),this.primaryTextColor=A(this.primaryColor),this.secondaryTextColor=A(this.secondaryColor),this.tertiaryTextColor=A(this.tertiaryColor),this.lineColor=A(this.background),this.textColor=A(this.background),this.background="white",this.mainBkg="#ECECFF",this.secondBkg="#ffffde",this.lineColor="#333333",this.border1="#9370DB",this.border2="#aaaa33",this.arrowheadColor="#333333",this.fontFamily='"trebuchet ms", verdana, arial, sans-serif',this.fontSize="16px",this.labelBackground="rgba(232,232,232, 0.8)",this.textColor="#333",this.THEME_COLOR_LIMIT=12,this.nodeBkg="calculated",this.nodeBorder="calculated",this.clusterBkg="calculated",this.clusterBorder="calculated",this.defaultLinkColor="calculated",this.titleColor="calculated",this.edgeLabelBackground="calculated",this.actorBorder="calculated",this.actorBkg="calculated",this.actorTextColor="black",this.actorLineColor="calculated",this.signalColor="calculated",this.signalTextColor="calculated",this.labelBoxBkgColor="calculated",this.labelBoxBorderColor="calculated",this.labelTextColor="calculated",this.loopTextColor="calculated",this.noteBorderColor="calculated",this.noteBkgColor="#fff5ad",this.noteTextColor="calculated",this.activationBorderColor="#666",this.activationBkgColor="#f4f4f4",this.sequenceNumberColor="white",this.sectionBkgColor="calculated",this.altSectionBkgColor="calculated",this.sectionBkgColor2="calculated",this.excludeBkgColor="#eeeeee",this.taskBorderColor="calculated",this.taskBkgColor="calculated",this.taskTextLightColor="calculated",this.taskTextColor=this.taskTextLightColor,this.taskTextDarkColor="calculated",this.taskTextOutsideColor=this.taskTextDarkColor,this.taskTextClickableColor="calculated",this.activeTaskBorderColor="calculated",this.activeTaskBkgColor="calculated",this.gridColor="calculated",this.doneTaskBkgColor="calculated",this.doneTaskBorderColor="calculated",this.critBorderColor="calculated",this.critBkgColor="calculated",this.todayLineColor="calculated",this.sectionBkgColor=ti(102,102,255,.49),this.altSectionBkgColor="white",this.sectionBkgColor2="#fff400",this.taskBorderColor="#534fbc",this.taskBkgColor="#8a90dd",this.taskTextLightColor="white",this.taskTextColor="calculated",this.taskTextDarkColor="black",this.taskTextOutsideColor="calculated",this.taskTextClickableColor="#003163",this.activeTaskBorderColor="#534fbc",this.activeTaskBkgColor="#bfc7ff",this.gridColor="lightgrey",this.doneTaskBkgColor="lightgrey",this.doneTaskBorderColor="grey",this.critBorderColor="#ff8888",this.critBkgColor="red",this.todayLineColor="red",this.personBorder=this.primaryBorderColor,this.personBkg=this.mainBkg,this.labelColor="black",this.errorBkgColor="#552222",this.errorTextColor="#552222",this.updateColors()}updateColors(){var e,r,i,n,a,s,o,l,c,h,f;this.cScale0=this.cScale0||this.primaryColor,this.cScale1=this.cScale1||this.secondaryColor,this.cScale2=this.cScale2||this.tertiaryColor,this.cScale3=this.cScale3||b(this.primaryColor,{h:30}),this.cScale4=this.cScale4||b(this.primaryColor,{h:60}),this.cScale5=this.cScale5||b(this.primaryColor,{h:90}),this.cScale6=this.cScale6||b(this.primaryColor,{h:120}),this.cScale7=this.cScale7||b(this.primaryColor,{h:150}),this.cScale8=this.cScale8||b(this.primaryColor,{h:210}),this.cScale9=this.cScale9||b(this.primaryColor,{h:270}),this.cScale10=this.cScale10||b(this.primaryColor,{h:300}),this.cScale11=this.cScale11||b(this.primaryColor,{h:330}),this.cScalePeer1=this.cScalePeer1||W(this.secondaryColor,45),this.cScalePeer2=this.cScalePeer2||W(this.tertiaryColor,40);for(let u=0;u{this[i]=e[i]}),this.updateColors(),r.forEach(i=>{this[i]=e[i]})}},d(Ti,"Theme"),Ti),Og=d(t=>{const e=new $g;return e.calculate(t),e},"getThemeVariables"),Si,Ig=(Si=class{constructor(){this.background="#f4f4f4",this.primaryColor="#cde498",this.secondaryColor="#cdffb2",this.background="white",this.mainBkg="#cde498",this.secondBkg="#cdffb2",this.lineColor="green",this.border1="#13540c",this.border2="#6eaa49",this.arrowheadColor="green",this.fontFamily='"trebuchet ms", verdana, arial, sans-serif',this.fontSize="16px",this.tertiaryColor=q("#cde498",10),this.primaryBorderColor=$t(this.primaryColor,this.darkMode),this.secondaryBorderColor=$t(this.secondaryColor,this.darkMode),this.tertiaryBorderColor=$t(this.tertiaryColor,this.darkMode),this.primaryTextColor=A(this.primaryColor),this.secondaryTextColor=A(this.secondaryColor),this.tertiaryTextColor=A(this.primaryColor),this.lineColor=A(this.background),this.textColor=A(this.background),this.THEME_COLOR_LIMIT=12,this.nodeBkg="calculated",this.nodeBorder="calculated",this.clusterBkg="calculated",this.clusterBorder="calculated",this.defaultLinkColor="calculated",this.titleColor="#333",this.edgeLabelBackground="#e8e8e8",this.actorBorder="calculated",this.actorBkg="calculated",this.actorTextColor="black",this.actorLineColor="calculated",this.signalColor="#333",this.signalTextColor="#333",this.labelBoxBkgColor="calculated",this.labelBoxBorderColor="#326932",this.labelTextColor="calculated",this.loopTextColor="calculated",this.noteBorderColor="calculated",this.noteBkgColor="#fff5ad",this.noteTextColor="calculated",this.activationBorderColor="#666",this.activationBkgColor="#f4f4f4",this.sequenceNumberColor="white",this.sectionBkgColor="#6eaa49",this.altSectionBkgColor="white",this.sectionBkgColor2="#6eaa49",this.excludeBkgColor="#eeeeee",this.taskBorderColor="calculated",this.taskBkgColor="#487e3a",this.taskTextLightColor="white",this.taskTextColor="calculated",this.taskTextDarkColor="black",this.taskTextOutsideColor="calculated",this.taskTextClickableColor="#003163",this.activeTaskBorderColor="calculated",this.activeTaskBkgColor="calculated",this.gridColor="lightgrey",this.doneTaskBkgColor="lightgrey",this.doneTaskBorderColor="grey",this.critBorderColor="#ff8888",this.critBkgColor="red",this.todayLineColor="red",this.personBorder=this.primaryBorderColor,this.personBkg=this.mainBkg,this.labelColor="black",this.errorBkgColor="#552222",this.errorTextColor="#552222"}updateColors(){var e,r,i,n,a,s,o,l,c,h,f;this.actorBorder=W(this.mainBkg,20),this.actorBkg=this.mainBkg,this.labelBoxBkgColor=this.actorBkg,this.labelTextColor=this.actorTextColor,this.loopTextColor=this.actorTextColor,this.noteBorderColor=this.border2,this.noteTextColor=this.actorTextColor,this.actorLineColor=this.actorBorder,this.cScale0=this.cScale0||this.primaryColor,this.cScale1=this.cScale1||this.secondaryColor,this.cScale2=this.cScale2||this.tertiaryColor,this.cScale3=this.cScale3||b(this.primaryColor,{h:30}),this.cScale4=this.cScale4||b(this.primaryColor,{h:60}),this.cScale5=this.cScale5||b(this.primaryColor,{h:90}),this.cScale6=this.cScale6||b(this.primaryColor,{h:120}),this.cScale7=this.cScale7||b(this.primaryColor,{h:150}),this.cScale8=this.cScale8||b(this.primaryColor,{h:210}),this.cScale9=this.cScale9||b(this.primaryColor,{h:270}),this.cScale10=this.cScale10||b(this.primaryColor,{h:300}),this.cScale11=this.cScale11||b(this.primaryColor,{h:330}),this.cScalePeer1=this.cScalePeer1||W(this.secondaryColor,45),this.cScalePeer2=this.cScalePeer2||W(this.tertiaryColor,40);for(let u=0;u{this[i]=e[i]}),this.updateColors(),r.forEach(i=>{this[i]=e[i]})}},d(Si,"Theme"),Si),Rg=d(t=>{const e=new Ig;return e.calculate(t),e},"getThemeVariables"),Li,Dg=(Li=class{constructor(){this.primaryColor="#eee",this.contrast="#707070",this.secondaryColor=q(this.contrast,55),this.background="#ffffff",this.tertiaryColor=b(this.primaryColor,{h:-160}),this.primaryBorderColor=$t(this.primaryColor,this.darkMode),this.secondaryBorderColor=$t(this.secondaryColor,this.darkMode),this.tertiaryBorderColor=$t(this.tertiaryColor,this.darkMode),this.primaryTextColor=A(this.primaryColor),this.secondaryTextColor=A(this.secondaryColor),this.tertiaryTextColor=A(this.tertiaryColor),this.lineColor=A(this.background),this.textColor=A(this.background),this.mainBkg="#eee",this.secondBkg="calculated",this.lineColor="#666",this.border1="#999",this.border2="calculated",this.note="#ffa",this.text="#333",this.critical="#d42",this.done="#bbb",this.arrowheadColor="#333333",this.fontFamily='"trebuchet ms", verdana, arial, sans-serif',this.fontSize="16px",this.THEME_COLOR_LIMIT=12,this.nodeBkg="calculated",this.nodeBorder="calculated",this.clusterBkg="calculated",this.clusterBorder="calculated",this.defaultLinkColor="calculated",this.titleColor="calculated",this.edgeLabelBackground="white",this.actorBorder="calculated",this.actorBkg="calculated",this.actorTextColor="calculated",this.actorLineColor=this.actorBorder,this.signalColor="calculated",this.signalTextColor="calculated",this.labelBoxBkgColor="calculated",this.labelBoxBorderColor="calculated",this.labelTextColor="calculated",this.loopTextColor="calculated",this.noteBorderColor="calculated",this.noteBkgColor="calculated",this.noteTextColor="calculated",this.activationBorderColor="#666",this.activationBkgColor="#f4f4f4",this.sequenceNumberColor="white",this.sectionBkgColor="calculated",this.altSectionBkgColor="white",this.sectionBkgColor2="calculated",this.excludeBkgColor="#eeeeee",this.taskBorderColor="calculated",this.taskBkgColor="calculated",this.taskTextLightColor="white",this.taskTextColor="calculated",this.taskTextDarkColor="calculated",this.taskTextOutsideColor="calculated",this.taskTextClickableColor="#003163",this.activeTaskBorderColor="calculated",this.activeTaskBkgColor="calculated",this.gridColor="calculated",this.doneTaskBkgColor="calculated",this.doneTaskBorderColor="calculated",this.critBkgColor="calculated",this.critBorderColor="calculated",this.todayLineColor="calculated",this.personBorder=this.primaryBorderColor,this.personBkg=this.mainBkg,this.labelColor="black",this.errorBkgColor="#552222",this.errorTextColor="#552222"}updateColors(){var e,r,i,n,a,s,o,l,c,h,f;this.secondBkg=q(this.contrast,55),this.border2=this.contrast,this.actorBorder=q(this.border1,23),this.actorBkg=this.mainBkg,this.actorTextColor=this.text,this.actorLineColor=this.actorBorder,this.signalColor=this.text,this.signalTextColor=this.text,this.labelBoxBkgColor=this.actorBkg,this.labelBoxBorderColor=this.actorBorder,this.labelTextColor=this.text,this.loopTextColor=this.text,this.noteBorderColor="#999",this.noteBkgColor="#666",this.noteTextColor="#fff",this.cScale0=this.cScale0||"#555",this.cScale1=this.cScale1||"#F4F4F4",this.cScale2=this.cScale2||"#555",this.cScale3=this.cScale3||"#BBB",this.cScale4=this.cScale4||"#777",this.cScale5=this.cScale5||"#999",this.cScale6=this.cScale6||"#DDD",this.cScale7=this.cScale7||"#FFF",this.cScale8=this.cScale8||"#DDD",this.cScale9=this.cScale9||"#BBB",this.cScale10=this.cScale10||"#999",this.cScale11=this.cScale11||"#777";for(let u=0;u{this[i]=e[i]}),this.updateColors(),r.forEach(i=>{this[i]=e[i]})}},d(Li,"Theme"),Li),Pg=d(t=>{const e=new Dg;return e.calculate(t),e},"getThemeVariables"),ke={base:{getThemeVariables:Eg},dark:{getThemeVariables:Fg},default:{getThemeVariables:Og},forest:{getThemeVariables:Rg},neutral:{getThemeVariables:Pg}},Be={flowchart:{useMaxWidth:!0,titleTopMargin:25,subGraphTitleMargin:{top:0,bottom:0},diagramPadding:8,htmlLabels:!0,nodeSpacing:50,rankSpacing:50,curve:"basis",padding:15,defaultRenderer:"dagre-wrapper",wrappingWidth:200},sequence:{useMaxWidth:!0,hideUnusedParticipants:!1,activationWidth:10,diagramMarginX:50,diagramMarginY:10,actorMargin:50,width:150,height:65,boxMargin:10,boxTextMargin:5,noteMargin:10,messageMargin:35,messageAlign:"center",mirrorActors:!0,forceMenus:!1,bottomMarginAdj:1,rightAngles:!1,showSequenceNumbers:!1,actorFontSize:14,actorFontFamily:'"Open Sans", sans-serif',actorFontWeight:400,noteFontSize:14,noteFontFamily:'"trebuchet ms", verdana, arial, sans-serif',noteFontWeight:400,noteAlign:"center",messageFontSize:16,messageFontFamily:'"trebuchet ms", verdana, arial, sans-serif',messageFontWeight:400,wrap:!1,wrapPadding:10,labelBoxWidth:50,labelBoxHeight:20},gantt:{useMaxWidth:!0,titleTopMargin:25,barHeight:20,barGap:4,topPadding:50,rightPadding:75,leftPadding:75,gridLineStartPadding:35,fontSize:11,sectionFontSize:11,numberSectionStyles:4,axisFormat:"%Y-%m-%d",topAxis:!1,displayMode:"",weekday:"sunday"},journey:{useMaxWidth:!0,diagramMarginX:50,diagramMarginY:10,leftMargin:150,width:150,height:50,boxMargin:10,boxTextMargin:5,noteMargin:10,messageMargin:35,messageAlign:"center",bottomMarginAdj:1,rightAngles:!1,taskFontSize:14,taskFontFamily:'"Open Sans", sans-serif',taskMargin:50,activationWidth:10,textPlacement:"fo",actorColours:["#8FBC8F","#7CFC00","#00FFFF","#20B2AA","#B0E0E6","#FFFFE0"],sectionFills:["#191970","#8B008B","#4B0082","#2F4F4F","#800000","#8B4513","#00008B"],sectionColours:["#fff"]},class:{useMaxWidth:!0,titleTopMargin:25,arrowMarkerAbsolute:!1,dividerMargin:10,padding:5,textHeight:10,defaultRenderer:"dagre-wrapper",htmlLabels:!1},state:{useMaxWidth:!0,titleTopMargin:25,dividerMargin:10,sizeUnit:5,padding:8,textHeight:10,titleShift:-15,noteMargin:10,forkWidth:70,forkHeight:7,miniPadding:2,fontSizeFactor:5.02,fontSize:24,labelHeight:16,edgeLengthFactor:"20",compositTitleSize:35,radius:5,defaultRenderer:"dagre-wrapper"},er:{useMaxWidth:!0,titleTopMargin:25,diagramPadding:20,layoutDirection:"TB",minEntityWidth:100,minEntityHeight:75,entityPadding:15,stroke:"gray",fill:"honeydew",fontSize:12},pie:{useMaxWidth:!0,textPosition:.75},quadrantChart:{useMaxWidth:!0,chartWidth:500,chartHeight:500,titleFontSize:20,titlePadding:10,quadrantPadding:5,xAxisLabelPadding:5,yAxisLabelPadding:5,xAxisLabelFontSize:16,yAxisLabelFontSize:16,quadrantLabelFontSize:16,quadrantTextTopPadding:5,pointTextPadding:5,pointLabelFontSize:12,pointRadius:5,xAxisPosition:"top",yAxisPosition:"left",quadrantInternalBorderStrokeWidth:1,quadrantExternalBorderStrokeWidth:2},xyChart:{useMaxWidth:!0,width:700,height:500,titleFontSize:20,titlePadding:10,showTitle:!0,xAxis:{$ref:"#/$defs/XYChartAxisConfig",showLabel:!0,labelFontSize:14,labelPadding:5,showTitle:!0,titleFontSize:16,titlePadding:5,showTick:!0,tickLength:5,tickWidth:2,showAxisLine:!0,axisLineWidth:2},yAxis:{$ref:"#/$defs/XYChartAxisConfig",showLabel:!0,labelFontSize:14,labelPadding:5,showTitle:!0,titleFontSize:16,titlePadding:5,showTick:!0,tickLength:5,tickWidth:2,showAxisLine:!0,axisLineWidth:2},chartOrientation:"vertical",plotReservedSpacePercent:50},requirement:{useMaxWidth:!0,rect_fill:"#f9f9f9",text_color:"#333",rect_border_size:"0.5px",rect_border_color:"#bbb",rect_min_width:200,rect_min_height:200,fontSize:14,rect_padding:10,line_height:20},mindmap:{useMaxWidth:!0,padding:10,maxNodeWidth:200},timeline:{useMaxWidth:!0,diagramMarginX:50,diagramMarginY:10,leftMargin:150,width:150,height:50,boxMargin:10,boxTextMargin:5,noteMargin:10,messageMargin:35,messageAlign:"center",bottomMarginAdj:1,rightAngles:!1,taskFontSize:14,taskFontFamily:'"Open Sans", sans-serif',taskMargin:50,activationWidth:10,textPlacement:"fo",actorColours:["#8FBC8F","#7CFC00","#00FFFF","#20B2AA","#B0E0E6","#FFFFE0"],sectionFills:["#191970","#8B008B","#4B0082","#2F4F4F","#800000","#8B4513","#00008B"],sectionColours:["#fff"],disableMulticolor:!1},gitGraph:{useMaxWidth:!0,titleTopMargin:25,diagramPadding:8,nodeLabel:{width:75,height:100,x:-25,y:0},mainBranchName:"main",mainBranchOrder:0,showCommitLabel:!0,showBranches:!0,rotateCommitLabel:!0,parallelCommits:!1,arrowMarkerAbsolute:!1},c4:{useMaxWidth:!0,diagramMarginX:50,diagramMarginY:10,c4ShapeMargin:50,c4ShapePadding:20,width:216,height:60,boxMargin:10,c4ShapeInRow:4,nextLinePaddingX:0,c4BoundaryInRow:2,personFontSize:14,personFontFamily:'"Open Sans", sans-serif',personFontWeight:"normal",external_personFontSize:14,external_personFontFamily:'"Open Sans", sans-serif',external_personFontWeight:"normal",systemFontSize:14,systemFontFamily:'"Open Sans", sans-serif',systemFontWeight:"normal",external_systemFontSize:14,external_systemFontFamily:'"Open Sans", sans-serif',external_systemFontWeight:"normal",system_dbFontSize:14,system_dbFontFamily:'"Open Sans", sans-serif',system_dbFontWeight:"normal",external_system_dbFontSize:14,external_system_dbFontFamily:'"Open Sans", sans-serif',external_system_dbFontWeight:"normal",system_queueFontSize:14,system_queueFontFamily:'"Open Sans", sans-serif',system_queueFontWeight:"normal",external_system_queueFontSize:14,external_system_queueFontFamily:'"Open Sans", sans-serif',external_system_queueFontWeight:"normal",boundaryFontSize:14,boundaryFontFamily:'"Open Sans", sans-serif',boundaryFontWeight:"normal",messageFontSize:12,messageFontFamily:'"Open Sans", sans-serif',messageFontWeight:"normal",containerFontSize:14,containerFontFamily:'"Open Sans", sans-serif',containerFontWeight:"normal",external_containerFontSize:14,external_containerFontFamily:'"Open Sans", sans-serif',external_containerFontWeight:"normal",container_dbFontSize:14,container_dbFontFamily:'"Open Sans", sans-serif',container_dbFontWeight:"normal",external_container_dbFontSize:14,external_container_dbFontFamily:'"Open Sans", sans-serif',external_container_dbFontWeight:"normal",container_queueFontSize:14,container_queueFontFamily:'"Open Sans", sans-serif',container_queueFontWeight:"normal",external_container_queueFontSize:14,external_container_queueFontFamily:'"Open Sans", sans-serif',external_container_queueFontWeight:"normal",componentFontSize:14,componentFontFamily:'"Open Sans", sans-serif',componentFontWeight:"normal",external_componentFontSize:14,external_componentFontFamily:'"Open Sans", sans-serif',external_componentFontWeight:"normal",component_dbFontSize:14,component_dbFontFamily:'"Open Sans", sans-serif',component_dbFontWeight:"normal",external_component_dbFontSize:14,external_component_dbFontFamily:'"Open Sans", sans-serif',external_component_dbFontWeight:"normal",component_queueFontSize:14,component_queueFontFamily:'"Open Sans", sans-serif',component_queueFontWeight:"normal",external_component_queueFontSize:14,external_component_queueFontFamily:'"Open Sans", sans-serif',external_component_queueFontWeight:"normal",wrap:!0,wrapPadding:10,person_bg_color:"#08427B",person_border_color:"#073B6F",external_person_bg_color:"#686868",external_person_border_color:"#8A8A8A",system_bg_color:"#1168BD",system_border_color:"#3C7FC0",system_db_bg_color:"#1168BD",system_db_border_color:"#3C7FC0",system_queue_bg_color:"#1168BD",system_queue_border_color:"#3C7FC0",external_system_bg_color:"#999999",external_system_border_color:"#8A8A8A",external_system_db_bg_color:"#999999",external_system_db_border_color:"#8A8A8A",external_system_queue_bg_color:"#999999",external_system_queue_border_color:"#8A8A8A",container_bg_color:"#438DD5",container_border_color:"#3C7FC0",container_db_bg_color:"#438DD5",container_db_border_color:"#3C7FC0",container_queue_bg_color:"#438DD5",container_queue_border_color:"#3C7FC0",external_container_bg_color:"#B3B3B3",external_container_border_color:"#A6A6A6",external_container_db_bg_color:"#B3B3B3",external_container_db_border_color:"#A6A6A6",external_container_queue_bg_color:"#B3B3B3",external_container_queue_border_color:"#A6A6A6",component_bg_color:"#85BBF0",component_border_color:"#78A8D8",component_db_bg_color:"#85BBF0",component_db_border_color:"#78A8D8",component_queue_bg_color:"#85BBF0",component_queue_border_color:"#78A8D8",external_component_bg_color:"#CCCCCC",external_component_border_color:"#BFBFBF",external_component_db_bg_color:"#CCCCCC",external_component_db_border_color:"#BFBFBF",external_component_queue_bg_color:"#CCCCCC",external_component_queue_border_color:"#BFBFBF"},sankey:{useMaxWidth:!0,width:600,height:400,linkColor:"gradient",nodeAlignment:"justify",showValues:!0,prefix:"",suffix:""},block:{useMaxWidth:!0,padding:8},packet:{useMaxWidth:!0,rowHeight:32,bitWidth:32,bitsPerRow:32,showBits:!0,paddingX:5,paddingY:5},theme:"default",look:"classic",handDrawnSeed:0,layout:"dagre",maxTextSize:5e4,maxEdges:500,darkMode:!1,fontFamily:'"trebuchet ms", verdana, arial, sans-serif;',logLevel:5,securityLevel:"strict",startOnLoad:!0,arrowMarkerAbsolute:!1,secure:["secure","securityLevel","startOnLoad","maxTextSize","suppressErrorRendering","maxEdges"],legacyMathML:!1,forceLegacyMathML:!1,deterministicIds:!1,fontSize:16,markdownAutoWrap:!0,suppressErrorRendering:!1},rh={...Be,deterministicIDSeed:void 0,elk:{mergeEdges:!1,nodePlacementStrategy:"SIMPLE"},themeCSS:void 0,themeVariables:ke.default.getThemeVariables(),sequence:{...Be.sequence,messageFont:d(function(){return{fontFamily:this.messageFontFamily,fontSize:this.messageFontSize,fontWeight:this.messageFontWeight}},"messageFont"),noteFont:d(function(){return{fontFamily:this.noteFontFamily,fontSize:this.noteFontSize,fontWeight:this.noteFontWeight}},"noteFont"),actorFont:d(function(){return{fontFamily:this.actorFontFamily,fontSize:this.actorFontSize,fontWeight:this.actorFontWeight}},"actorFont")},gantt:{...Be.gantt,tickInterval:void 0,useWidth:void 0},c4:{...Be.c4,useWidth:void 0,personFont:d(function(){return{fontFamily:this.personFontFamily,fontSize:this.personFontSize,fontWeight:this.personFontWeight}},"personFont"),external_personFont:d(function(){return{fontFamily:this.external_personFontFamily,fontSize:this.external_personFontSize,fontWeight:this.external_personFontWeight}},"external_personFont"),systemFont:d(function(){return{fontFamily:this.systemFontFamily,fontSize:this.systemFontSize,fontWeight:this.systemFontWeight}},"systemFont"),external_systemFont:d(function(){return{fontFamily:this.external_systemFontFamily,fontSize:this.external_systemFontSize,fontWeight:this.external_systemFontWeight}},"external_systemFont"),system_dbFont:d(function(){return{fontFamily:this.system_dbFontFamily,fontSize:this.system_dbFontSize,fontWeight:this.system_dbFontWeight}},"system_dbFont"),external_system_dbFont:d(function(){return{fontFamily:this.external_system_dbFontFamily,fontSize:this.external_system_dbFontSize,fontWeight:this.external_system_dbFontWeight}},"external_system_dbFont"),system_queueFont:d(function(){return{fontFamily:this.system_queueFontFamily,fontSize:this.system_queueFontSize,fontWeight:this.system_queueFontWeight}},"system_queueFont"),external_system_queueFont:d(function(){return{fontFamily:this.external_system_queueFontFamily,fontSize:this.external_system_queueFontSize,fontWeight:this.external_system_queueFontWeight}},"external_system_queueFont"),containerFont:d(function(){return{fontFamily:this.containerFontFamily,fontSize:this.containerFontSize,fontWeight:this.containerFontWeight}},"containerFont"),external_containerFont:d(function(){return{fontFamily:this.external_containerFontFamily,fontSize:this.external_containerFontSize,fontWeight:this.external_containerFontWeight}},"external_containerFont"),container_dbFont:d(function(){return{fontFamily:this.container_dbFontFamily,fontSize:this.container_dbFontSize,fontWeight:this.container_dbFontWeight}},"container_dbFont"),external_container_dbFont:d(function(){return{fontFamily:this.external_container_dbFontFamily,fontSize:this.external_container_dbFontSize,fontWeight:this.external_container_dbFontWeight}},"external_container_dbFont"),container_queueFont:d(function(){return{fontFamily:this.container_queueFontFamily,fontSize:this.container_queueFontSize,fontWeight:this.container_queueFontWeight}},"container_queueFont"),external_container_queueFont:d(function(){return{fontFamily:this.external_container_queueFontFamily,fontSize:this.external_container_queueFontSize,fontWeight:this.external_container_queueFontWeight}},"external_container_queueFont"),componentFont:d(function(){return{fontFamily:this.componentFontFamily,fontSize:this.componentFontSize,fontWeight:this.componentFontWeight}},"componentFont"),external_componentFont:d(function(){return{fontFamily:this.external_componentFontFamily,fontSize:this.external_componentFontSize,fontWeight:this.external_componentFontWeight}},"external_componentFont"),component_dbFont:d(function(){return{fontFamily:this.component_dbFontFamily,fontSize:this.component_dbFontSize,fontWeight:this.component_dbFontWeight}},"component_dbFont"),external_component_dbFont:d(function(){return{fontFamily:this.external_component_dbFontFamily,fontSize:this.external_component_dbFontSize,fontWeight:this.external_component_dbFontWeight}},"external_component_dbFont"),component_queueFont:d(function(){return{fontFamily:this.component_queueFontFamily,fontSize:this.component_queueFontSize,fontWeight:this.component_queueFontWeight}},"component_queueFont"),external_component_queueFont:d(function(){return{fontFamily:this.external_component_queueFontFamily,fontSize:this.external_component_queueFontSize,fontWeight:this.external_component_queueFontWeight}},"external_component_queueFont"),boundaryFont:d(function(){return{fontFamily:this.boundaryFontFamily,fontSize:this.boundaryFontSize,fontWeight:this.boundaryFontWeight}},"boundaryFont"),messageFont:d(function(){return{fontFamily:this.messageFontFamily,fontSize:this.messageFontSize,fontWeight:this.messageFontWeight}},"messageFont")},pie:{...Be.pie,useWidth:984},xyChart:{...Be.xyChart,useWidth:void 0},requirement:{...Be.requirement,useWidth:void 0},packet:{...Be.packet}},ih=d((t,e="")=>Object.keys(t).reduce((r,i)=>Array.isArray(t[i])?r:typeof t[i]=="object"&&t[i]!==null?[...r,e+i,...ih(t[i],"")]:[...r,e+i],[]),"keyify"),Ng=new Set(ih(rh,"")),zg=rh,Cn=d(t=>{if(k.debug("sanitizeDirective called with",t),!(typeof t!="object"||t==null)){if(Array.isArray(t)){t.forEach(e=>Cn(e));return}for(const e of Object.keys(t)){if(k.debug("Checking key",e),e.startsWith("__")||e.includes("proto")||e.includes("constr")||!Ng.has(e)||t[e]==null){k.debug("sanitize deleting key: ",e),delete t[e];continue}if(typeof t[e]=="object"){k.debug("sanitizing object",e),Cn(t[e]);continue}const r=["themeCSS","fontFamily","altFontFamily"];for(const i of r)e.includes(i)&&(k.debug("sanitizing css option",e),t[e]=qg(t[e]))}if(t.themeVariables)for(const e of Object.keys(t.themeVariables)){const r=t.themeVariables[e];r!=null&&r.match&&!r.match(/^[\d "#%(),.;A-Za-z]+$/)&&(t.themeVariables[e]="")}k.debug("After sanitization",t)}},"sanitizeDirective"),qg=d(t=>{let e=0,r=0;for(const i of t){if(e{let r=Ct({},t),i={};for(const n of e)oh(n),i=Ct(i,n);if(r=Ct(r,i),i.theme&&i.theme in ke){const n=Ct({},nh),a=Ct(n.themeVariables||{},i.themeVariables);r.theme&&r.theme in ke&&(r.themeVariables=ke[r.theme].getThemeVariables(a))}return ri=r,lh(ri),ri},"updateCurrentConfig"),Wg=d(t=>(Pt=Ct({},br),Pt=Ct(Pt,t),t.theme&&ke[t.theme]&&(Pt.themeVariables=ke[t.theme].getThemeVariables(t.themeVariables)),sa(Pt,_r),Pt),"setSiteConfig"),Hg=d(t=>{nh=Ct({},t)},"saveConfigFromInitialize"),jg=d(t=>(Pt=Ct(Pt,t),sa(Pt,_r),Pt),"updateSiteConfig"),ah=d(()=>Ct({},Pt),"getSiteConfig"),sh=d(t=>(lh(t),Ct(ri,t),Se()),"setConfig"),Se=d(()=>Ct({},ri),"getConfig"),oh=d(t=>{t&&(["secure",...Pt.secure??[]].forEach(e=>{Object.hasOwn(t,e)&&(k.debug(`Denied attempt to modify a secure key ${e}`,t[e]),delete t[e])}),Object.keys(t).forEach(e=>{e.startsWith("__")&&delete t[e]}),Object.keys(t).forEach(e=>{typeof t[e]=="string"&&(t[e].includes("<")||t[e].includes(">")||t[e].includes("url(data:"))&&delete t[e],typeof t[e]=="object"&&oh(t[e])}))},"sanitize"),Ug=d(t=>{var e;Cn(t),t.fontFamily&&!((e=t.themeVariables)!=null&&e.fontFamily)&&(t.themeVariables={...t.themeVariables,fontFamily:t.fontFamily}),_r.push(t),sa(Pt,_r)},"addDirective"),vn=d((t=Pt)=>{_r=[],sa(t,_r)},"reset"),Yg={LAZY_LOAD_DEPRECATED:"The configuration options lazyLoadedDiagrams and loadExternalDiagramsAtStartup are deprecated. Please use registerExternalDiagrams instead."},vl={},Gg=d(t=>{vl[t]||(k.warn(Yg[t]),vl[t]=!0)},"issueWarning"),lh=d(t=>{t&&(t.lazyLoadedDiagrams||t.loadExternalDiagramsAtStartup)&&Gg("LAZY_LOAD_DEPRECATED")},"checkConfig"),Fi=//gi,Vg=d(t=>t?uh(t).replace(/\\n/g,"#br#").split("#br#"):[""],"getRows"),Xg=(()=>{let t=!1;return()=>{t||(ch(),t=!0)}})();function ch(){const t="data-temp-href-target";yr.addHook("beforeSanitizeAttributes",e=>{e.tagName==="A"&&e.hasAttribute("target")&&e.setAttribute(t,e.getAttribute("target")??"")}),yr.addHook("afterSanitizeAttributes",e=>{e.tagName==="A"&&e.hasAttribute(t)&&(e.setAttribute("target",e.getAttribute(t)??""),e.removeAttribute(t),e.getAttribute("target")==="_blank"&&e.setAttribute("rel","noopener"))})}d(ch,"setupDompurifyHooks");var hh=d(t=>(Xg(),yr.sanitize(t)),"removeScript"),kl=d((t,e)=>{var r;if(((r=e.flowchart)==null?void 0:r.htmlLabels)!==!1){const i=e.securityLevel;i==="antiscript"||i==="strict"?t=hh(t):i!=="loose"&&(t=uh(t),t=t.replace(//g,">"),t=t.replace(/=/g,"="),t=Jg(t))}return t},"sanitizeMore"),Cr=d((t,e)=>t&&(e.dompurifyConfig?t=yr.sanitize(kl(t,e),e.dompurifyConfig).toString():t=yr.sanitize(kl(t,e),{FORBID_TAGS:["style"]}).toString(),t),"sanitizeText"),Zg=d((t,e)=>typeof t=="string"?Cr(t,e):t.flat().map(r=>Cr(r,e)),"sanitizeTextOrArray"),Kg=d(t=>Fi.test(t),"hasBreaks"),Qg=d(t=>t.split(Fi),"splitBreaks"),Jg=d(t=>t.replace(/#br#/g,"
                                      "),"placeholderToBreak"),uh=d(t=>t.replace(Fi,"#br#"),"breakToPlaceholder"),tm=d(t=>{let e="";return t&&(e=window.location.protocol+"//"+window.location.host+window.location.pathname+window.location.search,e=e.replaceAll(/\(/g,"\\("),e=e.replaceAll(/\)/g,"\\)")),e},"getUrl"),ee=d(t=>!(t===!1||["false","null","0"].includes(String(t).trim().toLowerCase())),"evaluate"),em=d(function(...t){const e=t.filter(r=>!isNaN(r));return Math.max(...e)},"getMax"),rm=d(function(...t){const e=t.filter(r=>!isNaN(r));return Math.min(...e)},"getMin"),kS=d(function(t){const e=t.split(/(,)/),r=[];for(let i=0;i0&&i+1Math.max(0,t.split(e).length-1),"countOccurrence"),im=d((t,e)=>{const r=es(t,"~"),i=es(e,"~");return r===1&&i===1},"shouldCombineSets"),nm=d(t=>{const e=es(t,"~");let r=!1;if(e<=1)return t;e%2!==0&&t.startsWith("~")&&(t=t.substring(1),r=!0);const i=[...t];let n=i.indexOf("~"),a=i.lastIndexOf("~");for(;n!==-1&&a!==-1&&n!==a;)i[n]="<",i[a]=">",n=i.indexOf("~"),a=i.lastIndexOf("~");return r&&i.unshift("~"),i.join("")},"processSet"),wl=d(()=>window.MathMLElement!==void 0,"isMathMLSupported"),rs=/\$\$(.*)\$\$/g,si=d(t=>{var e;return(((e=t.match(rs))==null?void 0:e.length)??0)>0},"hasKatex"),wS=d(async(t,e)=>{t=await Vs(t,e);const r=document.createElement("div");r.innerHTML=t,r.id="katex-temp",r.style.visibility="hidden",r.style.position="absolute",r.style.top="0";const i=document.querySelector("body");i==null||i.insertAdjacentElement("beforeend",r);const n={width:r.clientWidth,height:r.clientHeight};return r.remove(),n},"calculateMathMLDimensions"),Vs=d(async(t,e)=>{if(!si(t))return t;if(!(wl()||e.legacyMathML||e.forceLegacyMathML))return t.replace(rs,"MathML is unsupported in this environment.");const{default:r}=await at(()=>import("./katex-rPiVaalG.js"),__vite__mapDeps([])),i=e.forceLegacyMathML||!wl()&&e.legacyMathML?"htmlAndMathml":"mathml";return t.split(Fi).map(n=>si(n)?`
                                      ${n}
                                      `:`
                                      ${n}
                                      `).join("").replace(rs,(n,a)=>r.renderToString(a,{throwOnError:!0,displayMode:!0,output:i}).replace(/\n/g," ").replace(//g,""))},"renderKatex"),Ar={getRows:Vg,sanitizeText:Cr,sanitizeTextOrArray:Zg,hasBreaks:Kg,splitBreaks:Qg,lineBreakRegex:Fi,removeScript:hh,getUrl:tm,evaluate:ee,getMax:em,getMin:rm},am=d(function(t,e){for(let r of e)t.attr(r[0],r[1])},"d3Attrs"),sm=d(function(t,e,r){let i=new Map;return r?(i.set("width","100%"),i.set("style",`max-width: ${e}px;`)):(i.set("height",t),i.set("width",e)),i},"calculateSvgSizeAttrs"),fh=d(function(t,e,r,i){const n=sm(e,r,i);am(t,n)},"configureSvgSize"),om=d(function(t,e,r,i){const n=e.node().getBBox(),a=n.width,s=n.height;k.info(`SVG bounds: ${a}x${s}`,n);let o=0,l=0;k.info(`Graph bounds: ${o}x${l}`,t),o=a+r*2,l=s+r*2,k.info(`Calculated bounds: ${o}x${l}`),fh(e,l,o,i);const c=`${n.x-r} ${n.y-r} ${n.width+2*r} ${n.height+2*r}`;e.attr("viewBox",c)},"setupGraphViewbox"),hn={},lm=d((t,e,r)=>{let i="";return t in hn&&hn[t]?i=hn[t](r):k.warn(`No theme found for ${t}`),` & { font-family: ${r.fontFamily}; @@ -130,8 +130,8 @@ Please report this to https://github.com/markedjs/marked.`,e){const n="

                                      An err point:`,u,` node: `,e,` -res:`,ut.polygon(e,c,u)),ut.polygon(e,c,u)},n},"question"),ik=d((t,e,r,i,n)=>[`M${t+n},${e}`,`L${t+r-n},${e}`,`L${t+r},${e-i/2}`,`L${t+r-n},${e-i}`,`L${t+n},${e-i}`,`L${t},${e-i/2}`,"Z"].join(" "),"createHexagonPathD"),nk=d(async(t,e)=>{const{labelStyles:r,nodeStyles:i}=Lt(e);e.labelStyle=r;const{shapeSvg:n,bbox:a}=await At(t,e,Yt(e)),s=4,o=a.height+e.padding,l=o/s,c=a.width+2*l+e.padding,h=[{x:l,y:0},{x:c-l,y:0},{x:c,y:-o/2},{x:c-l,y:-o},{x:l,y:-o},{x:0,y:-o/2}];let f;const{cssStyles:u}=e;if(e.look==="handDrawn"){const p=ot.svg(n),g=vt(e,{}),m=ik(0,0,c,o,l),_=p.path(m,g);f=n.insert(()=>_,":first-child").attr("transform",`translate(${-c/2}, ${o/2})`),u&&f.attr("style",u)}else f=Ae(n,c,o,h);return i&&f.attr("style",i),e.width=c,e.height=o,dt(e,f),e.intersect=function(p){return ut.polygon(e,h,p)},n},"hexagon"),ak=d((t,e,r,i)=>[`M${t-2*i/6},${e}`,`L${t+r-i/6},${e}`,`L${t+r+2*i/6},${e-i}`,`L${t+i/6},${e-i}`,"Z"].join(" "),"createLeanRightPathD"),sk=d(async(t,e)=>{const{labelStyles:r,nodeStyles:i}=Lt(e);e.labelStyle=r;const{shapeSvg:n,bbox:a}=await At(t,e,Yt(e)),s=a.width+e.padding,o=a.height+e.padding,l=[{x:-2*o/6,y:0},{x:s-o/6,y:0},{x:s+2*o/6,y:-o},{x:o/6,y:-o}];let c;const{cssStyles:h}=e;if(e.look==="handDrawn"){const f=ot.svg(n),u=vt(e,{}),p=ak(0,0,s,o),g=f.path(p,u);c=n.insert(()=>g,":first-child").attr("transform",`translate(${-s/2}, ${o/2})`),h&&c.attr("style",h)}else c=Ae(n,s,o,l);return i&&c.attr("style",i),e.width=s,e.height=o,dt(e,c),e.intersect=function(f){return ut.polygon(e,l,f)},n},"lean_right"),ok=d((t,e,r,i)=>[`M${t+2*i/6},${e}`,`L${t+r+i/6},${e}`,`L${t+r-2*i/6},${e-i}`,`L${t-i/6},${e-i}`,"Z"].join(" "),"createLeanLeftPathD"),lk=d(async(t,e)=>{const{labelStyles:r,nodeStyles:i}=Lt(e);e.labelStyle=r;const{shapeSvg:n,bbox:a}=await At(t,e,Yt(e)),s=a.width+e.padding,o=a.height+e.padding,l=[{x:2*o/6,y:0},{x:s+o/6,y:0},{x:s-2*o/6,y:-o},{x:-o/6,y:-o}];let c;const{cssStyles:h}=e;if(e.look==="handDrawn"){const f=ot.svg(n),u=vt(e,{}),p=ok(0,0,s,o),g=f.path(p,u);c=n.insert(()=>g,":first-child").attr("transform",`translate(${-s/2}, ${o/2})`),h&&c.attr("style",h)}else c=Ae(n,s,o,l);return i&&c.attr("style",i),e.width=s,e.height=o,dt(e,c),e.intersect=function(f){return ut.polygon(e,l,f)},n},"lean_left"),ck=d((t,e,r,i)=>[`M${t-2*i/6},${e}`,`L${t+r+2*i/6},${e}`,`L${t+r-i/6},${e-i}`,`L${t+i/6},${e-i}`,"Z"].join(" "),"createTrapezoidPathD"),hk=d(async(t,e)=>{const{labelStyles:r,nodeStyles:i}=Lt(e);e.labelStyle=r;const{shapeSvg:n,bbox:a}=await At(t,e,Yt(e)),s=a.width+e.padding,o=a.height+e.padding,l=[{x:-2*o/6,y:0},{x:s+2*o/6,y:0},{x:s-o/6,y:-o},{x:o/6,y:-o}];let c;const{cssStyles:h}=e;if(e.look==="handDrawn"){const f=ot.svg(n),u=vt(e,{}),p=ck(0,0,s,o),g=f.path(p,u);c=n.insert(()=>g,":first-child").attr("transform",`translate(${-s/2}, ${o/2})`),h&&c.attr("style",h)}else c=Ae(n,s,o,l);return i&&c.attr("style",i),e.width=s,e.height=o,dt(e,c),e.intersect=function(f){return ut.polygon(e,l,f)},n},"trapezoid"),uk=d((t,e,r,i)=>[`M${t+i/6},${e}`,`L${t+r-i/6},${e}`,`L${t+r+2*i/6},${e-i}`,`L${t-2*i/6},${e-i}`,"Z"].join(" "),"createInvertedTrapezoidPathD"),fk=d(async(t,e)=>{const{labelStyles:r,nodeStyles:i}=Lt(e);e.labelStyle=r;const{shapeSvg:n,bbox:a}=await At(t,e,Yt(e)),s=a.width+e.padding,o=a.height+e.padding,l=[{x:o/6,y:0},{x:s-o/6,y:0},{x:s+2*o/6,y:-o},{x:-2*o/6,y:-o}];let c;const{cssStyles:h}=e;if(e.look==="handDrawn"){const f=ot.svg(n),u=vt(e,{}),p=uk(0,0,s,o),g=f.path(p,u);c=n.insert(()=>g,":first-child").attr("transform",`translate(${-s/2}, ${o/2})`),h&&c.attr("style",h)}else c=Ae(n,s,o,l);return i&&c.attr("style",i),e.width=s,e.height=o,dt(e,c),e.intersect=function(f){return ut.polygon(e,l,f)},n},"inv_trapezoid"),dk=d(async(t,e)=>{const{shapeSvg:r}=await At(t,e,"label"),i=r.insert("rect",":first-child");return i.attr("width",.1).attr("height",.1),r.attr("class","label edgeLabel"),dt(e,i),e.intersect=function(s){return ut.rect(e,s)},r},"labelRect"),Lc={state:Dv,stateStart:zv,stateEnd:qv,fork:Sc,join:Sc,choice:Wv,note:Hv,roundedRect:Pv,rectWithTitle:Uv,squareRect:Nv,stadium:jv,subroutine:Yv,cylinder:Zv,circle:Kv,doublecircle:Qv,odd:tk,diamond:rk,hexagon:nk,lean_right:sk,lean_left:lk,trapezoid:hk,inv_trapezoid:fk,labelRect:dk},mr=new Map,pk=d(async(t,e,r)=>{let i,n;if(e.shape==="rect"&&(e.rx&&e.ry?e.shape="roundedRect":e.shape="squareRect"),e.link){let a;K().securityLevel==="sandbox"?a="_top":e.linkTarget&&(a=e.linkTarget||"_blank"),i=t.insert("svg:a").attr("xlink:href",e.link).attr("target",a),n=await Lc[e.shape](i,e,r)}else n=await Lc[e.shape](t,e,r),i=n;return e.tooltip&&n.attr("title",e.tooltip),mr.set(e.id,i),e.haveCallback&&mr.get(e.id).attr("class",mr.get(e.id).attr("class")+" clickable"),i},"insertNode"),WS=d((t,e)=>{mr.set(e.id,t)},"setNodeElem"),HS=d(()=>{mr.clear()},"clear"),jS=d(t=>{const e=mr.get(t.id);k.trace("Transforming node",t.diff,t,"translate("+(t.x-t.width/2-5)+", "+t.width/2+")");const r=8,i=t.diff||0;return t.clusterNode?e.attr("transform","translate("+(t.x+i-t.width/2)+", "+(t.y-t.height/2-r)+")"):e.attr("transform","translate("+t.x+", "+t.y+")"),i},"positionNode"),gk={common:Ar,getConfig:Se,insertCluster:fv,insertEdge:_v,insertEdgeLabel:gv,insertMarkers:Fv,insertNode:pk,interpolateToCurve:yo,labelHelper:At,log:k,positionEdgeLabel:mv},gi={},df=d(t=>{for(const e of t)gi[e.name]=e},"registerLayoutLoaders"),mk=d(()=>{df([{name:"dagre",loader:d(async()=>await at(()=>import("./dagre-CQ6OS2HX-BRwnzFkj.js"),__vite__mapDeps([0,1,2,3,4,5,6,7])),"loader")}])},"registerDefaultLayoutLoaders");mk();var US=d(async(t,e)=>{if(!(t.layoutAlgorithm in gi))throw new Error(`Unknown layout algorithm: ${t.layoutAlgorithm}`);const r=gi[t.layoutAlgorithm];return(await r.loader()).render(t,e,gk,{algorithm:r.algorithm})},"render"),YS=d((t="",{fallback:e="dagre"}={})=>{if(t in gi)return t;if(e in gi)return k.warn(`Layout algorithm ${t} is not registered. Using ${e} as fallback.`),e;throw new Error(`Both layout algorithms ${t} and ${e} are not registered.`)},"getRegisteredLayoutAlgorithm"),Ac="11.0.2",yk=d(t=>{var n;const{securityLevel:e}=K();let r=nt("body");if(e==="sandbox"){const s=((n=nt(`#i${t}`).node())==null?void 0:n.contentDocument)??document;r=nt(s.body)}return r.select(`#${t}`)},"selectSvgElement"),pf="comm",gf="rule",mf="decl",xk="@import",bk="@keyframes",_k="@layer",yf=Math.abs,Ro=String.fromCharCode;function xf(t){return t.trim()}function mn(t,e,r){return t.replace(e,r)}function Ck(t,e,r){return t.indexOf(e,r)}function mi(t,e){return t.charCodeAt(e)|0}function yi(t,e,r){return t.slice(e,r)}function ve(t){return t.length}function vk(t){return t.length}function on(t,e){return e.push(t),t}var va=1,wr=1,bf=0,Zt=0,ft=0,Mr="";function Do(t,e,r,i,n,a,s,o){return{value:t,root:e,parent:r,type:i,props:n,children:a,line:va,column:wr,length:s,return:"",siblings:o}}function kk(){return ft}function wk(){return ft=Zt>0?mi(Mr,--Zt):0,wr--,ft===10&&(wr=1,va--),ft}function Jt(){return ft=Zt2||vs(ft)>3?"":" "}function Ak(t,e){for(;--e&&Jt()&&!(ft<48||ft>102||ft>57&&ft<65||ft>70&&ft<97););return ka(t,yn()+(e<6&&Xe()==32&&Jt()==32))}function ks(t){for(;Jt();)switch(ft){case t:return Zt;case 34:case 39:t!==34&&t!==39&&ks(ft);break;case 40:t===41&&ks(t);break;case 92:Jt();break}return Zt}function Bk(t,e){for(;Jt()&&t+ft!==57;)if(t+ft===84&&Xe()===47)break;return"/*"+ka(e,Zt-1)+"*"+Ro(t===47?t:Jt())}function Ek(t){for(;!vs(Xe());)Jt();return ka(t,Zt)}function Mk(t){return Sk(xn("",null,null,null,[""],t=Tk(t),0,[0],t))}function xn(t,e,r,i,n,a,s,o,l){for(var c=0,h=0,f=s,u=0,p=0,g=0,m=1,_=1,C=1,x=0,v="",B=n,$=a,O=i,E=v;_;)switch(g=x,x=Jt()){case 40:if(g!=108&&mi(E,f-1)==58){Ck(E+=mn(Xa(x),"&","&\f"),"&\f",yf(c?o[c-1]:0))!=-1&&(C=-1);break}case 34:case 39:case 91:E+=Xa(x);break;case 9:case 10:case 13:case 32:E+=Lk(g);break;case 92:E+=Ak(yn()-1,7);continue;case 47:switch(Xe()){case 42:case 47:on(Fk(Bk(Jt(),yn()),e,r,l),l);break;default:E+="/"}break;case 123*m:o[c++]=ve(E)*C;case 125*m:case 59:case 0:switch(x){case 0:case 125:_=0;case 59+h:C==-1&&(E=mn(E,/\f/g,"")),p>0&&ve(E)-f&&on(p>32?Ec(E+";",i,r,f-1,l):Ec(mn(E," ","")+";",i,r,f-2,l),l);break;case 59:E+=";";default:if(on(O=Bc(E,e,r,c,h,n,o,v,B=[],$=[],f,a),a),x===123)if(h===0)xn(E,e,O,O,B,a,f,o,$);else switch(u===99&&mi(E,3)===110?100:u){case 100:case 108:case 109:case 115:xn(t,O,O,i&&on(Bc(t,O,O,0,0,n,o,v,n,B=[],f,$),$),n,$,f,o,i?B:$);break;default:xn(E,O,O,O,[""],$,0,o,$)}}c=h=p=0,m=C=1,v=E="",f=s;break;case 58:f=1+ve(E),p=g;default:if(m<1){if(x==123)--m;else if(x==125&&m++==0&&wk()==125)continue}switch(E+=Ro(x),x*m){case 38:C=h>0?1:(E+="\f",-1);break;case 44:o[c++]=(ve(E)-1)*C,C=1;break;case 64:Xe()===45&&(E+=Xa(Jt())),u=Xe(),h=f=ve(v=E+=Ek(yn())),x++;break;case 45:g===45&&ve(E)==2&&(m=0)}}return a}function Bc(t,e,r,i,n,a,s,o,l,c,h,f){for(var u=n-1,p=n===0?a:[""],g=vk(p),m=0,_=0,C=0;m0?p[x]+" "+v:mn(v,/&\f/g,p[x])))&&(l[C++]=B);return Do(t,e,r,n===0?gf:o,l,c,h,f)}function Fk(t,e,r,i){return Do(t,e,r,pf,Ro(kk()),yi(t,2,-2),0,i)}function Ec(t,e,r,i,n){return Do(t,e,r,mf,yi(t,0,i),yi(t,i+1,-1),i,n)}function ws(t,e){for(var r="",i=0;i/^\s*C4Context|C4Container|C4Component|C4Dynamic|C4Deployment/.test(t),"detector"),Xk=d(async()=>{const{diagram:t}=await at(()=>import("./c4Diagram-ZHOUKFWV-20XrCBlj.js"),__vite__mapDeps([8,9,7]));return{id:_f,diagram:t}},"loader"),Zk={id:_f,detector:Vk,loader:Xk},Kk=Zk,Cf="flowchart",Qk=d((t,e)=>{var r,i;return((r=e==null?void 0:e.flowchart)==null?void 0:r.defaultRenderer)==="dagre-wrapper"||((i=e==null?void 0:e.flowchart)==null?void 0:i.defaultRenderer)==="elk"?!1:/^\s*graph/.test(t)},"detector"),Jk=d(async()=>{const{diagram:t}=await at(()=>import("./flowDiagram-TGP4CI55-B7tCuQuY.js"),__vite__mapDeps([10,11,12,13,7]));return{id:Cf,diagram:t}},"loader"),tw={id:Cf,detector:Qk,loader:Jk},ew=tw,vf="flowchart-v2",rw=d((t,e)=>{var r,i,n;return((r=e==null?void 0:e.flowchart)==null?void 0:r.defaultRenderer)==="dagre-d3"||((i=e==null?void 0:e.flowchart)==null?void 0:i.defaultRenderer)==="elk"?!1:/^\s*graph/.test(t)&&((n=e==null?void 0:e.flowchart)==null?void 0:n.defaultRenderer)==="dagre-wrapper"?!0:/^\s*flowchart/.test(t)},"detector"),iw=d(async()=>{const{diagram:t}=await at(()=>import("./flowDiagram-TGP4CI55-B7tCuQuY.js"),__vite__mapDeps([10,11,12,13,7]));return{id:vf,diagram:t}},"loader"),nw={id:vf,detector:rw,loader:iw},aw=nw,kf="er",sw=d(t=>/^\s*erDiagram/.test(t),"detector"),ow=d(async()=>{const{diagram:t}=await at(()=>import("./erDiagram-762WSSOR-CtIJPNj4.js"),__vite__mapDeps([14,1,2,3,4,7]));return{id:kf,diagram:t}},"loader"),lw={id:kf,detector:sw,loader:ow},cw=lw,wf="gitGraph",hw=d(t=>/^\s*gitGraph/.test(t),"detector"),uw=d(async()=>{const{diagram:t}=await at(()=>import("./gitGraphDiagram-LGD5RUNZ-DqNoDc6j.js"),__vite__mapDeps([15,16,17,18,7,2,4,6]));return{id:wf,diagram:t}},"loader"),fw={id:wf,detector:hw,loader:uw},dw=fw,Tf="gantt",pw=d(t=>/^\s*gantt/.test(t),"detector"),gw=d(async()=>{const{diagram:t}=await at(()=>import("./ganttDiagram-GAYIUD5S-p-lGuXqL.js"),__vite__mapDeps([19,20,21,7]));return{id:Tf,diagram:t}},"loader"),mw={id:Tf,detector:pw,loader:gw},yw=mw,Sf="info",xw=d(t=>/^\s*info/.test(t),"detector"),bw=d(async()=>{const{diagram:t}=await at(()=>import("./infoDiagram-GSXZ5C4N-BldMtTiD.js"),__vite__mapDeps([22,18,7,2,4,6]));return{id:Sf,diagram:t}},"loader"),_w={id:Sf,detector:xw,loader:bw},Lf="pie",Cw=d(t=>/^\s*pie/.test(t),"detector"),vw=d(async()=>{const{diagram:t}=await at(()=>import("./pieDiagram-WEX7LNAG-BT3MbsDU.js"),__vite__mapDeps([23,16,18,7,2,4,6,24,25,21]));return{id:Lf,diagram:t}},"loader"),kw={id:Lf,detector:Cw,loader:vw},Af="quadrantChart",ww=d(t=>/^\s*quadrantChart/.test(t),"detector"),Tw=d(async()=>{const{diagram:t}=await at(()=>import("./quadrantDiagram-SRYJ5FP7-DraEpiPS.js"),__vite__mapDeps([26,20,21,7]));return{id:Af,diagram:t}},"loader"),Sw={id:Af,detector:ww,loader:Tw},Lw=Sw,Bf="xychart",Aw=d(t=>/^\s*xychart-beta/.test(t),"detector"),Bw=d(async()=>{const{diagram:t}=await at(()=>import("./xychartDiagram-BZZU7QT5-VXQiVXRw.js"),__vite__mapDeps([27,21,25,20,7]));return{id:Bf,diagram:t}},"loader"),Ew={id:Bf,detector:Aw,loader:Bw},Mw=Ew,Ef="requirement",Fw=d(t=>/^\s*requirement(Diagram)?/.test(t),"detector"),$w=d(async()=>{const{diagram:t}=await at(()=>import("./requirementDiagram-V7TESSIR-ptPfSQ70.js"),__vite__mapDeps([28,1,2,3,4,7]));return{id:Ef,diagram:t}},"loader"),Ow={id:Ef,detector:Fw,loader:$w},Iw=Ow,Mf="sequence",Rw=d(t=>/^\s*sequenceDiagram/.test(t),"detector"),Dw=d(async()=>{const{diagram:t}=await at(()=>import("./sequenceDiagram-6SD7JOPP-BG3IUlAD.js"),__vite__mapDeps([29,9,17,7]));return{id:Mf,diagram:t}},"loader"),Pw={id:Mf,detector:Rw,loader:Dw},Nw=Pw,Ff="class",zw=d((t,e)=>{var r;return((r=e==null?void 0:e.class)==null?void 0:r.defaultRenderer)==="dagre-wrapper"?!1:/^\s*classDiagram/.test(t)},"detector"),qw=d(async()=>{const{diagram:t}=await at(()=>import("./classDiagram-MQQPYQM5-D7Ouc99y.js"),__vite__mapDeps([30,31,1,2,3,4,7]));return{id:Ff,diagram:t}},"loader"),Ww={id:Ff,detector:zw,loader:qw},Hw=Ww,$f="classDiagram",jw=d((t,e)=>{var r;return/^\s*classDiagram/.test(t)&&((r=e==null?void 0:e.class)==null?void 0:r.defaultRenderer)==="dagre-wrapper"?!0:/^\s*classDiagram-v2/.test(t)},"detector"),Uw=d(async()=>{const{diagram:t}=await at(()=>import("./classDiagram-v2-4S5WAI72-OQWCgw14.js"),__vite__mapDeps([32,33,12,31,1,2,3,4,5,6,7]));return{id:$f,diagram:t}},"loader"),Yw={id:$f,detector:jw,loader:Uw},Gw=Yw,Of="state",Vw=d((t,e)=>{var r;return((r=e==null?void 0:e.state)==null?void 0:r.defaultRenderer)==="dagre-wrapper"?!1:/^\s*stateDiagram/.test(t)},"detector"),Xw=d(async()=>{const{diagram:t}=await at(()=>import("./stateDiagram-N22R6T2Y-BFbyHmsw.js"),__vite__mapDeps([34,35,11,12,1,2,3,4,7]));return{id:Of,diagram:t}},"loader"),Zw={id:Of,detector:Vw,loader:Xw},Kw=Zw,If="stateDiagram",Qw=d((t,e)=>{var r;return!!(/^\s*stateDiagram-v2/.test(t)||/^\s*stateDiagram/.test(t)&&((r=e==null?void 0:e.state)==null?void 0:r.defaultRenderer)==="dagre-wrapper")},"detector"),Jw=d(async()=>{const{diagram:t}=await at(()=>import("./stateDiagram-v2-QXVA2PVL-C7QgvS5i.js"),__vite__mapDeps([36,35,11,12,7]));return{id:If,diagram:t}},"loader"),tT={id:If,detector:Qw,loader:Jw},eT=tT,Rf="journey",rT=d(t=>/^\s*journey/.test(t),"detector"),iT=d(async()=>{const{diagram:t}=await at(()=>import("./journeyDiagram-35ZZFJAM-BivG2OsD.js"),__vite__mapDeps([37,9,24,7]));return{id:Rf,diagram:t}},"loader"),nT={id:Rf,detector:rT,loader:iT},aT=nT,sT=d((t,e,r)=>{k.debug(`rendering svg for syntax error -`);const i=yk(e),n=i.append("g");i.attr("viewBox","0 0 2412 512"),fh(i,100,512,!0),n.append("path").attr("class","error-icon").attr("d","m411.313,123.313c6.25-6.25 6.25-16.375 0-22.625s-16.375-6.25-22.625,0l-32,32-9.375,9.375-20.688-20.688c-12.484-12.5-32.766-12.5-45.25,0l-16,16c-1.261,1.261-2.304,2.648-3.31,4.051-21.739-8.561-45.324-13.426-70.065-13.426-105.867,0-192,86.133-192,192s86.133,192 192,192 192-86.133 192-192c0-24.741-4.864-48.327-13.426-70.065 1.402-1.007 2.79-2.049 4.051-3.31l16-16c12.5-12.492 12.5-32.758 0-45.25l-20.688-20.688 9.375-9.375 32.001-31.999zm-219.313,100.687c-52.938,0-96,43.063-96,96 0,8.836-7.164,16-16,16s-16-7.164-16-16c0-70.578 57.422-128 128-128 8.836,0 16,7.164 16,16s-7.164,16-16,16z"),n.append("path").attr("class","error-icon").attr("d","m459.02,148.98c-6.25-6.25-16.375-6.25-22.625,0s-6.25,16.375 0,22.625l16,16c3.125,3.125 7.219,4.688 11.313,4.688 4.094,0 8.188-1.563 11.313-4.688 6.25-6.25 6.25-16.375 0-22.625l-16.001-16z"),n.append("path").attr("class","error-icon").attr("d","m340.395,75.605c3.125,3.125 7.219,4.688 11.313,4.688 4.094,0 8.188-1.563 11.313-4.688 6.25-6.25 6.25-16.375 0-22.625l-16-16c-6.25-6.25-16.375-6.25-22.625,0s-6.25,16.375 0,22.625l15.999,16z"),n.append("path").attr("class","error-icon").attr("d","m400,64c8.844,0 16-7.164 16-16v-32c0-8.836-7.156-16-16-16-8.844,0-16,7.164-16,16v32c0,8.836 7.156,16 16,16z"),n.append("path").attr("class","error-icon").attr("d","m496,96.586h-32c-8.844,0-16,7.164-16,16 0,8.836 7.156,16 16,16h32c8.844,0 16-7.164 16-16 0-8.836-7.156-16-16-16z"),n.append("path").attr("class","error-icon").attr("d","m436.98,75.605c3.125,3.125 7.219,4.688 11.313,4.688 4.094,0 8.188-1.563 11.313-4.688l32-32c6.25-6.25 6.25-16.375 0-22.625s-16.375-6.25-22.625,0l-32,32c-6.251,6.25-6.251,16.375-0.001,22.625z"),n.append("text").attr("class","error-text").attr("x",1440).attr("y",250).attr("font-size","150px").style("text-anchor","middle").text("Syntax error in text"),n.append("text").attr("class","error-text").attr("x",1250).attr("y",400).attr("font-size","100px").style("text-anchor","middle").text(`mermaid version ${r}`)},"draw"),Df={draw:sT},oT=Df,lT={db:{},renderer:Df,parser:{parse:d(()=>{},"parse")}},cT=lT,Pf="flowchart-elk",hT=d((t,e={})=>{var r;return/^\s*flowchart-elk/.test(t)||/^\s*flowchart|graph/.test(t)&&((r=e==null?void 0:e.flowchart)==null?void 0:r.defaultRenderer)==="elk"?(e.layout="elk",!0):!1},"detector"),uT=d(async()=>{const{diagram:t}=await at(()=>import("./flowDiagram-TGP4CI55-B7tCuQuY.js"),__vite__mapDeps([10,11,12,13,7]));return{id:Pf,diagram:t}},"loader"),fT={id:Pf,detector:hT,loader:uT},dT=fT,Nf="timeline",pT=d(t=>/^\s*timeline/.test(t),"detector"),gT=d(async()=>{const{diagram:t}=await at(()=>import("./timeline-definition-SFF34UE4-Ct_WbDfR.js"),__vite__mapDeps([38,24,7]));return{id:Nf,diagram:t}},"loader"),mT={id:Nf,detector:pT,loader:gT},yT=mT,zf="mindmap",xT=d(t=>/^\s*mindmap/.test(t),"detector"),bT=d(async()=>{const{diagram:t}=await at(()=>import("./mindmap-definition-6NGNQFMS-BtFGEdEC.js"),__vite__mapDeps([39,7]));return{id:zf,diagram:t}},"loader"),_T={id:zf,detector:xT,loader:bT},CT=_T,qf="sankey",vT=d(t=>/^\s*sankey-beta/.test(t),"detector"),kT=d(async()=>{const{diagram:t}=await at(()=>import("./sankeyDiagram-XVFEVEVI-B44r2-sr.js"),__vite__mapDeps([40,25,21,7]));return{id:qf,diagram:t}},"loader"),wT={id:qf,detector:vT,loader:kT},TT=wT,Wf="packet",ST=d(t=>/^\s*packet-beta/.test(t),"detector"),LT=d(async()=>{const{diagram:t}=await at(()=>import("./diagram-KYCGQLJB-BEfwcC9f.js"),__vite__mapDeps([41,16,18,7,2,4,6]));return{id:Wf,diagram:t}},"loader"),AT={id:Wf,detector:ST,loader:LT},Hf="block",BT=d(t=>/^\s*block-beta/.test(t),"detector"),ET=d(async()=>{const{diagram:t}=await at(()=>import("./blockDiagram-V6UOASA5-C4OVhM5p.js"),__vite__mapDeps([42,33,12,6,2,1,13,7]));return{id:Hf,diagram:t}},"loader"),MT={id:Hf,detector:BT,loader:ET},FT=MT,Dc=!1,wa=d(()=>{Dc||(Dc=!0,wn("error",cT,t=>t.toLowerCase().trim()==="error"),wn("---",{db:{clear:d(()=>{},"clear")},styles:{},renderer:{draw:d(()=>{},"draw")},parser:{parse:d(()=>{throw new Error("Diagrams beginning with --- are not valid. If you were trying to use a YAML front-matter, please ensure that you've correctly opened and closed the YAML front-matter with un-indented `---` blocks")},"parse")},init:d(()=>null,"init")},t=>t.toLowerCase().trimStart().startsWith("---")),th(Kk,Gw,Hw,cw,yw,_w,kw,Iw,Nw,dT,aw,ew,CT,yT,dw,eT,Kw,aT,Lw,TT,AT,Mw,FT))},"addDiagrams"),$T=d(async()=>{k.debug("Loading registered diagrams");const e=(await Promise.allSettled(Object.entries(xr).map(async([r,{detector:i,loader:n}])=>{if(n)try{is(r)}catch{try{const{diagram:a,id:s}=await n();wn(s,a,i)}catch(a){throw k.error(`Failed to load external diagram with key ${r}. Removing from detectors.`),delete xr[r],a}}}))).filter(r=>r.status==="rejected");if(e.length>0){k.error(`Failed to load ${e.length} external diagrams`);for(const r of e)k.error(r);throw new Error(`Failed to load ${e.length} external diagrams`)}},"loadRegisteredDiagrams"),Lr,Bs=(Lr=class{constructor(e,r,i,n,a){this.type=e,this.text=r,this.db=i,this.parser=n,this.renderer=a}static async fromText(e,r={}){var c,h;const i=Se(),n=Gs(e,i);e=aC(e)+` +res:`,ut.polygon(e,c,u)),ut.polygon(e,c,u)},n},"question"),ik=d((t,e,r,i,n)=>[`M${t+n},${e}`,`L${t+r-n},${e}`,`L${t+r},${e-i/2}`,`L${t+r-n},${e-i}`,`L${t+n},${e-i}`,`L${t},${e-i/2}`,"Z"].join(" "),"createHexagonPathD"),nk=d(async(t,e)=>{const{labelStyles:r,nodeStyles:i}=Lt(e);e.labelStyle=r;const{shapeSvg:n,bbox:a}=await At(t,e,Yt(e)),s=4,o=a.height+e.padding,l=o/s,c=a.width+2*l+e.padding,h=[{x:l,y:0},{x:c-l,y:0},{x:c,y:-o/2},{x:c-l,y:-o},{x:l,y:-o},{x:0,y:-o/2}];let f;const{cssStyles:u}=e;if(e.look==="handDrawn"){const p=ot.svg(n),g=vt(e,{}),m=ik(0,0,c,o,l),_=p.path(m,g);f=n.insert(()=>_,":first-child").attr("transform",`translate(${-c/2}, ${o/2})`),u&&f.attr("style",u)}else f=Ae(n,c,o,h);return i&&f.attr("style",i),e.width=c,e.height=o,dt(e,f),e.intersect=function(p){return ut.polygon(e,h,p)},n},"hexagon"),ak=d((t,e,r,i)=>[`M${t-2*i/6},${e}`,`L${t+r-i/6},${e}`,`L${t+r+2*i/6},${e-i}`,`L${t+i/6},${e-i}`,"Z"].join(" "),"createLeanRightPathD"),sk=d(async(t,e)=>{const{labelStyles:r,nodeStyles:i}=Lt(e);e.labelStyle=r;const{shapeSvg:n,bbox:a}=await At(t,e,Yt(e)),s=a.width+e.padding,o=a.height+e.padding,l=[{x:-2*o/6,y:0},{x:s-o/6,y:0},{x:s+2*o/6,y:-o},{x:o/6,y:-o}];let c;const{cssStyles:h}=e;if(e.look==="handDrawn"){const f=ot.svg(n),u=vt(e,{}),p=ak(0,0,s,o),g=f.path(p,u);c=n.insert(()=>g,":first-child").attr("transform",`translate(${-s/2}, ${o/2})`),h&&c.attr("style",h)}else c=Ae(n,s,o,l);return i&&c.attr("style",i),e.width=s,e.height=o,dt(e,c),e.intersect=function(f){return ut.polygon(e,l,f)},n},"lean_right"),ok=d((t,e,r,i)=>[`M${t+2*i/6},${e}`,`L${t+r+i/6},${e}`,`L${t+r-2*i/6},${e-i}`,`L${t-i/6},${e-i}`,"Z"].join(" "),"createLeanLeftPathD"),lk=d(async(t,e)=>{const{labelStyles:r,nodeStyles:i}=Lt(e);e.labelStyle=r;const{shapeSvg:n,bbox:a}=await At(t,e,Yt(e)),s=a.width+e.padding,o=a.height+e.padding,l=[{x:2*o/6,y:0},{x:s+o/6,y:0},{x:s-2*o/6,y:-o},{x:-o/6,y:-o}];let c;const{cssStyles:h}=e;if(e.look==="handDrawn"){const f=ot.svg(n),u=vt(e,{}),p=ok(0,0,s,o),g=f.path(p,u);c=n.insert(()=>g,":first-child").attr("transform",`translate(${-s/2}, ${o/2})`),h&&c.attr("style",h)}else c=Ae(n,s,o,l);return i&&c.attr("style",i),e.width=s,e.height=o,dt(e,c),e.intersect=function(f){return ut.polygon(e,l,f)},n},"lean_left"),ck=d((t,e,r,i)=>[`M${t-2*i/6},${e}`,`L${t+r+2*i/6},${e}`,`L${t+r-i/6},${e-i}`,`L${t+i/6},${e-i}`,"Z"].join(" "),"createTrapezoidPathD"),hk=d(async(t,e)=>{const{labelStyles:r,nodeStyles:i}=Lt(e);e.labelStyle=r;const{shapeSvg:n,bbox:a}=await At(t,e,Yt(e)),s=a.width+e.padding,o=a.height+e.padding,l=[{x:-2*o/6,y:0},{x:s+2*o/6,y:0},{x:s-o/6,y:-o},{x:o/6,y:-o}];let c;const{cssStyles:h}=e;if(e.look==="handDrawn"){const f=ot.svg(n),u=vt(e,{}),p=ck(0,0,s,o),g=f.path(p,u);c=n.insert(()=>g,":first-child").attr("transform",`translate(${-s/2}, ${o/2})`),h&&c.attr("style",h)}else c=Ae(n,s,o,l);return i&&c.attr("style",i),e.width=s,e.height=o,dt(e,c),e.intersect=function(f){return ut.polygon(e,l,f)},n},"trapezoid"),uk=d((t,e,r,i)=>[`M${t+i/6},${e}`,`L${t+r-i/6},${e}`,`L${t+r+2*i/6},${e-i}`,`L${t-2*i/6},${e-i}`,"Z"].join(" "),"createInvertedTrapezoidPathD"),fk=d(async(t,e)=>{const{labelStyles:r,nodeStyles:i}=Lt(e);e.labelStyle=r;const{shapeSvg:n,bbox:a}=await At(t,e,Yt(e)),s=a.width+e.padding,o=a.height+e.padding,l=[{x:o/6,y:0},{x:s-o/6,y:0},{x:s+2*o/6,y:-o},{x:-2*o/6,y:-o}];let c;const{cssStyles:h}=e;if(e.look==="handDrawn"){const f=ot.svg(n),u=vt(e,{}),p=uk(0,0,s,o),g=f.path(p,u);c=n.insert(()=>g,":first-child").attr("transform",`translate(${-s/2}, ${o/2})`),h&&c.attr("style",h)}else c=Ae(n,s,o,l);return i&&c.attr("style",i),e.width=s,e.height=o,dt(e,c),e.intersect=function(f){return ut.polygon(e,l,f)},n},"inv_trapezoid"),dk=d(async(t,e)=>{const{shapeSvg:r}=await At(t,e,"label"),i=r.insert("rect",":first-child");return i.attr("width",.1).attr("height",.1),r.attr("class","label edgeLabel"),dt(e,i),e.intersect=function(s){return ut.rect(e,s)},r},"labelRect"),Lc={state:Dv,stateStart:zv,stateEnd:qv,fork:Sc,join:Sc,choice:Wv,note:Hv,roundedRect:Pv,rectWithTitle:Uv,squareRect:Nv,stadium:jv,subroutine:Yv,cylinder:Zv,circle:Kv,doublecircle:Qv,odd:tk,diamond:rk,hexagon:nk,lean_right:sk,lean_left:lk,trapezoid:hk,inv_trapezoid:fk,labelRect:dk},mr=new Map,pk=d(async(t,e,r)=>{let i,n;if(e.shape==="rect"&&(e.rx&&e.ry?e.shape="roundedRect":e.shape="squareRect"),e.link){let a;K().securityLevel==="sandbox"?a="_top":e.linkTarget&&(a=e.linkTarget||"_blank"),i=t.insert("svg:a").attr("xlink:href",e.link).attr("target",a),n=await Lc[e.shape](i,e,r)}else n=await Lc[e.shape](t,e,r),i=n;return e.tooltip&&n.attr("title",e.tooltip),mr.set(e.id,i),e.haveCallback&&mr.get(e.id).attr("class",mr.get(e.id).attr("class")+" clickable"),i},"insertNode"),WS=d((t,e)=>{mr.set(e.id,t)},"setNodeElem"),HS=d(()=>{mr.clear()},"clear"),jS=d(t=>{const e=mr.get(t.id);k.trace("Transforming node",t.diff,t,"translate("+(t.x-t.width/2-5)+", "+t.width/2+")");const r=8,i=t.diff||0;return t.clusterNode?e.attr("transform","translate("+(t.x+i-t.width/2)+", "+(t.y-t.height/2-r)+")"):e.attr("transform","translate("+t.x+", "+t.y+")"),i},"positionNode"),gk={common:Ar,getConfig:Se,insertCluster:fv,insertEdge:_v,insertEdgeLabel:gv,insertMarkers:Fv,insertNode:pk,interpolateToCurve:yo,labelHelper:At,log:k,positionEdgeLabel:mv},gi={},df=d(t=>{for(const e of t)gi[e.name]=e},"registerLayoutLoaders"),mk=d(()=>{df([{name:"dagre",loader:d(async()=>await at(()=>import("./dagre-CQ6OS2HX-BAsLDm3b.js"),__vite__mapDeps([0,1,2,3,4,5,6,7])),"loader")}])},"registerDefaultLayoutLoaders");mk();var US=d(async(t,e)=>{if(!(t.layoutAlgorithm in gi))throw new Error(`Unknown layout algorithm: ${t.layoutAlgorithm}`);const r=gi[t.layoutAlgorithm];return(await r.loader()).render(t,e,gk,{algorithm:r.algorithm})},"render"),YS=d((t="",{fallback:e="dagre"}={})=>{if(t in gi)return t;if(e in gi)return k.warn(`Layout algorithm ${t} is not registered. Using ${e} as fallback.`),e;throw new Error(`Both layout algorithms ${t} and ${e} are not registered.`)},"getRegisteredLayoutAlgorithm"),Ac="11.0.2",yk=d(t=>{var n;const{securityLevel:e}=K();let r=nt("body");if(e==="sandbox"){const s=((n=nt(`#i${t}`).node())==null?void 0:n.contentDocument)??document;r=nt(s.body)}return r.select(`#${t}`)},"selectSvgElement"),pf="comm",gf="rule",mf="decl",xk="@import",bk="@keyframes",_k="@layer",yf=Math.abs,Ro=String.fromCharCode;function xf(t){return t.trim()}function mn(t,e,r){return t.replace(e,r)}function Ck(t,e,r){return t.indexOf(e,r)}function mi(t,e){return t.charCodeAt(e)|0}function yi(t,e,r){return t.slice(e,r)}function ve(t){return t.length}function vk(t){return t.length}function on(t,e){return e.push(t),t}var va=1,wr=1,bf=0,Zt=0,ft=0,Mr="";function Do(t,e,r,i,n,a,s,o){return{value:t,root:e,parent:r,type:i,props:n,children:a,line:va,column:wr,length:s,return:"",siblings:o}}function kk(){return ft}function wk(){return ft=Zt>0?mi(Mr,--Zt):0,wr--,ft===10&&(wr=1,va--),ft}function Jt(){return ft=Zt2||vs(ft)>3?"":" "}function Ak(t,e){for(;--e&&Jt()&&!(ft<48||ft>102||ft>57&&ft<65||ft>70&&ft<97););return ka(t,yn()+(e<6&&Xe()==32&&Jt()==32))}function ks(t){for(;Jt();)switch(ft){case t:return Zt;case 34:case 39:t!==34&&t!==39&&ks(ft);break;case 40:t===41&&ks(t);break;case 92:Jt();break}return Zt}function Bk(t,e){for(;Jt()&&t+ft!==57;)if(t+ft===84&&Xe()===47)break;return"/*"+ka(e,Zt-1)+"*"+Ro(t===47?t:Jt())}function Ek(t){for(;!vs(Xe());)Jt();return ka(t,Zt)}function Mk(t){return Sk(xn("",null,null,null,[""],t=Tk(t),0,[0],t))}function xn(t,e,r,i,n,a,s,o,l){for(var c=0,h=0,f=s,u=0,p=0,g=0,m=1,_=1,C=1,x=0,v="",B=n,$=a,O=i,E=v;_;)switch(g=x,x=Jt()){case 40:if(g!=108&&mi(E,f-1)==58){Ck(E+=mn(Xa(x),"&","&\f"),"&\f",yf(c?o[c-1]:0))!=-1&&(C=-1);break}case 34:case 39:case 91:E+=Xa(x);break;case 9:case 10:case 13:case 32:E+=Lk(g);break;case 92:E+=Ak(yn()-1,7);continue;case 47:switch(Xe()){case 42:case 47:on(Fk(Bk(Jt(),yn()),e,r,l),l);break;default:E+="/"}break;case 123*m:o[c++]=ve(E)*C;case 125*m:case 59:case 0:switch(x){case 0:case 125:_=0;case 59+h:C==-1&&(E=mn(E,/\f/g,"")),p>0&&ve(E)-f&&on(p>32?Ec(E+";",i,r,f-1,l):Ec(mn(E," ","")+";",i,r,f-2,l),l);break;case 59:E+=";";default:if(on(O=Bc(E,e,r,c,h,n,o,v,B=[],$=[],f,a),a),x===123)if(h===0)xn(E,e,O,O,B,a,f,o,$);else switch(u===99&&mi(E,3)===110?100:u){case 100:case 108:case 109:case 115:xn(t,O,O,i&&on(Bc(t,O,O,0,0,n,o,v,n,B=[],f,$),$),n,$,f,o,i?B:$);break;default:xn(E,O,O,O,[""],$,0,o,$)}}c=h=p=0,m=C=1,v=E="",f=s;break;case 58:f=1+ve(E),p=g;default:if(m<1){if(x==123)--m;else if(x==125&&m++==0&&wk()==125)continue}switch(E+=Ro(x),x*m){case 38:C=h>0?1:(E+="\f",-1);break;case 44:o[c++]=(ve(E)-1)*C,C=1;break;case 64:Xe()===45&&(E+=Xa(Jt())),u=Xe(),h=f=ve(v=E+=Ek(yn())),x++;break;case 45:g===45&&ve(E)==2&&(m=0)}}return a}function Bc(t,e,r,i,n,a,s,o,l,c,h,f){for(var u=n-1,p=n===0?a:[""],g=vk(p),m=0,_=0,C=0;m0?p[x]+" "+v:mn(v,/&\f/g,p[x])))&&(l[C++]=B);return Do(t,e,r,n===0?gf:o,l,c,h,f)}function Fk(t,e,r,i){return Do(t,e,r,pf,Ro(kk()),yi(t,2,-2),0,i)}function Ec(t,e,r,i,n){return Do(t,e,r,mf,yi(t,0,i),yi(t,i+1,-1),i,n)}function ws(t,e){for(var r="",i=0;i/^\s*C4Context|C4Container|C4Component|C4Dynamic|C4Deployment/.test(t),"detector"),Xk=d(async()=>{const{diagram:t}=await at(()=>import("./c4Diagram-ZHOUKFWV-rVMnyU9f.js"),__vite__mapDeps([8,9,7]));return{id:_f,diagram:t}},"loader"),Zk={id:_f,detector:Vk,loader:Xk},Kk=Zk,Cf="flowchart",Qk=d((t,e)=>{var r,i;return((r=e==null?void 0:e.flowchart)==null?void 0:r.defaultRenderer)==="dagre-wrapper"||((i=e==null?void 0:e.flowchart)==null?void 0:i.defaultRenderer)==="elk"?!1:/^\s*graph/.test(t)},"detector"),Jk=d(async()=>{const{diagram:t}=await at(()=>import("./flowDiagram-TGP4CI55-c9v2Ypd8.js"),__vite__mapDeps([10,11,12,13,7]));return{id:Cf,diagram:t}},"loader"),tw={id:Cf,detector:Qk,loader:Jk},ew=tw,vf="flowchart-v2",rw=d((t,e)=>{var r,i,n;return((r=e==null?void 0:e.flowchart)==null?void 0:r.defaultRenderer)==="dagre-d3"||((i=e==null?void 0:e.flowchart)==null?void 0:i.defaultRenderer)==="elk"?!1:/^\s*graph/.test(t)&&((n=e==null?void 0:e.flowchart)==null?void 0:n.defaultRenderer)==="dagre-wrapper"?!0:/^\s*flowchart/.test(t)},"detector"),iw=d(async()=>{const{diagram:t}=await at(()=>import("./flowDiagram-TGP4CI55-c9v2Ypd8.js"),__vite__mapDeps([10,11,12,13,7]));return{id:vf,diagram:t}},"loader"),nw={id:vf,detector:rw,loader:iw},aw=nw,kf="er",sw=d(t=>/^\s*erDiagram/.test(t),"detector"),ow=d(async()=>{const{diagram:t}=await at(()=>import("./erDiagram-762WSSOR-CqJrM1JX.js"),__vite__mapDeps([14,1,2,3,4,7]));return{id:kf,diagram:t}},"loader"),lw={id:kf,detector:sw,loader:ow},cw=lw,wf="gitGraph",hw=d(t=>/^\s*gitGraph/.test(t),"detector"),uw=d(async()=>{const{diagram:t}=await at(()=>import("./gitGraphDiagram-LGD5RUNZ-CGesRPAa.js"),__vite__mapDeps([15,16,17,18,7,2,4,6]));return{id:wf,diagram:t}},"loader"),fw={id:wf,detector:hw,loader:uw},dw=fw,Tf="gantt",pw=d(t=>/^\s*gantt/.test(t),"detector"),gw=d(async()=>{const{diagram:t}=await at(()=>import("./ganttDiagram-GAYIUD5S-BewWMKoe.js"),__vite__mapDeps([19,20,21,7]));return{id:Tf,diagram:t}},"loader"),mw={id:Tf,detector:pw,loader:gw},yw=mw,Sf="info",xw=d(t=>/^\s*info/.test(t),"detector"),bw=d(async()=>{const{diagram:t}=await at(()=>import("./infoDiagram-GSXZ5C4N-Dq_SIlpy.js"),__vite__mapDeps([22,18,7,2,4,6]));return{id:Sf,diagram:t}},"loader"),_w={id:Sf,detector:xw,loader:bw},Lf="pie",Cw=d(t=>/^\s*pie/.test(t),"detector"),vw=d(async()=>{const{diagram:t}=await at(()=>import("./pieDiagram-WEX7LNAG-DSCpd-br.js"),__vite__mapDeps([23,16,18,7,2,4,6,24,25,21]));return{id:Lf,diagram:t}},"loader"),kw={id:Lf,detector:Cw,loader:vw},Af="quadrantChart",ww=d(t=>/^\s*quadrantChart/.test(t),"detector"),Tw=d(async()=>{const{diagram:t}=await at(()=>import("./quadrantDiagram-SRYJ5FP7-DIAY3wdM.js"),__vite__mapDeps([26,20,21,7]));return{id:Af,diagram:t}},"loader"),Sw={id:Af,detector:ww,loader:Tw},Lw=Sw,Bf="xychart",Aw=d(t=>/^\s*xychart-beta/.test(t),"detector"),Bw=d(async()=>{const{diagram:t}=await at(()=>import("./xychartDiagram-BZZU7QT5-v7lh-lWp.js"),__vite__mapDeps([27,21,25,20,7]));return{id:Bf,diagram:t}},"loader"),Ew={id:Bf,detector:Aw,loader:Bw},Mw=Ew,Ef="requirement",Fw=d(t=>/^\s*requirement(Diagram)?/.test(t),"detector"),$w=d(async()=>{const{diagram:t}=await at(()=>import("./requirementDiagram-V7TESSIR-kqo49K2z.js"),__vite__mapDeps([28,1,2,3,4,7]));return{id:Ef,diagram:t}},"loader"),Ow={id:Ef,detector:Fw,loader:$w},Iw=Ow,Mf="sequence",Rw=d(t=>/^\s*sequenceDiagram/.test(t),"detector"),Dw=d(async()=>{const{diagram:t}=await at(()=>import("./sequenceDiagram-6SD7JOPP-BbpXK4ej.js"),__vite__mapDeps([29,9,17,7]));return{id:Mf,diagram:t}},"loader"),Pw={id:Mf,detector:Rw,loader:Dw},Nw=Pw,Ff="class",zw=d((t,e)=>{var r;return((r=e==null?void 0:e.class)==null?void 0:r.defaultRenderer)==="dagre-wrapper"?!1:/^\s*classDiagram/.test(t)},"detector"),qw=d(async()=>{const{diagram:t}=await at(()=>import("./classDiagram-MQQPYQM5-p-htZl6Q.js"),__vite__mapDeps([30,31,1,2,3,4,7]));return{id:Ff,diagram:t}},"loader"),Ww={id:Ff,detector:zw,loader:qw},Hw=Ww,$f="classDiagram",jw=d((t,e)=>{var r;return/^\s*classDiagram/.test(t)&&((r=e==null?void 0:e.class)==null?void 0:r.defaultRenderer)==="dagre-wrapper"?!0:/^\s*classDiagram-v2/.test(t)},"detector"),Uw=d(async()=>{const{diagram:t}=await at(()=>import("./classDiagram-v2-4S5WAI72-Dw_LLb4W.js"),__vite__mapDeps([32,33,12,31,1,2,3,4,5,6,7]));return{id:$f,diagram:t}},"loader"),Yw={id:$f,detector:jw,loader:Uw},Gw=Yw,Of="state",Vw=d((t,e)=>{var r;return((r=e==null?void 0:e.state)==null?void 0:r.defaultRenderer)==="dagre-wrapper"?!1:/^\s*stateDiagram/.test(t)},"detector"),Xw=d(async()=>{const{diagram:t}=await at(()=>import("./stateDiagram-N22R6T2Y-ClLx8lyS.js"),__vite__mapDeps([34,35,11,12,1,2,3,4,7]));return{id:Of,diagram:t}},"loader"),Zw={id:Of,detector:Vw,loader:Xw},Kw=Zw,If="stateDiagram",Qw=d((t,e)=>{var r;return!!(/^\s*stateDiagram-v2/.test(t)||/^\s*stateDiagram/.test(t)&&((r=e==null?void 0:e.state)==null?void 0:r.defaultRenderer)==="dagre-wrapper")},"detector"),Jw=d(async()=>{const{diagram:t}=await at(()=>import("./stateDiagram-v2-QXVA2PVL-Cuqsw1mS.js"),__vite__mapDeps([36,35,11,12,7]));return{id:If,diagram:t}},"loader"),tT={id:If,detector:Qw,loader:Jw},eT=tT,Rf="journey",rT=d(t=>/^\s*journey/.test(t),"detector"),iT=d(async()=>{const{diagram:t}=await at(()=>import("./journeyDiagram-35ZZFJAM-CX8IC_rs.js"),__vite__mapDeps([37,9,24,7]));return{id:Rf,diagram:t}},"loader"),nT={id:Rf,detector:rT,loader:iT},aT=nT,sT=d((t,e,r)=>{k.debug(`rendering svg for syntax error +`);const i=yk(e),n=i.append("g");i.attr("viewBox","0 0 2412 512"),fh(i,100,512,!0),n.append("path").attr("class","error-icon").attr("d","m411.313,123.313c6.25-6.25 6.25-16.375 0-22.625s-16.375-6.25-22.625,0l-32,32-9.375,9.375-20.688-20.688c-12.484-12.5-32.766-12.5-45.25,0l-16,16c-1.261,1.261-2.304,2.648-3.31,4.051-21.739-8.561-45.324-13.426-70.065-13.426-105.867,0-192,86.133-192,192s86.133,192 192,192 192-86.133 192-192c0-24.741-4.864-48.327-13.426-70.065 1.402-1.007 2.79-2.049 4.051-3.31l16-16c12.5-12.492 12.5-32.758 0-45.25l-20.688-20.688 9.375-9.375 32.001-31.999zm-219.313,100.687c-52.938,0-96,43.063-96,96 0,8.836-7.164,16-16,16s-16-7.164-16-16c0-70.578 57.422-128 128-128 8.836,0 16,7.164 16,16s-7.164,16-16,16z"),n.append("path").attr("class","error-icon").attr("d","m459.02,148.98c-6.25-6.25-16.375-6.25-22.625,0s-6.25,16.375 0,22.625l16,16c3.125,3.125 7.219,4.688 11.313,4.688 4.094,0 8.188-1.563 11.313-4.688 6.25-6.25 6.25-16.375 0-22.625l-16.001-16z"),n.append("path").attr("class","error-icon").attr("d","m340.395,75.605c3.125,3.125 7.219,4.688 11.313,4.688 4.094,0 8.188-1.563 11.313-4.688 6.25-6.25 6.25-16.375 0-22.625l-16-16c-6.25-6.25-16.375-6.25-22.625,0s-6.25,16.375 0,22.625l15.999,16z"),n.append("path").attr("class","error-icon").attr("d","m400,64c8.844,0 16-7.164 16-16v-32c0-8.836-7.156-16-16-16-8.844,0-16,7.164-16,16v32c0,8.836 7.156,16 16,16z"),n.append("path").attr("class","error-icon").attr("d","m496,96.586h-32c-8.844,0-16,7.164-16,16 0,8.836 7.156,16 16,16h32c8.844,0 16-7.164 16-16 0-8.836-7.156-16-16-16z"),n.append("path").attr("class","error-icon").attr("d","m436.98,75.605c3.125,3.125 7.219,4.688 11.313,4.688 4.094,0 8.188-1.563 11.313-4.688l32-32c6.25-6.25 6.25-16.375 0-22.625s-16.375-6.25-22.625,0l-32,32c-6.251,6.25-6.251,16.375-0.001,22.625z"),n.append("text").attr("class","error-text").attr("x",1440).attr("y",250).attr("font-size","150px").style("text-anchor","middle").text("Syntax error in text"),n.append("text").attr("class","error-text").attr("x",1250).attr("y",400).attr("font-size","100px").style("text-anchor","middle").text(`mermaid version ${r}`)},"draw"),Df={draw:sT},oT=Df,lT={db:{},renderer:Df,parser:{parse:d(()=>{},"parse")}},cT=lT,Pf="flowchart-elk",hT=d((t,e={})=>{var r;return/^\s*flowchart-elk/.test(t)||/^\s*flowchart|graph/.test(t)&&((r=e==null?void 0:e.flowchart)==null?void 0:r.defaultRenderer)==="elk"?(e.layout="elk",!0):!1},"detector"),uT=d(async()=>{const{diagram:t}=await at(()=>import("./flowDiagram-TGP4CI55-c9v2Ypd8.js"),__vite__mapDeps([10,11,12,13,7]));return{id:Pf,diagram:t}},"loader"),fT={id:Pf,detector:hT,loader:uT},dT=fT,Nf="timeline",pT=d(t=>/^\s*timeline/.test(t),"detector"),gT=d(async()=>{const{diagram:t}=await at(()=>import("./timeline-definition-SFF34UE4-GwiTm9yo.js"),__vite__mapDeps([38,24,7]));return{id:Nf,diagram:t}},"loader"),mT={id:Nf,detector:pT,loader:gT},yT=mT,zf="mindmap",xT=d(t=>/^\s*mindmap/.test(t),"detector"),bT=d(async()=>{const{diagram:t}=await at(()=>import("./mindmap-definition-6NGNQFMS-Bk10sQyA.js"),__vite__mapDeps([39,7]));return{id:zf,diagram:t}},"loader"),_T={id:zf,detector:xT,loader:bT},CT=_T,qf="sankey",vT=d(t=>/^\s*sankey-beta/.test(t),"detector"),kT=d(async()=>{const{diagram:t}=await at(()=>import("./sankeyDiagram-XVFEVEVI-BznKSljg.js"),__vite__mapDeps([40,25,21,7]));return{id:qf,diagram:t}},"loader"),wT={id:qf,detector:vT,loader:kT},TT=wT,Wf="packet",ST=d(t=>/^\s*packet-beta/.test(t),"detector"),LT=d(async()=>{const{diagram:t}=await at(()=>import("./diagram-KYCGQLJB-BYpHU2_P.js"),__vite__mapDeps([41,16,18,7,2,4,6]));return{id:Wf,diagram:t}},"loader"),AT={id:Wf,detector:ST,loader:LT},Hf="block",BT=d(t=>/^\s*block-beta/.test(t),"detector"),ET=d(async()=>{const{diagram:t}=await at(()=>import("./blockDiagram-V6UOASA5-Dajk3X5E.js"),__vite__mapDeps([42,33,12,6,2,1,13,7]));return{id:Hf,diagram:t}},"loader"),MT={id:Hf,detector:BT,loader:ET},FT=MT,Dc=!1,wa=d(()=>{Dc||(Dc=!0,wn("error",cT,t=>t.toLowerCase().trim()==="error"),wn("---",{db:{clear:d(()=>{},"clear")},styles:{},renderer:{draw:d(()=>{},"draw")},parser:{parse:d(()=>{throw new Error("Diagrams beginning with --- are not valid. If you were trying to use a YAML front-matter, please ensure that you've correctly opened and closed the YAML front-matter with un-indented `---` blocks")},"parse")},init:d(()=>null,"init")},t=>t.toLowerCase().trimStart().startsWith("---")),th(Kk,Gw,Hw,cw,yw,_w,kw,Iw,Nw,dT,aw,ew,CT,yT,dw,eT,Kw,aT,Lw,TT,AT,Mw,FT))},"addDiagrams"),$T=d(async()=>{k.debug("Loading registered diagrams");const e=(await Promise.allSettled(Object.entries(xr).map(async([r,{detector:i,loader:n}])=>{if(n)try{is(r)}catch{try{const{diagram:a,id:s}=await n();wn(s,a,i)}catch(a){throw k.error(`Failed to load external diagram with key ${r}. Removing from detectors.`),delete xr[r],a}}}))).filter(r=>r.status==="rejected");if(e.length>0){k.error(`Failed to load ${e.length} external diagrams`);for(const r of e)k.error(r);throw new Error(`Failed to load ${e.length} external diagrams`)}},"loadRegisteredDiagrams"),Lr,Bs=(Lr=class{constructor(e,r,i,n,a){this.type=e,this.text=r,this.db=i,this.parser=n,this.renderer=a}static async fromText(e,r={}){var c,h;const i=Se(),n=Gs(e,i);e=aC(e)+` `;try{is(n)}catch{const f=Ag(n);if(!f)throw new Jc(`Diagram ${n} not found.`);const{id:u,diagram:p}=await f();wn(u,p)}const{db:a,parser:s,renderer:o,init:l}=is(n);return s.parser&&(s.parser.yy=a),(c=a.clear)==null||c.call(a),l==null||l(i),r.title&&((h=a.setDiagramTitle)==null||h.call(a,r.title)),await s.parse(e),new Lr(n,e,a,s,o)}async render(e,r){await this.renderer.draw(this.text,e,r,this)}getParser(){return this.parser}getType(){return this.type}},d(Lr,"Diagram"),Lr),Pc=[],OT=d(()=>{Pc.forEach(t=>{t()}),Pc=[]},"attachFunctions"),IT="graphics-document document";function jf(t,e){t.attr("role",IT),e!==""&&t.attr("aria-roledescription",e)}d(jf,"setA11yDiagramInfo");function Uf(t,e,r,i){if(t.insert!==void 0){if(r){const n=`chart-desc-${i}`;t.attr("aria-describedby",n),t.insert("desc",":first-child").attr("id",n).text(r)}if(e){const n=`chart-title-${i}`;t.attr("aria-labelledby",n),t.insert("title",":first-child").attr("id",n).text(e)}}}d(Uf,"addSVGa11yTitleDescription");var RT=d(t=>t.replace(/^\s*%%(?!{)[^\n]+\n?/gm,"").trimStart(),"cleanupComments");function Po(t){return typeof t>"u"||t===null}d(Po,"isNothing");function Yf(t){return typeof t=="object"&&t!==null}d(Yf,"isObject");function Gf(t){return Array.isArray(t)?t:Po(t)?[]:[t]}d(Gf,"toArray");function Vf(t,e){var r,i,n,a;if(e)for(a=Object.keys(e),r=0,i=a.length;ro&&(a=" ... ",e=i-o+a.length),r-i>o&&(s=" ...",r=i+o-s.length),{str:a+t.slice(e,r).replace(/\t/g,"→")+s,pos:i-e+a.length}}d(bn,"getLine");function _n(t,e){return pt.repeat(" ",e-t.length)+t}d(_n,"padStart");function Kf(t,e){if(e=Object.create(e||null),!t.buffer)return null;e.maxLength||(e.maxLength=79),typeof e.indent!="number"&&(e.indent=1),typeof e.linesBefore!="number"&&(e.linesBefore=3),typeof e.linesAfter!="number"&&(e.linesAfter=2);for(var r=/\r?\n|\r|\0/g,i=[0],n=[],a,s=-1;a=r.exec(t.buffer);)n.push(a.index),i.push(a.index+a[0].length),t.position<=a.index&&s<0&&(s=i.length-2);s<0&&(s=i.length-1);var o="",l,c,h=Math.min(t.line+e.linesAfter,n.length).toString().length,f=e.maxLength-(e.indent+h+3);for(l=1;l<=e.linesBefore&&!(s-l<0);l++)c=bn(t.buffer,i[s-l],n[s-l],t.position-(i[s]-i[s-l]),f),o=pt.repeat(" ",e.indent)+_n((t.line-l+1).toString(),h)+" | "+c.str+` @@ -179,7 +179,7 @@ js-yaml/dist/js-yaml.mjs: */const GS=Object.freeze(Object.defineProperty({__proto__:null,default:_S},Symbol.toStringTag,{value:"Module"}));export{RS as $,ee as A,Gu as B,ya as C,Fo as D,fe as E,zg as F,ko as G,Se as H,K1 as I,_m as J,yk as K,Ac as L,Ux as M,jl as N,Hl as O,IS as P,ES as Q,$S as R,FS as S,AS as T,U,oo as V,OS as W,BS as X,hr as Y,DS as Z,d as _,Ct as a,Dl as a$,MS as a0,Og as a1,Xx as a2,si as a3,wS as a4,Vs as a5,vo as a6,W1 as a7,Yh as a8,kS as a9,M1 as aA,fo as aB,Rc as aC,qC as aD,Yx as aE,Zp as aF,Kp as aG,er as aH,N1 as aI,pu as aJ,fa as aK,ma as aL,Pn as aM,mu as aN,du as aO,g1 as aP,ro as aQ,Bh as aR,zt as aS,Oi as aT,xy as aU,Fh as aV,LS as aW,Jp as aX,io as aY,Fe as aZ,ci as a_,om as aa,vu as ab,yo as ac,jh as ad,ph as ae,km as af,Z1 as ag,Sg as ah,dh as ai,Mi as aj,q as ak,W as al,Fv as am,HS as an,qS as ao,zS as ap,dt as aq,WS as ar,pk as as,jS as at,fv as au,_v as av,mv as aw,gv as ax,P1 as ay,E_ as az,gm as b,Ty as b0,D1 as b1,E1 as b2,y_ as b3,po as b4,u1 as b5,q1 as b6,Ri as b7,Br as b8,In as b9,v1 as ba,Dk as bb,Ii as bc,Dn as bd,m1 as be,ou as bf,__ as bg,C_ as bh,We as bi,ac as bj,v_ as bk,go as bl,b_ as bm,T_ as bn,Er as bo,De as bp,tc as bq,mo as br,cu as bs,Ls as bt,z1 as bu,ga as bv,GS as bw,pm as c,K as d,Ar as e,wu as f,dm as g,di as h,Cr as i,nt as j,fh as k,k as l,gh as m,Fi as n,TS as o,SS as p,mm as q,ym as r,fm as s,um as t,le as u,PS as v,tC as w,YS as x,US as y,ti as z}; function __vite__mapDeps(indexes) { if (!__vite__mapDeps.viteFileDeps) { - __vite__mapDeps.viteFileDeps = ["assets/dagre-CQ6OS2HX-BRwnzFkj.js","assets/graph-Oq3lz9SV.js","assets/baseUniq-ZJgB7efo.js","assets/layout-7AWYeW5Q.js","assets/basePickBy-BXIHjUx3.js","assets/json-BFhFIfeY.js","assets/clone-B3i2nD77.js","assets/app-DBM4OJyw.js","assets/c4Diagram-ZHOUKFWV-20XrCBlj.js","assets/chunk-AIUMCIBP-g55d6rFj.js","assets/flowDiagram-TGP4CI55-B7tCuQuY.js","assets/chunk-FUIDI54P-DcJSRBm9.js","assets/chunk-Z2VRG6XP-DsASRjJ5.js","assets/channel-BHWICgEe.js","assets/erDiagram-762WSSOR-CtIJPNj4.js","assets/gitGraphDiagram-LGD5RUNZ-DqNoDc6j.js","assets/chunk-JJENOPKO-CSqkWYi8.js","assets/chunk-FBCX6ULS-BW7zNCW8.js","assets/gitGraph-F2EDSAW4-IXsRUTzt.js","assets/ganttDiagram-GAYIUD5S-p-lGuXqL.js","assets/linear-D4Bza9R9.js","assets/init-Gi6I4Gst.js","assets/infoDiagram-GSXZ5C4N-BldMtTiD.js","assets/pieDiagram-WEX7LNAG-BT3MbsDU.js","assets/arc-CO2v8jBL.js","assets/ordinal-Cboi1Yqb.js","assets/quadrantDiagram-SRYJ5FP7-DraEpiPS.js","assets/xychartDiagram-BZZU7QT5-VXQiVXRw.js","assets/requirementDiagram-V7TESSIR-ptPfSQ70.js","assets/sequenceDiagram-6SD7JOPP-BG3IUlAD.js","assets/classDiagram-MQQPYQM5-D7Ouc99y.js","assets/chunk-IBIA4ERB-Cq5yRPLn.js","assets/classDiagram-v2-4S5WAI72-OQWCgw14.js","assets/chunk-PDCO53Z4-RQMWNvLJ.js","assets/stateDiagram-N22R6T2Y-BFbyHmsw.js","assets/chunk-SVGOEX7Z-7nrOxk8C.js","assets/stateDiagram-v2-QXVA2PVL-C7QgvS5i.js","assets/journeyDiagram-35ZZFJAM-BivG2OsD.js","assets/timeline-definition-SFF34UE4-Ct_WbDfR.js","assets/mindmap-definition-6NGNQFMS-BtFGEdEC.js","assets/sankeyDiagram-XVFEVEVI-B44r2-sr.js","assets/diagram-KYCGQLJB-BEfwcC9f.js","assets/blockDiagram-V6UOASA5-C4OVhM5p.js"] + __vite__mapDeps.viteFileDeps = ["assets/dagre-CQ6OS2HX-BAsLDm3b.js","assets/graph-Cjb-DGHB.js","assets/baseUniq-D0lZO5yp.js","assets/layout-CHeuV-iP.js","assets/basePickBy-DpnmgMOi.js","assets/json-31kD9U7J.js","assets/clone-DWnk59eF.js","assets/app-D7uBbsY3.js","assets/c4Diagram-ZHOUKFWV-rVMnyU9f.js","assets/chunk-AIUMCIBP-v8d5o65o.js","assets/flowDiagram-TGP4CI55-c9v2Ypd8.js","assets/chunk-FUIDI54P-B3wdDwu1.js","assets/chunk-Z2VRG6XP-CV0pyCU1.js","assets/channel-uApa1cOK.js","assets/erDiagram-762WSSOR-CqJrM1JX.js","assets/gitGraphDiagram-LGD5RUNZ-CGesRPAa.js","assets/chunk-JJENOPKO-7opA8rsx.js","assets/chunk-FBCX6ULS-B99hIK7X.js","assets/gitGraph-F2EDSAW4-Df57CYyu.js","assets/ganttDiagram-GAYIUD5S-BewWMKoe.js","assets/linear-hDJDjKgB.js","assets/init-Gi6I4Gst.js","assets/infoDiagram-GSXZ5C4N-Dq_SIlpy.js","assets/pieDiagram-WEX7LNAG-DSCpd-br.js","assets/arc-9Itq1iXl.js","assets/ordinal-Cboi1Yqb.js","assets/quadrantDiagram-SRYJ5FP7-DIAY3wdM.js","assets/xychartDiagram-BZZU7QT5-v7lh-lWp.js","assets/requirementDiagram-V7TESSIR-kqo49K2z.js","assets/sequenceDiagram-6SD7JOPP-BbpXK4ej.js","assets/classDiagram-MQQPYQM5-p-htZl6Q.js","assets/chunk-IBIA4ERB-LOBGu4Xm.js","assets/classDiagram-v2-4S5WAI72-Dw_LLb4W.js","assets/chunk-PDCO53Z4-BcfC0Pnz.js","assets/stateDiagram-N22R6T2Y-ClLx8lyS.js","assets/chunk-SVGOEX7Z-FYkNEjJq.js","assets/stateDiagram-v2-QXVA2PVL-Cuqsw1mS.js","assets/journeyDiagram-35ZZFJAM-CX8IC_rs.js","assets/timeline-definition-SFF34UE4-GwiTm9yo.js","assets/mindmap-definition-6NGNQFMS-Bk10sQyA.js","assets/sankeyDiagram-XVFEVEVI-BznKSljg.js","assets/diagram-KYCGQLJB-BYpHU2_P.js","assets/blockDiagram-V6UOASA5-Dajk3X5E.js"] } return indexes.map((i) => __vite__mapDeps.viteFileDeps[i]) } diff --git a/assets/metrics.html-BT-2HBU5.js b/assets/metrics.html-CgPI3fiS.js similarity index 99% rename from assets/metrics.html-BT-2HBU5.js rename to assets/metrics.html-CgPI3fiS.js index 9ac44e9350..74cf4b7c33 100644 --- a/assets/metrics.html-BT-2HBU5.js +++ b/assets/metrics.html-CgPI3fiS.js @@ -1,4 +1,4 @@ -import{_ as i,r as p,o as l,c as u,a,b as s,d as n,e}from"./app-DBM4OJyw.js";const r={},c=e(`

                                      Метрики

                                      Более простой (и, надеюсь, лучший) способ экспорта статистики.

                                      Связанные настройки

                                      Можно добавить входящее подключение metrics в раздел inbounds:

                                          "inbounds": [
                                      +import{_ as i,r as p,o as l,c as u,a,b as s,d as n,e}from"./app-D7uBbsY3.js";const r={},c=e(`

                                      Метрики

                                      Более простой (и, надеюсь, лучший) способ экспорта статистики.

                                      Связанные настройки

                                      Можно добавить входящее подключение metrics в раздел inbounds:

                                          "inbounds": [
                                               {
                                                   "listen": "127.0.0.1",
                                                   "port": 11111,
                                      diff --git a/assets/metrics.html-Bf2B_O2D.js b/assets/metrics.html-DaweKFfI.js
                                      similarity index 99%
                                      rename from assets/metrics.html-Bf2B_O2D.js
                                      rename to assets/metrics.html-DaweKFfI.js
                                      index c2494a069a..4e6c55a4d0 100644
                                      --- a/assets/metrics.html-Bf2B_O2D.js
                                      +++ b/assets/metrics.html-DaweKFfI.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as i,r as p,o as l,c as u,a,b as s,d as n,e}from"./app-DBM4OJyw.js";const r={},c=e(`

                                      Metrics

                                      A more straightforward (and hopefully better) way to export metrics.

                                      It's possible to add a metrics inbound among inbounds.

                                          "inbounds": [
                                      +import{_ as i,r as p,o as l,c as u,a,b as s,d as n,e}from"./app-D7uBbsY3.js";const r={},c=e(`

                                      Metrics

                                      A more straightforward (and hopefully better) way to export metrics.

                                      It's possible to add a metrics inbound among inbounds.

                                          "inbounds": [
                                               {
                                                   "listen": "127.0.0.1",
                                                   "port": 11111,
                                      diff --git a/assets/metrics.html-DSYbmHxQ.js b/assets/metrics.html-JNEl1HLA.js
                                      similarity index 99%
                                      rename from assets/metrics.html-DSYbmHxQ.js
                                      rename to assets/metrics.html-JNEl1HLA.js
                                      index 0b5ba751a6..f95a349855 100644
                                      --- a/assets/metrics.html-DSYbmHxQ.js
                                      +++ b/assets/metrics.html-JNEl1HLA.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as i,r as p,o as l,c as u,a,b as s,d as n,e}from"./app-DBM4OJyw.js";const r={},c=e(`

                                      Metrics

                                      更直接(希望更好)的统计导出方式。

                                      相关配置

                                      可以在 inbounds 配置中增加一个 metrics 的 inbound

                                          "inbounds": [
                                      +import{_ as i,r as p,o as l,c as u,a,b as s,d as n,e}from"./app-D7uBbsY3.js";const r={},c=e(`

                                      Metrics

                                      更直接(希望更好)的统计导出方式。

                                      相关配置

                                      可以在 inbounds 配置中增加一个 metrics 的 inbound

                                          "inbounds": [
                                               {
                                                   "listen": "127.0.0.1",
                                                   "port": 11111,
                                      diff --git a/assets/mindmap-definition-6NGNQFMS-BtFGEdEC.js b/assets/mindmap-definition-6NGNQFMS-Bk10sQyA.js
                                      similarity index 99%
                                      rename from assets/mindmap-definition-6NGNQFMS-BtFGEdEC.js
                                      rename to assets/mindmap-definition-6NGNQFMS-Bk10sQyA.js
                                      index 78852e803b..17228225c7 100644
                                      --- a/assets/mindmap-definition-6NGNQFMS-BtFGEdEC.js
                                      +++ b/assets/mindmap-definition-6NGNQFMS-Bk10sQyA.js
                                      @@ -1,4 +1,4 @@
                                      -import{aF as vi,aG as sl,_ as ce,l as wr,j as ol,D as ul,a6 as ll,d as ci,K as fl,aa as hl,F as en,i as tn,aj as vl,ak as cl,al as dl}from"./mermaid.core-DapiNGBY.js";import"./app-DBM4OJyw.js";function qe(t){"@babel/helpers - typeof";return qe=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(e){return typeof e}:function(e){return e&&typeof Symbol=="function"&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},qe(t)}function di(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function gl(t,e){for(var r=0;rt.length)&&(e=t.length);for(var r=0,a=new Array(e);rt.length)&&(e=t.length);for(var r=0,a=new Array(e);r=t.length?{done:!0}:{done:!1,value:t[a++]}},e:function(u){throw u},f:n}}throw new TypeError(`Invalid attempt to iterate non-iterable instance.
                                       In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}var s=!0,i=!1,o;return{s:function(){r=r.call(t)},n:function(){var u=r.next();return s=u.done,u},e:function(u){i=!0,o=u},f:function(){try{!s&&r.return!=null&&r.return()}finally{if(i)throw o}}}}var Ye=typeof window>"u"?null:window,Xi=Ye?Ye.navigator:null;Ye&&Ye.document;var El=qe(""),uo=qe({}),wl=qe(function(){}),xl=typeof HTMLElement>"u"?"undefined":qe(HTMLElement),Ta=function(e){return e&&e.instanceString&&ze(e.instanceString)?e.instanceString():null},de=function(e){return e!=null&&qe(e)==El},ze=function(e){return e!=null&&qe(e)===wl},ke=function(e){return!yt(e)&&(Array.isArray?Array.isArray(e):e!=null&&e instanceof Array)},De=function(e){return e!=null&&qe(e)===uo&&!ke(e)&&e.constructor===Object},Tl=function(e){return e!=null&&qe(e)===uo},ie=function(e){return e!=null&&qe(e)===qe(1)&&!isNaN(e)},Cl=function(e){return ie(e)&&Math.floor(e)===e},rn=function(e){if(xl!=="undefined")return e!=null&&e instanceof HTMLElement},yt=function(e){return Ca(e)||lo(e)},Ca=function(e){return Ta(e)==="collection"&&e._private.single},lo=function(e){return Ta(e)==="collection"&&!e._private.single},pi=function(e){return Ta(e)==="core"},fo=function(e){return Ta(e)==="stylesheet"},Dl=function(e){return Ta(e)==="event"},er=function(e){return e==null?!0:!!(e===""||e.match(/^\s+$/))},Sl=function(e){return typeof HTMLElement>"u"?!1:e instanceof HTMLElement},Ll=function(e){return De(e)&&ie(e.x1)&&ie(e.x2)&&ie(e.y1)&&ie(e.y2)},Al=function(e){return Tl(e)&&ze(e.then)},Ol=function(){return Xi&&Xi.userAgent.match(/msie|trident|edge/i)},va=function(e,r){r||(r=function(){if(arguments.length===1)return arguments[0];if(arguments.length===0)return"undefined";for(var s=[],i=0;ir?1:0},Bl=function(e,r){return-1*vo(e,r)},Ee=Object.assign!=null?Object.assign.bind(Object):function(t){for(var e=arguments,r=1;r1&&(g-=1),g<1/6?c+(p-c)*6*g:g<1/2?p:g<2/3?c+(p-c)*(2/3-g)*6:c}var h=new RegExp("^"+Ml+"$").exec(e);if(h){if(a=parseInt(h[1]),a<0?a=(360- -1*a%360)%360:a>360&&(a=a%360),a/=360,n=parseFloat(h[2]),n<0||n>100||(n=n/100,s=parseFloat(h[3]),s<0||s>100)||(s=s/100,i=h[4],i!==void 0&&(i=parseFloat(i),i<0||i>1)))return;if(n===0)o=u=l=Math.round(s*255);else{var d=s<.5?s*(1+n):s+n-s*n,v=2*s-d;o=Math.round(255*f(v,d,a+1/3)),u=Math.round(255*f(v,d,a)),l=Math.round(255*f(v,d,a-1/3))}r=[o,u,l,i]}return r},zl=function(e){var r,a=new RegExp("^"+Nl+"$").exec(e);if(a){r=[];for(var n=[],s=1;s<=3;s++){var i=a[s];if(i[i.length-1]==="%"&&(n[s]=!0),i=parseFloat(i),n[s]&&(i=i/100*255),i<0||i>255)return;r.push(Math.floor(i))}var o=n[1]||n[2]||n[3],u=n[1]&&n[2]&&n[3];if(o&&!u)return;var l=a[4];if(l!==void 0){if(l=parseFloat(l),l<0||l>1)return;r.push(l)}}return r},Vl=function(e){return $l[e.toLowerCase()]},Ul=function(e){return(ke(e)?e:null)||Vl(e)||Fl(e)||zl(e)||Gl(e)},$l={transparent:[0,0,0,0],aliceblue:[240,248,255],antiquewhite:[250,235,215],aqua:[0,255,255],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,228,196],black:[0,0,0],blanchedalmond:[255,235,205],blue:[0,0,255],blueviolet:[138,43,226],brown:[165,42,42],burlywood:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerblue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgoldenrod:[184,134,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslategrey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgray:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,250,240],forestgreen:[34,139,34],fuchsia:[255,0,255],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[218,165,32],gray:[128,128,128],grey:[128,128,128],green:[0,128,0],greenyellow:[173,255,47],honeydew:[240,255,240],hotpink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230,250],lavenderblush:[255,240,245],lawngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcoral:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightsalmon:[255,160,122],lightseagreen:[32,178,170],lightskyblue:[135,206,250],lightslategray:[119,136,153],lightslategrey:[119,136,153],lightsteelblue:[176,196,222],lightyellow:[255,255,224],lime:[0,255,0],limegreen:[50,205,50],linen:[250,240,230],magenta:[255,0,255],maroon:[128,0,0],mediumaquamarine:[102,205,170],mediumblue:[0,0,205],mediumorchid:[186,85,211],mediumpurple:[147,112,219],mediumseagreen:[60,179,113],mediumslateblue:[123,104,238],mediumspringgreen:[0,250,154],mediumturquoise:[72,209,204],mediumvioletred:[199,21,133],midnightblue:[25,25,112],mintcream:[245,255,250],mistyrose:[255,228,225],moccasin:[255,228,181],navajowhite:[255,222,173],navy:[0,0,128],oldlace:[253,245,230],olive:[128,128,0],olivedrab:[107,142,35],orange:[255,165,0],orangered:[255,69,0],orchid:[218,112,214],palegoldenrod:[238,232,170],palegreen:[152,251,152],paleturquoise:[175,238,238],palevioletred:[219,112,147],papayawhip:[255,239,213],peachpuff:[255,218,185],peru:[205,133,63],pink:[255,192,203],plum:[221,160,221],powderblue:[176,224,230],purple:[128,0,128],red:[255,0,0],rosybrown:[188,143,143],royalblue:[65,105,225],saddlebrown:[139,69,19],salmon:[250,128,114],sandybrown:[244,164,96],seagreen:[46,139,87],seashell:[255,245,238],sienna:[160,82,45],silver:[192,192,192],skyblue:[135,206,235],slateblue:[106,90,205],slategray:[112,128,144],slategrey:[112,128,144],snow:[255,250,250],springgreen:[0,255,127],steelblue:[70,130,180],tan:[210,180,140],teal:[0,128,128],thistle:[216,191,216],tomato:[255,99,71],turquoise:[64,224,208],violet:[238,130,238],wheat:[245,222,179],white:[255,255,255],whitesmoke:[245,245,245],yellow:[255,255,0],yellowgreen:[154,205,50]},co=function(e){for(var r=e.map,a=e.keys,n=a.length,s=0;s=e||E<0||h&&x>=s}function y(){var S=kn();if(g(S))return b(S);o=setTimeout(y,p(S))}function b(S){return o=void 0,d&&a?v(S):(a=n=void 0,i)}function m(){o!==void 0&&clearTimeout(o),l=0,a=u=n=o=void 0}function T(){return o===void 0?i:b(kn())}function C(){var S=kn(),E=g(S);if(a=arguments,n=this,u=S,E){if(o===void 0)return c(u);if(h)return clearTimeout(o),o=setTimeout(y,e),v(u)}return o===void 0&&(o=setTimeout(y,e)),i}return C.cancel=m,C.flush=T,C}var pn=Lf,Pn=Ye?Ye.performance:null,mo=Pn&&Pn.now?function(){return Pn.now()}:function(){return Date.now()},Af=function(){if(Ye){if(Ye.requestAnimationFrame)return function(t){Ye.requestAnimationFrame(t)};if(Ye.mozRequestAnimationFrame)return function(t){Ye.mozRequestAnimationFrame(t)};if(Ye.webkitRequestAnimationFrame)return function(t){Ye.webkitRequestAnimationFrame(t)};if(Ye.msRequestAnimationFrame)return function(t){Ye.msRequestAnimationFrame(t)}}return function(t){t&&setTimeout(function(){t(mo())},1e3/60)}}(),an=function(e){return Af(e)},_t=mo,Ir=9261,bo=65599,sa=5381,Eo=function(e){for(var r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:Ir,a=r,n;n=e.next(),!n.done;)a=a*bo+n.value|0;return a},ca=function(e){var r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:Ir;return r*bo+e|0},da=function(e){var r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:sa;return(r<<5)+r+e|0},Of=function(e,r){return e*2097152+r},Wt=function(e){return e[0]*2097152+e[1]},Ra=function(e,r){return[ca(e[0],r[0]),da(e[1],r[1])]},Nf=function(e,r){var a={value:0,done:!1},n=0,s=e.length,i={next:function(){return n=0;n--)e[n]===r&&e.splice(n,1)},Ei=function(e){e.splice(0,e.length)},Ff=function(e,r){for(var a=0;a"u"?"undefined":qe(Set))!==zf?Set:Vf,yn=function(e,r){var a=arguments.length>2&&arguments[2]!==void 0?arguments[2]:!0;if(e===void 0||r===void 0||!pi(e)){Ve("An element must have a core reference and parameters set");return}var n=r.group;if(n==null&&(r.data&&r.data.source!=null&&r.data.target!=null?n="edges":n="nodes"),n!=="nodes"&&n!=="edges"){Ve("An element must be of type `nodes` or `edges`; you specified `"+n+"`");return}this.length=1,this[0]=this;var s=this._private={cy:e,single:!0,data:r.data||{},position:r.position||{x:0,y:0},autoWidth:void 0,autoHeight:void 0,autoPadding:void 0,compoundBoundsClean:!1,listeners:[],group:n,style:{},rstyle:{},styleCxts:[],styleKeys:{},removed:!0,selected:!!r.selected,selectable:r.selectable===void 0?!0:!!r.selectable,locked:!!r.locked,grabbed:!1,grabbable:r.grabbable===void 0?!0:!!r.grabbable,pannable:r.pannable===void 0?n==="edges":!!r.pannable,active:!1,classes:new $r,animation:{current:[],queue:[]},rscratch:{},scratch:r.scratch||{},edges:[],children:[],parent:r.parent&&r.parent.isNode()?r.parent:null,traversalCache:{},backgrounding:!1,bbCache:null,bbCacheShift:{x:0,y:0},bodyBounds:null,overlayBounds:null,labelBounds:{all:null,source:null,target:null,main:null},arrowBounds:{source:null,target:null,"mid-source":null,"mid-target":null}};if(s.position.x==null&&(s.position.x=0),s.position.y==null&&(s.position.y=0),r.renderedPosition){var i=r.renderedPosition,o=e.pan(),u=e.zoom();s.position={x:(i.x-o.x)/u,y:(i.y-o.y)/u}}var l=[];ke(r.classes)?l=r.classes:de(r.classes)&&(l=r.classes.split(/\s+/));for(var f=0,h=l.length;fb?1:0},f=function(y,b,m,T,C){var S;if(m==null&&(m=0),C==null&&(C=a),m<0)throw new Error("lo must be non-negative");for(T==null&&(T=y.length);mD;0<=D?w++:w--)x.push(w);return x}).apply(this).reverse(),E=[],T=0,C=S.length;TL;0<=L?++x:--x)A.push(i(y,m));return A},p=function(y,b,m,T){var C,S,E;for(T==null&&(T=a),C=y[m];m>b;){if(E=m-1>>1,S=y[E],T(C,S)<0){y[m]=S,m=E;continue}break}return y[m]=C},g=function(y,b,m){var T,C,S,E,x;for(m==null&&(m=a),C=y.length,x=b,S=y[b],T=2*b+1;T0;){var S=b.pop(),E=g(S),x=S.id();if(d[x]=E,E!==1/0)for(var w=S.neighborhood().intersect(c),D=0;D0)for(P.unshift(k);h[V];){var F=h[V];P.unshift(F.edge),P.unshift(F.node),B=F.node,V=B.id()}return o.spawn(P)}}}},Yf={kruskal:function(e){e=e||function(m){return 1};for(var r=this.byGroup(),a=r.nodes,n=r.edges,s=a.length,i=new Array(s),o=a,u=function(T){for(var C=0;C0;){if(C(),E++,T===f){for(var x=[],w=s,D=f,L=y[D];x.unshift(w),L!=null&&x.unshift(L),w=g[D],w!=null;)D=w.id(),L=y[D];return{found:!0,distance:h[T],path:this.spawn(x),steps:E}}v[T]=!0;for(var A=m._private.edges,I=0;IL&&(c[D]=L,b[D]=w,m[D]=C),!s){var A=w*f+x;!s&&c[A]>L&&(c[A]=L,b[A]=x,m[A]=C)}}}for(var I=0;I1&&arguments[1]!==void 0?arguments[1]:i,Oe=m(fe),Te=[],xe=Oe;;){if(xe==null)return r.spawn();var Se=b(xe),ee=Se.edge,N=Se.pred;if(Te.unshift(xe[0]),xe.same(pe)&&Te.length>0)break;ee!=null&&Te.unshift(ee),xe=N}return u.spawn(Te)},S=0;S=0;f--){var h=l[f],d=h[1],v=h[2];(r[d]===o&&r[v]===u||r[d]===u&&r[v]===o)&&l.splice(f,1)}for(var c=0;cn;){var s=Math.floor(Math.random()*r.length);r=Jf(s,e,r),a--}return r},jf={kargerStein:function(){var e=this,r=this.byGroup(),a=r.nodes,n=r.edges;n.unmergeBy(function(P){return P.isLoop()});var s=a.length,i=n.length,o=Math.ceil(Math.pow(Math.log(s)/Math.LN2,2)),u=Math.floor(s/Qf);if(s<2){Ve("At least 2 nodes are required for Karger-Stein algorithm");return}for(var l=[],f=0;f1&&arguments[1]!==void 0?arguments[1]:0,a=arguments.length>2&&arguments[2]!==void 0?arguments[2]:e.length,n=1/0,s=r;s1&&arguments[1]!==void 0?arguments[1]:0,a=arguments.length>2&&arguments[2]!==void 0?arguments[2]:e.length,n=-1/0,s=r;s1&&arguments[1]!==void 0?arguments[1]:0,a=arguments.length>2&&arguments[2]!==void 0?arguments[2]:e.length,n=0,s=0,i=r;i1&&arguments[1]!==void 0?arguments[1]:0,a=arguments.length>2&&arguments[2]!==void 0?arguments[2]:e.length,n=arguments.length>3&&arguments[3]!==void 0?arguments[3]:!0,s=arguments.length>4&&arguments[4]!==void 0?arguments[4]:!0,i=arguments.length>5&&arguments[5]!==void 0?arguments[5]:!0;n?e=e.slice(r,a):(a0&&e.splice(0,r));for(var o=0,u=e.length-1;u>=0;u--){var l=e[u];i?isFinite(l)||(e[u]=-1/0,o++):e.splice(u,1)}s&&e.sort(function(d,v){return d-v});var f=e.length,h=Math.floor(f/2);return f%2!==0?e[h+1+o]:(e[h-1+o]+e[h+o])/2},ih=function(e){return Math.PI*e/180},ka=function(e,r){return Math.atan2(r,e)-Math.PI/2},wi=Math.log2||function(t){return Math.log(t)/Math.log(2)},Lo=function(e){return e>0?1:e<0?-1:0},pr=function(e,r){return Math.sqrt(lr(e,r))},lr=function(e,r){var a=r.x-e.x,n=r.y-e.y;return a*a+n*n},sh=function(e){for(var r=e.length,a=0,n=0;n=e.x1&&e.y2>=e.y1)return{x1:e.x1,y1:e.y1,x2:e.x2,y2:e.y2,w:e.x2-e.x1,h:e.y2-e.y1};if(e.w!=null&&e.h!=null&&e.w>=0&&e.h>=0)return{x1:e.x1,y1:e.y1,x2:e.x1+e.w,y2:e.y1+e.h,w:e.w,h:e.h}}},uh=function(e){return{x1:e.x1,x2:e.x2,w:e.w,y1:e.y1,y2:e.y2,h:e.h}},lh=function(e){e.x1=1/0,e.y1=1/0,e.x2=-1/0,e.y2=-1/0,e.w=0,e.h=0},fh=function(e,r,a){return{x1:e.x1+r,x2:e.x2+r,y1:e.y1+a,y2:e.y2+a,w:e.w,h:e.h}},Ao=function(e,r){e.x1=Math.min(e.x1,r.x1),e.x2=Math.max(e.x2,r.x2),e.w=e.x2-e.x1,e.y1=Math.min(e.y1,r.y1),e.y2=Math.max(e.y2,r.y2),e.h=e.y2-e.y1},hh=function(e,r,a){e.x1=Math.min(e.x1,r),e.x2=Math.max(e.x2,r),e.w=e.x2-e.x1,e.y1=Math.min(e.y1,a),e.y2=Math.max(e.y2,a),e.h=e.y2-e.y1},Ha=function(e){var r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:0;return e.x1-=r,e.x2+=r,e.y1-=r,e.y2+=r,e.w=e.x2-e.x1,e.h=e.y2-e.y1,e},Xa=function(e){var r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:[0],a,n,s,i;if(r.length===1)a=n=s=i=r[0];else if(r.length===2)a=s=r[0],i=n=r[1];else if(r.length===4){var o=Lt(r,4);a=o[0],n=o[1],s=o[2],i=o[3]}return e.x1-=i,e.x2+=n,e.y1-=a,e.y2+=s,e.w=e.x2-e.x1,e.h=e.y2-e.y1,e},es=function(e,r){e.x1=r.x1,e.y1=r.y1,e.x2=r.x2,e.y2=r.y2,e.w=e.x2-e.x1,e.h=e.y2-e.y1},xi=function(e,r){return!(e.x1>r.x2||r.x1>e.x2||e.x2r.y2||r.y1>e.y2)},zr=function(e,r,a){return e.x1<=r&&r<=e.x2&&e.y1<=a&&a<=e.y2},vh=function(e,r){return zr(e,r.x,r.y)},Oo=function(e,r){return zr(e,r.x1,r.y1)&&zr(e,r.x2,r.y2)},No=function(e,r,a,n,s,i,o){var u=arguments.length>7&&arguments[7]!==void 0?arguments[7]:"auto",l=u==="auto"?yr(s,i):u,f=s/2,h=i/2;l=Math.min(l,f,h);var d=l!==f,v=l!==h,c;if(d){var p=a-f+l-o,g=n-h-o,y=a+f-l+o,b=g;if(c=Qt(e,r,a,n,p,g,y,b,!1),c.length>0)return c}if(v){var m=a+f+o,T=n-h+l-o,C=m,S=n+h-l+o;if(c=Qt(e,r,a,n,m,T,C,S,!1),c.length>0)return c}if(d){var E=a-f+l-o,x=n+h+o,w=a+f-l+o,D=x;if(c=Qt(e,r,a,n,E,x,w,D,!1),c.length>0)return c}if(v){var L=a-f-o,A=n-h+l-o,I=L,O=n+h-l+o;if(c=Qt(e,r,a,n,L,A,I,O,!1),c.length>0)return c}var M;{var R=a-f+l,k=n-h+l;if(M=oa(e,r,a,n,R,k,l+o),M.length>0&&M[0]<=R&&M[1]<=k)return[M[0],M[1]]}{var P=a+f-l,B=n-h+l;if(M=oa(e,r,a,n,P,B,l+o),M.length>0&&M[0]>=P&&M[1]<=B)return[M[0],M[1]]}{var V=a+f-l,F=n+h-l;if(M=oa(e,r,a,n,V,F,l+o),M.length>0&&M[0]>=V&&M[1]>=F)return[M[0],M[1]]}{var z=a-f+l,_=n+h-l;if(M=oa(e,r,a,n,z,_,l+o),M.length>0&&M[0]<=z&&M[1]>=_)return[M[0],M[1]]}return[]},ch=function(e,r,a,n,s,i,o){var u=o,l=Math.min(a,s),f=Math.max(a,s),h=Math.min(n,i),d=Math.max(n,i);return l-u<=e&&e<=f+u&&h-u<=r&&r<=d+u},dh=function(e,r,a,n,s,i,o,u,l){var f={x1:Math.min(a,o,s)-l,x2:Math.max(a,o,s)+l,y1:Math.min(n,u,i)-l,y2:Math.max(n,u,i)+l};return!(ef.x2||rf.y2)},gh=function(e,r,a,n){a-=n;var s=r*r-4*e*a;if(s<0)return[];var i=Math.sqrt(s),o=2*e,u=(-r+i)/o,l=(-r-i)/o;return[u,l]},ph=function(e,r,a,n,s){var i=1e-5;e===0&&(e=i),r/=e,a/=e,n/=e;var o,u,l,f,h,d,v,c;if(u=(3*a-r*r)/9,l=-(27*n)+r*(9*a-2*(r*r)),l/=54,o=u*u*u+l*l,s[1]=0,v=r/3,o>0){h=l+Math.sqrt(o),h=h<0?-Math.pow(-h,1/3):Math.pow(h,1/3),d=l-Math.sqrt(o),d=d<0?-Math.pow(-d,1/3):Math.pow(d,1/3),s[0]=-v+h+d,v+=(h+d)/2,s[4]=s[2]=-v,v=Math.sqrt(3)*(-d+h)/2,s[3]=v,s[5]=-v;return}if(s[5]=s[3]=0,o===0){c=l<0?-Math.pow(-l,1/3):Math.pow(l,1/3),s[0]=-v+2*c,s[4]=s[2]=-(c+v);return}u=-u,f=u*u*u,f=Math.acos(l/Math.sqrt(f)),c=2*Math.sqrt(u),s[0]=-v+c*Math.cos(f/3),s[2]=-v+c*Math.cos((f+2*Math.PI)/3),s[4]=-v+c*Math.cos((f+4*Math.PI)/3)},yh=function(e,r,a,n,s,i,o,u){var l=1*a*a-4*a*s+2*a*o+4*s*s-4*s*o+o*o+n*n-4*n*i+2*n*u+4*i*i-4*i*u+u*u,f=1*9*a*s-3*a*a-3*a*o-6*s*s+3*s*o+9*n*i-3*n*n-3*n*u-6*i*i+3*i*u,h=1*3*a*a-6*a*s+a*o-a*e+2*s*s+2*s*e-o*e+3*n*n-6*n*i+n*u-n*r+2*i*i+2*i*r-u*r,d=1*a*s-a*a+a*e-s*e+n*i-n*n+n*r-i*r,v=[];ph(l,f,h,d,v);for(var c=1e-7,p=[],g=0;g<6;g+=2)Math.abs(v[g+1])=0&&v[g]<=1&&p.push(v[g]);p.push(1),p.push(0);for(var y=-1,b,m,T,C=0;C=0?Tl?(e-s)*(e-s)+(r-i)*(r-i):f-d},gt=function(e,r,a){for(var n,s,i,o,u,l=0,f=0;f=e&&e>=i||n<=e&&e<=i)u=(e-n)/(i-n)*(o-s)+s,u>r&&l++;else continue;return l%2!==0},Yt=function(e,r,a,n,s,i,o,u,l){var f=new Array(a.length),h;u[0]!=null?(h=Math.atan(u[1]/u[0]),u[0]<0?h=h+Math.PI/2:h=-h-Math.PI/2):h=u;for(var d=Math.cos(-h),v=Math.sin(-h),c=0;c0){var g=on(f,-l);p=sn(g)}else p=f;return gt(e,r,p)},bh=function(e,r,a,n,s,i,o,u){for(var l=new Array(a.length*2),f=0;f=0&&g<=1&&b.push(g),y>=0&&y<=1&&b.push(y),b.length===0)return[];var m=b[0]*u[0]+e,T=b[0]*u[1]+r;if(b.length>1){if(b[0]==b[1])return[m,T];var C=b[1]*u[0]+e,S=b[1]*u[1]+r;return[m,T,C,S]}else return[m,T]},Fn=function(e,r,a){return r<=e&&e<=a||a<=e&&e<=r?e:e<=r&&r<=a||a<=r&&r<=e?r:a},Qt=function(e,r,a,n,s,i,o,u,l){var f=e-s,h=a-e,d=o-s,v=r-i,c=n-r,p=u-i,g=d*v-p*f,y=h*v-c*f,b=p*h-d*c;if(b!==0){var m=g/b,T=y/b,C=.001,S=0-C,E=1+C;return S<=m&&m<=E&&S<=T&&T<=E?[e+m*h,r+m*c]:l?[e+m*h,r+m*c]:[]}else return g===0||y===0?Fn(e,a,o)===o?[o,u]:Fn(e,a,s)===s?[s,i]:Fn(s,o,a)===a?[a,n]:[]:[]},ya=function(e,r,a,n,s,i,o,u){var l=[],f,h=new Array(a.length),d=!0;i==null&&(d=!1);var v;if(d){for(var c=0;c0){var p=on(h,-u);v=sn(p)}else v=h}else v=a;for(var g,y,b,m,T=0;T2){for(var c=[f[0],f[1]],p=Math.pow(c[0]-e,2)+Math.pow(c[1]-r,2),g=1;gf&&(f=T)},get:function(m){return l[m]}},d=0;d0?R=M.edgesTo(O)[0]:R=O.edgesTo(M)[0];var k=n(R);O=O.id(),x[O]>x[A]+k&&(x[O]=x[A]+k,w.nodes.indexOf(O)<0?w.push(O):w.updateItem(O),E[O]=0,S[O]=[]),x[O]==x[A]+k&&(E[O]=E[O]+E[A],S[O].push(A))}else for(var P=0;P0;){for(var z=C.pop(),_=0;_0&&o.push(a[u]);o.length!==0&&s.push(n.collection(o))}return s},Ph=function(e,r){for(var a=0;a5&&arguments[5]!==void 0?arguments[5]:Gh,o=n,u,l,f=0;f=2?ta(e,r,a,0,is,zh):ta(e,r,a,0,ns)},squaredEuclidean:function(e,r,a){return ta(e,r,a,0,is)},manhattan:function(e,r,a){return ta(e,r,a,0,ns)},max:function(e,r,a){return ta(e,r,a,-1/0,Vh)}};Vr["squared-euclidean"]=Vr.squaredEuclidean;Vr.squaredeuclidean=Vr.squaredEuclidean;function bn(t,e,r,a,n,s){var i;return ze(t)?i=t:i=Vr[t]||Vr.euclidean,e===0&&ze(t)?i(n,s):i(e,r,a,n,s)}var Uh=rt({k:2,m:2,sensitivityThreshold:1e-4,distance:"euclidean",maxIterations:10,attributes:[],testMode:!1,testCentroids:null}),Ci=function(e){return Uh(e)},un=function(e,r,a,n,s){var i=s!=="kMedoids",o=i?function(h){return a[h]}:function(h){return n[h](a)},u=function(d){return n[d](r)},l=a,f=r;return bn(e,n.length,o,u,l,f)},Gn=function(e,r,a){for(var n=a.length,s=new Array(n),i=new Array(n),o=new Array(r),u=null,l=0;la)return!1}return!0},Yh=function(e,r,a){for(var n=0;no&&(o=r[l][f],u=f);s[u].push(e[l])}for(var h=0;h=s.threshold||s.mode==="dendrogram"&&e.length===1)return!1;var c=r[i],p=r[n[i]],g;s.mode==="dendrogram"?g={left:c,right:p,key:c.key}:g={value:c.value.concat(p.value),key:c.key},e[c.index]=g,e.splice(p.index,1),r[c.key]=g;for(var y=0;ya[p.key][b.key]&&(u=a[p.key][b.key])):s.linkage==="max"?(u=a[c.key][b.key],a[c.key][b.key]0&&n.push(s);return n},hs=function(e,r,a){for(var n=[],s=0;so&&(i=l,o=r[s*e+l])}i>0&&n.push(i)}for(var f=0;fl&&(u=f,l=h)}a[s]=i[u]}return n=hs(e,r,a),n},vs=function(e){for(var r=this.cy(),a=this.nodes(),n=nv(e),s={},i=0;i=L?(A=L,L=O,I=M):O>A&&(A=O);for(var R=0;R0?1:0;E[w%n.minIterations*o+z]=_,F+=_}if(F>0&&(w>=n.minIterations-1||w==n.maxIterations-1)){for(var Z=0,Y=0;Y1||S>1)&&(o=!0),h[m]=[],b.outgoers().forEach(function(x){x.isEdge()&&h[m].push(x.id())})}else d[m]=[void 0,b.target().id()]}):i.forEach(function(b){var m=b.id();if(b.isNode()){var T=b.degree(!0);T%2&&(u?l?o=!0:l=m:u=m),h[m]=[],b.connectedEdges().forEach(function(C){return h[m].push(C.id())})}else d[m]=[b.source().id(),b.target().id()]});var v={found:!1,trail:void 0};if(o)return v;if(l&&u)if(s){if(f&&l!=f)return v;f=l}else{if(f&&l!=f&&u!=f)return v;f||(f=l)}else f||(f=i[0].id());var c=function(m){for(var T=m,C=[m],S,E,x;h[T].length;)S=h[T].shift(),E=d[S][0],x=d[S][1],T!=x?(h[x]=h[x].filter(function(w){return w!=S}),T=x):!s&&T!=E&&(h[E]=h[E].filter(function(w){return w!=S}),T=E),C.unshift(S),C.unshift(T);return C},p=[],g=[];for(g=c(f);g.length!=1;)h[g[0]].length==0?(p.unshift(i.getElementById(g.shift())),p.unshift(i.getElementById(g.shift()))):g=c(g.shift()).concat(g);p.unshift(i.getElementById(g.shift()));for(var y in h)if(h[y].length)return v;return v.found=!0,v.trail=this.spawn(p,!0),v}},Fa=function(){var e=this,r={},a=0,n=0,s=[],i=[],o={},u=function(d,v){for(var c=i.length-1,p=[],g=e.spawn();i[c].x!=d||i[c].y!=v;)p.push(i.pop().edge),c--;p.push(i.pop().edge),p.forEach(function(y){var b=y.connectedNodes().intersection(e);g.merge(y),b.forEach(function(m){var T=m.id(),C=m.connectedEdges().intersection(e);g.merge(m),r[T].cutVertex?g.merge(C.filter(function(S){return S.isLoop()})):g.merge(C)})}),s.push(g)},l=function h(d,v,c){d===c&&(n+=1),r[v]={id:a,low:a++,cutVertex:!1};var p=e.getElementById(v).connectedEdges().intersection(e);if(p.size()===0)s.push(e.spawn(e.getElementById(v)));else{var g,y,b,m;p.forEach(function(T){g=T.source().id(),y=T.target().id(),b=g===v?y:g,b!==c&&(m=T.id(),o[m]||(o[m]=!0,i.push({x:v,y:b,edge:T})),b in r?r[v].low=Math.min(r[v].low,r[b].id):(h(d,b,v),r[v].low=Math.min(r[v].low,r[b].low),r[v].id<=r[b].low&&(r[v].cutVertex=!0,u(v,b))))})}};e.forEach(function(h){if(h.isNode()){var d=h.id();d in r||(n=0,l(d,d),r[d].cutVertex=n>1)}});var f=Object.keys(r).filter(function(h){return r[h].cutVertex}).map(function(h){return e.getElementById(h)});return{cut:e.spawn(f),components:s}},vv={hopcroftTarjanBiconnected:Fa,htbc:Fa,htb:Fa,hopcroftTarjanBiconnectedComponents:Fa},Ga=function(){var e=this,r={},a=0,n=[],s=[],i=e.spawn(e),o=function u(l){s.push(l),r[l]={index:a,low:a++,explored:!1};var f=e.getElementById(l).connectedEdges().intersection(e);if(f.forEach(function(p){var g=p.target().id();g!==l&&(g in r||u(g),r[g].explored||(r[l].low=Math.min(r[l].low,r[g].low)))}),r[l].index===r[l].low){for(var h=e.spawn();;){var d=s.pop();if(h.merge(e.getElementById(d)),r[d].low=r[l].index,r[d].explored=!0,d===l)break}var v=h.edgesWith(h),c=h.merge(v);n.push(c),i=i.difference(c)}};return e.forEach(function(u){if(u.isNode()){var l=u.id();l in r||o(l)}}),{cut:i,components:n}},cv={tarjanStronglyConnected:Ga,tsc:Ga,tscc:Ga,tarjanStronglyConnectedComponents:Ga},Fo={};[ga,_f,Yf,Xf,Wf,Zf,jf,Ch,Pr,Br,Qn,Fh,Zh,rv,lv,hv,vv,cv].forEach(function(t){Ee(Fo,t)});/*!
                                       Embeddable Minimum Strictly-Compliant Promises/A+ 1.1.1 Thenable
                                      diff --git a/assets/mkcp.html-C_htobT5.js b/assets/mkcp.html-B5Aq1d1a.js
                                      similarity index 99%
                                      rename from assets/mkcp.html-C_htobT5.js
                                      rename to assets/mkcp.html-B5Aq1d1a.js
                                      index 017a0c893b..9df0c7104e 100644
                                      --- a/assets/mkcp.html-C_htobT5.js
                                      +++ b/assets/mkcp.html-B5Aq1d1a.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as c,r as s,o as i,c as d,a,b as e,d as n,e as t}from"./app-DBM4OJyw.js";const r={},l=t(`

                                      mKCP

                                      mKCP 使用 UDP 来模拟 TCP 连接。

                                      mKCP 牺牲带宽来降低延迟。传输同样的内容,mKCP 一般比 TCP 消耗更多的流量。

                                      提示

                                      请确定主机上的防火墙配置正确

                                      KcpObject

                                      KcpObject 对应传输配置的 kcpSettings 项。

                                      {
                                      +import{_ as c,r as s,o as i,c as d,a,b as e,d as n,e as t}from"./app-D7uBbsY3.js";const r={},l=t(`

                                      mKCP

                                      mKCP 使用 UDP 来模拟 TCP 连接。

                                      mKCP 牺牲带宽来降低延迟。传输同样的内容,mKCP 一般比 TCP 消耗更多的流量。

                                      提示

                                      请确定主机上的防火墙配置正确

                                      KcpObject

                                      KcpObject 对应传输配置的 kcpSettings 项。

                                      {
                                         "mtu": 1350,
                                         "tti": 20,
                                         "uplinkCapacity": 5,
                                      diff --git a/assets/mkcp.html-BmeTqtsZ.js b/assets/mkcp.html-BXKgWezP.js
                                      similarity index 98%
                                      rename from assets/mkcp.html-BmeTqtsZ.js
                                      rename to assets/mkcp.html-BXKgWezP.js
                                      index 614bd49f8c..5d76332404 100644
                                      --- a/assets/mkcp.html-BmeTqtsZ.js
                                      +++ b/assets/mkcp.html-BXKgWezP.js
                                      @@ -1 +1 @@
                                      -import{_ as i,r as n,o as r,c as s,a as e,b as t,d as a,e as h}from"./app-DBM4OJyw.js";const o={},p=t("h1",{id:"mkcp-协议",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#mkcp-协议"},[t("span",null,"mKCP 协议")])],-1),c={href:"https://github.com/skywind3000/kcp",target:"_blank",rel:"noopener noreferrer"},b=h('

                                      版本

                                      mKCP 没有版本号,不保证版本之间兼容性。

                                      依赖

                                      底层协议

                                      mKCP 是一个基于 UDP 的协议,所有通讯使用 UDP 传输。

                                      函数

                                      ',6),_={href:"https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function",target:"_blank",rel:"noopener noreferrer"},m=t("ul",null,[t("li",null,"输入参数为任意长度的字符串;"),t("li",null,"输入出一个 32 位无符号整数;")],-1),u=h('

                                      通讯过程

                                      1. mKCP 将数据流拆成若干个数据包进行发送。一个数据流有一个唯一标识,用以区分不同的数据流。数据流中的每一个数据包都携带了同样的标识。
                                      2. mKCP 没有握手过程,当收到一个数据包时,根据其携带的数据流的标识来判断是否为新的通话,或是正在进行中的通话。
                                      3. 每一个数据包中包含若干个片段(Segment),片段分为三类:数据(Data)、确认(ACK)、心跳(Ping)。每个片段需要单独处理。

                                      数据格式

                                      数据包

                                      4 字节2 字节L 字节
                                      认证信息 A数据长度 L片段部分

                                      其中:

                                      • 认证信息 A = fnv(片段部分),big endian;
                                      • 片段部分可能包含多个片段;

                                      数据片段

                                      2 字节1 字节1 字节4 字节4 字节4 字节2 字节Len 字节
                                      标识 Conv指令 Cmd选项 Opt时间戳 Ts序列号 Sn未确认序列号 Una长度 Len数据

                                      其中:

                                      • 标识 Conv: mKCP 数据流的标识
                                      • 指令 Cmd: 常量 0x01
                                      • 选项 Opt: 可选的值有:
                                        • 0x00: 空选项
                                        • 0x01: 对方已发出所有数据
                                      • 时间戳 Ts: 当前片段从远端发送出来时的时间,big endian
                                      • 序列号 Sn: 该数据片段时数据流中的位置,起始片段的序列号为 0,之后每个新片段按顺序加 1
                                      • 未确认序列号 Una: 远端主机正在发送的,且尚未收到确认的最小的 Sn

                                      确认片段

                                      2 字节1 字节1 字节4 字节4 字节4 字节2 字节Len * 4 字节
                                      标识 Conv指令 Cmd选项 Opt窗口 Wnd下一接收序列号 Sn时间戳 Ts长度 Len已收到的序列号

                                      其中:

                                      • 标识 Conv: mKCP 数据流的标识
                                      • 指令 Cmd: 常量 0x00
                                      • 选项 Opt: 同上
                                      • 窗口 Wnd: 远端主机可以接收的最大序列号
                                      • 下一接收序列号 Sn: 远端主机未收到的数据片段中的最小序列号
                                      • 时间戳 Ts: 远端主机最新收到的数据片段的时间戳,可用于计算延迟
                                      • 已收到的序列号: 每个 4 字节,表示此序列号的数据已经确认收到

                                      注释:

                                      • 远程主机期待收到序列号 [Sn, Wnd) 范围内的数据

                                      心跳片段

                                      2 字节1 字节1 字节4 字节4 字节4 字节
                                      标识 Conv指令 Cmd选项 Opt未确认序列号 Una下一接收序列号 Sn延迟 Rto

                                      其中:

                                      • 标识 Conv: mKCP 数据流的标识
                                      • 指令 Cmd: 可选的值有
                                        • 0x02: 远端主机强行终止会话
                                        • 0x03: 正常心跳
                                      • 选项 Opt: 同上
                                      • 未确认序列号 Una: 同数据片段的 Una
                                      • 下一接收序列号 Sn: 同确认片段的 Sn
                                      • 延迟 Rto: 远端主机自己计算出的延迟
                                      ',21);function f(C,x){const d=n("I18nTip"),l=n("ExternalLinkIcon");return r(),s("div",null,[e(d),p,t("p",null,[a("mKCP 是流式传输协议,由 "),t("a",c,[a("KCP 协议"),e(l)]),a(" 修改而来,可以按顺序传输任意的数据流。")]),b,t("ul",null,[t("li",null,[a("fnv: "),t("a",_,[a("FNV-1a"),e(l)]),a(" 哈希函数 "),m])]),u])}const P=i(o,[["render",f],["__file","mkcp.html.vue"]]);export{P as default}; +import{_ as i,r as n,o as r,c as s,a as e,b as t,d as a,e as h}from"./app-D7uBbsY3.js";const o={},p=t("h1",{id:"mkcp-协议",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#mkcp-协议"},[t("span",null,"mKCP 协议")])],-1),c={href:"https://github.com/skywind3000/kcp",target:"_blank",rel:"noopener noreferrer"},b=h('

                                      版本

                                      mKCP 没有版本号,不保证版本之间兼容性。

                                      依赖

                                      底层协议

                                      mKCP 是一个基于 UDP 的协议,所有通讯使用 UDP 传输。

                                      函数

                                      ',6),_={href:"https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function",target:"_blank",rel:"noopener noreferrer"},m=t("ul",null,[t("li",null,"输入参数为任意长度的字符串;"),t("li",null,"输入出一个 32 位无符号整数;")],-1),u=h('

                                      通讯过程

                                      1. mKCP 将数据流拆成若干个数据包进行发送。一个数据流有一个唯一标识,用以区分不同的数据流。数据流中的每一个数据包都携带了同样的标识。
                                      2. mKCP 没有握手过程,当收到一个数据包时,根据其携带的数据流的标识来判断是否为新的通话,或是正在进行中的通话。
                                      3. 每一个数据包中包含若干个片段(Segment),片段分为三类:数据(Data)、确认(ACK)、心跳(Ping)。每个片段需要单独处理。

                                      数据格式

                                      数据包

                                      4 字节2 字节L 字节
                                      认证信息 A数据长度 L片段部分

                                      其中:

                                      • 认证信息 A = fnv(片段部分),big endian;
                                      • 片段部分可能包含多个片段;

                                      数据片段

                                      2 字节1 字节1 字节4 字节4 字节4 字节2 字节Len 字节
                                      标识 Conv指令 Cmd选项 Opt时间戳 Ts序列号 Sn未确认序列号 Una长度 Len数据

                                      其中:

                                      • 标识 Conv: mKCP 数据流的标识
                                      • 指令 Cmd: 常量 0x01
                                      • 选项 Opt: 可选的值有:
                                        • 0x00: 空选项
                                        • 0x01: 对方已发出所有数据
                                      • 时间戳 Ts: 当前片段从远端发送出来时的时间,big endian
                                      • 序列号 Sn: 该数据片段时数据流中的位置,起始片段的序列号为 0,之后每个新片段按顺序加 1
                                      • 未确认序列号 Una: 远端主机正在发送的,且尚未收到确认的最小的 Sn

                                      确认片段

                                      2 字节1 字节1 字节4 字节4 字节4 字节2 字节Len * 4 字节
                                      标识 Conv指令 Cmd选项 Opt窗口 Wnd下一接收序列号 Sn时间戳 Ts长度 Len已收到的序列号

                                      其中:

                                      • 标识 Conv: mKCP 数据流的标识
                                      • 指令 Cmd: 常量 0x00
                                      • 选项 Opt: 同上
                                      • 窗口 Wnd: 远端主机可以接收的最大序列号
                                      • 下一接收序列号 Sn: 远端主机未收到的数据片段中的最小序列号
                                      • 时间戳 Ts: 远端主机最新收到的数据片段的时间戳,可用于计算延迟
                                      • 已收到的序列号: 每个 4 字节,表示此序列号的数据已经确认收到

                                      注释:

                                      • 远程主机期待收到序列号 [Sn, Wnd) 范围内的数据

                                      心跳片段

                                      2 字节1 字节1 字节4 字节4 字节4 字节
                                      标识 Conv指令 Cmd选项 Opt未确认序列号 Una下一接收序列号 Sn延迟 Rto

                                      其中:

                                      • 标识 Conv: mKCP 数据流的标识
                                      • 指令 Cmd: 可选的值有
                                        • 0x02: 远端主机强行终止会话
                                        • 0x03: 正常心跳
                                      • 选项 Opt: 同上
                                      • 未确认序列号 Una: 同数据片段的 Una
                                      • 下一接收序列号 Sn: 同确认片段的 Sn
                                      • 延迟 Rto: 远端主机自己计算出的延迟
                                      ',21);function f(C,x){const d=n("I18nTip"),l=n("ExternalLinkIcon");return r(),s("div",null,[e(d),p,t("p",null,[a("mKCP 是流式传输协议,由 "),t("a",c,[a("KCP 协议"),e(l)]),a(" 修改而来,可以按顺序传输任意的数据流。")]),b,t("ul",null,[t("li",null,[a("fnv: "),t("a",_,[a("FNV-1a"),e(l)]),a(" 哈希函数 "),m])]),u])}const P=i(o,[["render",f],["__file","mkcp.html.vue"]]);export{P as default}; diff --git a/assets/mkcp.html-CL2dbaXb.js b/assets/mkcp.html-C779sbex.js similarity index 99% rename from assets/mkcp.html-CL2dbaXb.js rename to assets/mkcp.html-C779sbex.js index 53fe181a04..80d7bc1f4e 100644 --- a/assets/mkcp.html-CL2dbaXb.js +++ b/assets/mkcp.html-C779sbex.js @@ -1,4 +1,4 @@ -import{_ as r,r as o,o as p,c as d,a as n,b as t,d as e,w as l,e as s}from"./app-DBM4OJyw.js";const u={},h=s('

                                      mKCP

                                      mKCP uses UDP to emulate TCP connections.

                                      mKCP sacrifices bandwidth to reduce latency. To transmit the same content, mKCP generally consumes more data than TCP.

                                      Tip

                                      Make sure the firewall on the host is configured correctly.

                                      KcpObject

                                      ',5),m=t("code",null,"KcpObject",-1),b=t("code",null,"kcpSettings",-1),f=s(`
                                      {
                                      +import{_ as r,r as o,o as p,c as d,a as n,b as t,d as e,w as l,e as s}from"./app-D7uBbsY3.js";const u={},h=s('

                                      mKCP

                                      mKCP uses UDP to emulate TCP connections.

                                      mKCP sacrifices bandwidth to reduce latency. To transmit the same content, mKCP generally consumes more data than TCP.

                                      Tip

                                      Make sure the firewall on the host is configured correctly.

                                      KcpObject

                                      ',5),m=t("code",null,"KcpObject",-1),b=t("code",null,"kcpSettings",-1),f=s(`
                                      {
                                         "mtu": 1350,
                                         "tti": 20,
                                         "uplinkCapacity": 5,
                                      diff --git a/assets/mkcp.html-OQhbYtWS.js b/assets/mkcp.html-DkNOr0bl.js
                                      similarity index 99%
                                      rename from assets/mkcp.html-OQhbYtWS.js
                                      rename to assets/mkcp.html-DkNOr0bl.js
                                      index 48fcb438c6..39ee5ac476 100644
                                      --- a/assets/mkcp.html-OQhbYtWS.js
                                      +++ b/assets/mkcp.html-DkNOr0bl.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as c,r as s,o as i,c as r,a,b as e,d as n,e as p}from"./app-DBM4OJyw.js";const d={},l=p(`

                                      mKCP

                                      mKCP использует UDP для имитации TCP-соединения.

                                      mKCP жертвует пропускной способностью ради уменьшения задержки. При передаче одного и того же контента mKCP, как правило, потребляет больше трафика, чем TCP.

                                      Подсказка

                                      Убедитесь, что на хосте правильно настроена конфигурация брандмауэра.

                                      KcpObject

                                      KcpObject соответствует параметрам передачи kcpSettings.

                                      {
                                      +import{_ as c,r as s,o as i,c as r,a,b as e,d as n,e as p}from"./app-D7uBbsY3.js";const d={},l=p(`

                                      mKCP

                                      mKCP использует UDP для имитации TCP-соединения.

                                      mKCP жертвует пропускной способностью ради уменьшения задержки. При передаче одного и того же контента mKCP, как правило, потребляет больше трафика, чем TCP.

                                      Подсказка

                                      Убедитесь, что на хосте правильно настроена конфигурация брандмауэра.

                                      KcpObject

                                      KcpObject соответствует параметрам передачи kcpSettings.

                                      {
                                         "mtu": 1350,
                                         "tti": 20,
                                         "uplinkCapacity": 5,
                                      diff --git a/assets/mkcp.html-ZQWAw5BE.js b/assets/mkcp.html-JU6IuAPN.js
                                      similarity index 98%
                                      rename from assets/mkcp.html-ZQWAw5BE.js
                                      rename to assets/mkcp.html-JU6IuAPN.js
                                      index 97cdb0627a..0ba4eaa154 100644
                                      --- a/assets/mkcp.html-ZQWAw5BE.js
                                      +++ b/assets/mkcp.html-JU6IuAPN.js
                                      @@ -1 +1 @@
                                      -import{_ as d,r as i,o as h,c as r,a,b as e,d as t,e as s}from"./app-DBM4OJyw.js";const l={},c=e("h1",{id:"mkcp-protocol",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#mkcp-protocol"},[e("span",null,"mKCP Protocol")])],-1),m={href:"https://github.com/skywind3000/kcp",target:"_blank",rel:"noopener noreferrer"},p=s('

                                      Version

                                      mKCP has no version number and does not guarantee compatibility between versions.

                                      Dependencies

                                      Underlying Protocol

                                      mKCP is a protocol based on UDP, and all communication uses UDP transmission.

                                      Functions

                                      ',6),u={href:"https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function",target:"_blank",rel:"noopener noreferrer"},b=e("ul",null,[e("li",null,"Takes a string of arbitrary length as input parameter;"),e("li",null,"Outputs a 32-bit unsigned integer.")],-1),f=s('

                                      Communication Process

                                      1. mKCP splits data streams into several data packets for transmission. Each data stream has a unique identifier to distinguish it from other data streams. Each data packet in the data stream carries the same identifier.
                                      2. mKCP does not have a handshake process. When receiving a data packet, it determines whether it is a new call or an ongoing call based on the identifier of the data stream it carries.
                                      3. Each data packet contains several segments (Segment), which are divided into three types: data (Data), acknowledgment (ACK), and heartbeat (Ping). Each segment needs to be processed separately.

                                      Data Format

                                      Data Packet

                                      4 Bytes2 BytesL Bytes
                                      Auth AData Len LFragment

                                      as which:

                                      • Authentication information A = fnv(fragment), big endian;
                                      • The fragment may contain multiple sections.

                                      Data snippet

                                      2 bytes1 byte1 byte4 bytes4 bytes4 bytes2 bytesLen bytes
                                      Conv flagCmd flagOpt flagTimestampSequenceUnacknowledgedLen flagData

                                      as which:

                                      • Identifier Conv: Identifier for mKCP data stream
                                      • Command Cmd: Constant 0x01
                                      • Option Opt: Optional values include:
                                        • 0x00: Empty option
                                        • 0x01: Opposite party has sent all data
                                      • Timestamp Ts: Time when the current segment was sent from the remote end, big endian
                                      • Sequence Number Sn: The position of the data segment in the data stream, the sequence number of the starting segment is 0, and each new segment is sequentially added by 1
                                      • Unacknowledged Sequence Number Una: The minimum Sn that the remote host is sending and has not yet received confirmation.

                                      Confirmation snippet

                                      2 bytes1 byte1 byte4 bytes4 bytes4 bytes2 bytesLen * 4 bytes
                                      Conv IDCmdOptWndNext Seq NumberTimestampLengthReceived Seq Number

                                      as which:

                                      • Identifier Conv: Identifier of the mKCP data stream
                                      • Command Cmd: Constant 0x00
                                      • Option Opt: Same as above
                                      • Window Wnd: The maximum sequence number that the remote host can receive
                                      • Next receive sequence number Sn: The smallest sequence number of the data segment that the remote host has not received
                                      • Timestamp Ts: The timestamp of the latest received data segment by the remote host, which can be used to calculate the delay
                                      • Received sequence numbers: Each 4 bytes, indicating that the data of this sequence number has been confirmed received.

                                      as which:

                                      • The remote host expects to receive data within the serial number [Sn, Wnd) range.

                                      Heartbeat Fragments

                                      2 Bytes1 Byte1 Byte4 Bytes4 Bytes4 Bytes
                                      Conv IDCmdOptUnacknowledged Seq NoNext Receive Seq NoRto

                                      as which:

                                      • Identifier Conv: Identifier for the mKCP data stream
                                      • Command Cmd: Optional values include:
                                        • 0x02: Remote host forcibly terminates the session
                                        • 0x03: Normal heartbeat
                                      • Option Opt: Same as above
                                      • Unacknowledged sequence number Una: Same as the Una of the data fragment
                                      • Next receive sequence number Sn: Same as the Sn of the acknowledgement fragment
                                      • Delay Rto: Delay calculated by the remote host itself
                                      ',21);function y(g,v){const o=i("I18nTip"),n=i("ExternalLinkIcon");return h(),r("div",null,[a(o),c,e("p",null,[t("mKCP is a stream transfer protocol, modified from the "),e("a",m,[t("KCP protocol"),a(n)]),t(", which can transmit any data stream in order.")]),p,e("ul",null,[e("li",null,[t("fnv: "),e("a",u,[t("FNV-1a"),a(n)]),t(" hash function "),b])]),f])}const C=d(l,[["render",y],["__file","mkcp.html.vue"]]);export{C as default}; +import{_ as d,r as i,o as h,c as r,a,b as e,d as t,e as s}from"./app-D7uBbsY3.js";const l={},c=e("h1",{id:"mkcp-protocol",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#mkcp-protocol"},[e("span",null,"mKCP Protocol")])],-1),m={href:"https://github.com/skywind3000/kcp",target:"_blank",rel:"noopener noreferrer"},p=s('

                                      Version

                                      mKCP has no version number and does not guarantee compatibility between versions.

                                      Dependencies

                                      Underlying Protocol

                                      mKCP is a protocol based on UDP, and all communication uses UDP transmission.

                                      Functions

                                      ',6),u={href:"https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function",target:"_blank",rel:"noopener noreferrer"},b=e("ul",null,[e("li",null,"Takes a string of arbitrary length as input parameter;"),e("li",null,"Outputs a 32-bit unsigned integer.")],-1),f=s('

                                      Communication Process

                                      1. mKCP splits data streams into several data packets for transmission. Each data stream has a unique identifier to distinguish it from other data streams. Each data packet in the data stream carries the same identifier.
                                      2. mKCP does not have a handshake process. When receiving a data packet, it determines whether it is a new call or an ongoing call based on the identifier of the data stream it carries.
                                      3. Each data packet contains several segments (Segment), which are divided into three types: data (Data), acknowledgment (ACK), and heartbeat (Ping). Each segment needs to be processed separately.

                                      Data Format

                                      Data Packet

                                      4 Bytes2 BytesL Bytes
                                      Auth AData Len LFragment

                                      as which:

                                      • Authentication information A = fnv(fragment), big endian;
                                      • The fragment may contain multiple sections.

                                      Data snippet

                                      2 bytes1 byte1 byte4 bytes4 bytes4 bytes2 bytesLen bytes
                                      Conv flagCmd flagOpt flagTimestampSequenceUnacknowledgedLen flagData

                                      as which:

                                      • Identifier Conv: Identifier for mKCP data stream
                                      • Command Cmd: Constant 0x01
                                      • Option Opt: Optional values include:
                                        • 0x00: Empty option
                                        • 0x01: Opposite party has sent all data
                                      • Timestamp Ts: Time when the current segment was sent from the remote end, big endian
                                      • Sequence Number Sn: The position of the data segment in the data stream, the sequence number of the starting segment is 0, and each new segment is sequentially added by 1
                                      • Unacknowledged Sequence Number Una: The minimum Sn that the remote host is sending and has not yet received confirmation.

                                      Confirmation snippet

                                      2 bytes1 byte1 byte4 bytes4 bytes4 bytes2 bytesLen * 4 bytes
                                      Conv IDCmdOptWndNext Seq NumberTimestampLengthReceived Seq Number

                                      as which:

                                      • Identifier Conv: Identifier of the mKCP data stream
                                      • Command Cmd: Constant 0x00
                                      • Option Opt: Same as above
                                      • Window Wnd: The maximum sequence number that the remote host can receive
                                      • Next receive sequence number Sn: The smallest sequence number of the data segment that the remote host has not received
                                      • Timestamp Ts: The timestamp of the latest received data segment by the remote host, which can be used to calculate the delay
                                      • Received sequence numbers: Each 4 bytes, indicating that the data of this sequence number has been confirmed received.

                                      as which:

                                      • The remote host expects to receive data within the serial number [Sn, Wnd) range.

                                      Heartbeat Fragments

                                      2 Bytes1 Byte1 Byte4 Bytes4 Bytes4 Bytes
                                      Conv IDCmdOptUnacknowledged Seq NoNext Receive Seq NoRto

                                      as which:

                                      • Identifier Conv: Identifier for the mKCP data stream
                                      • Command Cmd: Optional values include:
                                        • 0x02: Remote host forcibly terminates the session
                                        • 0x03: Normal heartbeat
                                      • Option Opt: Same as above
                                      • Unacknowledged sequence number Una: Same as the Una of the data fragment
                                      • Next receive sequence number Sn: Same as the Sn of the acknowledgement fragment
                                      • Delay Rto: Delay calculated by the remote host itself
                                      ',21);function y(g,v){const o=i("I18nTip"),n=i("ExternalLinkIcon");return h(),r("div",null,[a(o),c,e("p",null,[t("mKCP is a stream transfer protocol, modified from the "),e("a",m,[t("KCP protocol"),a(n)]),t(", which can transmit any data stream in order.")]),p,e("ul",null,[e("li",null,[t("fnv: "),e("a",u,[t("FNV-1a"),a(n)]),t(" hash function "),b])]),f])}const C=d(l,[["render",y],["__file","mkcp.html.vue"]]);export{C as default}; diff --git a/assets/mkcp.html-zExRKUGX.js b/assets/mkcp.html-uDvBjn0p.js similarity index 98% rename from assets/mkcp.html-zExRKUGX.js rename to assets/mkcp.html-uDvBjn0p.js index 614bd49f8c..5d76332404 100644 --- a/assets/mkcp.html-zExRKUGX.js +++ b/assets/mkcp.html-uDvBjn0p.js @@ -1 +1 @@ -import{_ as i,r as n,o as r,c as s,a as e,b as t,d as a,e as h}from"./app-DBM4OJyw.js";const o={},p=t("h1",{id:"mkcp-协议",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#mkcp-协议"},[t("span",null,"mKCP 协议")])],-1),c={href:"https://github.com/skywind3000/kcp",target:"_blank",rel:"noopener noreferrer"},b=h('

                                      版本

                                      mKCP 没有版本号,不保证版本之间兼容性。

                                      依赖

                                      底层协议

                                      mKCP 是一个基于 UDP 的协议,所有通讯使用 UDP 传输。

                                      函数

                                      ',6),_={href:"https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function",target:"_blank",rel:"noopener noreferrer"},m=t("ul",null,[t("li",null,"输入参数为任意长度的字符串;"),t("li",null,"输入出一个 32 位无符号整数;")],-1),u=h('

                                      通讯过程

                                      1. mKCP 将数据流拆成若干个数据包进行发送。一个数据流有一个唯一标识,用以区分不同的数据流。数据流中的每一个数据包都携带了同样的标识。
                                      2. mKCP 没有握手过程,当收到一个数据包时,根据其携带的数据流的标识来判断是否为新的通话,或是正在进行中的通话。
                                      3. 每一个数据包中包含若干个片段(Segment),片段分为三类:数据(Data)、确认(ACK)、心跳(Ping)。每个片段需要单独处理。

                                      数据格式

                                      数据包

                                      4 字节2 字节L 字节
                                      认证信息 A数据长度 L片段部分

                                      其中:

                                      • 认证信息 A = fnv(片段部分),big endian;
                                      • 片段部分可能包含多个片段;

                                      数据片段

                                      2 字节1 字节1 字节4 字节4 字节4 字节2 字节Len 字节
                                      标识 Conv指令 Cmd选项 Opt时间戳 Ts序列号 Sn未确认序列号 Una长度 Len数据

                                      其中:

                                      • 标识 Conv: mKCP 数据流的标识
                                      • 指令 Cmd: 常量 0x01
                                      • 选项 Opt: 可选的值有:
                                        • 0x00: 空选项
                                        • 0x01: 对方已发出所有数据
                                      • 时间戳 Ts: 当前片段从远端发送出来时的时间,big endian
                                      • 序列号 Sn: 该数据片段时数据流中的位置,起始片段的序列号为 0,之后每个新片段按顺序加 1
                                      • 未确认序列号 Una: 远端主机正在发送的,且尚未收到确认的最小的 Sn

                                      确认片段

                                      2 字节1 字节1 字节4 字节4 字节4 字节2 字节Len * 4 字节
                                      标识 Conv指令 Cmd选项 Opt窗口 Wnd下一接收序列号 Sn时间戳 Ts长度 Len已收到的序列号

                                      其中:

                                      • 标识 Conv: mKCP 数据流的标识
                                      • 指令 Cmd: 常量 0x00
                                      • 选项 Opt: 同上
                                      • 窗口 Wnd: 远端主机可以接收的最大序列号
                                      • 下一接收序列号 Sn: 远端主机未收到的数据片段中的最小序列号
                                      • 时间戳 Ts: 远端主机最新收到的数据片段的时间戳,可用于计算延迟
                                      • 已收到的序列号: 每个 4 字节,表示此序列号的数据已经确认收到

                                      注释:

                                      • 远程主机期待收到序列号 [Sn, Wnd) 范围内的数据

                                      心跳片段

                                      2 字节1 字节1 字节4 字节4 字节4 字节
                                      标识 Conv指令 Cmd选项 Opt未确认序列号 Una下一接收序列号 Sn延迟 Rto

                                      其中:

                                      • 标识 Conv: mKCP 数据流的标识
                                      • 指令 Cmd: 可选的值有
                                        • 0x02: 远端主机强行终止会话
                                        • 0x03: 正常心跳
                                      • 选项 Opt: 同上
                                      • 未确认序列号 Una: 同数据片段的 Una
                                      • 下一接收序列号 Sn: 同确认片段的 Sn
                                      • 延迟 Rto: 远端主机自己计算出的延迟
                                      ',21);function f(C,x){const d=n("I18nTip"),l=n("ExternalLinkIcon");return r(),s("div",null,[e(d),p,t("p",null,[a("mKCP 是流式传输协议,由 "),t("a",c,[a("KCP 协议"),e(l)]),a(" 修改而来,可以按顺序传输任意的数据流。")]),b,t("ul",null,[t("li",null,[a("fnv: "),t("a",_,[a("FNV-1a"),e(l)]),a(" 哈希函数 "),m])]),u])}const P=i(o,[["render",f],["__file","mkcp.html.vue"]]);export{P as default}; +import{_ as i,r as n,o as r,c as s,a as e,b as t,d as a,e as h}from"./app-D7uBbsY3.js";const o={},p=t("h1",{id:"mkcp-协议",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#mkcp-协议"},[t("span",null,"mKCP 协议")])],-1),c={href:"https://github.com/skywind3000/kcp",target:"_blank",rel:"noopener noreferrer"},b=h('

                                      版本

                                      mKCP 没有版本号,不保证版本之间兼容性。

                                      依赖

                                      底层协议

                                      mKCP 是一个基于 UDP 的协议,所有通讯使用 UDP 传输。

                                      函数

                                      ',6),_={href:"https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function",target:"_blank",rel:"noopener noreferrer"},m=t("ul",null,[t("li",null,"输入参数为任意长度的字符串;"),t("li",null,"输入出一个 32 位无符号整数;")],-1),u=h('

                                      通讯过程

                                      1. mKCP 将数据流拆成若干个数据包进行发送。一个数据流有一个唯一标识,用以区分不同的数据流。数据流中的每一个数据包都携带了同样的标识。
                                      2. mKCP 没有握手过程,当收到一个数据包时,根据其携带的数据流的标识来判断是否为新的通话,或是正在进行中的通话。
                                      3. 每一个数据包中包含若干个片段(Segment),片段分为三类:数据(Data)、确认(ACK)、心跳(Ping)。每个片段需要单独处理。

                                      数据格式

                                      数据包

                                      4 字节2 字节L 字节
                                      认证信息 A数据长度 L片段部分

                                      其中:

                                      • 认证信息 A = fnv(片段部分),big endian;
                                      • 片段部分可能包含多个片段;

                                      数据片段

                                      2 字节1 字节1 字节4 字节4 字节4 字节2 字节Len 字节
                                      标识 Conv指令 Cmd选项 Opt时间戳 Ts序列号 Sn未确认序列号 Una长度 Len数据

                                      其中:

                                      • 标识 Conv: mKCP 数据流的标识
                                      • 指令 Cmd: 常量 0x01
                                      • 选项 Opt: 可选的值有:
                                        • 0x00: 空选项
                                        • 0x01: 对方已发出所有数据
                                      • 时间戳 Ts: 当前片段从远端发送出来时的时间,big endian
                                      • 序列号 Sn: 该数据片段时数据流中的位置,起始片段的序列号为 0,之后每个新片段按顺序加 1
                                      • 未确认序列号 Una: 远端主机正在发送的,且尚未收到确认的最小的 Sn

                                      确认片段

                                      2 字节1 字节1 字节4 字节4 字节4 字节2 字节Len * 4 字节
                                      标识 Conv指令 Cmd选项 Opt窗口 Wnd下一接收序列号 Sn时间戳 Ts长度 Len已收到的序列号

                                      其中:

                                      • 标识 Conv: mKCP 数据流的标识
                                      • 指令 Cmd: 常量 0x00
                                      • 选项 Opt: 同上
                                      • 窗口 Wnd: 远端主机可以接收的最大序列号
                                      • 下一接收序列号 Sn: 远端主机未收到的数据片段中的最小序列号
                                      • 时间戳 Ts: 远端主机最新收到的数据片段的时间戳,可用于计算延迟
                                      • 已收到的序列号: 每个 4 字节,表示此序列号的数据已经确认收到

                                      注释:

                                      • 远程主机期待收到序列号 [Sn, Wnd) 范围内的数据

                                      心跳片段

                                      2 字节1 字节1 字节4 字节4 字节4 字节
                                      标识 Conv指令 Cmd选项 Opt未确认序列号 Una下一接收序列号 Sn延迟 Rto

                                      其中:

                                      • 标识 Conv: mKCP 数据流的标识
                                      • 指令 Cmd: 可选的值有
                                        • 0x02: 远端主机强行终止会话
                                        • 0x03: 正常心跳
                                      • 选项 Opt: 同上
                                      • 未确认序列号 Una: 同数据片段的 Una
                                      • 下一接收序列号 Sn: 同确认片段的 Sn
                                      • 延迟 Rto: 远端主机自己计算出的延迟
                                      ',21);function f(C,x){const d=n("I18nTip"),l=n("ExternalLinkIcon");return r(),s("div",null,[e(d),p,t("p",null,[a("mKCP 是流式传输协议,由 "),t("a",c,[a("KCP 协议"),e(l)]),a(" 修改而来,可以按顺序传输任意的数据流。")]),b,t("ul",null,[t("li",null,[a("fnv: "),t("a",_,[a("FNV-1a"),e(l)]),a(" 哈希函数 "),m])]),u])}const P=i(o,[["render",f],["__file","mkcp.html.vue"]]);export{P as default}; diff --git a/assets/multiple.html-ByHUK-DJ.js b/assets/multiple.html-CyWT5XGQ.js similarity index 99% rename from assets/multiple.html-ByHUK-DJ.js rename to assets/multiple.html-CyWT5XGQ.js index 43a55ebf81..c3546da492 100644 --- a/assets/multiple.html-ByHUK-DJ.js +++ b/assets/multiple.html-CyWT5XGQ.js @@ -1,4 +1,4 @@ -import{_ as s,r as a,o,c as t,a as p,e}from"./app-DBM4OJyw.js";const c={},l=e(`

                                      多文件配置

                                      Xray 程序支持使用多个配置文件。

                                      多配置文件的主要作用在于分散不同作用模块配置,便于管理和维护。

                                      该功能主要考虑是为了丰富 Xray 的生态链,比如对于 GUI 的客户端,一般只实现节点选择等固定的功能,对于太复杂的配置难以图形化实现;只需留一个 confdir 的自定义配置目录供配置复杂的功能;对于服务器的部署脚本,只需往 confdir 添加文件即可实现配置多种协议。

                                      多文件启动

                                      提示

                                      启动信息中会提示依次读入的每个配置文件,留意启动信息是否符合你预设的顺序。可以在每个文件名前面增加前缀数字的方式控制顺序。如 01_文件名, 02_文件名,数字越大排序越靠后。

                                      $ xray run -confdir /etc/xray/confs
                                      +import{_ as s,r as a,o,c as t,a as p,e}from"./app-D7uBbsY3.js";const c={},l=e(`

                                      多文件配置

                                      Xray 程序支持使用多个配置文件。

                                      多配置文件的主要作用在于分散不同作用模块配置,便于管理和维护。

                                      该功能主要考虑是为了丰富 Xray 的生态链,比如对于 GUI 的客户端,一般只实现节点选择等固定的功能,对于太复杂的配置难以图形化实现;只需留一个 confdir 的自定义配置目录供配置复杂的功能;对于服务器的部署脚本,只需往 confdir 添加文件即可实现配置多种协议。

                                      多文件启动

                                      提示

                                      启动信息中会提示依次读入的每个配置文件,留意启动信息是否符合你预设的顺序。可以在每个文件名前面增加前缀数字的方式控制顺序。如 01_文件名, 02_文件名,数字越大排序越靠后。

                                      $ xray run -confdir /etc/xray/confs
                                       

                                      也可使用 Xray.location.confdirXray_LOCATION_CONFDIR 指定 confdir

                                      参数 -confdir 的作用优先于环境变量,如果参数指定了有效的目录则不再读取环境变量中的路径。

                                      规则说明

                                      普通对象({}

                                      顶级对象后者覆盖或补充前者

                                      数组([]

                                      在 json 配置中的 inboundsoutbounds 是数组结构,他们有特殊的规则:

                                      • 查找原有 tag 相同的元素进行覆盖;若无法找到:
                                        • 对于 inbounds,添加至最后(inbounds 内元素顺序无关)
                                        • 对于 outbounds,添加至最前(outbounds 默认首选出口);但如果文件名含有 tail(大小写均可),添加至最后。

                                      配置例子

                                      假设 confs 文件夹下有以下三个配置文件。

                                      • 01.json
                                      {
                                         "log": {
                                           "loglevel": "warning"
                                      diff --git a/assets/multiple.html-DUUJue4s.js b/assets/multiple.html-D008nLUw.js
                                      similarity index 99%
                                      rename from assets/multiple.html-DUUJue4s.js
                                      rename to assets/multiple.html-D008nLUw.js
                                      index 72351e696a..51605ff0a1 100644
                                      --- a/assets/multiple.html-DUUJue4s.js
                                      +++ b/assets/multiple.html-D008nLUw.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as s,r as a,o as e,c as o,a as t,e as i}from"./app-DBM4OJyw.js";const p={},l=i(`

                                      Multi-file configuration

                                      The Xray program supports the use of multiple configuration files.

                                      The main purpose of using multiple configuration files is to distribute different module configurations, making it easier to manage and maintain.

                                      This feature is mainly designed to enrich the Xray ecosystem. For example, for GUI-based clients, only fixed functions such as node selection are usually implemented, and complex configurations are difficult to implement graphically. By leaving a custom confdir configuration directory for complex functions, server deployment scripts can simply add files to confdir to implement multiple protocol configurations.

                                      Multi-file startup

                                      Tip

                                      The startup information will indicate each configuration file being read in sequence. Please pay attention to whether the startup information matches the order you have set.

                                      $ xray run -confdir /etc/xray/confs
                                      +import{_ as s,r as a,o as e,c as o,a as t,e as i}from"./app-D7uBbsY3.js";const p={},l=i(`

                                      Multi-file configuration

                                      The Xray program supports the use of multiple configuration files.

                                      The main purpose of using multiple configuration files is to distribute different module configurations, making it easier to manage and maintain.

                                      This feature is mainly designed to enrich the Xray ecosystem. For example, for GUI-based clients, only fixed functions such as node selection are usually implemented, and complex configurations are difficult to implement graphically. By leaving a custom confdir configuration directory for complex functions, server deployment scripts can simply add files to confdir to implement multiple protocol configurations.

                                      Multi-file startup

                                      Tip

                                      The startup information will indicate each configuration file being read in sequence. Please pay attention to whether the startup information matches the order you have set.

                                      $ xray run -confdir /etc/xray/confs
                                       

                                      You can also use Xray.location.confdir or Xray_LOCATION_CONFDIR to specify the confdir.

                                      The -confdir parameter takes precedence over the environment variable. If a valid directory is specified by the parameter, the path in the environment variable will not be read.

                                      Rule Explanation

                                      Normal Objects({}

                                      In the top-level object of JSON, the latter overrides or supplements the former.

                                      For example:

                                      • base.json
                                      {
                                         "log": {},
                                         "api": {},
                                      diff --git a/assets/multiple.html-Bjf8GHFS.js b/assets/multiple.html-D1DFWDpc.js
                                      similarity index 99%
                                      rename from assets/multiple.html-Bjf8GHFS.js
                                      rename to assets/multiple.html-D1DFWDpc.js
                                      index db24aca0af..5cfc6a9423 100644
                                      --- a/assets/multiple.html-Bjf8GHFS.js
                                      +++ b/assets/multiple.html-D1DFWDpc.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as s,r as a,o,c as t,a as e,e as p}from"./app-DBM4OJyw.js";const c={},l=p(`

                                      Настройка с помощью нескольких файлов

                                      Программа Xray поддерживает использование нескольких файлов конфигурации.

                                      Основная цель использования нескольких файлов конфигурации — разделение настроек модулей с разными функциями для удобства управления и обслуживания.

                                      Эта функция в основном предназначена для обогащения экосистемы Xray. Например, для клиентских GUI обычно реализуются только фиксированные функции, такие как выбор узла, и слишком сложные конфигурации трудно реализовать графически. Можно оставить только один пользовательский каталог конфигурации confdir для настройки сложных функций. Для сценариев развертывания сервера достаточно добавить файлы в confdir для настройки различных протоколов.

                                      Запуск с несколькими файлами

                                      Подсказка

                                      В информации о запуске будет указан каждый считываемый файл конфигурации. Убедитесь, что порядок считывания соответствует ожидаемому. Вы можете контролировать порядок, добавляя префиксы с номерами к именам файлов. Например, 01_имя_файла, 02_имя_файла, чем больше число, тем позже файл будет обработан.

                                      $ xray run -confdir /etc/xray/confs
                                      +import{_ as s,r as a,o,c as t,a as e,e as p}from"./app-D7uBbsY3.js";const c={},l=p(`

                                      Настройка с помощью нескольких файлов

                                      Программа Xray поддерживает использование нескольких файлов конфигурации.

                                      Основная цель использования нескольких файлов конфигурации — разделение настроек модулей с разными функциями для удобства управления и обслуживания.

                                      Эта функция в основном предназначена для обогащения экосистемы Xray. Например, для клиентских GUI обычно реализуются только фиксированные функции, такие как выбор узла, и слишком сложные конфигурации трудно реализовать графически. Можно оставить только один пользовательский каталог конфигурации confdir для настройки сложных функций. Для сценариев развертывания сервера достаточно добавить файлы в confdir для настройки различных протоколов.

                                      Запуск с несколькими файлами

                                      Подсказка

                                      В информации о запуске будет указан каждый считываемый файл конфигурации. Убедитесь, что порядок считывания соответствует ожидаемому. Вы можете контролировать порядок, добавляя префиксы с номерами к именам файлов. Например, 01_имя_файла, 02_имя_файла, чем больше число, тем позже файл будет обработан.

                                      $ xray run -confdir /etc/xray/confs
                                       

                                      Также можно использовать Xray.location.confdir или Xray_LOCATION_CONFDIR для указания confdir.

                                      Параметр -confdir имеет приоритет над переменной среды. Если параметр указывает на допустимый каталог, значение переменной среды игнорируется.

                                      Правила

                                      Обычные объекты ({})

                                      Последующие объекты верхнего уровня перезаписывают или дополняют предыдущие.

                                      Массивы ([])

                                      В конфигурации JSON inbounds и outbounds имеют структуру массива, для них действуют особые правила:

                                      • Поиск существующего элемента с тем же tag для перезаписи. Если элемент не найден:
                                        • Для inbounds: добавляется в конец (порядок элементов в inbounds не имеет значения).
                                        • Для outbounds: добавляется в начало (по умолчанию используется первый выход в outbounds); но если имя файла содержит tail (регистр не имеет значения), элемент добавляется в конец.

                                      Пример конфигурации

                                      Предположим, что в папке confs есть следующие три файла конфигурации:

                                      • 01.json
                                      {
                                         "log": {
                                           "loglevel": "warning"
                                      diff --git a/assets/muxcool.html-DuGDfdPl.js b/assets/muxcool.html-C8vY0L1H.js
                                      similarity index 99%
                                      rename from assets/muxcool.html-DuGDfdPl.js
                                      rename to assets/muxcool.html-C8vY0L1H.js
                                      index 5d945c42a6..3b83acb0ab 100644
                                      --- a/assets/muxcool.html-DuGDfdPl.js
                                      +++ b/assets/muxcool.html-C8vY0L1H.js
                                      @@ -1 +1 @@
                                      -import{_ as n,r as a,o as i,c as r,a as d,b as t,d as e,e as h}from"./app-DBM4OJyw.js";const p={},s=h('

                                      Mux.Cool 协议

                                      Mux.Cool 协议是一个多路复用传输协议,用于在一条已建立的数据流中传输多个各自独立的数据流。

                                      版本

                                      当前版本是 1 Beta。

                                      依赖

                                      底层协议

                                      Mux.Cool 必须运行在一个已建立的可靠数据流之上。

                                      通讯过程

                                      一个 Mux.Cool 连接中可传输若干个子连接,每个子连接有一个独立的 ID 和状态。传输过程由帧(Frame)组成,每一帧用于传输一个特定的子连接的数据。

                                      客户端行为

                                      当有连接需求时并且没有现有可用的连接时,客户端向服务器发起一个新连接,以下称为“主连接”。

                                      1. 一个主连接可用于发送若干个子连接。客户端可自主决定主连接可承载的子连接数量。
                                      2. 对于一个新的子连接,客户端必须发送状态New以通知服务器建立子连接,然后使用状态Keep来传送数据。
                                      3. 当子连接结束时,客户端发送End状态来通知服务器关闭子连接。
                                      4. 客户端可自行决定何时关闭主连接,但必须确定服务器也同时保持连接。
                                      5. 客户端可使用 KeepAlive 状态来避免服务器关闭主连接。

                                      服务器端行为

                                      当服务器端接收到新的子连接时,服务器应当按正常的连接来处理。

                                      1. 当收到状态End时,服务器端可以关闭对目标地址的上行连接。
                                      2. 在服务器的响应中,必须使用与请求相同的 ID 来传输子连接的数据。
                                      3. 服务器不能使用New状态。
                                      4. 服务器可使用 KeepAlive 状态来避免客户端关闭主连接。

                                      传输格式

                                      Mux.Cool 使用对称传输格式,即客户端和服务器发送和接收相同格式的数据。

                                      帧格式

                                      2 字节L 字节X 字节
                                      元数据长度 L元数据额外数据

                                      元数据

                                      元数据有若干种类型。所有类型的元数据都包含 ID 和 Opt 两项,其含义为:

                                      ',21),c=t("li",null,"对于一般 Mux 子连接,ID 由 1 开始累加",-1),x={href:"https://github.com/XTLS/Xray-core/blob/main/common/xudp/xudp.go",target:"_blank",rel:"noopener noreferrer"},b=t("li",null,[e("Opt: "),t("ul",null,[t("li",null,"D(0x01): 有额外数据")])],-1),u=h('

                                      当选项 Opt(D) 开启时,额外数据格式如下:

                                      2 字节X-2 字节
                                      长度 X-2数据

                                      新建子连接 (New)

                                      2 字节1 字节1 字节1 字节2 字节1 字节A 字节8 字节
                                      ID0x01选项 Opt网络类型 N端口地址类型 T地址 AGlobal ID (XUDP)

                                      其中:

                                      • 网络类型 N:
                                        • 0x01:TCP,表示当前子连接的流量应当以 TCP 的方式发送至目标。
                                        • 0x02:UDP,表示当前子连接的流量应当以 UDP 的方式发送至目标。
                                      • 地址类型 T:
                                        • 0x01:IPv4
                                        • 0x02:域名
                                        • 0x03:IPv6
                                      • 地址 A:
                                        • 当 T = 0x01 时,A 为 4 字节 IPv4 地址;
                                        • 当 T = 0x02 时,A 为 1 字节长度(L) + L 字节域名;
                                        • 当 T = 0x03 时,A 为 16 字节 IPv6 地址;
                                      • Global ID (XUDP):
                                        • 客户端计算出 UDP 来源二元组的全局独特 ID,服务端用以确保当 XUDP 断线重连时,仍使用同一个端口与目标通信。

                                      在新建子连接时,若 Opt(D) 开启,则这一帧所带的数据需要被发往目标主机。

                                      保持子连接 (Keep)

                                      TCP

                                      2 字节1 字节1 字节
                                      ID0x02选项 Opt

                                      UDP

                                      2 字节1 字节1 字节1 字节2 字节1 字节A 字节
                                      ID0x02选项 Opt网络类型 N端口地址类型 T地址 A

                                      在保持子连接时,若 Opt(D) 开启,则这一帧所带的数据需要被发往目标主机。 XUDP 在 Opt(D) 之后加 UDP 地址,格式同新建子连接,但没有 Global ID。

                                      关闭子连接 (End)

                                      2 字节1 字节1 字节
                                      ID0x03选项 Opt

                                      在保持子连接时,若 Opt(D) 开启,则这一帧所带的数据需要被发往目标主机。

                                      保持连接 (KeepAlive)

                                      2 字节1 字节1 字节
                                      ID0x04选项 Opt

                                      在保持连接时:

                                      • 若 Opt(D) 开启,则这一帧所带的数据必须被丢弃。
                                      • ID 可为随机值。

                                      应用

                                      Mux.Cool 协议与底层协议无关,理论上可以使用任何可靠的流式连接来传输 Mux.Cool 的协议数据。

                                      在目标导向的协议如 Shadowsocks 和 VMess 协议中,连接建立时必须包含一个指定的地址。 为了保持兼容性,Mux.Cool 协议指定地址为“v1.mux.cool”。即当主连接的目标地址与之匹配时,则进行 Mux.Cool 方式的转发,否则按传统方式进行转发。(注:这是一个程序内的标记,VMess 和 VLESS 并不会在数据包中发送“v1.mux.cool”地址)

                                      ',23);function D(_,f){const l=a("I18nTip"),o=a("ExternalLinkIcon");return i(),r("div",null,[d(l),s,t("ul",null,[t("li",null,[e("ID: 子连接的唯一标识 "),t("ul",null,[c,t("li",null,[e("对于 Xray 实现的 "),t("a",x,[e("Single XUDP"),d(o)]),e(",ID 始终为 0")])])]),b]),u])}const m=n(p,[["render",D],["__file","muxcool.html.vue"]]);export{m as default}; +import{_ as n,r as a,o as i,c as r,a as d,b as t,d as e,e as h}from"./app-D7uBbsY3.js";const p={},s=h('

                                      Mux.Cool 协议

                                      Mux.Cool 协议是一个多路复用传输协议,用于在一条已建立的数据流中传输多个各自独立的数据流。

                                      版本

                                      当前版本是 1 Beta。

                                      依赖

                                      底层协议

                                      Mux.Cool 必须运行在一个已建立的可靠数据流之上。

                                      通讯过程

                                      一个 Mux.Cool 连接中可传输若干个子连接,每个子连接有一个独立的 ID 和状态。传输过程由帧(Frame)组成,每一帧用于传输一个特定的子连接的数据。

                                      客户端行为

                                      当有连接需求时并且没有现有可用的连接时,客户端向服务器发起一个新连接,以下称为“主连接”。

                                      1. 一个主连接可用于发送若干个子连接。客户端可自主决定主连接可承载的子连接数量。
                                      2. 对于一个新的子连接,客户端必须发送状态New以通知服务器建立子连接,然后使用状态Keep来传送数据。
                                      3. 当子连接结束时,客户端发送End状态来通知服务器关闭子连接。
                                      4. 客户端可自行决定何时关闭主连接,但必须确定服务器也同时保持连接。
                                      5. 客户端可使用 KeepAlive 状态来避免服务器关闭主连接。

                                      服务器端行为

                                      当服务器端接收到新的子连接时,服务器应当按正常的连接来处理。

                                      1. 当收到状态End时,服务器端可以关闭对目标地址的上行连接。
                                      2. 在服务器的响应中,必须使用与请求相同的 ID 来传输子连接的数据。
                                      3. 服务器不能使用New状态。
                                      4. 服务器可使用 KeepAlive 状态来避免客户端关闭主连接。

                                      传输格式

                                      Mux.Cool 使用对称传输格式,即客户端和服务器发送和接收相同格式的数据。

                                      帧格式

                                      2 字节L 字节X 字节
                                      元数据长度 L元数据额外数据

                                      元数据

                                      元数据有若干种类型。所有类型的元数据都包含 ID 和 Opt 两项,其含义为:

                                      ',21),c=t("li",null,"对于一般 Mux 子连接,ID 由 1 开始累加",-1),x={href:"https://github.com/XTLS/Xray-core/blob/main/common/xudp/xudp.go",target:"_blank",rel:"noopener noreferrer"},b=t("li",null,[e("Opt: "),t("ul",null,[t("li",null,"D(0x01): 有额外数据")])],-1),u=h('

                                      当选项 Opt(D) 开启时,额外数据格式如下:

                                      2 字节X-2 字节
                                      长度 X-2数据

                                      新建子连接 (New)

                                      2 字节1 字节1 字节1 字节2 字节1 字节A 字节8 字节
                                      ID0x01选项 Opt网络类型 N端口地址类型 T地址 AGlobal ID (XUDP)

                                      其中:

                                      • 网络类型 N:
                                        • 0x01:TCP,表示当前子连接的流量应当以 TCP 的方式发送至目标。
                                        • 0x02:UDP,表示当前子连接的流量应当以 UDP 的方式发送至目标。
                                      • 地址类型 T:
                                        • 0x01:IPv4
                                        • 0x02:域名
                                        • 0x03:IPv6
                                      • 地址 A:
                                        • 当 T = 0x01 时,A 为 4 字节 IPv4 地址;
                                        • 当 T = 0x02 时,A 为 1 字节长度(L) + L 字节域名;
                                        • 当 T = 0x03 时,A 为 16 字节 IPv6 地址;
                                      • Global ID (XUDP):
                                        • 客户端计算出 UDP 来源二元组的全局独特 ID,服务端用以确保当 XUDP 断线重连时,仍使用同一个端口与目标通信。

                                      在新建子连接时,若 Opt(D) 开启,则这一帧所带的数据需要被发往目标主机。

                                      保持子连接 (Keep)

                                      TCP

                                      2 字节1 字节1 字节
                                      ID0x02选项 Opt

                                      UDP

                                      2 字节1 字节1 字节1 字节2 字节1 字节A 字节
                                      ID0x02选项 Opt网络类型 N端口地址类型 T地址 A

                                      在保持子连接时,若 Opt(D) 开启,则这一帧所带的数据需要被发往目标主机。 XUDP 在 Opt(D) 之后加 UDP 地址,格式同新建子连接,但没有 Global ID。

                                      关闭子连接 (End)

                                      2 字节1 字节1 字节
                                      ID0x03选项 Opt

                                      在保持子连接时,若 Opt(D) 开启,则这一帧所带的数据需要被发往目标主机。

                                      保持连接 (KeepAlive)

                                      2 字节1 字节1 字节
                                      ID0x04选项 Opt

                                      在保持连接时:

                                      • 若 Opt(D) 开启,则这一帧所带的数据必须被丢弃。
                                      • ID 可为随机值。

                                      应用

                                      Mux.Cool 协议与底层协议无关,理论上可以使用任何可靠的流式连接来传输 Mux.Cool 的协议数据。

                                      在目标导向的协议如 Shadowsocks 和 VMess 协议中,连接建立时必须包含一个指定的地址。 为了保持兼容性,Mux.Cool 协议指定地址为“v1.mux.cool”。即当主连接的目标地址与之匹配时,则进行 Mux.Cool 方式的转发,否则按传统方式进行转发。(注:这是一个程序内的标记,VMess 和 VLESS 并不会在数据包中发送“v1.mux.cool”地址)

                                      ',23);function D(_,f){const l=a("I18nTip"),o=a("ExternalLinkIcon");return i(),r("div",null,[d(l),s,t("ul",null,[t("li",null,[e("ID: 子连接的唯一标识 "),t("ul",null,[c,t("li",null,[e("对于 Xray 实现的 "),t("a",x,[e("Single XUDP"),d(o)]),e(",ID 始终为 0")])])]),b]),u])}const m=n(p,[["render",D],["__file","muxcool.html.vue"]]);export{m as default}; diff --git a/assets/muxcool.html-u7BHHyP5.js b/assets/muxcool.html-CiEIIjvK.js similarity index 99% rename from assets/muxcool.html-u7BHHyP5.js rename to assets/muxcool.html-CiEIIjvK.js index 5d945c42a6..3b83acb0ab 100644 --- a/assets/muxcool.html-u7BHHyP5.js +++ b/assets/muxcool.html-CiEIIjvK.js @@ -1 +1 @@ -import{_ as n,r as a,o as i,c as r,a as d,b as t,d as e,e as h}from"./app-DBM4OJyw.js";const p={},s=h('

                                      Mux.Cool 协议

                                      Mux.Cool 协议是一个多路复用传输协议,用于在一条已建立的数据流中传输多个各自独立的数据流。

                                      版本

                                      当前版本是 1 Beta。

                                      依赖

                                      底层协议

                                      Mux.Cool 必须运行在一个已建立的可靠数据流之上。

                                      通讯过程

                                      一个 Mux.Cool 连接中可传输若干个子连接,每个子连接有一个独立的 ID 和状态。传输过程由帧(Frame)组成,每一帧用于传输一个特定的子连接的数据。

                                      客户端行为

                                      当有连接需求时并且没有现有可用的连接时,客户端向服务器发起一个新连接,以下称为“主连接”。

                                      1. 一个主连接可用于发送若干个子连接。客户端可自主决定主连接可承载的子连接数量。
                                      2. 对于一个新的子连接,客户端必须发送状态New以通知服务器建立子连接,然后使用状态Keep来传送数据。
                                      3. 当子连接结束时,客户端发送End状态来通知服务器关闭子连接。
                                      4. 客户端可自行决定何时关闭主连接,但必须确定服务器也同时保持连接。
                                      5. 客户端可使用 KeepAlive 状态来避免服务器关闭主连接。

                                      服务器端行为

                                      当服务器端接收到新的子连接时,服务器应当按正常的连接来处理。

                                      1. 当收到状态End时,服务器端可以关闭对目标地址的上行连接。
                                      2. 在服务器的响应中,必须使用与请求相同的 ID 来传输子连接的数据。
                                      3. 服务器不能使用New状态。
                                      4. 服务器可使用 KeepAlive 状态来避免客户端关闭主连接。

                                      传输格式

                                      Mux.Cool 使用对称传输格式,即客户端和服务器发送和接收相同格式的数据。

                                      帧格式

                                      2 字节L 字节X 字节
                                      元数据长度 L元数据额外数据

                                      元数据

                                      元数据有若干种类型。所有类型的元数据都包含 ID 和 Opt 两项,其含义为:

                                      ',21),c=t("li",null,"对于一般 Mux 子连接,ID 由 1 开始累加",-1),x={href:"https://github.com/XTLS/Xray-core/blob/main/common/xudp/xudp.go",target:"_blank",rel:"noopener noreferrer"},b=t("li",null,[e("Opt: "),t("ul",null,[t("li",null,"D(0x01): 有额外数据")])],-1),u=h('

                                      当选项 Opt(D) 开启时,额外数据格式如下:

                                      2 字节X-2 字节
                                      长度 X-2数据

                                      新建子连接 (New)

                                      2 字节1 字节1 字节1 字节2 字节1 字节A 字节8 字节
                                      ID0x01选项 Opt网络类型 N端口地址类型 T地址 AGlobal ID (XUDP)

                                      其中:

                                      • 网络类型 N:
                                        • 0x01:TCP,表示当前子连接的流量应当以 TCP 的方式发送至目标。
                                        • 0x02:UDP,表示当前子连接的流量应当以 UDP 的方式发送至目标。
                                      • 地址类型 T:
                                        • 0x01:IPv4
                                        • 0x02:域名
                                        • 0x03:IPv6
                                      • 地址 A:
                                        • 当 T = 0x01 时,A 为 4 字节 IPv4 地址;
                                        • 当 T = 0x02 时,A 为 1 字节长度(L) + L 字节域名;
                                        • 当 T = 0x03 时,A 为 16 字节 IPv6 地址;
                                      • Global ID (XUDP):
                                        • 客户端计算出 UDP 来源二元组的全局独特 ID,服务端用以确保当 XUDP 断线重连时,仍使用同一个端口与目标通信。

                                      在新建子连接时,若 Opt(D) 开启,则这一帧所带的数据需要被发往目标主机。

                                      保持子连接 (Keep)

                                      TCP

                                      2 字节1 字节1 字节
                                      ID0x02选项 Opt

                                      UDP

                                      2 字节1 字节1 字节1 字节2 字节1 字节A 字节
                                      ID0x02选项 Opt网络类型 N端口地址类型 T地址 A

                                      在保持子连接时,若 Opt(D) 开启,则这一帧所带的数据需要被发往目标主机。 XUDP 在 Opt(D) 之后加 UDP 地址,格式同新建子连接,但没有 Global ID。

                                      关闭子连接 (End)

                                      2 字节1 字节1 字节
                                      ID0x03选项 Opt

                                      在保持子连接时,若 Opt(D) 开启,则这一帧所带的数据需要被发往目标主机。

                                      保持连接 (KeepAlive)

                                      2 字节1 字节1 字节
                                      ID0x04选项 Opt

                                      在保持连接时:

                                      • 若 Opt(D) 开启,则这一帧所带的数据必须被丢弃。
                                      • ID 可为随机值。

                                      应用

                                      Mux.Cool 协议与底层协议无关,理论上可以使用任何可靠的流式连接来传输 Mux.Cool 的协议数据。

                                      在目标导向的协议如 Shadowsocks 和 VMess 协议中,连接建立时必须包含一个指定的地址。 为了保持兼容性,Mux.Cool 协议指定地址为“v1.mux.cool”。即当主连接的目标地址与之匹配时,则进行 Mux.Cool 方式的转发,否则按传统方式进行转发。(注:这是一个程序内的标记,VMess 和 VLESS 并不会在数据包中发送“v1.mux.cool”地址)

                                      ',23);function D(_,f){const l=a("I18nTip"),o=a("ExternalLinkIcon");return i(),r("div",null,[d(l),s,t("ul",null,[t("li",null,[e("ID: 子连接的唯一标识 "),t("ul",null,[c,t("li",null,[e("对于 Xray 实现的 "),t("a",x,[e("Single XUDP"),d(o)]),e(",ID 始终为 0")])])]),b]),u])}const m=n(p,[["render",D],["__file","muxcool.html.vue"]]);export{m as default}; +import{_ as n,r as a,o as i,c as r,a as d,b as t,d as e,e as h}from"./app-D7uBbsY3.js";const p={},s=h('

                                      Mux.Cool 协议

                                      Mux.Cool 协议是一个多路复用传输协议,用于在一条已建立的数据流中传输多个各自独立的数据流。

                                      版本

                                      当前版本是 1 Beta。

                                      依赖

                                      底层协议

                                      Mux.Cool 必须运行在一个已建立的可靠数据流之上。

                                      通讯过程

                                      一个 Mux.Cool 连接中可传输若干个子连接,每个子连接有一个独立的 ID 和状态。传输过程由帧(Frame)组成,每一帧用于传输一个特定的子连接的数据。

                                      客户端行为

                                      当有连接需求时并且没有现有可用的连接时,客户端向服务器发起一个新连接,以下称为“主连接”。

                                      1. 一个主连接可用于发送若干个子连接。客户端可自主决定主连接可承载的子连接数量。
                                      2. 对于一个新的子连接,客户端必须发送状态New以通知服务器建立子连接,然后使用状态Keep来传送数据。
                                      3. 当子连接结束时,客户端发送End状态来通知服务器关闭子连接。
                                      4. 客户端可自行决定何时关闭主连接,但必须确定服务器也同时保持连接。
                                      5. 客户端可使用 KeepAlive 状态来避免服务器关闭主连接。

                                      服务器端行为

                                      当服务器端接收到新的子连接时,服务器应当按正常的连接来处理。

                                      1. 当收到状态End时,服务器端可以关闭对目标地址的上行连接。
                                      2. 在服务器的响应中,必须使用与请求相同的 ID 来传输子连接的数据。
                                      3. 服务器不能使用New状态。
                                      4. 服务器可使用 KeepAlive 状态来避免客户端关闭主连接。

                                      传输格式

                                      Mux.Cool 使用对称传输格式,即客户端和服务器发送和接收相同格式的数据。

                                      帧格式

                                      2 字节L 字节X 字节
                                      元数据长度 L元数据额外数据

                                      元数据

                                      元数据有若干种类型。所有类型的元数据都包含 ID 和 Opt 两项,其含义为:

                                      ',21),c=t("li",null,"对于一般 Mux 子连接,ID 由 1 开始累加",-1),x={href:"https://github.com/XTLS/Xray-core/blob/main/common/xudp/xudp.go",target:"_blank",rel:"noopener noreferrer"},b=t("li",null,[e("Opt: "),t("ul",null,[t("li",null,"D(0x01): 有额外数据")])],-1),u=h('

                                      当选项 Opt(D) 开启时,额外数据格式如下:

                                      2 字节X-2 字节
                                      长度 X-2数据

                                      新建子连接 (New)

                                      2 字节1 字节1 字节1 字节2 字节1 字节A 字节8 字节
                                      ID0x01选项 Opt网络类型 N端口地址类型 T地址 AGlobal ID (XUDP)

                                      其中:

                                      • 网络类型 N:
                                        • 0x01:TCP,表示当前子连接的流量应当以 TCP 的方式发送至目标。
                                        • 0x02:UDP,表示当前子连接的流量应当以 UDP 的方式发送至目标。
                                      • 地址类型 T:
                                        • 0x01:IPv4
                                        • 0x02:域名
                                        • 0x03:IPv6
                                      • 地址 A:
                                        • 当 T = 0x01 时,A 为 4 字节 IPv4 地址;
                                        • 当 T = 0x02 时,A 为 1 字节长度(L) + L 字节域名;
                                        • 当 T = 0x03 时,A 为 16 字节 IPv6 地址;
                                      • Global ID (XUDP):
                                        • 客户端计算出 UDP 来源二元组的全局独特 ID,服务端用以确保当 XUDP 断线重连时,仍使用同一个端口与目标通信。

                                      在新建子连接时,若 Opt(D) 开启,则这一帧所带的数据需要被发往目标主机。

                                      保持子连接 (Keep)

                                      TCP

                                      2 字节1 字节1 字节
                                      ID0x02选项 Opt

                                      UDP

                                      2 字节1 字节1 字节1 字节2 字节1 字节A 字节
                                      ID0x02选项 Opt网络类型 N端口地址类型 T地址 A

                                      在保持子连接时,若 Opt(D) 开启,则这一帧所带的数据需要被发往目标主机。 XUDP 在 Opt(D) 之后加 UDP 地址,格式同新建子连接,但没有 Global ID。

                                      关闭子连接 (End)

                                      2 字节1 字节1 字节
                                      ID0x03选项 Opt

                                      在保持子连接时,若 Opt(D) 开启,则这一帧所带的数据需要被发往目标主机。

                                      保持连接 (KeepAlive)

                                      2 字节1 字节1 字节
                                      ID0x04选项 Opt

                                      在保持连接时:

                                      • 若 Opt(D) 开启,则这一帧所带的数据必须被丢弃。
                                      • ID 可为随机值。

                                      应用

                                      Mux.Cool 协议与底层协议无关,理论上可以使用任何可靠的流式连接来传输 Mux.Cool 的协议数据。

                                      在目标导向的协议如 Shadowsocks 和 VMess 协议中,连接建立时必须包含一个指定的地址。 为了保持兼容性,Mux.Cool 协议指定地址为“v1.mux.cool”。即当主连接的目标地址与之匹配时,则进行 Mux.Cool 方式的转发,否则按传统方式进行转发。(注:这是一个程序内的标记,VMess 和 VLESS 并不会在数据包中发送“v1.mux.cool”地址)

                                      ',23);function D(_,f){const l=a("I18nTip"),o=a("ExternalLinkIcon");return i(),r("div",null,[d(l),s,t("ul",null,[t("li",null,[e("ID: 子连接的唯一标识 "),t("ul",null,[c,t("li",null,[e("对于 Xray 实现的 "),t("a",x,[e("Single XUDP"),d(o)]),e(",ID 始终为 0")])])]),b]),u])}const m=n(p,[["render",D],["__file","muxcool.html.vue"]]);export{m as default}; diff --git a/assets/muxcool.html-DJdC30Uv.js b/assets/muxcool.html-DTO-WOrE.js similarity index 98% rename from assets/muxcool.html-DJdC30Uv.js rename to assets/muxcool.html-DTO-WOrE.js index 27991e6163..fc4458c10c 100644 --- a/assets/muxcool.html-DJdC30Uv.js +++ b/assets/muxcool.html-DTO-WOrE.js @@ -1 +1 @@ -import{_ as t,r as a,o as n,c as o,a as i,e as s}from"./app-DBM4OJyw.js";const d={},h=s('

                                      Mux.Cool Protocol

                                      Mux.Cool protocol is a multiplexing transport protocol that is used to transmit multiple independent data streams within an established data stream.

                                      Version

                                      The current version is 1 Beta.

                                      Dependencies

                                      Underlying Protocol

                                      Mux.Cool must run on top of a reliable established data stream.

                                      Communication Process

                                      Within a Mux.Cool connection, multiple sub-connections can be transmitted, each with a unique ID and status. The transmission process consists of frames, with each frame used to transmit data for a specific sub-connection.

                                      Client behavior

                                      When there is a need for a connection and there are no existing available connections, the client initiates a new connection to the server, referred to as the "main connection".

                                      1. One main connection can be used to send several sub-connections. The client can decide independently how many sub-connections the main connection can handle.
                                      2. For a new sub-connection, the client must send the New status to notify the server to establish the sub-connection, and then use the Keep status to transmit data.
                                      3. When the sub-connection ends, the client sends the End status to notify the server to close the sub-connection.
                                      4. The client can decide when to close the main connection, but must ensure that the server also maintains the connection.
                                      5. The client can use the KeepAlive status to prevent the server from closing the main connection.

                                      Server-side behavior

                                      When a new sub-connection is received on the server side, the server should handle it as a normal connection.

                                      1. When the status "End" is received, the server can close the upstream connection to the target address.
                                      2. The same ID used in the request must be used to transfer sub-connection data in the server response.
                                      3. The server cannot use the "New" status.
                                      4. The server can use the KeepAlive status to avoid the client closing the main connection.

                                      Data Format

                                      Mux.Cool uses symmetric transmission format, where the client and server send and receive data in the same format.

                                      Frame Format

                                      2 BytesL BytesX Bytes
                                      Metadata Length LMetadataAdditional Data

                                      Metadata

                                      There are several types of metadata. All types of metadata contain two items, ID and Opt, with the following meanings:

                                      • ID: Unique identifier of the sub-connection
                                        • For general MUX sub-connections, the ID is accumulated starting from 1
                                        • For XUDP, the ID is always 0
                                      • Opt:
                                        • D(0x01): Additional data is available

                                      When option Opt(D) is enabled, the additional data format is as follows:

                                      2 BytesX-2 Bytes
                                      Length X-2Data
                                      2 Bytes1 Byte1 Byte1 Byte2 Bytes1 ByteA Bytes
                                      ID0x01OptionNetwork NPortType TAddress

                                      where:

                                      • Network type N:
                                        • 0x01: TCP, indicating that the traffic of the current sub-connection should be sent to the destination in the way of TCP.
                                        • 0x02: UDP, indicating that the traffic of the current sub-connection should be sent to the destination in the way of UDP.
                                      • Address type T:
                                        • 0x01: IPv4
                                        • 0x02: Domain name
                                        • 0x03: IPv6
                                      • Address A:
                                        • When T = 0x01, A is a 4-byte IPv4 address;
                                        • When T = 0x02, A is a 1-byte length (L) + L-byte domain name;
                                        • When T = 0x03, A is a 16-byte IPv6 address;

                                      If Opt(D) is enabled when creating a sub-connection, the data carried by this frame needs to be sent to the target host.

                                      Keep sub-connections

                                      2 Bytes1 Byte1 Byte
                                      ID0x02Option

                                      If Opt(D) is enabled while maintaining sub-connections, the data carried by this frame needs to be sent to the target host. XUDP adds the UDP address after Opt(D), and the format is the same as creating a new sub-connection.

                                      End

                                      2 Bytes1 Byte1 Byte
                                      ID0x03Option

                                      If Opt(D) is enabled while maintaining sub-connections, the data carried by this frame needs to be sent to the target host.

                                      KeepAlive

                                      2 Bytes1 Byte1 Byte
                                      ID0x04Option Opt

                                      While staying connected:

                                      • If Opt(D) is enabled, the data carried by this frame must be discarded.
                                      • ID can be a random value.

                                      Application

                                      The Mux.Cool protocol is agnostic to the underlying protocol and can theoretically use any reliable streaming connection to transmit Mux.Cool protocol data.

                                      In target-oriented protocols such as Shadowsocks and VMess, a specified address must be included when establishing a connection. To maintain compatibility, the Mux.Cool protocol specifies the address as "v1.mux.cool". When the target address of the main connection matches this address, the Mux.Cool forwarding method is used. Otherwise, forwarding is done in the traditional way. (Note: This is an internal tag in the program, and VMess and VLESS do not send the "v1.mux.cool" address in data packets.)

                                      ',42);function r(c,l){const e=a("I18nTip");return n(),o("div",null,[i(e),h])}const u=t(d,[["render",r],["__file","muxcool.html.vue"]]);export{u as default}; +import{_ as t,r as a,o as n,c as o,a as i,e as s}from"./app-D7uBbsY3.js";const d={},h=s('

                                      Mux.Cool Protocol

                                      Mux.Cool protocol is a multiplexing transport protocol that is used to transmit multiple independent data streams within an established data stream.

                                      Version

                                      The current version is 1 Beta.

                                      Dependencies

                                      Underlying Protocol

                                      Mux.Cool must run on top of a reliable established data stream.

                                      Communication Process

                                      Within a Mux.Cool connection, multiple sub-connections can be transmitted, each with a unique ID and status. The transmission process consists of frames, with each frame used to transmit data for a specific sub-connection.

                                      Client behavior

                                      When there is a need for a connection and there are no existing available connections, the client initiates a new connection to the server, referred to as the "main connection".

                                      1. One main connection can be used to send several sub-connections. The client can decide independently how many sub-connections the main connection can handle.
                                      2. For a new sub-connection, the client must send the New status to notify the server to establish the sub-connection, and then use the Keep status to transmit data.
                                      3. When the sub-connection ends, the client sends the End status to notify the server to close the sub-connection.
                                      4. The client can decide when to close the main connection, but must ensure that the server also maintains the connection.
                                      5. The client can use the KeepAlive status to prevent the server from closing the main connection.

                                      Server-side behavior

                                      When a new sub-connection is received on the server side, the server should handle it as a normal connection.

                                      1. When the status "End" is received, the server can close the upstream connection to the target address.
                                      2. The same ID used in the request must be used to transfer sub-connection data in the server response.
                                      3. The server cannot use the "New" status.
                                      4. The server can use the KeepAlive status to avoid the client closing the main connection.

                                      Data Format

                                      Mux.Cool uses symmetric transmission format, where the client and server send and receive data in the same format.

                                      Frame Format

                                      2 BytesL BytesX Bytes
                                      Metadata Length LMetadataAdditional Data

                                      Metadata

                                      There are several types of metadata. All types of metadata contain two items, ID and Opt, with the following meanings:

                                      • ID: Unique identifier of the sub-connection
                                        • For general MUX sub-connections, the ID is accumulated starting from 1
                                        • For XUDP, the ID is always 0
                                      • Opt:
                                        • D(0x01): Additional data is available

                                      When option Opt(D) is enabled, the additional data format is as follows:

                                      2 BytesX-2 Bytes
                                      Length X-2Data
                                      2 Bytes1 Byte1 Byte1 Byte2 Bytes1 ByteA Bytes
                                      ID0x01OptionNetwork NPortType TAddress

                                      where:

                                      • Network type N:
                                        • 0x01: TCP, indicating that the traffic of the current sub-connection should be sent to the destination in the way of TCP.
                                        • 0x02: UDP, indicating that the traffic of the current sub-connection should be sent to the destination in the way of UDP.
                                      • Address type T:
                                        • 0x01: IPv4
                                        • 0x02: Domain name
                                        • 0x03: IPv6
                                      • Address A:
                                        • When T = 0x01, A is a 4-byte IPv4 address;
                                        • When T = 0x02, A is a 1-byte length (L) + L-byte domain name;
                                        • When T = 0x03, A is a 16-byte IPv6 address;

                                      If Opt(D) is enabled when creating a sub-connection, the data carried by this frame needs to be sent to the target host.

                                      Keep sub-connections

                                      2 Bytes1 Byte1 Byte
                                      ID0x02Option

                                      If Opt(D) is enabled while maintaining sub-connections, the data carried by this frame needs to be sent to the target host. XUDP adds the UDP address after Opt(D), and the format is the same as creating a new sub-connection.

                                      End

                                      2 Bytes1 Byte1 Byte
                                      ID0x03Option

                                      If Opt(D) is enabled while maintaining sub-connections, the data carried by this frame needs to be sent to the target host.

                                      KeepAlive

                                      2 Bytes1 Byte1 Byte
                                      ID0x04Option Opt

                                      While staying connected:

                                      • If Opt(D) is enabled, the data carried by this frame must be discarded.
                                      • ID can be a random value.

                                      Application

                                      The Mux.Cool protocol is agnostic to the underlying protocol and can theoretically use any reliable streaming connection to transmit Mux.Cool protocol data.

                                      In target-oriented protocols such as Shadowsocks and VMess, a specified address must be included when establishing a connection. To maintain compatibility, the Mux.Cool protocol specifies the address as "v1.mux.cool". When the target address of the main connection matches this address, the Mux.Cool forwarding method is used. Otherwise, forwarding is done in the traditional way. (Note: This is an internal tag in the program, and VMess and VLESS do not send the "v1.mux.cool" address in data packets.)

                                      ',42);function r(c,l){const e=a("I18nTip");return n(),o("div",null,[i(e),h])}const u=t(d,[["render",r],["__file","muxcool.html.vue"]]);export{u as default}; diff --git a/assets/news.html-AUkvoQ5N.js b/assets/news.html-BZwUtxlV.js similarity index 99% rename from assets/news.html-AUkvoQ5N.js rename to assets/news.html-BZwUtxlV.js index b41355f8d3..50afcffa74 100644 --- a/assets/news.html-AUkvoQ5N.js +++ b/assets/news.html-BZwUtxlV.js @@ -1 +1 @@ -import{_ as d,r as i,o as c,c as u,a as n,b as e,d as t,w as a,e as r}from"./app-DBM4OJyw.js";const _={},p=e("h1",{id:"the-great-chronicles",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#the-great-chronicles"},[e("span",null,"The Great Chronicles")])],-1),f=e("h2",{id:"_2024-9-12",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2024-9-12"},[e("span",null,"2024.9.12")])],-1),g=e("p",null,"The Great Chronicles Return to the Scene?!",-1),m={id:"_2024-9-7-v24-9-7",tabindex:"-1"},b={class:"header-anchor",href:"#_2024-9-7-v24-9-7"},v={href:"https://github.com/XTLS/Xray-core/releases/tag/v24.9.7",target:"_blank",rel:"noopener noreferrer"},y=e("p",null,"First release after abandoning semantic versioning.",-1),w=e("ul",null,[e("li",null,[t("This time, QUIC and DomainSocket transports were removed, along with two pieces of legacy code. "),e("ul",null,[e("li",null,"The binary size is 1MB smaller than v1.8.24.")])]),e("li",null,"As always, there are essential bug fixes.")],-1),T={id:"_2024-8-30-v1-8-24",tabindex:"-1"},k={class:"header-anchor",href:"#_2024-8-30-v1-8-24"},x={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.24",target:"_blank",rel:"noopener noreferrer"},S=r('

                                      While waiting for the SplitHTTP multiplex controller, the main branch had accumulated many important updates, so we decided to release a version first.

                                      • The Socks inbound now supports HTTP proxy requests by default.
                                      • UDP noise (preview)
                                      • And some other improvements.

                                      Due to the existence of semantic versioning, planning features and scheduling for each release have severely hindered the development, merging, and release of new features. Therefore, we decided to abandon semantic versioning starting with the next release and use the release date as the version number, such as v24.8.30, and cancel version planning, fully adopting continuous updates. Features will be merged and released as soon as they are ready, with a version released at the end of each month.

                                      After all, as a software aiming to help people bypass censorship, instead of maintaining a long-term stable version, it's more important to adapt new features and keep updating monthly.

                                      The next version will remove some legacy code no longer in used, add warning log for using deprecated features/configs, and for sure, some breaking changes. Be aware that future versions will be released once we consider something new is ready for a release.

                                      We believe that with your donations and the reform of the release format, the Xray-core project will develop even better.

                                      2024.8.26

                                      The Project VLESS group was established.

                                      ',8),X={href:"https://t.me/projectVless",target:"_blank",rel:"noopener noreferrer"},L=e("h2",{id:"_2024-8-3",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2024-8-3"},[e("span",null,"2024.8.3")])],-1),A={href:"https://github.com/XTLS/Xray-core/discussions/3633#discussioncomment-10240940",target:"_blank",rel:"noopener noreferrer"},P={id:"_2024-7-29-v1-8-23",tabindex:"-1"},C={class:"header-anchor",href:"#_2024-7-29-v1-8-23"},D={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.23",target:"_blank",rel:"noopener noreferrer"},H={href:"https://github.com/mmmray",target:"_blank",rel:"noopener noreferrer"},U=e("li",null,"Optimized the stability of SplitHTTP upstream, and the server must be upgraded to this version to support the new client.",-1),I=e("li",null,"More changes on SplitHTTP.",-1),N={id:"_2024-7-22-v1-8-21",tabindex:"-1"},R={class:"header-anchor",href:"#_2024-7-22-v1-8-21"},E={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.21",target:"_blank",rel:"noopener noreferrer"},j=e("p",null,"It seems to have returned to the original state of rapid-fire releases...",-1),W=e("p",null,"As foreshadowed in v1.8.16, SplitHTTP now preliminarily supports HTTP/3 (QUIC). Undoubtedly, SplitHTTP H3 has ushered in a new era.",-1),F=e("ul",null,[e("li",null,"SplitHTTP H3 is the first QUIC-based proxy fully compliant with standard H3, supporting CDN passthrough, and can be concealed using reverse proxy or Browser Dialer.")],-1),V=e("h2",{id:"_2024-7-16",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2024-7-16"},[e("span",null,"2024.7.16")])],-1),M={href:"https://github.com/iambabyninja",target:"_blank",rel:"noopener noreferrer"},G=e("blockquote",null,[e("p",null,"Привет, друзья из России!")],-1),Y=e("h2",{id:"_2024-7-15",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2024-7-15"},[e("span",null,"2024.7.15")])],-1),O=e("p",null,"Although Windows 7 will eventually be phased out with future upgrades, we can now delay that time a little.",-1),B={id:"_2024-6-18-v1-8-16",tabindex:"-1"},q={class:"header-anchor",href:"#_2024-6-18-v1-8-16"},z={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.16",target:"_blank",rel:"noopener noreferrer"},Q=e("p",null,"A new transport has arrived, currently called SplitHTTP.",-1),K=e("ul",null,[e("li",null,"There are two completely opposite ways to achieve further traffic obfuscation: multiplexing and splitting connections."),e("li",null,"It can achieve the same goals as Meek through CDNs that do not support WebSocket or gRPC, and SplitHTTP is simpler and more efficient than Meek."),e("li",null,"SplitHTTP does not have WebSocket's ALPN issues, which is a major advantage, and it will support HTTP/3 (QUIC) in the future."),e("li",null,"SplitHTTP has also been added to the sharing link package.")],-1),J=e("h2",{id:"_2024-6-2",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2024-6-2"},[e("span",null,"2024.6.2")])],-1),Z=e("p",null,"A new transport method is being developed...",-1),$={id:"_2024-4-26-v1-8-11",tabindex:"-1"},ee={class:"header-anchor",href:"#_2024-4-26-v1-8-11"},te={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.11",target:"_blank",rel:"noopener noreferrer"},ne=e("ul",null,[e("li",null,"Now there is a tool to generate ECH keys."),e("li",null,"Enhancements, fixes, and some obsolete code removal.")],-1),oe=e("h2",{id:"_2024-4-20",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2024-4-20"},[e("span",null,"2024.4.20")])],-1),ae={href:"https://github.com/Fangliding",target:"_blank",rel:"noopener noreferrer"},se=e("h2",{id:"_2024-4-13",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2024-4-13"},[e("span",null,"2024.4.13")])],-1),re=e("p",null,"VLESS Seed is ready, waiting for the right moment.",-1),le={id:"_2024-3-18-v1-8-10",tabindex:"-1"},ie={class:"header-anchor",href:"#_2024-3-18-v1-8-10"},he={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.10",target:"_blank",rel:"noopener noreferrer"},de=e("p",null,"Like WebSocket, HTTPUpgrade now also has 0-RTT.",-1),ce={id:"_2024-3-11-v1-8-9",tabindex:"-1"},ue={class:"header-anchor",href:"#_2024-3-11-v1-8-9"},_e={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.9",target:"_blank",rel:"noopener noreferrer"},pe=e("p",null,"Added HTTPUpgrade transport, said to be lighter than WebSocket.",-1),fe=e("ul",null,[e("li",null,"Already added to the sharing link package.")],-1),ge=e("h2",{id:"_2024-2-29",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2024-2-29"},[e("span",null,"2024.2.29")])],-1),me=e("p",null,[t("gRPC transport now also has a Host-like configuration field! It's called "),e("code",null,"authority"),t('. Now gRPC can also "domain front," without ALPN issues.')],-1),be={id:"_2024-2-25-v1-8-8",tabindex:"-1"},ve={class:"header-anchor",href:"#_2024-2-25-v1-8-8"},ye={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.8",target:"_blank",rel:"noopener noreferrer"},we=e("ul",null,[e("li",null,"Now XUDP traffic is uniformly padded with Vision, come and experience it."),e("li",null,"Added leastLoad balancer."),e("li",null,"Fixed errors, optimized performance...")],-1),Te=e("h2",{id:"_2024-1-9",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2024-1-9"},[e("span",null,"2024.1.9")])],-1),ke=e("p",null,"Shocked to hear that Win7 cannot run the new version of Xray-core? Upon exploration, it was discovered that Go has dropped support for Win7. Is there a way to continue supporting this somewhat ancient but still elegant operating system?",-1),xe=e("h2",{id:"_2023-11-21",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2023-11-21"},[e("span",null,"2023.11.21")])],-1),Se={href:"https://t.me/projectXtls/212",target:"_blank",rel:"noopener noreferrer"},Xe={id:"_2023-11-18-v1-8-6",tabindex:"-1"},Le={class:"header-anchor",href:"#_2023-11-18-v1-8-6"},Ae={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.6",target:"_blank",rel:"noopener noreferrer"},Pe=r('
                                      • WireGuard now also has a corresponding inbound. Freedom outbound finally has splice.
                                      • The domainStrategy for outbound has also been unified.
                                      • More delicious little treats.
                                      • Due to force majeure feature changes, Dragonfly BSD support has quietly left the stage.
                                      • Are we really saying goodbye to the classic Windows 7?

                                      2023.9.30

                                      Designed a brand new color scheme for v2rayNG, install the latest Pre-release version to experience it.

                                      ',3),Ce={id:"_2023-8-29-v1-8-4",tabindex:"-1"},De={class:"header-anchor",href:"#_2023-8-29-v1-8-4"},He={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.4",target:"_blank",rel:"noopener noreferrer"},Ue=r('

                                      After half a year of polishing, 1.8.x has finally reached its first recognized official version. Likewise, there are many integrated improvements this time, come and taste it!

                                      2023.7.22

                                      Another historical HTTP/2 transport issue has been fixed.

                                      2023.7.7

                                      Vision will soon have Seed support.

                                      2023.6.30

                                      The next XTLS flow control: xtls-rprx-switch 🍪

                                      • XTLS's 0-RTT has been teased for months, originally to maintain some mystery.
                                      • Compared to the existing XTLS Vision and Mux, it has even better advantages.

                                      2023.6.27

                                      ',9),Ie={href:"https://github.com/XTLS/Xray-core/discussions/2256#discussioncomment-6295296",target:"_blank",rel:"noopener noreferrer"},Ne={id:"_2023-6-19-v1-8-3",tabindex:"-1"},Re={class:"header-anchor",href:"#_2023-6-19-v1-8-3"},Ee={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.3",target:"_blank",rel:"noopener noreferrer"},je=r('
                                      • The first version after the code streamlining plan, VMess (MD5), MTProto, and Starlark-related code have been removed. Going light.
                                      • Code refactoring is also part of going light.
                                      • We have also not forgotten to add some enhancements and fix vulnerabilities.
                                      • v2rayNG has not yet supported Xray, and the new sharing link format cannot be used yet.

                                      2023.6.6

                                      Good News: The next XTLS flow control will not be called Vision. 🍪

                                      2023.4.21

                                      ',4),We={href:"https://github.com/XTLS/RealiTLScanner",target:"_blank",rel:"noopener noreferrer"},Fe=e("h2",{id:"_2023-4-20",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2023-4-20"},[e("span",null,"2023.4.20")])],-1),Ve={href:"https://github.com/XTLS/Xray-core/discussions/1967",target:"_blank",rel:"noopener noreferrer"},Me=e("h2",{id:"_2023-4-19",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2023-4-19"},[e("span",null,"2023.4.19")])],-1),Ge=e("p",null,[e("code",null,"xtls-0rtt-vision(-udp443)"),t(" 🍪")],-1),Ye={id:"_2023-4-18-v1-8-1",tabindex:"-1"},Oe={class:"header-anchor",href:"#_2023-4-18-v1-8-1"},Be={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.1",target:"_blank",rel:"noopener noreferrer"},qe=r('

                                      The upgraded XUDP is here!

                                      • Now XUDP features connection migration and port reuse, with a global Session ID , so mom doesn't have to worry about what to do when there is an unexpected disconnection anymore.
                                      • We’ve also added control settings for XUDP, giving you better control~
                                      • The new XUDP paired with XTLS Vision offers an even better experience~
                                      • As usual, there’s a little treat, enjoy~

                                      2023.4.6

                                      XUDP is also quietly upgrading...

                                      2023.3.29

                                      PLUX protocol 🍪

                                      2023.3.19

                                      The sharing link standard for REALITY has also emerged.

                                      ',8),ze={id:"_2023-3-9-v1-8-0",tabindex:"-1"},Qe={class:"header-anchor",href:"#_2023-3-9-v1-8-0"},Ke={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.0",target:"_blank",rel:"noopener noreferrer"},Je=r('

                                      THE NEXT FUTURE, REALITY is NOW release on Xray-core

                                      REALITY has been implemented and released! Welcome to try it out! XTLS Vision has also been improved, please upgrade both ends to the latest version for the best experience.

                                      • Due to changes in the Vision padding algorithm, there may be compatibility issues between old and new versions of XTLS Vision.
                                      • HTTP/2 transport has also been improved, enjoy the smooth experience with the new version~
                                      • There are many other small improvements, feel free to explore~

                                      2023.3.4

                                      Legends never die, they become a part of you VLESS.

                                      They simply fade away.

                                      2023.3.2

                                      Some lingering issues with HTTP/2 transport have been improved. Enjoy the smooth experience when testing with REALITY~

                                      2023.2.16

                                      THE NEXT FUTURE becomes THE REALITY NOW!

                                      2023.2.9

                                      REALITY is reality now!

                                      ',11),Ze={id:"_2023-2-8-v1-7-5",tabindex:"-1"},$e={class:"header-anchor",href:"#_2023-2-8-v1-7-5"},et={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.7.5",target:"_blank",rel:"noopener noreferrer"},tt=e("p",null,"Keep riding and never look back.",-1),nt={href:"https://github.com/yuhan6665",target:"_blank",rel:"noopener noreferrer"},ot=e("li",null,"XTLS Vision flow control is nearly complete and will soon be practical.",-1),at=e("li",null,"Now there are more options for uTLS fingerprint simulation, which one suits you?",-1),st=e("li",null,"Sharing links now also support sharing uTLS fingerprint configurations.",-1),rt=e("li",null,"There are more feature enhancements and fixes.",-1),lt=e("li",null,[t("This version will also be the last time to see XTLS Origin, Direct, and Splice flow control. "),e("s",null,"A bit nostalgic, isn’t it?")],-1),it=e("h2",{id:"_2023-1-29",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2023-1-29"},[e("span",null,"2023.1.29")])],-1),ht=e("p",null,"Winter cannot cover the NEXT FUTURE...",-1),dt={id:"_2022-12-26-v1-7-0",tabindex:"-1"},ct={class:"header-anchor",href:"#_2022-12-26-v1-7-0"},ut={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.7.0",target:"_blank",rel:"noopener noreferrer"},_t=e("p",null,"Due to a slip of the hand, this version number jumped directly up, thanks for everyone's support!",-1),pt=e("ul",null,[e("li",null,"From now on, Semantic Versioning will be strictly followed.")],-1),ft={id:"_2022-11-28-v1-6-5",tabindex:"-1"},gt={class:"header-anchor",href:"#_2022-11-28-v1-6-5"},mt={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.6.5",target:"_blank",rel:"noopener noreferrer"},bt=e("p",null,"This time we have WireGuard outbound.",-1),vt=e("ul",null,[e("li",null,"Using WireGuard with CF WARP can unlock some fun new ways to play."),e("li",null,"Of course, there are also security updates and fixes.")],-1),yt={id:"_2022-11-7-v1-6-3",tabindex:"-1"},wt={class:"header-anchor",href:"#_2022-11-7-v1-6-3"},Tt={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.6.3",target:"_blank",rel:"noopener noreferrer"},kt=e("p",null,[t("Now Vision flow control can also use uTLS fingerprint simulation, is this the benefit brought by "),e("code",null,"tlsSettings"),t("!")],-1),xt={id:"_2022-10-29-v1-6-2",tabindex:"-1"},St={class:"header-anchor",href:"#_2022-10-29-v1-6-2"},Xt={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.6.2",target:"_blank",rel:"noopener noreferrer"},Lt=e("p",null,"The first release with Vision flow control is out! Welcome to try it and give feedback!",-1),At={id:"_2022-10-22-v1-6-1",tabindex:"-1"},Pt={class:"header-anchor",href:"#_2022-10-22-v1-6-1"},Ct={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.6.1",target:"_blank",rel:"noopener noreferrer"},Dt=r('
                                      • Brought uTLS fingerprint support for WebSocket, HTTP/2, and gRPC transport!
                                        • The option that was previously only available under regular TLS for TCP transport is now better.
                                      • On Linux, TCP congestion control can be set independently for ingress and egress.

                                      2022.10.3

                                      The weather is getting cooler, but the pace of development hasn’t slowed down. Blocks fall from the sky, but progress can’t be stopped...

                                      • A new XTLS flow control is brewing...
                                        • Addressing existing flow control issues;
                                        • Direct splice activation for TLS 1.3;
                                        • Added TLS handshake length obfuscation;
                                        • Simplified code, using tlsSettings instead of xtlsSettings...
                                      ',4),Ht={id:"_2022-8-28-v1-5-10",tabindex:"-1"},Ut={class:"header-anchor",href:"#_2022-8-28-v1-5-10"},It={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.5.10",target:"_blank",rel:"noopener noreferrer"},Nt=e("p",null,"Underlying transport now supports more reasonable TCP Keepalive settings.",-1),Rt={id:"_2022-6-20-v1-5-8",tabindex:"-1"},Et={class:"header-anchor",href:"#_2022-6-20-v1-5-8"},jt={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.5.8",target:"_blank",rel:"noopener noreferrer"},Wt=e("p",null,"Now Shadowsocks-2022 relay is also supported.",-1),Ft={id:"_2022-5-29-v1-5-6",tabindex:"-1"},Vt={class:"header-anchor",href:"#_2022-5-29-v1-5-6"},Mt={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.5.6",target:"_blank",rel:"noopener noreferrer"},Gt=e("p",null,"Shadowsocks-2022 protocol has come to Xray-core!",-1),Yt={href:"https://github.com/nekohasekai",target:"_blank",rel:"noopener noreferrer"},Ot={href:"https://github.com/database64128",target:"_blank",rel:"noopener noreferrer"},Bt={href:"https://github.com/RPRX",target:"_blank",rel:"noopener noreferrer"},qt=e("p",null,"Shadowsocks-2022 is a newly designed protocol:",-1),zt=e("ul",null,[e("li",null,"It addresses security issues like replay attacks while retaining native udp support from Shadowsocks (using timestamps similar to vmess, so client and server need synchronized time)."),e("li",null,"Supports multi-user on a single port, and implements session mechanisms similar to quic and wireguard to reduce encryption overhead and ensure seamless migration during network changes.")],-1),Qt={id:"_2022-4-24-v1-5-5",tabindex:"-1"},Kt={class:"header-anchor",href:"#_2022-4-24-v1-5-5"},Jt={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.5.5",target:"_blank",rel:"noopener noreferrer"},Zt=e("p",null,"This time we brought a convenient visual data detection interface! Come and experience it!",-1),$t=e("ul",null,[e("li",null,"We also fixed some issues affecting user experience.")],-1),en={id:"_2022-3-13-v1-5-4",tabindex:"-1"},tn={class:"header-anchor",href:"#_2022-3-13-v1-5-4"},nn={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.5.4",target:"_blank",rel:"noopener noreferrer"},on=e("p",null,"Added a wxray.exe file for Windows platform with no black windows popping up, and brought enhancements for UDS listening.",-1),an={id:"_2022-1-29-v1-5-3",tabindex:"-1"},sn={class:"header-anchor",href:"#_2022-1-29-v1-5-3"},rn={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.5.3",target:"_blank",rel:"noopener noreferrer"},ln=e("p",null,"Farewell to the year of the Ox, and leap into the new year of the Tiger. 🧨",-1),hn=e("ul",null,[e("li",null,"This time we brought improvements to stream allocation for QUIC transport, making QUIC transport smoother.")],-1),dn={id:"_2021-12-24-v1-5-2",tabindex:"-1"},cn={class:"header-anchor",href:"#_2021-12-24-v1-5-2"},un={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.5.2",target:"_blank",rel:"noopener noreferrer"},_n=e("p",null,"Added a new option for gRPC, making it even better when used through a CDN.",-1),pn={id:"_2021-12-15-v1-5-1",tabindex:"-1"},fn={class:"header-anchor",href:"#_2021-12-15-v1-5-1"},gn={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.5.1",target:"_blank",rel:"noopener noreferrer"},mn=e("blockquote",null,[e("p",null,"“A transitional, phased maintenance version”")],-1),bn=e("ul",null,[e("li",null,"New features, enhancements, and a lot of fixes are coming in."),e("li",null,[t("Remember to remove "),e("code",null,"alterID"),t(" from your VMess configuration!")])],-1),vn={id:"_2021-10-20-v1-5-0",tabindex:"-1"},yn={class:"header-anchor",href:"#_2021-10-20-v1-5-0"},wn={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.5.0",target:"_blank",rel:"noopener noreferrer"},Tn=e("p",null,"A really big change!",-1),kn=e("ul",null,[e("li",null,"Refactored the DNS component, with more supported protocols and detailed configurations."),e("li",null,"Enhanced gRPC transport and FakeDNS."),e("li",null,"Finally supports Windows ARM64."),e("li",null,"More new features and improvements await you.")],-1),xn={id:"_2021-9-23-v1-4-5",tabindex:"-1"},Sn={class:"header-anchor",href:"#_2021-9-23-v1-4-5"},Xn={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.4.5",target:"_blank",rel:"noopener noreferrer"},Ln=r('

                                      Happy Mid-Autumn Festival, wishing you a joyful reunion.

                                      • Fixed a bug where the version number was too low and unlucky.
                                      • This update removed the insecure encryption methods from Shadowsocks. Please migrate to AEAD encryption as soon as possible.
                                      • This update fixed a longstanding issue from ancient times: enabling traffic statistics could cause a performance drop. Simply put, enabling statistics now will not impact performance regardless of the configuration.
                                      • Also included are security updates for XTLS and numerous other fixes.
                                      • By the way, due to the TLS library update, cipherSuites can no longer specify the order of cipher suites, and preferServerCipherSuites has been completely deprecated. In fact, these changes were already present in Xray-core v1.4.3.

                                      2021.9.16

                                      ',3),An={href:"https://xtls.github.io/",target:"_blank",rel:"noopener noreferrer"},Pn={id:"_2021-9-8-v1-4-3",tabindex:"-1"},Cn={class:"header-anchor",href:"#_2021-9-8-v1-4-3"},Dn={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.4.3",target:"_blank",rel:"noopener noreferrer"},Hn=r('

                                      This is a maintenance release. Development continues…

                                      • A large number of improvements and new features have accumulated during this period.
                                      • Added a new DomainMatcher, improving domain rule matching performance.
                                      • Added health checks for HTTP/2 and gRPC transports, improved handling of unknown SNI, and fixed a bunch of bugs.

                                      Helden sterben nicht!

                                      2021.7.14

                                      • AnXray's expensively designed new icon is now live!
                                        • The new icon is now more recognizable.
                                      • Over the past three weeks, AnXray has accumulated 600 stars, 2K+ channel subscriptions, and 11K+ GitHub downloads. Thank you for your support.
                                      • AX is short for AnXray. We recommend using AX to refer to AnXray—it's short and convenient.

                                      2021.6.21

                                      ',6),Un={href:"https://github.com/XTLS/AnXray",target:"_blank",rel:"noopener noreferrer"},In={href:"https://github.com/nekohasekai",target:"_blank",rel:"noopener noreferrer"},Nn=e("li",null,"Supports numerous protocols and plugins.",-1),Rn={href:"https://github.com/RPRX",target:"_blank",rel:"noopener noreferrer"},En=e("li",null,"There's also a small Easter egg waiting to be discovered in the app.",-1),jn=r('

                                      Spent the last few days refining details from morning till night. We hope you'll star and follow the project.

                                      2021.5.1

                                      Improvements to tun2socks have appeared in v2rayNG.

                                      2021.4.26

                                      Brought an improvement to tun2socks. You might get to enjoy it in the future~

                                      2021.4.12

                                      Let's foresee X-flutter; looking forward to what it might be like~ 🍪

                                      2021.4.6

                                      • VuePress Next.
                                      • With Dark Mode.

                                      2021.4.4

                                      • This document has a new homepage.
                                      • This document now has a dark mode.
                                      • Of course, dark mode still has various issues. Specific content will need to be gradually adjusted.
                                      • Additionally, the Telegram group chat has surpassed 5,000 members! An Anti-Spam bot has also been added!
                                      • 🎉🎉🎉
                                      ',11),Wn={id:"_2021-4-1-v1-4-2",tabindex:"-1"},Fn={class:"header-anchor",href:"#_2021-4-1-v1-4-2"},Vn={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.4.2",target:"_blank",rel:"noopener noreferrer"},Mn=r('
                                      • Not an April Fool's joke, updated today.
                                      • Added Browser Dialer to modify TLS fingerprints and behavior.
                                      • Added uTLS to modify the TLS Client Hello fingerprint.
                                      • Also fixed a bunch of strange issues; see the changelog for details.

                                      2021.3.25

                                      Yes, it’s still changing. -_-

                                      2021.3.15

                                      The documentation site is quietly undergoing some mysterious changes..., 🙊🙊🙊

                                      ',5),Gn={id:"_2021-3-14-v1-4-0",tabindex:"-1"},Yn={class:"header-anchor",href:"#_2021-3-14-v1-4-0"},On={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.4.0",target:"_blank",rel:"noopener noreferrer"},Bn=r("
                                      • Happy Pi-Day!
                                      • This is a major update:
                                        • Introduced transport layer support for chained proxies.
                                        • Introduced Domain Strategy for the Dialer, solving strange DNS issues.
                                        • Added gRPC transport method and a slightly faster Multi Mode.
                                        • Added WebSocket Early-Data feature, reducing WebSocket latency.
                                        • Added FakeDNS.
                                        • Also fixed a series of issues and added various features. For details, see the changelog.
                                      • VuePress is still more enjoyable~
                                      ",1),qn={id:"_2021-3-3-1-3-1",tabindex:"-1"},zn={class:"header-anchor",href:"#_2021-3-3-1-3-1"},Qn={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.3.1",target:"_blank",rel:"noopener noreferrer"},Kn=e("ul",null,[e("li",null,"This version uses Golang 1.16, officially supporting Apple Silicon natively."),e("li",null,[t("Also fixed a bug that could cause a panic. "),e("s",null,"Holmium_ thinks this is deceit, a sneak attack.")]),e("li",null,"Fixed several legacy issues.")],-1),Jn={id:"_2021-2-14-1-3-0",tabindex:"-1"},Zn={class:"header-anchor",href:"#_2021-2-14-1-3-0"},$n={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.3.0",target:"_blank",rel:"noopener noreferrer"},eo=e("ul",null,[e("li",null,"Happy 🐮 Year 🎉!"),e("li",null,"v1.3.0 implemented FullCone for all V protocols using a very clever mechanism, while ensuring some compatibility."),e("li",null,"OHHHHHHHHHHHH!")],-1),to={id:"_2021-01-31-1-2-4",tabindex:"-1"},no={class:"header-anchor",href:"#_2021-01-31-1-2-4"},oo={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.2.4",target:"_blank",rel:"noopener noreferrer"},ao=e("ul",null,[e("li",null,"Resolved two longstanding issues where “connecting to a standard Socks server might result in errors.”"),e("li",null,"It seems there’s not much change in this version, but it’s just the calm before the storm."),e("li",null,[t("(Yes, I’m a prophet) "),e("blockquote",null,[e("p",null,"You fool, you’re holding a UNO card.")])])],-1),so=e("h2",{id:"_2021-01-25",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2021-01-25"},[e("span",null,"2021.01.25")])],-1),ro=e("li",null,[t("The "),e("a",{href:"../en"},"English version of the documentation site"),t(" is gradually being updated, thanks to the hard work of everyone involved!")],-1),lo={id:"_2021-01-22-1-2-3",tabindex:"-1"},io={class:"header-anchor",href:"#_2021-01-22-1-2-3"},ho={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.2.3",target:"_blank",rel:"noopener noreferrer"},co=e("li",null,[e("strong",null,"Yet again"),t(", support for the SS protocol has been strengthened, now supporting multi-user on a single port!")],-1),uo=e("li",null,[e("strong",null,"Yet again"),t(", support for the trojan protocol has been strengthened, with new SNI-based routing for trojan fallback!")],-1),_o=e("li",null,[e("em",null,"(VLESS: sobbing)")],-1),po=e("li",null,"The weird UDP bugs have been fixed, making it “stable” in one word.",-1),fo=e("li",null,"Sniffing can now exclude domains you don't want to sniff, opening up some new possibilities.",-1),go={href:"https://github.com/bohanyang",target:"_blank",rel:"noopener noreferrer"},mo=e("li",null,"Other tasty cherries—just update and taste them.",-1),bo=r('

                                      2021.01.19

                                      • Some numbers:
                                        • 10 tags released
                                        • 100 issues resolved
                                        • 300 forks created
                                        • 2000 stars given
                                        • 3000 members in the group

                                      2021.01.17

                                      ',3),vo={href:"https://github.com/jiuqi9997",target:"_blank",rel:"noopener noreferrer"},yo={href:"https://xtls.github.io/en/",target:"_blank",rel:"noopener noreferrer"},wo={id:"_2021-01-15-1-2-2",tabindex:"-1"},To={class:"header-anchor",href:"#_2021-01-15-1-2-2"},ko={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.2.2",target:"_blank",rel:"noopener noreferrer"},xo=r('
                                      • Fallback routing has unlocked a new strange trick! You can now route based on SNI in the fallback!
                                      • The previously announced UUID modification is officially live. (Scroll down, scroll down)
                                      • The logs now look a bit more pleasing to the eye than last time.
                                      • Remote DOH has learned to use routing just like other DNS modes.
                                      • And of course, various other little candies. (Just update and taste them)
                                      • Oh, and, the first person to run Xray on an M1 Mac is Anthony TSE.

                                      2021.01.12

                                      ',2),So=e("li",null,[t("Upcoming UUID modification supports mapping between custom strings and UUIDs. This means you can write the id like this in the configuration file to correspond to users. "),e("ul",null,[e("li",null,[t("Client writes "),e("code",null,'"id": "I love 🍉 teacher 1314"'),t(",")]),e("li",null,[t("Server writes "),e("code",null,'"id": "5783a3e7-e373-51cd-8642-c83782b807c5"'),t(" (This UUID is the UUID mapping of "),e("code",null,"I love 🍉 teacher 1314"),t(")")])])],-1),Xo={id:"_2021-01-10-1-2-1",tabindex:"-1"},Lo={class:"header-anchor",href:"#_2021-01-10-1-2-1"},Ao={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.2.1",target:"_blank",rel:"noopener noreferrer"},Po=e("li",null,"(Possibly the most detailed and patient guide on the entire internet for configuring from zero)",-1),Co=e("li",null,"Many other details have been modified, and the documentation will become more standardized!",-1),Do={href:"https://github.com/ricuhkaen",target:"_blank",rel:"noopener noreferrer"},Ho={href:"https://github.com/BioniCosmos",target:"_blank",rel:"noopener noreferrer"},Uo={href:"https://github.com/kirin10000",target:"_blank",rel:"noopener noreferrer"},Io=r('
                                      • A lot of UDP-related fixes, now you can even play Rainbow Six Siege on Ubisoft's potato servers!
                                      • Google Voice should now work properly when making calls with v2rayNG.
                                      • Logs now look more pleasing to the eye.

                                      2021.01.07

                                      • Courtesy and respect should be fundamental principles that don’t need to be explicitly stated in the community.

                                      2021.01.05

                                      • The documentation website is quietly undergoing some mysterious changes..., 🙊🙊🙊

                                      2021.01.03

                                      ',6),No={href:"https://github.com/BioniCosmos",target:"_blank",rel:"noopener noreferrer"},Ro=e("li",null,"The TG group has surpassed 2500 members.",-1),Eo=e("h2",{id:"_2021-01-01",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2021-01-01"},[e("span",null,"2021.01.01")])],-1),jo={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.2.0",target:"_blank",rel:"noopener noreferrer"},Wo=e("p",null,"🎁 In the last few minutes of New Year's Day, v1.2.0 arrived, continuing the tradition of Friday updates, bringing the hard work of all contributors and the dark circles of @rprxx—living up to expectations!",-1),Fo=r('
                                    22. The New Year's gift 🎁 following the Christmas gift v1.1.5, a great benefit for gamers, full FullCone support.
                                    23. (UDP will continue to be enhanced!)
                                    24. If you’ve already opened your Christmas gift, this time there’s an even more beautifully wrapped package and little candies. (As always, no need to ask, just update and taste it)
                                    25. (No, what's below is not an ad, but a milestone.)
                                    26. Xray is the first unrestricted multi-protocol platform: Xray alone solves the problem, without relying on other implementations.
                                      • One person handles everything! Supports all major mainstream protocols!
                                      • Unparalleled performance!
                                      • Continuously improving features!
                                      • Incredible vitality and community affinity!
                                    27. ',5),Vo={href:"https://github.com/XTLS/Xray-core/discussions/56",target:"_blank",rel:"noopener noreferrer"},Mo={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.2.0",target:"_blank",rel:"noopener noreferrer"},Go=e("s",null,"(Ah, someone’s knocking at the door... I’ll tell you later)",-1),Yo=e("h2",{id:"_2020-12-29",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2020-12-29"},[e("span",null,"2020.12.29")])],-1),Oo={href:"https://t.me/projectXray",target:"_blank",rel:"noopener noreferrer"},Bo={id:"_2020-12-25-1-1-5",tabindex:"-1"},qo={class:"header-anchor",href:"#_2020-12-25-1-1-5"},zo={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.1.5",target:"_blank",rel:"noopener noreferrer"},Qo=e("p",null,"Merry Christmas!",-1),Ko=e("li",null,"A Christmas gift for gamers! You can now enjoy gaming with Xray! Thanks to SS/trojan UDP FullCone.",-1),Jo=e("li",null,"You can now write configuration files in your preferred format, such as YAML or TOML...",-1),Zo=e("li",null,"(VLESS’s UDP FullCone and more enhancements are coming soon!)",-1),$o=e("li",null,"No need to worry about certificate validation being blocked anymore, OCSP stapling is now online!",-1),ea={href:"https://github.com/XTLS/Xray-install",target:"_blank",rel:"noopener noreferrer"},ta=e("li",null,"And more delicious little cherries! (No need to ask, just update and taste it)",-1),na=e("h2",{id:"_2020-12-24",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2020-12-24"},[e("span",null,"2020.12.24")])],-1),oa={href:"https://xtls.github.io",target:"_blank",rel:"noopener noreferrer"},aa=e("p",null,"Everyone is welcome to check various contents and correct any errors/suggestions (can be submitted to the issue area of the documentation GitHub repository).",-1),sa={href:"https://github.com/XTLS/XTLS.github.io",target:"_blank",rel:"noopener noreferrer"},ra=e("p",null,"There’s a brief tutorial in the repository's README explaining how to help Xray improve the documentation website. Everyone is welcome to check it out, correct errors, modify, and add experiences.",-1),la=e("h2",{id:"_2020-12-23",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2020-12-23"},[e("span",null,"2020.12.23")])],-1),ia={href:"https://t.me/projectXray",target:"_blank",rel:"noopener noreferrer"},ha=e("h2",{id:"_2020-12-21",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2020-12-21"},[e("span",null,"2020.12.21")])],-1),da=e("ul",null,[e("li",null,"Project X group member count exceeds 2000."),e("li",null,"The group messages (including game groups) surpass 10,000 daily.")],-1),ca={id:"_2020-12-18-1-1-4",tabindex:"-1"},ua={class:"header-anchor",href:"#_2020-12-18-1-1-4"},_a={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.1.4",target:"_blank",rel:"noopener noreferrer"},pa=e("ul",null,[e("li",null,"Lower startup memory usage and memory usage optimization."),e("li",null,"Customize TLS at will to improve your SSL rating."),e("li",null,"Added Splice support for XTLS inbound and support for trojan XTLS."),e("li",null,"Also, best usage mode suggestions for Splice on your router.")],-1),fa=e("h2",{id:"_2020-12-17",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2020-12-17"},[e("span",null,"2020.12.17")])],-1),ga={href:"https://t.me/joinchat/UO4NixbB_XDQJOUjS6mHEQ",target:"_blank",rel:"noopener noreferrer"},ma=e("h2",{id:"_2020-12-15",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2020-12-15"},[e("span",null,"2020.12.15")])],-1),ba={href:"https://github.com/XTLS/Xray-install/tree/dev",target:"_blank",rel:"noopener noreferrer"},va={id:"_2020-12-11-1-1-3",tabindex:"-1"},ya={class:"header-anchor",href:"#_2020-12-11-1-1-3"},wa={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.1.3",target:"_blank",rel:"noopener noreferrer"},Ta=e("ul",null,[e("li",null,"Full version of REDIRECT transparent proxy mode."),e("li",null,"Optimization suggestions for Splice flow control mode on soft routers.")],-1),ka={id:"_2020-12-06-1-1-2",tabindex:"-1"},xa={class:"header-anchor",href:"#_2020-12-06-1-1-2"},Sa={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.1.2",target:"_blank",rel:"noopener noreferrer"},Xa=r('
                                      • Added splice mode for flow control, Linux exclusive, with unparalleled performance.
                                      • Enhanced API compatibility.

                                      2020.12.04

                                      Added splice mode.

                                      2020.11.27

                                      • Project X's GitHub main repository Xray-core has now received 500+ stars.
                                      • Featured on GitHub Trending.
                                      • Project X group members exceeded 1000, and channel subscribers reached 500+.
                                      ',5),La={id:"_2020-11-25-1-0-0",tabindex:"-1"},Aa={class:"header-anchor",href:"#_2020-11-25-1-0-0"},Pa={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.0.0",target:"_blank",rel:"noopener noreferrer"},Ca=e("p",null,"Xray’s first version.",-1),Da=e("ul",null,[e("li",null,"Based on v2ray-core with significant modifications."),e("li",null,"Comprehensive enhancements, excellent performance, fully compatible.")],-1),Ha=e("h2",{id:"_2020-11-23",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2020-11-23"},[e("span",null,"2020.11.23")])],-1),Ua=e("p",null,"project X start",-1),Ia=e("blockquote",null,[e("p",null,[e("s",null,"When the dream begins")])],-1);function Na(Ra,Ea){const h=i("I18nTip"),o=i("ExternalLinkIcon"),s=i("Badge"),l=i("RouterLink");return c(),u("div",null,[p,n(h),f,g,e("h2",m,[e("a",b,[e("span",null,[t("2024.9.7 "),n(s,null,{default:a(()=>[e("a",v,[t("v24.9.7"),n(o)])]),_:1})])])]),y,w,e("h2",T,[e("a",k,[e("span",null,[t("2024.8.30 "),n(s,null,{default:a(()=>[e("a",x,[t("v1.8.24"),n(o)])]),_:1})])])]),S,e("p",null,[t("We have created "),e("a",X,[t("Project VLESS"),n(o)]),t(" for non-Chinese users (mainly Russian).")]),L,e("p",null,[t("The first "),e("a",A,[t("Project X NFT"),n(o)]),t(" is officially released! Just as Xray has made history, releasing an NFT is also an unprecedented move in this field. These NFTs are highly commemorative and even historically significant, far beyond their current initial price. In time, they will undoubtedly become priceless. Once again, thank you for your support of Project X.")]),e("h2",P,[e("a",C,[e("span",null,[t("2024.7.29 "),n(s,null,{default:a(()=>[e("a",D,[t("v1.8.23"),n(o)])]),_:1})])])]),e("ul",null,[e("li",null,[t("Congratulations to "),e("a",H,[t("@mmmray"),n(o)]),t(" for contributing the 1000th commit to Xray-core!")]),U,I]),e("h2",N,[e("a",R,[e("span",null,[t("2024.7.22 "),n(s,null,{default:a(()=>[e("a",E,[t("v1.8.21"),n(o)])]),_:1})])])]),j,W,F,V,e("p",null,[t("Project X documentation now has a Russian version! Thanks to "),e("a",M,[t("@iambabyninja"),n(o)]),t(" for the translation!")]),G,Y,e("p",null,[t("Through known information and efforts, Xray-core now supports Windows 7 again! In subsequent releases, Windows 7 users can enjoy it by downloading and extracting the Xray-win7-32.zip or Xray-win7-64.zip packages. Thank you for your support! For specific usage, please click "),n(l,{to:"/en/document/install.html"},{default:a(()=>[t("here")]),_:1})]),O,e("h2",B,[e("a",q,[e("span",null,[t("2024.6.18 "),n(s,null,{default:a(()=>[e("a",z,[t("v1.8.16"),n(o)])]),_:1})])])]),Q,K,J,Z,e("h2",$,[e("a",ee,[e("span",null,[t("2024.4.26 "),n(s,null,{default:a(()=>[e("a",te,[t("v1.8.11"),n(o)])]),_:1})])])]),ne,oe,e("p",null,[t("We now have issue templates, thanks to "),e("a",ae,[t("@Fangliding"),n(o)]),t("!")]),se,re,e("h2",le,[e("a",ie,[e("span",null,[t("2024.3.18 "),n(s,null,{default:a(()=>[e("a",he,[t("v1.8.10"),n(o)])]),_:1})])])]),de,e("h2",ce,[e("a",ue,[e("span",null,[t("2024.3.11 "),n(s,null,{default:a(()=>[e("a",_e,[t("v1.8.9"),n(o)])]),_:1})])])]),pe,fe,ge,me,e("h2",be,[e("a",ve,[e("span",null,[t("2024.2.25 "),n(s,null,{default:a(()=>[e("a",ye,[t("v1.8.8"),n(o)])]),_:1})])])]),we,Te,ke,xe,e("p",null,[t("The "),e("a",Se,[t("paper"),n(o)]),t(" published at the USENIX top conference confirms that XTLS Vision has achieved its design goals. And XTLS will not stop there, breaking through towering walls like X-rays.")]),e("h2",Xe,[e("a",Le,[e("span",null,[t("2023.11.18 "),n(s,null,{default:a(()=>[e("a",Ae,[t("v1.8.6"),n(o)])]),_:1})])])]),Pe,e("h2",Ce,[e("a",De,[e("span",null,[t("2023.8.29 "),n(s,null,{default:a(()=>[e("a",He,[t("v1.8.4"),n(o)])]),_:1})])])]),Ue,e("p",null,[e("a",Ie,[t("How to choose a REALITY target domain? Check here to help you achieve twice the result with half the effort!"),n(o)])]),e("h2",Ne,[e("a",Re,[e("span",null,[t("2023.6.19 "),n(s,null,{default:a(()=>[e("a",Ee,[t("v1.8.3"),n(o)])]),_:1})])])]),je,e("p",null,[t("Maybe we can leverage "),e("a",We,[t("RealiTLScanner"),n(o)]),t("……")]),Fe,e("p",null,[t("After years of development and countless lines of code... "),e("a",Ve,[t("The code simplification plan"),n(o)]),t(" has been proposed!")]),Me,Ge,e("h2",Ye,[e("a",Oe,[e("span",null,[t("2023.4.18 "),n(s,null,{default:a(()=>[e("a",Be,[t("v1.8.1"),n(o)])]),_:1})])])]),qe,e("h2",ze,[e("a",Qe,[e("span",null,[t("2023.3.9 "),n(s,null,{default:a(()=>[e("a",Ke,[t("v1.8.0"),n(o)])]),_:1})])])]),Je,e("h2",Ze,[e("a",$e,[e("span",null,[t("2023.2.8 "),n(s,null,{default:a(()=>[e("a",et,[t("v1.7.5"),n(o)])]),_:1})])])]),tt,e("ul",null,[e("li",null,[t("Congratulations to "),e("a",nt,[t("@yuhan6665"),n(o)]),t(" for contributing the 500th commit to Xray-core!")]),ot,at,st,rt,lt]),it,ht,e("h2",dt,[e("a",ct,[e("span",null,[t("2022.12.26 "),n(s,null,{default:a(()=>[e("a",ut,[t("v1.7.0"),n(o)])]),_:1})])])]),_t,pt,e("h2",ft,[e("a",gt,[e("span",null,[t("2022.11.28 "),n(s,null,{default:a(()=>[e("a",mt,[t("v1.6.5"),n(o)])]),_:1})])])]),bt,vt,e("h2",yt,[e("a",wt,[e("span",null,[t("2022.11.7 "),n(s,null,{default:a(()=>[e("a",Tt,[t("v1.6.3"),n(o)])]),_:1})])])]),kt,e("h2",xt,[e("a",St,[e("span",null,[t("2022.10.29 "),n(s,null,{default:a(()=>[e("a",Xt,[t("v1.6.2"),n(o)])]),_:1})])])]),Lt,e("h2",At,[e("a",Pt,[e("span",null,[t("2022.10.22 "),n(s,null,{default:a(()=>[e("a",Ct,[t("v1.6.1"),n(o)])]),_:1})])])]),Dt,e("h2",Ht,[e("a",Ut,[e("span",null,[t("2022.8.28 "),n(s,null,{default:a(()=>[e("a",It,[t("v1.5.10"),n(o)])]),_:1})])])]),Nt,e("h2",Rt,[e("a",Et,[e("span",null,[t("2022.6.20 "),n(s,null,{default:a(()=>[e("a",jt,[t("v1.5.8"),n(o)])]),_:1})])])]),Wt,e("h2",Ft,[e("a",Vt,[e("span",null,[t("2022.5.29 "),n(s,null,{default:a(()=>[e("a",Mt,[t("v1.5.6"),n(o)])]),_:1})])])]),Gt,e("ul",null,[e("li",null,[t("Thanks to "),e("a",Yt,[t("@nekohasekai"),n(o)]),t(" for developing the brand new go implementation https://github.com/SagerNet/sing-shadowsocks and bringing it to Xray.")]),e("li",null,[t("Thanks to "),e("a",Ot,[t("@database64128"),n(o)]),t(" for driving the Shadowsocks community to propose a complete design.")]),e("li",null,[t("Thanks to "),e("a",Bt,[t("@RPRX"),n(o)]),t(" for submitting the original vulnerability.")])]),qt,zt,e("h2",Qt,[e("a",Kt,[e("span",null,[t("2022.4.24 "),n(s,null,{default:a(()=>[e("a",Jt,[t("v1.5.5"),n(o)])]),_:1})])])]),Zt,$t,e("h2",en,[e("a",tn,[e("span",null,[t("2022.3.13 "),n(s,null,{default:a(()=>[e("a",nn,[t("v1.5.4"),n(o)])]),_:1})])])]),on,e("h2",an,[e("a",sn,[e("span",null,[t("2022.1.29 "),n(s,null,{default:a(()=>[e("a",rn,[t("v1.5.3"),n(o)])]),_:1})])])]),ln,hn,e("h2",dn,[e("a",cn,[e("span",null,[t("2021.12.24 "),n(s,null,{default:a(()=>[e("a",un,[t("v1.5.2"),n(o)])]),_:1})])])]),_n,e("h2",pn,[e("a",fn,[e("span",null,[t("2021.12.15 "),n(s,null,{default:a(()=>[e("a",gn,[t("v1.5.1"),n(o)])]),_:1})])])]),mn,bn,e("h2",vn,[e("a",yn,[e("span",null,[t("2021.10.20 "),n(s,null,{default:a(()=>[e("a",wn,[t("v1.5.0"),n(o)])]),_:1})])])]),Tn,kn,e("h2",xn,[e("a",Sn,[e("span",null,[t("2021.9.23 "),n(s,null,{default:a(()=>[e("a",Xn,[t("v1.4.5"),n(o)])]),_:1})])])]),Ln,e("ul",null,[e("li",null,[t("The documentation site has fully transitioned to docs-next, providing a smoother and better experience! The address remains "),e("a",An,[t("https://xtls.github.io/"),n(o)]),t(".")])]),e("h2",Pn,[e("a",Cn,[e("span",null,[t("2021.9.8 "),n(s,null,{default:a(()=>[e("a",Dn,[t("v1.4.3"),n(o)])]),_:1})])])]),Hn,e("p",null,[t("Now, an open-source, free Android client based on Xray-core is available—"),e("a",Un,[t("AnXray"),n(o)]),t("! Maintained by "),e("a",In,[t("@nekohasekai"),n(o)]),t(".")]),e("ul",null,[Nn,e("li",null,[t("Chief visual designer "),e("a",Rn,[t("@RPRX"),n(o)]),t(" designed an X-style logo, slogan, and a unique black-and-white material theme.")]),En]),jn,e("h2",Wn,[e("a",Fn,[e("span",null,[t("2021.4.1 "),n(s,null,{default:a(()=>[e("a",Vn,[t("v1.4.2"),n(o)])]),_:1})])])]),Mn,e("h2",Gn,[e("a",Yn,[e("span",null,[t("2021.3.14 "),n(s,null,{default:a(()=>[e("a",On,[t("v1.4.0"),n(o)])]),_:1})])])]),Bn,e("h2",qn,[e("a",zn,[e("span",null,[t("2021.3.3 "),n(s,null,{default:a(()=>[e("a",Qn,[t("1.3.1"),n(o)])]),_:1})])])]),Kn,e("h2",Jn,[e("a",Zn,[e("span",null,[t("2021.2.14 "),n(s,null,{default:a(()=>[e("a",$n,[t("1.3.0"),n(o)])]),_:1})])])]),eo,e("h2",to,[e("a",no,[e("span",null,[t("2021.01.31 "),n(s,null,{default:a(()=>[e("a",oo,[t("1.2.4"),n(o)])]),_:1})])])]),ao,so,e("ul",null,[e("li",null,[t("Have you mastered the most detailed beginner's guide on the entire internet? 🍉 The teacher has started serializing "),n(l,{to:"/en/document/level-1/"},{default:a(()=>[t("Level One of the Guide")]),_:1}),t("...")]),ro]),e("h2",lo,[e("a",io,[e("span",null,[t("2021.01.22 "),n(s,null,{default:a(()=>[e("a",ho,[t("1.2.3"),n(o)])]),_:1})])])]),e("ul",null,[co,uo,_o,po,fo,e("li",null,[t("Salute to the big shot "),e("a",go,[t("@Bohan Yang"),n(o)]),t(" who discovers issues -> opens an issue -> tests on their own -> analyzes on their own -> finds the issue on their own -> fixes it on their own -> and then submits a PR upstream and downstream!")]),mo]),bo,e("ul",null,[e("li",null,[t("The hard work of translation has begun, thanks to "),e("a",vo,[t("@玖柒 Max"),n(o)]),t(" and all the other translation contributors.")]),e("li",null,[e("a",yo,[t("English version"),n(o)])])]),e("h2",wo,[e("a",To,[e("span",null,[t("2021.01.15 "),n(s,null,{default:a(()=>[e("a",ko,[t("1.2.2"),n(o)])]),_:1})])])]),xo,e("ul",null,[So,e("li",null,[t("The "),n(l,{to:"/en/document/level-0/"},{default:a(()=>[t("Simple White Language")]),_:1}),t(" by 🍉 teacher concludes with a grand finale, throwing flowers.")])]),e("h2",Xo,[e("a",Lo,[e("span",null,[t("2021.01.10 "),n(s,null,{default:a(()=>[e("a",Ao,[t("1.2.1"),n(o)])]),_:1})])])]),e("ul",null,[e("li",null,[t("The "),n(l,{to:"/en/document/level-0/"},{default:a(()=>[t("Simple White Language")]),_:1}),t(" series has been launched! 🍉 Teacher's painstaking work teaches you how to configure Xray from scratch!")]),Po,e("li",null,[n(l,{to:"/en/document/level-2/"},{default:a(()=>[t("Transparent Proxy")]),_:1}),t(" has also been updated with more articles.")]),Co,e("li",null,[t("Thanks to "),e("a",Do,[t("@ricuhkaen"),n(o)]),t(", "),e("a",Ho,[t("@BioniCosmos"),n(o)]),t(", "),e("a",Uo,[t("@kirin"),n(o)]),t(".")])]),Io,e("ul",null,[e("li",null,[t("The first PR in the documentation repository. 🎉 "),n(l,{to:"/en/document/level-2/tproxy.html"},{default:a(()=>[t("Transparent Proxy (TProxy) Configuration Tutorial")]),_:1}),t(", thanks to "),e("a",No,[t("@BioniCosmos"),n(o)]),t(".")]),Ro]),Eo,e("p",null,[t("[Happy New Year, Happy “Cow” Year!] 🎆🎇🎆 "),n(s,null,{default:a(()=>[e("a",jo,[t("1.2.0"),n(o)])]),_:1})]),Wo,e("ul",null,[Fo,e("li",null,[t("Xray will continue to move forward! Therefore, "),e("a",Vo,[t("Xray needs more heroes!!"),n(o)]),t("!")]),e("li",null,[t("PS: Please taste, taste every line of the "),e("a",Mo,[t("release notes"),n(o)]),t(" carefully. It seems there's a small secret Easter egg. "),Go])]),Yo,e("p",null,[t("Good news for gamers using transparent proxy! Xray-core TProxy inbound, SOCKS outbound UDP FullCone beta, "),e("a",Oo,[t("TG group"),n(o)]),t(" is hotly testing.")]),e("h2",Bo,[e("a",qo,[e("span",null,[t("2020.12.25 "),n(s,null,{default:a(()=>[e("a",zo,[t("1.1.5"),n(o)])]),_:1})])])]),Qo,e("ul",null,[Ko,Jo,Zo,$o,e("li",null,[t("Kirin brought a wave of script updates. "),e("a",ea,[t("Scripts here"),n(o)]),t(".")]),ta]),na,e("p",null,[t("For some unspeakable reasons, Xray’s documentation website was sneakily launched before the release date. The URL is: "),e("a",oa,[t("Yes, what you’re looking at"),n(o)]),t(".")]),aa,e("p",null,[t("The documentation website needs continuous improvement and content addition, as well as design refinement. Therefore, everyone is welcome to contribute to the construction of the documentation together. "),e("a",sa,[t("Documentation Repository"),n(o)]),t(".")]),ra,la,e("p",null,[t("Xray-core Shadowsocks UDP FullCone beta, "),e("a",ia,[t("TG group"),n(o)]),t(" is hotly testing.")]),ha,da,e("h2",ca,[e("a",ua,[e("span",null,[t("2020.12.18 "),n(s,null,{default:a(()=>[e("a",_a,[t("1.1.4"),n(o)])]),_:1})])])]),pa,fa,e("p",null,[t("Given the growing number of group members and gaming needs, the "),e("a",ga,[t("TG game group"),n(o)]),t(" has been launched.")]),ma,e("p",null,[e("a",ba,[t("Installation script dev branch"),n(o)]),t(" is now open and features are being continuously updated.")]),e("h2",va,[e("a",ya,[e("span",null,[t("2020.12.11 "),n(s,null,{default:a(()=>[e("a",wa,[t("1.1.3"),n(o)])]),_:1})])])]),Ta,e("h2",ka,[e("a",xa,[e("span",null,[t("2020.12.06 "),n(s,null,{default:a(()=>[e("a",Sa,[t("1.1.2"),n(o)])]),_:1})])])]),Xa,e("h2",La,[e("a",Aa,[e("span",null,[t("2020.11.25 "),n(s,null,{default:a(()=>[e("a",Pa,[t("1.0.0"),n(o)])]),_:1})])])]),Ca,Da,Ha,Ua,Ia])}const Wa=d(_,[["render",Na],["__file","news.html.vue"]]);export{Wa as default}; +import{_ as d,r as i,o as c,c as u,a as n,b as e,d as t,w as a,e as r}from"./app-D7uBbsY3.js";const _={},p=e("h1",{id:"the-great-chronicles",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#the-great-chronicles"},[e("span",null,"The Great Chronicles")])],-1),f=e("h2",{id:"_2024-9-12",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2024-9-12"},[e("span",null,"2024.9.12")])],-1),g=e("p",null,"The Great Chronicles Return to the Scene?!",-1),m={id:"_2024-9-7-v24-9-7",tabindex:"-1"},b={class:"header-anchor",href:"#_2024-9-7-v24-9-7"},v={href:"https://github.com/XTLS/Xray-core/releases/tag/v24.9.7",target:"_blank",rel:"noopener noreferrer"},y=e("p",null,"First release after abandoning semantic versioning.",-1),w=e("ul",null,[e("li",null,[t("This time, QUIC and DomainSocket transports were removed, along with two pieces of legacy code. "),e("ul",null,[e("li",null,"The binary size is 1MB smaller than v1.8.24.")])]),e("li",null,"As always, there are essential bug fixes.")],-1),T={id:"_2024-8-30-v1-8-24",tabindex:"-1"},k={class:"header-anchor",href:"#_2024-8-30-v1-8-24"},x={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.24",target:"_blank",rel:"noopener noreferrer"},S=r('

                                      While waiting for the SplitHTTP multiplex controller, the main branch had accumulated many important updates, so we decided to release a version first.

                                      • The Socks inbound now supports HTTP proxy requests by default.
                                      • UDP noise (preview)
                                      • And some other improvements.

                                      Due to the existence of semantic versioning, planning features and scheduling for each release have severely hindered the development, merging, and release of new features. Therefore, we decided to abandon semantic versioning starting with the next release and use the release date as the version number, such as v24.8.30, and cancel version planning, fully adopting continuous updates. Features will be merged and released as soon as they are ready, with a version released at the end of each month.

                                      After all, as a software aiming to help people bypass censorship, instead of maintaining a long-term stable version, it's more important to adapt new features and keep updating monthly.

                                      The next version will remove some legacy code no longer in used, add warning log for using deprecated features/configs, and for sure, some breaking changes. Be aware that future versions will be released once we consider something new is ready for a release.

                                      We believe that with your donations and the reform of the release format, the Xray-core project will develop even better.

                                      2024.8.26

                                      The Project VLESS group was established.

                                      ',8),X={href:"https://t.me/projectVless",target:"_blank",rel:"noopener noreferrer"},L=e("h2",{id:"_2024-8-3",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2024-8-3"},[e("span",null,"2024.8.3")])],-1),A={href:"https://github.com/XTLS/Xray-core/discussions/3633#discussioncomment-10240940",target:"_blank",rel:"noopener noreferrer"},P={id:"_2024-7-29-v1-8-23",tabindex:"-1"},C={class:"header-anchor",href:"#_2024-7-29-v1-8-23"},D={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.23",target:"_blank",rel:"noopener noreferrer"},H={href:"https://github.com/mmmray",target:"_blank",rel:"noopener noreferrer"},U=e("li",null,"Optimized the stability of SplitHTTP upstream, and the server must be upgraded to this version to support the new client.",-1),I=e("li",null,"More changes on SplitHTTP.",-1),N={id:"_2024-7-22-v1-8-21",tabindex:"-1"},R={class:"header-anchor",href:"#_2024-7-22-v1-8-21"},E={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.21",target:"_blank",rel:"noopener noreferrer"},j=e("p",null,"It seems to have returned to the original state of rapid-fire releases...",-1),W=e("p",null,"As foreshadowed in v1.8.16, SplitHTTP now preliminarily supports HTTP/3 (QUIC). Undoubtedly, SplitHTTP H3 has ushered in a new era.",-1),F=e("ul",null,[e("li",null,"SplitHTTP H3 is the first QUIC-based proxy fully compliant with standard H3, supporting CDN passthrough, and can be concealed using reverse proxy or Browser Dialer.")],-1),V=e("h2",{id:"_2024-7-16",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2024-7-16"},[e("span",null,"2024.7.16")])],-1),M={href:"https://github.com/iambabyninja",target:"_blank",rel:"noopener noreferrer"},G=e("blockquote",null,[e("p",null,"Привет, друзья из России!")],-1),Y=e("h2",{id:"_2024-7-15",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2024-7-15"},[e("span",null,"2024.7.15")])],-1),O=e("p",null,"Although Windows 7 will eventually be phased out with future upgrades, we can now delay that time a little.",-1),B={id:"_2024-6-18-v1-8-16",tabindex:"-1"},q={class:"header-anchor",href:"#_2024-6-18-v1-8-16"},z={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.16",target:"_blank",rel:"noopener noreferrer"},Q=e("p",null,"A new transport has arrived, currently called SplitHTTP.",-1),K=e("ul",null,[e("li",null,"There are two completely opposite ways to achieve further traffic obfuscation: multiplexing and splitting connections."),e("li",null,"It can achieve the same goals as Meek through CDNs that do not support WebSocket or gRPC, and SplitHTTP is simpler and more efficient than Meek."),e("li",null,"SplitHTTP does not have WebSocket's ALPN issues, which is a major advantage, and it will support HTTP/3 (QUIC) in the future."),e("li",null,"SplitHTTP has also been added to the sharing link package.")],-1),J=e("h2",{id:"_2024-6-2",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2024-6-2"},[e("span",null,"2024.6.2")])],-1),Z=e("p",null,"A new transport method is being developed...",-1),$={id:"_2024-4-26-v1-8-11",tabindex:"-1"},ee={class:"header-anchor",href:"#_2024-4-26-v1-8-11"},te={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.11",target:"_blank",rel:"noopener noreferrer"},ne=e("ul",null,[e("li",null,"Now there is a tool to generate ECH keys."),e("li",null,"Enhancements, fixes, and some obsolete code removal.")],-1),oe=e("h2",{id:"_2024-4-20",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2024-4-20"},[e("span",null,"2024.4.20")])],-1),ae={href:"https://github.com/Fangliding",target:"_blank",rel:"noopener noreferrer"},se=e("h2",{id:"_2024-4-13",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2024-4-13"},[e("span",null,"2024.4.13")])],-1),re=e("p",null,"VLESS Seed is ready, waiting for the right moment.",-1),le={id:"_2024-3-18-v1-8-10",tabindex:"-1"},ie={class:"header-anchor",href:"#_2024-3-18-v1-8-10"},he={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.10",target:"_blank",rel:"noopener noreferrer"},de=e("p",null,"Like WebSocket, HTTPUpgrade now also has 0-RTT.",-1),ce={id:"_2024-3-11-v1-8-9",tabindex:"-1"},ue={class:"header-anchor",href:"#_2024-3-11-v1-8-9"},_e={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.9",target:"_blank",rel:"noopener noreferrer"},pe=e("p",null,"Added HTTPUpgrade transport, said to be lighter than WebSocket.",-1),fe=e("ul",null,[e("li",null,"Already added to the sharing link package.")],-1),ge=e("h2",{id:"_2024-2-29",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2024-2-29"},[e("span",null,"2024.2.29")])],-1),me=e("p",null,[t("gRPC transport now also has a Host-like configuration field! It's called "),e("code",null,"authority"),t('. Now gRPC can also "domain front," without ALPN issues.')],-1),be={id:"_2024-2-25-v1-8-8",tabindex:"-1"},ve={class:"header-anchor",href:"#_2024-2-25-v1-8-8"},ye={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.8",target:"_blank",rel:"noopener noreferrer"},we=e("ul",null,[e("li",null,"Now XUDP traffic is uniformly padded with Vision, come and experience it."),e("li",null,"Added leastLoad balancer."),e("li",null,"Fixed errors, optimized performance...")],-1),Te=e("h2",{id:"_2024-1-9",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2024-1-9"},[e("span",null,"2024.1.9")])],-1),ke=e("p",null,"Shocked to hear that Win7 cannot run the new version of Xray-core? Upon exploration, it was discovered that Go has dropped support for Win7. Is there a way to continue supporting this somewhat ancient but still elegant operating system?",-1),xe=e("h2",{id:"_2023-11-21",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2023-11-21"},[e("span",null,"2023.11.21")])],-1),Se={href:"https://t.me/projectXtls/212",target:"_blank",rel:"noopener noreferrer"},Xe={id:"_2023-11-18-v1-8-6",tabindex:"-1"},Le={class:"header-anchor",href:"#_2023-11-18-v1-8-6"},Ae={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.6",target:"_blank",rel:"noopener noreferrer"},Pe=r('
                                      • WireGuard now also has a corresponding inbound. Freedom outbound finally has splice.
                                      • The domainStrategy for outbound has also been unified.
                                      • More delicious little treats.
                                      • Due to force majeure feature changes, Dragonfly BSD support has quietly left the stage.
                                      • Are we really saying goodbye to the classic Windows 7?

                                      2023.9.30

                                      Designed a brand new color scheme for v2rayNG, install the latest Pre-release version to experience it.

                                      ',3),Ce={id:"_2023-8-29-v1-8-4",tabindex:"-1"},De={class:"header-anchor",href:"#_2023-8-29-v1-8-4"},He={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.4",target:"_blank",rel:"noopener noreferrer"},Ue=r('

                                      After half a year of polishing, 1.8.x has finally reached its first recognized official version. Likewise, there are many integrated improvements this time, come and taste it!

                                      2023.7.22

                                      Another historical HTTP/2 transport issue has been fixed.

                                      2023.7.7

                                      Vision will soon have Seed support.

                                      2023.6.30

                                      The next XTLS flow control: xtls-rprx-switch 🍪

                                      • XTLS's 0-RTT has been teased for months, originally to maintain some mystery.
                                      • Compared to the existing XTLS Vision and Mux, it has even better advantages.

                                      2023.6.27

                                      ',9),Ie={href:"https://github.com/XTLS/Xray-core/discussions/2256#discussioncomment-6295296",target:"_blank",rel:"noopener noreferrer"},Ne={id:"_2023-6-19-v1-8-3",tabindex:"-1"},Re={class:"header-anchor",href:"#_2023-6-19-v1-8-3"},Ee={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.3",target:"_blank",rel:"noopener noreferrer"},je=r('
                                      • The first version after the code streamlining plan, VMess (MD5), MTProto, and Starlark-related code have been removed. Going light.
                                      • Code refactoring is also part of going light.
                                      • We have also not forgotten to add some enhancements and fix vulnerabilities.
                                      • v2rayNG has not yet supported Xray, and the new sharing link format cannot be used yet.

                                      2023.6.6

                                      Good News: The next XTLS flow control will not be called Vision. 🍪

                                      2023.4.21

                                      ',4),We={href:"https://github.com/XTLS/RealiTLScanner",target:"_blank",rel:"noopener noreferrer"},Fe=e("h2",{id:"_2023-4-20",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2023-4-20"},[e("span",null,"2023.4.20")])],-1),Ve={href:"https://github.com/XTLS/Xray-core/discussions/1967",target:"_blank",rel:"noopener noreferrer"},Me=e("h2",{id:"_2023-4-19",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2023-4-19"},[e("span",null,"2023.4.19")])],-1),Ge=e("p",null,[e("code",null,"xtls-0rtt-vision(-udp443)"),t(" 🍪")],-1),Ye={id:"_2023-4-18-v1-8-1",tabindex:"-1"},Oe={class:"header-anchor",href:"#_2023-4-18-v1-8-1"},Be={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.1",target:"_blank",rel:"noopener noreferrer"},qe=r('

                                      The upgraded XUDP is here!

                                      • Now XUDP features connection migration and port reuse, with a global Session ID , so mom doesn't have to worry about what to do when there is an unexpected disconnection anymore.
                                      • We’ve also added control settings for XUDP, giving you better control~
                                      • The new XUDP paired with XTLS Vision offers an even better experience~
                                      • As usual, there’s a little treat, enjoy~

                                      2023.4.6

                                      XUDP is also quietly upgrading...

                                      2023.3.29

                                      PLUX protocol 🍪

                                      2023.3.19

                                      The sharing link standard for REALITY has also emerged.

                                      ',8),ze={id:"_2023-3-9-v1-8-0",tabindex:"-1"},Qe={class:"header-anchor",href:"#_2023-3-9-v1-8-0"},Ke={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.0",target:"_blank",rel:"noopener noreferrer"},Je=r('

                                      THE NEXT FUTURE, REALITY is NOW release on Xray-core

                                      REALITY has been implemented and released! Welcome to try it out! XTLS Vision has also been improved, please upgrade both ends to the latest version for the best experience.

                                      • Due to changes in the Vision padding algorithm, there may be compatibility issues between old and new versions of XTLS Vision.
                                      • HTTP/2 transport has also been improved, enjoy the smooth experience with the new version~
                                      • There are many other small improvements, feel free to explore~

                                      2023.3.4

                                      Legends never die, they become a part of you VLESS.

                                      They simply fade away.

                                      2023.3.2

                                      Some lingering issues with HTTP/2 transport have been improved. Enjoy the smooth experience when testing with REALITY~

                                      2023.2.16

                                      THE NEXT FUTURE becomes THE REALITY NOW!

                                      2023.2.9

                                      REALITY is reality now!

                                      ',11),Ze={id:"_2023-2-8-v1-7-5",tabindex:"-1"},$e={class:"header-anchor",href:"#_2023-2-8-v1-7-5"},et={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.7.5",target:"_blank",rel:"noopener noreferrer"},tt=e("p",null,"Keep riding and never look back.",-1),nt={href:"https://github.com/yuhan6665",target:"_blank",rel:"noopener noreferrer"},ot=e("li",null,"XTLS Vision flow control is nearly complete and will soon be practical.",-1),at=e("li",null,"Now there are more options for uTLS fingerprint simulation, which one suits you?",-1),st=e("li",null,"Sharing links now also support sharing uTLS fingerprint configurations.",-1),rt=e("li",null,"There are more feature enhancements and fixes.",-1),lt=e("li",null,[t("This version will also be the last time to see XTLS Origin, Direct, and Splice flow control. "),e("s",null,"A bit nostalgic, isn’t it?")],-1),it=e("h2",{id:"_2023-1-29",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2023-1-29"},[e("span",null,"2023.1.29")])],-1),ht=e("p",null,"Winter cannot cover the NEXT FUTURE...",-1),dt={id:"_2022-12-26-v1-7-0",tabindex:"-1"},ct={class:"header-anchor",href:"#_2022-12-26-v1-7-0"},ut={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.7.0",target:"_blank",rel:"noopener noreferrer"},_t=e("p",null,"Due to a slip of the hand, this version number jumped directly up, thanks for everyone's support!",-1),pt=e("ul",null,[e("li",null,"From now on, Semantic Versioning will be strictly followed.")],-1),ft={id:"_2022-11-28-v1-6-5",tabindex:"-1"},gt={class:"header-anchor",href:"#_2022-11-28-v1-6-5"},mt={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.6.5",target:"_blank",rel:"noopener noreferrer"},bt=e("p",null,"This time we have WireGuard outbound.",-1),vt=e("ul",null,[e("li",null,"Using WireGuard with CF WARP can unlock some fun new ways to play."),e("li",null,"Of course, there are also security updates and fixes.")],-1),yt={id:"_2022-11-7-v1-6-3",tabindex:"-1"},wt={class:"header-anchor",href:"#_2022-11-7-v1-6-3"},Tt={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.6.3",target:"_blank",rel:"noopener noreferrer"},kt=e("p",null,[t("Now Vision flow control can also use uTLS fingerprint simulation, is this the benefit brought by "),e("code",null,"tlsSettings"),t("!")],-1),xt={id:"_2022-10-29-v1-6-2",tabindex:"-1"},St={class:"header-anchor",href:"#_2022-10-29-v1-6-2"},Xt={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.6.2",target:"_blank",rel:"noopener noreferrer"},Lt=e("p",null,"The first release with Vision flow control is out! Welcome to try it and give feedback!",-1),At={id:"_2022-10-22-v1-6-1",tabindex:"-1"},Pt={class:"header-anchor",href:"#_2022-10-22-v1-6-1"},Ct={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.6.1",target:"_blank",rel:"noopener noreferrer"},Dt=r('
                                      • Brought uTLS fingerprint support for WebSocket, HTTP/2, and gRPC transport!
                                        • The option that was previously only available under regular TLS for TCP transport is now better.
                                      • On Linux, TCP congestion control can be set independently for ingress and egress.

                                      2022.10.3

                                      The weather is getting cooler, but the pace of development hasn’t slowed down. Blocks fall from the sky, but progress can’t be stopped...

                                      • A new XTLS flow control is brewing...
                                        • Addressing existing flow control issues;
                                        • Direct splice activation for TLS 1.3;
                                        • Added TLS handshake length obfuscation;
                                        • Simplified code, using tlsSettings instead of xtlsSettings...
                                      ',4),Ht={id:"_2022-8-28-v1-5-10",tabindex:"-1"},Ut={class:"header-anchor",href:"#_2022-8-28-v1-5-10"},It={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.5.10",target:"_blank",rel:"noopener noreferrer"},Nt=e("p",null,"Underlying transport now supports more reasonable TCP Keepalive settings.",-1),Rt={id:"_2022-6-20-v1-5-8",tabindex:"-1"},Et={class:"header-anchor",href:"#_2022-6-20-v1-5-8"},jt={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.5.8",target:"_blank",rel:"noopener noreferrer"},Wt=e("p",null,"Now Shadowsocks-2022 relay is also supported.",-1),Ft={id:"_2022-5-29-v1-5-6",tabindex:"-1"},Vt={class:"header-anchor",href:"#_2022-5-29-v1-5-6"},Mt={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.5.6",target:"_blank",rel:"noopener noreferrer"},Gt=e("p",null,"Shadowsocks-2022 protocol has come to Xray-core!",-1),Yt={href:"https://github.com/nekohasekai",target:"_blank",rel:"noopener noreferrer"},Ot={href:"https://github.com/database64128",target:"_blank",rel:"noopener noreferrer"},Bt={href:"https://github.com/RPRX",target:"_blank",rel:"noopener noreferrer"},qt=e("p",null,"Shadowsocks-2022 is a newly designed protocol:",-1),zt=e("ul",null,[e("li",null,"It addresses security issues like replay attacks while retaining native udp support from Shadowsocks (using timestamps similar to vmess, so client and server need synchronized time)."),e("li",null,"Supports multi-user on a single port, and implements session mechanisms similar to quic and wireguard to reduce encryption overhead and ensure seamless migration during network changes.")],-1),Qt={id:"_2022-4-24-v1-5-5",tabindex:"-1"},Kt={class:"header-anchor",href:"#_2022-4-24-v1-5-5"},Jt={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.5.5",target:"_blank",rel:"noopener noreferrer"},Zt=e("p",null,"This time we brought a convenient visual data detection interface! Come and experience it!",-1),$t=e("ul",null,[e("li",null,"We also fixed some issues affecting user experience.")],-1),en={id:"_2022-3-13-v1-5-4",tabindex:"-1"},tn={class:"header-anchor",href:"#_2022-3-13-v1-5-4"},nn={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.5.4",target:"_blank",rel:"noopener noreferrer"},on=e("p",null,"Added a wxray.exe file for Windows platform with no black windows popping up, and brought enhancements for UDS listening.",-1),an={id:"_2022-1-29-v1-5-3",tabindex:"-1"},sn={class:"header-anchor",href:"#_2022-1-29-v1-5-3"},rn={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.5.3",target:"_blank",rel:"noopener noreferrer"},ln=e("p",null,"Farewell to the year of the Ox, and leap into the new year of the Tiger. 🧨",-1),hn=e("ul",null,[e("li",null,"This time we brought improvements to stream allocation for QUIC transport, making QUIC transport smoother.")],-1),dn={id:"_2021-12-24-v1-5-2",tabindex:"-1"},cn={class:"header-anchor",href:"#_2021-12-24-v1-5-2"},un={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.5.2",target:"_blank",rel:"noopener noreferrer"},_n=e("p",null,"Added a new option for gRPC, making it even better when used through a CDN.",-1),pn={id:"_2021-12-15-v1-5-1",tabindex:"-1"},fn={class:"header-anchor",href:"#_2021-12-15-v1-5-1"},gn={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.5.1",target:"_blank",rel:"noopener noreferrer"},mn=e("blockquote",null,[e("p",null,"“A transitional, phased maintenance version”")],-1),bn=e("ul",null,[e("li",null,"New features, enhancements, and a lot of fixes are coming in."),e("li",null,[t("Remember to remove "),e("code",null,"alterID"),t(" from your VMess configuration!")])],-1),vn={id:"_2021-10-20-v1-5-0",tabindex:"-1"},yn={class:"header-anchor",href:"#_2021-10-20-v1-5-0"},wn={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.5.0",target:"_blank",rel:"noopener noreferrer"},Tn=e("p",null,"A really big change!",-1),kn=e("ul",null,[e("li",null,"Refactored the DNS component, with more supported protocols and detailed configurations."),e("li",null,"Enhanced gRPC transport and FakeDNS."),e("li",null,"Finally supports Windows ARM64."),e("li",null,"More new features and improvements await you.")],-1),xn={id:"_2021-9-23-v1-4-5",tabindex:"-1"},Sn={class:"header-anchor",href:"#_2021-9-23-v1-4-5"},Xn={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.4.5",target:"_blank",rel:"noopener noreferrer"},Ln=r('

                                      Happy Mid-Autumn Festival, wishing you a joyful reunion.

                                      • Fixed a bug where the version number was too low and unlucky.
                                      • This update removed the insecure encryption methods from Shadowsocks. Please migrate to AEAD encryption as soon as possible.
                                      • This update fixed a longstanding issue from ancient times: enabling traffic statistics could cause a performance drop. Simply put, enabling statistics now will not impact performance regardless of the configuration.
                                      • Also included are security updates for XTLS and numerous other fixes.
                                      • By the way, due to the TLS library update, cipherSuites can no longer specify the order of cipher suites, and preferServerCipherSuites has been completely deprecated. In fact, these changes were already present in Xray-core v1.4.3.

                                      2021.9.16

                                      ',3),An={href:"https://xtls.github.io/",target:"_blank",rel:"noopener noreferrer"},Pn={id:"_2021-9-8-v1-4-3",tabindex:"-1"},Cn={class:"header-anchor",href:"#_2021-9-8-v1-4-3"},Dn={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.4.3",target:"_blank",rel:"noopener noreferrer"},Hn=r('

                                      This is a maintenance release. Development continues…

                                      • A large number of improvements and new features have accumulated during this period.
                                      • Added a new DomainMatcher, improving domain rule matching performance.
                                      • Added health checks for HTTP/2 and gRPC transports, improved handling of unknown SNI, and fixed a bunch of bugs.

                                      Helden sterben nicht!

                                      2021.7.14

                                      • AnXray's expensively designed new icon is now live!
                                        • The new icon is now more recognizable.
                                      • Over the past three weeks, AnXray has accumulated 600 stars, 2K+ channel subscriptions, and 11K+ GitHub downloads. Thank you for your support.
                                      • AX is short for AnXray. We recommend using AX to refer to AnXray—it's short and convenient.

                                      2021.6.21

                                      ',6),Un={href:"https://github.com/XTLS/AnXray",target:"_blank",rel:"noopener noreferrer"},In={href:"https://github.com/nekohasekai",target:"_blank",rel:"noopener noreferrer"},Nn=e("li",null,"Supports numerous protocols and plugins.",-1),Rn={href:"https://github.com/RPRX",target:"_blank",rel:"noopener noreferrer"},En=e("li",null,"There's also a small Easter egg waiting to be discovered in the app.",-1),jn=r('

                                      Spent the last few days refining details from morning till night. We hope you'll star and follow the project.

                                      2021.5.1

                                      Improvements to tun2socks have appeared in v2rayNG.

                                      2021.4.26

                                      Brought an improvement to tun2socks. You might get to enjoy it in the future~

                                      2021.4.12

                                      Let's foresee X-flutter; looking forward to what it might be like~ 🍪

                                      2021.4.6

                                      • VuePress Next.
                                      • With Dark Mode.

                                      2021.4.4

                                      • This document has a new homepage.
                                      • This document now has a dark mode.
                                      • Of course, dark mode still has various issues. Specific content will need to be gradually adjusted.
                                      • Additionally, the Telegram group chat has surpassed 5,000 members! An Anti-Spam bot has also been added!
                                      • 🎉🎉🎉
                                      ',11),Wn={id:"_2021-4-1-v1-4-2",tabindex:"-1"},Fn={class:"header-anchor",href:"#_2021-4-1-v1-4-2"},Vn={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.4.2",target:"_blank",rel:"noopener noreferrer"},Mn=r('
                                      • Not an April Fool's joke, updated today.
                                      • Added Browser Dialer to modify TLS fingerprints and behavior.
                                      • Added uTLS to modify the TLS Client Hello fingerprint.
                                      • Also fixed a bunch of strange issues; see the changelog for details.

                                      2021.3.25

                                      Yes, it’s still changing. -_-

                                      2021.3.15

                                      The documentation site is quietly undergoing some mysterious changes..., 🙊🙊🙊

                                      ',5),Gn={id:"_2021-3-14-v1-4-0",tabindex:"-1"},Yn={class:"header-anchor",href:"#_2021-3-14-v1-4-0"},On={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.4.0",target:"_blank",rel:"noopener noreferrer"},Bn=r("
                                      • Happy Pi-Day!
                                      • This is a major update:
                                        • Introduced transport layer support for chained proxies.
                                        • Introduced Domain Strategy for the Dialer, solving strange DNS issues.
                                        • Added gRPC transport method and a slightly faster Multi Mode.
                                        • Added WebSocket Early-Data feature, reducing WebSocket latency.
                                        • Added FakeDNS.
                                        • Also fixed a series of issues and added various features. For details, see the changelog.
                                      • VuePress is still more enjoyable~
                                      ",1),qn={id:"_2021-3-3-1-3-1",tabindex:"-1"},zn={class:"header-anchor",href:"#_2021-3-3-1-3-1"},Qn={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.3.1",target:"_blank",rel:"noopener noreferrer"},Kn=e("ul",null,[e("li",null,"This version uses Golang 1.16, officially supporting Apple Silicon natively."),e("li",null,[t("Also fixed a bug that could cause a panic. "),e("s",null,"Holmium_ thinks this is deceit, a sneak attack.")]),e("li",null,"Fixed several legacy issues.")],-1),Jn={id:"_2021-2-14-1-3-0",tabindex:"-1"},Zn={class:"header-anchor",href:"#_2021-2-14-1-3-0"},$n={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.3.0",target:"_blank",rel:"noopener noreferrer"},eo=e("ul",null,[e("li",null,"Happy 🐮 Year 🎉!"),e("li",null,"v1.3.0 implemented FullCone for all V protocols using a very clever mechanism, while ensuring some compatibility."),e("li",null,"OHHHHHHHHHHHH!")],-1),to={id:"_2021-01-31-1-2-4",tabindex:"-1"},no={class:"header-anchor",href:"#_2021-01-31-1-2-4"},oo={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.2.4",target:"_blank",rel:"noopener noreferrer"},ao=e("ul",null,[e("li",null,"Resolved two longstanding issues where “connecting to a standard Socks server might result in errors.”"),e("li",null,"It seems there’s not much change in this version, but it’s just the calm before the storm."),e("li",null,[t("(Yes, I’m a prophet) "),e("blockquote",null,[e("p",null,"You fool, you’re holding a UNO card.")])])],-1),so=e("h2",{id:"_2021-01-25",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2021-01-25"},[e("span",null,"2021.01.25")])],-1),ro=e("li",null,[t("The "),e("a",{href:"../en"},"English version of the documentation site"),t(" is gradually being updated, thanks to the hard work of everyone involved!")],-1),lo={id:"_2021-01-22-1-2-3",tabindex:"-1"},io={class:"header-anchor",href:"#_2021-01-22-1-2-3"},ho={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.2.3",target:"_blank",rel:"noopener noreferrer"},co=e("li",null,[e("strong",null,"Yet again"),t(", support for the SS protocol has been strengthened, now supporting multi-user on a single port!")],-1),uo=e("li",null,[e("strong",null,"Yet again"),t(", support for the trojan protocol has been strengthened, with new SNI-based routing for trojan fallback!")],-1),_o=e("li",null,[e("em",null,"(VLESS: sobbing)")],-1),po=e("li",null,"The weird UDP bugs have been fixed, making it “stable” in one word.",-1),fo=e("li",null,"Sniffing can now exclude domains you don't want to sniff, opening up some new possibilities.",-1),go={href:"https://github.com/bohanyang",target:"_blank",rel:"noopener noreferrer"},mo=e("li",null,"Other tasty cherries—just update and taste them.",-1),bo=r('

                                      2021.01.19

                                      • Some numbers:
                                        • 10 tags released
                                        • 100 issues resolved
                                        • 300 forks created
                                        • 2000 stars given
                                        • 3000 members in the group

                                      2021.01.17

                                      ',3),vo={href:"https://github.com/jiuqi9997",target:"_blank",rel:"noopener noreferrer"},yo={href:"https://xtls.github.io/en/",target:"_blank",rel:"noopener noreferrer"},wo={id:"_2021-01-15-1-2-2",tabindex:"-1"},To={class:"header-anchor",href:"#_2021-01-15-1-2-2"},ko={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.2.2",target:"_blank",rel:"noopener noreferrer"},xo=r('
                                      • Fallback routing has unlocked a new strange trick! You can now route based on SNI in the fallback!
                                      • The previously announced UUID modification is officially live. (Scroll down, scroll down)
                                      • The logs now look a bit more pleasing to the eye than last time.
                                      • Remote DOH has learned to use routing just like other DNS modes.
                                      • And of course, various other little candies. (Just update and taste them)
                                      • Oh, and, the first person to run Xray on an M1 Mac is Anthony TSE.

                                      2021.01.12

                                      ',2),So=e("li",null,[t("Upcoming UUID modification supports mapping between custom strings and UUIDs. This means you can write the id like this in the configuration file to correspond to users. "),e("ul",null,[e("li",null,[t("Client writes "),e("code",null,'"id": "I love 🍉 teacher 1314"'),t(",")]),e("li",null,[t("Server writes "),e("code",null,'"id": "5783a3e7-e373-51cd-8642-c83782b807c5"'),t(" (This UUID is the UUID mapping of "),e("code",null,"I love 🍉 teacher 1314"),t(")")])])],-1),Xo={id:"_2021-01-10-1-2-1",tabindex:"-1"},Lo={class:"header-anchor",href:"#_2021-01-10-1-2-1"},Ao={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.2.1",target:"_blank",rel:"noopener noreferrer"},Po=e("li",null,"(Possibly the most detailed and patient guide on the entire internet for configuring from zero)",-1),Co=e("li",null,"Many other details have been modified, and the documentation will become more standardized!",-1),Do={href:"https://github.com/ricuhkaen",target:"_blank",rel:"noopener noreferrer"},Ho={href:"https://github.com/BioniCosmos",target:"_blank",rel:"noopener noreferrer"},Uo={href:"https://github.com/kirin10000",target:"_blank",rel:"noopener noreferrer"},Io=r('
                                      • A lot of UDP-related fixes, now you can even play Rainbow Six Siege on Ubisoft's potato servers!
                                      • Google Voice should now work properly when making calls with v2rayNG.
                                      • Logs now look more pleasing to the eye.

                                      2021.01.07

                                      • Courtesy and respect should be fundamental principles that don’t need to be explicitly stated in the community.

                                      2021.01.05

                                      • The documentation website is quietly undergoing some mysterious changes..., 🙊🙊🙊

                                      2021.01.03

                                      ',6),No={href:"https://github.com/BioniCosmos",target:"_blank",rel:"noopener noreferrer"},Ro=e("li",null,"The TG group has surpassed 2500 members.",-1),Eo=e("h2",{id:"_2021-01-01",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2021-01-01"},[e("span",null,"2021.01.01")])],-1),jo={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.2.0",target:"_blank",rel:"noopener noreferrer"},Wo=e("p",null,"🎁 In the last few minutes of New Year's Day, v1.2.0 arrived, continuing the tradition of Friday updates, bringing the hard work of all contributors and the dark circles of @rprxx—living up to expectations!",-1),Fo=r('
                                    28. The New Year's gift 🎁 following the Christmas gift v1.1.5, a great benefit for gamers, full FullCone support.
                                    29. (UDP will continue to be enhanced!)
                                    30. If you’ve already opened your Christmas gift, this time there’s an even more beautifully wrapped package and little candies. (As always, no need to ask, just update and taste it)
                                    31. (No, what's below is not an ad, but a milestone.)
                                    32. Xray is the first unrestricted multi-protocol platform: Xray alone solves the problem, without relying on other implementations.
                                      • One person handles everything! Supports all major mainstream protocols!
                                      • Unparalleled performance!
                                      • Continuously improving features!
                                      • Incredible vitality and community affinity!
                                    33. ',5),Vo={href:"https://github.com/XTLS/Xray-core/discussions/56",target:"_blank",rel:"noopener noreferrer"},Mo={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.2.0",target:"_blank",rel:"noopener noreferrer"},Go=e("s",null,"(Ah, someone’s knocking at the door... I’ll tell you later)",-1),Yo=e("h2",{id:"_2020-12-29",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2020-12-29"},[e("span",null,"2020.12.29")])],-1),Oo={href:"https://t.me/projectXray",target:"_blank",rel:"noopener noreferrer"},Bo={id:"_2020-12-25-1-1-5",tabindex:"-1"},qo={class:"header-anchor",href:"#_2020-12-25-1-1-5"},zo={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.1.5",target:"_blank",rel:"noopener noreferrer"},Qo=e("p",null,"Merry Christmas!",-1),Ko=e("li",null,"A Christmas gift for gamers! You can now enjoy gaming with Xray! Thanks to SS/trojan UDP FullCone.",-1),Jo=e("li",null,"You can now write configuration files in your preferred format, such as YAML or TOML...",-1),Zo=e("li",null,"(VLESS’s UDP FullCone and more enhancements are coming soon!)",-1),$o=e("li",null,"No need to worry about certificate validation being blocked anymore, OCSP stapling is now online!",-1),ea={href:"https://github.com/XTLS/Xray-install",target:"_blank",rel:"noopener noreferrer"},ta=e("li",null,"And more delicious little cherries! (No need to ask, just update and taste it)",-1),na=e("h2",{id:"_2020-12-24",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2020-12-24"},[e("span",null,"2020.12.24")])],-1),oa={href:"https://xtls.github.io",target:"_blank",rel:"noopener noreferrer"},aa=e("p",null,"Everyone is welcome to check various contents and correct any errors/suggestions (can be submitted to the issue area of the documentation GitHub repository).",-1),sa={href:"https://github.com/XTLS/XTLS.github.io",target:"_blank",rel:"noopener noreferrer"},ra=e("p",null,"There’s a brief tutorial in the repository's README explaining how to help Xray improve the documentation website. Everyone is welcome to check it out, correct errors, modify, and add experiences.",-1),la=e("h2",{id:"_2020-12-23",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2020-12-23"},[e("span",null,"2020.12.23")])],-1),ia={href:"https://t.me/projectXray",target:"_blank",rel:"noopener noreferrer"},ha=e("h2",{id:"_2020-12-21",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2020-12-21"},[e("span",null,"2020.12.21")])],-1),da=e("ul",null,[e("li",null,"Project X group member count exceeds 2000."),e("li",null,"The group messages (including game groups) surpass 10,000 daily.")],-1),ca={id:"_2020-12-18-1-1-4",tabindex:"-1"},ua={class:"header-anchor",href:"#_2020-12-18-1-1-4"},_a={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.1.4",target:"_blank",rel:"noopener noreferrer"},pa=e("ul",null,[e("li",null,"Lower startup memory usage and memory usage optimization."),e("li",null,"Customize TLS at will to improve your SSL rating."),e("li",null,"Added Splice support for XTLS inbound and support for trojan XTLS."),e("li",null,"Also, best usage mode suggestions for Splice on your router.")],-1),fa=e("h2",{id:"_2020-12-17",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2020-12-17"},[e("span",null,"2020.12.17")])],-1),ga={href:"https://t.me/joinchat/UO4NixbB_XDQJOUjS6mHEQ",target:"_blank",rel:"noopener noreferrer"},ma=e("h2",{id:"_2020-12-15",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2020-12-15"},[e("span",null,"2020.12.15")])],-1),ba={href:"https://github.com/XTLS/Xray-install/tree/dev",target:"_blank",rel:"noopener noreferrer"},va={id:"_2020-12-11-1-1-3",tabindex:"-1"},ya={class:"header-anchor",href:"#_2020-12-11-1-1-3"},wa={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.1.3",target:"_blank",rel:"noopener noreferrer"},Ta=e("ul",null,[e("li",null,"Full version of REDIRECT transparent proxy mode."),e("li",null,"Optimization suggestions for Splice flow control mode on soft routers.")],-1),ka={id:"_2020-12-06-1-1-2",tabindex:"-1"},xa={class:"header-anchor",href:"#_2020-12-06-1-1-2"},Sa={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.1.2",target:"_blank",rel:"noopener noreferrer"},Xa=r('
                                      • Added splice mode for flow control, Linux exclusive, with unparalleled performance.
                                      • Enhanced API compatibility.

                                      2020.12.04

                                      Added splice mode.

                                      2020.11.27

                                      • Project X's GitHub main repository Xray-core has now received 500+ stars.
                                      • Featured on GitHub Trending.
                                      • Project X group members exceeded 1000, and channel subscribers reached 500+.
                                      ',5),La={id:"_2020-11-25-1-0-0",tabindex:"-1"},Aa={class:"header-anchor",href:"#_2020-11-25-1-0-0"},Pa={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.0.0",target:"_blank",rel:"noopener noreferrer"},Ca=e("p",null,"Xray’s first version.",-1),Da=e("ul",null,[e("li",null,"Based on v2ray-core with significant modifications."),e("li",null,"Comprehensive enhancements, excellent performance, fully compatible.")],-1),Ha=e("h2",{id:"_2020-11-23",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2020-11-23"},[e("span",null,"2020.11.23")])],-1),Ua=e("p",null,"project X start",-1),Ia=e("blockquote",null,[e("p",null,[e("s",null,"When the dream begins")])],-1);function Na(Ra,Ea){const h=i("I18nTip"),o=i("ExternalLinkIcon"),s=i("Badge"),l=i("RouterLink");return c(),u("div",null,[p,n(h),f,g,e("h2",m,[e("a",b,[e("span",null,[t("2024.9.7 "),n(s,null,{default:a(()=>[e("a",v,[t("v24.9.7"),n(o)])]),_:1})])])]),y,w,e("h2",T,[e("a",k,[e("span",null,[t("2024.8.30 "),n(s,null,{default:a(()=>[e("a",x,[t("v1.8.24"),n(o)])]),_:1})])])]),S,e("p",null,[t("We have created "),e("a",X,[t("Project VLESS"),n(o)]),t(" for non-Chinese users (mainly Russian).")]),L,e("p",null,[t("The first "),e("a",A,[t("Project X NFT"),n(o)]),t(" is officially released! Just as Xray has made history, releasing an NFT is also an unprecedented move in this field. These NFTs are highly commemorative and even historically significant, far beyond their current initial price. In time, they will undoubtedly become priceless. Once again, thank you for your support of Project X.")]),e("h2",P,[e("a",C,[e("span",null,[t("2024.7.29 "),n(s,null,{default:a(()=>[e("a",D,[t("v1.8.23"),n(o)])]),_:1})])])]),e("ul",null,[e("li",null,[t("Congratulations to "),e("a",H,[t("@mmmray"),n(o)]),t(" for contributing the 1000th commit to Xray-core!")]),U,I]),e("h2",N,[e("a",R,[e("span",null,[t("2024.7.22 "),n(s,null,{default:a(()=>[e("a",E,[t("v1.8.21"),n(o)])]),_:1})])])]),j,W,F,V,e("p",null,[t("Project X documentation now has a Russian version! Thanks to "),e("a",M,[t("@iambabyninja"),n(o)]),t(" for the translation!")]),G,Y,e("p",null,[t("Through known information and efforts, Xray-core now supports Windows 7 again! In subsequent releases, Windows 7 users can enjoy it by downloading and extracting the Xray-win7-32.zip or Xray-win7-64.zip packages. Thank you for your support! For specific usage, please click "),n(l,{to:"/en/document/install.html"},{default:a(()=>[t("here")]),_:1})]),O,e("h2",B,[e("a",q,[e("span",null,[t("2024.6.18 "),n(s,null,{default:a(()=>[e("a",z,[t("v1.8.16"),n(o)])]),_:1})])])]),Q,K,J,Z,e("h2",$,[e("a",ee,[e("span",null,[t("2024.4.26 "),n(s,null,{default:a(()=>[e("a",te,[t("v1.8.11"),n(o)])]),_:1})])])]),ne,oe,e("p",null,[t("We now have issue templates, thanks to "),e("a",ae,[t("@Fangliding"),n(o)]),t("!")]),se,re,e("h2",le,[e("a",ie,[e("span",null,[t("2024.3.18 "),n(s,null,{default:a(()=>[e("a",he,[t("v1.8.10"),n(o)])]),_:1})])])]),de,e("h2",ce,[e("a",ue,[e("span",null,[t("2024.3.11 "),n(s,null,{default:a(()=>[e("a",_e,[t("v1.8.9"),n(o)])]),_:1})])])]),pe,fe,ge,me,e("h2",be,[e("a",ve,[e("span",null,[t("2024.2.25 "),n(s,null,{default:a(()=>[e("a",ye,[t("v1.8.8"),n(o)])]),_:1})])])]),we,Te,ke,xe,e("p",null,[t("The "),e("a",Se,[t("paper"),n(o)]),t(" published at the USENIX top conference confirms that XTLS Vision has achieved its design goals. And XTLS will not stop there, breaking through towering walls like X-rays.")]),e("h2",Xe,[e("a",Le,[e("span",null,[t("2023.11.18 "),n(s,null,{default:a(()=>[e("a",Ae,[t("v1.8.6"),n(o)])]),_:1})])])]),Pe,e("h2",Ce,[e("a",De,[e("span",null,[t("2023.8.29 "),n(s,null,{default:a(()=>[e("a",He,[t("v1.8.4"),n(o)])]),_:1})])])]),Ue,e("p",null,[e("a",Ie,[t("How to choose a REALITY target domain? Check here to help you achieve twice the result with half the effort!"),n(o)])]),e("h2",Ne,[e("a",Re,[e("span",null,[t("2023.6.19 "),n(s,null,{default:a(()=>[e("a",Ee,[t("v1.8.3"),n(o)])]),_:1})])])]),je,e("p",null,[t("Maybe we can leverage "),e("a",We,[t("RealiTLScanner"),n(o)]),t("……")]),Fe,e("p",null,[t("After years of development and countless lines of code... "),e("a",Ve,[t("The code simplification plan"),n(o)]),t(" has been proposed!")]),Me,Ge,e("h2",Ye,[e("a",Oe,[e("span",null,[t("2023.4.18 "),n(s,null,{default:a(()=>[e("a",Be,[t("v1.8.1"),n(o)])]),_:1})])])]),qe,e("h2",ze,[e("a",Qe,[e("span",null,[t("2023.3.9 "),n(s,null,{default:a(()=>[e("a",Ke,[t("v1.8.0"),n(o)])]),_:1})])])]),Je,e("h2",Ze,[e("a",$e,[e("span",null,[t("2023.2.8 "),n(s,null,{default:a(()=>[e("a",et,[t("v1.7.5"),n(o)])]),_:1})])])]),tt,e("ul",null,[e("li",null,[t("Congratulations to "),e("a",nt,[t("@yuhan6665"),n(o)]),t(" for contributing the 500th commit to Xray-core!")]),ot,at,st,rt,lt]),it,ht,e("h2",dt,[e("a",ct,[e("span",null,[t("2022.12.26 "),n(s,null,{default:a(()=>[e("a",ut,[t("v1.7.0"),n(o)])]),_:1})])])]),_t,pt,e("h2",ft,[e("a",gt,[e("span",null,[t("2022.11.28 "),n(s,null,{default:a(()=>[e("a",mt,[t("v1.6.5"),n(o)])]),_:1})])])]),bt,vt,e("h2",yt,[e("a",wt,[e("span",null,[t("2022.11.7 "),n(s,null,{default:a(()=>[e("a",Tt,[t("v1.6.3"),n(o)])]),_:1})])])]),kt,e("h2",xt,[e("a",St,[e("span",null,[t("2022.10.29 "),n(s,null,{default:a(()=>[e("a",Xt,[t("v1.6.2"),n(o)])]),_:1})])])]),Lt,e("h2",At,[e("a",Pt,[e("span",null,[t("2022.10.22 "),n(s,null,{default:a(()=>[e("a",Ct,[t("v1.6.1"),n(o)])]),_:1})])])]),Dt,e("h2",Ht,[e("a",Ut,[e("span",null,[t("2022.8.28 "),n(s,null,{default:a(()=>[e("a",It,[t("v1.5.10"),n(o)])]),_:1})])])]),Nt,e("h2",Rt,[e("a",Et,[e("span",null,[t("2022.6.20 "),n(s,null,{default:a(()=>[e("a",jt,[t("v1.5.8"),n(o)])]),_:1})])])]),Wt,e("h2",Ft,[e("a",Vt,[e("span",null,[t("2022.5.29 "),n(s,null,{default:a(()=>[e("a",Mt,[t("v1.5.6"),n(o)])]),_:1})])])]),Gt,e("ul",null,[e("li",null,[t("Thanks to "),e("a",Yt,[t("@nekohasekai"),n(o)]),t(" for developing the brand new go implementation https://github.com/SagerNet/sing-shadowsocks and bringing it to Xray.")]),e("li",null,[t("Thanks to "),e("a",Ot,[t("@database64128"),n(o)]),t(" for driving the Shadowsocks community to propose a complete design.")]),e("li",null,[t("Thanks to "),e("a",Bt,[t("@RPRX"),n(o)]),t(" for submitting the original vulnerability.")])]),qt,zt,e("h2",Qt,[e("a",Kt,[e("span",null,[t("2022.4.24 "),n(s,null,{default:a(()=>[e("a",Jt,[t("v1.5.5"),n(o)])]),_:1})])])]),Zt,$t,e("h2",en,[e("a",tn,[e("span",null,[t("2022.3.13 "),n(s,null,{default:a(()=>[e("a",nn,[t("v1.5.4"),n(o)])]),_:1})])])]),on,e("h2",an,[e("a",sn,[e("span",null,[t("2022.1.29 "),n(s,null,{default:a(()=>[e("a",rn,[t("v1.5.3"),n(o)])]),_:1})])])]),ln,hn,e("h2",dn,[e("a",cn,[e("span",null,[t("2021.12.24 "),n(s,null,{default:a(()=>[e("a",un,[t("v1.5.2"),n(o)])]),_:1})])])]),_n,e("h2",pn,[e("a",fn,[e("span",null,[t("2021.12.15 "),n(s,null,{default:a(()=>[e("a",gn,[t("v1.5.1"),n(o)])]),_:1})])])]),mn,bn,e("h2",vn,[e("a",yn,[e("span",null,[t("2021.10.20 "),n(s,null,{default:a(()=>[e("a",wn,[t("v1.5.0"),n(o)])]),_:1})])])]),Tn,kn,e("h2",xn,[e("a",Sn,[e("span",null,[t("2021.9.23 "),n(s,null,{default:a(()=>[e("a",Xn,[t("v1.4.5"),n(o)])]),_:1})])])]),Ln,e("ul",null,[e("li",null,[t("The documentation site has fully transitioned to docs-next, providing a smoother and better experience! The address remains "),e("a",An,[t("https://xtls.github.io/"),n(o)]),t(".")])]),e("h2",Pn,[e("a",Cn,[e("span",null,[t("2021.9.8 "),n(s,null,{default:a(()=>[e("a",Dn,[t("v1.4.3"),n(o)])]),_:1})])])]),Hn,e("p",null,[t("Now, an open-source, free Android client based on Xray-core is available—"),e("a",Un,[t("AnXray"),n(o)]),t("! Maintained by "),e("a",In,[t("@nekohasekai"),n(o)]),t(".")]),e("ul",null,[Nn,e("li",null,[t("Chief visual designer "),e("a",Rn,[t("@RPRX"),n(o)]),t(" designed an X-style logo, slogan, and a unique black-and-white material theme.")]),En]),jn,e("h2",Wn,[e("a",Fn,[e("span",null,[t("2021.4.1 "),n(s,null,{default:a(()=>[e("a",Vn,[t("v1.4.2"),n(o)])]),_:1})])])]),Mn,e("h2",Gn,[e("a",Yn,[e("span",null,[t("2021.3.14 "),n(s,null,{default:a(()=>[e("a",On,[t("v1.4.0"),n(o)])]),_:1})])])]),Bn,e("h2",qn,[e("a",zn,[e("span",null,[t("2021.3.3 "),n(s,null,{default:a(()=>[e("a",Qn,[t("1.3.1"),n(o)])]),_:1})])])]),Kn,e("h2",Jn,[e("a",Zn,[e("span",null,[t("2021.2.14 "),n(s,null,{default:a(()=>[e("a",$n,[t("1.3.0"),n(o)])]),_:1})])])]),eo,e("h2",to,[e("a",no,[e("span",null,[t("2021.01.31 "),n(s,null,{default:a(()=>[e("a",oo,[t("1.2.4"),n(o)])]),_:1})])])]),ao,so,e("ul",null,[e("li",null,[t("Have you mastered the most detailed beginner's guide on the entire internet? 🍉 The teacher has started serializing "),n(l,{to:"/en/document/level-1/"},{default:a(()=>[t("Level One of the Guide")]),_:1}),t("...")]),ro]),e("h2",lo,[e("a",io,[e("span",null,[t("2021.01.22 "),n(s,null,{default:a(()=>[e("a",ho,[t("1.2.3"),n(o)])]),_:1})])])]),e("ul",null,[co,uo,_o,po,fo,e("li",null,[t("Salute to the big shot "),e("a",go,[t("@Bohan Yang"),n(o)]),t(" who discovers issues -> opens an issue -> tests on their own -> analyzes on their own -> finds the issue on their own -> fixes it on their own -> and then submits a PR upstream and downstream!")]),mo]),bo,e("ul",null,[e("li",null,[t("The hard work of translation has begun, thanks to "),e("a",vo,[t("@玖柒 Max"),n(o)]),t(" and all the other translation contributors.")]),e("li",null,[e("a",yo,[t("English version"),n(o)])])]),e("h2",wo,[e("a",To,[e("span",null,[t("2021.01.15 "),n(s,null,{default:a(()=>[e("a",ko,[t("1.2.2"),n(o)])]),_:1})])])]),xo,e("ul",null,[So,e("li",null,[t("The "),n(l,{to:"/en/document/level-0/"},{default:a(()=>[t("Simple White Language")]),_:1}),t(" by 🍉 teacher concludes with a grand finale, throwing flowers.")])]),e("h2",Xo,[e("a",Lo,[e("span",null,[t("2021.01.10 "),n(s,null,{default:a(()=>[e("a",Ao,[t("1.2.1"),n(o)])]),_:1})])])]),e("ul",null,[e("li",null,[t("The "),n(l,{to:"/en/document/level-0/"},{default:a(()=>[t("Simple White Language")]),_:1}),t(" series has been launched! 🍉 Teacher's painstaking work teaches you how to configure Xray from scratch!")]),Po,e("li",null,[n(l,{to:"/en/document/level-2/"},{default:a(()=>[t("Transparent Proxy")]),_:1}),t(" has also been updated with more articles.")]),Co,e("li",null,[t("Thanks to "),e("a",Do,[t("@ricuhkaen"),n(o)]),t(", "),e("a",Ho,[t("@BioniCosmos"),n(o)]),t(", "),e("a",Uo,[t("@kirin"),n(o)]),t(".")])]),Io,e("ul",null,[e("li",null,[t("The first PR in the documentation repository. 🎉 "),n(l,{to:"/en/document/level-2/tproxy.html"},{default:a(()=>[t("Transparent Proxy (TProxy) Configuration Tutorial")]),_:1}),t(", thanks to "),e("a",No,[t("@BioniCosmos"),n(o)]),t(".")]),Ro]),Eo,e("p",null,[t("[Happy New Year, Happy “Cow” Year!] 🎆🎇🎆 "),n(s,null,{default:a(()=>[e("a",jo,[t("1.2.0"),n(o)])]),_:1})]),Wo,e("ul",null,[Fo,e("li",null,[t("Xray will continue to move forward! Therefore, "),e("a",Vo,[t("Xray needs more heroes!!"),n(o)]),t("!")]),e("li",null,[t("PS: Please taste, taste every line of the "),e("a",Mo,[t("release notes"),n(o)]),t(" carefully. It seems there's a small secret Easter egg. "),Go])]),Yo,e("p",null,[t("Good news for gamers using transparent proxy! Xray-core TProxy inbound, SOCKS outbound UDP FullCone beta, "),e("a",Oo,[t("TG group"),n(o)]),t(" is hotly testing.")]),e("h2",Bo,[e("a",qo,[e("span",null,[t("2020.12.25 "),n(s,null,{default:a(()=>[e("a",zo,[t("1.1.5"),n(o)])]),_:1})])])]),Qo,e("ul",null,[Ko,Jo,Zo,$o,e("li",null,[t("Kirin brought a wave of script updates. "),e("a",ea,[t("Scripts here"),n(o)]),t(".")]),ta]),na,e("p",null,[t("For some unspeakable reasons, Xray’s documentation website was sneakily launched before the release date. The URL is: "),e("a",oa,[t("Yes, what you’re looking at"),n(o)]),t(".")]),aa,e("p",null,[t("The documentation website needs continuous improvement and content addition, as well as design refinement. Therefore, everyone is welcome to contribute to the construction of the documentation together. "),e("a",sa,[t("Documentation Repository"),n(o)]),t(".")]),ra,la,e("p",null,[t("Xray-core Shadowsocks UDP FullCone beta, "),e("a",ia,[t("TG group"),n(o)]),t(" is hotly testing.")]),ha,da,e("h2",ca,[e("a",ua,[e("span",null,[t("2020.12.18 "),n(s,null,{default:a(()=>[e("a",_a,[t("1.1.4"),n(o)])]),_:1})])])]),pa,fa,e("p",null,[t("Given the growing number of group members and gaming needs, the "),e("a",ga,[t("TG game group"),n(o)]),t(" has been launched.")]),ma,e("p",null,[e("a",ba,[t("Installation script dev branch"),n(o)]),t(" is now open and features are being continuously updated.")]),e("h2",va,[e("a",ya,[e("span",null,[t("2020.12.11 "),n(s,null,{default:a(()=>[e("a",wa,[t("1.1.3"),n(o)])]),_:1})])])]),Ta,e("h2",ka,[e("a",xa,[e("span",null,[t("2020.12.06 "),n(s,null,{default:a(()=>[e("a",Sa,[t("1.1.2"),n(o)])]),_:1})])])]),Xa,e("h2",La,[e("a",Aa,[e("span",null,[t("2020.11.25 "),n(s,null,{default:a(()=>[e("a",Pa,[t("1.0.0"),n(o)])]),_:1})])])]),Ca,Da,Ha,Ua,Ia])}const Wa=d(_,[["render",Na],["__file","news.html.vue"]]);export{Wa as default}; diff --git a/assets/news.html-DY4EgGn2.js b/assets/news.html-BeMBU7o5.js similarity index 99% rename from assets/news.html-DY4EgGn2.js rename to assets/news.html-BeMBU7o5.js index 8aa42d44b7..d738ae010e 100644 --- a/assets/news.html-DY4EgGn2.js +++ b/assets/news.html-BeMBU7o5.js @@ -1 +1 @@ -import{_,r as i,o as c,c as d,a as n,b as e,d as l,w as s,e as o}from"./app-DBM4OJyw.js";const u={},p=e("h1",{id:"大史记",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#大史记"},[e("span",null,"大史记")])],-1),f=e("h2",{id:"_2024-9-12",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2024-9-12"},[e("span",null,"2024.9.12")])],-1),b=e("p",null,"大史记重出江湖?!",-1),g={id:"_2024-9-7-v24-9-7",tabindex:"-1"},X={class:"header-anchor",href:"#_2024-9-7-v24-9-7"},v={href:"https://github.com/XTLS/Xray-core/releases/tag/v24.9.7",target:"_blank",rel:"noopener noreferrer"},S=e("p",null,"更改版本号之后的首次发版。",-1),T=e("ul",null,[e("li",null,[l("这次移除了 QUIC 以及 DomainSocket 传输,移除了两处远古配置遗留代码。 "),e("ul",null,[e("li",null,"二进制大小比 v1.8.24 减小了 1MB。")])]),e("li",null,"依然有每次必备的 bug 修复。")],-1),k={id:"_2024-8-30-v1-8-24",tabindex:"-1"},m={class:"header-anchor",href:"#_2024-8-30-v1-8-24"},x={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.24",target:"_blank",rel:"noopener noreferrer"},y=o('

                                      在等待 SplitHTTP multiplex controller 期间,main 分支已经积累了大量重要更新,所以我们决定先发一个版本。

                                      • Socks 入站现在默认兼容 HTTP 代理请求。
                                      • UDP noise (preview)
                                      • 还有一些改进。

                                      由于传统版本号的存在,为每个版本规划功能、进行排期已经严重阻碍了新功能的开发、合并、发布。所以我们决定从下个版本开始弃用传统的版本号,改用发版日期作为版本号,如 v24.8.30,并取消版本规划,全面采用流式更新,写好的功能直接合并,不再等待,预计每月月底发一个版本。

                                      毕竟对于反审查软件来说,相较于传统的版本号,新功能的及时性、每月更新更为重要,而不是发一个功能确定的版本并长期维护。

                                      下个版本会移除一些历史久远的代码,以后日常积累新代码、提醒迁移,跨年新版删代码、breaking。

                                      我们相信有了各位的捐款以及对发版形式的革新,Xray-core 这个项目会发展得更好。

                                      2024.8.26

                                      Project VLESS 群组创立。

                                      ',8),L={href:"https://t.me/projectVless",target:"_blank",rel:"noopener noreferrer"},P=e("h2",{id:"_2024-8-3",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2024-8-3"},[e("span",null,"2024.8.3")])],-1),H={href:"https://github.com/XTLS/Xray-core/discussions/3633",target:"_blank",rel:"noopener noreferrer"},D=e("p",null,"就像 Xray 开创过很多历史一样,发行 NFT 也是这个领域前无古人的操作。这些 NFT 非常有纪念意义,甚至可以说是有历史意义,远大于现在的初始价格,假以时日它们必将价值连城。最后再次感谢大家对 Project X 的支持。",-1),U={id:"_2024-7-29-v1-8-23",tabindex:"-1"},R={class:"header-anchor",href:"#_2024-7-29-v1-8-23"},C={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.23",target:"_blank",rel:"noopener noreferrer"},E={href:"https://github.com/mmmray",target:"_blank",rel:"noopener noreferrer"},N=e("li",null,"优化了 SplitHTTP 上行的稳定性,服务端必须升级到该版本以支持新版客户端。",-1),I=e("li",null,"更多 SplitHTTP 上的变化。",-1),V={id:"_2024-7-22-v1-8-21",tabindex:"-1"},w={class:"header-anchor",href:"#_2024-7-22-v1-8-21"},A={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.21",target:"_blank",rel:"noopener noreferrer"},W=e("p",null,"中间似乎回到了最初的腹泻式发版状态……",-1),j=e("p",null,"正如 v1.8.16 所预告的,SplitHTTP 现已初步支持 HTTP/3(QUIC)。毫无疑问,SplitHTTP H3 已经开启了一个崭新的时代。",-1),B=e("ul",null,[e("li",null,"SplitHTTP H3 是第一个完全基于标准 H3、支持套 CDN 的 QUIC 类代理,亦可用反代、Browser Dialer 来隐蔽自身。")],-1),F=e("h2",{id:"_2024-7-16",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2024-7-16"},[e("span",null,"2024.7.16")])],-1),G={href:"https://github.com/iambabyninja",target:"_blank",rel:"noopener noreferrer"},M=e("blockquote",null,[e("p",null,"Привет, друзья из России!")],-1),q=e("h2",{id:"_2024-7-15",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2024-7-15"},[e("span",null,"2024.7.15")])],-1),O=e("p",null,"虽然日后随着各方面升级 Windows 7 最终会离开,但是现在还是可以让这个时间来得稍微晚一些。",-1),Y={id:"_2024-6-18-v1-8-16",tabindex:"-1"},Q={class:"header-anchor",href:"#_2024-6-18-v1-8-16"},K={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.16",target:"_blank",rel:"noopener noreferrer"},z=e("p",null,"新传输来了,它目前叫 SplitHTTP。",-1),J=e("ul",null,[e("li",null,"实现进一步的流量混淆有两种刚好相反的方式:多路复用与拆分连接。"),e("li",null,"可以通过不支持 WebSocket、gRPC 的 CDN,实现与 Meek 相同的目标,且 SplitHTTP 比 Meek 更简单、效率更高。"),e("li",null,"SplitHTTP 没有 WebSocket 的 ALPN 问题,这是一大优势,未来还会支持 HTTP/3(QUIC)。"),e("li",null,"另外 SplitHTTP 也已经加入分享链接套餐~")],-1),Z=e("h2",{id:"_2024-6-2",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2024-6-2"},[e("span",null,"2024.6.2")])],-1),$=e("p",null,"一个新的传输方式正在被打造……",-1),ee={id:"_2024-4-26-v1-8-11",tabindex:"-1"},le={class:"header-anchor",href:"#_2024-4-26-v1-8-11"},ne={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.11",target:"_blank",rel:"noopener noreferrer"},te=e("ul",null,[e("li",null,"现在有了生成 ECH 密钥的工具。"),e("li",null,"增强、修复,并移除了一点不再使用的代码。")],-1),se=e("h2",{id:"_2024-4-20",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2024-4-20"},[e("span",null,"2024.4.20")])],-1),ae={href:"https://github.com/Fangliding",target:"_blank",rel:"noopener noreferrer"},oe=e("h2",{id:"_2024-4-13",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2024-4-13"},[e("span",null,"2024.4.13")])],-1),re=e("p",null,"VLESS Seed 整备完毕,待势而发。",-1),ie={id:"_2024-3-18-v1-8-10",tabindex:"-1"},he={class:"header-anchor",href:"#_2024-3-18-v1-8-10"},_e={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.10",target:"_blank",rel:"noopener noreferrer"},ce=e("p",null,"和 WebSocket 一样,HTTPUpgrade 也有 0-RTT 了。",-1),de={id:"_2024-3-11-v1-8-9",tabindex:"-1"},ue={class:"header-anchor",href:"#_2024-3-11-v1-8-9"},pe={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.9",target:"_blank",rel:"noopener noreferrer"},fe=e("p",null,"新增 HTTPUpgrade 传输,听说比 WebSocket 要轻。",-1),be=e("ul",null,[e("li",null,"已加入分享链接套餐~")],-1),ge=e("h2",{id:"_2024-2-29",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2024-2-29"},[e("span",null,"2024.2.29")])],-1),Xe=e("p",null,[l("gRPC 传输现在也有 Host 一样的配置字段了!它叫 "),e("code",null,"authority"),l("。这下 gRPC 也能“域前置”了,没有 ALPN 问题。")],-1),ve={id:"_2024-2-25-v1-8-8",tabindex:"-1"},Se={class:"header-anchor",href:"#_2024-2-25-v1-8-8"},Te={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.8",target:"_blank",rel:"noopener noreferrer"},ke=e("ul",null,[e("li",null,"现在 XUDP 流量统一使用 Vision 填充了,速来体验。"),e("li",null,"新增了 leastLoad balancer。"),e("li",null,"修复错误、优化性能……")],-1),me=e("h2",{id:"_2024-1-9",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2024-1-9"},[e("span",null,"2024.1.9")])],-1),xe=e("p",null,"惊闻 Win7 无法运行新版 Xray-core?探索之下竟发现 Go 放弃了对 Win7 的支持。有什么办法能继续支持这个有些古老但是依然优雅的操作系统吗?",-1),ye=e("h2",{id:"_2023-11-21",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2023-11-21"},[e("span",null,"2023.11.21")])],-1),Le={href:"https://t.me/projectXtls/212",target:"_blank",rel:"noopener noreferrer"},Pe=e("p",null,"而 XTLS 也不会止步于此,如 X 射线一般穿破高耸的围墙。",-1),He={id:"_2023-11-18-v1-8-6",tabindex:"-1"},De={class:"header-anchor",href:"#_2023-11-18-v1-8-6"},Ue={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.6",target:"_blank",rel:"noopener noreferrer"},Re=o('
                                      • WireGuard 现在也有了对应的入站。Freedom 出站也终于有了 splice。
                                      • 现在出站的 domainStrategy 也得到了统一。
                                      • 更多的美味小点心。
                                      • 因为 不可抗力 功能变更,Dragonfly BSD 支持黯然离场。
                                      • 我们真的要对一代经典 Windows 7 说再见了吗?

                                      2023.9.30

                                      为 v2rayNG 设计了全新的配色,安装最新的 Pre-release 版本即可体验。

                                      ',3),Ce={id:"_2023-8-29-v1-8-4",tabindex:"-1"},Ee={class:"header-anchor",href:"#_2023-8-29-v1-8-4"},Ne={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.4",target:"_blank",rel:"noopener noreferrer"},Ie=o('

                                      1.8.x 在经过半年的打磨后终于来到了第一个认可的正式版了。

                                      同样地,这次集成的改进也不少,速来品尝!

                                      2023.7.22

                                      又修好了一个 HTTP/2 传输的历史遗留断流问题。

                                      2023.7.7

                                      即将给 Vision 添加 Seed 支持。

                                      2023.6.30

                                      下一个 XTLS 流控:xtls-rprx-switch 🍪

                                      • XTLS 的 0-RTT 已经预告几个月了,本来也是想保留神秘感。
                                      • 对比现有的 XTLS Vision 和 Mux 有着更加不错的优势。

                                      2023.6.27

                                      ',10),Ve={href:"https://github.com/XTLS/Xray-core/discussions/2256#discussioncomment-6295296",target:"_blank",rel:"noopener noreferrer"},we={id:"_2023-6-19-v1-8-3",tabindex:"-1"},Ae={class:"header-anchor",href:"#_2023-6-19-v1-8-3"},We={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.3",target:"_blank",rel:"noopener noreferrer"},je=o('
                                      • 精简代码计划后的第一个版本,VMess (MD5)、MTProto 以及 Starlark 相关代码已被卸下。轻装上阵。
                                      • 对代码进重构也是轻装上阵的一部分。
                                      • 同时我们也没有忘记增添一些增强功能,还有修复漏洞。
                                      • v1.8.3 为今年的最后一个版本。

                                      2023.6.6

                                      好消息:下一个 XTLS 流控不叫 Vision。 🍪

                                      2023.4.21

                                      ',4),Be={href:"https://github.com/XTLS/RealiTLScanner",target:"_blank",rel:"noopener noreferrer"},Fe=e("h2",{id:"_2023-4-20",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2023-4-20"},[e("span",null,"2023.4.20")])],-1),Ge={href:"https://github.com/XTLS/Xray-core/discussions/1967",target:"_blank",rel:"noopener noreferrer"},Me=e("h2",{id:"_2023-4-19",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2023-4-19"},[e("span",null,"2023.4.19")])],-1),qe=e("p",null,[e("code",null,"xtls-0rtt-vision(-udp443)"),l(" 🍪")],-1),Oe={id:"_2023-4-18-v1-8-1",tabindex:"-1"},Ye={class:"header-anchor",href:"#_2023-4-18-v1-8-1"},Qe={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.1",target:"_blank",rel:"noopener noreferrer"},Ke=o('

                                      升级后的 XUDP 也来了!

                                      • 现在 XUDP 也带有连接迁移、端口复用的特性,并且带有全局 Session ID ,麻麻再也不用担心意外断线的时候怎么办了
                                      • 同时我们也添加了 XUDP 的控制配置,让你能更好掌控它~
                                      • 新的 XUDP 配合 XTLS Vision 食用风味更好喔~
                                      • 惯例还有小甜点,欢迎品尝~

                                      2023.4.6

                                      XUDP 也在悄然升级……

                                      2023.3.29

                                      PLUX protocol 🍪

                                      2023.3.19

                                      对 REALITY 的分享链接标准也已经出现了。

                                      ',8),ze={id:"_2023-3-9-v1-8-0",tabindex:"-1"},Je={class:"header-anchor",href:"#_2023-3-9-v1-8-0"},Ze={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.0",target:"_blank",rel:"noopener noreferrer"},$e=o('

                                      THE NEXT FUTURE, REALITY is NOW release on Xray-core

                                      REALITY 已经实装发版!欢迎体验! XTLS Vision 也已经完善,请两端升级至最新版食用。

                                      • 因为这次 Vision 填充算法改变,XTLS Vision 旧版和新版之间会存在兼容性问题。
                                      • HTTP/2 传输也已经做了改善,现在使用新版即可纵享丝滑~
                                      • 还有大量小改进欢迎体验~

                                      2023.3.4

                                      Legends never die, they become a part of you VLESS.

                                      They simply fade away.

                                      2023.3.2

                                      HTTP/2 传输的一些遗留问题已经被改善,欢迎搭配 REALITY 测试纵享丝滑~

                                      2023.2.16

                                      THE NEXT FUTURE becomes THE REALITY NOW!

                                      2023.2.9

                                      REALITY is reality now!

                                      ',11),el={id:"_2023-2-8-v1-7-5",tabindex:"-1"},ll={class:"header-anchor",href:"#_2023-2-8-v1-7-5"},nl={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.7.5",target:"_blank",rel:"noopener noreferrer"},tl=e("p",null,"Keep riding and never look back.",-1),sl={href:"https://github.com/yuhan6665",target:"_blank",rel:"noopener noreferrer"},al=e("li",null,"XTLS Vision 流控已经接近完善,即将实用。",-1),ol=e("li",null,"现在对 uTLS 指纹模拟添加了更多可选项,有哪一款适合你?",-1),rl=e("li",null,"分享链接也支持同时分享 uTLS 指纹配置了。",-1),il=e("li",null,"还有更多的功能增强和修复。",-1),hl=e("li",null,[l("这一版也是能最后一次看到 XTLS Origin、Direct 和 Splice 流控的一版了。 "),e("s",null,"有点伤感不是吗?")],-1),_l=e("h2",{id:"_2023-1-29",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2023-1-29"},[e("span",null,"2023.1.29")])],-1),cl=e("p",null,"Winter cannot cover the NEXT FUTURE...",-1),dl={id:"_2022-12-26-v1-7-0",tabindex:"-1"},ul={class:"header-anchor",href:"#_2022-12-26-v1-7-0"},pl={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.7.0",target:"_blank",rel:"noopener noreferrer"},fl=e("p",null,"因为手滑,这次的版本号直接大升,感谢大家支持!",-1),bl=e("ul",null,[e("li",null,"以后将会严格执行 Semantic Versioning。")],-1),gl={id:"_2022-11-28-v1-6-5",tabindex:"-1"},Xl={class:"header-anchor",href:"#_2022-11-28-v1-6-5"},vl={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.6.5",target:"_blank",rel:"noopener noreferrer"},Sl=e("p",null,"这次我们有了 WireGuard 出站。",-1),Tl=e("ul",null,[e("li",null,"使用 WireGuard 搭配 CF WARP 使用可以解锁有趣的新玩法呢。"),e("li",null,"同样安全更新和修复也不会少。")],-1),kl={id:"_2022-11-7-v1-6-3",tabindex:"-1"},ml={class:"header-anchor",href:"#_2022-11-7-v1-6-3"},xl={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.6.3",target:"_blank",rel:"noopener noreferrer"},yl=e("p",null,[l("现在 Vision 流控也能使用 uTLS 指纹模拟了,这就是使用 "),e("code",null,"tlsSettings"),l(" 带来的好处吗!")],-1),Ll={id:"_2022-10-29-v1-6-2",tabindex:"-1"},Pl={class:"header-anchor",href:"#_2022-10-29-v1-6-2"},Hl={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.6.2",target:"_blank",rel:"noopener noreferrer"},Dl=e("p",null,"第一个包含 Vision 流控的发行版已经放出!欢迎试用并提交反馈!",-1),Ul={id:"_2022-10-22-v1-6-1",tabindex:"-1"},Rl={class:"header-anchor",href:"#_2022-10-22-v1-6-1"},Cl={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.6.1",target:"_blank",rel:"noopener noreferrer"},El=o('
                                      • 为 WebSocket、HTTP/2 以及 gRPC 传输带来了 uTLS 指纹支持!
                                        • 之前只有普通 TLS 下 TCP 传输能用的选项现在更好用了。
                                      • Linux 下可以单独为出入口设置 TCP 拥塞控制了。

                                      2022.10.3

                                      天气渐凉,但是并没有凉下开发的脚步。封锁天降,但无法阻止前行……

                                      • 新的 XTLS 流控酝酿中……
                                        • 解决之前流控已有的问题;
                                        • 对 TLS 1.3 直接启用 splice;
                                        • 增加 TLS 握手长度混淆;
                                        • 简化代码,使用 tlsSettings 而不是 xtlsSettings……
                                      ',4),Nl={id:"_2022-8-28-v1-5-10",tabindex:"-1"},Il={class:"header-anchor",href:"#_2022-8-28-v1-5-10"},Vl={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.5.10",target:"_blank",rel:"noopener noreferrer"},wl=e("p",null,"底层传输支持更合理的 TCP Keepalive 配置了。",-1),Al={id:"_2022-6-20-v1-5-8",tabindex:"-1"},Wl={class:"header-anchor",href:"#_2022-6-20-v1-5-8"},jl={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.5.8",target:"_blank",rel:"noopener noreferrer"},Bl=e("p",null,"现在 Shadowsocks-2022 的 relay 中转也受支持了。",-1),Fl={id:"_2022-5-29-v1-5-6",tabindex:"-1"},Gl={class:"header-anchor",href:"#_2022-5-29-v1-5-6"},Ml={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.5.6",target:"_blank",rel:"noopener noreferrer"},ql=e("p",null,"Shadowsocks-2022 协议来到了 Xray-core!",-1),Ol={href:"https://github.com/nekohasekai",target:"_blank",rel:"noopener noreferrer"},Yl={href:"https://github.com/database64128",target:"_blank",rel:"noopener noreferrer"},Ql={href:"https://github.com/RPRX",target:"_blank",rel:"noopener noreferrer"},Kl=e("p",null,"Shadowsocks-2022 是重新设计的全新协议:",-1),zl=e("ul",null,[e("li",null,"在保留 Shadowsocks 原生 udp 的基础上解决了重放攻击等安全问题(与 vmess 一样使用时间戳,因此客户端与服务端需要时间一致)。"),e("li",null,"支持单端口多用户,并且参考 quic、wireguard 等协议设计与实现使用了 session 机制,减低加密负担,保证网络变动时的无缝迁移。")],-1),Jl={id:"_2022-4-24-v1-5-5",tabindex:"-1"},Zl={class:"header-anchor",href:"#_2022-4-24-v1-5-5"},$l={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.5.5",target:"_blank",rel:"noopener noreferrer"},en=e("p",null,"这次带来了方便可视化的检测数据接口!快来体验!",-1),ln=e("ul",null,[e("li",null,"顺便修复了一些影响使用体验的问题。")],-1),nn={id:"_2022-3-13-v1-5-4",tabindex:"-1"},tn={class:"header-anchor",href:"#_2022-3-13-v1-5-4"},sn={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.5.4",target:"_blank",rel:"noopener noreferrer"},an=e("p",null,"给 Windows 平台加上了没有黑窗冒出的 wxray.exe 文件,并带来了对 UDS 监听的增强。",-1),on={id:"_2022-1-29-v1-5-3",tabindex:"-1"},rn={class:"header-anchor",href:"#_2022-1-29-v1-5-3"},hn={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.5.3",target:"_blank",rel:"noopener noreferrer"},_n=e("p",null,"牛辞胜岁,虎跃新程。🧨",-1),cn=e("ul",null,[e("li",null,"这次带来了对 QUIC 传输的流分配改进,使用 QUIC 传输现在更丝滑了。")],-1),dn={id:"_2021-12-24-v1-5-2",tabindex:"-1"},un={class:"header-anchor",href:"#_2021-12-24-v1-5-2"},pn={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.5.2",target:"_blank",rel:"noopener noreferrer"},fn=e("p",null,"为 gRPC 添加了一个新的选项,在通过 CDN 时变得更好用了。",-1),bn={id:"_2021-12-15-v1-5-1",tabindex:"-1"},gn={class:"header-anchor",href:"#_2021-12-15-v1-5-1"},Xn={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.5.1",target:"_blank",rel:"noopener noreferrer"},vn=e("blockquote",null,[e("p",null,"“过渡时期的阶段性的维护版本”")],-1),Sn=e("ul",null,[e("li",null,"新功能、增强还有大量修复陆续有来。"),e("li",null,[l("记得将 VMess 配置中的 "),e("code",null,"alterID"),l(" 去掉!")])],-1),Tn={id:"_2021-10-20-v1-5-0",tabindex:"-1"},kn={class:"header-anchor",href:"#_2021-10-20-v1-5-0"},mn={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.5.0",target:"_blank",rel:"noopener noreferrer"},xn=e("p",null,"真的是巨大的改动!",-1),yn=e("ul",null,[e("li",null,"重构了 DNS 组件,支持的协议和细化配置更多了。"),e("li",null,"增强了 gRPC 传输以及 FakeDNS。"),e("li",null,"现在终于支持 Windows ARM64 了。"),e("li",null,"更多新功能和改进等待体验。")],-1),Ln={id:"_2021-9-23-v1-4-5",tabindex:"-1"},Pn={class:"header-anchor",href:"#_2021-9-23-v1-4-5"},Hn={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.4.5",target:"_blank",rel:"noopener noreferrer"},Dn=o('

                                      中秋快乐,阖家团圆。

                                      • 修正了版本号过低,版本号不吉利的 bug。
                                      • 这次移除了 Shadowsocks 里面已经不安全的加密方式。要尽快迁移到 AEAD 加密上面喔。
                                      • 这次修复了远古时期开始就存在的历史问题:开启流量统计功能可能会使性能下降。简单来说,不论什么配置现在打开统计都不会对性能有任何影响了。
                                      • 还有对 XTLS 的安全性更新以及大量修复。
                                      • 对了,因为 TLS 库的更新,cipherSuites 不能再指定加密套件顺序了,而 preferServerCipherSuites 已经被彻底弃用。事实上这些变化在 Xray-core v1.4.3 中已经产生了。

                                      2021.9.16

                                      ',3),Un={href:"https://xtls.github.io/",target:"_blank",rel:"noopener noreferrer"},Rn={id:"_2021-9-8-v1-4-3",tabindex:"-1"},Cn={class:"header-anchor",href:"#_2021-9-8-v1-4-3"},En={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.4.3",target:"_blank",rel:"noopener noreferrer"},Nn=o('

                                      这是一个阶段性维护版本。开发仍在继续……

                                      • 在此期间累积了大量改进和新功能。
                                      • 加入新的 DomainMatcher,现在域名规则匹配性能更好了。
                                      • 加入对 HTTP/2 和 gRPC 传输的健康检查、对未知 SNI 的处理改进,以及修复了一大堆 bug。

                                      Helden sterben nicht!

                                      2021.7.14

                                      • AnXray 重金设计 的新图标已经上线!
                                        • 现在图标的辨识度更高了。
                                      • 过去三个星期,AnXray 共积累了 600 stars、2K+ 频道订阅数和 11K+ GitHub 下载量,感谢大家的支持。
                                      • AX 为 AnXray 的缩写,推荐用 AX 指代 AnXray,简短方便

                                      2021.6.21

                                      ',6),In={href:"https://github.com/XTLS/AnXray",target:"_blank",rel:"noopener noreferrer"},Vn={href:"https://github.com/nekohasekai",target:"_blank",rel:"noopener noreferrer"},wn=e("li",null,"支持众多协议、插件.",-1),An={href:"https://github.com/RPRX",target:"_blank",rel:"noopener noreferrer"},Wn=e("li",null,"APP 内还有个小彩蛋等你去发现。",-1),jn=o('

                                      前两天从早到晚反复打磨细节,希望大家多多 Star、关注。

                                      2021.5.1

                                      对 tun2socks 的改进出现在 v2rayNG 上面了。

                                      2021.4.26

                                      给 tun2socks 带来了一个改进。后续有可能能吃到它~

                                      2021.4.12

                                      现在带来了 X-flutter 前瞻,可以期待一下会是什么样子呢~ 🍪

                                      2021.4.6

                                      • VuePress Next.
                                      • With Dark Mode.

                                      2021.4.4

                                      • 本文档迎来的新的首页。
                                      • 本文档迎来了暗黑模式。
                                      • 当然,暗黑模式还有各种各样的问题。具体的内容还需要慢慢调整。
                                      • 另:Telegram 群聊突破了 5000 人!还加入了 Anti-Spam 机器人!
                                      • 🎉🎉🎉
                                      ',11),Bn={id:"_2021-4-1-v1-4-2",tabindex:"-1"},Fn={class:"header-anchor",href:"#_2021-4-1-v1-4-2"},Gn={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.4.2",target:"_blank",rel:"noopener noreferrer"},Mn=o('
                                      • 不是愚人节玩笑,今天更新。
                                      • 加入 Browser Dialer,用与改变 TLS 指纹与行为。
                                      • 加入 uTLS,用与改变 TLS Client Hello 的指纹。
                                      • 顺便修复了一大堆奇妙的问题,具体的内容见更新日志。

                                      2021.3.25

                                      没错还在变。 -_-

                                      2021.3.15

                                      文档网站正在悄悄的进行着某些神秘的变化。。。,🙊🙊🙊

                                      ',5),qn={id:"_2021-3-14-v1-4-0",tabindex:"-1"},On={class:"header-anchor",href:"#_2021-3-14-v1-4-0"},Yn={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.4.0",target:"_blank",rel:"noopener noreferrer"},Qn=o("
                                      • Happy Pi-Day!
                                      • 这次是个大更新:
                                        • 为链式代理引入了传输层支持。
                                        • 为 Dialer 引入了 Domain Strategy,解决奇妙的 DNS 问题。
                                        • 添加了 gRPC 传输方式,与更快一点的 Multi Mode。
                                        • 添加了 WebSocket Early-Data 功能,减少了 WebSocket 的延迟。
                                        • 添加了 FakeDNS。
                                        • 还修复了系列的问题,添加了各类功能,详情请见更新日志。
                                      • 还是 VuePress 比较爽啊(
                                      ",1),Kn={id:"_2021-3-3-1-3-1",tabindex:"-1"},zn={class:"header-anchor",href:"#_2021-3-3-1-3-1"},Jn={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.3.1",target:"_blank",rel:"noopener noreferrer"},Zn=e("ul",null,[e("li",null,"这个版本使用了 Golang 1.16,正式原生支持 Apple Silicon。"),e("li",null,[l("同时修复了一个会导致 Panic 的 bug。"),e("s",null,"Holmium_认为这是在骗、在偷袭。")]),e("li",null,"修复了几个遗留问题。")],-1),$n={id:"_2021-2-14-1-3-0",tabindex:"-1"},et={class:"header-anchor",href:"#_2021-2-14-1-3-0"},lt={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.3.0",target:"_blank",rel:"noopener noreferrer"},nt=e("ul",null,[e("li",null,"Happy 🐮 Year 🎉!"),e("li",null,"v1.3.0 通过非常巧妙的机制实现了 V 系协议全部 FullCone,同时保证了一定的兼容性。"),e("li",null,"OHHHHHHHHHHHH!")],-1),tt={id:"_2021-01-31-1-2-4",tabindex:"-1"},st={class:"header-anchor",href:"#_2021-01-31-1-2-4"},at={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.2.4",target:"_blank",rel:"noopener noreferrer"},ot=e("ul",null,[e("li",null,"解决两个“连接至标准 Socks 服务端时可能出错”的历史遗留问题。"),e("li",null,"似乎这个版本没有什么改变,但这只是暴风雨前的宁静。"),e("li",null,[l("(没错我就是先知) "),e("blockquote",null,[e("p",null,"你个傻子,你拿的是 UNO 牌。")])])],-1),rt=e("h2",{id:"_2021-01-25",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2021-01-25"},[e("span",null,"2021.01.25")])],-1),it=e("li",null,[e("a",{href:"../en"},"英文版文档网站"),l("逐渐增加内容 ing, 感谢各位大佬的辛苦付出~!")],-1),ht={id:"_2021-01-22-1-2-3",tabindex:"-1"},_t={class:"header-anchor",href:"#_2021-01-22-1-2-3"},ct={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.2.3",target:"_blank",rel:"noopener noreferrer"},dt=e("li",null,[l("对 SS 协议的支持"),e("strong",null,"又"),l("变强了, 支持单端口多用户!")],-1),ut=e("li",null,[l("对 trojan 协议的支持也"),e("strong",null,"又"),l("变强了, trojan 的回落也解锁 SNI 分流的新姿势啦~!")],-1),pt=e("li",null,[e("em",null,"(VLESS: 嘤嘤嘤)")],-1),ft=e("li",null,'UDP 奇奇怪怪的 BUG 被干掉了, 一个字, "稳定".',-1),bt=e("li",null,"嗅探可以排除你不想嗅探的域名, 可以开启一些新玩法.",-1),gt={href:"https://github.com/bohanyang",target:"_blank",rel:"noopener noreferrer"},Xt=e("li",null,"其他美味小樱桃, 惯例更新品尝就对啦.",-1),vt=o('

                                      2021.01.19

                                      • 一些数字
                                        • 版本发布了 10   个 tag
                                        • 解决掉了 100  个 issue
                                        • 复刻了 300  个 fork
                                        • 点了 2000 个 star
                                        • 群 3000 个 人

                                      2021.01.17

                                      ',3),St={href:"https://github.com/jiuqi9997",target:"_blank",rel:"noopener noreferrer"},Tt={href:"https://xtls.github.io/en/",target:"_blank",rel:"noopener noreferrer"},kt={id:"_2021-01-15-1-2-2",tabindex:"-1"},mt={class:"header-anchor",href:"#_2021-01-15-1-2-2"},xt={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.2.2",target:"_blank",rel:"noopener noreferrer"},yt=o('
                                      • 回落分流又解锁了奇怪的新姿势! 回落中可以根据 SNI 分流啦~!
                                      • 之前预告的 UUID 修改正式上线.(往下看往下看)
                                      • 日志现在看起来比上一次顺眼又更顺眼了一丢丢.
                                      • 远程 DOH 和其他的 DNS 模式一样学会了走路由分流.
                                      • 当然还有其他各种小糖果.(更新品尝就对了)
                                      • 啊, 还有, 世界上第一個 M1 上跑起 Xray 的男人是 Anthony TSE

                                      2021.01.12

                                      ',2),Lt=e("li",null,[l("将要到来的 UUID 修改, 支持自定义字符串和 UUID 之间的映射. 这意味着你将可以这样在配置文件中写 id 来对应用户. "),e("ul",null,[e("li",null,'客户端写 "id": "我爱 🍉 老师 1314",'),e("li",null,[l('服务端写 "id": "5783a3e7-e373-51cd-8642-c83782b807c5" (此 UUID 是 '),e("code",null,"我爱🍉老师1314"),l(" 的 UUID 映射)")])])],-1),Pt={id:"_2021-01-10-1-2-1",tabindex:"-1"},Ht={class:"header-anchor",href:"#_2021-01-10-1-2-1"},Dt={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.2.1",target:"_blank",rel:"noopener noreferrer"},Ut=e("li",null,"(可能是整个互联网上, 最详细最有耐心的教你从 0 开始配置的教程)",-1),Rt=e("li",null,"还有很多细节修改, 文档将会越来越规范!",-1),Ct={href:"https://github.com/ricuhkaen",target:"_blank",rel:"noopener noreferrer"},Et={href:"https://github.com/BioniCosmos",target:"_blank",rel:"noopener noreferrer"},Nt={href:"https://github.com/kirin10000",target:"_blank",rel:"noopener noreferrer"},It=o('
                                      • 大量的 UDP 相关修复, 甚至可以在育碧的土豆服务器上玩彩虹六号!
                                      • Google Voice 应该也可以正常使用 v2rayNG 拨打了.
                                      • 日志现在看起来更顺眼.

                                      2021.01.07

                                      • 礼貌和尊重本应是社区不需要明说的准则之一。

                                      2021.01.05

                                      • 文档网站正在悄悄的进行着某些神秘的变化。。。,🙊🙊🙊

                                      2021.01.03

                                      ',6),Vt={href:"https://github.com/BioniCosmos",target:"_blank",rel:"noopener noreferrer"},wt=e("li",null,"tg 群突破 2500。",-1),At=e("h2",{id:"_2021-01-01",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2021-01-01"},[e("span",null,"2021.01.01")])],-1),Wt={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.2.0",target:"_blank",rel:"noopener noreferrer"},jt=e("p",null,"🎁 在元旦的最后几分钟,v1.2.0 它来了,带着周五必更的惯例,带着各位贡献大佬的心血以及 @rprxx 的黑眼圈,不负众望的来了!",-1),Bt=o('
                                    34. 圣诞礼物v1.1.5后的元旦礼物 🎁,游戏玩家大福利,全面 FullCone。
                                    35. (UDP 还会继续增强!)
                                    36. 如果你已经拆过圣诞礼物,这次还有比圣诞礼物更精美的包装和小糖果哦。(同样不用问,更新品尝就对了)
                                    37. (不,下面不是广告,是里程碑。)
                                    38. Xray 是有史以来第一个不受限制的多协议平台:只需 Xray 即可解决问题,无需借力其它实现。
                                      • 一人扛起了所有!支持各大主流协议!
                                      • 一骑绝尘的性能!
                                      • 日趋完善的功能!
                                      • 可怕的生命力与社区亲和力!
                                    39. ',5),Ft={href:"https://github.com/XTLS/Xray-core/discussions/56",target:"_blank",rel:"noopener noreferrer"},Gt={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.2.0",target:"_blank",rel:"noopener noreferrer"},Mt=e("s",null,"(啊,有人敲门...我一会和你们说)",-1),qt=e("h2",{id:"_2020-12-29",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2020-12-29"},[e("span",null,"2020.12.29")])],-1),Ot={href:"https://t.me/projectXray",target:"_blank",rel:"noopener noreferrer"},Yt={id:"_2020-12-25-1-1-5",tabindex:"-1"},Qt={class:"header-anchor",href:"#_2020-12-25-1-1-5"},Kt={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.1.5",target:"_blank",rel:"noopener noreferrer"},zt=e("p",null,"圣诞节快乐!",-1),Jt=e("li",null,"游戏玩家的圣诞礼物!你可以用 xray 爽快的打游戏啦!因为有了 SS/trojan UDP fullcone",-1),Zt=e("li",null,"你可以用你喜欢的格式写配置文件了,比如 yaml,比如 toml...",-1),$t=e("li",null,"(VLESS 的 UDP fullcone 和更多增强很快就到!)",-1),es=e("li",null,"无须再担心证书验证被墙,OCSP stapling 已经上线!",-1),ls={href:"https://github.com/XTLS/Xray-install",target:"_blank",rel:"noopener noreferrer"},ns=e("li",null,"还有更多美味小樱桃!(不用问,更新品尝就对了)",-1),ts=e("h2",{id:"_2020-12-24",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2020-12-24"},[e("span",null,"2020.12.24")])],-1),ss={href:"https://xtls.github.io",target:"_blank",rel:"noopener noreferrer"},as=e("p",null,"大家可以查阅各种内容也欢迎纠错/提出建议(可发往文档 github 仓库的 issue 区)",-1),os={href:"https://github.com/XTLS/XTLS.github.io",target:"_blank",rel:"noopener noreferrer"},rs=e("p",null,"仓库的 readme 中有简略教程说明如何帮助 xray 改进文档网站. 欢迎大家查看,纠错,修改,增加心得。",-1),is=e("h2",{id:"_2020-12-23",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2020-12-23"},[e("span",null,"2020.12.23")])],-1),hs={href:"https://t.me/projectXray",target:"_blank",rel:"noopener noreferrer"},_s=e("h2",{id:"_2020-12-21",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2020-12-21"},[e("span",null,"2020.12.21")])],-1),cs=e("ul",null,[e("li",null,"Project X 群人数 2000+"),e("li",null,"群消息(含游戏群) 日均破万")],-1),ds={id:"_2020-12-18-1-1-4",tabindex:"-1"},us={class:"header-anchor",href:"#_2020-12-18-1-1-4"},ps={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.1.4",target:"_blank",rel:"noopener noreferrer"},fs=e("ul",null,[e("li",null,"更低的启动内占用和内存使用优化"),e("li",null,"随意定制的 TLS 提高你的 SSL 评级"),e("li",null,"支持 XTLS 入站的 Splice 以及支持 trojan 的 XTLS"),e("li",null,"还有在您路由器上使用的 Splice 最佳使用模式建议")],-1),bs=e("h2",{id:"_2020-12-17",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2020-12-17"},[e("span",null,"2020.12.17")])],-1),gs={href:"https://t.me/joinchat/UO4NixbB_XDQJOUjS6mHEQ",target:"_blank",rel:"noopener noreferrer"},Xs=e("h2",{id:"_2020-12-15",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2020-12-15"},[e("span",null,"2020.12.15")])],-1),vs={href:"https://github.com/XTLS/Xray-install/tree/dev",target:"_blank",rel:"noopener noreferrer"},Ss={id:"_2020-12-11-1-1-3",tabindex:"-1"},Ts={class:"header-anchor",href:"#_2020-12-11-1-1-3"},ks={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.1.3",target:"_blank",rel:"noopener noreferrer"},ms=e("ul",null,[e("li",null,"完整版本的 REDIRECT 透明代理模式."),e("li",null,"软路由 splice 流控模式的优化建议.")],-1),xs={id:"_2020-12-06-1-1-2",tabindex:"-1"},ys={class:"header-anchor",href:"#_2020-12-06-1-1-2"},Ls={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.1.2",target:"_blank",rel:"noopener noreferrer"},Ps=o('
                                      • 流控增加 splice 模式, Linux 限定, 性能一骑绝尘.
                                      • 增强了 API 兼容

                                      2020.12.04

                                      增加 splice 模式

                                      2020.11.27

                                      • Project X 的 GitHub 主仓库 Xray-core 已获 500+ stars
                                      • 登上了 GitHub Trending
                                      • Project X 群人数破千,频道订阅数 500+
                                      ',5),Hs={id:"_2020-11-25-1-0-0",tabindex:"-1"},Ds={class:"header-anchor",href:"#_2020-11-25-1-0-0"},Us={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.0.0",target:"_blank",rel:"noopener noreferrer"},Rs=e("p",null,"Xray 的第一个版本.",-1),Cs=e("ul",null,[e("li",null,"基于 v2ray-core 修改而来,改动较大"),e("li",null,"全面增强, 性能卓越, 完全兼容")],-1),Es=e("h2",{id:"_2020-11-23",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2020-11-23"},[e("span",null,"2020.11.23")])],-1),Ns=e("p",null,"project X start",-1),Is=e("blockquote",null,[e("p",null,[e("s",null,"梦开始的时候")])],-1);function Vs(ws,As){const h=i("I18nTip"),t=i("ExternalLinkIcon"),a=i("Badge"),r=i("RouterLink");return c(),d("div",null,[p,n(h),f,b,e("h2",g,[e("a",X,[e("span",null,[l("2024.9.7 "),n(a,null,{default:s(()=>[e("a",v,[l("v24.9.7"),n(t)])]),_:1})])])]),S,T,e("h2",k,[e("a",m,[e("span",null,[l("2024.8.30 "),n(a,null,{default:s(()=>[e("a",x,[l("v1.8.24"),n(t)])]),_:1})])])]),y,e("p",null,[l("We have created "),e("a",L,[l("Project VLESS"),n(t)]),l(" for non-Chinese users (mainly Russian).")]),P,e("p",null,[l("第一个 "),e("a",H,[l("Project X NFT"),n(t)]),l(" 正式发行!")]),D,e("h2",U,[e("a",R,[e("span",null,[l("2024.7.29 "),n(a,null,{default:s(()=>[e("a",C,[l("v1.8.23"),n(t)])]),_:1})])])]),e("ul",null,[e("li",null,[l("恭喜 "),e("a",E,[l("@mmmray"),n(t)]),l(" 贡献了 Xray-core 的第 1000 个 commit!")]),N,I]),e("h2",V,[e("a",w,[e("span",null,[l("2024.7.22 "),n(a,null,{default:s(()=>[e("a",A,[l("v1.8.21"),n(t)])]),_:1})])])]),W,j,B,F,e("p",null,[l("Project X 文档迎来了俄语版!感谢 "),e("a",G,[l("@iambabyninja"),n(t)]),l(" 的翻译!")]),M,q,e("p",null,[l("通过已知信息以及努力,Xray-core 现在重新支持 Windows 7!在后续的发版中,Windows 7 用户下载名为 Xray-win7-32.zip 或 Xray-win7-64.zip 的压缩包解压即可享受,感谢大家的支持!具体使用方式请点"),n(r,{to:"/document/install.html"},{default:s(()=>[l("这里")]),_:1})]),O,e("h2",Y,[e("a",Q,[e("span",null,[l("2024.6.18 "),n(a,null,{default:s(()=>[e("a",K,[l("v1.8.16"),n(t)])]),_:1})])])]),z,J,Z,$,e("h2",ee,[e("a",le,[e("span",null,[l("2024.4.26 "),n(a,null,{default:s(()=>[e("a",ne,[l("v1.8.11"),n(t)])]),_:1})])])]),te,se,e("p",null,[l("我们现在有了 issues 模板,感谢 "),e("a",ae,[l("@Fangliding"),n(t)]),l(" !")]),oe,re,e("h2",ie,[e("a",he,[e("span",null,[l("2024.3.18 "),n(a,null,{default:s(()=>[e("a",_e,[l("v1.8.10"),n(t)])]),_:1})])])]),ce,e("h2",de,[e("a",ue,[e("span",null,[l("2024.3.11 "),n(a,null,{default:s(()=>[e("a",pe,[l("v1.8.9"),n(t)])]),_:1})])])]),fe,be,ge,Xe,e("h2",ve,[e("a",Se,[e("span",null,[l("2024.2.25 "),n(a,null,{default:s(()=>[e("a",Te,[l("v1.8.8"),n(t)])]),_:1})])])]),ke,me,xe,ye,e("p",null,[l("发表在 USENIX 顶会的"),e("a",Le,[l("论文"),n(t)]),l("证实,XTLS Vision 已经达到它的设计目标。")]),Pe,e("h2",He,[e("a",De,[e("span",null,[l("2023.11.18 "),n(a,null,{default:s(()=>[e("a",Ue,[l("v1.8.6"),n(t)])]),_:1})])])]),Re,e("h2",Ce,[e("a",Ee,[e("span",null,[l("2023.8.29 "),n(a,null,{default:s(()=>[e("a",Ne,[l("v1.8.4"),n(t)])]),_:1})])])]),Ie,e("p",null,[e("a",Ve,[l("如何选取 REALITY 目标域名?来看这里助你事半功倍!"),n(t)])]),e("h2",we,[e("a",Ae,[e("span",null,[l("2023.6.19 "),n(a,null,{default:s(()=>[e("a",We,[l("v1.8.3"),n(t)])]),_:1})])])]),je,e("p",null,[l("也许我们可以借助一下 "),e("a",Be,[l("RealiTLScanner"),n(t)]),l("……")]),Fe,e("p",null,[l("经过长年累月的开发,累积代码不计其数…… "),e("a",Ge,[l("精简代码计划"),n(t)]),l(" 被提出了!")]),Me,qe,e("h2",Oe,[e("a",Ye,[e("span",null,[l("2023.4.18 "),n(a,null,{default:s(()=>[e("a",Qe,[l("v1.8.1"),n(t)])]),_:1})])])]),Ke,e("h2",ze,[e("a",Je,[e("span",null,[l("2023.3.9 "),n(a,null,{default:s(()=>[e("a",Ze,[l("v1.8.0"),n(t)])]),_:1})])])]),$e,e("h2",el,[e("a",ll,[e("span",null,[l("2023.2.8 "),n(a,null,{default:s(()=>[e("a",nl,[l("v1.7.5"),n(t)])]),_:1})])])]),tl,e("ul",null,[e("li",null,[l("恭喜 "),e("a",sl,[l("@yuhan6665"),n(t)]),l(" 贡献了 Xray-core 的第 500 个 commit!")]),al,ol,rl,il,hl]),_l,cl,e("h2",dl,[e("a",ul,[e("span",null,[l("2022.12.26 "),n(a,null,{default:s(()=>[e("a",pl,[l("v1.7.0"),n(t)])]),_:1})])])]),fl,bl,e("h2",gl,[e("a",Xl,[e("span",null,[l("2022.11.28 "),n(a,null,{default:s(()=>[e("a",vl,[l("v1.6.5"),n(t)])]),_:1})])])]),Sl,Tl,e("h2",kl,[e("a",ml,[e("span",null,[l("2022.11.7 "),n(a,null,{default:s(()=>[e("a",xl,[l("v1.6.3"),n(t)])]),_:1})])])]),yl,e("h2",Ll,[e("a",Pl,[e("span",null,[l("2022.10.29 "),n(a,null,{default:s(()=>[e("a",Hl,[l("v1.6.2"),n(t)])]),_:1})])])]),Dl,e("h2",Ul,[e("a",Rl,[e("span",null,[l("2022.10.22 "),n(a,null,{default:s(()=>[e("a",Cl,[l("v1.6.1"),n(t)])]),_:1})])])]),El,e("h2",Nl,[e("a",Il,[e("span",null,[l("2022.8.28 "),n(a,null,{default:s(()=>[e("a",Vl,[l("v1.5.10"),n(t)])]),_:1})])])]),wl,e("h2",Al,[e("a",Wl,[e("span",null,[l("2022.6.20 "),n(a,null,{default:s(()=>[e("a",jl,[l("v1.5.8"),n(t)])]),_:1})])])]),Bl,e("h2",Fl,[e("a",Gl,[e("span",null,[l("2022.5.29 "),n(a,null,{default:s(()=>[e("a",Ml,[l("v1.5.6"),n(t)])]),_:1})])])]),ql,e("ul",null,[e("li",null,[l("感谢 "),e("a",Ol,[l("@nekohasekai"),n(t)]),l(" 开发全新 go 实现 https://github.com/SagerNet/sing-shadowsocks 并引入 Xray。")]),e("li",null,[l("感谢 "),e("a",Yl,[l("@database64128"),n(t)]),l(" 推动 Shadowsocks 社区提出完整设计方案。")]),e("li",null,[l("感谢 "),e("a",Ql,[l("@RPRX"),n(t)]),l(" 提交原始漏洞。")])]),Kl,zl,e("h2",Jl,[e("a",Zl,[e("span",null,[l("2022.4.24 "),n(a,null,{default:s(()=>[e("a",$l,[l("v1.5.5"),n(t)])]),_:1})])])]),en,ln,e("h2",nn,[e("a",tn,[e("span",null,[l("2022.3.13 "),n(a,null,{default:s(()=>[e("a",sn,[l("v1.5.4"),n(t)])]),_:1})])])]),an,e("h2",on,[e("a",rn,[e("span",null,[l("2022.1.29 "),n(a,null,{default:s(()=>[e("a",hn,[l("v1.5.3"),n(t)])]),_:1})])])]),_n,cn,e("h2",dn,[e("a",un,[e("span",null,[l("2021.12.24 "),n(a,null,{default:s(()=>[e("a",pn,[l("v1.5.2"),n(t)])]),_:1})])])]),fn,e("h2",bn,[e("a",gn,[e("span",null,[l("2021.12.15 "),n(a,null,{default:s(()=>[e("a",Xn,[l("v1.5.1"),n(t)])]),_:1})])])]),vn,Sn,e("h2",Tn,[e("a",kn,[e("span",null,[l("2021.10.20 "),n(a,null,{default:s(()=>[e("a",mn,[l("v1.5.0"),n(t)])]),_:1})])])]),xn,yn,e("h2",Ln,[e("a",Pn,[e("span",null,[l("2021.9.23 "),n(a,null,{default:s(()=>[e("a",Hn,[l("v1.4.5"),n(t)])]),_:1})])])]),Dn,e("ul",null,[e("li",null,[l("文档站已经完全切换到 docs-next,丝般顺滑,体验更好!地址仍为 "),e("a",Un,[l("https://xtls.github.io/"),n(t)])])]),e("h2",Rn,[e("a",Cn,[e("span",null,[l("2021.9.8 "),n(a,null,{default:s(()=>[e("a",En,[l("v1.4.3"),n(t)])]),_:1})])])]),Nn,e("p",null,[l("现在一个以 Xray-core 为核心的开源、自由的 Android 客户端已经出现——"),e("a",In,[l("AnXray"),n(t)]),l("!由 "),e("a",Vn,[l("@nekohasekai"),n(t)]),l(" 维护。")]),e("ul",null,[wn,e("li",null,[l("首席视觉设计师 "),e("a",An,[l("@RPRX"),n(t)]),l(" 设计了 X-style 的 logo、slogan,以及独一无二的 material 黑白主题。")]),Wn]),jn,e("h2",Bn,[e("a",Fn,[e("span",null,[l("2021.4.1 "),n(a,null,{default:s(()=>[e("a",Gn,[l("v1.4.2"),n(t)])]),_:1})])])]),Mn,e("h2",qn,[e("a",On,[e("span",null,[l("2021.3.14 "),n(a,null,{default:s(()=>[e("a",Yn,[l("v1.4.0"),n(t)])]),_:1})])])]),Qn,e("h2",Kn,[e("a",zn,[e("span",null,[l("2021.3.3 "),n(a,null,{default:s(()=>[e("a",Jn,[l("1.3.1"),n(t)])]),_:1})])])]),Zn,e("h2",$n,[e("a",et,[e("span",null,[l("2021.2.14 "),n(a,null,{default:s(()=>[e("a",lt,[l("1.3.0"),n(t)])]),_:1})])])]),nt,e("h2",tt,[e("a",st,[e("span",null,[l("2021.01.31 "),n(a,null,{default:s(()=>[e("a",at,[l("1.2.4"),n(t)])]),_:1})])])]),ot,rt,e("ul",null,[e("li",null,[l("全互联网最好最详细的秘籍入门篇同学们练熟了吗? 🍉 老师开始连载"),n(r,{to:"/document/level-1/"},{default:s(()=>[l("秘籍第一层")]),_:1}),l("咯...")]),it]),e("h2",ht,[e("a",_t,[e("span",null,[l("2021.01.22 "),n(a,null,{default:s(()=>[e("a",ct,[l("1.2.3"),n(t)])]),_:1})])])]),e("ul",null,[dt,ut,pt,ft,bt,e("li",null,[l("向发现问题->开 issue->自行测试->自行分析->自行找到问题->自行解决->然后给上下游提交 PR 的大佬 "),e("a",gt,[l("@Bohan Yang"),n(t)]),l(" 致敬!")]),Xt]),vt,e("ul",null,[e("li",null,[l("辛苦的翻译工作开始了, 感谢 "),e("a",St,[l("@玖柒 Max"),n(t)]),l("和其他所有的翻译大佬们.")]),e("li",null,[e("a",Tt,[l("English version"),n(t)])])]),e("h2",kt,[e("a",mt,[e("span",null,[l("2021.01.15 "),n(a,null,{default:s(()=>[e("a",xt,[l("1.2.2"),n(t)])]),_:1})])])]),yt,e("ul",null,[Lt,e("li",null,[l("🍉 老师的"),n(r,{to:"/document/level-0/"},{default:s(()=>[l("小小白白话文")]),_:1}),l("大结局, 撒花.")])]),e("h2",Pt,[e("a",Ht,[e("span",null,[l("2021.01.10 "),n(a,null,{default:s(()=>[e("a",Dt,[l("1.2.1"),n(t)])]),_:1})])])]),e("ul",null,[e("li",null,[n(r,{to:"/document/level-0/"},{default:s(()=>[l("小小白白话文")]),_:1}),l("连载上线啦,🍉 老师呕心沥血之作, 手把手教你从什么都不会到熟练配置 Xray!")]),Ut,e("li",null,[n(r,{to:"/document/level-2/"},{default:s(()=>[l("透明代理")]),_:1}),l("也增加了更多文章.")]),Rt,e("li",null,[l("感谢 "),e("a",Ct,[l("@ricuhkaen"),n(t)]),l(" , "),e("a",Et,[l("@BioniCosmos"),n(t)]),l(", "),e("a",Nt,[l("@kirin"),n(t)])])]),It,e("ul",null,[e("li",null,[l("文档仓库第一个 PR。🎉 "),n(r,{to:"/document/level-2/tproxy.html"},{default:s(()=>[l("透明代理(TProxy)配置教程 ")]),_:1}),l(" ,感谢 "),e("a",Vt,[l("@BioniCosmos"),n(t)])]),wt]),At,e("p",null,[l("【祝大家新年快乐,嗨皮牛耶!】🎆🎇🎆 "),n(a,null,{default:s(()=>[e("a",Wt,[l("1.2.0"),n(t)])]),_:1})]),jt,e("ul",null,[Bt,e("li",null,[l("Xray 将继续保持前行! 因此 "),e("a",Ft,[l("Xray 需要更多的英雄!!"),n(t)]),l("!")]),e("li",null,[l("PS:请品,请细品"),e("a",Gt,[l("release notes"),n(t)]),l("每一句。似乎有一个小秘密小彩蛋 "),Mt])]),qt,e("p",null,[l("透明代理的游戏玩家利好! Xray-core tproxy 入站, socks 出站 UDP FullCone 测试版, "),e("a",Ot,[l("TG 群"),n(t)]),l("火热测试中")]),e("h2",Yt,[e("a",Qt,[e("span",null,[l("2020.12.25 "),n(a,null,{default:s(()=>[e("a",Kt,[l("1.1.5"),n(t)])]),_:1})])])]),zt,e("ul",null,[Jt,Zt,$t,es,e("li",null,[l("kirin 带来了一大波 脚本更新."),e("a",ls,[l("脚本在此"),n(t)])]),ns]),ts,e("p",null,[l("因为某些不可描述的原因,Xray 的文档网站已在发布日前偷跑上线。 网址为:"),e("a",ss,[l("没错你正在看的就是"),n(t)])]),as,e("p",null,[l("文档网站需要不断完善和增加内容,以及完善设计。 因此更欢迎大家一起为文档建设添砖加瓦。 "),e("a",os,[l("文档的仓库"),n(t)])]),rs,is,e("p",null,[l("Xray-core Shadowsocks UDP FullCone 测试版, "),e("a",hs,[l("TG 群"),n(t)]),l("火热测试中")]),_s,cs,e("h2",ds,[e("a",us,[e("span",null,[l("2020.12.18 "),n(a,null,{default:s(()=>[e("a",ps,[l("1.1.4"),n(t)])]),_:1})])])]),fs,bs,e("p",null,[l("鉴于日益增长群人数和游戏需求, 开启了"),e("a",gs,[l("TG 游戏群"),n(t)])]),Xs,e("p",null,[e("a",vs,[l("安装脚本 dev 分支"),n(t)]),l("开启, 持续更新功能中.")]),e("h2",Ss,[e("a",Ts,[e("span",null,[l("2020.12.11 "),n(a,null,{default:s(()=>[e("a",ks,[l("1.1.3"),n(t)])]),_:1})])])]),ms,e("h2",xs,[e("a",ys,[e("span",null,[l("2020.12.06 "),n(a,null,{default:s(()=>[e("a",Ls,[l("1.1.2"),n(t)])]),_:1})])])]),Ps,e("h2",Hs,[e("a",Ds,[e("span",null,[l("2020.11.25 "),n(a,null,{default:s(()=>[e("a",Us,[l("1.0.0"),n(t)])]),_:1})])])]),Rs,Cs,Es,Ns,Is])}const js=_(u,[["render",Vs],["__file","news.html.vue"]]);export{js as default}; +import{_,r as i,o as c,c as d,a as n,b as e,d as l,w as s,e as o}from"./app-D7uBbsY3.js";const u={},p=e("h1",{id:"大史记",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#大史记"},[e("span",null,"大史记")])],-1),f=e("h2",{id:"_2024-9-12",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2024-9-12"},[e("span",null,"2024.9.12")])],-1),b=e("p",null,"大史记重出江湖?!",-1),g={id:"_2024-9-7-v24-9-7",tabindex:"-1"},X={class:"header-anchor",href:"#_2024-9-7-v24-9-7"},v={href:"https://github.com/XTLS/Xray-core/releases/tag/v24.9.7",target:"_blank",rel:"noopener noreferrer"},S=e("p",null,"更改版本号之后的首次发版。",-1),T=e("ul",null,[e("li",null,[l("这次移除了 QUIC 以及 DomainSocket 传输,移除了两处远古配置遗留代码。 "),e("ul",null,[e("li",null,"二进制大小比 v1.8.24 减小了 1MB。")])]),e("li",null,"依然有每次必备的 bug 修复。")],-1),k={id:"_2024-8-30-v1-8-24",tabindex:"-1"},m={class:"header-anchor",href:"#_2024-8-30-v1-8-24"},x={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.24",target:"_blank",rel:"noopener noreferrer"},y=o('

                                      在等待 SplitHTTP multiplex controller 期间,main 分支已经积累了大量重要更新,所以我们决定先发一个版本。

                                      • Socks 入站现在默认兼容 HTTP 代理请求。
                                      • UDP noise (preview)
                                      • 还有一些改进。

                                      由于传统版本号的存在,为每个版本规划功能、进行排期已经严重阻碍了新功能的开发、合并、发布。所以我们决定从下个版本开始弃用传统的版本号,改用发版日期作为版本号,如 v24.8.30,并取消版本规划,全面采用流式更新,写好的功能直接合并,不再等待,预计每月月底发一个版本。

                                      毕竟对于反审查软件来说,相较于传统的版本号,新功能的及时性、每月更新更为重要,而不是发一个功能确定的版本并长期维护。

                                      下个版本会移除一些历史久远的代码,以后日常积累新代码、提醒迁移,跨年新版删代码、breaking。

                                      我们相信有了各位的捐款以及对发版形式的革新,Xray-core 这个项目会发展得更好。

                                      2024.8.26

                                      Project VLESS 群组创立。

                                      ',8),L={href:"https://t.me/projectVless",target:"_blank",rel:"noopener noreferrer"},P=e("h2",{id:"_2024-8-3",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2024-8-3"},[e("span",null,"2024.8.3")])],-1),H={href:"https://github.com/XTLS/Xray-core/discussions/3633",target:"_blank",rel:"noopener noreferrer"},D=e("p",null,"就像 Xray 开创过很多历史一样,发行 NFT 也是这个领域前无古人的操作。这些 NFT 非常有纪念意义,甚至可以说是有历史意义,远大于现在的初始价格,假以时日它们必将价值连城。最后再次感谢大家对 Project X 的支持。",-1),U={id:"_2024-7-29-v1-8-23",tabindex:"-1"},R={class:"header-anchor",href:"#_2024-7-29-v1-8-23"},C={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.23",target:"_blank",rel:"noopener noreferrer"},E={href:"https://github.com/mmmray",target:"_blank",rel:"noopener noreferrer"},N=e("li",null,"优化了 SplitHTTP 上行的稳定性,服务端必须升级到该版本以支持新版客户端。",-1),I=e("li",null,"更多 SplitHTTP 上的变化。",-1),V={id:"_2024-7-22-v1-8-21",tabindex:"-1"},w={class:"header-anchor",href:"#_2024-7-22-v1-8-21"},A={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.21",target:"_blank",rel:"noopener noreferrer"},W=e("p",null,"中间似乎回到了最初的腹泻式发版状态……",-1),j=e("p",null,"正如 v1.8.16 所预告的,SplitHTTP 现已初步支持 HTTP/3(QUIC)。毫无疑问,SplitHTTP H3 已经开启了一个崭新的时代。",-1),B=e("ul",null,[e("li",null,"SplitHTTP H3 是第一个完全基于标准 H3、支持套 CDN 的 QUIC 类代理,亦可用反代、Browser Dialer 来隐蔽自身。")],-1),F=e("h2",{id:"_2024-7-16",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2024-7-16"},[e("span",null,"2024.7.16")])],-1),G={href:"https://github.com/iambabyninja",target:"_blank",rel:"noopener noreferrer"},M=e("blockquote",null,[e("p",null,"Привет, друзья из России!")],-1),q=e("h2",{id:"_2024-7-15",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2024-7-15"},[e("span",null,"2024.7.15")])],-1),O=e("p",null,"虽然日后随着各方面升级 Windows 7 最终会离开,但是现在还是可以让这个时间来得稍微晚一些。",-1),Y={id:"_2024-6-18-v1-8-16",tabindex:"-1"},Q={class:"header-anchor",href:"#_2024-6-18-v1-8-16"},K={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.16",target:"_blank",rel:"noopener noreferrer"},z=e("p",null,"新传输来了,它目前叫 SplitHTTP。",-1),J=e("ul",null,[e("li",null,"实现进一步的流量混淆有两种刚好相反的方式:多路复用与拆分连接。"),e("li",null,"可以通过不支持 WebSocket、gRPC 的 CDN,实现与 Meek 相同的目标,且 SplitHTTP 比 Meek 更简单、效率更高。"),e("li",null,"SplitHTTP 没有 WebSocket 的 ALPN 问题,这是一大优势,未来还会支持 HTTP/3(QUIC)。"),e("li",null,"另外 SplitHTTP 也已经加入分享链接套餐~")],-1),Z=e("h2",{id:"_2024-6-2",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2024-6-2"},[e("span",null,"2024.6.2")])],-1),$=e("p",null,"一个新的传输方式正在被打造……",-1),ee={id:"_2024-4-26-v1-8-11",tabindex:"-1"},le={class:"header-anchor",href:"#_2024-4-26-v1-8-11"},ne={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.11",target:"_blank",rel:"noopener noreferrer"},te=e("ul",null,[e("li",null,"现在有了生成 ECH 密钥的工具。"),e("li",null,"增强、修复,并移除了一点不再使用的代码。")],-1),se=e("h2",{id:"_2024-4-20",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2024-4-20"},[e("span",null,"2024.4.20")])],-1),ae={href:"https://github.com/Fangliding",target:"_blank",rel:"noopener noreferrer"},oe=e("h2",{id:"_2024-4-13",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2024-4-13"},[e("span",null,"2024.4.13")])],-1),re=e("p",null,"VLESS Seed 整备完毕,待势而发。",-1),ie={id:"_2024-3-18-v1-8-10",tabindex:"-1"},he={class:"header-anchor",href:"#_2024-3-18-v1-8-10"},_e={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.10",target:"_blank",rel:"noopener noreferrer"},ce=e("p",null,"和 WebSocket 一样,HTTPUpgrade 也有 0-RTT 了。",-1),de={id:"_2024-3-11-v1-8-9",tabindex:"-1"},ue={class:"header-anchor",href:"#_2024-3-11-v1-8-9"},pe={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.9",target:"_blank",rel:"noopener noreferrer"},fe=e("p",null,"新增 HTTPUpgrade 传输,听说比 WebSocket 要轻。",-1),be=e("ul",null,[e("li",null,"已加入分享链接套餐~")],-1),ge=e("h2",{id:"_2024-2-29",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2024-2-29"},[e("span",null,"2024.2.29")])],-1),Xe=e("p",null,[l("gRPC 传输现在也有 Host 一样的配置字段了!它叫 "),e("code",null,"authority"),l("。这下 gRPC 也能“域前置”了,没有 ALPN 问题。")],-1),ve={id:"_2024-2-25-v1-8-8",tabindex:"-1"},Se={class:"header-anchor",href:"#_2024-2-25-v1-8-8"},Te={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.8",target:"_blank",rel:"noopener noreferrer"},ke=e("ul",null,[e("li",null,"现在 XUDP 流量统一使用 Vision 填充了,速来体验。"),e("li",null,"新增了 leastLoad balancer。"),e("li",null,"修复错误、优化性能……")],-1),me=e("h2",{id:"_2024-1-9",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2024-1-9"},[e("span",null,"2024.1.9")])],-1),xe=e("p",null,"惊闻 Win7 无法运行新版 Xray-core?探索之下竟发现 Go 放弃了对 Win7 的支持。有什么办法能继续支持这个有些古老但是依然优雅的操作系统吗?",-1),ye=e("h2",{id:"_2023-11-21",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2023-11-21"},[e("span",null,"2023.11.21")])],-1),Le={href:"https://t.me/projectXtls/212",target:"_blank",rel:"noopener noreferrer"},Pe=e("p",null,"而 XTLS 也不会止步于此,如 X 射线一般穿破高耸的围墙。",-1),He={id:"_2023-11-18-v1-8-6",tabindex:"-1"},De={class:"header-anchor",href:"#_2023-11-18-v1-8-6"},Ue={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.6",target:"_blank",rel:"noopener noreferrer"},Re=o('
                                      • WireGuard 现在也有了对应的入站。Freedom 出站也终于有了 splice。
                                      • 现在出站的 domainStrategy 也得到了统一。
                                      • 更多的美味小点心。
                                      • 因为 不可抗力 功能变更,Dragonfly BSD 支持黯然离场。
                                      • 我们真的要对一代经典 Windows 7 说再见了吗?

                                      2023.9.30

                                      为 v2rayNG 设计了全新的配色,安装最新的 Pre-release 版本即可体验。

                                      ',3),Ce={id:"_2023-8-29-v1-8-4",tabindex:"-1"},Ee={class:"header-anchor",href:"#_2023-8-29-v1-8-4"},Ne={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.4",target:"_blank",rel:"noopener noreferrer"},Ie=o('

                                      1.8.x 在经过半年的打磨后终于来到了第一个认可的正式版了。

                                      同样地,这次集成的改进也不少,速来品尝!

                                      2023.7.22

                                      又修好了一个 HTTP/2 传输的历史遗留断流问题。

                                      2023.7.7

                                      即将给 Vision 添加 Seed 支持。

                                      2023.6.30

                                      下一个 XTLS 流控:xtls-rprx-switch 🍪

                                      • XTLS 的 0-RTT 已经预告几个月了,本来也是想保留神秘感。
                                      • 对比现有的 XTLS Vision 和 Mux 有着更加不错的优势。

                                      2023.6.27

                                      ',10),Ve={href:"https://github.com/XTLS/Xray-core/discussions/2256#discussioncomment-6295296",target:"_blank",rel:"noopener noreferrer"},we={id:"_2023-6-19-v1-8-3",tabindex:"-1"},Ae={class:"header-anchor",href:"#_2023-6-19-v1-8-3"},We={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.3",target:"_blank",rel:"noopener noreferrer"},je=o('
                                      • 精简代码计划后的第一个版本,VMess (MD5)、MTProto 以及 Starlark 相关代码已被卸下。轻装上阵。
                                      • 对代码进重构也是轻装上阵的一部分。
                                      • 同时我们也没有忘记增添一些增强功能,还有修复漏洞。
                                      • v1.8.3 为今年的最后一个版本。

                                      2023.6.6

                                      好消息:下一个 XTLS 流控不叫 Vision。 🍪

                                      2023.4.21

                                      ',4),Be={href:"https://github.com/XTLS/RealiTLScanner",target:"_blank",rel:"noopener noreferrer"},Fe=e("h2",{id:"_2023-4-20",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2023-4-20"},[e("span",null,"2023.4.20")])],-1),Ge={href:"https://github.com/XTLS/Xray-core/discussions/1967",target:"_blank",rel:"noopener noreferrer"},Me=e("h2",{id:"_2023-4-19",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2023-4-19"},[e("span",null,"2023.4.19")])],-1),qe=e("p",null,[e("code",null,"xtls-0rtt-vision(-udp443)"),l(" 🍪")],-1),Oe={id:"_2023-4-18-v1-8-1",tabindex:"-1"},Ye={class:"header-anchor",href:"#_2023-4-18-v1-8-1"},Qe={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.1",target:"_blank",rel:"noopener noreferrer"},Ke=o('

                                      升级后的 XUDP 也来了!

                                      • 现在 XUDP 也带有连接迁移、端口复用的特性,并且带有全局 Session ID ,麻麻再也不用担心意外断线的时候怎么办了
                                      • 同时我们也添加了 XUDP 的控制配置,让你能更好掌控它~
                                      • 新的 XUDP 配合 XTLS Vision 食用风味更好喔~
                                      • 惯例还有小甜点,欢迎品尝~

                                      2023.4.6

                                      XUDP 也在悄然升级……

                                      2023.3.29

                                      PLUX protocol 🍪

                                      2023.3.19

                                      对 REALITY 的分享链接标准也已经出现了。

                                      ',8),ze={id:"_2023-3-9-v1-8-0",tabindex:"-1"},Je={class:"header-anchor",href:"#_2023-3-9-v1-8-0"},Ze={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.0",target:"_blank",rel:"noopener noreferrer"},$e=o('

                                      THE NEXT FUTURE, REALITY is NOW release on Xray-core

                                      REALITY 已经实装发版!欢迎体验! XTLS Vision 也已经完善,请两端升级至最新版食用。

                                      • 因为这次 Vision 填充算法改变,XTLS Vision 旧版和新版之间会存在兼容性问题。
                                      • HTTP/2 传输也已经做了改善,现在使用新版即可纵享丝滑~
                                      • 还有大量小改进欢迎体验~

                                      2023.3.4

                                      Legends never die, they become a part of you VLESS.

                                      They simply fade away.

                                      2023.3.2

                                      HTTP/2 传输的一些遗留问题已经被改善,欢迎搭配 REALITY 测试纵享丝滑~

                                      2023.2.16

                                      THE NEXT FUTURE becomes THE REALITY NOW!

                                      2023.2.9

                                      REALITY is reality now!

                                      ',11),el={id:"_2023-2-8-v1-7-5",tabindex:"-1"},ll={class:"header-anchor",href:"#_2023-2-8-v1-7-5"},nl={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.7.5",target:"_blank",rel:"noopener noreferrer"},tl=e("p",null,"Keep riding and never look back.",-1),sl={href:"https://github.com/yuhan6665",target:"_blank",rel:"noopener noreferrer"},al=e("li",null,"XTLS Vision 流控已经接近完善,即将实用。",-1),ol=e("li",null,"现在对 uTLS 指纹模拟添加了更多可选项,有哪一款适合你?",-1),rl=e("li",null,"分享链接也支持同时分享 uTLS 指纹配置了。",-1),il=e("li",null,"还有更多的功能增强和修复。",-1),hl=e("li",null,[l("这一版也是能最后一次看到 XTLS Origin、Direct 和 Splice 流控的一版了。 "),e("s",null,"有点伤感不是吗?")],-1),_l=e("h2",{id:"_2023-1-29",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2023-1-29"},[e("span",null,"2023.1.29")])],-1),cl=e("p",null,"Winter cannot cover the NEXT FUTURE...",-1),dl={id:"_2022-12-26-v1-7-0",tabindex:"-1"},ul={class:"header-anchor",href:"#_2022-12-26-v1-7-0"},pl={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.7.0",target:"_blank",rel:"noopener noreferrer"},fl=e("p",null,"因为手滑,这次的版本号直接大升,感谢大家支持!",-1),bl=e("ul",null,[e("li",null,"以后将会严格执行 Semantic Versioning。")],-1),gl={id:"_2022-11-28-v1-6-5",tabindex:"-1"},Xl={class:"header-anchor",href:"#_2022-11-28-v1-6-5"},vl={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.6.5",target:"_blank",rel:"noopener noreferrer"},Sl=e("p",null,"这次我们有了 WireGuard 出站。",-1),Tl=e("ul",null,[e("li",null,"使用 WireGuard 搭配 CF WARP 使用可以解锁有趣的新玩法呢。"),e("li",null,"同样安全更新和修复也不会少。")],-1),kl={id:"_2022-11-7-v1-6-3",tabindex:"-1"},ml={class:"header-anchor",href:"#_2022-11-7-v1-6-3"},xl={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.6.3",target:"_blank",rel:"noopener noreferrer"},yl=e("p",null,[l("现在 Vision 流控也能使用 uTLS 指纹模拟了,这就是使用 "),e("code",null,"tlsSettings"),l(" 带来的好处吗!")],-1),Ll={id:"_2022-10-29-v1-6-2",tabindex:"-1"},Pl={class:"header-anchor",href:"#_2022-10-29-v1-6-2"},Hl={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.6.2",target:"_blank",rel:"noopener noreferrer"},Dl=e("p",null,"第一个包含 Vision 流控的发行版已经放出!欢迎试用并提交反馈!",-1),Ul={id:"_2022-10-22-v1-6-1",tabindex:"-1"},Rl={class:"header-anchor",href:"#_2022-10-22-v1-6-1"},Cl={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.6.1",target:"_blank",rel:"noopener noreferrer"},El=o('
                                      • 为 WebSocket、HTTP/2 以及 gRPC 传输带来了 uTLS 指纹支持!
                                        • 之前只有普通 TLS 下 TCP 传输能用的选项现在更好用了。
                                      • Linux 下可以单独为出入口设置 TCP 拥塞控制了。

                                      2022.10.3

                                      天气渐凉,但是并没有凉下开发的脚步。封锁天降,但无法阻止前行……

                                      • 新的 XTLS 流控酝酿中……
                                        • 解决之前流控已有的问题;
                                        • 对 TLS 1.3 直接启用 splice;
                                        • 增加 TLS 握手长度混淆;
                                        • 简化代码,使用 tlsSettings 而不是 xtlsSettings……
                                      ',4),Nl={id:"_2022-8-28-v1-5-10",tabindex:"-1"},Il={class:"header-anchor",href:"#_2022-8-28-v1-5-10"},Vl={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.5.10",target:"_blank",rel:"noopener noreferrer"},wl=e("p",null,"底层传输支持更合理的 TCP Keepalive 配置了。",-1),Al={id:"_2022-6-20-v1-5-8",tabindex:"-1"},Wl={class:"header-anchor",href:"#_2022-6-20-v1-5-8"},jl={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.5.8",target:"_blank",rel:"noopener noreferrer"},Bl=e("p",null,"现在 Shadowsocks-2022 的 relay 中转也受支持了。",-1),Fl={id:"_2022-5-29-v1-5-6",tabindex:"-1"},Gl={class:"header-anchor",href:"#_2022-5-29-v1-5-6"},Ml={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.5.6",target:"_blank",rel:"noopener noreferrer"},ql=e("p",null,"Shadowsocks-2022 协议来到了 Xray-core!",-1),Ol={href:"https://github.com/nekohasekai",target:"_blank",rel:"noopener noreferrer"},Yl={href:"https://github.com/database64128",target:"_blank",rel:"noopener noreferrer"},Ql={href:"https://github.com/RPRX",target:"_blank",rel:"noopener noreferrer"},Kl=e("p",null,"Shadowsocks-2022 是重新设计的全新协议:",-1),zl=e("ul",null,[e("li",null,"在保留 Shadowsocks 原生 udp 的基础上解决了重放攻击等安全问题(与 vmess 一样使用时间戳,因此客户端与服务端需要时间一致)。"),e("li",null,"支持单端口多用户,并且参考 quic、wireguard 等协议设计与实现使用了 session 机制,减低加密负担,保证网络变动时的无缝迁移。")],-1),Jl={id:"_2022-4-24-v1-5-5",tabindex:"-1"},Zl={class:"header-anchor",href:"#_2022-4-24-v1-5-5"},$l={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.5.5",target:"_blank",rel:"noopener noreferrer"},en=e("p",null,"这次带来了方便可视化的检测数据接口!快来体验!",-1),ln=e("ul",null,[e("li",null,"顺便修复了一些影响使用体验的问题。")],-1),nn={id:"_2022-3-13-v1-5-4",tabindex:"-1"},tn={class:"header-anchor",href:"#_2022-3-13-v1-5-4"},sn={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.5.4",target:"_blank",rel:"noopener noreferrer"},an=e("p",null,"给 Windows 平台加上了没有黑窗冒出的 wxray.exe 文件,并带来了对 UDS 监听的增强。",-1),on={id:"_2022-1-29-v1-5-3",tabindex:"-1"},rn={class:"header-anchor",href:"#_2022-1-29-v1-5-3"},hn={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.5.3",target:"_blank",rel:"noopener noreferrer"},_n=e("p",null,"牛辞胜岁,虎跃新程。🧨",-1),cn=e("ul",null,[e("li",null,"这次带来了对 QUIC 传输的流分配改进,使用 QUIC 传输现在更丝滑了。")],-1),dn={id:"_2021-12-24-v1-5-2",tabindex:"-1"},un={class:"header-anchor",href:"#_2021-12-24-v1-5-2"},pn={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.5.2",target:"_blank",rel:"noopener noreferrer"},fn=e("p",null,"为 gRPC 添加了一个新的选项,在通过 CDN 时变得更好用了。",-1),bn={id:"_2021-12-15-v1-5-1",tabindex:"-1"},gn={class:"header-anchor",href:"#_2021-12-15-v1-5-1"},Xn={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.5.1",target:"_blank",rel:"noopener noreferrer"},vn=e("blockquote",null,[e("p",null,"“过渡时期的阶段性的维护版本”")],-1),Sn=e("ul",null,[e("li",null,"新功能、增强还有大量修复陆续有来。"),e("li",null,[l("记得将 VMess 配置中的 "),e("code",null,"alterID"),l(" 去掉!")])],-1),Tn={id:"_2021-10-20-v1-5-0",tabindex:"-1"},kn={class:"header-anchor",href:"#_2021-10-20-v1-5-0"},mn={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.5.0",target:"_blank",rel:"noopener noreferrer"},xn=e("p",null,"真的是巨大的改动!",-1),yn=e("ul",null,[e("li",null,"重构了 DNS 组件,支持的协议和细化配置更多了。"),e("li",null,"增强了 gRPC 传输以及 FakeDNS。"),e("li",null,"现在终于支持 Windows ARM64 了。"),e("li",null,"更多新功能和改进等待体验。")],-1),Ln={id:"_2021-9-23-v1-4-5",tabindex:"-1"},Pn={class:"header-anchor",href:"#_2021-9-23-v1-4-5"},Hn={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.4.5",target:"_blank",rel:"noopener noreferrer"},Dn=o('

                                      中秋快乐,阖家团圆。

                                      • 修正了版本号过低,版本号不吉利的 bug。
                                      • 这次移除了 Shadowsocks 里面已经不安全的加密方式。要尽快迁移到 AEAD 加密上面喔。
                                      • 这次修复了远古时期开始就存在的历史问题:开启流量统计功能可能会使性能下降。简单来说,不论什么配置现在打开统计都不会对性能有任何影响了。
                                      • 还有对 XTLS 的安全性更新以及大量修复。
                                      • 对了,因为 TLS 库的更新,cipherSuites 不能再指定加密套件顺序了,而 preferServerCipherSuites 已经被彻底弃用。事实上这些变化在 Xray-core v1.4.3 中已经产生了。

                                      2021.9.16

                                      ',3),Un={href:"https://xtls.github.io/",target:"_blank",rel:"noopener noreferrer"},Rn={id:"_2021-9-8-v1-4-3",tabindex:"-1"},Cn={class:"header-anchor",href:"#_2021-9-8-v1-4-3"},En={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.4.3",target:"_blank",rel:"noopener noreferrer"},Nn=o('

                                      这是一个阶段性维护版本。开发仍在继续……

                                      • 在此期间累积了大量改进和新功能。
                                      • 加入新的 DomainMatcher,现在域名规则匹配性能更好了。
                                      • 加入对 HTTP/2 和 gRPC 传输的健康检查、对未知 SNI 的处理改进,以及修复了一大堆 bug。

                                      Helden sterben nicht!

                                      2021.7.14

                                      • AnXray 重金设计 的新图标已经上线!
                                        • 现在图标的辨识度更高了。
                                      • 过去三个星期,AnXray 共积累了 600 stars、2K+ 频道订阅数和 11K+ GitHub 下载量,感谢大家的支持。
                                      • AX 为 AnXray 的缩写,推荐用 AX 指代 AnXray,简短方便

                                      2021.6.21

                                      ',6),In={href:"https://github.com/XTLS/AnXray",target:"_blank",rel:"noopener noreferrer"},Vn={href:"https://github.com/nekohasekai",target:"_blank",rel:"noopener noreferrer"},wn=e("li",null,"支持众多协议、插件.",-1),An={href:"https://github.com/RPRX",target:"_blank",rel:"noopener noreferrer"},Wn=e("li",null,"APP 内还有个小彩蛋等你去发现。",-1),jn=o('

                                      前两天从早到晚反复打磨细节,希望大家多多 Star、关注。

                                      2021.5.1

                                      对 tun2socks 的改进出现在 v2rayNG 上面了。

                                      2021.4.26

                                      给 tun2socks 带来了一个改进。后续有可能能吃到它~

                                      2021.4.12

                                      现在带来了 X-flutter 前瞻,可以期待一下会是什么样子呢~ 🍪

                                      2021.4.6

                                      • VuePress Next.
                                      • With Dark Mode.

                                      2021.4.4

                                      • 本文档迎来的新的首页。
                                      • 本文档迎来了暗黑模式。
                                      • 当然,暗黑模式还有各种各样的问题。具体的内容还需要慢慢调整。
                                      • 另:Telegram 群聊突破了 5000 人!还加入了 Anti-Spam 机器人!
                                      • 🎉🎉🎉
                                      ',11),Bn={id:"_2021-4-1-v1-4-2",tabindex:"-1"},Fn={class:"header-anchor",href:"#_2021-4-1-v1-4-2"},Gn={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.4.2",target:"_blank",rel:"noopener noreferrer"},Mn=o('
                                      • 不是愚人节玩笑,今天更新。
                                      • 加入 Browser Dialer,用与改变 TLS 指纹与行为。
                                      • 加入 uTLS,用与改变 TLS Client Hello 的指纹。
                                      • 顺便修复了一大堆奇妙的问题,具体的内容见更新日志。

                                      2021.3.25

                                      没错还在变。 -_-

                                      2021.3.15

                                      文档网站正在悄悄的进行着某些神秘的变化。。。,🙊🙊🙊

                                      ',5),qn={id:"_2021-3-14-v1-4-0",tabindex:"-1"},On={class:"header-anchor",href:"#_2021-3-14-v1-4-0"},Yn={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.4.0",target:"_blank",rel:"noopener noreferrer"},Qn=o("
                                      • Happy Pi-Day!
                                      • 这次是个大更新:
                                        • 为链式代理引入了传输层支持。
                                        • 为 Dialer 引入了 Domain Strategy,解决奇妙的 DNS 问题。
                                        • 添加了 gRPC 传输方式,与更快一点的 Multi Mode。
                                        • 添加了 WebSocket Early-Data 功能,减少了 WebSocket 的延迟。
                                        • 添加了 FakeDNS。
                                        • 还修复了系列的问题,添加了各类功能,详情请见更新日志。
                                      • 还是 VuePress 比较爽啊(
                                      ",1),Kn={id:"_2021-3-3-1-3-1",tabindex:"-1"},zn={class:"header-anchor",href:"#_2021-3-3-1-3-1"},Jn={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.3.1",target:"_blank",rel:"noopener noreferrer"},Zn=e("ul",null,[e("li",null,"这个版本使用了 Golang 1.16,正式原生支持 Apple Silicon。"),e("li",null,[l("同时修复了一个会导致 Panic 的 bug。"),e("s",null,"Holmium_认为这是在骗、在偷袭。")]),e("li",null,"修复了几个遗留问题。")],-1),$n={id:"_2021-2-14-1-3-0",tabindex:"-1"},et={class:"header-anchor",href:"#_2021-2-14-1-3-0"},lt={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.3.0",target:"_blank",rel:"noopener noreferrer"},nt=e("ul",null,[e("li",null,"Happy 🐮 Year 🎉!"),e("li",null,"v1.3.0 通过非常巧妙的机制实现了 V 系协议全部 FullCone,同时保证了一定的兼容性。"),e("li",null,"OHHHHHHHHHHHH!")],-1),tt={id:"_2021-01-31-1-2-4",tabindex:"-1"},st={class:"header-anchor",href:"#_2021-01-31-1-2-4"},at={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.2.4",target:"_blank",rel:"noopener noreferrer"},ot=e("ul",null,[e("li",null,"解决两个“连接至标准 Socks 服务端时可能出错”的历史遗留问题。"),e("li",null,"似乎这个版本没有什么改变,但这只是暴风雨前的宁静。"),e("li",null,[l("(没错我就是先知) "),e("blockquote",null,[e("p",null,"你个傻子,你拿的是 UNO 牌。")])])],-1),rt=e("h2",{id:"_2021-01-25",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2021-01-25"},[e("span",null,"2021.01.25")])],-1),it=e("li",null,[e("a",{href:"../en"},"英文版文档网站"),l("逐渐增加内容 ing, 感谢各位大佬的辛苦付出~!")],-1),ht={id:"_2021-01-22-1-2-3",tabindex:"-1"},_t={class:"header-anchor",href:"#_2021-01-22-1-2-3"},ct={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.2.3",target:"_blank",rel:"noopener noreferrer"},dt=e("li",null,[l("对 SS 协议的支持"),e("strong",null,"又"),l("变强了, 支持单端口多用户!")],-1),ut=e("li",null,[l("对 trojan 协议的支持也"),e("strong",null,"又"),l("变强了, trojan 的回落也解锁 SNI 分流的新姿势啦~!")],-1),pt=e("li",null,[e("em",null,"(VLESS: 嘤嘤嘤)")],-1),ft=e("li",null,'UDP 奇奇怪怪的 BUG 被干掉了, 一个字, "稳定".',-1),bt=e("li",null,"嗅探可以排除你不想嗅探的域名, 可以开启一些新玩法.",-1),gt={href:"https://github.com/bohanyang",target:"_blank",rel:"noopener noreferrer"},Xt=e("li",null,"其他美味小樱桃, 惯例更新品尝就对啦.",-1),vt=o('

                                      2021.01.19

                                      • 一些数字
                                        • 版本发布了 10   个 tag
                                        • 解决掉了 100  个 issue
                                        • 复刻了 300  个 fork
                                        • 点了 2000 个 star
                                        • 群 3000 个 人

                                      2021.01.17

                                      ',3),St={href:"https://github.com/jiuqi9997",target:"_blank",rel:"noopener noreferrer"},Tt={href:"https://xtls.github.io/en/",target:"_blank",rel:"noopener noreferrer"},kt={id:"_2021-01-15-1-2-2",tabindex:"-1"},mt={class:"header-anchor",href:"#_2021-01-15-1-2-2"},xt={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.2.2",target:"_blank",rel:"noopener noreferrer"},yt=o('
                                      • 回落分流又解锁了奇怪的新姿势! 回落中可以根据 SNI 分流啦~!
                                      • 之前预告的 UUID 修改正式上线.(往下看往下看)
                                      • 日志现在看起来比上一次顺眼又更顺眼了一丢丢.
                                      • 远程 DOH 和其他的 DNS 模式一样学会了走路由分流.
                                      • 当然还有其他各种小糖果.(更新品尝就对了)
                                      • 啊, 还有, 世界上第一個 M1 上跑起 Xray 的男人是 Anthony TSE

                                      2021.01.12

                                      ',2),Lt=e("li",null,[l("将要到来的 UUID 修改, 支持自定义字符串和 UUID 之间的映射. 这意味着你将可以这样在配置文件中写 id 来对应用户. "),e("ul",null,[e("li",null,'客户端写 "id": "我爱 🍉 老师 1314",'),e("li",null,[l('服务端写 "id": "5783a3e7-e373-51cd-8642-c83782b807c5" (此 UUID 是 '),e("code",null,"我爱🍉老师1314"),l(" 的 UUID 映射)")])])],-1),Pt={id:"_2021-01-10-1-2-1",tabindex:"-1"},Ht={class:"header-anchor",href:"#_2021-01-10-1-2-1"},Dt={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.2.1",target:"_blank",rel:"noopener noreferrer"},Ut=e("li",null,"(可能是整个互联网上, 最详细最有耐心的教你从 0 开始配置的教程)",-1),Rt=e("li",null,"还有很多细节修改, 文档将会越来越规范!",-1),Ct={href:"https://github.com/ricuhkaen",target:"_blank",rel:"noopener noreferrer"},Et={href:"https://github.com/BioniCosmos",target:"_blank",rel:"noopener noreferrer"},Nt={href:"https://github.com/kirin10000",target:"_blank",rel:"noopener noreferrer"},It=o('
                                      • 大量的 UDP 相关修复, 甚至可以在育碧的土豆服务器上玩彩虹六号!
                                      • Google Voice 应该也可以正常使用 v2rayNG 拨打了.
                                      • 日志现在看起来更顺眼.

                                      2021.01.07

                                      • 礼貌和尊重本应是社区不需要明说的准则之一。

                                      2021.01.05

                                      • 文档网站正在悄悄的进行着某些神秘的变化。。。,🙊🙊🙊

                                      2021.01.03

                                      ',6),Vt={href:"https://github.com/BioniCosmos",target:"_blank",rel:"noopener noreferrer"},wt=e("li",null,"tg 群突破 2500。",-1),At=e("h2",{id:"_2021-01-01",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2021-01-01"},[e("span",null,"2021.01.01")])],-1),Wt={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.2.0",target:"_blank",rel:"noopener noreferrer"},jt=e("p",null,"🎁 在元旦的最后几分钟,v1.2.0 它来了,带着周五必更的惯例,带着各位贡献大佬的心血以及 @rprxx 的黑眼圈,不负众望的来了!",-1),Bt=o('
                                    40. 圣诞礼物v1.1.5后的元旦礼物 🎁,游戏玩家大福利,全面 FullCone。
                                    41. (UDP 还会继续增强!)
                                    42. 如果你已经拆过圣诞礼物,这次还有比圣诞礼物更精美的包装和小糖果哦。(同样不用问,更新品尝就对了)
                                    43. (不,下面不是广告,是里程碑。)
                                    44. Xray 是有史以来第一个不受限制的多协议平台:只需 Xray 即可解决问题,无需借力其它实现。
                                      • 一人扛起了所有!支持各大主流协议!
                                      • 一骑绝尘的性能!
                                      • 日趋完善的功能!
                                      • 可怕的生命力与社区亲和力!
                                    45. ',5),Ft={href:"https://github.com/XTLS/Xray-core/discussions/56",target:"_blank",rel:"noopener noreferrer"},Gt={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.2.0",target:"_blank",rel:"noopener noreferrer"},Mt=e("s",null,"(啊,有人敲门...我一会和你们说)",-1),qt=e("h2",{id:"_2020-12-29",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2020-12-29"},[e("span",null,"2020.12.29")])],-1),Ot={href:"https://t.me/projectXray",target:"_blank",rel:"noopener noreferrer"},Yt={id:"_2020-12-25-1-1-5",tabindex:"-1"},Qt={class:"header-anchor",href:"#_2020-12-25-1-1-5"},Kt={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.1.5",target:"_blank",rel:"noopener noreferrer"},zt=e("p",null,"圣诞节快乐!",-1),Jt=e("li",null,"游戏玩家的圣诞礼物!你可以用 xray 爽快的打游戏啦!因为有了 SS/trojan UDP fullcone",-1),Zt=e("li",null,"你可以用你喜欢的格式写配置文件了,比如 yaml,比如 toml...",-1),$t=e("li",null,"(VLESS 的 UDP fullcone 和更多增强很快就到!)",-1),es=e("li",null,"无须再担心证书验证被墙,OCSP stapling 已经上线!",-1),ls={href:"https://github.com/XTLS/Xray-install",target:"_blank",rel:"noopener noreferrer"},ns=e("li",null,"还有更多美味小樱桃!(不用问,更新品尝就对了)",-1),ts=e("h2",{id:"_2020-12-24",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2020-12-24"},[e("span",null,"2020.12.24")])],-1),ss={href:"https://xtls.github.io",target:"_blank",rel:"noopener noreferrer"},as=e("p",null,"大家可以查阅各种内容也欢迎纠错/提出建议(可发往文档 github 仓库的 issue 区)",-1),os={href:"https://github.com/XTLS/XTLS.github.io",target:"_blank",rel:"noopener noreferrer"},rs=e("p",null,"仓库的 readme 中有简略教程说明如何帮助 xray 改进文档网站. 欢迎大家查看,纠错,修改,增加心得。",-1),is=e("h2",{id:"_2020-12-23",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2020-12-23"},[e("span",null,"2020.12.23")])],-1),hs={href:"https://t.me/projectXray",target:"_blank",rel:"noopener noreferrer"},_s=e("h2",{id:"_2020-12-21",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2020-12-21"},[e("span",null,"2020.12.21")])],-1),cs=e("ul",null,[e("li",null,"Project X 群人数 2000+"),e("li",null,"群消息(含游戏群) 日均破万")],-1),ds={id:"_2020-12-18-1-1-4",tabindex:"-1"},us={class:"header-anchor",href:"#_2020-12-18-1-1-4"},ps={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.1.4",target:"_blank",rel:"noopener noreferrer"},fs=e("ul",null,[e("li",null,"更低的启动内占用和内存使用优化"),e("li",null,"随意定制的 TLS 提高你的 SSL 评级"),e("li",null,"支持 XTLS 入站的 Splice 以及支持 trojan 的 XTLS"),e("li",null,"还有在您路由器上使用的 Splice 最佳使用模式建议")],-1),bs=e("h2",{id:"_2020-12-17",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2020-12-17"},[e("span",null,"2020.12.17")])],-1),gs={href:"https://t.me/joinchat/UO4NixbB_XDQJOUjS6mHEQ",target:"_blank",rel:"noopener noreferrer"},Xs=e("h2",{id:"_2020-12-15",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2020-12-15"},[e("span",null,"2020.12.15")])],-1),vs={href:"https://github.com/XTLS/Xray-install/tree/dev",target:"_blank",rel:"noopener noreferrer"},Ss={id:"_2020-12-11-1-1-3",tabindex:"-1"},Ts={class:"header-anchor",href:"#_2020-12-11-1-1-3"},ks={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.1.3",target:"_blank",rel:"noopener noreferrer"},ms=e("ul",null,[e("li",null,"完整版本的 REDIRECT 透明代理模式."),e("li",null,"软路由 splice 流控模式的优化建议.")],-1),xs={id:"_2020-12-06-1-1-2",tabindex:"-1"},ys={class:"header-anchor",href:"#_2020-12-06-1-1-2"},Ls={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.1.2",target:"_blank",rel:"noopener noreferrer"},Ps=o('
                                      • 流控增加 splice 模式, Linux 限定, 性能一骑绝尘.
                                      • 增强了 API 兼容

                                      2020.12.04

                                      增加 splice 模式

                                      2020.11.27

                                      • Project X 的 GitHub 主仓库 Xray-core 已获 500+ stars
                                      • 登上了 GitHub Trending
                                      • Project X 群人数破千,频道订阅数 500+
                                      ',5),Hs={id:"_2020-11-25-1-0-0",tabindex:"-1"},Ds={class:"header-anchor",href:"#_2020-11-25-1-0-0"},Us={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.0.0",target:"_blank",rel:"noopener noreferrer"},Rs=e("p",null,"Xray 的第一个版本.",-1),Cs=e("ul",null,[e("li",null,"基于 v2ray-core 修改而来,改动较大"),e("li",null,"全面增强, 性能卓越, 完全兼容")],-1),Es=e("h2",{id:"_2020-11-23",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2020-11-23"},[e("span",null,"2020.11.23")])],-1),Ns=e("p",null,"project X start",-1),Is=e("blockquote",null,[e("p",null,[e("s",null,"梦开始的时候")])],-1);function Vs(ws,As){const h=i("I18nTip"),t=i("ExternalLinkIcon"),a=i("Badge"),r=i("RouterLink");return c(),d("div",null,[p,n(h),f,b,e("h2",g,[e("a",X,[e("span",null,[l("2024.9.7 "),n(a,null,{default:s(()=>[e("a",v,[l("v24.9.7"),n(t)])]),_:1})])])]),S,T,e("h2",k,[e("a",m,[e("span",null,[l("2024.8.30 "),n(a,null,{default:s(()=>[e("a",x,[l("v1.8.24"),n(t)])]),_:1})])])]),y,e("p",null,[l("We have created "),e("a",L,[l("Project VLESS"),n(t)]),l(" for non-Chinese users (mainly Russian).")]),P,e("p",null,[l("第一个 "),e("a",H,[l("Project X NFT"),n(t)]),l(" 正式发行!")]),D,e("h2",U,[e("a",R,[e("span",null,[l("2024.7.29 "),n(a,null,{default:s(()=>[e("a",C,[l("v1.8.23"),n(t)])]),_:1})])])]),e("ul",null,[e("li",null,[l("恭喜 "),e("a",E,[l("@mmmray"),n(t)]),l(" 贡献了 Xray-core 的第 1000 个 commit!")]),N,I]),e("h2",V,[e("a",w,[e("span",null,[l("2024.7.22 "),n(a,null,{default:s(()=>[e("a",A,[l("v1.8.21"),n(t)])]),_:1})])])]),W,j,B,F,e("p",null,[l("Project X 文档迎来了俄语版!感谢 "),e("a",G,[l("@iambabyninja"),n(t)]),l(" 的翻译!")]),M,q,e("p",null,[l("通过已知信息以及努力,Xray-core 现在重新支持 Windows 7!在后续的发版中,Windows 7 用户下载名为 Xray-win7-32.zip 或 Xray-win7-64.zip 的压缩包解压即可享受,感谢大家的支持!具体使用方式请点"),n(r,{to:"/document/install.html"},{default:s(()=>[l("这里")]),_:1})]),O,e("h2",Y,[e("a",Q,[e("span",null,[l("2024.6.18 "),n(a,null,{default:s(()=>[e("a",K,[l("v1.8.16"),n(t)])]),_:1})])])]),z,J,Z,$,e("h2",ee,[e("a",le,[e("span",null,[l("2024.4.26 "),n(a,null,{default:s(()=>[e("a",ne,[l("v1.8.11"),n(t)])]),_:1})])])]),te,se,e("p",null,[l("我们现在有了 issues 模板,感谢 "),e("a",ae,[l("@Fangliding"),n(t)]),l(" !")]),oe,re,e("h2",ie,[e("a",he,[e("span",null,[l("2024.3.18 "),n(a,null,{default:s(()=>[e("a",_e,[l("v1.8.10"),n(t)])]),_:1})])])]),ce,e("h2",de,[e("a",ue,[e("span",null,[l("2024.3.11 "),n(a,null,{default:s(()=>[e("a",pe,[l("v1.8.9"),n(t)])]),_:1})])])]),fe,be,ge,Xe,e("h2",ve,[e("a",Se,[e("span",null,[l("2024.2.25 "),n(a,null,{default:s(()=>[e("a",Te,[l("v1.8.8"),n(t)])]),_:1})])])]),ke,me,xe,ye,e("p",null,[l("发表在 USENIX 顶会的"),e("a",Le,[l("论文"),n(t)]),l("证实,XTLS Vision 已经达到它的设计目标。")]),Pe,e("h2",He,[e("a",De,[e("span",null,[l("2023.11.18 "),n(a,null,{default:s(()=>[e("a",Ue,[l("v1.8.6"),n(t)])]),_:1})])])]),Re,e("h2",Ce,[e("a",Ee,[e("span",null,[l("2023.8.29 "),n(a,null,{default:s(()=>[e("a",Ne,[l("v1.8.4"),n(t)])]),_:1})])])]),Ie,e("p",null,[e("a",Ve,[l("如何选取 REALITY 目标域名?来看这里助你事半功倍!"),n(t)])]),e("h2",we,[e("a",Ae,[e("span",null,[l("2023.6.19 "),n(a,null,{default:s(()=>[e("a",We,[l("v1.8.3"),n(t)])]),_:1})])])]),je,e("p",null,[l("也许我们可以借助一下 "),e("a",Be,[l("RealiTLScanner"),n(t)]),l("……")]),Fe,e("p",null,[l("经过长年累月的开发,累积代码不计其数…… "),e("a",Ge,[l("精简代码计划"),n(t)]),l(" 被提出了!")]),Me,qe,e("h2",Oe,[e("a",Ye,[e("span",null,[l("2023.4.18 "),n(a,null,{default:s(()=>[e("a",Qe,[l("v1.8.1"),n(t)])]),_:1})])])]),Ke,e("h2",ze,[e("a",Je,[e("span",null,[l("2023.3.9 "),n(a,null,{default:s(()=>[e("a",Ze,[l("v1.8.0"),n(t)])]),_:1})])])]),$e,e("h2",el,[e("a",ll,[e("span",null,[l("2023.2.8 "),n(a,null,{default:s(()=>[e("a",nl,[l("v1.7.5"),n(t)])]),_:1})])])]),tl,e("ul",null,[e("li",null,[l("恭喜 "),e("a",sl,[l("@yuhan6665"),n(t)]),l(" 贡献了 Xray-core 的第 500 个 commit!")]),al,ol,rl,il,hl]),_l,cl,e("h2",dl,[e("a",ul,[e("span",null,[l("2022.12.26 "),n(a,null,{default:s(()=>[e("a",pl,[l("v1.7.0"),n(t)])]),_:1})])])]),fl,bl,e("h2",gl,[e("a",Xl,[e("span",null,[l("2022.11.28 "),n(a,null,{default:s(()=>[e("a",vl,[l("v1.6.5"),n(t)])]),_:1})])])]),Sl,Tl,e("h2",kl,[e("a",ml,[e("span",null,[l("2022.11.7 "),n(a,null,{default:s(()=>[e("a",xl,[l("v1.6.3"),n(t)])]),_:1})])])]),yl,e("h2",Ll,[e("a",Pl,[e("span",null,[l("2022.10.29 "),n(a,null,{default:s(()=>[e("a",Hl,[l("v1.6.2"),n(t)])]),_:1})])])]),Dl,e("h2",Ul,[e("a",Rl,[e("span",null,[l("2022.10.22 "),n(a,null,{default:s(()=>[e("a",Cl,[l("v1.6.1"),n(t)])]),_:1})])])]),El,e("h2",Nl,[e("a",Il,[e("span",null,[l("2022.8.28 "),n(a,null,{default:s(()=>[e("a",Vl,[l("v1.5.10"),n(t)])]),_:1})])])]),wl,e("h2",Al,[e("a",Wl,[e("span",null,[l("2022.6.20 "),n(a,null,{default:s(()=>[e("a",jl,[l("v1.5.8"),n(t)])]),_:1})])])]),Bl,e("h2",Fl,[e("a",Gl,[e("span",null,[l("2022.5.29 "),n(a,null,{default:s(()=>[e("a",Ml,[l("v1.5.6"),n(t)])]),_:1})])])]),ql,e("ul",null,[e("li",null,[l("感谢 "),e("a",Ol,[l("@nekohasekai"),n(t)]),l(" 开发全新 go 实现 https://github.com/SagerNet/sing-shadowsocks 并引入 Xray。")]),e("li",null,[l("感谢 "),e("a",Yl,[l("@database64128"),n(t)]),l(" 推动 Shadowsocks 社区提出完整设计方案。")]),e("li",null,[l("感谢 "),e("a",Ql,[l("@RPRX"),n(t)]),l(" 提交原始漏洞。")])]),Kl,zl,e("h2",Jl,[e("a",Zl,[e("span",null,[l("2022.4.24 "),n(a,null,{default:s(()=>[e("a",$l,[l("v1.5.5"),n(t)])]),_:1})])])]),en,ln,e("h2",nn,[e("a",tn,[e("span",null,[l("2022.3.13 "),n(a,null,{default:s(()=>[e("a",sn,[l("v1.5.4"),n(t)])]),_:1})])])]),an,e("h2",on,[e("a",rn,[e("span",null,[l("2022.1.29 "),n(a,null,{default:s(()=>[e("a",hn,[l("v1.5.3"),n(t)])]),_:1})])])]),_n,cn,e("h2",dn,[e("a",un,[e("span",null,[l("2021.12.24 "),n(a,null,{default:s(()=>[e("a",pn,[l("v1.5.2"),n(t)])]),_:1})])])]),fn,e("h2",bn,[e("a",gn,[e("span",null,[l("2021.12.15 "),n(a,null,{default:s(()=>[e("a",Xn,[l("v1.5.1"),n(t)])]),_:1})])])]),vn,Sn,e("h2",Tn,[e("a",kn,[e("span",null,[l("2021.10.20 "),n(a,null,{default:s(()=>[e("a",mn,[l("v1.5.0"),n(t)])]),_:1})])])]),xn,yn,e("h2",Ln,[e("a",Pn,[e("span",null,[l("2021.9.23 "),n(a,null,{default:s(()=>[e("a",Hn,[l("v1.4.5"),n(t)])]),_:1})])])]),Dn,e("ul",null,[e("li",null,[l("文档站已经完全切换到 docs-next,丝般顺滑,体验更好!地址仍为 "),e("a",Un,[l("https://xtls.github.io/"),n(t)])])]),e("h2",Rn,[e("a",Cn,[e("span",null,[l("2021.9.8 "),n(a,null,{default:s(()=>[e("a",En,[l("v1.4.3"),n(t)])]),_:1})])])]),Nn,e("p",null,[l("现在一个以 Xray-core 为核心的开源、自由的 Android 客户端已经出现——"),e("a",In,[l("AnXray"),n(t)]),l("!由 "),e("a",Vn,[l("@nekohasekai"),n(t)]),l(" 维护。")]),e("ul",null,[wn,e("li",null,[l("首席视觉设计师 "),e("a",An,[l("@RPRX"),n(t)]),l(" 设计了 X-style 的 logo、slogan,以及独一无二的 material 黑白主题。")]),Wn]),jn,e("h2",Bn,[e("a",Fn,[e("span",null,[l("2021.4.1 "),n(a,null,{default:s(()=>[e("a",Gn,[l("v1.4.2"),n(t)])]),_:1})])])]),Mn,e("h2",qn,[e("a",On,[e("span",null,[l("2021.3.14 "),n(a,null,{default:s(()=>[e("a",Yn,[l("v1.4.0"),n(t)])]),_:1})])])]),Qn,e("h2",Kn,[e("a",zn,[e("span",null,[l("2021.3.3 "),n(a,null,{default:s(()=>[e("a",Jn,[l("1.3.1"),n(t)])]),_:1})])])]),Zn,e("h2",$n,[e("a",et,[e("span",null,[l("2021.2.14 "),n(a,null,{default:s(()=>[e("a",lt,[l("1.3.0"),n(t)])]),_:1})])])]),nt,e("h2",tt,[e("a",st,[e("span",null,[l("2021.01.31 "),n(a,null,{default:s(()=>[e("a",at,[l("1.2.4"),n(t)])]),_:1})])])]),ot,rt,e("ul",null,[e("li",null,[l("全互联网最好最详细的秘籍入门篇同学们练熟了吗? 🍉 老师开始连载"),n(r,{to:"/document/level-1/"},{default:s(()=>[l("秘籍第一层")]),_:1}),l("咯...")]),it]),e("h2",ht,[e("a",_t,[e("span",null,[l("2021.01.22 "),n(a,null,{default:s(()=>[e("a",ct,[l("1.2.3"),n(t)])]),_:1})])])]),e("ul",null,[dt,ut,pt,ft,bt,e("li",null,[l("向发现问题->开 issue->自行测试->自行分析->自行找到问题->自行解决->然后给上下游提交 PR 的大佬 "),e("a",gt,[l("@Bohan Yang"),n(t)]),l(" 致敬!")]),Xt]),vt,e("ul",null,[e("li",null,[l("辛苦的翻译工作开始了, 感谢 "),e("a",St,[l("@玖柒 Max"),n(t)]),l("和其他所有的翻译大佬们.")]),e("li",null,[e("a",Tt,[l("English version"),n(t)])])]),e("h2",kt,[e("a",mt,[e("span",null,[l("2021.01.15 "),n(a,null,{default:s(()=>[e("a",xt,[l("1.2.2"),n(t)])]),_:1})])])]),yt,e("ul",null,[Lt,e("li",null,[l("🍉 老师的"),n(r,{to:"/document/level-0/"},{default:s(()=>[l("小小白白话文")]),_:1}),l("大结局, 撒花.")])]),e("h2",Pt,[e("a",Ht,[e("span",null,[l("2021.01.10 "),n(a,null,{default:s(()=>[e("a",Dt,[l("1.2.1"),n(t)])]),_:1})])])]),e("ul",null,[e("li",null,[n(r,{to:"/document/level-0/"},{default:s(()=>[l("小小白白话文")]),_:1}),l("连载上线啦,🍉 老师呕心沥血之作, 手把手教你从什么都不会到熟练配置 Xray!")]),Ut,e("li",null,[n(r,{to:"/document/level-2/"},{default:s(()=>[l("透明代理")]),_:1}),l("也增加了更多文章.")]),Rt,e("li",null,[l("感谢 "),e("a",Ct,[l("@ricuhkaen"),n(t)]),l(" , "),e("a",Et,[l("@BioniCosmos"),n(t)]),l(", "),e("a",Nt,[l("@kirin"),n(t)])])]),It,e("ul",null,[e("li",null,[l("文档仓库第一个 PR。🎉 "),n(r,{to:"/document/level-2/tproxy.html"},{default:s(()=>[l("透明代理(TProxy)配置教程 ")]),_:1}),l(" ,感谢 "),e("a",Vt,[l("@BioniCosmos"),n(t)])]),wt]),At,e("p",null,[l("【祝大家新年快乐,嗨皮牛耶!】🎆🎇🎆 "),n(a,null,{default:s(()=>[e("a",Wt,[l("1.2.0"),n(t)])]),_:1})]),jt,e("ul",null,[Bt,e("li",null,[l("Xray 将继续保持前行! 因此 "),e("a",Ft,[l("Xray 需要更多的英雄!!"),n(t)]),l("!")]),e("li",null,[l("PS:请品,请细品"),e("a",Gt,[l("release notes"),n(t)]),l("每一句。似乎有一个小秘密小彩蛋 "),Mt])]),qt,e("p",null,[l("透明代理的游戏玩家利好! Xray-core tproxy 入站, socks 出站 UDP FullCone 测试版, "),e("a",Ot,[l("TG 群"),n(t)]),l("火热测试中")]),e("h2",Yt,[e("a",Qt,[e("span",null,[l("2020.12.25 "),n(a,null,{default:s(()=>[e("a",Kt,[l("1.1.5"),n(t)])]),_:1})])])]),zt,e("ul",null,[Jt,Zt,$t,es,e("li",null,[l("kirin 带来了一大波 脚本更新."),e("a",ls,[l("脚本在此"),n(t)])]),ns]),ts,e("p",null,[l("因为某些不可描述的原因,Xray 的文档网站已在发布日前偷跑上线。 网址为:"),e("a",ss,[l("没错你正在看的就是"),n(t)])]),as,e("p",null,[l("文档网站需要不断完善和增加内容,以及完善设计。 因此更欢迎大家一起为文档建设添砖加瓦。 "),e("a",os,[l("文档的仓库"),n(t)])]),rs,is,e("p",null,[l("Xray-core Shadowsocks UDP FullCone 测试版, "),e("a",hs,[l("TG 群"),n(t)]),l("火热测试中")]),_s,cs,e("h2",ds,[e("a",us,[e("span",null,[l("2020.12.18 "),n(a,null,{default:s(()=>[e("a",ps,[l("1.1.4"),n(t)])]),_:1})])])]),fs,bs,e("p",null,[l("鉴于日益增长群人数和游戏需求, 开启了"),e("a",gs,[l("TG 游戏群"),n(t)])]),Xs,e("p",null,[e("a",vs,[l("安装脚本 dev 分支"),n(t)]),l("开启, 持续更新功能中.")]),e("h2",Ss,[e("a",Ts,[e("span",null,[l("2020.12.11 "),n(a,null,{default:s(()=>[e("a",ks,[l("1.1.3"),n(t)])]),_:1})])])]),ms,e("h2",xs,[e("a",ys,[e("span",null,[l("2020.12.06 "),n(a,null,{default:s(()=>[e("a",Ls,[l("1.1.2"),n(t)])]),_:1})])])]),Ps,e("h2",Hs,[e("a",Ds,[e("span",null,[l("2020.11.25 "),n(a,null,{default:s(()=>[e("a",Us,[l("1.0.0"),n(t)])]),_:1})])])]),Rs,Cs,Es,Ns,Is])}const js=_(u,[["render",Vs],["__file","news.html.vue"]]);export{js as default}; diff --git a/assets/news.html-UWoLxj1_.js b/assets/news.html-BzYbyEWd.js similarity index 99% rename from assets/news.html-UWoLxj1_.js rename to assets/news.html-BzYbyEWd.js index 5a057fc200..59dbdd6f29 100644 --- a/assets/news.html-UWoLxj1_.js +++ b/assets/news.html-BzYbyEWd.js @@ -1 +1 @@ -import{_,r as i,o as c,c as d,a as n,b as e,d as l,w as s,e as o}from"./app-DBM4OJyw.js";const u={},p=e("h1",{id:"大史记",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#大史记"},[e("span",null,"大史记")])],-1),f=e("h2",{id:"_2024-9-12",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2024-9-12"},[e("span",null,"2024.9.12")])],-1),b=e("p",null,"大史记重出江湖?!",-1),g={id:"_2024-9-7-v24-9-7",tabindex:"-1"},X={class:"header-anchor",href:"#_2024-9-7-v24-9-7"},v={href:"https://github.com/XTLS/Xray-core/releases/tag/v24.9.7",target:"_blank",rel:"noopener noreferrer"},S=e("p",null,"更改版本号之后的首次发版。",-1),T=e("ul",null,[e("li",null,[l("这次移除了 QUIC 以及 DomainSocket 传输,移除了两处远古配置遗留代码。 "),e("ul",null,[e("li",null,"二进制大小比 v1.8.24 减小了 1MB。")])]),e("li",null,"依然有每次必备的 bug 修复。")],-1),k={id:"_2024-8-30-v1-8-24",tabindex:"-1"},m={class:"header-anchor",href:"#_2024-8-30-v1-8-24"},x={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.24",target:"_blank",rel:"noopener noreferrer"},y=o('

                                      在等待 SplitHTTP multiplex controller 期间,main 分支已经积累了大量重要更新,所以我们决定先发一个版本。

                                      • Socks 入站现在默认兼容 HTTP 代理请求。
                                      • UDP noise (preview)
                                      • 还有一些改进。

                                      由于传统版本号的存在,为每个版本规划功能、进行排期已经严重阻碍了新功能的开发、合并、发布。所以我们决定从下个版本开始弃用传统的版本号,改用发版日期作为版本号,如 v24.8.30,并取消版本规划,全面采用流式更新,写好的功能直接合并,不再等待,预计每月月底发一个版本。

                                      毕竟对于反审查软件来说,相较于传统的版本号,新功能的及时性、每月更新更为重要,而不是发一个功能确定的版本并长期维护。

                                      下个版本会移除一些历史久远的代码,以后日常积累新代码、提醒迁移,跨年新版删代码、breaking。

                                      我们相信有了各位的捐款以及对发版形式的革新,Xray-core 这个项目会发展得更好。

                                      2024.8.26

                                      Project VLESS 群组创立。

                                      ',8),L={href:"https://t.me/projectVless",target:"_blank",rel:"noopener noreferrer"},P=e("h2",{id:"_2024-8-3",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2024-8-3"},[e("span",null,"2024.8.3")])],-1),H={href:"https://github.com/XTLS/Xray-core/discussions/3633#discussioncomment-10231076",target:"_blank",rel:"noopener noreferrer"},D=e("p",null,"就像 Xray 开创过很多历史一样,发行 NFT 也是这个领域前无古人的操作。这些 NFT 非常有纪念意义,甚至可以说是有历史意义,远大于现在的初始价格,假以时日它们必将价值连城。最后再次感谢大家对 Project X 的支持。",-1),U={id:"_2024-7-29-v1-8-23",tabindex:"-1"},R={class:"header-anchor",href:"#_2024-7-29-v1-8-23"},C={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.23",target:"_blank",rel:"noopener noreferrer"},E={href:"https://github.com/mmmray",target:"_blank",rel:"noopener noreferrer"},N=e("li",null,"优化了 SplitHTTP 上行的稳定性,服务端必须升级到该版本以支持新版客户端。",-1),I=e("li",null,"更多 SplitHTTP 上的变化。",-1),V={id:"_2024-7-22-v1-8-21",tabindex:"-1"},w={class:"header-anchor",href:"#_2024-7-22-v1-8-21"},A={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.21",target:"_blank",rel:"noopener noreferrer"},W=e("p",null,"中间似乎回到了最初的腹泻式发版状态……",-1),j=e("p",null,"正如 v1.8.16 所预告的,SplitHTTP 现已初步支持 HTTP/3(QUIC)。毫无疑问,SplitHTTP H3 已经开启了一个崭新的时代。",-1),B=e("ul",null,[e("li",null,"SplitHTTP H3 是第一个完全基于标准 H3、支持套 CDN 的 QUIC 类代理,亦可用反代、Browser Dialer 来隐蔽自身。")],-1),F=e("h2",{id:"_2024-7-16",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2024-7-16"},[e("span",null,"2024.7.16")])],-1),G={href:"https://github.com/iambabyninja",target:"_blank",rel:"noopener noreferrer"},M=e("blockquote",null,[e("p",null,"Привет, друзья из России!")],-1),q=e("h2",{id:"_2024-7-15",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2024-7-15"},[e("span",null,"2024.7.15")])],-1),O=e("p",null,"虽然日后随着各方面升级 Windows 7 最终会离开,但是现在还是可以让这个时间来得稍微晚一些。",-1),Y={id:"_2024-6-18-v1-8-16",tabindex:"-1"},Q={class:"header-anchor",href:"#_2024-6-18-v1-8-16"},K={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.16",target:"_blank",rel:"noopener noreferrer"},z=e("p",null,"新传输来了,它目前叫 SplitHTTP。",-1),J=e("ul",null,[e("li",null,"实现进一步的流量混淆有两种刚好相反的方式:多路复用与拆分连接。"),e("li",null,"可以通过不支持 WebSocket、gRPC 的 CDN,实现与 Meek 相同的目标,且 SplitHTTP 比 Meek 更简单、效率更高。"),e("li",null,"SplitHTTP 没有 WebSocket 的 ALPN 问题,这是一大优势,未来还会支持 HTTP/3(QUIC)。"),e("li",null,"另外 SplitHTTP 也已经加入分享链接套餐~")],-1),Z=e("h2",{id:"_2024-6-2",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2024-6-2"},[e("span",null,"2024.6.2")])],-1),$=e("p",null,"一个新的传输方式正在被打造……",-1),ee={id:"_2024-4-26-v1-8-11",tabindex:"-1"},le={class:"header-anchor",href:"#_2024-4-26-v1-8-11"},ne={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.11",target:"_blank",rel:"noopener noreferrer"},te=e("ul",null,[e("li",null,"现在有了生成 ECH 密钥的工具。"),e("li",null,"增强、修复,并移除了一点不再使用的代码。")],-1),se=e("h2",{id:"_2024-4-20",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2024-4-20"},[e("span",null,"2024.4.20")])],-1),ae={href:"https://github.com/Fangliding",target:"_blank",rel:"noopener noreferrer"},oe=e("h2",{id:"_2024-4-13",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2024-4-13"},[e("span",null,"2024.4.13")])],-1),re=e("p",null,"VLESS Seed 整备完毕,待势而发。",-1),ie={id:"_2024-3-18-v1-8-10",tabindex:"-1"},he={class:"header-anchor",href:"#_2024-3-18-v1-8-10"},_e={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.10",target:"_blank",rel:"noopener noreferrer"},ce=e("p",null,"和 WebSocket 一样,HTTPUpgrade 也有 0-RTT 了。",-1),de={id:"_2024-3-11-v1-8-9",tabindex:"-1"},ue={class:"header-anchor",href:"#_2024-3-11-v1-8-9"},pe={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.9",target:"_blank",rel:"noopener noreferrer"},fe=e("p",null,"新增 HTTPUpgrade 传输,听说比 WebSocket 要轻。",-1),be=e("ul",null,[e("li",null,"已加入分享链接套餐~")],-1),ge=e("h2",{id:"_2024-2-29",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2024-2-29"},[e("span",null,"2024.2.29")])],-1),Xe=e("p",null,[l("gRPC 传输现在也有 Host 一样的配置字段了!它叫 "),e("code",null,"authority"),l("。这下 gRPC 也能“域前置”了,没有 ALPN 问题。")],-1),ve={id:"_2024-2-25-v1-8-8",tabindex:"-1"},Se={class:"header-anchor",href:"#_2024-2-25-v1-8-8"},Te={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.8",target:"_blank",rel:"noopener noreferrer"},ke=e("ul",null,[e("li",null,"现在 XUDP 流量统一使用 Vision 填充了,速来体验。"),e("li",null,"新增了 leastLoad balancer。"),e("li",null,"修复错误、优化性能……")],-1),me=e("h2",{id:"_2024-1-9",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2024-1-9"},[e("span",null,"2024.1.9")])],-1),xe=e("p",null,"惊闻 Win7 无法运行新版 Xray-core?探索之下竟发现 Go 放弃了对 Win7 的支持。有什么办法能继续支持这个有些古老但是依然优雅的操作系统吗?",-1),ye=e("h2",{id:"_2023-11-21",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2023-11-21"},[e("span",null,"2023.11.21")])],-1),Le={href:"https://t.me/projectXtls/212",target:"_blank",rel:"noopener noreferrer"},Pe=e("p",null,"而 XTLS 也不会止步于此,如 X 射线一般穿破高耸的围墙。",-1),He={id:"_2023-11-18-v1-8-6",tabindex:"-1"},De={class:"header-anchor",href:"#_2023-11-18-v1-8-6"},Ue={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.6",target:"_blank",rel:"noopener noreferrer"},Re=o('
                                      • WireGuard 现在也有了对应的入站。Freedom 出站也终于有了 splice。
                                      • 现在出站的 domainStrategy 也得到了统一。
                                      • 更多的美味小点心。
                                      • 因为 不可抗力 功能变更,Dragonfly BSD 支持黯然离场。
                                      • 我们真的要对一代经典 Windows 7 说再见了吗?

                                      2023.9.30

                                      为 v2rayNG 设计了全新的配色,安装最新的 Pre-release 版本即可体验。

                                      ',3),Ce={id:"_2023-8-29-v1-8-4",tabindex:"-1"},Ee={class:"header-anchor",href:"#_2023-8-29-v1-8-4"},Ne={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.4",target:"_blank",rel:"noopener noreferrer"},Ie=o('

                                      1.8.x 在经过半年的打磨后终于来到了第一个认可的正式版了。

                                      同样地,这次集成的改进也不少,速来品尝!

                                      2023.7.22

                                      又修好了一个 HTTP/2 传输的历史遗留断流问题。

                                      2023.7.7

                                      即将给 Vision 添加 Seed 支持。

                                      2023.6.30

                                      下一个 XTLS 流控:xtls-rprx-switch 🍪

                                      • XTLS 的 0-RTT 已经预告几个月了,本来也是想保留神秘感。
                                      • 对比现有的 XTLS Vision 和 Mux 有着更加不错的优势。

                                      2023.6.27

                                      ',10),Ve={href:"https://github.com/XTLS/Xray-core/discussions/2256#discussioncomment-6295296",target:"_blank",rel:"noopener noreferrer"},we={id:"_2023-6-19-v1-8-3",tabindex:"-1"},Ae={class:"header-anchor",href:"#_2023-6-19-v1-8-3"},We={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.3",target:"_blank",rel:"noopener noreferrer"},je=o('
                                      • 精简代码计划后的第一个版本,VMess (MD5)、MTProto 以及 Starlark 相关代码已被卸下。轻装上阵。
                                      • 对代码进重构也是轻装上阵的一部分。
                                      • 同时我们也没有忘记增添一些增强功能,还有修复漏洞。
                                      • v1.8.3 为今年的最后一个版本。

                                      2023.6.6

                                      好消息:下一个 XTLS 流控不叫 Vision。 🍪

                                      2023.4.21

                                      ',4),Be={href:"https://github.com/XTLS/RealiTLScanner",target:"_blank",rel:"noopener noreferrer"},Fe=e("h2",{id:"_2023-4-20",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2023-4-20"},[e("span",null,"2023.4.20")])],-1),Ge={href:"https://github.com/XTLS/Xray-core/discussions/1967",target:"_blank",rel:"noopener noreferrer"},Me=e("h2",{id:"_2023-4-19",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2023-4-19"},[e("span",null,"2023.4.19")])],-1),qe=e("p",null,[e("code",null,"xtls-0rtt-vision(-udp443)"),l(" 🍪")],-1),Oe={id:"_2023-4-18-v1-8-1",tabindex:"-1"},Ye={class:"header-anchor",href:"#_2023-4-18-v1-8-1"},Qe={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.1",target:"_blank",rel:"noopener noreferrer"},Ke=o('

                                      升级后的 XUDP 也来了!

                                      • 现在 XUDP 也带有连接迁移、端口复用的特性,并且带有全局 Session ID ,麻麻再也不用担心意外断线的时候怎么办了
                                      • 同时我们也添加了 XUDP 的控制配置,让你能更好掌控它~
                                      • 新的 XUDP 配合 XTLS Vision 食用风味更好喔~
                                      • 惯例还有小甜点,欢迎品尝~

                                      2023.4.6

                                      XUDP 也在悄然升级……

                                      2023.3.29

                                      PLUX protocol 🍪

                                      2023.3.19

                                      对 REALITY 的分享链接标准也已经出现了。

                                      ',8),ze={id:"_2023-3-9-v1-8-0",tabindex:"-1"},Je={class:"header-anchor",href:"#_2023-3-9-v1-8-0"},Ze={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.0",target:"_blank",rel:"noopener noreferrer"},$e=o('

                                      THE NEXT FUTURE, REALITY is NOW release on Xray-core

                                      REALITY 已经实装发版!欢迎体验! XTLS Vision 也已经完善,请两端升级至最新版食用。

                                      • 因为这次 Vision 填充算法改变,XTLS Vision 旧版和新版之间会存在兼容性问题。
                                      • HTTP/2 传输也已经做了改善,现在使用新版即可纵享丝滑~
                                      • 还有大量小改进欢迎体验~

                                      2023.3.4

                                      Legends never die, they become a part of you VLESS.

                                      They simply fade away.

                                      2023.3.2

                                      HTTP/2 传输的一些遗留问题已经被改善,欢迎搭配 REALITY 测试纵享丝滑~

                                      2023.2.16

                                      THE NEXT FUTURE becomes THE REALITY NOW!

                                      2023.2.9

                                      REALITY is reality now!

                                      ',11),el={id:"_2023-2-8-v1-7-5",tabindex:"-1"},ll={class:"header-anchor",href:"#_2023-2-8-v1-7-5"},nl={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.7.5",target:"_blank",rel:"noopener noreferrer"},tl=e("p",null,"Keep riding and never look back.",-1),sl={href:"https://github.com/yuhan6665",target:"_blank",rel:"noopener noreferrer"},al=e("li",null,"XTLS Vision 流控已经接近完善,即将实用。",-1),ol=e("li",null,"现在对 uTLS 指纹模拟添加了更多可选项,有哪一款适合你?",-1),rl=e("li",null,"分享链接也支持同时分享 uTLS 指纹配置了。",-1),il=e("li",null,"还有更多的功能增强和修复。",-1),hl=e("li",null,[l("这一版也是能最后一次看到 XTLS Origin、Direct 和 Splice 流控的一版了。 "),e("s",null,"有点伤感不是吗?")],-1),_l=e("h2",{id:"_2023-1-29",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2023-1-29"},[e("span",null,"2023.1.29")])],-1),cl=e("p",null,"Winter cannot cover the NEXT FUTURE...",-1),dl={id:"_2022-12-26-v1-7-0",tabindex:"-1"},ul={class:"header-anchor",href:"#_2022-12-26-v1-7-0"},pl={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.7.0",target:"_blank",rel:"noopener noreferrer"},fl=e("p",null,"因为手滑,这次的版本号直接大升,感谢大家支持!",-1),bl=e("ul",null,[e("li",null,"以后将会严格执行 Semantic Versioning。")],-1),gl={id:"_2022-11-28-v1-6-5",tabindex:"-1"},Xl={class:"header-anchor",href:"#_2022-11-28-v1-6-5"},vl={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.6.5",target:"_blank",rel:"noopener noreferrer"},Sl=e("p",null,"这次我们有了 WireGuard 出站。",-1),Tl=e("ul",null,[e("li",null,"使用 WireGuard 搭配 CF WARP 使用可以解锁有趣的新玩法呢。"),e("li",null,"同样安全更新和修复也不会少。")],-1),kl={id:"_2022-11-7-v1-6-3",tabindex:"-1"},ml={class:"header-anchor",href:"#_2022-11-7-v1-6-3"},xl={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.6.3",target:"_blank",rel:"noopener noreferrer"},yl=e("p",null,[l("现在 Vision 流控也能使用 uTLS 指纹模拟了,这就是使用 "),e("code",null,"tlsSettings"),l(" 带来的好处吗!")],-1),Ll={id:"_2022-10-29-v1-6-2",tabindex:"-1"},Pl={class:"header-anchor",href:"#_2022-10-29-v1-6-2"},Hl={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.6.2",target:"_blank",rel:"noopener noreferrer"},Dl=e("p",null,"第一个包含 Vision 流控的发行版已经放出!欢迎试用并提交反馈!",-1),Ul={id:"_2022-10-22-v1-6-1",tabindex:"-1"},Rl={class:"header-anchor",href:"#_2022-10-22-v1-6-1"},Cl={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.6.1",target:"_blank",rel:"noopener noreferrer"},El=o('
                                      • 为 WebSocket、HTTP/2 以及 gRPC 传输带来了 uTLS 指纹支持!
                                        • 之前只有普通 TLS 下 TCP 传输能用的选项现在更好用了。
                                      • Linux 下可以单独为出入口设置 TCP 拥塞控制了。

                                      2022.10.3

                                      天气渐凉,但是并没有凉下开发的脚步。封锁天降,但无法阻止前行……

                                      • 新的 XTLS 流控酝酿中……
                                        • 解决之前流控已有的问题;
                                        • 对 TLS 1.3 直接启用 splice;
                                        • 增加 TLS 握手长度混淆;
                                        • 简化代码,使用 tlsSettings 而不是 xtlsSettings……
                                      ',4),Nl={id:"_2022-8-28-v1-5-10",tabindex:"-1"},Il={class:"header-anchor",href:"#_2022-8-28-v1-5-10"},Vl={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.5.10",target:"_blank",rel:"noopener noreferrer"},wl=e("p",null,"底层传输支持更合理的 TCP Keepalive 配置了。",-1),Al={id:"_2022-6-20-v1-5-8",tabindex:"-1"},Wl={class:"header-anchor",href:"#_2022-6-20-v1-5-8"},jl={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.5.8",target:"_blank",rel:"noopener noreferrer"},Bl=e("p",null,"现在 Shadowsocks-2022 的 relay 中转也受支持了。",-1),Fl={id:"_2022-5-29-v1-5-6",tabindex:"-1"},Gl={class:"header-anchor",href:"#_2022-5-29-v1-5-6"},Ml={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.5.6",target:"_blank",rel:"noopener noreferrer"},ql=e("p",null,"Shadowsocks-2022 协议来到了 Xray-core!",-1),Ol={href:"https://github.com/nekohasekai",target:"_blank",rel:"noopener noreferrer"},Yl={href:"https://github.com/database64128",target:"_blank",rel:"noopener noreferrer"},Ql={href:"https://github.com/RPRX",target:"_blank",rel:"noopener noreferrer"},Kl=e("p",null,"Shadowsocks-2022 是重新设计的全新协议:",-1),zl=e("ul",null,[e("li",null,"在保留 Shadowsocks 原生 udp 的基础上解决了重放攻击等安全问题(与 vmess 一样使用时间戳,因此客户端与服务端需要时间一致)。"),e("li",null,"支持单端口多用户,并且参考 quic、wireguard 等协议设计与实现使用了 session 机制,减低加密负担,保证网络变动时的无缝迁移。")],-1),Jl={id:"_2022-4-24-v1-5-5",tabindex:"-1"},Zl={class:"header-anchor",href:"#_2022-4-24-v1-5-5"},$l={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.5.5",target:"_blank",rel:"noopener noreferrer"},en=e("p",null,"这次带来了方便可视化的检测数据接口!快来体验!",-1),ln=e("ul",null,[e("li",null,"顺便修复了一些影响使用体验的问题。")],-1),nn={id:"_2022-3-13-v1-5-4",tabindex:"-1"},tn={class:"header-anchor",href:"#_2022-3-13-v1-5-4"},sn={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.5.4",target:"_blank",rel:"noopener noreferrer"},an=e("p",null,"给 Windows 平台加上了没有黑窗冒出的 wxray.exe 文件,并带来了对 UDS 监听的增强。",-1),on={id:"_2022-1-29-v1-5-3",tabindex:"-1"},rn={class:"header-anchor",href:"#_2022-1-29-v1-5-3"},hn={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.5.3",target:"_blank",rel:"noopener noreferrer"},_n=e("p",null,"牛辞胜岁,虎跃新程。🧨",-1),cn=e("ul",null,[e("li",null,"这次带来了对 QUIC 传输的流分配改进,使用 QUIC 传输现在更丝滑了。")],-1),dn={id:"_2021-12-24-v1-5-2",tabindex:"-1"},un={class:"header-anchor",href:"#_2021-12-24-v1-5-2"},pn={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.5.2",target:"_blank",rel:"noopener noreferrer"},fn=e("p",null,"为 gRPC 添加了一个新的选项,在通过 CDN 时变得更好用了。",-1),bn={id:"_2021-12-15-v1-5-1",tabindex:"-1"},gn={class:"header-anchor",href:"#_2021-12-15-v1-5-1"},Xn={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.5.1",target:"_blank",rel:"noopener noreferrer"},vn=e("blockquote",null,[e("p",null,"“过渡时期的阶段性的维护版本”")],-1),Sn=e("ul",null,[e("li",null,"新功能、增强还有大量修复陆续有来。"),e("li",null,[l("记得将 VMess 配置中的 "),e("code",null,"alterID"),l(" 去掉!")])],-1),Tn={id:"_2021-10-20-v1-5-0",tabindex:"-1"},kn={class:"header-anchor",href:"#_2021-10-20-v1-5-0"},mn={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.5.0",target:"_blank",rel:"noopener noreferrer"},xn=e("p",null,"真的是巨大的改动!",-1),yn=e("ul",null,[e("li",null,"重构了 DNS 组件,支持的协议和细化配置更多了。"),e("li",null,"增强了 gRPC 传输以及 FakeDNS。"),e("li",null,"现在终于支持 Windows ARM64 了。"),e("li",null,"更多新功能和改进等待体验。")],-1),Ln={id:"_2021-9-23-v1-4-5",tabindex:"-1"},Pn={class:"header-anchor",href:"#_2021-9-23-v1-4-5"},Hn={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.4.5",target:"_blank",rel:"noopener noreferrer"},Dn=o('

                                      中秋快乐,阖家团圆。

                                      • 修正了版本号过低,版本号不吉利的 bug。
                                      • 这次移除了 Shadowsocks 里面已经不安全的加密方式。要尽快迁移到 AEAD 加密上面喔。
                                      • 这次修复了远古时期开始就存在的历史问题:开启流量统计功能可能会使性能下降。简单来说,不论什么配置现在打开统计都不会对性能有任何影响了。
                                      • 还有对 XTLS 的安全性更新以及大量修复。
                                      • 对了,因为 TLS 库的更新,cipherSuites 不能再指定加密套件顺序了,而 preferServerCipherSuites 已经被彻底弃用。事实上这些变化在 Xray-core v1.4.3 中已经产生了。

                                      2021.9.16

                                      ',3),Un={href:"https://xtls.github.io/",target:"_blank",rel:"noopener noreferrer"},Rn={id:"_2021-9-8-v1-4-3",tabindex:"-1"},Cn={class:"header-anchor",href:"#_2021-9-8-v1-4-3"},En={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.4.3",target:"_blank",rel:"noopener noreferrer"},Nn=o('

                                      这是一个阶段性维护版本。开发仍在继续……

                                      • 在此期间累积了大量改进和新功能。
                                      • 加入新的 DomainMatcher,现在域名规则匹配性能更好了。
                                      • 加入对 HTTP/2 和 gRPC 传输的健康检查、对未知 SNI 的处理改进,以及修复了一大堆 bug。

                                      Helden sterben nicht!

                                      2021.7.14

                                      • AnXray 重金设计 的新图标已经上线!
                                        • 现在图标的辨识度更高了。
                                      • 过去三个星期,AnXray 共积累了 600 stars、2K+ 频道订阅数和 11K+ GitHub 下载量,感谢大家的支持。
                                      • AX 为 AnXray 的缩写,推荐用 AX 指代 AnXray,简短方便

                                      2021.6.21

                                      ',6),In={href:"https://github.com/XTLS/AnXray",target:"_blank",rel:"noopener noreferrer"},Vn={href:"https://github.com/nekohasekai",target:"_blank",rel:"noopener noreferrer"},wn=e("li",null,"支持众多协议、插件.",-1),An={href:"https://github.com/RPRX",target:"_blank",rel:"noopener noreferrer"},Wn=e("li",null,"APP 内还有个小彩蛋等你去发现。",-1),jn=o('

                                      前两天从早到晚反复打磨细节,希望大家多多 Star、关注。

                                      2021.5.1

                                      对 tun2socks 的改进出现在 v2rayNG 上面了。

                                      2021.4.26

                                      给 tun2socks 带来了一个改进。后续有可能能吃到它~

                                      2021.4.12

                                      现在带来了 X-flutter 前瞻,可以期待一下会是什么样子呢~ 🍪

                                      2021.4.6

                                      • VuePress Next.
                                      • With Dark Mode.

                                      2021.4.4

                                      • 本文档迎来的新的首页。
                                      • 本文档迎来了暗黑模式。
                                      • 当然,暗黑模式还有各种各样的问题。具体的内容还需要慢慢调整。
                                      • 另:Telegram 群聊突破了 5000 人!还加入了 Anti-Spam 机器人!
                                      • 🎉🎉🎉
                                      ',11),Bn={id:"_2021-4-1-v1-4-2",tabindex:"-1"},Fn={class:"header-anchor",href:"#_2021-4-1-v1-4-2"},Gn={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.4.2",target:"_blank",rel:"noopener noreferrer"},Mn=o('
                                      • 不是愚人节玩笑,今天更新。
                                      • 加入 Browser Dialer,用与改变 TLS 指纹与行为。
                                      • 加入 uTLS,用与改变 TLS Client Hello 的指纹。
                                      • 顺便修复了一大堆奇妙的问题,具体的内容见更新日志。

                                      2021.3.25

                                      没错还在变。 -_-

                                      2021.3.15

                                      文档网站正在悄悄的进行着某些神秘的变化。。。,🙊🙊🙊

                                      ',5),qn={id:"_2021-3-14-v1-4-0",tabindex:"-1"},On={class:"header-anchor",href:"#_2021-3-14-v1-4-0"},Yn={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.4.0",target:"_blank",rel:"noopener noreferrer"},Qn=o("
                                      • Happy Pi-Day!
                                      • 这次是个大更新:
                                        • 为链式代理引入了传输层支持。
                                        • 为 Dialer 引入了 Domain Strategy,解决奇妙的 DNS 问题。
                                        • 添加了 gRPC 传输方式,与更快一点的 Multi Mode。
                                        • 添加了 WebSocket Early-Data 功能,减少了 WebSocket 的延迟。
                                        • 添加了 FakeDNS。
                                        • 还修复了系列的问题,添加了各类功能,详情请见更新日志。
                                      • 还是 VuePress 比较爽啊(
                                      ",1),Kn={id:"_2021-3-3-1-3-1",tabindex:"-1"},zn={class:"header-anchor",href:"#_2021-3-3-1-3-1"},Jn={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.3.1",target:"_blank",rel:"noopener noreferrer"},Zn=e("ul",null,[e("li",null,"这个版本使用了 Golang 1.16,正式原生支持 Apple Silicon。"),e("li",null,[l("同时修复了一个会导致 Panic 的 bug。"),e("s",null,"Holmium_认为这是在骗、在偷袭。")]),e("li",null,"修复了几个遗留问题。")],-1),$n={id:"_2021-2-14-1-3-0",tabindex:"-1"},et={class:"header-anchor",href:"#_2021-2-14-1-3-0"},lt={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.3.0",target:"_blank",rel:"noopener noreferrer"},nt=e("ul",null,[e("li",null,"Happy 🐮 Year 🎉!"),e("li",null,"v1.3.0 通过非常巧妙的机制实现了 V 系协议全部 FullCone,同时保证了一定的兼容性。"),e("li",null,"OHHHHHHHHHHHH!")],-1),tt={id:"_2021-01-31-1-2-4",tabindex:"-1"},st={class:"header-anchor",href:"#_2021-01-31-1-2-4"},at={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.2.4",target:"_blank",rel:"noopener noreferrer"},ot=e("ul",null,[e("li",null,"解决两个“连接至标准 Socks 服务端时可能出错”的历史遗留问题。"),e("li",null,"似乎这个版本没有什么改变,但这只是暴风雨前的宁静。"),e("li",null,[l("(没错我就是先知) "),e("blockquote",null,[e("p",null,"你个傻子,你拿的是 UNO 牌。")])])],-1),rt=e("h2",{id:"_2021-01-25",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2021-01-25"},[e("span",null,"2021.01.25")])],-1),it=e("li",null,[e("a",{href:"../en"},"英文版文档网站"),l("逐渐增加内容 ing, 感谢各位大佬的辛苦付出~!")],-1),ht={id:"_2021-01-22-1-2-3",tabindex:"-1"},_t={class:"header-anchor",href:"#_2021-01-22-1-2-3"},ct={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.2.3",target:"_blank",rel:"noopener noreferrer"},dt=e("li",null,[l("对 SS 协议的支持"),e("strong",null,"又"),l("变强了, 支持单端口多用户!")],-1),ut=e("li",null,[l("对 trojan 协议的支持也"),e("strong",null,"又"),l("变强了, trojan 的回落也解锁 SNI 分流的新姿势啦~!")],-1),pt=e("li",null,[e("em",null,"(VLESS: 嘤嘤嘤)")],-1),ft=e("li",null,'UDP 奇奇怪怪的 BUG 被干掉了, 一个字, "稳定".',-1),bt=e("li",null,"嗅探可以排除你不想嗅探的域名, 可以开启一些新玩法.",-1),gt={href:"https://github.com/bohanyang",target:"_blank",rel:"noopener noreferrer"},Xt=e("li",null,"其他美味小樱桃, 惯例更新品尝就对啦.",-1),vt=o('

                                      2021.01.19

                                      • 一些数字
                                        • 版本发布了 10   个 tag
                                        • 解决掉了 100  个 issue
                                        • 复刻了 300  个 fork
                                        • 点了 2000 个 star
                                        • 群 3000 个 人

                                      2021.01.17

                                      ',3),St={href:"https://github.com/jiuqi9997",target:"_blank",rel:"noopener noreferrer"},Tt={href:"https://xtls.github.io/en/",target:"_blank",rel:"noopener noreferrer"},kt={id:"_2021-01-15-1-2-2",tabindex:"-1"},mt={class:"header-anchor",href:"#_2021-01-15-1-2-2"},xt={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.2.2",target:"_blank",rel:"noopener noreferrer"},yt=o('
                                      • 回落分流又解锁了奇怪的新姿势! 回落中可以根据 SNI 分流啦~!
                                      • 之前预告的 UUID 修改正式上线.(往下看往下看)
                                      • 日志现在看起来比上一次顺眼又更顺眼了一丢丢.
                                      • 远程 DOH 和其他的 DNS 模式一样学会了走路由分流.
                                      • 当然还有其他各种小糖果.(更新品尝就对了)
                                      • 啊, 还有, 世界上第一個 M1 上跑起 Xray 的男人是 Anthony TSE

                                      2021.01.12

                                      ',2),Lt=e("li",null,[l("将要到来的 UUID 修改, 支持自定义字符串和 UUID 之间的映射. 这意味着你将可以这样在配置文件中写 id 来对应用户. "),e("ul",null,[e("li",null,'客户端写 "id": "我爱 🍉 老师 1314",'),e("li",null,[l('服务端写 "id": "5783a3e7-e373-51cd-8642-c83782b807c5" (此 UUID 是 '),e("code",null,"我爱🍉老师1314"),l(" 的 UUID 映射)")])])],-1),Pt={id:"_2021-01-10-1-2-1",tabindex:"-1"},Ht={class:"header-anchor",href:"#_2021-01-10-1-2-1"},Dt={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.2.1",target:"_blank",rel:"noopener noreferrer"},Ut=e("li",null,"(可能是整个互联网上, 最详细最有耐心的教你从 0 开始配置的教程)",-1),Rt=e("li",null,"还有很多细节修改, 文档将会越来越规范!",-1),Ct={href:"https://github.com/ricuhkaen",target:"_blank",rel:"noopener noreferrer"},Et={href:"https://github.com/BioniCosmos",target:"_blank",rel:"noopener noreferrer"},Nt={href:"https://github.com/kirin10000",target:"_blank",rel:"noopener noreferrer"},It=o('
                                      • 大量的 UDP 相关修复, 甚至可以在育碧的土豆服务器上玩彩虹六号!
                                      • Google Voice 应该也可以正常使用 v2rayNG 拨打了.
                                      • 日志现在看起来更顺眼.

                                      2021.01.07

                                      • 礼貌和尊重本应是社区不需要明说的准则之一。

                                      2021.01.05

                                      • 文档网站正在悄悄的进行着某些神秘的变化。。。,🙊🙊🙊

                                      2021.01.03

                                      ',6),Vt={href:"https://github.com/BioniCosmos",target:"_blank",rel:"noopener noreferrer"},wt=e("li",null,"tg 群突破 2500。",-1),At=e("h2",{id:"_2021-01-01",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2021-01-01"},[e("span",null,"2021.01.01")])],-1),Wt={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.2.0",target:"_blank",rel:"noopener noreferrer"},jt=e("p",null,"🎁 在元旦的最后几分钟,v1.2.0 它来了,带着周五必更的惯例,带着各位贡献大佬的心血以及 @rprxx 的黑眼圈,不负众望的来了!",-1),Bt=o('
                                    46. 圣诞礼物v1.1.5后的元旦礼物 🎁,游戏玩家大福利,全面 FullCone。
                                    47. (UDP 还会继续增强!)
                                    48. 如果你已经拆过圣诞礼物,这次还有比圣诞礼物更精美的包装和小糖果哦。(同样不用问,更新品尝就对了)
                                    49. (不,下面不是广告,是里程碑。)
                                    50. Xray 是有史以来第一个不受限制的多协议平台:只需 Xray 即可解决问题,无需借力其它实现。
                                      • 一人扛起了所有!支持各大主流协议!
                                      • 一骑绝尘的性能!
                                      • 日趋完善的功能!
                                      • 可怕的生命力与社区亲和力!
                                    51. ',5),Ft={href:"https://github.com/XTLS/Xray-core/discussions/56",target:"_blank",rel:"noopener noreferrer"},Gt={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.2.0",target:"_blank",rel:"noopener noreferrer"},Mt=e("s",null,"(啊,有人敲门...我一会和你们说)",-1),qt=e("h2",{id:"_2020-12-29",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2020-12-29"},[e("span",null,"2020.12.29")])],-1),Ot={href:"https://t.me/projectXray",target:"_blank",rel:"noopener noreferrer"},Yt={id:"_2020-12-25-1-1-5",tabindex:"-1"},Qt={class:"header-anchor",href:"#_2020-12-25-1-1-5"},Kt={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.1.5",target:"_blank",rel:"noopener noreferrer"},zt=e("p",null,"圣诞节快乐!",-1),Jt=e("li",null,"游戏玩家的圣诞礼物!你可以用 xray 爽快的打游戏啦!因为有了 SS/trojan UDP fullcone",-1),Zt=e("li",null,"你可以用你喜欢的格式写配置文件了,比如 yaml,比如 toml...",-1),$t=e("li",null,"(VLESS 的 UDP fullcone 和更多增强很快就到!)",-1),es=e("li",null,"无须再担心证书验证被墙,OCSP stapling 已经上线!",-1),ls={href:"https://github.com/XTLS/Xray-install",target:"_blank",rel:"noopener noreferrer"},ns=e("li",null,"还有更多美味小樱桃!(不用问,更新品尝就对了)",-1),ts=e("h2",{id:"_2020-12-24",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2020-12-24"},[e("span",null,"2020.12.24")])],-1),ss={href:"https://xtls.github.io",target:"_blank",rel:"noopener noreferrer"},as=e("p",null,"大家可以查阅各种内容也欢迎纠错/提出建议(可发往文档 github 仓库的 issue 区)",-1),os={href:"https://github.com/XTLS/XTLS.github.io",target:"_blank",rel:"noopener noreferrer"},rs=e("p",null,"仓库的 readme 中有简略教程说明如何帮助 xray 改进文档网站. 欢迎大家查看,纠错,修改,增加心得。",-1),is=e("h2",{id:"_2020-12-23",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2020-12-23"},[e("span",null,"2020.12.23")])],-1),hs={href:"https://t.me/projectXray",target:"_blank",rel:"noopener noreferrer"},_s=e("h2",{id:"_2020-12-21",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2020-12-21"},[e("span",null,"2020.12.21")])],-1),cs=e("ul",null,[e("li",null,"Project X 群人数 2000+"),e("li",null,"群消息(含游戏群) 日均破万")],-1),ds={id:"_2020-12-18-1-1-4",tabindex:"-1"},us={class:"header-anchor",href:"#_2020-12-18-1-1-4"},ps={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.1.4",target:"_blank",rel:"noopener noreferrer"},fs=e("ul",null,[e("li",null,"更低的启动内占用和内存使用优化"),e("li",null,"随意定制的 TLS 提高你的 SSL 评级"),e("li",null,"支持 XTLS 入站的 Splice 以及支持 trojan 的 XTLS"),e("li",null,"还有在您路由器上使用的 Splice 最佳使用模式建议")],-1),bs=e("h2",{id:"_2020-12-17",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2020-12-17"},[e("span",null,"2020.12.17")])],-1),gs={href:"https://t.me/joinchat/UO4NixbB_XDQJOUjS6mHEQ",target:"_blank",rel:"noopener noreferrer"},Xs=e("h2",{id:"_2020-12-15",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2020-12-15"},[e("span",null,"2020.12.15")])],-1),vs={href:"https://github.com/XTLS/Xray-install/tree/dev",target:"_blank",rel:"noopener noreferrer"},Ss={id:"_2020-12-11-1-1-3",tabindex:"-1"},Ts={class:"header-anchor",href:"#_2020-12-11-1-1-3"},ks={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.1.3",target:"_blank",rel:"noopener noreferrer"},ms=e("ul",null,[e("li",null,"完整版本的 REDIRECT 透明代理模式."),e("li",null,"软路由 splice 流控模式的优化建议.")],-1),xs={id:"_2020-12-06-1-1-2",tabindex:"-1"},ys={class:"header-anchor",href:"#_2020-12-06-1-1-2"},Ls={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.1.2",target:"_blank",rel:"noopener noreferrer"},Ps=o('
                                      • 流控增加 splice 模式, Linux 限定, 性能一骑绝尘.
                                      • 增强了 API 兼容

                                      2020.12.04

                                      增加 splice 模式

                                      2020.11.27

                                      • Project X 的 GitHub 主仓库 Xray-core 已获 500+ stars
                                      • 登上了 GitHub Trending
                                      • Project X 群人数破千,频道订阅数 500+
                                      ',5),Hs={id:"_2020-11-25-1-0-0",tabindex:"-1"},Ds={class:"header-anchor",href:"#_2020-11-25-1-0-0"},Us={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.0.0",target:"_blank",rel:"noopener noreferrer"},Rs=e("p",null,"Xray 的第一个版本.",-1),Cs=e("ul",null,[e("li",null,"基于 v2ray-core 修改而来,改动较大"),e("li",null,"全面增强, 性能卓越, 完全兼容")],-1),Es=e("h2",{id:"_2020-11-23",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2020-11-23"},[e("span",null,"2020.11.23")])],-1),Ns=e("p",null,"project X start",-1),Is=e("blockquote",null,[e("p",null,[e("s",null,"梦开始的时候")])],-1);function Vs(ws,As){const h=i("I18nTip"),t=i("ExternalLinkIcon"),a=i("Badge"),r=i("RouterLink");return c(),d("div",null,[p,n(h),f,b,e("h2",g,[e("a",X,[e("span",null,[l("2024.9.7 "),n(a,null,{default:s(()=>[e("a",v,[l("v24.9.7"),n(t)])]),_:1})])])]),S,T,e("h2",k,[e("a",m,[e("span",null,[l("2024.8.30 "),n(a,null,{default:s(()=>[e("a",x,[l("v1.8.24"),n(t)])]),_:1})])])]),y,e("p",null,[l("We have created "),e("a",L,[l("Project VLESS"),n(t)]),l(" for non-Chinese users (mainly Russian).")]),P,e("p",null,[l("第一个 "),e("a",H,[l("Project X NFT"),n(t)]),l(" 正式发行!")]),D,e("h2",U,[e("a",R,[e("span",null,[l("2024.7.29 "),n(a,null,{default:s(()=>[e("a",C,[l("v1.8.23"),n(t)])]),_:1})])])]),e("ul",null,[e("li",null,[l("恭喜 "),e("a",E,[l("@mmmray"),n(t)]),l(" 贡献了 Xray-core 的第 1000 个 commit!")]),N,I]),e("h2",V,[e("a",w,[e("span",null,[l("2024.7.22 "),n(a,null,{default:s(()=>[e("a",A,[l("v1.8.21"),n(t)])]),_:1})])])]),W,j,B,F,e("p",null,[l("Project X 文档迎来了俄语版!感谢 "),e("a",G,[l("@iambabyninja"),n(t)]),l(" 的翻译!")]),M,q,e("p",null,[l("通过已知信息以及努力,Xray-core 现在重新支持 Windows 7!在后续的发版中,Windows 7 用户下载名为 Xray-win7-32.zip 或 Xray-win7-64.zip 的压缩包解压即可享受,感谢大家的支持!具体使用方式请点"),n(r,{to:"/ru/document/install.html"},{default:s(()=>[l("这里")]),_:1})]),O,e("h2",Y,[e("a",Q,[e("span",null,[l("2024.6.18 "),n(a,null,{default:s(()=>[e("a",K,[l("v1.8.16"),n(t)])]),_:1})])])]),z,J,Z,$,e("h2",ee,[e("a",le,[e("span",null,[l("2024.4.26 "),n(a,null,{default:s(()=>[e("a",ne,[l("v1.8.11"),n(t)])]),_:1})])])]),te,se,e("p",null,[l("我们现在有了 issues 模板,感谢 "),e("a",ae,[l("@Fangliding"),n(t)]),l(" !")]),oe,re,e("h2",ie,[e("a",he,[e("span",null,[l("2024.3.18 "),n(a,null,{default:s(()=>[e("a",_e,[l("v1.8.10"),n(t)])]),_:1})])])]),ce,e("h2",de,[e("a",ue,[e("span",null,[l("2024.3.11 "),n(a,null,{default:s(()=>[e("a",pe,[l("v1.8.9"),n(t)])]),_:1})])])]),fe,be,ge,Xe,e("h2",ve,[e("a",Se,[e("span",null,[l("2024.2.25 "),n(a,null,{default:s(()=>[e("a",Te,[l("v1.8.8"),n(t)])]),_:1})])])]),ke,me,xe,ye,e("p",null,[l("发表在 USENIX 顶会的"),e("a",Le,[l("论文"),n(t)]),l("证实,XTLS Vision 已经达到它的设计目标。")]),Pe,e("h2",He,[e("a",De,[e("span",null,[l("2023.11.18 "),n(a,null,{default:s(()=>[e("a",Ue,[l("v1.8.6"),n(t)])]),_:1})])])]),Re,e("h2",Ce,[e("a",Ee,[e("span",null,[l("2023.8.29 "),n(a,null,{default:s(()=>[e("a",Ne,[l("v1.8.4"),n(t)])]),_:1})])])]),Ie,e("p",null,[e("a",Ve,[l("如何选取 REALITY 目标域名?来看这里助你事半功倍!"),n(t)])]),e("h2",we,[e("a",Ae,[e("span",null,[l("2023.6.19 "),n(a,null,{default:s(()=>[e("a",We,[l("v1.8.3"),n(t)])]),_:1})])])]),je,e("p",null,[l("也许我们可以借助一下 "),e("a",Be,[l("RealiTLScanner"),n(t)]),l("……")]),Fe,e("p",null,[l("经过长年累月的开发,累积代码不计其数…… "),e("a",Ge,[l("精简代码计划"),n(t)]),l(" 被提出了!")]),Me,qe,e("h2",Oe,[e("a",Ye,[e("span",null,[l("2023.4.18 "),n(a,null,{default:s(()=>[e("a",Qe,[l("v1.8.1"),n(t)])]),_:1})])])]),Ke,e("h2",ze,[e("a",Je,[e("span",null,[l("2023.3.9 "),n(a,null,{default:s(()=>[e("a",Ze,[l("v1.8.0"),n(t)])]),_:1})])])]),$e,e("h2",el,[e("a",ll,[e("span",null,[l("2023.2.8 "),n(a,null,{default:s(()=>[e("a",nl,[l("v1.7.5"),n(t)])]),_:1})])])]),tl,e("ul",null,[e("li",null,[l("恭喜 "),e("a",sl,[l("@yuhan6665"),n(t)]),l(" 贡献了 Xray-core 的第 500 个 commit!")]),al,ol,rl,il,hl]),_l,cl,e("h2",dl,[e("a",ul,[e("span",null,[l("2022.12.26 "),n(a,null,{default:s(()=>[e("a",pl,[l("v1.7.0"),n(t)])]),_:1})])])]),fl,bl,e("h2",gl,[e("a",Xl,[e("span",null,[l("2022.11.28 "),n(a,null,{default:s(()=>[e("a",vl,[l("v1.6.5"),n(t)])]),_:1})])])]),Sl,Tl,e("h2",kl,[e("a",ml,[e("span",null,[l("2022.11.7 "),n(a,null,{default:s(()=>[e("a",xl,[l("v1.6.3"),n(t)])]),_:1})])])]),yl,e("h2",Ll,[e("a",Pl,[e("span",null,[l("2022.10.29 "),n(a,null,{default:s(()=>[e("a",Hl,[l("v1.6.2"),n(t)])]),_:1})])])]),Dl,e("h2",Ul,[e("a",Rl,[e("span",null,[l("2022.10.22 "),n(a,null,{default:s(()=>[e("a",Cl,[l("v1.6.1"),n(t)])]),_:1})])])]),El,e("h2",Nl,[e("a",Il,[e("span",null,[l("2022.8.28 "),n(a,null,{default:s(()=>[e("a",Vl,[l("v1.5.10"),n(t)])]),_:1})])])]),wl,e("h2",Al,[e("a",Wl,[e("span",null,[l("2022.6.20 "),n(a,null,{default:s(()=>[e("a",jl,[l("v1.5.8"),n(t)])]),_:1})])])]),Bl,e("h2",Fl,[e("a",Gl,[e("span",null,[l("2022.5.29 "),n(a,null,{default:s(()=>[e("a",Ml,[l("v1.5.6"),n(t)])]),_:1})])])]),ql,e("ul",null,[e("li",null,[l("感谢 "),e("a",Ol,[l("@nekohasekai"),n(t)]),l(" 开发全新 go 实现 https://github.com/SagerNet/sing-shadowsocks 并引入 Xray。")]),e("li",null,[l("感谢 "),e("a",Yl,[l("@database64128"),n(t)]),l(" 推动 Shadowsocks 社区提出完整设计方案。")]),e("li",null,[l("感谢 "),e("a",Ql,[l("@RPRX"),n(t)]),l(" 提交原始漏洞。")])]),Kl,zl,e("h2",Jl,[e("a",Zl,[e("span",null,[l("2022.4.24 "),n(a,null,{default:s(()=>[e("a",$l,[l("v1.5.5"),n(t)])]),_:1})])])]),en,ln,e("h2",nn,[e("a",tn,[e("span",null,[l("2022.3.13 "),n(a,null,{default:s(()=>[e("a",sn,[l("v1.5.4"),n(t)])]),_:1})])])]),an,e("h2",on,[e("a",rn,[e("span",null,[l("2022.1.29 "),n(a,null,{default:s(()=>[e("a",hn,[l("v1.5.3"),n(t)])]),_:1})])])]),_n,cn,e("h2",dn,[e("a",un,[e("span",null,[l("2021.12.24 "),n(a,null,{default:s(()=>[e("a",pn,[l("v1.5.2"),n(t)])]),_:1})])])]),fn,e("h2",bn,[e("a",gn,[e("span",null,[l("2021.12.15 "),n(a,null,{default:s(()=>[e("a",Xn,[l("v1.5.1"),n(t)])]),_:1})])])]),vn,Sn,e("h2",Tn,[e("a",kn,[e("span",null,[l("2021.10.20 "),n(a,null,{default:s(()=>[e("a",mn,[l("v1.5.0"),n(t)])]),_:1})])])]),xn,yn,e("h2",Ln,[e("a",Pn,[e("span",null,[l("2021.9.23 "),n(a,null,{default:s(()=>[e("a",Hn,[l("v1.4.5"),n(t)])]),_:1})])])]),Dn,e("ul",null,[e("li",null,[l("文档站已经完全切换到 docs-next,丝般顺滑,体验更好!地址仍为 "),e("a",Un,[l("https://xtls.github.io/"),n(t)])])]),e("h2",Rn,[e("a",Cn,[e("span",null,[l("2021.9.8 "),n(a,null,{default:s(()=>[e("a",En,[l("v1.4.3"),n(t)])]),_:1})])])]),Nn,e("p",null,[l("现在一个以 Xray-core 为核心的开源、自由的 Android 客户端已经出现——"),e("a",In,[l("AnXray"),n(t)]),l("!由 "),e("a",Vn,[l("@nekohasekai"),n(t)]),l(" 维护。")]),e("ul",null,[wn,e("li",null,[l("首席视觉设计师 "),e("a",An,[l("@RPRX"),n(t)]),l(" 设计了 X-style 的 logo、slogan,以及独一无二的 material 黑白主题。")]),Wn]),jn,e("h2",Bn,[e("a",Fn,[e("span",null,[l("2021.4.1 "),n(a,null,{default:s(()=>[e("a",Gn,[l("v1.4.2"),n(t)])]),_:1})])])]),Mn,e("h2",qn,[e("a",On,[e("span",null,[l("2021.3.14 "),n(a,null,{default:s(()=>[e("a",Yn,[l("v1.4.0"),n(t)])]),_:1})])])]),Qn,e("h2",Kn,[e("a",zn,[e("span",null,[l("2021.3.3 "),n(a,null,{default:s(()=>[e("a",Jn,[l("1.3.1"),n(t)])]),_:1})])])]),Zn,e("h2",$n,[e("a",et,[e("span",null,[l("2021.2.14 "),n(a,null,{default:s(()=>[e("a",lt,[l("1.3.0"),n(t)])]),_:1})])])]),nt,e("h2",tt,[e("a",st,[e("span",null,[l("2021.01.31 "),n(a,null,{default:s(()=>[e("a",at,[l("1.2.4"),n(t)])]),_:1})])])]),ot,rt,e("ul",null,[e("li",null,[l("全互联网最好最详细的秘籍入门篇同学们练熟了吗? 🍉 老师开始连载"),n(r,{to:"/ru/document/level-1/"},{default:s(()=>[l("秘籍第一层")]),_:1}),l("咯...")]),it]),e("h2",ht,[e("a",_t,[e("span",null,[l("2021.01.22 "),n(a,null,{default:s(()=>[e("a",ct,[l("1.2.3"),n(t)])]),_:1})])])]),e("ul",null,[dt,ut,pt,ft,bt,e("li",null,[l("向发现问题->开 issue->自行测试->自行分析->自行找到问题->自行解决->然后给上下游提交 PR 的大佬 "),e("a",gt,[l("@Bohan Yang"),n(t)]),l(" 致敬!")]),Xt]),vt,e("ul",null,[e("li",null,[l("辛苦的翻译工作开始了, 感谢 "),e("a",St,[l("@玖柒 Max"),n(t)]),l("和其他所有的翻译大佬们.")]),e("li",null,[e("a",Tt,[l("English version"),n(t)])])]),e("h2",kt,[e("a",mt,[e("span",null,[l("2021.01.15 "),n(a,null,{default:s(()=>[e("a",xt,[l("1.2.2"),n(t)])]),_:1})])])]),yt,e("ul",null,[Lt,e("li",null,[l("🍉 老师的"),n(r,{to:"/ru/document/level-0/"},{default:s(()=>[l("小小白白话文")]),_:1}),l("大结局, 撒花.")])]),e("h2",Pt,[e("a",Ht,[e("span",null,[l("2021.01.10 "),n(a,null,{default:s(()=>[e("a",Dt,[l("1.2.1"),n(t)])]),_:1})])])]),e("ul",null,[e("li",null,[n(r,{to:"/ru/document/level-0/"},{default:s(()=>[l("小小白白话文")]),_:1}),l("连载上线啦,🍉 老师呕心沥血之作, 手把手教你从什么都不会到熟练配置 Xray!")]),Ut,e("li",null,[n(r,{to:"/ru/document/level-2/"},{default:s(()=>[l("透明代理")]),_:1}),l("也增加了更多文章.")]),Rt,e("li",null,[l("感谢 "),e("a",Ct,[l("@ricuhkaen"),n(t)]),l(" , "),e("a",Et,[l("@BioniCosmos"),n(t)]),l(", "),e("a",Nt,[l("@kirin"),n(t)])])]),It,e("ul",null,[e("li",null,[l("文档仓库第一个 PR。🎉 "),n(r,{to:"/ru/document/level-2/tproxy.html"},{default:s(()=>[l("透明代理(TProxy)配置教程 ")]),_:1}),l(" ,感谢 "),e("a",Vt,[l("@BioniCosmos"),n(t)])]),wt]),At,e("p",null,[l("【祝大家新年快乐,嗨皮牛耶!】🎆🎇🎆 "),n(a,null,{default:s(()=>[e("a",Wt,[l("1.2.0"),n(t)])]),_:1})]),jt,e("ul",null,[Bt,e("li",null,[l("Xray 将继续保持前行! 因此 "),e("a",Ft,[l("Xray 需要更多的英雄!!"),n(t)]),l("!")]),e("li",null,[l("PS:请品,请细品"),e("a",Gt,[l("release notes"),n(t)]),l("每一句。似乎有一个小秘密小彩蛋 "),Mt])]),qt,e("p",null,[l("透明代理的游戏玩家利好! Xray-core tproxy 入站, socks 出站 UDP FullCone 测试版, "),e("a",Ot,[l("TG 群"),n(t)]),l("火热测试中")]),e("h2",Yt,[e("a",Qt,[e("span",null,[l("2020.12.25 "),n(a,null,{default:s(()=>[e("a",Kt,[l("1.1.5"),n(t)])]),_:1})])])]),zt,e("ul",null,[Jt,Zt,$t,es,e("li",null,[l("kirin 带来了一大波 脚本更新."),e("a",ls,[l("脚本在此"),n(t)])]),ns]),ts,e("p",null,[l("因为某些不可描述的原因,Xray 的文档网站已在发布日前偷跑上线。 网址为:"),e("a",ss,[l("没错你正在看的就是"),n(t)])]),as,e("p",null,[l("文档网站需要不断完善和增加内容,以及完善设计。 因此更欢迎大家一起为文档建设添砖加瓦。 "),e("a",os,[l("文档的仓库"),n(t)])]),rs,is,e("p",null,[l("Xray-core Shadowsocks UDP FullCone 测试版, "),e("a",hs,[l("TG 群"),n(t)]),l("火热测试中")]),_s,cs,e("h2",ds,[e("a",us,[e("span",null,[l("2020.12.18 "),n(a,null,{default:s(()=>[e("a",ps,[l("1.1.4"),n(t)])]),_:1})])])]),fs,bs,e("p",null,[l("鉴于日益增长群人数和游戏需求, 开启了"),e("a",gs,[l("TG 游戏群"),n(t)])]),Xs,e("p",null,[e("a",vs,[l("安装脚本 dev 分支"),n(t)]),l("开启, 持续更新功能中.")]),e("h2",Ss,[e("a",Ts,[e("span",null,[l("2020.12.11 "),n(a,null,{default:s(()=>[e("a",ks,[l("1.1.3"),n(t)])]),_:1})])])]),ms,e("h2",xs,[e("a",ys,[e("span",null,[l("2020.12.06 "),n(a,null,{default:s(()=>[e("a",Ls,[l("1.1.2"),n(t)])]),_:1})])])]),Ps,e("h2",Hs,[e("a",Ds,[e("span",null,[l("2020.11.25 "),n(a,null,{default:s(()=>[e("a",Us,[l("1.0.0"),n(t)])]),_:1})])])]),Rs,Cs,Es,Ns,Is])}const js=_(u,[["render",Vs],["__file","news.html.vue"]]);export{js as default}; +import{_,r as i,o as c,c as d,a as n,b as e,d as l,w as s,e as o}from"./app-D7uBbsY3.js";const u={},p=e("h1",{id:"大史记",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#大史记"},[e("span",null,"大史记")])],-1),f=e("h2",{id:"_2024-9-12",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2024-9-12"},[e("span",null,"2024.9.12")])],-1),b=e("p",null,"大史记重出江湖?!",-1),g={id:"_2024-9-7-v24-9-7",tabindex:"-1"},X={class:"header-anchor",href:"#_2024-9-7-v24-9-7"},v={href:"https://github.com/XTLS/Xray-core/releases/tag/v24.9.7",target:"_blank",rel:"noopener noreferrer"},S=e("p",null,"更改版本号之后的首次发版。",-1),T=e("ul",null,[e("li",null,[l("这次移除了 QUIC 以及 DomainSocket 传输,移除了两处远古配置遗留代码。 "),e("ul",null,[e("li",null,"二进制大小比 v1.8.24 减小了 1MB。")])]),e("li",null,"依然有每次必备的 bug 修复。")],-1),k={id:"_2024-8-30-v1-8-24",tabindex:"-1"},m={class:"header-anchor",href:"#_2024-8-30-v1-8-24"},x={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.24",target:"_blank",rel:"noopener noreferrer"},y=o('

                                      在等待 SplitHTTP multiplex controller 期间,main 分支已经积累了大量重要更新,所以我们决定先发一个版本。

                                      • Socks 入站现在默认兼容 HTTP 代理请求。
                                      • UDP noise (preview)
                                      • 还有一些改进。

                                      由于传统版本号的存在,为每个版本规划功能、进行排期已经严重阻碍了新功能的开发、合并、发布。所以我们决定从下个版本开始弃用传统的版本号,改用发版日期作为版本号,如 v24.8.30,并取消版本规划,全面采用流式更新,写好的功能直接合并,不再等待,预计每月月底发一个版本。

                                      毕竟对于反审查软件来说,相较于传统的版本号,新功能的及时性、每月更新更为重要,而不是发一个功能确定的版本并长期维护。

                                      下个版本会移除一些历史久远的代码,以后日常积累新代码、提醒迁移,跨年新版删代码、breaking。

                                      我们相信有了各位的捐款以及对发版形式的革新,Xray-core 这个项目会发展得更好。

                                      2024.8.26

                                      Project VLESS 群组创立。

                                      ',8),L={href:"https://t.me/projectVless",target:"_blank",rel:"noopener noreferrer"},P=e("h2",{id:"_2024-8-3",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2024-8-3"},[e("span",null,"2024.8.3")])],-1),H={href:"https://github.com/XTLS/Xray-core/discussions/3633#discussioncomment-10231076",target:"_blank",rel:"noopener noreferrer"},D=e("p",null,"就像 Xray 开创过很多历史一样,发行 NFT 也是这个领域前无古人的操作。这些 NFT 非常有纪念意义,甚至可以说是有历史意义,远大于现在的初始价格,假以时日它们必将价值连城。最后再次感谢大家对 Project X 的支持。",-1),U={id:"_2024-7-29-v1-8-23",tabindex:"-1"},R={class:"header-anchor",href:"#_2024-7-29-v1-8-23"},C={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.23",target:"_blank",rel:"noopener noreferrer"},E={href:"https://github.com/mmmray",target:"_blank",rel:"noopener noreferrer"},N=e("li",null,"优化了 SplitHTTP 上行的稳定性,服务端必须升级到该版本以支持新版客户端。",-1),I=e("li",null,"更多 SplitHTTP 上的变化。",-1),V={id:"_2024-7-22-v1-8-21",tabindex:"-1"},w={class:"header-anchor",href:"#_2024-7-22-v1-8-21"},A={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.21",target:"_blank",rel:"noopener noreferrer"},W=e("p",null,"中间似乎回到了最初的腹泻式发版状态……",-1),j=e("p",null,"正如 v1.8.16 所预告的,SplitHTTP 现已初步支持 HTTP/3(QUIC)。毫无疑问,SplitHTTP H3 已经开启了一个崭新的时代。",-1),B=e("ul",null,[e("li",null,"SplitHTTP H3 是第一个完全基于标准 H3、支持套 CDN 的 QUIC 类代理,亦可用反代、Browser Dialer 来隐蔽自身。")],-1),F=e("h2",{id:"_2024-7-16",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2024-7-16"},[e("span",null,"2024.7.16")])],-1),G={href:"https://github.com/iambabyninja",target:"_blank",rel:"noopener noreferrer"},M=e("blockquote",null,[e("p",null,"Привет, друзья из России!")],-1),q=e("h2",{id:"_2024-7-15",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2024-7-15"},[e("span",null,"2024.7.15")])],-1),O=e("p",null,"虽然日后随着各方面升级 Windows 7 最终会离开,但是现在还是可以让这个时间来得稍微晚一些。",-1),Y={id:"_2024-6-18-v1-8-16",tabindex:"-1"},Q={class:"header-anchor",href:"#_2024-6-18-v1-8-16"},K={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.16",target:"_blank",rel:"noopener noreferrer"},z=e("p",null,"新传输来了,它目前叫 SplitHTTP。",-1),J=e("ul",null,[e("li",null,"实现进一步的流量混淆有两种刚好相反的方式:多路复用与拆分连接。"),e("li",null,"可以通过不支持 WebSocket、gRPC 的 CDN,实现与 Meek 相同的目标,且 SplitHTTP 比 Meek 更简单、效率更高。"),e("li",null,"SplitHTTP 没有 WebSocket 的 ALPN 问题,这是一大优势,未来还会支持 HTTP/3(QUIC)。"),e("li",null,"另外 SplitHTTP 也已经加入分享链接套餐~")],-1),Z=e("h2",{id:"_2024-6-2",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2024-6-2"},[e("span",null,"2024.6.2")])],-1),$=e("p",null,"一个新的传输方式正在被打造……",-1),ee={id:"_2024-4-26-v1-8-11",tabindex:"-1"},le={class:"header-anchor",href:"#_2024-4-26-v1-8-11"},ne={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.11",target:"_blank",rel:"noopener noreferrer"},te=e("ul",null,[e("li",null,"现在有了生成 ECH 密钥的工具。"),e("li",null,"增强、修复,并移除了一点不再使用的代码。")],-1),se=e("h2",{id:"_2024-4-20",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2024-4-20"},[e("span",null,"2024.4.20")])],-1),ae={href:"https://github.com/Fangliding",target:"_blank",rel:"noopener noreferrer"},oe=e("h2",{id:"_2024-4-13",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2024-4-13"},[e("span",null,"2024.4.13")])],-1),re=e("p",null,"VLESS Seed 整备完毕,待势而发。",-1),ie={id:"_2024-3-18-v1-8-10",tabindex:"-1"},he={class:"header-anchor",href:"#_2024-3-18-v1-8-10"},_e={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.10",target:"_blank",rel:"noopener noreferrer"},ce=e("p",null,"和 WebSocket 一样,HTTPUpgrade 也有 0-RTT 了。",-1),de={id:"_2024-3-11-v1-8-9",tabindex:"-1"},ue={class:"header-anchor",href:"#_2024-3-11-v1-8-9"},pe={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.9",target:"_blank",rel:"noopener noreferrer"},fe=e("p",null,"新增 HTTPUpgrade 传输,听说比 WebSocket 要轻。",-1),be=e("ul",null,[e("li",null,"已加入分享链接套餐~")],-1),ge=e("h2",{id:"_2024-2-29",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2024-2-29"},[e("span",null,"2024.2.29")])],-1),Xe=e("p",null,[l("gRPC 传输现在也有 Host 一样的配置字段了!它叫 "),e("code",null,"authority"),l("。这下 gRPC 也能“域前置”了,没有 ALPN 问题。")],-1),ve={id:"_2024-2-25-v1-8-8",tabindex:"-1"},Se={class:"header-anchor",href:"#_2024-2-25-v1-8-8"},Te={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.8",target:"_blank",rel:"noopener noreferrer"},ke=e("ul",null,[e("li",null,"现在 XUDP 流量统一使用 Vision 填充了,速来体验。"),e("li",null,"新增了 leastLoad balancer。"),e("li",null,"修复错误、优化性能……")],-1),me=e("h2",{id:"_2024-1-9",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2024-1-9"},[e("span",null,"2024.1.9")])],-1),xe=e("p",null,"惊闻 Win7 无法运行新版 Xray-core?探索之下竟发现 Go 放弃了对 Win7 的支持。有什么办法能继续支持这个有些古老但是依然优雅的操作系统吗?",-1),ye=e("h2",{id:"_2023-11-21",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2023-11-21"},[e("span",null,"2023.11.21")])],-1),Le={href:"https://t.me/projectXtls/212",target:"_blank",rel:"noopener noreferrer"},Pe=e("p",null,"而 XTLS 也不会止步于此,如 X 射线一般穿破高耸的围墙。",-1),He={id:"_2023-11-18-v1-8-6",tabindex:"-1"},De={class:"header-anchor",href:"#_2023-11-18-v1-8-6"},Ue={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.6",target:"_blank",rel:"noopener noreferrer"},Re=o('
                                      • WireGuard 现在也有了对应的入站。Freedom 出站也终于有了 splice。
                                      • 现在出站的 domainStrategy 也得到了统一。
                                      • 更多的美味小点心。
                                      • 因为 不可抗力 功能变更,Dragonfly BSD 支持黯然离场。
                                      • 我们真的要对一代经典 Windows 7 说再见了吗?

                                      2023.9.30

                                      为 v2rayNG 设计了全新的配色,安装最新的 Pre-release 版本即可体验。

                                      ',3),Ce={id:"_2023-8-29-v1-8-4",tabindex:"-1"},Ee={class:"header-anchor",href:"#_2023-8-29-v1-8-4"},Ne={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.4",target:"_blank",rel:"noopener noreferrer"},Ie=o('

                                      1.8.x 在经过半年的打磨后终于来到了第一个认可的正式版了。

                                      同样地,这次集成的改进也不少,速来品尝!

                                      2023.7.22

                                      又修好了一个 HTTP/2 传输的历史遗留断流问题。

                                      2023.7.7

                                      即将给 Vision 添加 Seed 支持。

                                      2023.6.30

                                      下一个 XTLS 流控:xtls-rprx-switch 🍪

                                      • XTLS 的 0-RTT 已经预告几个月了,本来也是想保留神秘感。
                                      • 对比现有的 XTLS Vision 和 Mux 有着更加不错的优势。

                                      2023.6.27

                                      ',10),Ve={href:"https://github.com/XTLS/Xray-core/discussions/2256#discussioncomment-6295296",target:"_blank",rel:"noopener noreferrer"},we={id:"_2023-6-19-v1-8-3",tabindex:"-1"},Ae={class:"header-anchor",href:"#_2023-6-19-v1-8-3"},We={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.3",target:"_blank",rel:"noopener noreferrer"},je=o('
                                      • 精简代码计划后的第一个版本,VMess (MD5)、MTProto 以及 Starlark 相关代码已被卸下。轻装上阵。
                                      • 对代码进重构也是轻装上阵的一部分。
                                      • 同时我们也没有忘记增添一些增强功能,还有修复漏洞。
                                      • v1.8.3 为今年的最后一个版本。

                                      2023.6.6

                                      好消息:下一个 XTLS 流控不叫 Vision。 🍪

                                      2023.4.21

                                      ',4),Be={href:"https://github.com/XTLS/RealiTLScanner",target:"_blank",rel:"noopener noreferrer"},Fe=e("h2",{id:"_2023-4-20",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2023-4-20"},[e("span",null,"2023.4.20")])],-1),Ge={href:"https://github.com/XTLS/Xray-core/discussions/1967",target:"_blank",rel:"noopener noreferrer"},Me=e("h2",{id:"_2023-4-19",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2023-4-19"},[e("span",null,"2023.4.19")])],-1),qe=e("p",null,[e("code",null,"xtls-0rtt-vision(-udp443)"),l(" 🍪")],-1),Oe={id:"_2023-4-18-v1-8-1",tabindex:"-1"},Ye={class:"header-anchor",href:"#_2023-4-18-v1-8-1"},Qe={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.1",target:"_blank",rel:"noopener noreferrer"},Ke=o('

                                      升级后的 XUDP 也来了!

                                      • 现在 XUDP 也带有连接迁移、端口复用的特性,并且带有全局 Session ID ,麻麻再也不用担心意外断线的时候怎么办了
                                      • 同时我们也添加了 XUDP 的控制配置,让你能更好掌控它~
                                      • 新的 XUDP 配合 XTLS Vision 食用风味更好喔~
                                      • 惯例还有小甜点,欢迎品尝~

                                      2023.4.6

                                      XUDP 也在悄然升级……

                                      2023.3.29

                                      PLUX protocol 🍪

                                      2023.3.19

                                      对 REALITY 的分享链接标准也已经出现了。

                                      ',8),ze={id:"_2023-3-9-v1-8-0",tabindex:"-1"},Je={class:"header-anchor",href:"#_2023-3-9-v1-8-0"},Ze={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.8.0",target:"_blank",rel:"noopener noreferrer"},$e=o('

                                      THE NEXT FUTURE, REALITY is NOW release on Xray-core

                                      REALITY 已经实装发版!欢迎体验! XTLS Vision 也已经完善,请两端升级至最新版食用。

                                      • 因为这次 Vision 填充算法改变,XTLS Vision 旧版和新版之间会存在兼容性问题。
                                      • HTTP/2 传输也已经做了改善,现在使用新版即可纵享丝滑~
                                      • 还有大量小改进欢迎体验~

                                      2023.3.4

                                      Legends never die, they become a part of you VLESS.

                                      They simply fade away.

                                      2023.3.2

                                      HTTP/2 传输的一些遗留问题已经被改善,欢迎搭配 REALITY 测试纵享丝滑~

                                      2023.2.16

                                      THE NEXT FUTURE becomes THE REALITY NOW!

                                      2023.2.9

                                      REALITY is reality now!

                                      ',11),el={id:"_2023-2-8-v1-7-5",tabindex:"-1"},ll={class:"header-anchor",href:"#_2023-2-8-v1-7-5"},nl={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.7.5",target:"_blank",rel:"noopener noreferrer"},tl=e("p",null,"Keep riding and never look back.",-1),sl={href:"https://github.com/yuhan6665",target:"_blank",rel:"noopener noreferrer"},al=e("li",null,"XTLS Vision 流控已经接近完善,即将实用。",-1),ol=e("li",null,"现在对 uTLS 指纹模拟添加了更多可选项,有哪一款适合你?",-1),rl=e("li",null,"分享链接也支持同时分享 uTLS 指纹配置了。",-1),il=e("li",null,"还有更多的功能增强和修复。",-1),hl=e("li",null,[l("这一版也是能最后一次看到 XTLS Origin、Direct 和 Splice 流控的一版了。 "),e("s",null,"有点伤感不是吗?")],-1),_l=e("h2",{id:"_2023-1-29",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2023-1-29"},[e("span",null,"2023.1.29")])],-1),cl=e("p",null,"Winter cannot cover the NEXT FUTURE...",-1),dl={id:"_2022-12-26-v1-7-0",tabindex:"-1"},ul={class:"header-anchor",href:"#_2022-12-26-v1-7-0"},pl={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.7.0",target:"_blank",rel:"noopener noreferrer"},fl=e("p",null,"因为手滑,这次的版本号直接大升,感谢大家支持!",-1),bl=e("ul",null,[e("li",null,"以后将会严格执行 Semantic Versioning。")],-1),gl={id:"_2022-11-28-v1-6-5",tabindex:"-1"},Xl={class:"header-anchor",href:"#_2022-11-28-v1-6-5"},vl={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.6.5",target:"_blank",rel:"noopener noreferrer"},Sl=e("p",null,"这次我们有了 WireGuard 出站。",-1),Tl=e("ul",null,[e("li",null,"使用 WireGuard 搭配 CF WARP 使用可以解锁有趣的新玩法呢。"),e("li",null,"同样安全更新和修复也不会少。")],-1),kl={id:"_2022-11-7-v1-6-3",tabindex:"-1"},ml={class:"header-anchor",href:"#_2022-11-7-v1-6-3"},xl={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.6.3",target:"_blank",rel:"noopener noreferrer"},yl=e("p",null,[l("现在 Vision 流控也能使用 uTLS 指纹模拟了,这就是使用 "),e("code",null,"tlsSettings"),l(" 带来的好处吗!")],-1),Ll={id:"_2022-10-29-v1-6-2",tabindex:"-1"},Pl={class:"header-anchor",href:"#_2022-10-29-v1-6-2"},Hl={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.6.2",target:"_blank",rel:"noopener noreferrer"},Dl=e("p",null,"第一个包含 Vision 流控的发行版已经放出!欢迎试用并提交反馈!",-1),Ul={id:"_2022-10-22-v1-6-1",tabindex:"-1"},Rl={class:"header-anchor",href:"#_2022-10-22-v1-6-1"},Cl={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.6.1",target:"_blank",rel:"noopener noreferrer"},El=o('
                                      • 为 WebSocket、HTTP/2 以及 gRPC 传输带来了 uTLS 指纹支持!
                                        • 之前只有普通 TLS 下 TCP 传输能用的选项现在更好用了。
                                      • Linux 下可以单独为出入口设置 TCP 拥塞控制了。

                                      2022.10.3

                                      天气渐凉,但是并没有凉下开发的脚步。封锁天降,但无法阻止前行……

                                      • 新的 XTLS 流控酝酿中……
                                        • 解决之前流控已有的问题;
                                        • 对 TLS 1.3 直接启用 splice;
                                        • 增加 TLS 握手长度混淆;
                                        • 简化代码,使用 tlsSettings 而不是 xtlsSettings……
                                      ',4),Nl={id:"_2022-8-28-v1-5-10",tabindex:"-1"},Il={class:"header-anchor",href:"#_2022-8-28-v1-5-10"},Vl={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.5.10",target:"_blank",rel:"noopener noreferrer"},wl=e("p",null,"底层传输支持更合理的 TCP Keepalive 配置了。",-1),Al={id:"_2022-6-20-v1-5-8",tabindex:"-1"},Wl={class:"header-anchor",href:"#_2022-6-20-v1-5-8"},jl={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.5.8",target:"_blank",rel:"noopener noreferrer"},Bl=e("p",null,"现在 Shadowsocks-2022 的 relay 中转也受支持了。",-1),Fl={id:"_2022-5-29-v1-5-6",tabindex:"-1"},Gl={class:"header-anchor",href:"#_2022-5-29-v1-5-6"},Ml={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.5.6",target:"_blank",rel:"noopener noreferrer"},ql=e("p",null,"Shadowsocks-2022 协议来到了 Xray-core!",-1),Ol={href:"https://github.com/nekohasekai",target:"_blank",rel:"noopener noreferrer"},Yl={href:"https://github.com/database64128",target:"_blank",rel:"noopener noreferrer"},Ql={href:"https://github.com/RPRX",target:"_blank",rel:"noopener noreferrer"},Kl=e("p",null,"Shadowsocks-2022 是重新设计的全新协议:",-1),zl=e("ul",null,[e("li",null,"在保留 Shadowsocks 原生 udp 的基础上解决了重放攻击等安全问题(与 vmess 一样使用时间戳,因此客户端与服务端需要时间一致)。"),e("li",null,"支持单端口多用户,并且参考 quic、wireguard 等协议设计与实现使用了 session 机制,减低加密负担,保证网络变动时的无缝迁移。")],-1),Jl={id:"_2022-4-24-v1-5-5",tabindex:"-1"},Zl={class:"header-anchor",href:"#_2022-4-24-v1-5-5"},$l={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.5.5",target:"_blank",rel:"noopener noreferrer"},en=e("p",null,"这次带来了方便可视化的检测数据接口!快来体验!",-1),ln=e("ul",null,[e("li",null,"顺便修复了一些影响使用体验的问题。")],-1),nn={id:"_2022-3-13-v1-5-4",tabindex:"-1"},tn={class:"header-anchor",href:"#_2022-3-13-v1-5-4"},sn={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.5.4",target:"_blank",rel:"noopener noreferrer"},an=e("p",null,"给 Windows 平台加上了没有黑窗冒出的 wxray.exe 文件,并带来了对 UDS 监听的增强。",-1),on={id:"_2022-1-29-v1-5-3",tabindex:"-1"},rn={class:"header-anchor",href:"#_2022-1-29-v1-5-3"},hn={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.5.3",target:"_blank",rel:"noopener noreferrer"},_n=e("p",null,"牛辞胜岁,虎跃新程。🧨",-1),cn=e("ul",null,[e("li",null,"这次带来了对 QUIC 传输的流分配改进,使用 QUIC 传输现在更丝滑了。")],-1),dn={id:"_2021-12-24-v1-5-2",tabindex:"-1"},un={class:"header-anchor",href:"#_2021-12-24-v1-5-2"},pn={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.5.2",target:"_blank",rel:"noopener noreferrer"},fn=e("p",null,"为 gRPC 添加了一个新的选项,在通过 CDN 时变得更好用了。",-1),bn={id:"_2021-12-15-v1-5-1",tabindex:"-1"},gn={class:"header-anchor",href:"#_2021-12-15-v1-5-1"},Xn={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.5.1",target:"_blank",rel:"noopener noreferrer"},vn=e("blockquote",null,[e("p",null,"“过渡时期的阶段性的维护版本”")],-1),Sn=e("ul",null,[e("li",null,"新功能、增强还有大量修复陆续有来。"),e("li",null,[l("记得将 VMess 配置中的 "),e("code",null,"alterID"),l(" 去掉!")])],-1),Tn={id:"_2021-10-20-v1-5-0",tabindex:"-1"},kn={class:"header-anchor",href:"#_2021-10-20-v1-5-0"},mn={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.5.0",target:"_blank",rel:"noopener noreferrer"},xn=e("p",null,"真的是巨大的改动!",-1),yn=e("ul",null,[e("li",null,"重构了 DNS 组件,支持的协议和细化配置更多了。"),e("li",null,"增强了 gRPC 传输以及 FakeDNS。"),e("li",null,"现在终于支持 Windows ARM64 了。"),e("li",null,"更多新功能和改进等待体验。")],-1),Ln={id:"_2021-9-23-v1-4-5",tabindex:"-1"},Pn={class:"header-anchor",href:"#_2021-9-23-v1-4-5"},Hn={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.4.5",target:"_blank",rel:"noopener noreferrer"},Dn=o('

                                      中秋快乐,阖家团圆。

                                      • 修正了版本号过低,版本号不吉利的 bug。
                                      • 这次移除了 Shadowsocks 里面已经不安全的加密方式。要尽快迁移到 AEAD 加密上面喔。
                                      • 这次修复了远古时期开始就存在的历史问题:开启流量统计功能可能会使性能下降。简单来说,不论什么配置现在打开统计都不会对性能有任何影响了。
                                      • 还有对 XTLS 的安全性更新以及大量修复。
                                      • 对了,因为 TLS 库的更新,cipherSuites 不能再指定加密套件顺序了,而 preferServerCipherSuites 已经被彻底弃用。事实上这些变化在 Xray-core v1.4.3 中已经产生了。

                                      2021.9.16

                                      ',3),Un={href:"https://xtls.github.io/",target:"_blank",rel:"noopener noreferrer"},Rn={id:"_2021-9-8-v1-4-3",tabindex:"-1"},Cn={class:"header-anchor",href:"#_2021-9-8-v1-4-3"},En={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.4.3",target:"_blank",rel:"noopener noreferrer"},Nn=o('

                                      这是一个阶段性维护版本。开发仍在继续……

                                      • 在此期间累积了大量改进和新功能。
                                      • 加入新的 DomainMatcher,现在域名规则匹配性能更好了。
                                      • 加入对 HTTP/2 和 gRPC 传输的健康检查、对未知 SNI 的处理改进,以及修复了一大堆 bug。

                                      Helden sterben nicht!

                                      2021.7.14

                                      • AnXray 重金设计 的新图标已经上线!
                                        • 现在图标的辨识度更高了。
                                      • 过去三个星期,AnXray 共积累了 600 stars、2K+ 频道订阅数和 11K+ GitHub 下载量,感谢大家的支持。
                                      • AX 为 AnXray 的缩写,推荐用 AX 指代 AnXray,简短方便

                                      2021.6.21

                                      ',6),In={href:"https://github.com/XTLS/AnXray",target:"_blank",rel:"noopener noreferrer"},Vn={href:"https://github.com/nekohasekai",target:"_blank",rel:"noopener noreferrer"},wn=e("li",null,"支持众多协议、插件.",-1),An={href:"https://github.com/RPRX",target:"_blank",rel:"noopener noreferrer"},Wn=e("li",null,"APP 内还有个小彩蛋等你去发现。",-1),jn=o('

                                      前两天从早到晚反复打磨细节,希望大家多多 Star、关注。

                                      2021.5.1

                                      对 tun2socks 的改进出现在 v2rayNG 上面了。

                                      2021.4.26

                                      给 tun2socks 带来了一个改进。后续有可能能吃到它~

                                      2021.4.12

                                      现在带来了 X-flutter 前瞻,可以期待一下会是什么样子呢~ 🍪

                                      2021.4.6

                                      • VuePress Next.
                                      • With Dark Mode.

                                      2021.4.4

                                      • 本文档迎来的新的首页。
                                      • 本文档迎来了暗黑模式。
                                      • 当然,暗黑模式还有各种各样的问题。具体的内容还需要慢慢调整。
                                      • 另:Telegram 群聊突破了 5000 人!还加入了 Anti-Spam 机器人!
                                      • 🎉🎉🎉
                                      ',11),Bn={id:"_2021-4-1-v1-4-2",tabindex:"-1"},Fn={class:"header-anchor",href:"#_2021-4-1-v1-4-2"},Gn={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.4.2",target:"_blank",rel:"noopener noreferrer"},Mn=o('
                                      • 不是愚人节玩笑,今天更新。
                                      • 加入 Browser Dialer,用与改变 TLS 指纹与行为。
                                      • 加入 uTLS,用与改变 TLS Client Hello 的指纹。
                                      • 顺便修复了一大堆奇妙的问题,具体的内容见更新日志。

                                      2021.3.25

                                      没错还在变。 -_-

                                      2021.3.15

                                      文档网站正在悄悄的进行着某些神秘的变化。。。,🙊🙊🙊

                                      ',5),qn={id:"_2021-3-14-v1-4-0",tabindex:"-1"},On={class:"header-anchor",href:"#_2021-3-14-v1-4-0"},Yn={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.4.0",target:"_blank",rel:"noopener noreferrer"},Qn=o("
                                      • Happy Pi-Day!
                                      • 这次是个大更新:
                                        • 为链式代理引入了传输层支持。
                                        • 为 Dialer 引入了 Domain Strategy,解决奇妙的 DNS 问题。
                                        • 添加了 gRPC 传输方式,与更快一点的 Multi Mode。
                                        • 添加了 WebSocket Early-Data 功能,减少了 WebSocket 的延迟。
                                        • 添加了 FakeDNS。
                                        • 还修复了系列的问题,添加了各类功能,详情请见更新日志。
                                      • 还是 VuePress 比较爽啊(
                                      ",1),Kn={id:"_2021-3-3-1-3-1",tabindex:"-1"},zn={class:"header-anchor",href:"#_2021-3-3-1-3-1"},Jn={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.3.1",target:"_blank",rel:"noopener noreferrer"},Zn=e("ul",null,[e("li",null,"这个版本使用了 Golang 1.16,正式原生支持 Apple Silicon。"),e("li",null,[l("同时修复了一个会导致 Panic 的 bug。"),e("s",null,"Holmium_认为这是在骗、在偷袭。")]),e("li",null,"修复了几个遗留问题。")],-1),$n={id:"_2021-2-14-1-3-0",tabindex:"-1"},et={class:"header-anchor",href:"#_2021-2-14-1-3-0"},lt={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.3.0",target:"_blank",rel:"noopener noreferrer"},nt=e("ul",null,[e("li",null,"Happy 🐮 Year 🎉!"),e("li",null,"v1.3.0 通过非常巧妙的机制实现了 V 系协议全部 FullCone,同时保证了一定的兼容性。"),e("li",null,"OHHHHHHHHHHHH!")],-1),tt={id:"_2021-01-31-1-2-4",tabindex:"-1"},st={class:"header-anchor",href:"#_2021-01-31-1-2-4"},at={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.2.4",target:"_blank",rel:"noopener noreferrer"},ot=e("ul",null,[e("li",null,"解决两个“连接至标准 Socks 服务端时可能出错”的历史遗留问题。"),e("li",null,"似乎这个版本没有什么改变,但这只是暴风雨前的宁静。"),e("li",null,[l("(没错我就是先知) "),e("blockquote",null,[e("p",null,"你个傻子,你拿的是 UNO 牌。")])])],-1),rt=e("h2",{id:"_2021-01-25",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2021-01-25"},[e("span",null,"2021.01.25")])],-1),it=e("li",null,[e("a",{href:"../en"},"英文版文档网站"),l("逐渐增加内容 ing, 感谢各位大佬的辛苦付出~!")],-1),ht={id:"_2021-01-22-1-2-3",tabindex:"-1"},_t={class:"header-anchor",href:"#_2021-01-22-1-2-3"},ct={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.2.3",target:"_blank",rel:"noopener noreferrer"},dt=e("li",null,[l("对 SS 协议的支持"),e("strong",null,"又"),l("变强了, 支持单端口多用户!")],-1),ut=e("li",null,[l("对 trojan 协议的支持也"),e("strong",null,"又"),l("变强了, trojan 的回落也解锁 SNI 分流的新姿势啦~!")],-1),pt=e("li",null,[e("em",null,"(VLESS: 嘤嘤嘤)")],-1),ft=e("li",null,'UDP 奇奇怪怪的 BUG 被干掉了, 一个字, "稳定".',-1),bt=e("li",null,"嗅探可以排除你不想嗅探的域名, 可以开启一些新玩法.",-1),gt={href:"https://github.com/bohanyang",target:"_blank",rel:"noopener noreferrer"},Xt=e("li",null,"其他美味小樱桃, 惯例更新品尝就对啦.",-1),vt=o('

                                      2021.01.19

                                      • 一些数字
                                        • 版本发布了 10   个 tag
                                        • 解决掉了 100  个 issue
                                        • 复刻了 300  个 fork
                                        • 点了 2000 个 star
                                        • 群 3000 个 人

                                      2021.01.17

                                      ',3),St={href:"https://github.com/jiuqi9997",target:"_blank",rel:"noopener noreferrer"},Tt={href:"https://xtls.github.io/en/",target:"_blank",rel:"noopener noreferrer"},kt={id:"_2021-01-15-1-2-2",tabindex:"-1"},mt={class:"header-anchor",href:"#_2021-01-15-1-2-2"},xt={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.2.2",target:"_blank",rel:"noopener noreferrer"},yt=o('
                                      • 回落分流又解锁了奇怪的新姿势! 回落中可以根据 SNI 分流啦~!
                                      • 之前预告的 UUID 修改正式上线.(往下看往下看)
                                      • 日志现在看起来比上一次顺眼又更顺眼了一丢丢.
                                      • 远程 DOH 和其他的 DNS 模式一样学会了走路由分流.
                                      • 当然还有其他各种小糖果.(更新品尝就对了)
                                      • 啊, 还有, 世界上第一個 M1 上跑起 Xray 的男人是 Anthony TSE

                                      2021.01.12

                                      ',2),Lt=e("li",null,[l("将要到来的 UUID 修改, 支持自定义字符串和 UUID 之间的映射. 这意味着你将可以这样在配置文件中写 id 来对应用户. "),e("ul",null,[e("li",null,'客户端写 "id": "我爱 🍉 老师 1314",'),e("li",null,[l('服务端写 "id": "5783a3e7-e373-51cd-8642-c83782b807c5" (此 UUID 是 '),e("code",null,"我爱🍉老师1314"),l(" 的 UUID 映射)")])])],-1),Pt={id:"_2021-01-10-1-2-1",tabindex:"-1"},Ht={class:"header-anchor",href:"#_2021-01-10-1-2-1"},Dt={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.2.1",target:"_blank",rel:"noopener noreferrer"},Ut=e("li",null,"(可能是整个互联网上, 最详细最有耐心的教你从 0 开始配置的教程)",-1),Rt=e("li",null,"还有很多细节修改, 文档将会越来越规范!",-1),Ct={href:"https://github.com/ricuhkaen",target:"_blank",rel:"noopener noreferrer"},Et={href:"https://github.com/BioniCosmos",target:"_blank",rel:"noopener noreferrer"},Nt={href:"https://github.com/kirin10000",target:"_blank",rel:"noopener noreferrer"},It=o('
                                      • 大量的 UDP 相关修复, 甚至可以在育碧的土豆服务器上玩彩虹六号!
                                      • Google Voice 应该也可以正常使用 v2rayNG 拨打了.
                                      • 日志现在看起来更顺眼.

                                      2021.01.07

                                      • 礼貌和尊重本应是社区不需要明说的准则之一。

                                      2021.01.05

                                      • 文档网站正在悄悄的进行着某些神秘的变化。。。,🙊🙊🙊

                                      2021.01.03

                                      ',6),Vt={href:"https://github.com/BioniCosmos",target:"_blank",rel:"noopener noreferrer"},wt=e("li",null,"tg 群突破 2500。",-1),At=e("h2",{id:"_2021-01-01",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2021-01-01"},[e("span",null,"2021.01.01")])],-1),Wt={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.2.0",target:"_blank",rel:"noopener noreferrer"},jt=e("p",null,"🎁 在元旦的最后几分钟,v1.2.0 它来了,带着周五必更的惯例,带着各位贡献大佬的心血以及 @rprxx 的黑眼圈,不负众望的来了!",-1),Bt=o('
                                    52. 圣诞礼物v1.1.5后的元旦礼物 🎁,游戏玩家大福利,全面 FullCone。
                                    53. (UDP 还会继续增强!)
                                    54. 如果你已经拆过圣诞礼物,这次还有比圣诞礼物更精美的包装和小糖果哦。(同样不用问,更新品尝就对了)
                                    55. (不,下面不是广告,是里程碑。)
                                    56. Xray 是有史以来第一个不受限制的多协议平台:只需 Xray 即可解决问题,无需借力其它实现。
                                      • 一人扛起了所有!支持各大主流协议!
                                      • 一骑绝尘的性能!
                                      • 日趋完善的功能!
                                      • 可怕的生命力与社区亲和力!
                                    57. ',5),Ft={href:"https://github.com/XTLS/Xray-core/discussions/56",target:"_blank",rel:"noopener noreferrer"},Gt={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.2.0",target:"_blank",rel:"noopener noreferrer"},Mt=e("s",null,"(啊,有人敲门...我一会和你们说)",-1),qt=e("h2",{id:"_2020-12-29",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2020-12-29"},[e("span",null,"2020.12.29")])],-1),Ot={href:"https://t.me/projectXray",target:"_blank",rel:"noopener noreferrer"},Yt={id:"_2020-12-25-1-1-5",tabindex:"-1"},Qt={class:"header-anchor",href:"#_2020-12-25-1-1-5"},Kt={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.1.5",target:"_blank",rel:"noopener noreferrer"},zt=e("p",null,"圣诞节快乐!",-1),Jt=e("li",null,"游戏玩家的圣诞礼物!你可以用 xray 爽快的打游戏啦!因为有了 SS/trojan UDP fullcone",-1),Zt=e("li",null,"你可以用你喜欢的格式写配置文件了,比如 yaml,比如 toml...",-1),$t=e("li",null,"(VLESS 的 UDP fullcone 和更多增强很快就到!)",-1),es=e("li",null,"无须再担心证书验证被墙,OCSP stapling 已经上线!",-1),ls={href:"https://github.com/XTLS/Xray-install",target:"_blank",rel:"noopener noreferrer"},ns=e("li",null,"还有更多美味小樱桃!(不用问,更新品尝就对了)",-1),ts=e("h2",{id:"_2020-12-24",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2020-12-24"},[e("span",null,"2020.12.24")])],-1),ss={href:"https://xtls.github.io",target:"_blank",rel:"noopener noreferrer"},as=e("p",null,"大家可以查阅各种内容也欢迎纠错/提出建议(可发往文档 github 仓库的 issue 区)",-1),os={href:"https://github.com/XTLS/XTLS.github.io",target:"_blank",rel:"noopener noreferrer"},rs=e("p",null,"仓库的 readme 中有简略教程说明如何帮助 xray 改进文档网站. 欢迎大家查看,纠错,修改,增加心得。",-1),is=e("h2",{id:"_2020-12-23",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2020-12-23"},[e("span",null,"2020.12.23")])],-1),hs={href:"https://t.me/projectXray",target:"_blank",rel:"noopener noreferrer"},_s=e("h2",{id:"_2020-12-21",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2020-12-21"},[e("span",null,"2020.12.21")])],-1),cs=e("ul",null,[e("li",null,"Project X 群人数 2000+"),e("li",null,"群消息(含游戏群) 日均破万")],-1),ds={id:"_2020-12-18-1-1-4",tabindex:"-1"},us={class:"header-anchor",href:"#_2020-12-18-1-1-4"},ps={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.1.4",target:"_blank",rel:"noopener noreferrer"},fs=e("ul",null,[e("li",null,"更低的启动内占用和内存使用优化"),e("li",null,"随意定制的 TLS 提高你的 SSL 评级"),e("li",null,"支持 XTLS 入站的 Splice 以及支持 trojan 的 XTLS"),e("li",null,"还有在您路由器上使用的 Splice 最佳使用模式建议")],-1),bs=e("h2",{id:"_2020-12-17",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2020-12-17"},[e("span",null,"2020.12.17")])],-1),gs={href:"https://t.me/joinchat/UO4NixbB_XDQJOUjS6mHEQ",target:"_blank",rel:"noopener noreferrer"},Xs=e("h2",{id:"_2020-12-15",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2020-12-15"},[e("span",null,"2020.12.15")])],-1),vs={href:"https://github.com/XTLS/Xray-install/tree/dev",target:"_blank",rel:"noopener noreferrer"},Ss={id:"_2020-12-11-1-1-3",tabindex:"-1"},Ts={class:"header-anchor",href:"#_2020-12-11-1-1-3"},ks={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.1.3",target:"_blank",rel:"noopener noreferrer"},ms=e("ul",null,[e("li",null,"完整版本的 REDIRECT 透明代理模式."),e("li",null,"软路由 splice 流控模式的优化建议.")],-1),xs={id:"_2020-12-06-1-1-2",tabindex:"-1"},ys={class:"header-anchor",href:"#_2020-12-06-1-1-2"},Ls={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.1.2",target:"_blank",rel:"noopener noreferrer"},Ps=o('
                                      • 流控增加 splice 模式, Linux 限定, 性能一骑绝尘.
                                      • 增强了 API 兼容

                                      2020.12.04

                                      增加 splice 模式

                                      2020.11.27

                                      • Project X 的 GitHub 主仓库 Xray-core 已获 500+ stars
                                      • 登上了 GitHub Trending
                                      • Project X 群人数破千,频道订阅数 500+
                                      ',5),Hs={id:"_2020-11-25-1-0-0",tabindex:"-1"},Ds={class:"header-anchor",href:"#_2020-11-25-1-0-0"},Us={href:"https://github.com/XTLS/Xray-core/releases/tag/v1.0.0",target:"_blank",rel:"noopener noreferrer"},Rs=e("p",null,"Xray 的第一个版本.",-1),Cs=e("ul",null,[e("li",null,"基于 v2ray-core 修改而来,改动较大"),e("li",null,"全面增强, 性能卓越, 完全兼容")],-1),Es=e("h2",{id:"_2020-11-23",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_2020-11-23"},[e("span",null,"2020.11.23")])],-1),Ns=e("p",null,"project X start",-1),Is=e("blockquote",null,[e("p",null,[e("s",null,"梦开始的时候")])],-1);function Vs(ws,As){const h=i("I18nTip"),t=i("ExternalLinkIcon"),a=i("Badge"),r=i("RouterLink");return c(),d("div",null,[p,n(h),f,b,e("h2",g,[e("a",X,[e("span",null,[l("2024.9.7 "),n(a,null,{default:s(()=>[e("a",v,[l("v24.9.7"),n(t)])]),_:1})])])]),S,T,e("h2",k,[e("a",m,[e("span",null,[l("2024.8.30 "),n(a,null,{default:s(()=>[e("a",x,[l("v1.8.24"),n(t)])]),_:1})])])]),y,e("p",null,[l("We have created "),e("a",L,[l("Project VLESS"),n(t)]),l(" for non-Chinese users (mainly Russian).")]),P,e("p",null,[l("第一个 "),e("a",H,[l("Project X NFT"),n(t)]),l(" 正式发行!")]),D,e("h2",U,[e("a",R,[e("span",null,[l("2024.7.29 "),n(a,null,{default:s(()=>[e("a",C,[l("v1.8.23"),n(t)])]),_:1})])])]),e("ul",null,[e("li",null,[l("恭喜 "),e("a",E,[l("@mmmray"),n(t)]),l(" 贡献了 Xray-core 的第 1000 个 commit!")]),N,I]),e("h2",V,[e("a",w,[e("span",null,[l("2024.7.22 "),n(a,null,{default:s(()=>[e("a",A,[l("v1.8.21"),n(t)])]),_:1})])])]),W,j,B,F,e("p",null,[l("Project X 文档迎来了俄语版!感谢 "),e("a",G,[l("@iambabyninja"),n(t)]),l(" 的翻译!")]),M,q,e("p",null,[l("通过已知信息以及努力,Xray-core 现在重新支持 Windows 7!在后续的发版中,Windows 7 用户下载名为 Xray-win7-32.zip 或 Xray-win7-64.zip 的压缩包解压即可享受,感谢大家的支持!具体使用方式请点"),n(r,{to:"/ru/document/install.html"},{default:s(()=>[l("这里")]),_:1})]),O,e("h2",Y,[e("a",Q,[e("span",null,[l("2024.6.18 "),n(a,null,{default:s(()=>[e("a",K,[l("v1.8.16"),n(t)])]),_:1})])])]),z,J,Z,$,e("h2",ee,[e("a",le,[e("span",null,[l("2024.4.26 "),n(a,null,{default:s(()=>[e("a",ne,[l("v1.8.11"),n(t)])]),_:1})])])]),te,se,e("p",null,[l("我们现在有了 issues 模板,感谢 "),e("a",ae,[l("@Fangliding"),n(t)]),l(" !")]),oe,re,e("h2",ie,[e("a",he,[e("span",null,[l("2024.3.18 "),n(a,null,{default:s(()=>[e("a",_e,[l("v1.8.10"),n(t)])]),_:1})])])]),ce,e("h2",de,[e("a",ue,[e("span",null,[l("2024.3.11 "),n(a,null,{default:s(()=>[e("a",pe,[l("v1.8.9"),n(t)])]),_:1})])])]),fe,be,ge,Xe,e("h2",ve,[e("a",Se,[e("span",null,[l("2024.2.25 "),n(a,null,{default:s(()=>[e("a",Te,[l("v1.8.8"),n(t)])]),_:1})])])]),ke,me,xe,ye,e("p",null,[l("发表在 USENIX 顶会的"),e("a",Le,[l("论文"),n(t)]),l("证实,XTLS Vision 已经达到它的设计目标。")]),Pe,e("h2",He,[e("a",De,[e("span",null,[l("2023.11.18 "),n(a,null,{default:s(()=>[e("a",Ue,[l("v1.8.6"),n(t)])]),_:1})])])]),Re,e("h2",Ce,[e("a",Ee,[e("span",null,[l("2023.8.29 "),n(a,null,{default:s(()=>[e("a",Ne,[l("v1.8.4"),n(t)])]),_:1})])])]),Ie,e("p",null,[e("a",Ve,[l("如何选取 REALITY 目标域名?来看这里助你事半功倍!"),n(t)])]),e("h2",we,[e("a",Ae,[e("span",null,[l("2023.6.19 "),n(a,null,{default:s(()=>[e("a",We,[l("v1.8.3"),n(t)])]),_:1})])])]),je,e("p",null,[l("也许我们可以借助一下 "),e("a",Be,[l("RealiTLScanner"),n(t)]),l("……")]),Fe,e("p",null,[l("经过长年累月的开发,累积代码不计其数…… "),e("a",Ge,[l("精简代码计划"),n(t)]),l(" 被提出了!")]),Me,qe,e("h2",Oe,[e("a",Ye,[e("span",null,[l("2023.4.18 "),n(a,null,{default:s(()=>[e("a",Qe,[l("v1.8.1"),n(t)])]),_:1})])])]),Ke,e("h2",ze,[e("a",Je,[e("span",null,[l("2023.3.9 "),n(a,null,{default:s(()=>[e("a",Ze,[l("v1.8.0"),n(t)])]),_:1})])])]),$e,e("h2",el,[e("a",ll,[e("span",null,[l("2023.2.8 "),n(a,null,{default:s(()=>[e("a",nl,[l("v1.7.5"),n(t)])]),_:1})])])]),tl,e("ul",null,[e("li",null,[l("恭喜 "),e("a",sl,[l("@yuhan6665"),n(t)]),l(" 贡献了 Xray-core 的第 500 个 commit!")]),al,ol,rl,il,hl]),_l,cl,e("h2",dl,[e("a",ul,[e("span",null,[l("2022.12.26 "),n(a,null,{default:s(()=>[e("a",pl,[l("v1.7.0"),n(t)])]),_:1})])])]),fl,bl,e("h2",gl,[e("a",Xl,[e("span",null,[l("2022.11.28 "),n(a,null,{default:s(()=>[e("a",vl,[l("v1.6.5"),n(t)])]),_:1})])])]),Sl,Tl,e("h2",kl,[e("a",ml,[e("span",null,[l("2022.11.7 "),n(a,null,{default:s(()=>[e("a",xl,[l("v1.6.3"),n(t)])]),_:1})])])]),yl,e("h2",Ll,[e("a",Pl,[e("span",null,[l("2022.10.29 "),n(a,null,{default:s(()=>[e("a",Hl,[l("v1.6.2"),n(t)])]),_:1})])])]),Dl,e("h2",Ul,[e("a",Rl,[e("span",null,[l("2022.10.22 "),n(a,null,{default:s(()=>[e("a",Cl,[l("v1.6.1"),n(t)])]),_:1})])])]),El,e("h2",Nl,[e("a",Il,[e("span",null,[l("2022.8.28 "),n(a,null,{default:s(()=>[e("a",Vl,[l("v1.5.10"),n(t)])]),_:1})])])]),wl,e("h2",Al,[e("a",Wl,[e("span",null,[l("2022.6.20 "),n(a,null,{default:s(()=>[e("a",jl,[l("v1.5.8"),n(t)])]),_:1})])])]),Bl,e("h2",Fl,[e("a",Gl,[e("span",null,[l("2022.5.29 "),n(a,null,{default:s(()=>[e("a",Ml,[l("v1.5.6"),n(t)])]),_:1})])])]),ql,e("ul",null,[e("li",null,[l("感谢 "),e("a",Ol,[l("@nekohasekai"),n(t)]),l(" 开发全新 go 实现 https://github.com/SagerNet/sing-shadowsocks 并引入 Xray。")]),e("li",null,[l("感谢 "),e("a",Yl,[l("@database64128"),n(t)]),l(" 推动 Shadowsocks 社区提出完整设计方案。")]),e("li",null,[l("感谢 "),e("a",Ql,[l("@RPRX"),n(t)]),l(" 提交原始漏洞。")])]),Kl,zl,e("h2",Jl,[e("a",Zl,[e("span",null,[l("2022.4.24 "),n(a,null,{default:s(()=>[e("a",$l,[l("v1.5.5"),n(t)])]),_:1})])])]),en,ln,e("h2",nn,[e("a",tn,[e("span",null,[l("2022.3.13 "),n(a,null,{default:s(()=>[e("a",sn,[l("v1.5.4"),n(t)])]),_:1})])])]),an,e("h2",on,[e("a",rn,[e("span",null,[l("2022.1.29 "),n(a,null,{default:s(()=>[e("a",hn,[l("v1.5.3"),n(t)])]),_:1})])])]),_n,cn,e("h2",dn,[e("a",un,[e("span",null,[l("2021.12.24 "),n(a,null,{default:s(()=>[e("a",pn,[l("v1.5.2"),n(t)])]),_:1})])])]),fn,e("h2",bn,[e("a",gn,[e("span",null,[l("2021.12.15 "),n(a,null,{default:s(()=>[e("a",Xn,[l("v1.5.1"),n(t)])]),_:1})])])]),vn,Sn,e("h2",Tn,[e("a",kn,[e("span",null,[l("2021.10.20 "),n(a,null,{default:s(()=>[e("a",mn,[l("v1.5.0"),n(t)])]),_:1})])])]),xn,yn,e("h2",Ln,[e("a",Pn,[e("span",null,[l("2021.9.23 "),n(a,null,{default:s(()=>[e("a",Hn,[l("v1.4.5"),n(t)])]),_:1})])])]),Dn,e("ul",null,[e("li",null,[l("文档站已经完全切换到 docs-next,丝般顺滑,体验更好!地址仍为 "),e("a",Un,[l("https://xtls.github.io/"),n(t)])])]),e("h2",Rn,[e("a",Cn,[e("span",null,[l("2021.9.8 "),n(a,null,{default:s(()=>[e("a",En,[l("v1.4.3"),n(t)])]),_:1})])])]),Nn,e("p",null,[l("现在一个以 Xray-core 为核心的开源、自由的 Android 客户端已经出现——"),e("a",In,[l("AnXray"),n(t)]),l("!由 "),e("a",Vn,[l("@nekohasekai"),n(t)]),l(" 维护。")]),e("ul",null,[wn,e("li",null,[l("首席视觉设计师 "),e("a",An,[l("@RPRX"),n(t)]),l(" 设计了 X-style 的 logo、slogan,以及独一无二的 material 黑白主题。")]),Wn]),jn,e("h2",Bn,[e("a",Fn,[e("span",null,[l("2021.4.1 "),n(a,null,{default:s(()=>[e("a",Gn,[l("v1.4.2"),n(t)])]),_:1})])])]),Mn,e("h2",qn,[e("a",On,[e("span",null,[l("2021.3.14 "),n(a,null,{default:s(()=>[e("a",Yn,[l("v1.4.0"),n(t)])]),_:1})])])]),Qn,e("h2",Kn,[e("a",zn,[e("span",null,[l("2021.3.3 "),n(a,null,{default:s(()=>[e("a",Jn,[l("1.3.1"),n(t)])]),_:1})])])]),Zn,e("h2",$n,[e("a",et,[e("span",null,[l("2021.2.14 "),n(a,null,{default:s(()=>[e("a",lt,[l("1.3.0"),n(t)])]),_:1})])])]),nt,e("h2",tt,[e("a",st,[e("span",null,[l("2021.01.31 "),n(a,null,{default:s(()=>[e("a",at,[l("1.2.4"),n(t)])]),_:1})])])]),ot,rt,e("ul",null,[e("li",null,[l("全互联网最好最详细的秘籍入门篇同学们练熟了吗? 🍉 老师开始连载"),n(r,{to:"/ru/document/level-1/"},{default:s(()=>[l("秘籍第一层")]),_:1}),l("咯...")]),it]),e("h2",ht,[e("a",_t,[e("span",null,[l("2021.01.22 "),n(a,null,{default:s(()=>[e("a",ct,[l("1.2.3"),n(t)])]),_:1})])])]),e("ul",null,[dt,ut,pt,ft,bt,e("li",null,[l("向发现问题->开 issue->自行测试->自行分析->自行找到问题->自行解决->然后给上下游提交 PR 的大佬 "),e("a",gt,[l("@Bohan Yang"),n(t)]),l(" 致敬!")]),Xt]),vt,e("ul",null,[e("li",null,[l("辛苦的翻译工作开始了, 感谢 "),e("a",St,[l("@玖柒 Max"),n(t)]),l("和其他所有的翻译大佬们.")]),e("li",null,[e("a",Tt,[l("English version"),n(t)])])]),e("h2",kt,[e("a",mt,[e("span",null,[l("2021.01.15 "),n(a,null,{default:s(()=>[e("a",xt,[l("1.2.2"),n(t)])]),_:1})])])]),yt,e("ul",null,[Lt,e("li",null,[l("🍉 老师的"),n(r,{to:"/ru/document/level-0/"},{default:s(()=>[l("小小白白话文")]),_:1}),l("大结局, 撒花.")])]),e("h2",Pt,[e("a",Ht,[e("span",null,[l("2021.01.10 "),n(a,null,{default:s(()=>[e("a",Dt,[l("1.2.1"),n(t)])]),_:1})])])]),e("ul",null,[e("li",null,[n(r,{to:"/ru/document/level-0/"},{default:s(()=>[l("小小白白话文")]),_:1}),l("连载上线啦,🍉 老师呕心沥血之作, 手把手教你从什么都不会到熟练配置 Xray!")]),Ut,e("li",null,[n(r,{to:"/ru/document/level-2/"},{default:s(()=>[l("透明代理")]),_:1}),l("也增加了更多文章.")]),Rt,e("li",null,[l("感谢 "),e("a",Ct,[l("@ricuhkaen"),n(t)]),l(" , "),e("a",Et,[l("@BioniCosmos"),n(t)]),l(", "),e("a",Nt,[l("@kirin"),n(t)])])]),It,e("ul",null,[e("li",null,[l("文档仓库第一个 PR。🎉 "),n(r,{to:"/ru/document/level-2/tproxy.html"},{default:s(()=>[l("透明代理(TProxy)配置教程 ")]),_:1}),l(" ,感谢 "),e("a",Vt,[l("@BioniCosmos"),n(t)])]),wt]),At,e("p",null,[l("【祝大家新年快乐,嗨皮牛耶!】🎆🎇🎆 "),n(a,null,{default:s(()=>[e("a",Wt,[l("1.2.0"),n(t)])]),_:1})]),jt,e("ul",null,[Bt,e("li",null,[l("Xray 将继续保持前行! 因此 "),e("a",Ft,[l("Xray 需要更多的英雄!!"),n(t)]),l("!")]),e("li",null,[l("PS:请品,请细品"),e("a",Gt,[l("release notes"),n(t)]),l("每一句。似乎有一个小秘密小彩蛋 "),Mt])]),qt,e("p",null,[l("透明代理的游戏玩家利好! Xray-core tproxy 入站, socks 出站 UDP FullCone 测试版, "),e("a",Ot,[l("TG 群"),n(t)]),l("火热测试中")]),e("h2",Yt,[e("a",Qt,[e("span",null,[l("2020.12.25 "),n(a,null,{default:s(()=>[e("a",Kt,[l("1.1.5"),n(t)])]),_:1})])])]),zt,e("ul",null,[Jt,Zt,$t,es,e("li",null,[l("kirin 带来了一大波 脚本更新."),e("a",ls,[l("脚本在此"),n(t)])]),ns]),ts,e("p",null,[l("因为某些不可描述的原因,Xray 的文档网站已在发布日前偷跑上线。 网址为:"),e("a",ss,[l("没错你正在看的就是"),n(t)])]),as,e("p",null,[l("文档网站需要不断完善和增加内容,以及完善设计。 因此更欢迎大家一起为文档建设添砖加瓦。 "),e("a",os,[l("文档的仓库"),n(t)])]),rs,is,e("p",null,[l("Xray-core Shadowsocks UDP FullCone 测试版, "),e("a",hs,[l("TG 群"),n(t)]),l("火热测试中")]),_s,cs,e("h2",ds,[e("a",us,[e("span",null,[l("2020.12.18 "),n(a,null,{default:s(()=>[e("a",ps,[l("1.1.4"),n(t)])]),_:1})])])]),fs,bs,e("p",null,[l("鉴于日益增长群人数和游戏需求, 开启了"),e("a",gs,[l("TG 游戏群"),n(t)])]),Xs,e("p",null,[e("a",vs,[l("安装脚本 dev 分支"),n(t)]),l("开启, 持续更新功能中.")]),e("h2",Ss,[e("a",Ts,[e("span",null,[l("2020.12.11 "),n(a,null,{default:s(()=>[e("a",ks,[l("1.1.3"),n(t)])]),_:1})])])]),ms,e("h2",xs,[e("a",ys,[e("span",null,[l("2020.12.06 "),n(a,null,{default:s(()=>[e("a",Ls,[l("1.1.2"),n(t)])]),_:1})])])]),Ps,e("h2",Hs,[e("a",Ds,[e("span",null,[l("2020.11.25 "),n(a,null,{default:s(()=>[e("a",Us,[l("1.0.0"),n(t)])]),_:1})])])]),Rs,Cs,Es,Ns,Is])}const js=_(u,[["render",Vs],["__file","news.html.vue"]]);export{js as default}; diff --git a/assets/nginx_or_haproxy_tls_tunnel.html-CMszb--u.js b/assets/nginx_or_haproxy_tls_tunnel.html-CYGy05Cb.js similarity index 99% rename from assets/nginx_or_haproxy_tls_tunnel.html-CMszb--u.js rename to assets/nginx_or_haproxy_tls_tunnel.html-CYGy05Cb.js index 600e31f55f..38426aad92 100644 --- a/assets/nginx_or_haproxy_tls_tunnel.html-CMszb--u.js +++ b/assets/nginx_or_haproxy_tls_tunnel.html-CYGy05Cb.js @@ -1,4 +1,4 @@ -import{_ as l,r as s,o,c as p,a as e,b as r,d as n,w as c,e as a}from"./app-DBM4OJyw.js";const d={},u=a('

                                      Nginx или Haproxy реализуют HTTPS-туннели, туннели HTTP/2 over HTTPS, туннели WebSocket over HTTP/2 over HTTPS, туннели gRPC over HTTP/2 over HTTPS, а также туннели gRPC over HTTP/2 over HTTPS с двусторонней аутентификацией по самозаверяющему сертификату.

                                      Создание HTTPS-туннеля с помощью Nginx на стороне клиента и сервера для скрытия отпечатков

                                      Сетевая структура:

                                      xray_client ---tcp--- nginx_client ---HTTPS--- nginx_sever ---tcp--- xray_server

                                      Компиляция nginx с поддержкой --with-stream

                                      Выполните компиляцию как на клиенте, так и на сервере.

                                      curl -O -L http://nginx.org/download/nginx-1.22.1.tar.gz

                                      tar -zxvf nginx-1.22.1.tar.gz

                                      cd nginx-1.22.1

                                      apt install gcc make // Для компиляции требуются gcc и make

                                      ./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_v2_module --with-stream --with-stream_ssl_module // На этом шаге могут потребоваться дополнительные библиотеки, установите их в соответствии с сообщениями об ошибках.

                                      make && make install

                                      После компиляции папка nginx будет находиться в /usr/local/nginx.

                                      Настройка nginx

                                      Отредактируйте конфигурационный файл nginx.conf.

                                      vim /usr/local/nginx/conf/nginx.conf

                                      Добавьте следующую конфигурацию на стороне сервера.

                                      ',17),v=a(`
                                      stream {
                                      +import{_ as l,r as s,o,c as p,a as e,b as r,d as n,w as c,e as a}from"./app-D7uBbsY3.js";const d={},u=a('

                                      Nginx или Haproxy реализуют HTTPS-туннели, туннели HTTP/2 over HTTPS, туннели WebSocket over HTTP/2 over HTTPS, туннели gRPC over HTTP/2 over HTTPS, а также туннели gRPC over HTTP/2 over HTTPS с двусторонней аутентификацией по самозаверяющему сертификату.

                                      Создание HTTPS-туннеля с помощью Nginx на стороне клиента и сервера для скрытия отпечатков

                                      Сетевая структура:

                                      xray_client ---tcp--- nginx_client ---HTTPS--- nginx_sever ---tcp--- xray_server

                                      Компиляция nginx с поддержкой --with-stream

                                      Выполните компиляцию как на клиенте, так и на сервере.

                                      curl -O -L http://nginx.org/download/nginx-1.22.1.tar.gz

                                      tar -zxvf nginx-1.22.1.tar.gz

                                      cd nginx-1.22.1

                                      apt install gcc make // Для компиляции требуются gcc и make

                                      ./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_v2_module --with-stream --with-stream_ssl_module // На этом шаге могут потребоваться дополнительные библиотеки, установите их в соответствии с сообщениями об ошибках.

                                      make && make install

                                      После компиляции папка nginx будет находиться в /usr/local/nginx.

                                      Настройка nginx

                                      Отредактируйте конфигурационный файл nginx.conf.

                                      vim /usr/local/nginx/conf/nginx.conf

                                      Добавьте следующую конфигурацию на стороне сервера.

                                      ',17),v=a(`
                                      stream {
                                           server {
                                               listen 443 ssl;
                                               listen [::]:443 ssl;
                                      diff --git a/assets/nginx_or_haproxy_tls_tunnel.html-DOANhXpE.js b/assets/nginx_or_haproxy_tls_tunnel.html-DR7z7Hc7.js
                                      similarity index 99%
                                      rename from assets/nginx_or_haproxy_tls_tunnel.html-DOANhXpE.js
                                      rename to assets/nginx_or_haproxy_tls_tunnel.html-DR7z7Hc7.js
                                      index 0ea3cac06a..25c43e162b 100644
                                      --- a/assets/nginx_or_haproxy_tls_tunnel.html-DOANhXpE.js
                                      +++ b/assets/nginx_or_haproxy_tls_tunnel.html-DR7z7Hc7.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as a,r as e,o as t,c as r,a as n,b as v,d as i,w as u,e as s}from"./app-DBM4OJyw.js";const c={},o=s('

                                      Nginx 或 Haproxy 实现的 HTTPS 隧道、HTTP/2 over HTTPS 隧道、WebSocket over HTTP/2 over HTTPS 隧道、gRPC over HTTP/2 over HTTPS 隧道以及自签证书双端认证的 gRPC over HTTP/2 over HTTPS 隧道

                                      客户端服务端 Nginx 构建 HTTPS 隧道隐藏指纹

                                      网路结构:

                                      xray_client ---tcp--- nginx_client ---HTTPS--- nginx_sever ---tcp--- xray_server

                                      编译 nginx --with-stream

                                      在客户端及服务端均编译

                                      curl -O -L http://nginx.org/download/nginx-1.22.1.tar.gz

                                      tar -zxvf nginx-1.22.1.tar.gz

                                      cd nginx-1.22.1

                                      apt install gcc make //编译依赖 gcc 以及 make

                                      ./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_v2_module --with-stream --with-stream_ssl_module //此步需要依赖一些库,根据报错安装相应 lib

                                      make && make install

                                      编译之后 nginx 文件夹位于 /usr/local/nginx

                                      配置 nginx

                                      编辑 nginx 配置文件 nginx.conf

                                      vim /usr/local/nginx/conf/nginx.conf

                                      服务端加入如下配置

                                      ',17),m=s(`
                                      stream {
                                      +import{_ as a,r as e,o as t,c as r,a as n,b as v,d as i,w as u,e as s}from"./app-D7uBbsY3.js";const c={},o=s('

                                      Nginx 或 Haproxy 实现的 HTTPS 隧道、HTTP/2 over HTTPS 隧道、WebSocket over HTTP/2 over HTTPS 隧道、gRPC over HTTP/2 over HTTPS 隧道以及自签证书双端认证的 gRPC over HTTP/2 over HTTPS 隧道

                                      客户端服务端 Nginx 构建 HTTPS 隧道隐藏指纹

                                      网路结构:

                                      xray_client ---tcp--- nginx_client ---HTTPS--- nginx_sever ---tcp--- xray_server

                                      编译 nginx --with-stream

                                      在客户端及服务端均编译

                                      curl -O -L http://nginx.org/download/nginx-1.22.1.tar.gz

                                      tar -zxvf nginx-1.22.1.tar.gz

                                      cd nginx-1.22.1

                                      apt install gcc make //编译依赖 gcc 以及 make

                                      ./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_v2_module --with-stream --with-stream_ssl_module //此步需要依赖一些库,根据报错安装相应 lib

                                      make && make install

                                      编译之后 nginx 文件夹位于 /usr/local/nginx

                                      配置 nginx

                                      编辑 nginx 配置文件 nginx.conf

                                      vim /usr/local/nginx/conf/nginx.conf

                                      服务端加入如下配置

                                      ',17),m=s(`
                                      stream {
                                           server {
                                               listen 443 ssl;
                                               listen [::]:443 ssl;
                                      diff --git a/assets/nginx_or_haproxy_tls_tunnel.html-DkUD4xx5.js b/assets/nginx_or_haproxy_tls_tunnel.html-ojUDrBVB.js
                                      similarity index 99%
                                      rename from assets/nginx_or_haproxy_tls_tunnel.html-DkUD4xx5.js
                                      rename to assets/nginx_or_haproxy_tls_tunnel.html-ojUDrBVB.js
                                      index 1d7bd47db5..8cf40459e9 100644
                                      --- a/assets/nginx_or_haproxy_tls_tunnel.html-DkUD4xx5.js
                                      +++ b/assets/nginx_or_haproxy_tls_tunnel.html-ojUDrBVB.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as a,r as e,o as t,c as r,a as n,b as v,d as i,w as u,e as s}from"./app-DBM4OJyw.js";const c={},o=s('

                                      Nginx 或 Haproxy 实现的 HTTPS 隧道、HTTP/2 over HTTPS 隧道、WebSocket over HTTP/2 over HTTPS 隧道、gRPC over HTTP/2 over HTTPS 隧道以及自签证书双端认证的 gRPC over HTTP/2 over HTTPS 隧道

                                      客户端服务端 Nginx 构建 HTTPS 隧道隐藏指纹

                                      网路结构:

                                      xray_client ---tcp--- nginx_client ---HTTPS--- nginx_sever ---tcp--- xray_server

                                      编译 nginx --with-stream

                                      在客户端及服务端均编译

                                      curl -O -L http://nginx.org/download/nginx-1.22.1.tar.gz

                                      tar -zxvf nginx-1.22.1.tar.gz

                                      cd nginx-1.22.1

                                      apt install gcc make //编译依赖 gcc 以及 make

                                      ./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_v2_module --with-stream --with-stream_ssl_module //此步需要依赖一些库,根据报错安装相应 lib

                                      make && make install

                                      编译之后 nginx 文件夹位于 /usr/local/nginx

                                      配置 nginx

                                      编辑 nginx 配置文件 nginx.conf

                                      vim /usr/local/nginx/conf/nginx.conf

                                      服务端加入如下配置

                                      ',17),m=s(`
                                      stream {
                                      +import{_ as a,r as e,o as t,c as r,a as n,b as v,d as i,w as u,e as s}from"./app-D7uBbsY3.js";const c={},o=s('

                                      Nginx 或 Haproxy 实现的 HTTPS 隧道、HTTP/2 over HTTPS 隧道、WebSocket over HTTP/2 over HTTPS 隧道、gRPC over HTTP/2 over HTTPS 隧道以及自签证书双端认证的 gRPC over HTTP/2 over HTTPS 隧道

                                      客户端服务端 Nginx 构建 HTTPS 隧道隐藏指纹

                                      网路结构:

                                      xray_client ---tcp--- nginx_client ---HTTPS--- nginx_sever ---tcp--- xray_server

                                      编译 nginx --with-stream

                                      在客户端及服务端均编译

                                      curl -O -L http://nginx.org/download/nginx-1.22.1.tar.gz

                                      tar -zxvf nginx-1.22.1.tar.gz

                                      cd nginx-1.22.1

                                      apt install gcc make //编译依赖 gcc 以及 make

                                      ./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_v2_module --with-stream --with-stream_ssl_module //此步需要依赖一些库,根据报错安装相应 lib

                                      make && make install

                                      编译之后 nginx 文件夹位于 /usr/local/nginx

                                      配置 nginx

                                      编辑 nginx 配置文件 nginx.conf

                                      vim /usr/local/nginx/conf/nginx.conf

                                      服务端加入如下配置

                                      ',17),m=s(`
                                      stream {
                                           server {
                                               listen 443 ssl;
                                               listen [::]:443 ssl;
                                      diff --git a/assets/observatory.html-BbQKQJhA.js b/assets/observatory.html-BL0BAmEr.js
                                      similarity index 99%
                                      rename from assets/observatory.html-BbQKQJhA.js
                                      rename to assets/observatory.html-BL0BAmEr.js
                                      index 5bbd596442..89445b04a9 100644
                                      --- a/assets/observatory.html-BbQKQJhA.js
                                      +++ b/assets/observatory.html-BL0BAmEr.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as e,r as n,o as t,c as s,a,e as c}from"./app-DBM4OJyw.js";const i={},r=c(`

                                      Connection Monitoring

                                      The connection monitoring component uses HTTPing to detect the connection status of outbound proxies. The monitoring results can be used by other components, such as load balancers. There are currently two options: observatory (background connection monitoring) and burstObservatory (concurrent connection monitoring). You can choose one of them as needed.

                                      ObservatoryObject

                                      {
                                      +import{_ as e,r as n,o as t,c as s,a,e as c}from"./app-D7uBbsY3.js";const i={},r=c(`

                                      Connection Monitoring

                                      The connection monitoring component uses HTTPing to detect the connection status of outbound proxies. The monitoring results can be used by other components, such as load balancers. There are currently two options: observatory (background connection monitoring) and burstObservatory (concurrent connection monitoring). You can choose one of them as needed.

                                      ObservatoryObject

                                      {
                                         "subjectSelector":[
                                           "outbound"
                                         ],
                                      diff --git a/assets/observatory.html-BMuTIcPE.js b/assets/observatory.html-CYfqKbFA.js
                                      similarity index 99%
                                      rename from assets/observatory.html-BMuTIcPE.js
                                      rename to assets/observatory.html-CYfqKbFA.js
                                      index d976557bd7..26f2f325c7 100644
                                      --- a/assets/observatory.html-BMuTIcPE.js
                                      +++ b/assets/observatory.html-CYfqKbFA.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as n,r as e,o as s,c as t,a,e as c}from"./app-DBM4OJyw.js";const p={},u=c(`

                                      连接观测

                                      连接观测组件使用 HTTPing 的方式探测出站代理的连接状态。观测结果可以被其他组件使用,如负载均衡器。目前有 observatory (后台连接观测)和 burstObservatory (并发连接观测)两种。按需选择其中之一就行。

                                      ObservatoryObject

                                      {
                                      +import{_ as n,r as e,o as s,c as t,a,e as c}from"./app-D7uBbsY3.js";const p={},u=c(`

                                      连接观测

                                      连接观测组件使用 HTTPing 的方式探测出站代理的连接状态。观测结果可以被其他组件使用,如负载均衡器。目前有 observatory (后台连接观测)和 burstObservatory (并发连接观测)两种。按需选择其中之一就行。

                                      ObservatoryObject

                                      {
                                         "subjectSelector":[
                                           "outbound"
                                         ],
                                      diff --git a/assets/observatory.html-Bqwm-FiF.js b/assets/observatory.html-i7tnhJjx.js
                                      similarity index 99%
                                      rename from assets/observatory.html-Bqwm-FiF.js
                                      rename to assets/observatory.html-i7tnhJjx.js
                                      index 9c3f774a26..126e6382b4 100644
                                      --- a/assets/observatory.html-Bqwm-FiF.js
                                      +++ b/assets/observatory.html-i7tnhJjx.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as e,r as n,o as s,c as t,a,e as c}from"./app-DBM4OJyw.js";const p={},u=c(`

                                      Мониторинг подключений

                                      Компонент мониторинга подключений использует HTTP-пинги для проверки состояния подключения исходящих прокси. Результаты мониторинга могут использоваться другими компонентами, например, балансировщиком нагрузки.
                                      В настоящее время доступны два режима: observatory (фоновый мониторинг подключений) и burstObservatory (мониторинг параллельных подключений).
                                      Выберите один из них в соответствии с вашими потребностями.

                                      ObservatoryObject

                                      {
                                      +import{_ as e,r as n,o as s,c as t,a,e as c}from"./app-D7uBbsY3.js";const p={},u=c(`

                                      Мониторинг подключений

                                      Компонент мониторинга подключений использует HTTP-пинги для проверки состояния подключения исходящих прокси. Результаты мониторинга могут использоваться другими компонентами, например, балансировщиком нагрузки.
                                      В настоящее время доступны два режима: observatory (фоновый мониторинг подключений) и burstObservatory (мониторинг параллельных подключений).
                                      Выберите один из них в соответствии с вашими потребностями.

                                      ObservatoryObject

                                      {
                                         "subjectSelector":[
                                           "outbound"
                                         ],
                                      diff --git a/assets/outbound.html-w2bkUi_e.js b/assets/outbound.html-BpCUakwX.js
                                      similarity index 99%
                                      rename from assets/outbound.html-w2bkUi_e.js
                                      rename to assets/outbound.html-BpCUakwX.js
                                      index 8835f8cad0..be93856744 100644
                                      --- a/assets/outbound.html-w2bkUi_e.js
                                      +++ b/assets/outbound.html-BpCUakwX.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as d,r as e,o as l,c as i,a as s,b as n,d as o,w as a,e as c}from"./app-DBM4OJyw.js";const r={},b=n("h1",{id:"出站代理-mux、xudp",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#出站代理-mux、xudp"},[n("span",null,"出站代理(Mux、XUDP)")])],-1),k=c(`

                                      OutboundObject

                                      OutboundObject 对应配置文件中 outbounds 项的一个子元素。

                                      提示

                                      列表中的第一个元素作为主 outbound。当路由匹配不存在或没有匹配成功时,流量由主 outbound 发出。

                                      {
                                      +import{_ as d,r as e,o as l,c as i,a as s,b as n,d as o,w as a,e as c}from"./app-D7uBbsY3.js";const r={},b=n("h1",{id:"出站代理-mux、xudp",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#出站代理-mux、xudp"},[n("span",null,"出站代理(Mux、XUDP)")])],-1),k=c(`

                                      OutboundObject

                                      OutboundObject 对应配置文件中 outbounds 项的一个子元素。

                                      提示

                                      列表中的第一个元素作为主 outbound。当路由匹配不存在或没有匹配成功时,流量由主 outbound 发出。

                                      {
                                         "outbounds": [
                                           {
                                             "sendThrough": "0.0.0.0",
                                      diff --git a/assets/outbound.html-B5z5DraB.js b/assets/outbound.html-DVewdwtU.js
                                      similarity index 99%
                                      rename from assets/outbound.html-B5z5DraB.js
                                      rename to assets/outbound.html-DVewdwtU.js
                                      index db5b10b00e..8e7eb78c61 100644
                                      --- a/assets/outbound.html-B5z5DraB.js
                                      +++ b/assets/outbound.html-DVewdwtU.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as r,r as t,o as l,c as d,a as s,b as n,d as o,w as a,e as c}from"./app-DBM4OJyw.js";const i={},b=n("h1",{id:"исходящие-подключения",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#исходящие-подключения"},[n("span",null,"Исходящие подключения")])],-1),k=c(`

                                      OutboundObject

                                      OutboundObject соответствует дочернему элементу поля outbounds в конфигурационном файле.

                                      Подсказка

                                      Первый элемент в списке используется как основной исходящий узел.
                                      Если совпадений с правилами маршрутизации нет или ни одно правило не сработало, трафик отправляется через основной исходящий узел.

                                      {
                                      +import{_ as r,r as t,o as l,c as d,a as s,b as n,d as o,w as a,e as c}from"./app-D7uBbsY3.js";const i={},b=n("h1",{id:"исходящие-подключения",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#исходящие-подключения"},[n("span",null,"Исходящие подключения")])],-1),k=c(`

                                      OutboundObject

                                      OutboundObject соответствует дочернему элементу поля outbounds в конфигурационном файле.

                                      Подсказка

                                      Первый элемент в списке используется как основной исходящий узел.
                                      Если совпадений с правилами маршрутизации нет или ни одно правило не сработало, трафик отправляется через основной исходящий узел.

                                      {
                                         "outbounds": [
                                           {
                                             "sendThrough": "0.0.0.0",
                                      diff --git a/assets/outbound.html-CpUBTknQ.js b/assets/outbound.html-lqQ_d0C5.js
                                      similarity index 99%
                                      rename from assets/outbound.html-CpUBTknQ.js
                                      rename to assets/outbound.html-lqQ_d0C5.js
                                      index f148dbf387..3ab8c97188 100644
                                      --- a/assets/outbound.html-CpUBTknQ.js
                                      +++ b/assets/outbound.html-lqQ_d0C5.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as u,r as s,o as r,c as p,a as n,b as e,d as o,w as a,e as c}from"./app-DBM4OJyw.js";const d={},h=e("h1",{id:"outbound-proxies",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#outbound-proxies"},[e("span",null,"Outbound Proxies")])],-1),b=c(`

                                      OutboundObject

                                      The OutboundObject corresponds to a sub-element of the outbounds item in the configuration file.

                                      Tip

                                      The first element in the list serves as the main outbound. When there is no match or no successful match for the routing, the traffic is sent out by the main outbound.

                                      {
                                      +import{_ as u,r as s,o as r,c as p,a as n,b as e,d as o,w as a,e as c}from"./app-D7uBbsY3.js";const d={},h=e("h1",{id:"outbound-proxies",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#outbound-proxies"},[e("span",null,"Outbound Proxies")])],-1),b=c(`

                                      OutboundObject

                                      The OutboundObject corresponds to a sub-element of the outbounds item in the configuration file.

                                      Tip

                                      The first element in the list serves as the main outbound. When there is no match or no successful match for the routing, the traffic is sent out by the main outbound.

                                      {
                                         "outbounds": [
                                           {
                                             "sendThrough": "0.0.0.0",
                                      diff --git a/assets/pieDiagram-WEX7LNAG-BT3MbsDU.js b/assets/pieDiagram-WEX7LNAG-DSCpd-br.js
                                      similarity index 92%
                                      rename from assets/pieDiagram-WEX7LNAG-BT3MbsDU.js
                                      rename to assets/pieDiagram-WEX7LNAG-DSCpd-br.js
                                      index 5aae18d869..85ded2f0ae 100644
                                      --- a/assets/pieDiagram-WEX7LNAG-BT3MbsDU.js
                                      +++ b/assets/pieDiagram-WEX7LNAG-DSCpd-br.js
                                      @@ -1,4 +1,4 @@
                                      -import{p as U}from"./chunk-JJENOPKO-CSqkWYi8.js";import{Y as y,P as z,aE as j,F as q,q as K,r as Y,s as Z,g as H,c as J,b as Q,_ as p,l as F,t as X,d as tt,G as et,K as at,a6 as rt,k as nt}from"./mermaid.core-DapiNGBY.js";import{p as it}from"./gitGraph-F2EDSAW4-IXsRUTzt.js";import{d as O}from"./arc-CO2v8jBL.js";import{o as st}from"./ordinal-Cboi1Yqb.js";import"./app-DBM4OJyw.js";import"./baseUniq-ZJgB7efo.js";import"./basePickBy-BXIHjUx3.js";import"./clone-B3i2nD77.js";import"./init-Gi6I4Gst.js";function ot(t,a){return at?1:a>=t?0:NaN}function lt(t){return t}function ct(){var t=lt,a=ot,m=null,o=y(0),g=y(z),x=y(0);function i(e){var r,l=(e=j(e)).length,c,A,h=0,u=new Array(l),n=new Array(l),v=+o.apply(this,arguments),w=Math.min(z,Math.max(-z,g.apply(this,arguments)-v)),f,T=Math.min(Math.abs(w)/l,x.apply(this,arguments)),$=T*(w<0?-1:1),d;for(r=0;r0&&(h+=d);for(a!=null?u.sort(function(S,C){return a(n[S],n[C])}):m!=null&&u.sort(function(S,C){return m(e[S],e[C])}),r=0,A=h?(w-l*$)/h:0;r0?d*A:0)+$,n[c]={data:e[c],index:r,value:d,startAngle:v,endAngle:f,padAngle:T};return n}return i.value=function(e){return arguments.length?(t=typeof e=="function"?e:y(+e),i):t},i.sortValues=function(e){return arguments.length?(a=e,m=null,i):a},i.sort=function(e){return arguments.length?(m=e,a=null,i):m},i.startAngle=function(e){return arguments.length?(o=typeof e=="function"?e:y(+e),i):o},i.endAngle=function(e){return arguments.length?(g=typeof e=="function"?e:y(+e),i):g},i.padAngle=function(e){return arguments.length?(x=typeof e=="function"?e:y(+e),i):x},i}var R=q.pie,G={sections:new Map,showData:!1,config:R},b=G.sections,P=G.showData,ut=structuredClone(R),pt=p(()=>structuredClone(ut),"getConfig"),gt=p(()=>{b=new Map,P=G.showData,X()},"clear"),dt=p(({label:t,value:a})=>{b.has(t)||(b.set(t,a),F.debug(`added new section: ${t}, with value: ${a}`))},"addSection"),ft=p(()=>b,"getSections"),mt=p(t=>{P=t},"setShowData"),ht=p(()=>P,"getShowData"),I={getConfig:pt,clear:gt,setDiagramTitle:K,getDiagramTitle:Y,setAccTitle:Z,getAccTitle:H,setAccDescription:J,getAccDescription:Q,addSection:dt,getSections:ft,setShowData:mt,getShowData:ht},vt=p((t,a)=>{U(t,a),a.setShowData(t.showData),t.sections.map(a.addSection)},"populateDb"),St={parse:p(async t=>{const a=await it("pie",t);F.debug(a),vt(a,I)},"parse")},yt=p(t=>`
                                      +import{p as U}from"./chunk-JJENOPKO-7opA8rsx.js";import{Y as y,P as z,aE as j,F as q,q as K,r as Y,s as Z,g as H,c as J,b as Q,_ as p,l as F,t as X,d as tt,G as et,K as at,a6 as rt,k as nt}from"./mermaid.core-D8igZDel.js";import{p as it}from"./gitGraph-F2EDSAW4-Df57CYyu.js";import{d as O}from"./arc-9Itq1iXl.js";import{o as st}from"./ordinal-Cboi1Yqb.js";import"./app-D7uBbsY3.js";import"./baseUniq-D0lZO5yp.js";import"./basePickBy-DpnmgMOi.js";import"./clone-DWnk59eF.js";import"./init-Gi6I4Gst.js";function ot(t,a){return at?1:a>=t?0:NaN}function lt(t){return t}function ct(){var t=lt,a=ot,m=null,o=y(0),g=y(z),x=y(0);function i(e){var r,l=(e=j(e)).length,c,A,h=0,u=new Array(l),n=new Array(l),v=+o.apply(this,arguments),w=Math.min(z,Math.max(-z,g.apply(this,arguments)-v)),f,T=Math.min(Math.abs(w)/l,x.apply(this,arguments)),$=T*(w<0?-1:1),d;for(r=0;r0&&(h+=d);for(a!=null?u.sort(function(S,C){return a(n[S],n[C])}):m!=null&&u.sort(function(S,C){return m(e[S],e[C])}),r=0,A=h?(w-l*$)/h:0;r0?d*A:0)+$,n[c]={data:e[c],index:r,value:d,startAngle:v,endAngle:f,padAngle:T};return n}return i.value=function(e){return arguments.length?(t=typeof e=="function"?e:y(+e),i):t},i.sortValues=function(e){return arguments.length?(a=e,m=null,i):a},i.sort=function(e){return arguments.length?(m=e,a=null,i):m},i.startAngle=function(e){return arguments.length?(o=typeof e=="function"?e:y(+e),i):o},i.endAngle=function(e){return arguments.length?(g=typeof e=="function"?e:y(+e),i):g},i.padAngle=function(e){return arguments.length?(x=typeof e=="function"?e:y(+e),i):x},i}var R=q.pie,G={sections:new Map,showData:!1,config:R},b=G.sections,P=G.showData,ut=structuredClone(R),pt=p(()=>structuredClone(ut),"getConfig"),gt=p(()=>{b=new Map,P=G.showData,X()},"clear"),dt=p(({label:t,value:a})=>{b.has(t)||(b.set(t,a),F.debug(`added new section: ${t}, with value: ${a}`))},"addSection"),ft=p(()=>b,"getSections"),mt=p(t=>{P=t},"setShowData"),ht=p(()=>P,"getShowData"),I={getConfig:pt,clear:gt,setDiagramTitle:K,getDiagramTitle:Y,setAccTitle:Z,getAccTitle:H,setAccDescription:J,getAccDescription:Q,addSection:dt,getSections:ft,setShowData:mt,getShowData:ht},vt=p((t,a)=>{U(t,a),a.setShowData(t.showData),t.sections.map(a.addSection)},"populateDb"),St={parse:p(async t=>{const a=await it("pie",t);F.debug(a),vt(a,I)},"parse")},yt=p(t=>`
                                         .pieCircle{
                                           stroke: ${t.pieStrokeColor};
                                           stroke-width : ${t.pieStrokeWidth};
                                      diff --git a/assets/policy.html-BALvOnk-.js b/assets/policy.html-CA7G3Iy7.js
                                      similarity index 98%
                                      rename from assets/policy.html-BALvOnk-.js
                                      rename to assets/policy.html-CA7G3Iy7.js
                                      index 75e57738b3..edac966d85 100644
                                      --- a/assets/policy.html-BALvOnk-.js
                                      +++ b/assets/policy.html-CA7G3Iy7.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as s,r as e,o as a,c as o,a as t,e as p}from"./app-DBM4OJyw.js";const c={},l=p(`

                                      Local Policy

                                      Local policy can be used to set different policy settings for different user levels, such as connection timeout settings. Each connection handled by Xray corresponds to a user, and different policies are applied based on the user's level.

                                      PolicyObject

                                      PolicyObject corresponds to the policy field in the configuration file.

                                      {
                                      +import{_ as s,r as e,o as a,c as o,a as t,e as p}from"./app-D7uBbsY3.js";const c={},l=p(`

                                      Local Policy

                                      Local policy can be used to set different policy settings for different user levels, such as connection timeout settings. Each connection handled by Xray corresponds to a user, and different policies are applied based on the user's level.

                                      PolicyObject

                                      PolicyObject corresponds to the policy field in the configuration file.

                                      {
                                         "policy": {
                                           "levels": {
                                             "0": {
                                      diff --git a/assets/policy.html-B5iTeN8-.js b/assets/policy.html-CzEm0fhQ.js
                                      similarity index 99%
                                      rename from assets/policy.html-B5iTeN8-.js
                                      rename to assets/policy.html-CzEm0fhQ.js
                                      index 0dcbc51a39..7b1857292d 100644
                                      --- a/assets/policy.html-B5iTeN8-.js
                                      +++ b/assets/policy.html-CzEm0fhQ.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as s,r as a,o as e,c as o,a as p,e as t}from"./app-DBM4OJyw.js";const c={},l=t(`

                                      Локальные политики

                                      Локальные политики позволяют настраивать различные уровни пользователей и соответствующие им политики, например, настройки тайм-аута подключения.
                                      Каждое соединение, обрабатываемое Xray, соответствует определенному пользователю, и к нему применяются политики в соответствии с уровнем пользователя (level).

                                      PolicyObject

                                      PolicyObject соответствует полю policy в конфигурационном файле.

                                      {
                                      +import{_ as s,r as a,o as e,c as o,a as p,e as t}from"./app-D7uBbsY3.js";const c={},l=t(`

                                      Локальные политики

                                      Локальные политики позволяют настраивать различные уровни пользователей и соответствующие им политики, например, настройки тайм-аута подключения.
                                      Каждое соединение, обрабатываемое Xray, соответствует определенному пользователю, и к нему применяются политики в соответствии с уровнем пользователя (level).

                                      PolicyObject

                                      PolicyObject соответствует полю policy в конфигурационном файле.

                                      {
                                         "policy": {
                                           "levels": {
                                             "0": {
                                      diff --git a/assets/policy.html-Dor87Wko.js b/assets/policy.html-DmXgvAr6.js
                                      similarity index 98%
                                      rename from assets/policy.html-Dor87Wko.js
                                      rename to assets/policy.html-DmXgvAr6.js
                                      index bbfb60e862..5071e6d8a5 100644
                                      --- a/assets/policy.html-Dor87Wko.js
                                      +++ b/assets/policy.html-DmXgvAr6.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as s,r as a,o as e,c as o,a as t,e as p}from"./app-DBM4OJyw.js";const c={},l=p(`

                                      本地策略

                                      本地策略,可以设置不同的用户等级和对应的策略设置,比如连接超时设置。Xray 处理的每一个连接都对应一个用户,按照用户的等级(level)应用不同的策略。

                                      PolicyObject

                                      PolicyObject 对应配置文件的 policy 项。

                                      {
                                      +import{_ as s,r as a,o as e,c as o,a as t,e as p}from"./app-D7uBbsY3.js";const c={},l=p(`

                                      本地策略

                                      本地策略,可以设置不同的用户等级和对应的策略设置,比如连接超时设置。Xray 处理的每一个连接都对应一个用户,按照用户的等级(level)应用不同的策略。

                                      PolicyObject

                                      PolicyObject 对应配置文件的 policy 项。

                                      {
                                         "policy": {
                                           "levels": {
                                             "0": {
                                      diff --git a/assets/quadrantDiagram-SRYJ5FP7-DraEpiPS.js b/assets/quadrantDiagram-SRYJ5FP7-DIAY3wdM.js
                                      similarity index 99%
                                      rename from assets/quadrantDiagram-SRYJ5FP7-DraEpiPS.js
                                      rename to assets/quadrantDiagram-SRYJ5FP7-DIAY3wdM.js
                                      index 0e10f28024..fa1d6abd20 100644
                                      --- a/assets/quadrantDiagram-SRYJ5FP7-DraEpiPS.js
                                      +++ b/assets/quadrantDiagram-SRYJ5FP7-DIAY3wdM.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as o,a1 as _e,F as D,l as At,d as wt,i as Ae,r as ie,s as ke,g as Fe,q as Pe,b as ve,c as Ce,t as Le,j as zt,k as Ee}from"./mermaid.core-DapiNGBY.js";import{l as ee}from"./linear-D4Bza9R9.js";import"./app-DBM4OJyw.js";import"./init-Gi6I4Gst.js";var Vt=function(){var t=o(function(j,r,l,g){for(l=l||{},g=j.length;g--;l[j[g]]=r);return l},"o"),n=[1,3],u=[1,4],c=[1,5],h=[1,6],p=[1,7],y=[1,4,5,10,12,13,14,18,25,35,37,39,41,42,48,50,51,52,53,54,55,56,57,60,61,63,64,65,66,67],S=[1,4,5,10,12,13,14,18,25,28,35,37,39,41,42,48,50,51,52,53,54,55,56,57,60,61,63,64,65,66,67],a=[55,56,57],A=[2,36],d=[1,37],T=[1,36],q=[1,38],m=[1,35],b=[1,43],x=[1,41],O=[1,14],Y=[1,23],G=[1,18],yt=[1,19],Tt=[1,20],ht=[1,21],Ft=[1,22],ct=[1,24],dt=[1,25],ut=[1,26],xt=[1,27],i=[1,28],Bt=[1,29],W=[1,32],U=[1,33],k=[1,34],F=[1,39],P=[1,40],v=[1,42],C=[1,44],H=[1,62],X=[1,61],L=[4,5,8,10,12,13,14,18,44,47,49,55,56,57,63,64,65,66,67],Rt=[1,65],Nt=[1,66],Wt=[1,67],Ut=[1,68],Qt=[1,69],Ot=[1,70],Ht=[1,71],Xt=[1,72],Mt=[1,73],Yt=[1,74],jt=[1,75],Gt=[1,76],I=[4,5,6,7,8,9,10,11,12,13,14,15,18],J=[1,90],$=[1,91],tt=[1,92],et=[1,99],it=[1,93],at=[1,96],nt=[1,94],st=[1,95],rt=[1,97],ot=[1,98],Pt=[1,102],Kt=[10,55,56,57],R=[4,5,6,8,10,11,13,17,18,19,20,55,56,57],vt={trace:o(function(){},"trace"),yy:{},symbols_:{error:2,idStringToken:3,ALPHA:4,NUM:5,NODE_STRING:6,DOWN:7,MINUS:8,DEFAULT:9,COMMA:10,COLON:11,AMP:12,BRKT:13,MULT:14,UNICODE_TEXT:15,styleComponent:16,UNIT:17,SPACE:18,STYLE:19,PCT:20,idString:21,style:22,stylesOpt:23,classDefStatement:24,CLASSDEF:25,start:26,eol:27,QUADRANT:28,document:29,line:30,statement:31,axisDetails:32,quadrantDetails:33,points:34,title:35,title_value:36,acc_title:37,acc_title_value:38,acc_descr:39,acc_descr_value:40,acc_descr_multiline_value:41,section:42,text:43,point_start:44,point_x:45,point_y:46,class_name:47,"X-AXIS":48,"AXIS-TEXT-DELIMITER":49,"Y-AXIS":50,QUADRANT_1:51,QUADRANT_2:52,QUADRANT_3:53,QUADRANT_4:54,NEWLINE:55,SEMI:56,EOF:57,alphaNumToken:58,textNoTagsToken:59,STR:60,MD_STR:61,alphaNum:62,PUNCTUATION:63,PLUS:64,EQUALS:65,DOT:66,UNDERSCORE:67,$accept:0,$end:1},terminals_:{2:"error",4:"ALPHA",5:"NUM",6:"NODE_STRING",7:"DOWN",8:"MINUS",9:"DEFAULT",10:"COMMA",11:"COLON",12:"AMP",13:"BRKT",14:"MULT",15:"UNICODE_TEXT",17:"UNIT",18:"SPACE",19:"STYLE",20:"PCT",25:"CLASSDEF",28:"QUADRANT",35:"title",36:"title_value",37:"acc_title",38:"acc_title_value",39:"acc_descr",40:"acc_descr_value",41:"acc_descr_multiline_value",42:"section",44:"point_start",45:"point_x",46:"point_y",47:"class_name",48:"X-AXIS",49:"AXIS-TEXT-DELIMITER",50:"Y-AXIS",51:"QUADRANT_1",52:"QUADRANT_2",53:"QUADRANT_3",54:"QUADRANT_4",55:"NEWLINE",56:"SEMI",57:"EOF",60:"STR",61:"MD_STR",63:"PUNCTUATION",64:"PLUS",65:"EQUALS",66:"DOT",67:"UNDERSCORE"},productions_:[0,[3,1],[3,1],[3,1],[3,1],[3,1],[3,1],[3,1],[3,1],[3,1],[3,1],[3,1],[3,1],[16,1],[16,1],[16,1],[16,1],[16,1],[16,1],[16,1],[16,1],[16,1],[16,1],[21,1],[21,2],[22,1],[22,2],[23,1],[23,3],[24,5],[26,2],[26,2],[26,2],[29,0],[29,2],[30,2],[31,0],[31,1],[31,2],[31,1],[31,1],[31,1],[31,2],[31,2],[31,2],[31,1],[31,1],[34,4],[34,5],[34,5],[34,6],[32,4],[32,3],[32,2],[32,4],[32,3],[32,2],[33,2],[33,2],[33,2],[33,2],[27,1],[27,1],[27,1],[43,1],[43,2],[43,1],[43,1],[62,1],[62,2],[58,1],[58,1],[58,1],[58,1],[58,1],[58,1],[58,1],[58,1],[58,1],[58,1],[58,1],[59,1],[59,1],[59,1]],performAction:o(function(r,l,g,f,_,e,ft){var s=e.length-1;switch(_){case 23:this.$=e[s];break;case 24:this.$=e[s-1]+""+e[s];break;case 26:this.$=e[s-1]+e[s];break;case 27:this.$=[e[s].trim()];break;case 28:e[s-2].push(e[s].trim()),this.$=e[s-2];break;case 29:this.$=e[s-4],f.addClass(e[s-2],e[s]);break;case 37:this.$=[];break;case 42:this.$=e[s].trim(),f.setDiagramTitle(this.$);break;case 43:this.$=e[s].trim(),f.setAccTitle(this.$);break;case 44:case 45:this.$=e[s].trim(),f.setAccDescription(this.$);break;case 46:f.addSection(e[s].substr(8)),this.$=e[s].substr(8);break;case 47:f.addPoint(e[s-3],"",e[s-1],e[s],[]);break;case 48:f.addPoint(e[s-4],e[s-3],e[s-1],e[s],[]);break;case 49:f.addPoint(e[s-4],"",e[s-2],e[s-1],e[s]);break;case 50:f.addPoint(e[s-5],e[s-4],e[s-2],e[s-1],e[s]);break;case 51:f.setXAxisLeftText(e[s-2]),f.setXAxisRightText(e[s]);break;case 52:e[s-1].text+=" ⟶ ",f.setXAxisLeftText(e[s-1]);break;case 53:f.setXAxisLeftText(e[s]);break;case 54:f.setYAxisBottomText(e[s-2]),f.setYAxisTopText(e[s]);break;case 55:e[s-1].text+=" ⟶ ",f.setYAxisBottomText(e[s-1]);break;case 56:f.setYAxisBottomText(e[s]);break;case 57:f.setQuadrant1Text(e[s]);break;case 58:f.setQuadrant2Text(e[s]);break;case 59:f.setQuadrant3Text(e[s]);break;case 60:f.setQuadrant4Text(e[s]);break;case 64:this.$={text:e[s],type:"text"};break;case 65:this.$={text:e[s-1].text+""+e[s],type:e[s-1].type};break;case 66:this.$={text:e[s],type:"text"};break;case 67:this.$={text:e[s],type:"markdown"};break;case 68:this.$=e[s];break;case 69:this.$=e[s-1]+""+e[s];break}},"anonymous"),table:[{18:n,26:1,27:2,28:u,55:c,56:h,57:p},{1:[3]},{18:n,26:8,27:2,28:u,55:c,56:h,57:p},{18:n,26:9,27:2,28:u,55:c,56:h,57:p},t(y,[2,33],{29:10}),t(S,[2,61]),t(S,[2,62]),t(S,[2,63]),{1:[2,30]},{1:[2,31]},t(a,A,{30:11,31:12,24:13,32:15,33:16,34:17,43:30,58:31,1:[2,32],4:d,5:T,10:q,12:m,13:b,14:x,18:O,25:Y,35:G,37:yt,39:Tt,41:ht,42:Ft,48:ct,50:dt,51:ut,52:xt,53:i,54:Bt,60:W,61:U,63:k,64:F,65:P,66:v,67:C}),t(y,[2,34]),{27:45,55:c,56:h,57:p},t(a,[2,37]),t(a,A,{24:13,32:15,33:16,34:17,43:30,58:31,31:46,4:d,5:T,10:q,12:m,13:b,14:x,18:O,25:Y,35:G,37:yt,39:Tt,41:ht,42:Ft,48:ct,50:dt,51:ut,52:xt,53:i,54:Bt,60:W,61:U,63:k,64:F,65:P,66:v,67:C}),t(a,[2,39]),t(a,[2,40]),t(a,[2,41]),{36:[1,47]},{38:[1,48]},{40:[1,49]},t(a,[2,45]),t(a,[2,46]),{18:[1,50]},{4:d,5:T,10:q,12:m,13:b,14:x,43:51,58:31,60:W,61:U,63:k,64:F,65:P,66:v,67:C},{4:d,5:T,10:q,12:m,13:b,14:x,43:52,58:31,60:W,61:U,63:k,64:F,65:P,66:v,67:C},{4:d,5:T,10:q,12:m,13:b,14:x,43:53,58:31,60:W,61:U,63:k,64:F,65:P,66:v,67:C},{4:d,5:T,10:q,12:m,13:b,14:x,43:54,58:31,60:W,61:U,63:k,64:F,65:P,66:v,67:C},{4:d,5:T,10:q,12:m,13:b,14:x,43:55,58:31,60:W,61:U,63:k,64:F,65:P,66:v,67:C},{4:d,5:T,10:q,12:m,13:b,14:x,43:56,58:31,60:W,61:U,63:k,64:F,65:P,66:v,67:C},{4:d,5:T,8:H,10:q,12:m,13:b,14:x,18:X,44:[1,57],47:[1,58],58:60,59:59,63:k,64:F,65:P,66:v,67:C},t(L,[2,64]),t(L,[2,66]),t(L,[2,67]),t(L,[2,70]),t(L,[2,71]),t(L,[2,72]),t(L,[2,73]),t(L,[2,74]),t(L,[2,75]),t(L,[2,76]),t(L,[2,77]),t(L,[2,78]),t(L,[2,79]),t(L,[2,80]),t(y,[2,35]),t(a,[2,38]),t(a,[2,42]),t(a,[2,43]),t(a,[2,44]),{3:64,4:Rt,5:Nt,6:Wt,7:Ut,8:Qt,9:Ot,10:Ht,11:Xt,12:Mt,13:Yt,14:jt,15:Gt,21:63},t(a,[2,53],{59:59,58:60,4:d,5:T,8:H,10:q,12:m,13:b,14:x,18:X,49:[1,77],63:k,64:F,65:P,66:v,67:C}),t(a,[2,56],{59:59,58:60,4:d,5:T,8:H,10:q,12:m,13:b,14:x,18:X,49:[1,78],63:k,64:F,65:P,66:v,67:C}),t(a,[2,57],{59:59,58:60,4:d,5:T,8:H,10:q,12:m,13:b,14:x,18:X,63:k,64:F,65:P,66:v,67:C}),t(a,[2,58],{59:59,58:60,4:d,5:T,8:H,10:q,12:m,13:b,14:x,18:X,63:k,64:F,65:P,66:v,67:C}),t(a,[2,59],{59:59,58:60,4:d,5:T,8:H,10:q,12:m,13:b,14:x,18:X,63:k,64:F,65:P,66:v,67:C}),t(a,[2,60],{59:59,58:60,4:d,5:T,8:H,10:q,12:m,13:b,14:x,18:X,63:k,64:F,65:P,66:v,67:C}),{45:[1,79]},{44:[1,80]},t(L,[2,65]),t(L,[2,81]),t(L,[2,82]),t(L,[2,83]),{3:82,4:Rt,5:Nt,6:Wt,7:Ut,8:Qt,9:Ot,10:Ht,11:Xt,12:Mt,13:Yt,14:jt,15:Gt,18:[1,81]},t(I,[2,23]),t(I,[2,1]),t(I,[2,2]),t(I,[2,3]),t(I,[2,4]),t(I,[2,5]),t(I,[2,6]),t(I,[2,7]),t(I,[2,8]),t(I,[2,9]),t(I,[2,10]),t(I,[2,11]),t(I,[2,12]),t(a,[2,52],{58:31,43:83,4:d,5:T,10:q,12:m,13:b,14:x,60:W,61:U,63:k,64:F,65:P,66:v,67:C}),t(a,[2,55],{58:31,43:84,4:d,5:T,10:q,12:m,13:b,14:x,60:W,61:U,63:k,64:F,65:P,66:v,67:C}),{46:[1,85]},{45:[1,86]},{4:J,5:$,6:tt,8:et,11:it,13:at,16:89,17:nt,18:st,19:rt,20:ot,22:88,23:87},t(I,[2,24]),t(a,[2,51],{59:59,58:60,4:d,5:T,8:H,10:q,12:m,13:b,14:x,18:X,63:k,64:F,65:P,66:v,67:C}),t(a,[2,54],{59:59,58:60,4:d,5:T,8:H,10:q,12:m,13:b,14:x,18:X,63:k,64:F,65:P,66:v,67:C}),t(a,[2,47],{22:88,16:89,23:100,4:J,5:$,6:tt,8:et,11:it,13:at,17:nt,18:st,19:rt,20:ot}),{46:[1,101]},t(a,[2,29],{10:Pt}),t(Kt,[2,27],{16:103,4:J,5:$,6:tt,8:et,11:it,13:at,17:nt,18:st,19:rt,20:ot}),t(R,[2,25]),t(R,[2,13]),t(R,[2,14]),t(R,[2,15]),t(R,[2,16]),t(R,[2,17]),t(R,[2,18]),t(R,[2,19]),t(R,[2,20]),t(R,[2,21]),t(R,[2,22]),t(a,[2,49],{10:Pt}),t(a,[2,48],{22:88,16:89,23:104,4:J,5:$,6:tt,8:et,11:it,13:at,17:nt,18:st,19:rt,20:ot}),{4:J,5:$,6:tt,8:et,11:it,13:at,16:89,17:nt,18:st,19:rt,20:ot,22:105},t(R,[2,26]),t(a,[2,50],{10:Pt}),t(Kt,[2,28],{16:103,4:J,5:$,6:tt,8:et,11:it,13:at,17:nt,18:st,19:rt,20:ot})],defaultActions:{8:[2,30],9:[2,31]},parseError:o(function(r,l){if(l.recoverable)this.trace(r);else{var g=new Error(r);throw g.hash=l,g}},"parseError"),parse:o(function(r){var l=this,g=[0],f=[],_=[null],e=[],ft=this.table,s="",mt=0,Zt=0,qe=2,Jt=1,me=e.slice.call(arguments,1),E=Object.create(this.lexer),K={yy:{}};for(var Ct in this.yy)Object.prototype.hasOwnProperty.call(this.yy,Ct)&&(K.yy[Ct]=this.yy[Ct]);E.setInput(r,K.yy),K.yy.lexer=E,K.yy.parser=this,typeof E.yylloc>"u"&&(E.yylloc={});var Lt=E.yylloc;e.push(Lt);var be=E.options&&E.options.ranges;typeof K.yy.parseError=="function"?this.parseError=K.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function Se(B){g.length=g.length-2*B,_.length=_.length-B,e.length=e.length-B}o(Se,"popStack");function $t(){var B;return B=f.pop()||E.lex()||Jt,typeof B!="number"&&(B instanceof Array&&(f=B,B=f.pop()),B=l.symbols_[B]||B),B}o($t,"lex");for(var w,Z,N,Et,lt={},bt,M,te,St;;){if(Z=g[g.length-1],this.defaultActions[Z]?N=this.defaultActions[Z]:((w===null||typeof w>"u")&&(w=$t()),N=ft[Z]&&ft[Z][w]),typeof N>"u"||!N.length||!N[0]){var Dt="";St=[];for(bt in ft[Z])this.terminals_[bt]&&bt>qe&&St.push("'"+this.terminals_[bt]+"'");E.showPosition?Dt="Parse error on line "+(mt+1)+`:
                                      +import{_ as o,a1 as _e,F as D,l as At,d as wt,i as Ae,r as ie,s as ke,g as Fe,q as Pe,b as ve,c as Ce,t as Le,j as zt,k as Ee}from"./mermaid.core-D8igZDel.js";import{l as ee}from"./linear-hDJDjKgB.js";import"./app-D7uBbsY3.js";import"./init-Gi6I4Gst.js";var Vt=function(){var t=o(function(j,r,l,g){for(l=l||{},g=j.length;g--;l[j[g]]=r);return l},"o"),n=[1,3],u=[1,4],c=[1,5],h=[1,6],p=[1,7],y=[1,4,5,10,12,13,14,18,25,35,37,39,41,42,48,50,51,52,53,54,55,56,57,60,61,63,64,65,66,67],S=[1,4,5,10,12,13,14,18,25,28,35,37,39,41,42,48,50,51,52,53,54,55,56,57,60,61,63,64,65,66,67],a=[55,56,57],A=[2,36],d=[1,37],T=[1,36],q=[1,38],m=[1,35],b=[1,43],x=[1,41],O=[1,14],Y=[1,23],G=[1,18],yt=[1,19],Tt=[1,20],ht=[1,21],Ft=[1,22],ct=[1,24],dt=[1,25],ut=[1,26],xt=[1,27],i=[1,28],Bt=[1,29],W=[1,32],U=[1,33],k=[1,34],F=[1,39],P=[1,40],v=[1,42],C=[1,44],H=[1,62],X=[1,61],L=[4,5,8,10,12,13,14,18,44,47,49,55,56,57,63,64,65,66,67],Rt=[1,65],Nt=[1,66],Wt=[1,67],Ut=[1,68],Qt=[1,69],Ot=[1,70],Ht=[1,71],Xt=[1,72],Mt=[1,73],Yt=[1,74],jt=[1,75],Gt=[1,76],I=[4,5,6,7,8,9,10,11,12,13,14,15,18],J=[1,90],$=[1,91],tt=[1,92],et=[1,99],it=[1,93],at=[1,96],nt=[1,94],st=[1,95],rt=[1,97],ot=[1,98],Pt=[1,102],Kt=[10,55,56,57],R=[4,5,6,8,10,11,13,17,18,19,20,55,56,57],vt={trace:o(function(){},"trace"),yy:{},symbols_:{error:2,idStringToken:3,ALPHA:4,NUM:5,NODE_STRING:6,DOWN:7,MINUS:8,DEFAULT:9,COMMA:10,COLON:11,AMP:12,BRKT:13,MULT:14,UNICODE_TEXT:15,styleComponent:16,UNIT:17,SPACE:18,STYLE:19,PCT:20,idString:21,style:22,stylesOpt:23,classDefStatement:24,CLASSDEF:25,start:26,eol:27,QUADRANT:28,document:29,line:30,statement:31,axisDetails:32,quadrantDetails:33,points:34,title:35,title_value:36,acc_title:37,acc_title_value:38,acc_descr:39,acc_descr_value:40,acc_descr_multiline_value:41,section:42,text:43,point_start:44,point_x:45,point_y:46,class_name:47,"X-AXIS":48,"AXIS-TEXT-DELIMITER":49,"Y-AXIS":50,QUADRANT_1:51,QUADRANT_2:52,QUADRANT_3:53,QUADRANT_4:54,NEWLINE:55,SEMI:56,EOF:57,alphaNumToken:58,textNoTagsToken:59,STR:60,MD_STR:61,alphaNum:62,PUNCTUATION:63,PLUS:64,EQUALS:65,DOT:66,UNDERSCORE:67,$accept:0,$end:1},terminals_:{2:"error",4:"ALPHA",5:"NUM",6:"NODE_STRING",7:"DOWN",8:"MINUS",9:"DEFAULT",10:"COMMA",11:"COLON",12:"AMP",13:"BRKT",14:"MULT",15:"UNICODE_TEXT",17:"UNIT",18:"SPACE",19:"STYLE",20:"PCT",25:"CLASSDEF",28:"QUADRANT",35:"title",36:"title_value",37:"acc_title",38:"acc_title_value",39:"acc_descr",40:"acc_descr_value",41:"acc_descr_multiline_value",42:"section",44:"point_start",45:"point_x",46:"point_y",47:"class_name",48:"X-AXIS",49:"AXIS-TEXT-DELIMITER",50:"Y-AXIS",51:"QUADRANT_1",52:"QUADRANT_2",53:"QUADRANT_3",54:"QUADRANT_4",55:"NEWLINE",56:"SEMI",57:"EOF",60:"STR",61:"MD_STR",63:"PUNCTUATION",64:"PLUS",65:"EQUALS",66:"DOT",67:"UNDERSCORE"},productions_:[0,[3,1],[3,1],[3,1],[3,1],[3,1],[3,1],[3,1],[3,1],[3,1],[3,1],[3,1],[3,1],[16,1],[16,1],[16,1],[16,1],[16,1],[16,1],[16,1],[16,1],[16,1],[16,1],[21,1],[21,2],[22,1],[22,2],[23,1],[23,3],[24,5],[26,2],[26,2],[26,2],[29,0],[29,2],[30,2],[31,0],[31,1],[31,2],[31,1],[31,1],[31,1],[31,2],[31,2],[31,2],[31,1],[31,1],[34,4],[34,5],[34,5],[34,6],[32,4],[32,3],[32,2],[32,4],[32,3],[32,2],[33,2],[33,2],[33,2],[33,2],[27,1],[27,1],[27,1],[43,1],[43,2],[43,1],[43,1],[62,1],[62,2],[58,1],[58,1],[58,1],[58,1],[58,1],[58,1],[58,1],[58,1],[58,1],[58,1],[58,1],[59,1],[59,1],[59,1]],performAction:o(function(r,l,g,f,_,e,ft){var s=e.length-1;switch(_){case 23:this.$=e[s];break;case 24:this.$=e[s-1]+""+e[s];break;case 26:this.$=e[s-1]+e[s];break;case 27:this.$=[e[s].trim()];break;case 28:e[s-2].push(e[s].trim()),this.$=e[s-2];break;case 29:this.$=e[s-4],f.addClass(e[s-2],e[s]);break;case 37:this.$=[];break;case 42:this.$=e[s].trim(),f.setDiagramTitle(this.$);break;case 43:this.$=e[s].trim(),f.setAccTitle(this.$);break;case 44:case 45:this.$=e[s].trim(),f.setAccDescription(this.$);break;case 46:f.addSection(e[s].substr(8)),this.$=e[s].substr(8);break;case 47:f.addPoint(e[s-3],"",e[s-1],e[s],[]);break;case 48:f.addPoint(e[s-4],e[s-3],e[s-1],e[s],[]);break;case 49:f.addPoint(e[s-4],"",e[s-2],e[s-1],e[s]);break;case 50:f.addPoint(e[s-5],e[s-4],e[s-2],e[s-1],e[s]);break;case 51:f.setXAxisLeftText(e[s-2]),f.setXAxisRightText(e[s]);break;case 52:e[s-1].text+=" ⟶ ",f.setXAxisLeftText(e[s-1]);break;case 53:f.setXAxisLeftText(e[s]);break;case 54:f.setYAxisBottomText(e[s-2]),f.setYAxisTopText(e[s]);break;case 55:e[s-1].text+=" ⟶ ",f.setYAxisBottomText(e[s-1]);break;case 56:f.setYAxisBottomText(e[s]);break;case 57:f.setQuadrant1Text(e[s]);break;case 58:f.setQuadrant2Text(e[s]);break;case 59:f.setQuadrant3Text(e[s]);break;case 60:f.setQuadrant4Text(e[s]);break;case 64:this.$={text:e[s],type:"text"};break;case 65:this.$={text:e[s-1].text+""+e[s],type:e[s-1].type};break;case 66:this.$={text:e[s],type:"text"};break;case 67:this.$={text:e[s],type:"markdown"};break;case 68:this.$=e[s];break;case 69:this.$=e[s-1]+""+e[s];break}},"anonymous"),table:[{18:n,26:1,27:2,28:u,55:c,56:h,57:p},{1:[3]},{18:n,26:8,27:2,28:u,55:c,56:h,57:p},{18:n,26:9,27:2,28:u,55:c,56:h,57:p},t(y,[2,33],{29:10}),t(S,[2,61]),t(S,[2,62]),t(S,[2,63]),{1:[2,30]},{1:[2,31]},t(a,A,{30:11,31:12,24:13,32:15,33:16,34:17,43:30,58:31,1:[2,32],4:d,5:T,10:q,12:m,13:b,14:x,18:O,25:Y,35:G,37:yt,39:Tt,41:ht,42:Ft,48:ct,50:dt,51:ut,52:xt,53:i,54:Bt,60:W,61:U,63:k,64:F,65:P,66:v,67:C}),t(y,[2,34]),{27:45,55:c,56:h,57:p},t(a,[2,37]),t(a,A,{24:13,32:15,33:16,34:17,43:30,58:31,31:46,4:d,5:T,10:q,12:m,13:b,14:x,18:O,25:Y,35:G,37:yt,39:Tt,41:ht,42:Ft,48:ct,50:dt,51:ut,52:xt,53:i,54:Bt,60:W,61:U,63:k,64:F,65:P,66:v,67:C}),t(a,[2,39]),t(a,[2,40]),t(a,[2,41]),{36:[1,47]},{38:[1,48]},{40:[1,49]},t(a,[2,45]),t(a,[2,46]),{18:[1,50]},{4:d,5:T,10:q,12:m,13:b,14:x,43:51,58:31,60:W,61:U,63:k,64:F,65:P,66:v,67:C},{4:d,5:T,10:q,12:m,13:b,14:x,43:52,58:31,60:W,61:U,63:k,64:F,65:P,66:v,67:C},{4:d,5:T,10:q,12:m,13:b,14:x,43:53,58:31,60:W,61:U,63:k,64:F,65:P,66:v,67:C},{4:d,5:T,10:q,12:m,13:b,14:x,43:54,58:31,60:W,61:U,63:k,64:F,65:P,66:v,67:C},{4:d,5:T,10:q,12:m,13:b,14:x,43:55,58:31,60:W,61:U,63:k,64:F,65:P,66:v,67:C},{4:d,5:T,10:q,12:m,13:b,14:x,43:56,58:31,60:W,61:U,63:k,64:F,65:P,66:v,67:C},{4:d,5:T,8:H,10:q,12:m,13:b,14:x,18:X,44:[1,57],47:[1,58],58:60,59:59,63:k,64:F,65:P,66:v,67:C},t(L,[2,64]),t(L,[2,66]),t(L,[2,67]),t(L,[2,70]),t(L,[2,71]),t(L,[2,72]),t(L,[2,73]),t(L,[2,74]),t(L,[2,75]),t(L,[2,76]),t(L,[2,77]),t(L,[2,78]),t(L,[2,79]),t(L,[2,80]),t(y,[2,35]),t(a,[2,38]),t(a,[2,42]),t(a,[2,43]),t(a,[2,44]),{3:64,4:Rt,5:Nt,6:Wt,7:Ut,8:Qt,9:Ot,10:Ht,11:Xt,12:Mt,13:Yt,14:jt,15:Gt,21:63},t(a,[2,53],{59:59,58:60,4:d,5:T,8:H,10:q,12:m,13:b,14:x,18:X,49:[1,77],63:k,64:F,65:P,66:v,67:C}),t(a,[2,56],{59:59,58:60,4:d,5:T,8:H,10:q,12:m,13:b,14:x,18:X,49:[1,78],63:k,64:F,65:P,66:v,67:C}),t(a,[2,57],{59:59,58:60,4:d,5:T,8:H,10:q,12:m,13:b,14:x,18:X,63:k,64:F,65:P,66:v,67:C}),t(a,[2,58],{59:59,58:60,4:d,5:T,8:H,10:q,12:m,13:b,14:x,18:X,63:k,64:F,65:P,66:v,67:C}),t(a,[2,59],{59:59,58:60,4:d,5:T,8:H,10:q,12:m,13:b,14:x,18:X,63:k,64:F,65:P,66:v,67:C}),t(a,[2,60],{59:59,58:60,4:d,5:T,8:H,10:q,12:m,13:b,14:x,18:X,63:k,64:F,65:P,66:v,67:C}),{45:[1,79]},{44:[1,80]},t(L,[2,65]),t(L,[2,81]),t(L,[2,82]),t(L,[2,83]),{3:82,4:Rt,5:Nt,6:Wt,7:Ut,8:Qt,9:Ot,10:Ht,11:Xt,12:Mt,13:Yt,14:jt,15:Gt,18:[1,81]},t(I,[2,23]),t(I,[2,1]),t(I,[2,2]),t(I,[2,3]),t(I,[2,4]),t(I,[2,5]),t(I,[2,6]),t(I,[2,7]),t(I,[2,8]),t(I,[2,9]),t(I,[2,10]),t(I,[2,11]),t(I,[2,12]),t(a,[2,52],{58:31,43:83,4:d,5:T,10:q,12:m,13:b,14:x,60:W,61:U,63:k,64:F,65:P,66:v,67:C}),t(a,[2,55],{58:31,43:84,4:d,5:T,10:q,12:m,13:b,14:x,60:W,61:U,63:k,64:F,65:P,66:v,67:C}),{46:[1,85]},{45:[1,86]},{4:J,5:$,6:tt,8:et,11:it,13:at,16:89,17:nt,18:st,19:rt,20:ot,22:88,23:87},t(I,[2,24]),t(a,[2,51],{59:59,58:60,4:d,5:T,8:H,10:q,12:m,13:b,14:x,18:X,63:k,64:F,65:P,66:v,67:C}),t(a,[2,54],{59:59,58:60,4:d,5:T,8:H,10:q,12:m,13:b,14:x,18:X,63:k,64:F,65:P,66:v,67:C}),t(a,[2,47],{22:88,16:89,23:100,4:J,5:$,6:tt,8:et,11:it,13:at,17:nt,18:st,19:rt,20:ot}),{46:[1,101]},t(a,[2,29],{10:Pt}),t(Kt,[2,27],{16:103,4:J,5:$,6:tt,8:et,11:it,13:at,17:nt,18:st,19:rt,20:ot}),t(R,[2,25]),t(R,[2,13]),t(R,[2,14]),t(R,[2,15]),t(R,[2,16]),t(R,[2,17]),t(R,[2,18]),t(R,[2,19]),t(R,[2,20]),t(R,[2,21]),t(R,[2,22]),t(a,[2,49],{10:Pt}),t(a,[2,48],{22:88,16:89,23:104,4:J,5:$,6:tt,8:et,11:it,13:at,17:nt,18:st,19:rt,20:ot}),{4:J,5:$,6:tt,8:et,11:it,13:at,16:89,17:nt,18:st,19:rt,20:ot,22:105},t(R,[2,26]),t(a,[2,50],{10:Pt}),t(Kt,[2,28],{16:103,4:J,5:$,6:tt,8:et,11:it,13:at,17:nt,18:st,19:rt,20:ot})],defaultActions:{8:[2,30],9:[2,31]},parseError:o(function(r,l){if(l.recoverable)this.trace(r);else{var g=new Error(r);throw g.hash=l,g}},"parseError"),parse:o(function(r){var l=this,g=[0],f=[],_=[null],e=[],ft=this.table,s="",mt=0,Zt=0,qe=2,Jt=1,me=e.slice.call(arguments,1),E=Object.create(this.lexer),K={yy:{}};for(var Ct in this.yy)Object.prototype.hasOwnProperty.call(this.yy,Ct)&&(K.yy[Ct]=this.yy[Ct]);E.setInput(r,K.yy),K.yy.lexer=E,K.yy.parser=this,typeof E.yylloc>"u"&&(E.yylloc={});var Lt=E.yylloc;e.push(Lt);var be=E.options&&E.options.ranges;typeof K.yy.parseError=="function"?this.parseError=K.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function Se(B){g.length=g.length-2*B,_.length=_.length-B,e.length=e.length-B}o(Se,"popStack");function $t(){var B;return B=f.pop()||E.lex()||Jt,typeof B!="number"&&(B instanceof Array&&(f=B,B=f.pop()),B=l.symbols_[B]||B),B}o($t,"lex");for(var w,Z,N,Et,lt={},bt,M,te,St;;){if(Z=g[g.length-1],this.defaultActions[Z]?N=this.defaultActions[Z]:((w===null||typeof w>"u")&&(w=$t()),N=ft[Z]&&ft[Z][w]),typeof N>"u"||!N.length||!N[0]){var Dt="";St=[];for(bt in ft[Z])this.terminals_[bt]&&bt>qe&&St.push("'"+this.terminals_[bt]+"'");E.showPosition?Dt="Parse error on line "+(mt+1)+`:
                                       `+E.showPosition()+`
                                       Expecting `+St.join(", ")+", got '"+(this.terminals_[w]||w)+"'":Dt="Parse error on line "+(mt+1)+": Unexpected "+(w==Jt?"end of input":"'"+(this.terminals_[w]||w)+"'"),this.parseError(Dt,{text:E.match,token:this.terminals_[w]||w,line:E.yylineno,loc:Lt,expected:St})}if(N[0]instanceof Array&&N.length>1)throw new Error("Parse Error: multiple actions possible at state: "+Z+", token: "+w);switch(N[0]){case 1:g.push(w),_.push(E.yytext),e.push(E.yylloc),g.push(N[1]),w=null,Zt=E.yyleng,s=E.yytext,mt=E.yylineno,Lt=E.yylloc;break;case 2:if(M=this.productions_[N[1]][1],lt.$=_[_.length-M],lt._$={first_line:e[e.length-(M||1)].first_line,last_line:e[e.length-1].last_line,first_column:e[e.length-(M||1)].first_column,last_column:e[e.length-1].last_column},be&&(lt._$.range=[e[e.length-(M||1)].range[0],e[e.length-1].range[1]]),Et=this.performAction.apply(lt,[s,Zt,mt,K.yy,N[1],_,e].concat(me)),typeof Et<"u")return Et;M&&(g=g.slice(0,-1*M*2),_=_.slice(0,-1*M),e=e.slice(0,-1*M)),g.push(this.productions_[N[1]][0]),_.push(lt.$),e.push(lt._$),te=ft[g[g.length-2]][g[g.length-1]],g.push(te);break;case 3:return!0}}return!0},"parse")},Te=function(){var j={EOF:1,parseError:o(function(l,g){if(this.yy.parser)this.yy.parser.parseError(l,g);else throw new Error(l)},"parseError"),setInput:o(function(r,l){return this.yy=l||this.yy||{},this._input=r,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},"setInput"),input:o(function(){var r=this._input[0];this.yytext+=r,this.yyleng++,this.offset++,this.match+=r,this.matched+=r;var l=r.match(/(?:\r\n?|\n).*/g);return l?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),r},"input"),unput:o(function(r){var l=r.length,g=r.split(/(?:\r\n?|\n)/g);this._input=r+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-l),this.offset-=l;var f=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),g.length-1&&(this.yylineno-=g.length-1);var _=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:g?(g.length===f.length?this.yylloc.first_column:0)+f[f.length-g.length].length-g[0].length:this.yylloc.first_column-l},this.options.ranges&&(this.yylloc.range=[_[0],_[0]+this.yyleng-l]),this.yyleng=this.yytext.length,this},"unput"),more:o(function(){return this._more=!0,this},"more"),reject:o(function(){if(this.options.backtrack_lexer)this._backtrack=!0;else return this.parseError("Lexical error on line "+(this.yylineno+1)+`. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).
                                       `+this.showPosition(),{text:"",token:null,line:this.yylineno});return this},"reject"),less:o(function(r){this.unput(this.match.slice(r))},"less"),pastInput:o(function(){var r=this.matched.substr(0,this.matched.length-this.match.length);return(r.length>20?"...":"")+r.substr(-20).replace(/\n/g,"")},"pastInput"),upcomingInput:o(function(){var r=this.match;return r.length<20&&(r+=this._input.substr(0,20-r.length)),(r.substr(0,20)+(r.length>20?"...":"")).replace(/\n/g,"")},"upcomingInput"),showPosition:o(function(){var r=this.pastInput(),l=new Array(r.length+1).join("-");return r+this.upcomingInput()+`
                                      diff --git a/assets/redirect.html-CZZO3MVR.js b/assets/redirect.html-B5Y1mNVs.js
                                      similarity index 99%
                                      rename from assets/redirect.html-CZZO3MVR.js
                                      rename to assets/redirect.html-B5Y1mNVs.js
                                      index 3e35713ba5..808c68a57f 100644
                                      --- a/assets/redirect.html-CZZO3MVR.js
                                      +++ b/assets/redirect.html-B5Y1mNVs.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as o,r as e,o as l,c as i,a,b as s,d as n,e as c}from"./app-DBM4OJyw.js";const u={},r=s("h1",{id:"基于-fwmark-或-sendthrough-的流量重定向",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#基于-fwmark-或-sendthrough-的流量重定向"},[s("span",null,"基于 fwmark 或 sendThrough 的流量重定向")])],-1),d=c(`

                                      通过 Xray 将特定的流量指向特定出口,实现全局路由“分流”

                                      前言

                                      之前在网络上看到许多代理或者 VPN 会接管全局路由,如果与 Xray 同时安装,会导致 Xray 失效。参考了网络上许多教程,及时分流,也是通过维护一张或者多张 CIDR 路由表来实现的。这种情况下并不优雅,如果我想可以任意替换,实现按需分流,那有没有更好的办法呢?有!

                                      通过 fwmark 或 Xray 的 sendThrough/sockopt.interface,再简单配合路由表功能即可实现:

                                      1. Xray 可设置指定的 Tag、域名等走指定接口。如果您的接口是双栈的,可以指定 IPV4 或者 IPV6
                                      2. 其余用户则走原 IPV4 或者 IPV6

                                      具体设置如下(以 Debian10 为例):

                                      1、安装代理或者 VPN 软件(例如 Wireguard、IPsec 等)

                                      根据不同系统和不同软件,请参考官方安装方法

                                      2、编辑 VPN 配置文件(以 WireGuard 为例)

                                      原始文件:

                                      [Interface]
                                      +import{_ as o,r as e,o as l,c as i,a,b as s,d as n,e as c}from"./app-D7uBbsY3.js";const u={},r=s("h1",{id:"基于-fwmark-或-sendthrough-的流量重定向",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#基于-fwmark-或-sendthrough-的流量重定向"},[s("span",null,"基于 fwmark 或 sendThrough 的流量重定向")])],-1),d=c(`

                                      通过 Xray 将特定的流量指向特定出口,实现全局路由“分流”

                                      前言

                                      之前在网络上看到许多代理或者 VPN 会接管全局路由,如果与 Xray 同时安装,会导致 Xray 失效。参考了网络上许多教程,及时分流,也是通过维护一张或者多张 CIDR 路由表来实现的。这种情况下并不优雅,如果我想可以任意替换,实现按需分流,那有没有更好的办法呢?有!

                                      通过 fwmark 或 Xray 的 sendThrough/sockopt.interface,再简单配合路由表功能即可实现:

                                      1. Xray 可设置指定的 Tag、域名等走指定接口。如果您的接口是双栈的,可以指定 IPV4 或者 IPV6
                                      2. 其余用户则走原 IPV4 或者 IPV6

                                      具体设置如下(以 Debian10 为例):

                                      1、安装代理或者 VPN 软件(例如 Wireguard、IPsec 等)

                                      根据不同系统和不同软件,请参考官方安装方法

                                      2、编辑 VPN 配置文件(以 WireGuard 为例)

                                      原始文件:

                                      [Interface]
                                       PrivateKey = <PriKey>
                                       Address = <IPv4>
                                       Address = <IPv6>
                                      diff --git a/assets/redirect.html-DToMsmqC.js b/assets/redirect.html-C82dlL2o.js
                                      similarity index 99%
                                      rename from assets/redirect.html-DToMsmqC.js
                                      rename to assets/redirect.html-C82dlL2o.js
                                      index 47d806b76d..545526ed34 100644
                                      --- a/assets/redirect.html-DToMsmqC.js
                                      +++ b/assets/redirect.html-C82dlL2o.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as o,r as e,o as l,c as i,a,b as s,d as n,e as c}from"./app-DBM4OJyw.js";const u={},r=s("h1",{id:"перенаправление-трафика-на-основе-fwmark-или-sendthrough",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#перенаправление-трафика-на-основе-fwmark-или-sendthrough"},[s("span",null,"Перенаправление трафика на основе fwmark или sendThrough")])],-1),d=c(`

                                      Направление определенного трафика через определенный выходной узел с помощью Xray для реализации "разделения" глобальной маршрутизации

                                      Введение

                                      Я видел много прокси-серверов или VPN, которые перехватывают весь трафик, что приводит к неработоспособности Xray, если он установлен одновременно с ними. Многие руководства, которые я находил, предлагали решать эту проблему путем разделения трафика на основе таблиц маршрутизации CIDR. Это не очень элегантно, и если я хочу иметь возможность гибко переключаться между маршрутами и реализовывать разделение трафика по требованию, то есть ли лучший способ? Да, есть!

                                      С помощью fwmark или sendThrough/sockopt.interface в Xray и простой настройки таблицы маршрутизации можно добиться следующего:

                                      1. Xray может направлять трафик с определенным тегом, доменным именем и т.д. через определенный интерфейс. Если ваш интерфейс поддерживает dual-stack, вы можете указать IPv4 или IPv6.
                                      2. Остальной трафик будет идти через исходный интерфейс IPv4 или IPv6.

                                      Вот как это настроить (на примере Debian 10):

                                      1. Установите прокси-сервер или VPN-клиент (например, Wireguard, IPsec и т.д.)

                                      Обратитесь к официальной документации для получения инструкций по установке для вашей системы и программного обеспечения.

                                      2. Отредактируйте конфигурационный файл VPN (на примере WireGuard)

                                      Исходный файл:

                                      [Interface]
                                      +import{_ as o,r as e,o as l,c as i,a,b as s,d as n,e as c}from"./app-D7uBbsY3.js";const u={},r=s("h1",{id:"перенаправление-трафика-на-основе-fwmark-или-sendthrough",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#перенаправление-трафика-на-основе-fwmark-или-sendthrough"},[s("span",null,"Перенаправление трафика на основе fwmark или sendThrough")])],-1),d=c(`

                                      Направление определенного трафика через определенный выходной узел с помощью Xray для реализации "разделения" глобальной маршрутизации

                                      Введение

                                      Я видел много прокси-серверов или VPN, которые перехватывают весь трафик, что приводит к неработоспособности Xray, если он установлен одновременно с ними. Многие руководства, которые я находил, предлагали решать эту проблему путем разделения трафика на основе таблиц маршрутизации CIDR. Это не очень элегантно, и если я хочу иметь возможность гибко переключаться между маршрутами и реализовывать разделение трафика по требованию, то есть ли лучший способ? Да, есть!

                                      С помощью fwmark или sendThrough/sockopt.interface в Xray и простой настройки таблицы маршрутизации можно добиться следующего:

                                      1. Xray может направлять трафик с определенным тегом, доменным именем и т.д. через определенный интерфейс. Если ваш интерфейс поддерживает dual-stack, вы можете указать IPv4 или IPv6.
                                      2. Остальной трафик будет идти через исходный интерфейс IPv4 или IPv6.

                                      Вот как это настроить (на примере Debian 10):

                                      1. Установите прокси-сервер или VPN-клиент (например, Wireguard, IPsec и т.д.)

                                      Обратитесь к официальной документации для получения инструкций по установке для вашей системы и программного обеспечения.

                                      2. Отредактируйте конфигурационный файл VPN (на примере WireGuard)

                                      Исходный файл:

                                      [Interface]
                                       PrivateKey = <PriKey>
                                       Address = <IPv4>
                                       Address = <IPv6>
                                      diff --git a/assets/redirect.html-C39Qzzo5.js b/assets/redirect.html-VwFhzSui.js
                                      similarity index 99%
                                      rename from assets/redirect.html-C39Qzzo5.js
                                      rename to assets/redirect.html-VwFhzSui.js
                                      index 4b6bd2fe1d..20e88d85cd 100644
                                      --- a/assets/redirect.html-C39Qzzo5.js
                                      +++ b/assets/redirect.html-VwFhzSui.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as i,r as l,o as r,c as u,a,w as e,b as n,e as o,d as s}from"./app-DBM4OJyw.js";const k={},d=n("h1",{id:"基于-fwmark-或-sendthrough-的流量重定向",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#基于-fwmark-或-sendthrough-的流量重定向"},[n("span",null,"基于 fwmark 或 sendThrough 的流量重定向")])],-1),v=o('

                                      通过 Xray 将特定的流量指向特定出口,实现全局路由“分流”

                                      前言

                                      之前在网络上看到许多代理或者 VPN 会接管全局路由,如果与 Xray 同时安装,会导致 Xray 失效。参考了网络上许多教程,及时分流,也是通过维护一张或者多张 CIDR 路由表来实现的。这种情况下并不优雅,如果我想可以任意替换,实现按需分流,那有没有更好的办法呢?有!

                                      通过 fwmark 或 Xray 的 sendThrough,再简单配合路由表功能即可实现:

                                      1. Xray 可设置指定的 Tag、域名等走指定接口。如果您的接口是双栈的,可以指定 IPV4 或者 IPV6
                                      2. 其余用户则走原 IPV4 或者 IPV6

                                      具体设置如下(以 Debian10 为例):

                                      1、安装代理或者 VPN 软件(例如 Wireguard、IPsec 等)

                                      根据不同系统和不同软件,请参考官方安装方法

                                      2、编辑 VPN 配置文件(以 WireGuard 为例)

                                      原始文件:

                                      ',10),m=n("div",{class:"language-ini line-numbers-mode","data-ext":"ini","data-title":"ini"},[n("pre",{class:"language-ini"},[n("code",null,[n("span",{class:"token section"},[n("span",{class:"token punctuation"},"["),n("span",{class:"token section-name selector"},"Interface"),n("span",{class:"token punctuation"},"]")]),s(` +import{_ as i,r as l,o as r,c as u,a,w as e,b as n,e as o,d as s}from"./app-D7uBbsY3.js";const k={},d=n("h1",{id:"基于-fwmark-或-sendthrough-的流量重定向",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#基于-fwmark-或-sendthrough-的流量重定向"},[n("span",null,"基于 fwmark 或 sendThrough 的流量重定向")])],-1),v=o('

                                      通过 Xray 将特定的流量指向特定出口,实现全局路由“分流”

                                      前言

                                      之前在网络上看到许多代理或者 VPN 会接管全局路由,如果与 Xray 同时安装,会导致 Xray 失效。参考了网络上许多教程,及时分流,也是通过维护一张或者多张 CIDR 路由表来实现的。这种情况下并不优雅,如果我想可以任意替换,实现按需分流,那有没有更好的办法呢?有!

                                      通过 fwmark 或 Xray 的 sendThrough,再简单配合路由表功能即可实现:

                                      1. Xray 可设置指定的 Tag、域名等走指定接口。如果您的接口是双栈的,可以指定 IPV4 或者 IPV6
                                      2. 其余用户则走原 IPV4 或者 IPV6

                                      具体设置如下(以 Debian10 为例):

                                      1、安装代理或者 VPN 软件(例如 Wireguard、IPsec 等)

                                      根据不同系统和不同软件,请参考官方安装方法

                                      2、编辑 VPN 配置文件(以 WireGuard 为例)

                                      原始文件:

                                      ',10),m=n("div",{class:"language-ini line-numbers-mode","data-ext":"ini","data-title":"ini"},[n("pre",{class:"language-ini"},[n("code",null,[n("span",{class:"token section"},[n("span",{class:"token punctuation"},"["),n("span",{class:"token section-name selector"},"Interface"),n("span",{class:"token punctuation"},"]")]),s(` `),n("span",{class:"token key attr-name"},"PrivateKey"),s(),n("span",{class:"token punctuation"},"="),s(),n("span",{class:"token value attr-value"},"xxxxxxxxxxxxxxxxxxxx"),s(` `),n("span",{class:"token key attr-name"},"Address"),s(),n("span",{class:"token punctuation"},"="),s(),n("span",{class:"token value attr-value"},[s('"'),n("span",{class:"token inner-value"},"your wg0 v4 address"),s('"')]),s(` `),n("span",{class:"token key attr-name"},"Address"),s(),n("span",{class:"token punctuation"},"="),s(),n("span",{class:"token value attr-value"},[s('"'),n("span",{class:"token inner-value"},"your wg0 v6 address"),s('"')]),s(` diff --git a/assets/requirementDiagram-V7TESSIR-ptPfSQ70.js b/assets/requirementDiagram-V7TESSIR-kqo49K2z.js similarity index 99% rename from assets/requirementDiagram-V7TESSIR-ptPfSQ70.js rename to assets/requirementDiagram-V7TESSIR-kqo49K2z.js index 897b68eb8d..a11019ce8d 100644 --- a/assets/requirementDiagram-V7TESSIR-ptPfSQ70.js +++ b/assets/requirementDiagram-V7TESSIR-kqo49K2z.js @@ -1,4 +1,4 @@ -import{_ as r,d as ve,s as Fe,g as De,c as Pe,b as Ye,l as xe,t as Ue,j as ce,k as Be,a2 as Qe,e as Te}from"./mermaid.core-DapiNGBY.js";import{G as He}from"./graph-Oq3lz9SV.js";import{l as We}from"./layout-7AWYeW5Q.js";import"./app-DBM4OJyw.js";import"./baseUniq-ZJgB7efo.js";import"./basePickBy-BXIHjUx3.js";var he=function(){var e=r(function($,i,a,l){for(a=a||{},l=$.length;l--;a[$[l]]=i);return a},"o"),t=[1,3],c=[1,4],d=[1,5],u=[1,6],p=[5,6,8,9,11,13,31,32,33,34,35,36,44,62,63],y=[1,18],h=[2,7],o=[1,22],g=[1,23],R=[1,24],I=[1,25],b=[1,26],w=[1,27],q=[1,20],v=[1,28],A=[1,29],F=[62,63],pe=[5,8,9,11,13,31,32,33,34,35,36,44,51,53,62,63],fe=[1,47],ye=[1,48],_e=[1,49],ge=[1,50],Ee=[1,51],Re=[1,52],me=[1,53],O=[53,54],D=[1,64],P=[1,60],Y=[1,61],U=[1,62],B=[1,63],Q=[1,65],j=[1,69],X=[1,70],J=[1,67],Z=[1,68],S=[5,8,9,11,13,31,32,33,34,35,36,44,62,63],ne={trace:r(function(){},"trace"),yy:{},symbols_:{error:2,start:3,directive:4,NEWLINE:5,RD:6,diagram:7,EOF:8,acc_title:9,acc_title_value:10,acc_descr:11,acc_descr_value:12,acc_descr_multiline_value:13,requirementDef:14,elementDef:15,relationshipDef:16,requirementType:17,requirementName:18,STRUCT_START:19,requirementBody:20,ID:21,COLONSEP:22,id:23,TEXT:24,text:25,RISK:26,riskLevel:27,VERIFYMTHD:28,verifyType:29,STRUCT_STOP:30,REQUIREMENT:31,FUNCTIONAL_REQUIREMENT:32,INTERFACE_REQUIREMENT:33,PERFORMANCE_REQUIREMENT:34,PHYSICAL_REQUIREMENT:35,DESIGN_CONSTRAINT:36,LOW_RISK:37,MED_RISK:38,HIGH_RISK:39,VERIFY_ANALYSIS:40,VERIFY_DEMONSTRATION:41,VERIFY_INSPECTION:42,VERIFY_TEST:43,ELEMENT:44,elementName:45,elementBody:46,TYPE:47,type:48,DOCREF:49,ref:50,END_ARROW_L:51,relationship:52,LINE:53,END_ARROW_R:54,CONTAINS:55,COPIES:56,DERIVES:57,SATISFIES:58,VERIFIES:59,REFINES:60,TRACES:61,unqString:62,qString:63,$accept:0,$end:1},terminals_:{2:"error",5:"NEWLINE",6:"RD",8:"EOF",9:"acc_title",10:"acc_title_value",11:"acc_descr",12:"acc_descr_value",13:"acc_descr_multiline_value",19:"STRUCT_START",21:"ID",22:"COLONSEP",24:"TEXT",26:"RISK",28:"VERIFYMTHD",30:"STRUCT_STOP",31:"REQUIREMENT",32:"FUNCTIONAL_REQUIREMENT",33:"INTERFACE_REQUIREMENT",34:"PERFORMANCE_REQUIREMENT",35:"PHYSICAL_REQUIREMENT",36:"DESIGN_CONSTRAINT",37:"LOW_RISK",38:"MED_RISK",39:"HIGH_RISK",40:"VERIFY_ANALYSIS",41:"VERIFY_DEMONSTRATION",42:"VERIFY_INSPECTION",43:"VERIFY_TEST",44:"ELEMENT",47:"TYPE",49:"DOCREF",51:"END_ARROW_L",53:"LINE",54:"END_ARROW_R",55:"CONTAINS",56:"COPIES",57:"DERIVES",58:"SATISFIES",59:"VERIFIES",60:"REFINES",61:"TRACES",62:"unqString",63:"qString"},productions_:[0,[3,3],[3,2],[3,4],[4,2],[4,2],[4,1],[7,0],[7,2],[7,2],[7,2],[7,2],[7,2],[14,5],[20,5],[20,5],[20,5],[20,5],[20,2],[20,1],[17,1],[17,1],[17,1],[17,1],[17,1],[17,1],[27,1],[27,1],[27,1],[29,1],[29,1],[29,1],[29,1],[15,5],[46,5],[46,5],[46,2],[46,1],[16,5],[16,5],[52,1],[52,1],[52,1],[52,1],[52,1],[52,1],[52,1],[18,1],[18,1],[23,1],[23,1],[25,1],[25,1],[45,1],[45,1],[48,1],[48,1],[50,1],[50,1]],performAction:r(function(i,a,l,n,f,s,K){var E=s.length-1;switch(f){case 4:this.$=s[E].trim(),n.setAccTitle(this.$);break;case 5:case 6:this.$=s[E].trim(),n.setAccDescription(this.$);break;case 7:this.$=[];break;case 13:n.addRequirement(s[E-3],s[E-4]);break;case 14:n.setNewReqId(s[E-2]);break;case 15:n.setNewReqText(s[E-2]);break;case 16:n.setNewReqRisk(s[E-2]);break;case 17:n.setNewReqVerifyMethod(s[E-2]);break;case 20:this.$=n.RequirementType.REQUIREMENT;break;case 21:this.$=n.RequirementType.FUNCTIONAL_REQUIREMENT;break;case 22:this.$=n.RequirementType.INTERFACE_REQUIREMENT;break;case 23:this.$=n.RequirementType.PERFORMANCE_REQUIREMENT;break;case 24:this.$=n.RequirementType.PHYSICAL_REQUIREMENT;break;case 25:this.$=n.RequirementType.DESIGN_CONSTRAINT;break;case 26:this.$=n.RiskLevel.LOW_RISK;break;case 27:this.$=n.RiskLevel.MED_RISK;break;case 28:this.$=n.RiskLevel.HIGH_RISK;break;case 29:this.$=n.VerifyType.VERIFY_ANALYSIS;break;case 30:this.$=n.VerifyType.VERIFY_DEMONSTRATION;break;case 31:this.$=n.VerifyType.VERIFY_INSPECTION;break;case 32:this.$=n.VerifyType.VERIFY_TEST;break;case 33:n.addElement(s[E-3]);break;case 34:n.setNewElementType(s[E-2]);break;case 35:n.setNewElementDocRef(s[E-2]);break;case 38:n.addRelationship(s[E-2],s[E],s[E-4]);break;case 39:n.addRelationship(s[E-2],s[E-4],s[E]);break;case 40:this.$=n.Relationships.CONTAINS;break;case 41:this.$=n.Relationships.COPIES;break;case 42:this.$=n.Relationships.DERIVES;break;case 43:this.$=n.Relationships.SATISFIES;break;case 44:this.$=n.Relationships.VERIFIES;break;case 45:this.$=n.Relationships.REFINES;break;case 46:this.$=n.Relationships.TRACES;break}},"anonymous"),table:[{3:1,4:2,6:t,9:c,11:d,13:u},{1:[3]},{3:8,4:2,5:[1,7],6:t,9:c,11:d,13:u},{5:[1,9]},{10:[1,10]},{12:[1,11]},e(p,[2,6]),{3:12,4:2,6:t,9:c,11:d,13:u},{1:[2,2]},{4:17,5:y,7:13,8:h,9:c,11:d,13:u,14:14,15:15,16:16,17:19,23:21,31:o,32:g,33:R,34:I,35:b,36:w,44:q,62:v,63:A},e(p,[2,4]),e(p,[2,5]),{1:[2,1]},{8:[1,30]},{4:17,5:y,7:31,8:h,9:c,11:d,13:u,14:14,15:15,16:16,17:19,23:21,31:o,32:g,33:R,34:I,35:b,36:w,44:q,62:v,63:A},{4:17,5:y,7:32,8:h,9:c,11:d,13:u,14:14,15:15,16:16,17:19,23:21,31:o,32:g,33:R,34:I,35:b,36:w,44:q,62:v,63:A},{4:17,5:y,7:33,8:h,9:c,11:d,13:u,14:14,15:15,16:16,17:19,23:21,31:o,32:g,33:R,34:I,35:b,36:w,44:q,62:v,63:A},{4:17,5:y,7:34,8:h,9:c,11:d,13:u,14:14,15:15,16:16,17:19,23:21,31:o,32:g,33:R,34:I,35:b,36:w,44:q,62:v,63:A},{4:17,5:y,7:35,8:h,9:c,11:d,13:u,14:14,15:15,16:16,17:19,23:21,31:o,32:g,33:R,34:I,35:b,36:w,44:q,62:v,63:A},{18:36,62:[1,37],63:[1,38]},{45:39,62:[1,40],63:[1,41]},{51:[1,42],53:[1,43]},e(F,[2,20]),e(F,[2,21]),e(F,[2,22]),e(F,[2,23]),e(F,[2,24]),e(F,[2,25]),e(pe,[2,49]),e(pe,[2,50]),{1:[2,3]},{8:[2,8]},{8:[2,9]},{8:[2,10]},{8:[2,11]},{8:[2,12]},{19:[1,44]},{19:[2,47]},{19:[2,48]},{19:[1,45]},{19:[2,53]},{19:[2,54]},{52:46,55:fe,56:ye,57:_e,58:ge,59:Ee,60:Re,61:me},{52:54,55:fe,56:ye,57:_e,58:ge,59:Ee,60:Re,61:me},{5:[1,55]},{5:[1,56]},{53:[1,57]},e(O,[2,40]),e(O,[2,41]),e(O,[2,42]),e(O,[2,43]),e(O,[2,44]),e(O,[2,45]),e(O,[2,46]),{54:[1,58]},{5:D,20:59,21:P,24:Y,26:U,28:B,30:Q},{5:j,30:X,46:66,47:J,49:Z},{23:71,62:v,63:A},{23:72,62:v,63:A},e(S,[2,13]),{22:[1,73]},{22:[1,74]},{22:[1,75]},{22:[1,76]},{5:D,20:77,21:P,24:Y,26:U,28:B,30:Q},e(S,[2,19]),e(S,[2,33]),{22:[1,78]},{22:[1,79]},{5:j,30:X,46:80,47:J,49:Z},e(S,[2,37]),e(S,[2,38]),e(S,[2,39]),{23:81,62:v,63:A},{25:82,62:[1,83],63:[1,84]},{27:85,37:[1,86],38:[1,87],39:[1,88]},{29:89,40:[1,90],41:[1,91],42:[1,92],43:[1,93]},e(S,[2,18]),{48:94,62:[1,95],63:[1,96]},{50:97,62:[1,98],63:[1,99]},e(S,[2,36]),{5:[1,100]},{5:[1,101]},{5:[2,51]},{5:[2,52]},{5:[1,102]},{5:[2,26]},{5:[2,27]},{5:[2,28]},{5:[1,103]},{5:[2,29]},{5:[2,30]},{5:[2,31]},{5:[2,32]},{5:[1,104]},{5:[2,55]},{5:[2,56]},{5:[1,105]},{5:[2,57]},{5:[2,58]},{5:D,20:106,21:P,24:Y,26:U,28:B,30:Q},{5:D,20:107,21:P,24:Y,26:U,28:B,30:Q},{5:D,20:108,21:P,24:Y,26:U,28:B,30:Q},{5:D,20:109,21:P,24:Y,26:U,28:B,30:Q},{5:j,30:X,46:110,47:J,49:Z},{5:j,30:X,46:111,47:J,49:Z},e(S,[2,14]),e(S,[2,15]),e(S,[2,16]),e(S,[2,17]),e(S,[2,34]),e(S,[2,35])],defaultActions:{8:[2,2],12:[2,1],30:[2,3],31:[2,8],32:[2,9],33:[2,10],34:[2,11],35:[2,12],37:[2,47],38:[2,48],40:[2,53],41:[2,54],83:[2,51],84:[2,52],86:[2,26],87:[2,27],88:[2,28],90:[2,29],91:[2,30],92:[2,31],93:[2,32],95:[2,55],96:[2,56],98:[2,57],99:[2,58]},parseError:r(function(i,a){if(a.recoverable)this.trace(i);else{var l=new Error(i);throw l.hash=a,l}},"parseError"),parse:r(function(i){var a=this,l=[0],n=[],f=[null],s=[],K=this.table,E="",te=0,Ie=0,Le=2,be=1,Oe=s.slice.call(arguments,1),m=Object.create(this.lexer),C={yy:{}};for(var se in this.yy)Object.prototype.hasOwnProperty.call(this.yy,se)&&(C.yy[se]=this.yy[se]);m.setInput(i,C.yy),C.yy.lexer=m,C.yy.parser=this,typeof m.yylloc>"u"&&(m.yylloc={});var ae=m.yylloc;s.push(ae);var Ce=m.options&&m.options.ranges;typeof C.yy.parseError=="function"?this.parseError=C.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function Me(N){l.length=l.length-2*N,f.length=f.length-N,s.length=s.length-N}r(Me,"popStack");function Se(){var N;return N=n.pop()||m.lex()||be,typeof N!="number"&&(N instanceof Array&&(n=N,N=n.pop()),N=a.symbols_[N]||N),N}r(Se,"lex");for(var k,M,x,le,H={},ie,V,ke,re;;){if(M=l[l.length-1],this.defaultActions[M]?x=this.defaultActions[M]:((k===null||typeof k>"u")&&(k=Se()),x=K[M]&&K[M][k]),typeof x>"u"||!x.length||!x[0]){var oe="";re=[];for(ie in K[M])this.terminals_[ie]&&ie>Le&&re.push("'"+this.terminals_[ie]+"'");m.showPosition?oe="Parse error on line "+(te+1)+`: +import{_ as r,d as ve,s as Fe,g as De,c as Pe,b as Ye,l as xe,t as Ue,j as ce,k as Be,a2 as Qe,e as Te}from"./mermaid.core-D8igZDel.js";import{G as He}from"./graph-Cjb-DGHB.js";import{l as We}from"./layout-CHeuV-iP.js";import"./app-D7uBbsY3.js";import"./baseUniq-D0lZO5yp.js";import"./basePickBy-DpnmgMOi.js";var he=function(){var e=r(function($,i,a,l){for(a=a||{},l=$.length;l--;a[$[l]]=i);return a},"o"),t=[1,3],c=[1,4],d=[1,5],u=[1,6],p=[5,6,8,9,11,13,31,32,33,34,35,36,44,62,63],y=[1,18],h=[2,7],o=[1,22],g=[1,23],R=[1,24],I=[1,25],b=[1,26],w=[1,27],q=[1,20],v=[1,28],A=[1,29],F=[62,63],pe=[5,8,9,11,13,31,32,33,34,35,36,44,51,53,62,63],fe=[1,47],ye=[1,48],_e=[1,49],ge=[1,50],Ee=[1,51],Re=[1,52],me=[1,53],O=[53,54],D=[1,64],P=[1,60],Y=[1,61],U=[1,62],B=[1,63],Q=[1,65],j=[1,69],X=[1,70],J=[1,67],Z=[1,68],S=[5,8,9,11,13,31,32,33,34,35,36,44,62,63],ne={trace:r(function(){},"trace"),yy:{},symbols_:{error:2,start:3,directive:4,NEWLINE:5,RD:6,diagram:7,EOF:8,acc_title:9,acc_title_value:10,acc_descr:11,acc_descr_value:12,acc_descr_multiline_value:13,requirementDef:14,elementDef:15,relationshipDef:16,requirementType:17,requirementName:18,STRUCT_START:19,requirementBody:20,ID:21,COLONSEP:22,id:23,TEXT:24,text:25,RISK:26,riskLevel:27,VERIFYMTHD:28,verifyType:29,STRUCT_STOP:30,REQUIREMENT:31,FUNCTIONAL_REQUIREMENT:32,INTERFACE_REQUIREMENT:33,PERFORMANCE_REQUIREMENT:34,PHYSICAL_REQUIREMENT:35,DESIGN_CONSTRAINT:36,LOW_RISK:37,MED_RISK:38,HIGH_RISK:39,VERIFY_ANALYSIS:40,VERIFY_DEMONSTRATION:41,VERIFY_INSPECTION:42,VERIFY_TEST:43,ELEMENT:44,elementName:45,elementBody:46,TYPE:47,type:48,DOCREF:49,ref:50,END_ARROW_L:51,relationship:52,LINE:53,END_ARROW_R:54,CONTAINS:55,COPIES:56,DERIVES:57,SATISFIES:58,VERIFIES:59,REFINES:60,TRACES:61,unqString:62,qString:63,$accept:0,$end:1},terminals_:{2:"error",5:"NEWLINE",6:"RD",8:"EOF",9:"acc_title",10:"acc_title_value",11:"acc_descr",12:"acc_descr_value",13:"acc_descr_multiline_value",19:"STRUCT_START",21:"ID",22:"COLONSEP",24:"TEXT",26:"RISK",28:"VERIFYMTHD",30:"STRUCT_STOP",31:"REQUIREMENT",32:"FUNCTIONAL_REQUIREMENT",33:"INTERFACE_REQUIREMENT",34:"PERFORMANCE_REQUIREMENT",35:"PHYSICAL_REQUIREMENT",36:"DESIGN_CONSTRAINT",37:"LOW_RISK",38:"MED_RISK",39:"HIGH_RISK",40:"VERIFY_ANALYSIS",41:"VERIFY_DEMONSTRATION",42:"VERIFY_INSPECTION",43:"VERIFY_TEST",44:"ELEMENT",47:"TYPE",49:"DOCREF",51:"END_ARROW_L",53:"LINE",54:"END_ARROW_R",55:"CONTAINS",56:"COPIES",57:"DERIVES",58:"SATISFIES",59:"VERIFIES",60:"REFINES",61:"TRACES",62:"unqString",63:"qString"},productions_:[0,[3,3],[3,2],[3,4],[4,2],[4,2],[4,1],[7,0],[7,2],[7,2],[7,2],[7,2],[7,2],[14,5],[20,5],[20,5],[20,5],[20,5],[20,2],[20,1],[17,1],[17,1],[17,1],[17,1],[17,1],[17,1],[27,1],[27,1],[27,1],[29,1],[29,1],[29,1],[29,1],[15,5],[46,5],[46,5],[46,2],[46,1],[16,5],[16,5],[52,1],[52,1],[52,1],[52,1],[52,1],[52,1],[52,1],[18,1],[18,1],[23,1],[23,1],[25,1],[25,1],[45,1],[45,1],[48,1],[48,1],[50,1],[50,1]],performAction:r(function(i,a,l,n,f,s,K){var E=s.length-1;switch(f){case 4:this.$=s[E].trim(),n.setAccTitle(this.$);break;case 5:case 6:this.$=s[E].trim(),n.setAccDescription(this.$);break;case 7:this.$=[];break;case 13:n.addRequirement(s[E-3],s[E-4]);break;case 14:n.setNewReqId(s[E-2]);break;case 15:n.setNewReqText(s[E-2]);break;case 16:n.setNewReqRisk(s[E-2]);break;case 17:n.setNewReqVerifyMethod(s[E-2]);break;case 20:this.$=n.RequirementType.REQUIREMENT;break;case 21:this.$=n.RequirementType.FUNCTIONAL_REQUIREMENT;break;case 22:this.$=n.RequirementType.INTERFACE_REQUIREMENT;break;case 23:this.$=n.RequirementType.PERFORMANCE_REQUIREMENT;break;case 24:this.$=n.RequirementType.PHYSICAL_REQUIREMENT;break;case 25:this.$=n.RequirementType.DESIGN_CONSTRAINT;break;case 26:this.$=n.RiskLevel.LOW_RISK;break;case 27:this.$=n.RiskLevel.MED_RISK;break;case 28:this.$=n.RiskLevel.HIGH_RISK;break;case 29:this.$=n.VerifyType.VERIFY_ANALYSIS;break;case 30:this.$=n.VerifyType.VERIFY_DEMONSTRATION;break;case 31:this.$=n.VerifyType.VERIFY_INSPECTION;break;case 32:this.$=n.VerifyType.VERIFY_TEST;break;case 33:n.addElement(s[E-3]);break;case 34:n.setNewElementType(s[E-2]);break;case 35:n.setNewElementDocRef(s[E-2]);break;case 38:n.addRelationship(s[E-2],s[E],s[E-4]);break;case 39:n.addRelationship(s[E-2],s[E-4],s[E]);break;case 40:this.$=n.Relationships.CONTAINS;break;case 41:this.$=n.Relationships.COPIES;break;case 42:this.$=n.Relationships.DERIVES;break;case 43:this.$=n.Relationships.SATISFIES;break;case 44:this.$=n.Relationships.VERIFIES;break;case 45:this.$=n.Relationships.REFINES;break;case 46:this.$=n.Relationships.TRACES;break}},"anonymous"),table:[{3:1,4:2,6:t,9:c,11:d,13:u},{1:[3]},{3:8,4:2,5:[1,7],6:t,9:c,11:d,13:u},{5:[1,9]},{10:[1,10]},{12:[1,11]},e(p,[2,6]),{3:12,4:2,6:t,9:c,11:d,13:u},{1:[2,2]},{4:17,5:y,7:13,8:h,9:c,11:d,13:u,14:14,15:15,16:16,17:19,23:21,31:o,32:g,33:R,34:I,35:b,36:w,44:q,62:v,63:A},e(p,[2,4]),e(p,[2,5]),{1:[2,1]},{8:[1,30]},{4:17,5:y,7:31,8:h,9:c,11:d,13:u,14:14,15:15,16:16,17:19,23:21,31:o,32:g,33:R,34:I,35:b,36:w,44:q,62:v,63:A},{4:17,5:y,7:32,8:h,9:c,11:d,13:u,14:14,15:15,16:16,17:19,23:21,31:o,32:g,33:R,34:I,35:b,36:w,44:q,62:v,63:A},{4:17,5:y,7:33,8:h,9:c,11:d,13:u,14:14,15:15,16:16,17:19,23:21,31:o,32:g,33:R,34:I,35:b,36:w,44:q,62:v,63:A},{4:17,5:y,7:34,8:h,9:c,11:d,13:u,14:14,15:15,16:16,17:19,23:21,31:o,32:g,33:R,34:I,35:b,36:w,44:q,62:v,63:A},{4:17,5:y,7:35,8:h,9:c,11:d,13:u,14:14,15:15,16:16,17:19,23:21,31:o,32:g,33:R,34:I,35:b,36:w,44:q,62:v,63:A},{18:36,62:[1,37],63:[1,38]},{45:39,62:[1,40],63:[1,41]},{51:[1,42],53:[1,43]},e(F,[2,20]),e(F,[2,21]),e(F,[2,22]),e(F,[2,23]),e(F,[2,24]),e(F,[2,25]),e(pe,[2,49]),e(pe,[2,50]),{1:[2,3]},{8:[2,8]},{8:[2,9]},{8:[2,10]},{8:[2,11]},{8:[2,12]},{19:[1,44]},{19:[2,47]},{19:[2,48]},{19:[1,45]},{19:[2,53]},{19:[2,54]},{52:46,55:fe,56:ye,57:_e,58:ge,59:Ee,60:Re,61:me},{52:54,55:fe,56:ye,57:_e,58:ge,59:Ee,60:Re,61:me},{5:[1,55]},{5:[1,56]},{53:[1,57]},e(O,[2,40]),e(O,[2,41]),e(O,[2,42]),e(O,[2,43]),e(O,[2,44]),e(O,[2,45]),e(O,[2,46]),{54:[1,58]},{5:D,20:59,21:P,24:Y,26:U,28:B,30:Q},{5:j,30:X,46:66,47:J,49:Z},{23:71,62:v,63:A},{23:72,62:v,63:A},e(S,[2,13]),{22:[1,73]},{22:[1,74]},{22:[1,75]},{22:[1,76]},{5:D,20:77,21:P,24:Y,26:U,28:B,30:Q},e(S,[2,19]),e(S,[2,33]),{22:[1,78]},{22:[1,79]},{5:j,30:X,46:80,47:J,49:Z},e(S,[2,37]),e(S,[2,38]),e(S,[2,39]),{23:81,62:v,63:A},{25:82,62:[1,83],63:[1,84]},{27:85,37:[1,86],38:[1,87],39:[1,88]},{29:89,40:[1,90],41:[1,91],42:[1,92],43:[1,93]},e(S,[2,18]),{48:94,62:[1,95],63:[1,96]},{50:97,62:[1,98],63:[1,99]},e(S,[2,36]),{5:[1,100]},{5:[1,101]},{5:[2,51]},{5:[2,52]},{5:[1,102]},{5:[2,26]},{5:[2,27]},{5:[2,28]},{5:[1,103]},{5:[2,29]},{5:[2,30]},{5:[2,31]},{5:[2,32]},{5:[1,104]},{5:[2,55]},{5:[2,56]},{5:[1,105]},{5:[2,57]},{5:[2,58]},{5:D,20:106,21:P,24:Y,26:U,28:B,30:Q},{5:D,20:107,21:P,24:Y,26:U,28:B,30:Q},{5:D,20:108,21:P,24:Y,26:U,28:B,30:Q},{5:D,20:109,21:P,24:Y,26:U,28:B,30:Q},{5:j,30:X,46:110,47:J,49:Z},{5:j,30:X,46:111,47:J,49:Z},e(S,[2,14]),e(S,[2,15]),e(S,[2,16]),e(S,[2,17]),e(S,[2,34]),e(S,[2,35])],defaultActions:{8:[2,2],12:[2,1],30:[2,3],31:[2,8],32:[2,9],33:[2,10],34:[2,11],35:[2,12],37:[2,47],38:[2,48],40:[2,53],41:[2,54],83:[2,51],84:[2,52],86:[2,26],87:[2,27],88:[2,28],90:[2,29],91:[2,30],92:[2,31],93:[2,32],95:[2,55],96:[2,56],98:[2,57],99:[2,58]},parseError:r(function(i,a){if(a.recoverable)this.trace(i);else{var l=new Error(i);throw l.hash=a,l}},"parseError"),parse:r(function(i){var a=this,l=[0],n=[],f=[null],s=[],K=this.table,E="",te=0,Ie=0,Le=2,be=1,Oe=s.slice.call(arguments,1),m=Object.create(this.lexer),C={yy:{}};for(var se in this.yy)Object.prototype.hasOwnProperty.call(this.yy,se)&&(C.yy[se]=this.yy[se]);m.setInput(i,C.yy),C.yy.lexer=m,C.yy.parser=this,typeof m.yylloc>"u"&&(m.yylloc={});var ae=m.yylloc;s.push(ae);var Ce=m.options&&m.options.ranges;typeof C.yy.parseError=="function"?this.parseError=C.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function Me(N){l.length=l.length-2*N,f.length=f.length-N,s.length=s.length-N}r(Me,"popStack");function Se(){var N;return N=n.pop()||m.lex()||be,typeof N!="number"&&(N instanceof Array&&(n=N,N=n.pop()),N=a.symbols_[N]||N),N}r(Se,"lex");for(var k,M,x,le,H={},ie,V,ke,re;;){if(M=l[l.length-1],this.defaultActions[M]?x=this.defaultActions[M]:((k===null||typeof k>"u")&&(k=Se()),x=K[M]&&K[M][k]),typeof x>"u"||!x.length||!x[0]){var oe="";re=[];for(ie in K[M])this.terminals_[ie]&&ie>Le&&re.push("'"+this.terminals_[ie]+"'");m.showPosition?oe="Parse error on line "+(te+1)+`: `+m.showPosition()+` Expecting `+re.join(", ")+", got '"+(this.terminals_[k]||k)+"'":oe="Parse error on line "+(te+1)+": Unexpected "+(k==be?"end of input":"'"+(this.terminals_[k]||k)+"'"),this.parseError(oe,{text:m.match,token:this.terminals_[k]||k,line:m.yylineno,loc:ae,expected:re})}if(x[0]instanceof Array&&x.length>1)throw new Error("Parse Error: multiple actions possible at state: "+M+", token: "+k);switch(x[0]){case 1:l.push(k),f.push(m.yytext),s.push(m.yylloc),l.push(x[1]),k=null,Ie=m.yyleng,E=m.yytext,te=m.yylineno,ae=m.yylloc;break;case 2:if(V=this.productions_[x[1]][1],H.$=f[f.length-V],H._$={first_line:s[s.length-(V||1)].first_line,last_line:s[s.length-1].last_line,first_column:s[s.length-(V||1)].first_column,last_column:s[s.length-1].last_column},Ce&&(H._$.range=[s[s.length-(V||1)].range[0],s[s.length-1].range[1]]),le=this.performAction.apply(H,[E,Ie,te,C.yy,x[1],f,s].concat(Oe)),typeof le<"u")return le;V&&(l=l.slice(0,-1*V*2),f=f.slice(0,-1*V),s=s.slice(0,-1*V)),l.push(this.productions_[x[1]][0]),f.push(H.$),s.push(H._$),ke=K[l[l.length-2]][l[l.length-1]],l.push(ke);break;case 3:return!0}}return!0},"parse")},$e=function(){var $={EOF:1,parseError:r(function(a,l){if(this.yy.parser)this.yy.parser.parseError(a,l);else throw new Error(a)},"parseError"),setInput:r(function(i,a){return this.yy=a||this.yy||{},this._input=i,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},"setInput"),input:r(function(){var i=this._input[0];this.yytext+=i,this.yyleng++,this.offset++,this.match+=i,this.matched+=i;var a=i.match(/(?:\r\n?|\n).*/g);return a?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),i},"input"),unput:r(function(i){var a=i.length,l=i.split(/(?:\r\n?|\n)/g);this._input=i+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-a),this.offset-=a;var n=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),l.length-1&&(this.yylineno-=l.length-1);var f=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:l?(l.length===n.length?this.yylloc.first_column:0)+n[n.length-l.length].length-l[0].length:this.yylloc.first_column-a},this.options.ranges&&(this.yylloc.range=[f[0],f[0]+this.yyleng-a]),this.yyleng=this.yytext.length,this},"unput"),more:r(function(){return this._more=!0,this},"more"),reject:r(function(){if(this.options.backtrack_lexer)this._backtrack=!0;else return this.parseError("Lexical error on line "+(this.yylineno+1)+`. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true). `+this.showPosition(),{text:"",token:null,line:this.yylineno});return this},"reject"),less:r(function(i){this.unput(this.match.slice(i))},"less"),pastInput:r(function(){var i=this.matched.substr(0,this.matched.length-this.match.length);return(i.length>20?"...":"")+i.substr(-20).replace(/\n/g,"")},"pastInput"),upcomingInput:r(function(){var i=this.match;return i.length<20&&(i+=this._input.substr(0,20-i.length)),(i.substr(0,20)+(i.length>20?"...":"")).replace(/\n/g,"")},"upcomingInput"),showPosition:r(function(){var i=this.pastInput(),a=new Array(i.length+1).join("-");return i+this.upcomingInput()+` diff --git a/assets/reverse.html-CW54AkoO.js b/assets/reverse.html-7Uo0yIWr.js similarity index 99% rename from assets/reverse.html-CW54AkoO.js rename to assets/reverse.html-7Uo0yIWr.js index 1af657afb9..0ee243abf8 100644 --- a/assets/reverse.html-CW54AkoO.js +++ b/assets/reverse.html-7Uo0yIWr.js @@ -1,4 +1,4 @@ -import{_ as i,r as p,o as l,c as u,a,b as s,d as n,w as e,e as t}from"./app-DBM4OJyw.js";const r={},d=t('

                                      反向代理

                                      反向代理可以把服务器端的流量向客户端转发,即逆向流量转发。

                                      反向代理的大致工作原理如下:

                                      • 假设在主机 A 中有一个网页服务器,这台主机没有公网 IP,无法在公网上直接访问。另有一台主机 B,它可以由公网访问。现在我们需要把 B 作为入口,把流量从 B 转发到 A。
                                      • 在主机 A 中配置 Xray,称为bridge,在 B 中也配置 Xray,称为 portal
                                      • bridge 会向 portal 主动建立连接,此连接的目标地址可以自行设定。portal 会收到两种连接,一是由 bridge 发来的连接,二是公网用户发来的连接。portal 会自动将两类连接合并。于是 bridge 就可以收到公网流量了。
                                      • bridge 在收到公网流量之后,会将其原封不动地发给主机 A 中的网页服务器。当然,这一步需要路由的协作。
                                      • bridge 会根据流量的大小进行动态的负载均衡。
                                      ',4),v={class:"custom-container tip"},k=s("p",{class:"custom-container-title"},"提示",-1),b=t(`

                                      注意

                                      反向代理功能尚处于测试阶段,可能会有一些问题。

                                      ReverseObject

                                      ReverseObject 对应配置文件的 reverse 项。

                                      {
                                      +import{_ as i,r as p,o as l,c as u,a,b as s,d as n,w as e,e as t}from"./app-D7uBbsY3.js";const r={},d=t('

                                      反向代理

                                      反向代理可以把服务器端的流量向客户端转发,即逆向流量转发。

                                      反向代理的大致工作原理如下:

                                      • 假设在主机 A 中有一个网页服务器,这台主机没有公网 IP,无法在公网上直接访问。另有一台主机 B,它可以由公网访问。现在我们需要把 B 作为入口,把流量从 B 转发到 A。
                                      • 在主机 A 中配置 Xray,称为bridge,在 B 中也配置 Xray,称为 portal
                                      • bridge 会向 portal 主动建立连接,此连接的目标地址可以自行设定。portal 会收到两种连接,一是由 bridge 发来的连接,二是公网用户发来的连接。portal 会自动将两类连接合并。于是 bridge 就可以收到公网流量了。
                                      • bridge 在收到公网流量之后,会将其原封不动地发给主机 A 中的网页服务器。当然,这一步需要路由的协作。
                                      • bridge 会根据流量的大小进行动态的负载均衡。
                                      ',4),v={class:"custom-container tip"},k=s("p",{class:"custom-container-title"},"提示",-1),b=t(`

                                      注意

                                      反向代理功能尚处于测试阶段,可能会有一些问题。

                                      ReverseObject

                                      ReverseObject 对应配置文件的 reverse 项。

                                      {
                                         "reverse": {
                                           "bridges": [
                                             {
                                      diff --git a/assets/reverse.html-DLWtaE_H.js b/assets/reverse.html-CfQGiukd.js
                                      similarity index 99%
                                      rename from assets/reverse.html-DLWtaE_H.js
                                      rename to assets/reverse.html-CfQGiukd.js
                                      index c160cbefa6..8c7c597869 100644
                                      --- a/assets/reverse.html-DLWtaE_H.js
                                      +++ b/assets/reverse.html-CfQGiukd.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as i,r as p,o as l,c as u,a,b as s,d as n,w as e,e as t}from"./app-DBM4OJyw.js";const r={},d=t('

                                      Обратный прокси

                                      Обратный прокси позволяет перенаправлять трафик с сервера на клиент, то есть перенаправлять трафик в обратном направлении.

                                      Принцип работы обратного прокси:

                                      • Предположим, что на хосте A запущен веб-сервер, но у этого хоста нет публичного IP-адреса, и к нему нельзя получить доступ из Интернета.
                                        У нас есть другой хост B с публичным IP-адресом.
                                        Мы хотим использовать хост B в качестве шлюза и перенаправлять трафик с B на A.
                                      • На хосте A настроен Xray, называемый bridge, и на хосте B также настроен Xray, называемый portal.
                                      • bridge устанавливает соединение с portal.
                                        Целевой адрес этого соединения можно настроить произвольно.
                                        portal получает два типа соединений: соединения от bridge и соединения от пользователей из Интернета.
                                        portal автоматически объединяет эти два типа соединений.
                                        Таким образом, bridge может получать трафик из Интернета.
                                      • После получения трафика из Интернета bridge перенаправляет его на веб-сервер на хосте A без изменений.
                                        Конечно, для этого требуется настроить маршрутизацию.
                                      • bridge выполняет динамическую балансировку нагрузки в зависимости от объема трафика.
                                      ',4),v={class:"custom-container tip"},k=s("p",{class:"custom-container-title"},"Подсказка",-1),b=s("br",null,null,-1),q=t(`

                                      Внимание

                                      Функция обратного прокси находится в стадии тестирования и может работать некорректно.

                                      ReverseObject

                                      ReverseObject соответствует полю reverse в конфигурационном файле.

                                      {
                                      +import{_ as i,r as p,o as l,c as u,a,b as s,d as n,w as e,e as t}from"./app-D7uBbsY3.js";const r={},d=t('

                                      Обратный прокси

                                      Обратный прокси позволяет перенаправлять трафик с сервера на клиент, то есть перенаправлять трафик в обратном направлении.

                                      Принцип работы обратного прокси:

                                      • Предположим, что на хосте A запущен веб-сервер, но у этого хоста нет публичного IP-адреса, и к нему нельзя получить доступ из Интернета.
                                        У нас есть другой хост B с публичным IP-адресом.
                                        Мы хотим использовать хост B в качестве шлюза и перенаправлять трафик с B на A.
                                      • На хосте A настроен Xray, называемый bridge, и на хосте B также настроен Xray, называемый portal.
                                      • bridge устанавливает соединение с portal.
                                        Целевой адрес этого соединения можно настроить произвольно.
                                        portal получает два типа соединений: соединения от bridge и соединения от пользователей из Интернета.
                                        portal автоматически объединяет эти два типа соединений.
                                        Таким образом, bridge может получать трафик из Интернета.
                                      • После получения трафика из Интернета bridge перенаправляет его на веб-сервер на хосте A без изменений.
                                        Конечно, для этого требуется настроить маршрутизацию.
                                      • bridge выполняет динамическую балансировку нагрузки в зависимости от объема трафика.
                                      ',4),v={class:"custom-container tip"},k=s("p",{class:"custom-container-title"},"Подсказка",-1),b=s("br",null,null,-1),q=t(`

                                      Внимание

                                      Функция обратного прокси находится в стадии тестирования и может работать некорректно.

                                      ReverseObject

                                      ReverseObject соответствует полю reverse в конфигурационном файле.

                                      {
                                         "reverse": {
                                           "bridges": [
                                             {
                                      diff --git a/assets/reverse.html-BNoHKOBx.js b/assets/reverse.html-CpkNXRut.js
                                      similarity index 99%
                                      rename from assets/reverse.html-BNoHKOBx.js
                                      rename to assets/reverse.html-CpkNXRut.js
                                      index 6c0321526c..219576ba7b 100644
                                      --- a/assets/reverse.html-BNoHKOBx.js
                                      +++ b/assets/reverse.html-CpkNXRut.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as c,r as o,o as r,c as l,a,b as s,d as n,w as p,e}from"./app-DBM4OJyw.js";const u={},d=e(`

                                      Reverse Proxy

                                      A reverse proxy forwards traffic from a server to a client, which is known as reverse traffic forwarding.

                                      Here's how a reverse proxy generally works:

                                      • Suppose there is a web server in host A, which does not have a public IP address and cannot be accessed directly on the Internet. There is another host B that can be accessed via the public network. Now we need to use B as the entry point to forward traffic from B to A.
                                      • Configure Xray in host A as a bridge, and also configure Xray in B as a portal.
                                      • Bridge will actively establish a connection to portal, and the destination address of this connection can be set by itself. Portal will receive two types of connections: one is the connection sent by bridge, and the other is the connection sent by public network users. Portal will automatically merge the two types of connections. So bridge can receive public network traffic.
                                      • After receiving the public network traffic, bridge will forward it unchanged to the web server in host A. Of course, this step requires the cooperation of routing.
                                      • Bridge will dynamically load balance according to the size of the traffic.

                                      Tip

                                      Reverse proxy has Mux enabled by default, so please do not enable Mux again on the outbound it uses.

                                      Warning

                                      The reverse proxy function is still in the testing phase and may have some issues.

                                      ReverseObject

                                      ReverseObject corresponds to the reverse field in the configuration file.

                                      {
                                      +import{_ as c,r as o,o as r,c as l,a,b as s,d as n,w as p,e}from"./app-D7uBbsY3.js";const u={},d=e(`

                                      Reverse Proxy

                                      A reverse proxy forwards traffic from a server to a client, which is known as reverse traffic forwarding.

                                      Here's how a reverse proxy generally works:

                                      • Suppose there is a web server in host A, which does not have a public IP address and cannot be accessed directly on the Internet. There is another host B that can be accessed via the public network. Now we need to use B as the entry point to forward traffic from B to A.
                                      • Configure Xray in host A as a bridge, and also configure Xray in B as a portal.
                                      • Bridge will actively establish a connection to portal, and the destination address of this connection can be set by itself. Portal will receive two types of connections: one is the connection sent by bridge, and the other is the connection sent by public network users. Portal will automatically merge the two types of connections. So bridge can receive public network traffic.
                                      • After receiving the public network traffic, bridge will forward it unchanged to the web server in host A. Of course, this step requires the cooperation of routing.
                                      • Bridge will dynamically load balance according to the size of the traffic.

                                      Tip

                                      Reverse proxy has Mux enabled by default, so please do not enable Mux again on the outbound it uses.

                                      Warning

                                      The reverse proxy function is still in the testing phase and may have some issues.

                                      ReverseObject

                                      ReverseObject corresponds to the reverse field in the configuration file.

                                      {
                                         "reverse": {
                                           "bridges": [
                                             {
                                      diff --git a/assets/routing-lv1-part1.html-CM6bRG4P.js b/assets/routing-lv1-part1.html-BYLEkwqC.js
                                      similarity index 99%
                                      rename from assets/routing-lv1-part1.html-CM6bRG4P.js
                                      rename to assets/routing-lv1-part1.html-BYLEkwqC.js
                                      index f3dc1f1849..054756aa81 100644
                                      --- a/assets/routing-lv1-part1.html-CM6bRG4P.js
                                      +++ b/assets/routing-lv1-part1.html-BYLEkwqC.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as i,r as p,o as u,c as r,a,b as n,d as s,w as d,e as t}from"./app-DBM4OJyw.js";const k="/assets/routing-lv1-img01-trio-Dac-S2au.jpg",v={},g=t('

                                      路由 (routing) 功能简析(上)

                                      如果说 Xray 的【强大】主要体现在它极致的速度和广泛的兼容性。那么 Xray 的【灵活】,则主要应该归功于它巧妙的【路由】功能。本文就稍微说明一下这个功能的逻辑以及使用方式。

                                      1. 初识【路由】三兄弟

                                      要理解路由,就要理解完整的路由功能需要有三兄弟来合力完成:1. 入站;2. 路由;3. 出站

                                      路由三兄弟

                                      三兄弟桃园结义,不求同年同月同日生,但求同年同月同日死。

                                      所以谨记:任何一个元素错误,就可能导致路由功能无法正常工作。

                                      因为路由的灵活性非常高,只看技术文档很容易把自己绕晕,所以本文我们用几个具体的示例来逐层讲解。

                                      啰嗦君

                                      路由功能实在过于灵活,所以本文的示例,都是为了讲解对应的概念,实际使用时请根据自己的需求进行调整。

                                      2. 基本功: “兄弟一条心”

                                      下图的示例,就是在客户端的 Xray 入站接收 APP 数据、在路由 100%转发给出站,并从出站流向 VPS。

                                      ',11),q=t(`

                                      下面我们来逐个分析:

                                      2.1 入站

                                      提示

                                      入站: 就是流量如何流入 Xray

                                      下面的入站配置示例,用大白话说就是:数据按照 socks 协议,通过 10808 端口,从本机 127.0.0.1 流入Xray。同时,Xray 将这个入站用 [tag] 命名为 inbound-10808

                                      {
                                      +import{_ as i,r as p,o as u,c as r,a,b as n,d as s,w as d,e as t}from"./app-D7uBbsY3.js";const k="/assets/routing-lv1-img01-trio-Dac-S2au.jpg",v={},g=t('

                                      路由 (routing) 功能简析(上)

                                      如果说 Xray 的【强大】主要体现在它极致的速度和广泛的兼容性。那么 Xray 的【灵活】,则主要应该归功于它巧妙的【路由】功能。本文就稍微说明一下这个功能的逻辑以及使用方式。

                                      1. 初识【路由】三兄弟

                                      要理解路由,就要理解完整的路由功能需要有三兄弟来合力完成:1. 入站;2. 路由;3. 出站

                                      路由三兄弟

                                      三兄弟桃园结义,不求同年同月同日生,但求同年同月同日死。

                                      所以谨记:任何一个元素错误,就可能导致路由功能无法正常工作。

                                      因为路由的灵活性非常高,只看技术文档很容易把自己绕晕,所以本文我们用几个具体的示例来逐层讲解。

                                      啰嗦君

                                      路由功能实在过于灵活,所以本文的示例,都是为了讲解对应的概念,实际使用时请根据自己的需求进行调整。

                                      2. 基本功: “兄弟一条心”

                                      下图的示例,就是在客户端的 Xray 入站接收 APP 数据、在路由 100%转发给出站,并从出站流向 VPS。

                                      ',11),q=t(`

                                      下面我们来逐个分析:

                                      2.1 入站

                                      提示

                                      入站: 就是流量如何流入 Xray

                                      下面的入站配置示例,用大白话说就是:数据按照 socks 协议,通过 10808 端口,从本机 127.0.0.1 流入Xray。同时,Xray 将这个入站用 [tag] 命名为 inbound-10808

                                      {
                                         "inbounds": [
                                           {
                                             "tag": "inbound-10808",
                                      diff --git a/assets/routing-lv1-part1.html-lS-Lwun1.js b/assets/routing-lv1-part1.html-Byn2h66N.js
                                      similarity index 99%
                                      rename from assets/routing-lv1-part1.html-lS-Lwun1.js
                                      rename to assets/routing-lv1-part1.html-Byn2h66N.js
                                      index 18dcb2fba7..60db0dfd6d 100644
                                      --- a/assets/routing-lv1-part1.html-lS-Lwun1.js
                                      +++ b/assets/routing-lv1-part1.html-Byn2h66N.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as i,r as p,o as u,c as r,a as o,b as n,d as s,w as d,e as a}from"./app-DBM4OJyw.js";const D="/assets/routing-lv1-img01-trio-Dac-S2au.jpg",g={},k=a('

                                      Краткий обзор функции маршрутизации (routing) (часть 1)

                                      Если "мощность" Xray в основном заключается в его высокой скорости и широкой совместимости, то его "гибкость" в первую очередь связана с продуманной функцией "routing" (маршрутизация). В этой статье мы кратко рассмотрим логику этой функции и способы ее применения.

                                      1. Знакомство с тремя братьями-маршрутизаторами

                                      Чтобы понять маршрутизацию, нужно понимать, что для ее полноценной работы нужны три компонента: 1. входящий трафик (inbound); 2. маршрутизация (routing); 3. исходящий трафик (outbound).

                                      Три брата-маршрутизатора

                                      Три брата, поклявшиеся в верности, не обязательно родились в один день, но должны быть готовы умереть в один день.

                                      Поэтому запомните: если один из элементов работает неправильно, функция маршрутизации может не работать.

                                      Поскольку маршрутизация очень гибкая, чтение только технической документации может вас запутать, поэтому в этой статье мы будем использовать конкретные примеры, чтобы объяснить все пошагово.

                                      Внимание

                                      Функция маршрутизации настолько гибкая, что примеры в этой статье приведены только для объяснения соответствующих концепций. На практике, пожалуйста, корректируйте их в соответствии с вашими потребностями.

                                      2. Основы: "Братья едины"

                                      На рисунке ниже показан пример, когда входящий трафик от приложения поступает на Xray на клиенте, маршрутизируется на исходящий трафик и отправляется на VPS.

                                      ',11),q=a(`

                                      Давайте проанализируем каждый шаг:

                                      2.1 Входящий трафик

                                      Подсказка

                                      Входящий трафик (inbound): это то, как трафик попадает в Xray.

                                      Пример конфигурации входящего трафика ниже означает, что данные поступают в Xray по протоколу socks через порт 10808 с локального адреса 127.0.0.1. Xray присваивает этому входящему трафику имя inbound-10808 с помощью [tag].

                                      {
                                      +import{_ as i,r as p,o as u,c as r,a as o,b as n,d as s,w as d,e as a}from"./app-D7uBbsY3.js";const D="/assets/routing-lv1-img01-trio-Dac-S2au.jpg",g={},k=a('

                                      Краткий обзор функции маршрутизации (routing) (часть 1)

                                      Если "мощность" Xray в основном заключается в его высокой скорости и широкой совместимости, то его "гибкость" в первую очередь связана с продуманной функцией "routing" (маршрутизация). В этой статье мы кратко рассмотрим логику этой функции и способы ее применения.

                                      1. Знакомство с тремя братьями-маршрутизаторами

                                      Чтобы понять маршрутизацию, нужно понимать, что для ее полноценной работы нужны три компонента: 1. входящий трафик (inbound); 2. маршрутизация (routing); 3. исходящий трафик (outbound).

                                      Три брата-маршрутизатора

                                      Три брата, поклявшиеся в верности, не обязательно родились в один день, но должны быть готовы умереть в один день.

                                      Поэтому запомните: если один из элементов работает неправильно, функция маршрутизации может не работать.

                                      Поскольку маршрутизация очень гибкая, чтение только технической документации может вас запутать, поэтому в этой статье мы будем использовать конкретные примеры, чтобы объяснить все пошагово.

                                      Внимание

                                      Функция маршрутизации настолько гибкая, что примеры в этой статье приведены только для объяснения соответствующих концепций. На практике, пожалуйста, корректируйте их в соответствии с вашими потребностями.

                                      2. Основы: "Братья едины"

                                      На рисунке ниже показан пример, когда входящий трафик от приложения поступает на Xray на клиенте, маршрутизируется на исходящий трафик и отправляется на VPS.

                                      ',11),q=a(`

                                      Давайте проанализируем каждый шаг:

                                      2.1 Входящий трафик

                                      Подсказка

                                      Входящий трафик (inbound): это то, как трафик попадает в Xray.

                                      Пример конфигурации входящего трафика ниже означает, что данные поступают в Xray по протоколу socks через порт 10808 с локального адреса 127.0.0.1. Xray присваивает этому входящему трафику имя inbound-10808 с помощью [tag].

                                      {
                                         "inbounds": [
                                           {
                                             "tag": "inbound-10808",
                                      diff --git a/assets/routing-lv1-part1.html-DXlYZzcq.js b/assets/routing-lv1-part1.html-nqov9OAV.js
                                      similarity index 99%
                                      rename from assets/routing-lv1-part1.html-DXlYZzcq.js
                                      rename to assets/routing-lv1-part1.html-nqov9OAV.js
                                      index 555ff8620b..380d02c20f 100644
                                      --- a/assets/routing-lv1-part1.html-DXlYZzcq.js
                                      +++ b/assets/routing-lv1-part1.html-nqov9OAV.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as i,r as p,o as u,c as r,a,b as n,d as s,w as d,e as t}from"./app-DBM4OJyw.js";const k="/assets/routing-lv1-img01-trio-Dac-S2au.jpg",v={},g=t('

                                      路由 (routing) 功能简析(上)

                                      如果说 Xray 的【强大】主要体现在它极致的速度和广泛的兼容性。那么 Xray 的【灵活】,则主要应该归功于它巧妙的【路由】功能。本文就稍微说明一下这个功能的逻辑以及使用方式。

                                      1. 初识【路由】三兄弟

                                      要理解路由,就要理解完整的路由功能需要有三兄弟来合力完成:1. 入站;2. 路由;3. 出站

                                      路由三兄弟

                                      三兄弟桃园结义,不求同年同月同日生,但求同年同月同日死。

                                      所以谨记:任何一个元素错误,就可能导致路由功能无法正常工作。

                                      因为路由的灵活性非常高,只看技术文档很容易把自己绕晕,所以本文我们用几个具体的示例来逐层讲解。

                                      啰嗦君

                                      路由功能实在过于灵活,所以本文的示例,都是为了讲解对应的概念,实际使用时请根据自己的需求进行调整。

                                      2. 基本功: “兄弟一条心”

                                      下图的示例,就是在客户端的 Xray 入站接收 APP 数据、在路由 100%转发给出站,并从出站流向 VPS。

                                      ',11),q=t(`

                                      下面我们来逐个分析:

                                      2.1 入站

                                      Tip

                                      入站: 就是流量如何流入 Xray

                                      下面的入站配置示例,用大白话说就是:数据按照 socks 协议,通过 10808 端口,从本机 127.0.0.1 流入Xray。同时,Xray 将这个入站用 [tag] 命名为 inbound-10808

                                      {
                                      +import{_ as i,r as p,o as u,c as r,a,b as n,d as s,w as d,e as t}from"./app-D7uBbsY3.js";const k="/assets/routing-lv1-img01-trio-Dac-S2au.jpg",v={},g=t('

                                      路由 (routing) 功能简析(上)

                                      如果说 Xray 的【强大】主要体现在它极致的速度和广泛的兼容性。那么 Xray 的【灵活】,则主要应该归功于它巧妙的【路由】功能。本文就稍微说明一下这个功能的逻辑以及使用方式。

                                      1. 初识【路由】三兄弟

                                      要理解路由,就要理解完整的路由功能需要有三兄弟来合力完成:1. 入站;2. 路由;3. 出站

                                      路由三兄弟

                                      三兄弟桃园结义,不求同年同月同日生,但求同年同月同日死。

                                      所以谨记:任何一个元素错误,就可能导致路由功能无法正常工作。

                                      因为路由的灵活性非常高,只看技术文档很容易把自己绕晕,所以本文我们用几个具体的示例来逐层讲解。

                                      啰嗦君

                                      路由功能实在过于灵活,所以本文的示例,都是为了讲解对应的概念,实际使用时请根据自己的需求进行调整。

                                      2. 基本功: “兄弟一条心”

                                      下图的示例,就是在客户端的 Xray 入站接收 APP 数据、在路由 100%转发给出站,并从出站流向 VPS。

                                      ',11),q=t(`

                                      下面我们来逐个分析:

                                      2.1 入站

                                      Tip

                                      入站: 就是流量如何流入 Xray

                                      下面的入站配置示例,用大白话说就是:数据按照 socks 协议,通过 10808 端口,从本机 127.0.0.1 流入Xray。同时,Xray 将这个入站用 [tag] 命名为 inbound-10808

                                      {
                                         "inbounds": [
                                           {
                                             "tag": "inbound-10808",
                                      diff --git a/assets/routing-lv1-part2.html-C6Xae5-1.js b/assets/routing-lv1-part2.html-DNcAgdJC.js
                                      similarity index 99%
                                      rename from assets/routing-lv1-part2.html-C6Xae5-1.js
                                      rename to assets/routing-lv1-part2.html-DNcAgdJC.js
                                      index 3286e0509c..a81f922f7f 100644
                                      --- a/assets/routing-lv1-part2.html-C6Xae5-1.js
                                      +++ b/assets/routing-lv1-part2.html-DNcAgdJC.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as l,r as p,o as u,c as d,a,b as s,d as n,w as e,e as o}from"./app-DBM4OJyw.js";const r={},k=s("h1",{id:"路由-routing-功能简析-下",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#路由-routing-功能简析-下"},[s("span",null,"路由 (routing) 功能简析(下)")])],-1),v=s("p",null,[n("欢迎继续学习 "),s("code",null,"Xray"),n(" 的【路由】功能!")],-1),m=s("code",null,"geosite.dat",-1),q=o('

                                      如前面所说,域名分流仅仅是【路由】功能的牛刀小试而已。下面就让我们来看看除了域名之外,还什么可以用做分流依据的东西吧!

                                      5. 攻城略池 - 多种路由匹配条件

                                      [域名], [IP], [协议], etc.

                                      基于域名的分流,已经可以让我们对网络流量进行基本合理的分流。为什么说【基本合理】呢?

                                      因为【三分天下】虽然是正确的战略方向,但如果只用【域名】来实现这个战略,其实漏洞百出,比如:

                                      1. 我读了《小小白白话文》后,给 VPS 新申请了一个 proxy.yourdomain.com 的域名, 我希望它无论如何都代理,geosite.dat 里面有吗?
                                      2. 如果我还有个 direct.yourdomain.com 的域名,我希望它无论如何都直连, geosite.dat 里面有吗?
                                      3. 本机 127.0.0.1 的内部流量,是否正确直连了?(比如 docker 等)
                                      4. 路由器、本地局域网 192.168.*.* 的流量,是否正确直连了?(比如路由器、群晖等)
                                      5. 我的国内 DNS 查询(如 223.5.5.5)是否正确直连了?
                                      6. 我的国外 DNS 查询(如 1.1.1.1)是否正确代理了?
                                      7. 其他类似国内公共 DNS 一样没有域名、只有 IP 地址的国内网站,是否正确直连了?
                                      8. 其他类似国外公共 DNS 一样没有域名、只有 IP 地址的国外网站,是否正确代理了?
                                      9. BT 下载的流量,虽然来源是国外,但如果通过 VPS 下载很可能导致违规使用被封,这该如何强制直连?
                                      10. ......

                                      我之所以说只用【域名分流】会漏洞百出,是因为 geosite.dat 文件内只包含了一部分常用的域名。换言之,仅仅依赖它,则会:

                                      • 无法匹配文件里没有的新域名
                                      • 无法匹配基于 IP 地址的规则
                                      • 无法匹配基于网络协议的规则

                                      啰嗦君

                                      那我们来复习一下,当上面这些情况无法匹配时,会发生什么?对了,会触发隐藏路由规则,即【转发给第一个出站 】。这其实就是说:

                                      • 当你的第一个出站是 [direct-out] 时:需要直连的都正确了,但需要代理的则都错误
                                      • 当你的第一个出站是 [proxy-out-vless] 时:需要代理的都正确了,但需要直连的则都错误

                                      所以,我们需要一个办法,让我们鱼与熊掌兼得。这样的办法是否存在呢?当然存在! 我们需要的只是【域名】之外更多的【分流判断依据】而已。

                                      5.1 基于指定域名分流:[domain], [full]

                                      ',11),b=o("
                                    58. 如果需要匹配某个子域名,如 a-name.yourdomain.com,我们使用 full: "a-name.yourdomain.com"
                                    59. 前面的 问题1问题2,就可以通过给 proxy.yourdomain.com 指定 [proxy-out-vless] 出站,给 direct.yourdomain.com 指定 [direct-out] 出站来解决
                                    60. 如果需要匹配 yourdomain.com 的所有子域名,我们使用 domain: "yourdomain.com" 实现
                                    61. 上述两个可以成为两个独立的路由规则,达到某些子域名直连,其他子域名代理的配置
                                    62. ",4),g=s("code",null,"[domain]",-1),y=o(`

                                      上述配置如下:

                                      {
                                      +import{_ as l,r as p,o as u,c as d,a,b as s,d as n,w as e,e as o}from"./app-D7uBbsY3.js";const r={},k=s("h1",{id:"路由-routing-功能简析-下",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#路由-routing-功能简析-下"},[s("span",null,"路由 (routing) 功能简析(下)")])],-1),v=s("p",null,[n("欢迎继续学习 "),s("code",null,"Xray"),n(" 的【路由】功能!")],-1),m=s("code",null,"geosite.dat",-1),q=o('

                                      如前面所说,域名分流仅仅是【路由】功能的牛刀小试而已。下面就让我们来看看除了域名之外,还什么可以用做分流依据的东西吧!

                                      5. 攻城略池 - 多种路由匹配条件

                                      [域名], [IP], [协议], etc.

                                      基于域名的分流,已经可以让我们对网络流量进行基本合理的分流。为什么说【基本合理】呢?

                                      因为【三分天下】虽然是正确的战略方向,但如果只用【域名】来实现这个战略,其实漏洞百出,比如:

                                      1. 我读了《小小白白话文》后,给 VPS 新申请了一个 proxy.yourdomain.com 的域名, 我希望它无论如何都代理,geosite.dat 里面有吗?
                                      2. 如果我还有个 direct.yourdomain.com 的域名,我希望它无论如何都直连, geosite.dat 里面有吗?
                                      3. 本机 127.0.0.1 的内部流量,是否正确直连了?(比如 docker 等)
                                      4. 路由器、本地局域网 192.168.*.* 的流量,是否正确直连了?(比如路由器、群晖等)
                                      5. 我的国内 DNS 查询(如 223.5.5.5)是否正确直连了?
                                      6. 我的国外 DNS 查询(如 1.1.1.1)是否正确代理了?
                                      7. 其他类似国内公共 DNS 一样没有域名、只有 IP 地址的国内网站,是否正确直连了?
                                      8. 其他类似国外公共 DNS 一样没有域名、只有 IP 地址的国外网站,是否正确代理了?
                                      9. BT 下载的流量,虽然来源是国外,但如果通过 VPS 下载很可能导致违规使用被封,这该如何强制直连?
                                      10. ......

                                      我之所以说只用【域名分流】会漏洞百出,是因为 geosite.dat 文件内只包含了一部分常用的域名。换言之,仅仅依赖它,则会:

                                      • 无法匹配文件里没有的新域名
                                      • 无法匹配基于 IP 地址的规则
                                      • 无法匹配基于网络协议的规则

                                      啰嗦君

                                      那我们来复习一下,当上面这些情况无法匹配时,会发生什么?对了,会触发隐藏路由规则,即【转发给第一个出站 】。这其实就是说:

                                      • 当你的第一个出站是 [direct-out] 时:需要直连的都正确了,但需要代理的则都错误
                                      • 当你的第一个出站是 [proxy-out-vless] 时:需要代理的都正确了,但需要直连的则都错误

                                      所以,我们需要一个办法,让我们鱼与熊掌兼得。这样的办法是否存在呢?当然存在! 我们需要的只是【域名】之外更多的【分流判断依据】而已。

                                      5.1 基于指定域名分流:[domain], [full]

                                      ',11),b=o("
                                    63. 如果需要匹配某个子域名,如 a-name.yourdomain.com,我们使用 full: "a-name.yourdomain.com"
                                    64. 前面的 问题1问题2,就可以通过给 proxy.yourdomain.com 指定 [proxy-out-vless] 出站,给 direct.yourdomain.com 指定 [direct-out] 出站来解决
                                    65. 如果需要匹配 yourdomain.com 的所有子域名,我们使用 domain: "yourdomain.com" 实现
                                    66. 上述两个可以成为两个独立的路由规则,达到某些子域名直连,其他子域名代理的配置
                                    67. ",4),g=s("code",null,"[domain]",-1),y=o(`

                                      上述配置如下:

                                      {
                                         "routing": {
                                           "domainStrategy": "AsIs",
                                           "rules": [
                                      diff --git a/assets/routing-lv1-part2.html-iX-deabM.js b/assets/routing-lv1-part2.html-DfZ-Hwqj.js
                                      similarity index 99%
                                      rename from assets/routing-lv1-part2.html-iX-deabM.js
                                      rename to assets/routing-lv1-part2.html-DfZ-Hwqj.js
                                      index 2bcb02d1b6..cf79c74804 100644
                                      --- a/assets/routing-lv1-part2.html-iX-deabM.js
                                      +++ b/assets/routing-lv1-part2.html-DfZ-Hwqj.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as l,r as p,o as u,c as r,a,b as s,d as n,w as e,e as o}from"./app-DBM4OJyw.js";const d={},k=s("h1",{id:"краткии-обзор-функции-маршрутизации-routing-часть-2",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#краткии-обзор-функции-маршрутизации-routing-часть-2"},[s("span",null,"Краткий обзор функции маршрутизации (routing) (часть 2)")])],-1),v=s("p",null,[n("Добро пожаловать на продолжение изучения "),s("strong",null,"функции маршрутизации"),n(" в "),s("code",null,"Xray"),n("!")],-1),m=s("strong",null,"функции маршрутизации",-1),q=s("code",null,"geosite.dat",-1),D=o('

                                      Как уже было сказано, разделение по домену — это лишь верхушка айсберга возможностей функции маршрутизации. Давайте посмотрим, что еще, кроме домена, можно использовать в качестве критерия для разделения трафика!

                                      5. Покорение новых высот - Различные условия сопоставления маршрутов

                                      [домен], [IP], [протокол], etc.

                                      Разделение по домену уже позволяет нам в общих чертах разделить сетевой трафик. Почему в общих чертах?

                                      Потому что, хотя "разделение мира на три части" — это правильная стратегия, ее реализация только с помощью доменов имеет множество недостатков, например:

                                      1. После прочтения нашего руководства я зарегистрировал новый домен proxy.yourdomain.com для своего VPS и хочу, чтобы трафик на него всегда проксировался. Есть ли он в geosite.dat?
                                      2. У меня есть еще один домен direct.yourdomain.com, и я хочу, чтобы трафик на него всегда шел напрямую. Есть ли он в geosite.dat?
                                      3. Правильно ли настроен прямой доступ для локального трафика на 127.0.0.1 (например, docker)?
                                      4. Правильно ли настроен прямой доступ для трафика в моей локальной сети 192.168.*.* (например, роутер, NAS)?
                                      5. Правильно ли настроен прямой доступ для моих DNS-запросов к внутренним DNS-серверам (например, 223.5.5.5)?
                                      6. Правильно ли настроен прокси для моих DNS-запросов к внешним DNS-серверам (например, 1.1.1.1)?
                                      7. Правильно ли настроен прямой доступ для других внутренних сайтов, у которых нет доменного имени, а только IP-адрес, как у внутренних DNS-серверов?
                                      8. Правильно ли настроен прокси для других внешних сайтов, у которых нет доменного имени, а только IP-адрес, как у внешних DNS-серверов?
                                      9. Как настроить принудительное прямое подключение для торрент-трафика, который, хотя и поступает извне, может привести к блокировке VPS при проксировании?
                                      10. ......

                                      Я говорю, что разделение по домену имеет много недостатков, потому что файл geosite.dat содержит только ограниченный набор часто используемых доменов. Другими словами, полагаясь только на него, мы:

                                      • не сможем сопоставить новые домены, которых нет в файле;
                                      • не сможем сопоставить правила на основе IP-адресов;
                                      • не сможем сопоставить правила на основе сетевых протоколов.

                                      Внимание

                                      Давайте вспомним, что происходит, когда эти условия не выполняются? Верно, срабатывает скрытое правило маршрутизации: трафик перенаправляется на первый исходящий трафик. Это означает, что:

                                      • если вашим первым исходящим трафиком является [direct-out]: все, что должно идти напрямую, будет работать правильно, а все, что должно проксироваться, будет работать неправильно;
                                      • если вашим первым исходящим трафиком является [proxy-out-vless]: все, что должно проксироваться, будет работать правильно, а все, что должно идти напрямую, будет работать неправильно.

                                      Поэтому нам нужен способ, который позволит нам получить и то, и другое. Существует ли такой способ? Конечно, существует! Нам просто нужны дополнительные критерии сопоставления помимо домена.

                                      5.1 Разделение по определенному домену: [domain], [full] и т. д.

                                      ',11),g=o("
                                    68. Для сопоставления поддомена, например a-name.yourdomain.com, мы используем full: "a-name.yourdomain.com".
                                    69. Проблемы 1 и 2, описанные выше, можно решить, указав исходящий трафик [proxy-out-vless] для proxy.yourdomain.com и исходящий трафик [direct-out] для direct.yourdomain.com.
                                    70. Для сопоставления всех поддоменов yourdomain.com мы используем domain: "yourdomain.com".
                                    71. Эти два правила могут быть независимыми, чтобы настроить прямое подключение для одних поддоменов и проксирование для других.
                                    72. ",4),b=s("code",null,"[domain]",-1),y=o(`

                                      Конфигурация выглядит следующим образом:

                                      {
                                      +import{_ as l,r as p,o as u,c as r,a,b as s,d as n,w as e,e as o}from"./app-D7uBbsY3.js";const d={},k=s("h1",{id:"краткии-обзор-функции-маршрутизации-routing-часть-2",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#краткии-обзор-функции-маршрутизации-routing-часть-2"},[s("span",null,"Краткий обзор функции маршрутизации (routing) (часть 2)")])],-1),v=s("p",null,[n("Добро пожаловать на продолжение изучения "),s("strong",null,"функции маршрутизации"),n(" в "),s("code",null,"Xray"),n("!")],-1),m=s("strong",null,"функции маршрутизации",-1),q=s("code",null,"geosite.dat",-1),D=o('

                                      Как уже было сказано, разделение по домену — это лишь верхушка айсберга возможностей функции маршрутизации. Давайте посмотрим, что еще, кроме домена, можно использовать в качестве критерия для разделения трафика!

                                      5. Покорение новых высот - Различные условия сопоставления маршрутов

                                      [домен], [IP], [протокол], etc.

                                      Разделение по домену уже позволяет нам в общих чертах разделить сетевой трафик. Почему в общих чертах?

                                      Потому что, хотя "разделение мира на три части" — это правильная стратегия, ее реализация только с помощью доменов имеет множество недостатков, например:

                                      1. После прочтения нашего руководства я зарегистрировал новый домен proxy.yourdomain.com для своего VPS и хочу, чтобы трафик на него всегда проксировался. Есть ли он в geosite.dat?
                                      2. У меня есть еще один домен direct.yourdomain.com, и я хочу, чтобы трафик на него всегда шел напрямую. Есть ли он в geosite.dat?
                                      3. Правильно ли настроен прямой доступ для локального трафика на 127.0.0.1 (например, docker)?
                                      4. Правильно ли настроен прямой доступ для трафика в моей локальной сети 192.168.*.* (например, роутер, NAS)?
                                      5. Правильно ли настроен прямой доступ для моих DNS-запросов к внутренним DNS-серверам (например, 223.5.5.5)?
                                      6. Правильно ли настроен прокси для моих DNS-запросов к внешним DNS-серверам (например, 1.1.1.1)?
                                      7. Правильно ли настроен прямой доступ для других внутренних сайтов, у которых нет доменного имени, а только IP-адрес, как у внутренних DNS-серверов?
                                      8. Правильно ли настроен прокси для других внешних сайтов, у которых нет доменного имени, а только IP-адрес, как у внешних DNS-серверов?
                                      9. Как настроить принудительное прямое подключение для торрент-трафика, который, хотя и поступает извне, может привести к блокировке VPS при проксировании?
                                      10. ......

                                      Я говорю, что разделение по домену имеет много недостатков, потому что файл geosite.dat содержит только ограниченный набор часто используемых доменов. Другими словами, полагаясь только на него, мы:

                                      • не сможем сопоставить новые домены, которых нет в файле;
                                      • не сможем сопоставить правила на основе IP-адресов;
                                      • не сможем сопоставить правила на основе сетевых протоколов.

                                      Внимание

                                      Давайте вспомним, что происходит, когда эти условия не выполняются? Верно, срабатывает скрытое правило маршрутизации: трафик перенаправляется на первый исходящий трафик. Это означает, что:

                                      • если вашим первым исходящим трафиком является [direct-out]: все, что должно идти напрямую, будет работать правильно, а все, что должно проксироваться, будет работать неправильно;
                                      • если вашим первым исходящим трафиком является [proxy-out-vless]: все, что должно проксироваться, будет работать правильно, а все, что должно идти напрямую, будет работать неправильно.

                                      Поэтому нам нужен способ, который позволит нам получить и то, и другое. Существует ли такой способ? Конечно, существует! Нам просто нужны дополнительные критерии сопоставления помимо домена.

                                      5.1 Разделение по определенному домену: [domain], [full] и т. д.

                                      ',11),g=o("
                                    73. Для сопоставления поддомена, например a-name.yourdomain.com, мы используем full: "a-name.yourdomain.com".
                                    74. Проблемы 1 и 2, описанные выше, можно решить, указав исходящий трафик [proxy-out-vless] для proxy.yourdomain.com и исходящий трафик [direct-out] для direct.yourdomain.com.
                                    75. Для сопоставления всех поддоменов yourdomain.com мы используем domain: "yourdomain.com".
                                    76. Эти два правила могут быть независимыми, чтобы настроить прямое подключение для одних поддоменов и проксирование для других.
                                    77. ",4),b=s("code",null,"[domain]",-1),y=o(`

                                      Конфигурация выглядит следующим образом:

                                      {
                                         "routing": {
                                           "domainStrategy": "AsIs",
                                           "rules": [
                                      diff --git a/assets/routing-lv1-part2.html-D9GASUUF.js b/assets/routing-lv1-part2.html-DlBr3dUB.js
                                      similarity index 99%
                                      rename from assets/routing-lv1-part2.html-D9GASUUF.js
                                      rename to assets/routing-lv1-part2.html-DlBr3dUB.js
                                      index e523126086..b50388a9a8 100644
                                      --- a/assets/routing-lv1-part2.html-D9GASUUF.js
                                      +++ b/assets/routing-lv1-part2.html-DlBr3dUB.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as l,r as p,o as u,c as d,a,b as s,d as n,w as e,e as o}from"./app-DBM4OJyw.js";const r={},k=s("h1",{id:"路由-routing-功能简析-下",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#路由-routing-功能简析-下"},[s("span",null,"路由 (routing) 功能简析(下)")])],-1),v=s("p",null,[n("欢迎继续学习 "),s("code",null,"Xray"),n(" 的【路由】功能!")],-1),m=s("code",null,"geosite.dat",-1),q=o('

                                      如前面所说,域名分流仅仅是【路由】功能的牛刀小试而已。下面就让我们来看看除了域名之外,还什么可以用做分流依据的东西吧!

                                      5. 攻城略池 - 多种路由匹配条件

                                      [域名], [IP], [协议], etc.

                                      基于域名的分流,已经可以让我们对网络流量进行基本合理的分流。为什么说【基本合理】呢?

                                      因为【三分天下】虽然是正确的战略方向,但如果只用【域名】来实现这个战略,其实漏洞百出,比如:

                                      1. 我读了《小小白白话文》后,给 VPS 新申请了一个 proxy.yourdomain.com 的域名, 我希望它无论如何都代理,geosite.dat 里面有吗?
                                      2. 如果我还有个 direct.yourdomain.com 的域名,我希望它无论如何都直连, geosite.dat 里面有吗?
                                      3. 本机 127.0.0.1 的内部流量,是否正确直连了?(比如 docker 等)
                                      4. 路由器、本地局域网 192.168.*.* 的流量,是否正确直连了?(比如路由器、群晖等)
                                      5. 我的国内 DNS 查询(如 223.5.5.5)是否正确直连了?
                                      6. 我的国外 DNS 查询(如 1.1.1.1)是否正确代理了?
                                      7. 其他类似国内公共 DNS 一样没有域名、只有 IP 地址的国内网站,是否正确直连了?
                                      8. 其他类似国外公共 DNS 一样没有域名、只有 IP 地址的国外网站,是否正确代理了?
                                      9. BT 下载的流量,虽然来源是国外,但如果通过 VPS 下载很可能导致违规使用被封,这该如何强制直连?
                                      10. ......

                                      我之所以说只用【域名分流】会漏洞百出,是因为 geosite.dat 文件内只包含了一部分常用的域名。换言之,仅仅依赖它,则会:

                                      • 无法匹配文件里没有的新域名
                                      • 无法匹配基于 IP 地址的规则
                                      • 无法匹配基于网络协议的规则

                                      啰嗦君

                                      那我们来复习一下,当上面这些情况无法匹配时,会发生什么?对了,会触发隐藏路由规则,即【转发给第一个出站 】。这其实就是说:

                                      • 当你的第一个出站是 [direct-out] 时:需要直连的都正确了,但需要代理的则都错误
                                      • 当你的第一个出站是 [proxy-out-vless] 时:需要代理的都正确了,但需要直连的则都错误

                                      所以,我们需要一个办法,让我们鱼与熊掌兼得。这样的办法是否存在呢?当然存在! 我们需要的只是【域名】之外更多的【分流判断依据】而已。

                                      5.1 基于指定域名分流:[domain], [full]

                                      ',11),b=o("
                                    78. 如果需要匹配某个子域名,如 a-name.yourdomain.com,我们使用 full: "a-name.yourdomain.com"
                                    79. 前面的 问题1问题2,就可以通过给 proxy.yourdomain.com 指定 [proxy-out-vless] 出站,给 direct.yourdomain.com 指定 [direct-out] 出站来解决
                                    80. 如果需要匹配 yourdomain.com 的所有子域名,我们使用 domain: "yourdomain.com" 实现
                                    81. 上述两个可以成为两个独立的路由规则,达到某些子域名直连,其他子域名代理的配置
                                    82. ",4),g=s("code",null,"[domain]",-1),y=o(`

                                      上述配置如下:

                                      {
                                      +import{_ as l,r as p,o as u,c as d,a,b as s,d as n,w as e,e as o}from"./app-D7uBbsY3.js";const r={},k=s("h1",{id:"路由-routing-功能简析-下",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#路由-routing-功能简析-下"},[s("span",null,"路由 (routing) 功能简析(下)")])],-1),v=s("p",null,[n("欢迎继续学习 "),s("code",null,"Xray"),n(" 的【路由】功能!")],-1),m=s("code",null,"geosite.dat",-1),q=o('

                                      如前面所说,域名分流仅仅是【路由】功能的牛刀小试而已。下面就让我们来看看除了域名之外,还什么可以用做分流依据的东西吧!

                                      5. 攻城略池 - 多种路由匹配条件

                                      [域名], [IP], [协议], etc.

                                      基于域名的分流,已经可以让我们对网络流量进行基本合理的分流。为什么说【基本合理】呢?

                                      因为【三分天下】虽然是正确的战略方向,但如果只用【域名】来实现这个战略,其实漏洞百出,比如:

                                      1. 我读了《小小白白话文》后,给 VPS 新申请了一个 proxy.yourdomain.com 的域名, 我希望它无论如何都代理,geosite.dat 里面有吗?
                                      2. 如果我还有个 direct.yourdomain.com 的域名,我希望它无论如何都直连, geosite.dat 里面有吗?
                                      3. 本机 127.0.0.1 的内部流量,是否正确直连了?(比如 docker 等)
                                      4. 路由器、本地局域网 192.168.*.* 的流量,是否正确直连了?(比如路由器、群晖等)
                                      5. 我的国内 DNS 查询(如 223.5.5.5)是否正确直连了?
                                      6. 我的国外 DNS 查询(如 1.1.1.1)是否正确代理了?
                                      7. 其他类似国内公共 DNS 一样没有域名、只有 IP 地址的国内网站,是否正确直连了?
                                      8. 其他类似国外公共 DNS 一样没有域名、只有 IP 地址的国外网站,是否正确代理了?
                                      9. BT 下载的流量,虽然来源是国外,但如果通过 VPS 下载很可能导致违规使用被封,这该如何强制直连?
                                      10. ......

                                      我之所以说只用【域名分流】会漏洞百出,是因为 geosite.dat 文件内只包含了一部分常用的域名。换言之,仅仅依赖它,则会:

                                      • 无法匹配文件里没有的新域名
                                      • 无法匹配基于 IP 地址的规则
                                      • 无法匹配基于网络协议的规则

                                      啰嗦君

                                      那我们来复习一下,当上面这些情况无法匹配时,会发生什么?对了,会触发隐藏路由规则,即【转发给第一个出站 】。这其实就是说:

                                      • 当你的第一个出站是 [direct-out] 时:需要直连的都正确了,但需要代理的则都错误
                                      • 当你的第一个出站是 [proxy-out-vless] 时:需要代理的都正确了,但需要直连的则都错误

                                      所以,我们需要一个办法,让我们鱼与熊掌兼得。这样的办法是否存在呢?当然存在! 我们需要的只是【域名】之外更多的【分流判断依据】而已。

                                      5.1 基于指定域名分流:[domain], [full]

                                      ',11),b=o("
                                    83. 如果需要匹配某个子域名,如 a-name.yourdomain.com,我们使用 full: "a-name.yourdomain.com"
                                    84. 前面的 问题1问题2,就可以通过给 proxy.yourdomain.com 指定 [proxy-out-vless] 出站,给 direct.yourdomain.com 指定 [direct-out] 出站来解决
                                    85. 如果需要匹配 yourdomain.com 的所有子域名,我们使用 domain: "yourdomain.com" 实现
                                    86. 上述两个可以成为两个独立的路由规则,达到某些子域名直连,其他子域名代理的配置
                                    87. ",4),g=s("code",null,"[domain]",-1),y=o(`

                                      上述配置如下:

                                      {
                                         "routing": {
                                           "domainStrategy": "AsIs",
                                           "rules": [
                                      diff --git a/assets/routing.html-xbGVqnxN.js b/assets/routing.html-BzSZN0AZ.js
                                      similarity index 99%
                                      rename from assets/routing.html-xbGVqnxN.js
                                      rename to assets/routing.html-BzSZN0AZ.js
                                      index 7f9c290ad8..af933acd52 100644
                                      --- a/assets/routing.html-xbGVqnxN.js
                                      +++ b/assets/routing.html-BzSZN0AZ.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as r,r as s,o as u,c as p,a as t,b as e,d as o,w as i,e as n}from"./app-DBM4OJyw.js";const d={},h=e("h1",{id:"routing",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#routing"},[e("span",null,"Routing")])],-1),m=e("p",null,"The routing module can send inbound data through different outbound connections according to different rules to achieve on-demand proxying.",-1),q=e("p",null,"A common use case is to split domestic and foreign traffic. Xray can use its internal mechanisms to determine the traffic from different regions and then send them to different outbound proxies.",-1),f=n(`

                                      RoutingObject

                                      RoutingObject corresponds to the routing item in the configuration file.

                                      {
                                      +import{_ as r,r as s,o as u,c as p,a as t,b as e,d as o,w as i,e as n}from"./app-D7uBbsY3.js";const d={},h=e("h1",{id:"routing",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#routing"},[e("span",null,"Routing")])],-1),m=e("p",null,"The routing module can send inbound data through different outbound connections according to different rules to achieve on-demand proxying.",-1),q=e("p",null,"A common use case is to split domestic and foreign traffic. Xray can use its internal mechanisms to determine the traffic from different regions and then send them to different outbound proxies.",-1),f=n(`

                                      RoutingObject

                                      RoutingObject corresponds to the routing item in the configuration file.

                                      {
                                         "routing": {
                                           "domainStrategy": "AsIs",
                                           "domainMatcher": "hybrid",
                                      diff --git a/assets/routing.html-DwJ4ma_9.js b/assets/routing.html-CPw6r5Sh.js
                                      similarity index 99%
                                      rename from assets/routing.html-DwJ4ma_9.js
                                      rename to assets/routing.html-CPw6r5Sh.js
                                      index 510b1a7f98..f60a21ea01 100644
                                      --- a/assets/routing.html-DwJ4ma_9.js
                                      +++ b/assets/routing.html-CPw6r5Sh.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as l,r as c,o as i,c as d,a as s,b as n,d as o,w as a,e}from"./app-DBM4OJyw.js";const r={},q=n("h1",{id:"路由",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#路由"},[n("span",null,"路由")])],-1),k=n("p",null,"路由功能模块可以将入站数据按不同规则由不同的出站连接发出,以达到按需代理的目的。",-1),b=n("p",null,"如常见用法是分流国内外流量,Xray 可以通过内部机制判断不同地区的流量,然后将它们发送到不同的出站代理。",-1),v=e(`

                                      RoutingObject

                                      RoutingObject 对应配置文件的 routing 项。

                                      {
                                      +import{_ as l,r as c,o as i,c as d,a as s,b as n,d as o,w as a,e}from"./app-D7uBbsY3.js";const r={},q=n("h1",{id:"路由",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#路由"},[n("span",null,"路由")])],-1),k=n("p",null,"路由功能模块可以将入站数据按不同规则由不同的出站连接发出,以达到按需代理的目的。",-1),b=n("p",null,"如常见用法是分流国内外流量,Xray 可以通过内部机制判断不同地区的流量,然后将它们发送到不同的出站代理。",-1),v=e(`

                                      RoutingObject

                                      RoutingObject 对应配置文件的 routing 项。

                                      {
                                         "routing": {
                                           "domainStrategy": "AsIs",
                                           "domainMatcher": "hybrid",
                                      diff --git a/assets/routing.html-JmIqwiJt.js b/assets/routing.html-DxkdJQtA.js
                                      similarity index 99%
                                      rename from assets/routing.html-JmIqwiJt.js
                                      rename to assets/routing.html-DxkdJQtA.js
                                      index 1376c87ad6..6f72276704 100644
                                      --- a/assets/routing.html-JmIqwiJt.js
                                      +++ b/assets/routing.html-DxkdJQtA.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as l,r as c,o as i,c as r,a as s,b as o,d as n,w as e,e as t}from"./app-DBM4OJyw.js";const d={},q=o("h1",{id:"маршрутизация",tabindex:"-1"},[o("a",{class:"header-anchor",href:"#маршрутизация"},[o("span",null,"Маршрутизация")])],-1),b=o("p",null,"Модуль маршрутизации позволяет направлять входящие данные через разные исходящие подключения в соответствии с различными правилами, что позволяет реализовать проксирование по требованию.",-1),k=o("p",null,[n("Например, распространенным сценарием использования является разделение трафика на внутренний и внешний."),o("br"),n(" Xray может определять трафик из разных регионов с помощью внутренних механизмов и отправлять его через разные исходящие подключения.")],-1),v=t(`

                                      RoutingObject

                                      RoutingObject соответствует полю routing в конфигурационном файле.

                                      {
                                      +import{_ as l,r as c,o as i,c as r,a as s,b as o,d as n,w as e,e as t}from"./app-D7uBbsY3.js";const d={},q=o("h1",{id:"маршрутизация",tabindex:"-1"},[o("a",{class:"header-anchor",href:"#маршрутизация"},[o("span",null,"Маршрутизация")])],-1),b=o("p",null,"Модуль маршрутизации позволяет направлять входящие данные через разные исходящие подключения в соответствии с различными правилами, что позволяет реализовать проксирование по требованию.",-1),k=o("p",null,[n("Например, распространенным сценарием использования является разделение трафика на внутренний и внешний."),o("br"),n(" Xray может определять трафик из разных регионов с помощью внутренних механизмов и отправлять его через разные исходящие подключения.")],-1),v=t(`

                                      RoutingObject

                                      RoutingObject соответствует полю routing в конфигурационном файле.

                                      {
                                         "routing": {
                                           "domainStrategy": "AsIs",
                                           "domainMatcher": "hybrid",
                                      diff --git a/assets/sankeyDiagram-XVFEVEVI-B44r2-sr.js b/assets/sankeyDiagram-XVFEVEVI-BznKSljg.js
                                      similarity index 99%
                                      rename from assets/sankeyDiagram-XVFEVEVI-B44r2-sr.js
                                      rename to assets/sankeyDiagram-XVFEVEVI-BznKSljg.js
                                      index aa92cda18d..571fc4c997 100644
                                      --- a/assets/sankeyDiagram-XVFEVEVI-B44r2-sr.js
                                      +++ b/assets/sankeyDiagram-XVFEVEVI-BznKSljg.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as m,d as lt,g as _t,s as xt,b as vt,c as bt,r as wt,q as St,t as Lt,e as Et,p as At,j as H,aa as Tt}from"./mermaid.core-DapiNGBY.js";import{o as Mt}from"./ordinal-Cboi1Yqb.js";import"./app-DBM4OJyw.js";import"./init-Gi6I4Gst.js";function Nt(t){for(var e=t.length/6|0,i=new Array(e),a=0;a=a)&&(i=a);else{let a=-1;for(let h of t)(h=e(h,++a,t))!=null&&(i=h)&&(i=h)}return i}function pt(t,e){let i;if(e===void 0)for(const a of t)a!=null&&(i>a||i===void 0&&a>=a)&&(i=a);else{let a=-1;for(let h of t)(h=e(h,++a,t))!=null&&(i>h||i===void 0&&h>=h)&&(i=h)}return i}function nt(t,e){let i=0;if(e===void 0)for(let a of t)(a=+a)&&(i+=a);else{let a=-1;for(let h of t)(h=+e(h,++a,t))&&(i+=h)}return i}function Pt(t){return t.target.depth}function Ct(t){return t.depth}function Ot(t,e){return e-1-t.height}function mt(t,e){return t.sourceLinks.length?t.depth:e-1}function Dt(t){return t.targetLinks.length?t.depth:t.sourceLinks.length?pt(t.sourceLinks,Pt)-1:0}function X(t){return function(){return t}}function ut(t,e){return Q(t.source,e.source)||t.index-e.index}function ht(t,e){return Q(t.target,e.target)||t.index-e.index}function Q(t,e){return t.y0-e.y0}function it(t){return t.value}function jt(t){return t.index}function zt(t){return t.nodes}function $t(t){return t.links}function ft(t,e){const i=t.get(e);if(!i)throw new Error("missing: "+e);return i}function yt({nodes:t}){for(const e of t){let i=e.y0,a=i;for(const h of e.sourceLinks)h.y0=i+h.width/2,i+=h.width;for(const h of e.targetLinks)h.y1=a+h.width/2,a+=h.width}}function Bt(){let t=0,e=0,i=1,a=1,h=24,d=8,p,_=jt,s=mt,o,l,x=zt,v=$t,y=6;function b(){const n={nodes:x.apply(null,arguments),links:v.apply(null,arguments)};return M(n),T(n),N(n),C(n),S(n),yt(n),n}b.update=function(n){return yt(n),n},b.nodeId=function(n){return arguments.length?(_=typeof n=="function"?n:X(n),b):_},b.nodeAlign=function(n){return arguments.length?(s=typeof n=="function"?n:X(n),b):s},b.nodeSort=function(n){return arguments.length?(o=n,b):o},b.nodeWidth=function(n){return arguments.length?(h=+n,b):h},b.nodePadding=function(n){return arguments.length?(d=p=+n,b):d},b.nodes=function(n){return arguments.length?(x=typeof n=="function"?n:X(n),b):x},b.links=function(n){return arguments.length?(v=typeof n=="function"?n:X(n),b):v},b.linkSort=function(n){return arguments.length?(l=n,b):l},b.size=function(n){return arguments.length?(t=e=0,i=+n[0],a=+n[1],b):[i-t,a-e]},b.extent=function(n){return arguments.length?(t=+n[0][0],i=+n[1][0],e=+n[0][1],a=+n[1][1],b):[[t,e],[i,a]]},b.iterations=function(n){return arguments.length?(y=+n,b):y};function M({nodes:n,links:f}){for(const[c,r]of n.entries())r.index=c,r.sourceLinks=[],r.targetLinks=[];const u=new Map(n.map((c,r)=>[_(c,r,n),c]));for(const[c,r]of f.entries()){r.index=c;let{source:k,target:w}=r;typeof k!="object"&&(k=r.source=ft(u,k)),typeof w!="object"&&(w=r.target=ft(u,w)),k.sourceLinks.push(r),w.targetLinks.push(r)}if(l!=null)for(const{sourceLinks:c,targetLinks:r}of n)c.sort(l),r.sort(l)}function T({nodes:n}){for(const f of n)f.value=f.fixedValue===void 0?Math.max(nt(f.sourceLinks,it),nt(f.targetLinks,it)):f.fixedValue}function N({nodes:n}){const f=n.length;let u=new Set(n),c=new Set,r=0;for(;u.size;){for(const k of u){k.depth=r;for(const{target:w}of k.sourceLinks)c.add(w)}if(++r>f)throw new Error("circular link");u=c,c=new Set}}function C({nodes:n}){const f=n.length;let u=new Set(n),c=new Set,r=0;for(;u.size;){for(const k of u){k.height=r;for(const{source:w}of k.targetLinks)c.add(w)}if(++r>f)throw new Error("circular link");u=c,c=new Set}}function j({nodes:n}){const f=ct(n,r=>r.depth)+1,u=(i-t-h)/(f-1),c=new Array(f);for(const r of n){const k=Math.max(0,Math.min(f-1,Math.floor(s.call(null,r,f))));r.layer=k,r.x0=t+k*u,r.x1=r.x0+h,c[k]?c[k].push(r):c[k]=[r]}if(o)for(const r of c)r.sort(o);return c}function R(n){const f=pt(n,u=>(a-e-(u.length-1)*p)/nt(u,it));for(const u of n){let c=e;for(const r of u){r.y0=c,r.y1=c+r.value*f,c=r.y1+p;for(const k of r.sourceLinks)k.width=k.value*f}c=(a-c+p)/(u.length+1);for(let r=0;ru.length)-1)),R(f);for(let u=0;u0))continue;let W=(L/V-w.y0)*f;w.y0+=W,w.y1+=W,E(w)}o===void 0&&k.sort(Q),O(k,u)}}function $(n,f,u){for(let c=n.length,r=c-2;r>=0;--r){const k=n[r];for(const w of k){let L=0,V=0;for(const{target:U,value:et}of w.sourceLinks){let G=et*(U.layer-w.layer);L+=I(w,U)*G,V+=G}if(!(V>0))continue;let W=(L/V-w.y0)*f;w.y0+=W,w.y1+=W,E(w)}o===void 0&&k.sort(Q),O(k,u)}}function O(n,f){const u=n.length>>1,c=n[u];g(n,c.y0-p,u-1,f),D(n,c.y1+p,u+1,f),g(n,a,n.length-1,f),D(n,e,0,f)}function D(n,f,u,c){for(;u1e-6&&(r.y0+=k,r.y1+=k),f=r.y1+p}}function g(n,f,u,c){for(;u>=0;--u){const r=n[u],k=(r.y1-f)*c;k>1e-6&&(r.y0-=k,r.y1-=k),f=r.y0-p}}function E({sourceLinks:n,targetLinks:f}){if(l===void 0){for(const{source:{sourceLinks:u}}of f)u.sort(ht);for(const{target:{targetLinks:u}}of n)u.sort(ut)}}function A(n){if(l===void 0)for(const{sourceLinks:f,targetLinks:u}of n)f.sort(ht),u.sort(ut)}function z(n,f){let u=n.y0-(n.sourceLinks.length-1)*p/2;for(const{target:c,width:r}of n.sourceLinks){if(c===f)break;u+=r+p}for(const{source:c,width:r}of f.targetLinks){if(c===n)break;u-=r}return u}function I(n,f){let u=f.y0-(f.targetLinks.length-1)*p/2;for(const{source:c,width:r}of f.targetLinks){if(c===n)break;u+=r+p}for(const{target:c,width:r}of n.sourceLinks){if(c===f)break;u-=r}return u}return b}var st=Math.PI,rt=2*st,F=1e-6,Rt=rt-F;function ot(){this._x0=this._y0=this._x1=this._y1=null,this._=""}function kt(){return new ot}ot.prototype=kt.prototype={constructor:ot,moveTo:function(t,e){this._+="M"+(this._x0=this._x1=+t)+","+(this._y0=this._y1=+e)},closePath:function(){this._x1!==null&&(this._x1=this._x0,this._y1=this._y0,this._+="Z")},lineTo:function(t,e){this._+="L"+(this._x1=+t)+","+(this._y1=+e)},quadraticCurveTo:function(t,e,i,a){this._+="Q"+ +t+","+ +e+","+(this._x1=+i)+","+(this._y1=+a)},bezierCurveTo:function(t,e,i,a,h,d){this._+="C"+ +t+","+ +e+","+ +i+","+ +a+","+(this._x1=+h)+","+(this._y1=+d)},arcTo:function(t,e,i,a,h){t=+t,e=+e,i=+i,a=+a,h=+h;var d=this._x1,p=this._y1,_=i-t,s=a-e,o=d-t,l=p-e,x=o*o+l*l;if(h<0)throw new Error("negative radius: "+h);if(this._x1===null)this._+="M"+(this._x1=t)+","+(this._y1=e);else if(x>F)if(!(Math.abs(l*_-s*o)>F)||!h)this._+="L"+(this._x1=t)+","+(this._y1=e);else{var v=i-d,y=a-p,b=_*_+s*s,M=v*v+y*y,T=Math.sqrt(b),N=Math.sqrt(x),C=h*Math.tan((st-Math.acos((b+x-M)/(2*T*N)))/2),j=C/N,R=C/T;Math.abs(j-1)>F&&(this._+="L"+(t+j*o)+","+(e+j*l)),this._+="A"+h+","+h+",0,0,"+ +(l*v>o*y)+","+(this._x1=t+R*_)+","+(this._y1=e+R*s)}},arc:function(t,e,i,a,h,d){t=+t,e=+e,i=+i,d=!!d;var p=i*Math.cos(a),_=i*Math.sin(a),s=t+p,o=e+_,l=1^d,x=d?a-h:h-a;if(i<0)throw new Error("negative radius: "+i);this._x1===null?this._+="M"+s+","+o:(Math.abs(this._x1-s)>F||Math.abs(this._y1-o)>F)&&(this._+="L"+s+","+o),i&&(x<0&&(x=x%rt+rt),x>Rt?this._+="A"+i+","+i+",0,1,"+l+","+(t-p)+","+(e-_)+"A"+i+","+i+",0,1,"+l+","+(this._x1=s)+","+(this._y1=o):x>F&&(this._+="A"+i+","+i+",0,"+ +(x>=st)+","+l+","+(this._x1=t+i*Math.cos(h))+","+(this._y1=e+i*Math.sin(h))))},rect:function(t,e,i,a){this._+="M"+(this._x0=this._x1=+t)+","+(this._y0=this._y1=+e)+"h"+ +i+"v"+ +a+"h"+-i+"Z"},toString:function(){return this._}};function dt(t){return function(){return t}}function Vt(t){return t[0]}function Ft(t){return t[1]}var Wt=Array.prototype.slice;function Ut(t){return t.source}function Gt(t){return t.target}function Yt(t){var e=Ut,i=Gt,a=Vt,h=Ft,d=null;function p(){var _,s=Wt.call(arguments),o=e.apply(this,s),l=i.apply(this,s);if(d||(d=_=kt()),t(d,+a.apply(this,(s[0]=o,s)),+h.apply(this,s),+a.apply(this,(s[0]=l,s)),+h.apply(this,s)),_)return d=null,_+""||null}return p.source=function(_){return arguments.length?(e=_,p):e},p.target=function(_){return arguments.length?(i=_,p):i},p.x=function(_){return arguments.length?(a=typeof _=="function"?_:dt(+_),p):a},p.y=function(_){return arguments.length?(h=typeof _=="function"?_:dt(+_),p):h},p.context=function(_){return arguments.length?(d=_??null,p):d},p}function qt(t,e,i,a,h){t.moveTo(e,i),t.bezierCurveTo(e=(e+a)/2,i,e,h,a,h)}function Ht(){return Yt(qt)}function Xt(t){return[t.source.x1,t.y0]}function Qt(t){return[t.target.x0,t.y1]}function Kt(){return Ht().source(Xt).target(Qt)}var at=function(){var t=m(function(_,s,o,l){for(o=o||{},l=_.length;l--;o[_[l]]=s);return o},"o"),e=[1,9],i=[1,10],a=[1,5,10,12],h={trace:m(function(){},"trace"),yy:{},symbols_:{error:2,start:3,SANKEY:4,NEWLINE:5,csv:6,opt_eof:7,record:8,csv_tail:9,EOF:10,"field[source]":11,COMMA:12,"field[target]":13,"field[value]":14,field:15,escaped:16,non_escaped:17,DQUOTE:18,ESCAPED_TEXT:19,NON_ESCAPED_TEXT:20,$accept:0,$end:1},terminals_:{2:"error",4:"SANKEY",5:"NEWLINE",10:"EOF",11:"field[source]",12:"COMMA",13:"field[target]",14:"field[value]",18:"DQUOTE",19:"ESCAPED_TEXT",20:"NON_ESCAPED_TEXT"},productions_:[0,[3,4],[6,2],[9,2],[9,0],[7,1],[7,0],[8,5],[15,1],[15,1],[16,3],[17,1]],performAction:m(function(s,o,l,x,v,y,b){var M=y.length-1;switch(v){case 7:const T=x.findOrCreateNode(y[M-4].trim().replaceAll('""','"')),N=x.findOrCreateNode(y[M-2].trim().replaceAll('""','"')),C=parseFloat(y[M].trim());x.addLink(T,N,C);break;case 8:case 9:case 11:this.$=y[M];break;case 10:this.$=y[M-1];break}},"anonymous"),table:[{3:1,4:[1,2]},{1:[3]},{5:[1,3]},{6:4,8:5,15:6,16:7,17:8,18:e,20:i},{1:[2,6],7:11,10:[1,12]},t(i,[2,4],{9:13,5:[1,14]}),{12:[1,15]},t(a,[2,8]),t(a,[2,9]),{19:[1,16]},t(a,[2,11]),{1:[2,1]},{1:[2,5]},t(i,[2,2]),{6:17,8:5,15:6,16:7,17:8,18:e,20:i},{15:18,16:7,17:8,18:e,20:i},{18:[1,19]},t(i,[2,3]),{12:[1,20]},t(a,[2,10]),{15:21,16:7,17:8,18:e,20:i},t([1,5,10],[2,7])],defaultActions:{11:[2,1],12:[2,5]},parseError:m(function(s,o){if(o.recoverable)this.trace(s);else{var l=new Error(s);throw l.hash=o,l}},"parseError"),parse:m(function(s){var o=this,l=[0],x=[],v=[null],y=[],b=this.table,M="",T=0,N=0,C=2,j=1,R=y.slice.call(arguments,1),S=Object.create(this.lexer),P={yy:{}};for(var $ in this.yy)Object.prototype.hasOwnProperty.call(this.yy,$)&&(P.yy[$]=this.yy[$]);S.setInput(s,P.yy),P.yy.lexer=S,P.yy.parser=this,typeof S.yylloc>"u"&&(S.yylloc={});var O=S.yylloc;y.push(O);var D=S.options&&S.options.ranges;typeof P.yy.parseError=="function"?this.parseError=P.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function g(L){l.length=l.length-2*L,v.length=v.length-L,y.length=y.length-L}m(g,"popStack");function E(){var L;return L=x.pop()||S.lex()||j,typeof L!="number"&&(L instanceof Array&&(x=L,L=x.pop()),L=o.symbols_[L]||L),L}m(E,"lex");for(var A,z,I,n,f={},u,c,r,k;;){if(z=l[l.length-1],this.defaultActions[z]?I=this.defaultActions[z]:((A===null||typeof A>"u")&&(A=E()),I=b[z]&&b[z][A]),typeof I>"u"||!I.length||!I[0]){var w="";k=[];for(u in b[z])this.terminals_[u]&&u>C&&k.push("'"+this.terminals_[u]+"'");S.showPosition?w="Parse error on line "+(T+1)+`:
                                      +import{_ as m,d as lt,g as _t,s as xt,b as vt,c as bt,r as wt,q as St,t as Lt,e as Et,p as At,j as H,aa as Tt}from"./mermaid.core-D8igZDel.js";import{o as Mt}from"./ordinal-Cboi1Yqb.js";import"./app-D7uBbsY3.js";import"./init-Gi6I4Gst.js";function Nt(t){for(var e=t.length/6|0,i=new Array(e),a=0;a=a)&&(i=a);else{let a=-1;for(let h of t)(h=e(h,++a,t))!=null&&(i=h)&&(i=h)}return i}function pt(t,e){let i;if(e===void 0)for(const a of t)a!=null&&(i>a||i===void 0&&a>=a)&&(i=a);else{let a=-1;for(let h of t)(h=e(h,++a,t))!=null&&(i>h||i===void 0&&h>=h)&&(i=h)}return i}function nt(t,e){let i=0;if(e===void 0)for(let a of t)(a=+a)&&(i+=a);else{let a=-1;for(let h of t)(h=+e(h,++a,t))&&(i+=h)}return i}function Pt(t){return t.target.depth}function Ct(t){return t.depth}function Ot(t,e){return e-1-t.height}function mt(t,e){return t.sourceLinks.length?t.depth:e-1}function Dt(t){return t.targetLinks.length?t.depth:t.sourceLinks.length?pt(t.sourceLinks,Pt)-1:0}function X(t){return function(){return t}}function ut(t,e){return Q(t.source,e.source)||t.index-e.index}function ht(t,e){return Q(t.target,e.target)||t.index-e.index}function Q(t,e){return t.y0-e.y0}function it(t){return t.value}function jt(t){return t.index}function zt(t){return t.nodes}function $t(t){return t.links}function ft(t,e){const i=t.get(e);if(!i)throw new Error("missing: "+e);return i}function yt({nodes:t}){for(const e of t){let i=e.y0,a=i;for(const h of e.sourceLinks)h.y0=i+h.width/2,i+=h.width;for(const h of e.targetLinks)h.y1=a+h.width/2,a+=h.width}}function Bt(){let t=0,e=0,i=1,a=1,h=24,d=8,p,_=jt,s=mt,o,l,x=zt,v=$t,y=6;function b(){const n={nodes:x.apply(null,arguments),links:v.apply(null,arguments)};return M(n),T(n),N(n),C(n),S(n),yt(n),n}b.update=function(n){return yt(n),n},b.nodeId=function(n){return arguments.length?(_=typeof n=="function"?n:X(n),b):_},b.nodeAlign=function(n){return arguments.length?(s=typeof n=="function"?n:X(n),b):s},b.nodeSort=function(n){return arguments.length?(o=n,b):o},b.nodeWidth=function(n){return arguments.length?(h=+n,b):h},b.nodePadding=function(n){return arguments.length?(d=p=+n,b):d},b.nodes=function(n){return arguments.length?(x=typeof n=="function"?n:X(n),b):x},b.links=function(n){return arguments.length?(v=typeof n=="function"?n:X(n),b):v},b.linkSort=function(n){return arguments.length?(l=n,b):l},b.size=function(n){return arguments.length?(t=e=0,i=+n[0],a=+n[1],b):[i-t,a-e]},b.extent=function(n){return arguments.length?(t=+n[0][0],i=+n[1][0],e=+n[0][1],a=+n[1][1],b):[[t,e],[i,a]]},b.iterations=function(n){return arguments.length?(y=+n,b):y};function M({nodes:n,links:f}){for(const[c,r]of n.entries())r.index=c,r.sourceLinks=[],r.targetLinks=[];const u=new Map(n.map((c,r)=>[_(c,r,n),c]));for(const[c,r]of f.entries()){r.index=c;let{source:k,target:w}=r;typeof k!="object"&&(k=r.source=ft(u,k)),typeof w!="object"&&(w=r.target=ft(u,w)),k.sourceLinks.push(r),w.targetLinks.push(r)}if(l!=null)for(const{sourceLinks:c,targetLinks:r}of n)c.sort(l),r.sort(l)}function T({nodes:n}){for(const f of n)f.value=f.fixedValue===void 0?Math.max(nt(f.sourceLinks,it),nt(f.targetLinks,it)):f.fixedValue}function N({nodes:n}){const f=n.length;let u=new Set(n),c=new Set,r=0;for(;u.size;){for(const k of u){k.depth=r;for(const{target:w}of k.sourceLinks)c.add(w)}if(++r>f)throw new Error("circular link");u=c,c=new Set}}function C({nodes:n}){const f=n.length;let u=new Set(n),c=new Set,r=0;for(;u.size;){for(const k of u){k.height=r;for(const{source:w}of k.targetLinks)c.add(w)}if(++r>f)throw new Error("circular link");u=c,c=new Set}}function j({nodes:n}){const f=ct(n,r=>r.depth)+1,u=(i-t-h)/(f-1),c=new Array(f);for(const r of n){const k=Math.max(0,Math.min(f-1,Math.floor(s.call(null,r,f))));r.layer=k,r.x0=t+k*u,r.x1=r.x0+h,c[k]?c[k].push(r):c[k]=[r]}if(o)for(const r of c)r.sort(o);return c}function R(n){const f=pt(n,u=>(a-e-(u.length-1)*p)/nt(u,it));for(const u of n){let c=e;for(const r of u){r.y0=c,r.y1=c+r.value*f,c=r.y1+p;for(const k of r.sourceLinks)k.width=k.value*f}c=(a-c+p)/(u.length+1);for(let r=0;ru.length)-1)),R(f);for(let u=0;u0))continue;let W=(L/V-w.y0)*f;w.y0+=W,w.y1+=W,E(w)}o===void 0&&k.sort(Q),O(k,u)}}function $(n,f,u){for(let c=n.length,r=c-2;r>=0;--r){const k=n[r];for(const w of k){let L=0,V=0;for(const{target:U,value:et}of w.sourceLinks){let G=et*(U.layer-w.layer);L+=I(w,U)*G,V+=G}if(!(V>0))continue;let W=(L/V-w.y0)*f;w.y0+=W,w.y1+=W,E(w)}o===void 0&&k.sort(Q),O(k,u)}}function O(n,f){const u=n.length>>1,c=n[u];g(n,c.y0-p,u-1,f),D(n,c.y1+p,u+1,f),g(n,a,n.length-1,f),D(n,e,0,f)}function D(n,f,u,c){for(;u1e-6&&(r.y0+=k,r.y1+=k),f=r.y1+p}}function g(n,f,u,c){for(;u>=0;--u){const r=n[u],k=(r.y1-f)*c;k>1e-6&&(r.y0-=k,r.y1-=k),f=r.y0-p}}function E({sourceLinks:n,targetLinks:f}){if(l===void 0){for(const{source:{sourceLinks:u}}of f)u.sort(ht);for(const{target:{targetLinks:u}}of n)u.sort(ut)}}function A(n){if(l===void 0)for(const{sourceLinks:f,targetLinks:u}of n)f.sort(ht),u.sort(ut)}function z(n,f){let u=n.y0-(n.sourceLinks.length-1)*p/2;for(const{target:c,width:r}of n.sourceLinks){if(c===f)break;u+=r+p}for(const{source:c,width:r}of f.targetLinks){if(c===n)break;u-=r}return u}function I(n,f){let u=f.y0-(f.targetLinks.length-1)*p/2;for(const{source:c,width:r}of f.targetLinks){if(c===n)break;u+=r+p}for(const{target:c,width:r}of n.sourceLinks){if(c===f)break;u-=r}return u}return b}var st=Math.PI,rt=2*st,F=1e-6,Rt=rt-F;function ot(){this._x0=this._y0=this._x1=this._y1=null,this._=""}function kt(){return new ot}ot.prototype=kt.prototype={constructor:ot,moveTo:function(t,e){this._+="M"+(this._x0=this._x1=+t)+","+(this._y0=this._y1=+e)},closePath:function(){this._x1!==null&&(this._x1=this._x0,this._y1=this._y0,this._+="Z")},lineTo:function(t,e){this._+="L"+(this._x1=+t)+","+(this._y1=+e)},quadraticCurveTo:function(t,e,i,a){this._+="Q"+ +t+","+ +e+","+(this._x1=+i)+","+(this._y1=+a)},bezierCurveTo:function(t,e,i,a,h,d){this._+="C"+ +t+","+ +e+","+ +i+","+ +a+","+(this._x1=+h)+","+(this._y1=+d)},arcTo:function(t,e,i,a,h){t=+t,e=+e,i=+i,a=+a,h=+h;var d=this._x1,p=this._y1,_=i-t,s=a-e,o=d-t,l=p-e,x=o*o+l*l;if(h<0)throw new Error("negative radius: "+h);if(this._x1===null)this._+="M"+(this._x1=t)+","+(this._y1=e);else if(x>F)if(!(Math.abs(l*_-s*o)>F)||!h)this._+="L"+(this._x1=t)+","+(this._y1=e);else{var v=i-d,y=a-p,b=_*_+s*s,M=v*v+y*y,T=Math.sqrt(b),N=Math.sqrt(x),C=h*Math.tan((st-Math.acos((b+x-M)/(2*T*N)))/2),j=C/N,R=C/T;Math.abs(j-1)>F&&(this._+="L"+(t+j*o)+","+(e+j*l)),this._+="A"+h+","+h+",0,0,"+ +(l*v>o*y)+","+(this._x1=t+R*_)+","+(this._y1=e+R*s)}},arc:function(t,e,i,a,h,d){t=+t,e=+e,i=+i,d=!!d;var p=i*Math.cos(a),_=i*Math.sin(a),s=t+p,o=e+_,l=1^d,x=d?a-h:h-a;if(i<0)throw new Error("negative radius: "+i);this._x1===null?this._+="M"+s+","+o:(Math.abs(this._x1-s)>F||Math.abs(this._y1-o)>F)&&(this._+="L"+s+","+o),i&&(x<0&&(x=x%rt+rt),x>Rt?this._+="A"+i+","+i+",0,1,"+l+","+(t-p)+","+(e-_)+"A"+i+","+i+",0,1,"+l+","+(this._x1=s)+","+(this._y1=o):x>F&&(this._+="A"+i+","+i+",0,"+ +(x>=st)+","+l+","+(this._x1=t+i*Math.cos(h))+","+(this._y1=e+i*Math.sin(h))))},rect:function(t,e,i,a){this._+="M"+(this._x0=this._x1=+t)+","+(this._y0=this._y1=+e)+"h"+ +i+"v"+ +a+"h"+-i+"Z"},toString:function(){return this._}};function dt(t){return function(){return t}}function Vt(t){return t[0]}function Ft(t){return t[1]}var Wt=Array.prototype.slice;function Ut(t){return t.source}function Gt(t){return t.target}function Yt(t){var e=Ut,i=Gt,a=Vt,h=Ft,d=null;function p(){var _,s=Wt.call(arguments),o=e.apply(this,s),l=i.apply(this,s);if(d||(d=_=kt()),t(d,+a.apply(this,(s[0]=o,s)),+h.apply(this,s),+a.apply(this,(s[0]=l,s)),+h.apply(this,s)),_)return d=null,_+""||null}return p.source=function(_){return arguments.length?(e=_,p):e},p.target=function(_){return arguments.length?(i=_,p):i},p.x=function(_){return arguments.length?(a=typeof _=="function"?_:dt(+_),p):a},p.y=function(_){return arguments.length?(h=typeof _=="function"?_:dt(+_),p):h},p.context=function(_){return arguments.length?(d=_??null,p):d},p}function qt(t,e,i,a,h){t.moveTo(e,i),t.bezierCurveTo(e=(e+a)/2,i,e,h,a,h)}function Ht(){return Yt(qt)}function Xt(t){return[t.source.x1,t.y0]}function Qt(t){return[t.target.x0,t.y1]}function Kt(){return Ht().source(Xt).target(Qt)}var at=function(){var t=m(function(_,s,o,l){for(o=o||{},l=_.length;l--;o[_[l]]=s);return o},"o"),e=[1,9],i=[1,10],a=[1,5,10,12],h={trace:m(function(){},"trace"),yy:{},symbols_:{error:2,start:3,SANKEY:4,NEWLINE:5,csv:6,opt_eof:7,record:8,csv_tail:9,EOF:10,"field[source]":11,COMMA:12,"field[target]":13,"field[value]":14,field:15,escaped:16,non_escaped:17,DQUOTE:18,ESCAPED_TEXT:19,NON_ESCAPED_TEXT:20,$accept:0,$end:1},terminals_:{2:"error",4:"SANKEY",5:"NEWLINE",10:"EOF",11:"field[source]",12:"COMMA",13:"field[target]",14:"field[value]",18:"DQUOTE",19:"ESCAPED_TEXT",20:"NON_ESCAPED_TEXT"},productions_:[0,[3,4],[6,2],[9,2],[9,0],[7,1],[7,0],[8,5],[15,1],[15,1],[16,3],[17,1]],performAction:m(function(s,o,l,x,v,y,b){var M=y.length-1;switch(v){case 7:const T=x.findOrCreateNode(y[M-4].trim().replaceAll('""','"')),N=x.findOrCreateNode(y[M-2].trim().replaceAll('""','"')),C=parseFloat(y[M].trim());x.addLink(T,N,C);break;case 8:case 9:case 11:this.$=y[M];break;case 10:this.$=y[M-1];break}},"anonymous"),table:[{3:1,4:[1,2]},{1:[3]},{5:[1,3]},{6:4,8:5,15:6,16:7,17:8,18:e,20:i},{1:[2,6],7:11,10:[1,12]},t(i,[2,4],{9:13,5:[1,14]}),{12:[1,15]},t(a,[2,8]),t(a,[2,9]),{19:[1,16]},t(a,[2,11]),{1:[2,1]},{1:[2,5]},t(i,[2,2]),{6:17,8:5,15:6,16:7,17:8,18:e,20:i},{15:18,16:7,17:8,18:e,20:i},{18:[1,19]},t(i,[2,3]),{12:[1,20]},t(a,[2,10]),{15:21,16:7,17:8,18:e,20:i},t([1,5,10],[2,7])],defaultActions:{11:[2,1],12:[2,5]},parseError:m(function(s,o){if(o.recoverable)this.trace(s);else{var l=new Error(s);throw l.hash=o,l}},"parseError"),parse:m(function(s){var o=this,l=[0],x=[],v=[null],y=[],b=this.table,M="",T=0,N=0,C=2,j=1,R=y.slice.call(arguments,1),S=Object.create(this.lexer),P={yy:{}};for(var $ in this.yy)Object.prototype.hasOwnProperty.call(this.yy,$)&&(P.yy[$]=this.yy[$]);S.setInput(s,P.yy),P.yy.lexer=S,P.yy.parser=this,typeof S.yylloc>"u"&&(S.yylloc={});var O=S.yylloc;y.push(O);var D=S.options&&S.options.ranges;typeof P.yy.parseError=="function"?this.parseError=P.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function g(L){l.length=l.length-2*L,v.length=v.length-L,y.length=y.length-L}m(g,"popStack");function E(){var L;return L=x.pop()||S.lex()||j,typeof L!="number"&&(L instanceof Array&&(x=L,L=x.pop()),L=o.symbols_[L]||L),L}m(E,"lex");for(var A,z,I,n,f={},u,c,r,k;;){if(z=l[l.length-1],this.defaultActions[z]?I=this.defaultActions[z]:((A===null||typeof A>"u")&&(A=E()),I=b[z]&&b[z][A]),typeof I>"u"||!I.length||!I[0]){var w="";k=[];for(u in b[z])this.terminals_[u]&&u>C&&k.push("'"+this.terminals_[u]+"'");S.showPosition?w="Parse error on line "+(T+1)+`:
                                       `+S.showPosition()+`
                                       Expecting `+k.join(", ")+", got '"+(this.terminals_[A]||A)+"'":w="Parse error on line "+(T+1)+": Unexpected "+(A==j?"end of input":"'"+(this.terminals_[A]||A)+"'"),this.parseError(w,{text:S.match,token:this.terminals_[A]||A,line:S.yylineno,loc:O,expected:k})}if(I[0]instanceof Array&&I.length>1)throw new Error("Parse Error: multiple actions possible at state: "+z+", token: "+A);switch(I[0]){case 1:l.push(A),v.push(S.yytext),y.push(S.yylloc),l.push(I[1]),A=null,N=S.yyleng,M=S.yytext,T=S.yylineno,O=S.yylloc;break;case 2:if(c=this.productions_[I[1]][1],f.$=v[v.length-c],f._$={first_line:y[y.length-(c||1)].first_line,last_line:y[y.length-1].last_line,first_column:y[y.length-(c||1)].first_column,last_column:y[y.length-1].last_column},D&&(f._$.range=[y[y.length-(c||1)].range[0],y[y.length-1].range[1]]),n=this.performAction.apply(f,[M,N,T,P.yy,I[1],v,y].concat(R)),typeof n<"u")return n;c&&(l=l.slice(0,-1*c*2),v=v.slice(0,-1*c),y=y.slice(0,-1*c)),l.push(this.productions_[I[1]][0]),v.push(f.$),y.push(f._$),r=b[l[l.length-2]][l[l.length-1]],l.push(r);break;case 3:return!0}}return!0},"parse")},d=function(){var _={EOF:1,parseError:m(function(o,l){if(this.yy.parser)this.yy.parser.parseError(o,l);else throw new Error(o)},"parseError"),setInput:m(function(s,o){return this.yy=o||this.yy||{},this._input=s,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},"setInput"),input:m(function(){var s=this._input[0];this.yytext+=s,this.yyleng++,this.offset++,this.match+=s,this.matched+=s;var o=s.match(/(?:\r\n?|\n).*/g);return o?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),s},"input"),unput:m(function(s){var o=s.length,l=s.split(/(?:\r\n?|\n)/g);this._input=s+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-o),this.offset-=o;var x=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),l.length-1&&(this.yylineno-=l.length-1);var v=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:l?(l.length===x.length?this.yylloc.first_column:0)+x[x.length-l.length].length-l[0].length:this.yylloc.first_column-o},this.options.ranges&&(this.yylloc.range=[v[0],v[0]+this.yyleng-o]),this.yyleng=this.yytext.length,this},"unput"),more:m(function(){return this._more=!0,this},"more"),reject:m(function(){if(this.options.backtrack_lexer)this._backtrack=!0;else return this.parseError("Lexical error on line "+(this.yylineno+1)+`. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).
                                       `+this.showPosition(),{text:"",token:null,line:this.yylineno});return this},"reject"),less:m(function(s){this.unput(this.match.slice(s))},"less"),pastInput:m(function(){var s=this.matched.substr(0,this.matched.length-this.match.length);return(s.length>20?"...":"")+s.substr(-20).replace(/\n/g,"")},"pastInput"),upcomingInput:m(function(){var s=this.match;return s.length<20&&(s+=this._input.substr(0,20-s.length)),(s.substr(0,20)+(s.length>20?"...":"")).replace(/\n/g,"")},"upcomingInput"),showPosition:m(function(){var s=this.pastInput(),o=new Array(s.length+1).join("-");return s+this.upcomingInput()+`
                                      diff --git a/assets/sequenceDiagram-6SD7JOPP-BG3IUlAD.js b/assets/sequenceDiagram-6SD7JOPP-BbpXK4ej.js
                                      similarity index 99%
                                      rename from assets/sequenceDiagram-6SD7JOPP-BG3IUlAD.js
                                      rename to assets/sequenceDiagram-6SD7JOPP-BbpXK4ej.js
                                      index 7a0025ff65..4f7dcaa62b 100644
                                      --- a/assets/sequenceDiagram-6SD7JOPP-BG3IUlAD.js
                                      +++ b/assets/sequenceDiagram-6SD7JOPP-BbpXK4ej.js
                                      @@ -1,4 +1,4 @@
                                      -import{g as St,a as Kt,d as Se,b as Me,c as Re,e as De}from"./chunk-AIUMCIBP-g55d6rFj.js";import{I as Ce}from"./chunk-FBCX6ULS-BW7zNCW8.js";import{_ as d,g as Oe,r as Be,q as Ve,d as at,s as se,c as Ye,b as Fe,e as _,a3 as lt,a4 as wt,u as F,l as J,t as We,i as Mt,a as qe,j as kt,k as ze,m as ae,a5 as ie,H as Ft,a6 as ne,a7 as He}from"./mermaid.core-DapiNGBY.js";import"./app-DBM4OJyw.js";var Wt=function(){var t=d(function(pt,I,L,A){for(L=L||{},A=pt.length;A--;L[pt[A]]=I);return L},"o"),e=[1,2],o=[1,3],r=[1,4],a=[2,4],i=[1,9],c=[1,11],h=[1,13],p=[1,14],s=[1,16],f=[1,17],E=[1,18],g=[1,24],T=[1,25],m=[1,26],w=[1,27],k=[1,28],V=[1,29],M=[1,30],Y=[1,31],C=[1,32],z=[1,33],H=[1,34],Z=[1,35],et=[1,36],K=[1,37],U=[1,38],q=[1,39],R=[1,41],Q=[1,42],G=[1,43],j=[1,44],rt=[1,45],S=[1,46],y=[1,4,5,13,14,16,18,21,23,29,30,31,33,35,36,37,38,39,41,43,44,46,47,48,49,50,52,53,54,59,60,61,62,70],P=[4,5,16,50,52,53],$=[4,5,13,14,16,18,21,23,29,30,31,33,35,36,37,38,39,41,43,44,46,50,52,53,54,59,60,61,62,70],it=[4,5,13,14,16,18,21,23,29,30,31,33,35,36,37,38,39,41,43,44,46,49,50,52,53,54,59,60,61,62,70],N=[4,5,13,14,16,18,21,23,29,30,31,33,35,36,37,38,39,41,43,44,46,48,50,52,53,54,59,60,61,62,70],Jt=[4,5,13,14,16,18,21,23,29,30,31,33,35,36,37,38,39,41,43,44,46,47,50,52,53,54,59,60,61,62,70],ot=[68,69,70],dt=[1,122],Ct={trace:d(function(){},"trace"),yy:{},symbols_:{error:2,start:3,SPACE:4,NEWLINE:5,SD:6,document:7,line:8,statement:9,box_section:10,box_line:11,participant_statement:12,create:13,box:14,restOfLine:15,end:16,signal:17,autonumber:18,NUM:19,off:20,activate:21,actor:22,deactivate:23,note_statement:24,links_statement:25,link_statement:26,properties_statement:27,details_statement:28,title:29,legacy_title:30,acc_title:31,acc_title_value:32,acc_descr:33,acc_descr_value:34,acc_descr_multiline_value:35,loop:36,rect:37,opt:38,alt:39,else_sections:40,par:41,par_sections:42,par_over:43,critical:44,option_sections:45,break:46,option:47,and:48,else:49,participant:50,AS:51,participant_actor:52,destroy:53,note:54,placement:55,text2:56,over:57,actor_pair:58,links:59,link:60,properties:61,details:62,spaceList:63,",":64,left_of:65,right_of:66,signaltype:67,"+":68,"-":69,ACTOR:70,SOLID_OPEN_ARROW:71,DOTTED_OPEN_ARROW:72,SOLID_ARROW:73,BIDIRECTIONAL_SOLID_ARROW:74,DOTTED_ARROW:75,BIDIRECTIONAL_DOTTED_ARROW:76,SOLID_CROSS:77,DOTTED_CROSS:78,SOLID_POINT:79,DOTTED_POINT:80,TXT:81,$accept:0,$end:1},terminals_:{2:"error",4:"SPACE",5:"NEWLINE",6:"SD",13:"create",14:"box",15:"restOfLine",16:"end",18:"autonumber",19:"NUM",20:"off",21:"activate",23:"deactivate",29:"title",30:"legacy_title",31:"acc_title",32:"acc_title_value",33:"acc_descr",34:"acc_descr_value",35:"acc_descr_multiline_value",36:"loop",37:"rect",38:"opt",39:"alt",41:"par",43:"par_over",44:"critical",46:"break",47:"option",48:"and",49:"else",50:"participant",51:"AS",52:"participant_actor",53:"destroy",54:"note",57:"over",59:"links",60:"link",61:"properties",62:"details",64:",",65:"left_of",66:"right_of",68:"+",69:"-",70:"ACTOR",71:"SOLID_OPEN_ARROW",72:"DOTTED_OPEN_ARROW",73:"SOLID_ARROW",74:"BIDIRECTIONAL_SOLID_ARROW",75:"DOTTED_ARROW",76:"BIDIRECTIONAL_DOTTED_ARROW",77:"SOLID_CROSS",78:"DOTTED_CROSS",79:"SOLID_POINT",80:"DOTTED_POINT",81:"TXT"},productions_:[0,[3,2],[3,2],[3,2],[7,0],[7,2],[8,2],[8,1],[8,1],[10,0],[10,2],[11,2],[11,1],[11,1],[9,1],[9,2],[9,4],[9,2],[9,4],[9,3],[9,3],[9,2],[9,3],[9,3],[9,2],[9,2],[9,2],[9,2],[9,2],[9,1],[9,1],[9,2],[9,2],[9,1],[9,4],[9,4],[9,4],[9,4],[9,4],[9,4],[9,4],[9,4],[45,1],[45,4],[42,1],[42,4],[40,1],[40,4],[12,5],[12,3],[12,5],[12,3],[12,3],[24,4],[24,4],[25,3],[26,3],[27,3],[28,3],[63,2],[63,1],[58,3],[58,1],[55,1],[55,1],[17,5],[17,5],[17,4],[22,1],[67,1],[67,1],[67,1],[67,1],[67,1],[67,1],[67,1],[67,1],[67,1],[67,1],[56,1]],performAction:d(function(I,L,A,b,D,l,mt){var u=l.length-1;switch(D){case 3:return b.apply(l[u]),l[u];case 4:case 9:this.$=[];break;case 5:case 10:l[u-1].push(l[u]),this.$=l[u-1];break;case 6:case 7:case 11:case 12:this.$=l[u];break;case 8:case 13:this.$=[];break;case 15:l[u].type="createParticipant",this.$=l[u];break;case 16:l[u-1].unshift({type:"boxStart",boxData:b.parseBoxData(l[u-2])}),l[u-1].push({type:"boxEnd",boxText:l[u-2]}),this.$=l[u-1];break;case 18:this.$={type:"sequenceIndex",sequenceIndex:Number(l[u-2]),sequenceIndexStep:Number(l[u-1]),sequenceVisible:!0,signalType:b.LINETYPE.AUTONUMBER};break;case 19:this.$={type:"sequenceIndex",sequenceIndex:Number(l[u-1]),sequenceIndexStep:1,sequenceVisible:!0,signalType:b.LINETYPE.AUTONUMBER};break;case 20:this.$={type:"sequenceIndex",sequenceVisible:!1,signalType:b.LINETYPE.AUTONUMBER};break;case 21:this.$={type:"sequenceIndex",sequenceVisible:!0,signalType:b.LINETYPE.AUTONUMBER};break;case 22:this.$={type:"activeStart",signalType:b.LINETYPE.ACTIVE_START,actor:l[u-1].actor};break;case 23:this.$={type:"activeEnd",signalType:b.LINETYPE.ACTIVE_END,actor:l[u-1].actor};break;case 29:b.setDiagramTitle(l[u].substring(6)),this.$=l[u].substring(6);break;case 30:b.setDiagramTitle(l[u].substring(7)),this.$=l[u].substring(7);break;case 31:this.$=l[u].trim(),b.setAccTitle(this.$);break;case 32:case 33:this.$=l[u].trim(),b.setAccDescription(this.$);break;case 34:l[u-1].unshift({type:"loopStart",loopText:b.parseMessage(l[u-2]),signalType:b.LINETYPE.LOOP_START}),l[u-1].push({type:"loopEnd",loopText:l[u-2],signalType:b.LINETYPE.LOOP_END}),this.$=l[u-1];break;case 35:l[u-1].unshift({type:"rectStart",color:b.parseMessage(l[u-2]),signalType:b.LINETYPE.RECT_START}),l[u-1].push({type:"rectEnd",color:b.parseMessage(l[u-2]),signalType:b.LINETYPE.RECT_END}),this.$=l[u-1];break;case 36:l[u-1].unshift({type:"optStart",optText:b.parseMessage(l[u-2]),signalType:b.LINETYPE.OPT_START}),l[u-1].push({type:"optEnd",optText:b.parseMessage(l[u-2]),signalType:b.LINETYPE.OPT_END}),this.$=l[u-1];break;case 37:l[u-1].unshift({type:"altStart",altText:b.parseMessage(l[u-2]),signalType:b.LINETYPE.ALT_START}),l[u-1].push({type:"altEnd",signalType:b.LINETYPE.ALT_END}),this.$=l[u-1];break;case 38:l[u-1].unshift({type:"parStart",parText:b.parseMessage(l[u-2]),signalType:b.LINETYPE.PAR_START}),l[u-1].push({type:"parEnd",signalType:b.LINETYPE.PAR_END}),this.$=l[u-1];break;case 39:l[u-1].unshift({type:"parStart",parText:b.parseMessage(l[u-2]),signalType:b.LINETYPE.PAR_OVER_START}),l[u-1].push({type:"parEnd",signalType:b.LINETYPE.PAR_END}),this.$=l[u-1];break;case 40:l[u-1].unshift({type:"criticalStart",criticalText:b.parseMessage(l[u-2]),signalType:b.LINETYPE.CRITICAL_START}),l[u-1].push({type:"criticalEnd",signalType:b.LINETYPE.CRITICAL_END}),this.$=l[u-1];break;case 41:l[u-1].unshift({type:"breakStart",breakText:b.parseMessage(l[u-2]),signalType:b.LINETYPE.BREAK_START}),l[u-1].push({type:"breakEnd",optText:b.parseMessage(l[u-2]),signalType:b.LINETYPE.BREAK_END}),this.$=l[u-1];break;case 43:this.$=l[u-3].concat([{type:"option",optionText:b.parseMessage(l[u-1]),signalType:b.LINETYPE.CRITICAL_OPTION},l[u]]);break;case 45:this.$=l[u-3].concat([{type:"and",parText:b.parseMessage(l[u-1]),signalType:b.LINETYPE.PAR_AND},l[u]]);break;case 47:this.$=l[u-3].concat([{type:"else",altText:b.parseMessage(l[u-1]),signalType:b.LINETYPE.ALT_ELSE},l[u]]);break;case 48:l[u-3].draw="participant",l[u-3].type="addParticipant",l[u-3].description=b.parseMessage(l[u-1]),this.$=l[u-3];break;case 49:l[u-1].draw="participant",l[u-1].type="addParticipant",this.$=l[u-1];break;case 50:l[u-3].draw="actor",l[u-3].type="addParticipant",l[u-3].description=b.parseMessage(l[u-1]),this.$=l[u-3];break;case 51:l[u-1].draw="actor",l[u-1].type="addParticipant",this.$=l[u-1];break;case 52:l[u-1].type="destroyParticipant",this.$=l[u-1];break;case 53:this.$=[l[u-1],{type:"addNote",placement:l[u-2],actor:l[u-1].actor,text:l[u]}];break;case 54:l[u-2]=[].concat(l[u-1],l[u-1]).slice(0,2),l[u-2][0]=l[u-2][0].actor,l[u-2][1]=l[u-2][1].actor,this.$=[l[u-1],{type:"addNote",placement:b.PLACEMENT.OVER,actor:l[u-2].slice(0,2),text:l[u]}];break;case 55:this.$=[l[u-1],{type:"addLinks",actor:l[u-1].actor,text:l[u]}];break;case 56:this.$=[l[u-1],{type:"addALink",actor:l[u-1].actor,text:l[u]}];break;case 57:this.$=[l[u-1],{type:"addProperties",actor:l[u-1].actor,text:l[u]}];break;case 58:this.$=[l[u-1],{type:"addDetails",actor:l[u-1].actor,text:l[u]}];break;case 61:this.$=[l[u-2],l[u]];break;case 62:this.$=l[u];break;case 63:this.$=b.PLACEMENT.LEFTOF;break;case 64:this.$=b.PLACEMENT.RIGHTOF;break;case 65:this.$=[l[u-4],l[u-1],{type:"addMessage",from:l[u-4].actor,to:l[u-1].actor,signalType:l[u-3],msg:l[u],activate:!0},{type:"activeStart",signalType:b.LINETYPE.ACTIVE_START,actor:l[u-1].actor}];break;case 66:this.$=[l[u-4],l[u-1],{type:"addMessage",from:l[u-4].actor,to:l[u-1].actor,signalType:l[u-3],msg:l[u]},{type:"activeEnd",signalType:b.LINETYPE.ACTIVE_END,actor:l[u-4].actor}];break;case 67:this.$=[l[u-3],l[u-1],{type:"addMessage",from:l[u-3].actor,to:l[u-1].actor,signalType:l[u-2],msg:l[u]}];break;case 68:this.$={type:"addParticipant",actor:l[u]};break;case 69:this.$=b.LINETYPE.SOLID_OPEN;break;case 70:this.$=b.LINETYPE.DOTTED_OPEN;break;case 71:this.$=b.LINETYPE.SOLID;break;case 72:this.$=b.LINETYPE.BIDIRECTIONAL_SOLID;break;case 73:this.$=b.LINETYPE.DOTTED;break;case 74:this.$=b.LINETYPE.BIDIRECTIONAL_DOTTED;break;case 75:this.$=b.LINETYPE.SOLID_CROSS;break;case 76:this.$=b.LINETYPE.DOTTED_CROSS;break;case 77:this.$=b.LINETYPE.SOLID_POINT;break;case 78:this.$=b.LINETYPE.DOTTED_POINT;break;case 79:this.$=b.parseMessage(l[u].trim().substring(1));break}},"anonymous"),table:[{3:1,4:e,5:o,6:r},{1:[3]},{3:5,4:e,5:o,6:r},{3:6,4:e,5:o,6:r},t([1,4,5,13,14,18,21,23,29,30,31,33,35,36,37,38,39,41,43,44,46,50,52,53,54,59,60,61,62,70],a,{7:7}),{1:[2,1]},{1:[2,2]},{1:[2,3],4:i,5:c,8:8,9:10,12:12,13:h,14:p,17:15,18:s,21:f,22:40,23:E,24:19,25:20,26:21,27:22,28:23,29:g,30:T,31:m,33:w,35:k,36:V,37:M,38:Y,39:C,41:z,43:H,44:Z,46:et,50:K,52:U,53:q,54:R,59:Q,60:G,61:j,62:rt,70:S},t(y,[2,5]),{9:47,12:12,13:h,14:p,17:15,18:s,21:f,22:40,23:E,24:19,25:20,26:21,27:22,28:23,29:g,30:T,31:m,33:w,35:k,36:V,37:M,38:Y,39:C,41:z,43:H,44:Z,46:et,50:K,52:U,53:q,54:R,59:Q,60:G,61:j,62:rt,70:S},t(y,[2,7]),t(y,[2,8]),t(y,[2,14]),{12:48,50:K,52:U,53:q},{15:[1,49]},{5:[1,50]},{5:[1,53],19:[1,51],20:[1,52]},{22:54,70:S},{22:55,70:S},{5:[1,56]},{5:[1,57]},{5:[1,58]},{5:[1,59]},{5:[1,60]},t(y,[2,29]),t(y,[2,30]),{32:[1,61]},{34:[1,62]},t(y,[2,33]),{15:[1,63]},{15:[1,64]},{15:[1,65]},{15:[1,66]},{15:[1,67]},{15:[1,68]},{15:[1,69]},{15:[1,70]},{22:71,70:S},{22:72,70:S},{22:73,70:S},{67:74,71:[1,75],72:[1,76],73:[1,77],74:[1,78],75:[1,79],76:[1,80],77:[1,81],78:[1,82],79:[1,83],80:[1,84]},{55:85,57:[1,86],65:[1,87],66:[1,88]},{22:89,70:S},{22:90,70:S},{22:91,70:S},{22:92,70:S},t([5,51,64,71,72,73,74,75,76,77,78,79,80,81],[2,68]),t(y,[2,6]),t(y,[2,15]),t(P,[2,9],{10:93}),t(y,[2,17]),{5:[1,95],19:[1,94]},{5:[1,96]},t(y,[2,21]),{5:[1,97]},{5:[1,98]},t(y,[2,24]),t(y,[2,25]),t(y,[2,26]),t(y,[2,27]),t(y,[2,28]),t(y,[2,31]),t(y,[2,32]),t($,a,{7:99}),t($,a,{7:100}),t($,a,{7:101}),t(it,a,{40:102,7:103}),t(N,a,{42:104,7:105}),t(N,a,{7:105,42:106}),t(Jt,a,{45:107,7:108}),t($,a,{7:109}),{5:[1,111],51:[1,110]},{5:[1,113],51:[1,112]},{5:[1,114]},{22:117,68:[1,115],69:[1,116],70:S},t(ot,[2,69]),t(ot,[2,70]),t(ot,[2,71]),t(ot,[2,72]),t(ot,[2,73]),t(ot,[2,74]),t(ot,[2,75]),t(ot,[2,76]),t(ot,[2,77]),t(ot,[2,78]),{22:118,70:S},{22:120,58:119,70:S},{70:[2,63]},{70:[2,64]},{56:121,81:dt},{56:123,81:dt},{56:124,81:dt},{56:125,81:dt},{4:[1,128],5:[1,130],11:127,12:129,16:[1,126],50:K,52:U,53:q},{5:[1,131]},t(y,[2,19]),t(y,[2,20]),t(y,[2,22]),t(y,[2,23]),{4:i,5:c,8:8,9:10,12:12,13:h,14:p,16:[1,132],17:15,18:s,21:f,22:40,23:E,24:19,25:20,26:21,27:22,28:23,29:g,30:T,31:m,33:w,35:k,36:V,37:M,38:Y,39:C,41:z,43:H,44:Z,46:et,50:K,52:U,53:q,54:R,59:Q,60:G,61:j,62:rt,70:S},{4:i,5:c,8:8,9:10,12:12,13:h,14:p,16:[1,133],17:15,18:s,21:f,22:40,23:E,24:19,25:20,26:21,27:22,28:23,29:g,30:T,31:m,33:w,35:k,36:V,37:M,38:Y,39:C,41:z,43:H,44:Z,46:et,50:K,52:U,53:q,54:R,59:Q,60:G,61:j,62:rt,70:S},{4:i,5:c,8:8,9:10,12:12,13:h,14:p,16:[1,134],17:15,18:s,21:f,22:40,23:E,24:19,25:20,26:21,27:22,28:23,29:g,30:T,31:m,33:w,35:k,36:V,37:M,38:Y,39:C,41:z,43:H,44:Z,46:et,50:K,52:U,53:q,54:R,59:Q,60:G,61:j,62:rt,70:S},{16:[1,135]},{4:i,5:c,8:8,9:10,12:12,13:h,14:p,16:[2,46],17:15,18:s,21:f,22:40,23:E,24:19,25:20,26:21,27:22,28:23,29:g,30:T,31:m,33:w,35:k,36:V,37:M,38:Y,39:C,41:z,43:H,44:Z,46:et,49:[1,136],50:K,52:U,53:q,54:R,59:Q,60:G,61:j,62:rt,70:S},{16:[1,137]},{4:i,5:c,8:8,9:10,12:12,13:h,14:p,16:[2,44],17:15,18:s,21:f,22:40,23:E,24:19,25:20,26:21,27:22,28:23,29:g,30:T,31:m,33:w,35:k,36:V,37:M,38:Y,39:C,41:z,43:H,44:Z,46:et,48:[1,138],50:K,52:U,53:q,54:R,59:Q,60:G,61:j,62:rt,70:S},{16:[1,139]},{16:[1,140]},{4:i,5:c,8:8,9:10,12:12,13:h,14:p,16:[2,42],17:15,18:s,21:f,22:40,23:E,24:19,25:20,26:21,27:22,28:23,29:g,30:T,31:m,33:w,35:k,36:V,37:M,38:Y,39:C,41:z,43:H,44:Z,46:et,47:[1,141],50:K,52:U,53:q,54:R,59:Q,60:G,61:j,62:rt,70:S},{4:i,5:c,8:8,9:10,12:12,13:h,14:p,16:[1,142],17:15,18:s,21:f,22:40,23:E,24:19,25:20,26:21,27:22,28:23,29:g,30:T,31:m,33:w,35:k,36:V,37:M,38:Y,39:C,41:z,43:H,44:Z,46:et,50:K,52:U,53:q,54:R,59:Q,60:G,61:j,62:rt,70:S},{15:[1,143]},t(y,[2,49]),{15:[1,144]},t(y,[2,51]),t(y,[2,52]),{22:145,70:S},{22:146,70:S},{56:147,81:dt},{56:148,81:dt},{56:149,81:dt},{64:[1,150],81:[2,62]},{5:[2,55]},{5:[2,79]},{5:[2,56]},{5:[2,57]},{5:[2,58]},t(y,[2,16]),t(P,[2,10]),{12:151,50:K,52:U,53:q},t(P,[2,12]),t(P,[2,13]),t(y,[2,18]),t(y,[2,34]),t(y,[2,35]),t(y,[2,36]),t(y,[2,37]),{15:[1,152]},t(y,[2,38]),{15:[1,153]},t(y,[2,39]),t(y,[2,40]),{15:[1,154]},t(y,[2,41]),{5:[1,155]},{5:[1,156]},{56:157,81:dt},{56:158,81:dt},{5:[2,67]},{5:[2,53]},{5:[2,54]},{22:159,70:S},t(P,[2,11]),t(it,a,{7:103,40:160}),t(N,a,{7:105,42:161}),t(Jt,a,{7:108,45:162}),t(y,[2,48]),t(y,[2,50]),{5:[2,65]},{5:[2,66]},{81:[2,61]},{16:[2,47]},{16:[2,45]},{16:[2,43]}],defaultActions:{5:[2,1],6:[2,2],87:[2,63],88:[2,64],121:[2,55],122:[2,79],123:[2,56],124:[2,57],125:[2,58],147:[2,67],148:[2,53],149:[2,54],157:[2,65],158:[2,66],159:[2,61],160:[2,47],161:[2,45],162:[2,43]},parseError:d(function(I,L){if(L.recoverable)this.trace(I);else{var A=new Error(I);throw A.hash=L,A}},"parseError"),parse:d(function(I){var L=this,A=[0],b=[],D=[null],l=[],mt=this.table,u="",Lt=0,Zt=0,Pe=2,Qt=1,Ae=l.slice.call(arguments,1),W=Object.create(this.lexer),ut={yy:{}};for(var Ot in this.yy)Object.prototype.hasOwnProperty.call(this.yy,Ot)&&(ut.yy[Ot]=this.yy[Ot]);W.setInput(I,ut.yy),ut.yy.lexer=W,ut.yy.parser=this,typeof W.yylloc>"u"&&(W.yylloc={});var Bt=W.yylloc;l.push(Bt);var ke=W.options&&W.options.ranges;typeof ut.yy.parseError=="function"?this.parseError=ut.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function Ne(tt){A.length=A.length-2*tt,D.length=D.length-tt,l.length=l.length-tt}d(Ne,"popStack");function jt(){var tt;return tt=b.pop()||W.lex()||Qt,typeof tt!="number"&&(tt instanceof Array&&(b=tt,tt=b.pop()),tt=L.symbols_[tt]||tt),tt}d(jt,"lex");for(var X,gt,st,Vt,yt={},Pt,ht,$t,At;;){if(gt=A[A.length-1],this.defaultActions[gt]?st=this.defaultActions[gt]:((X===null||typeof X>"u")&&(X=jt()),st=mt[gt]&&mt[gt][X]),typeof st>"u"||!st.length||!st[0]){var Yt="";At=[];for(Pt in mt[gt])this.terminals_[Pt]&&Pt>Pe&&At.push("'"+this.terminals_[Pt]+"'");W.showPosition?Yt="Parse error on line "+(Lt+1)+`:
                                      +import{g as St,a as Kt,d as Se,b as Me,c as Re,e as De}from"./chunk-AIUMCIBP-v8d5o65o.js";import{I as Ce}from"./chunk-FBCX6ULS-B99hIK7X.js";import{_ as d,g as Oe,r as Be,q as Ve,d as at,s as se,c as Ye,b as Fe,e as _,a3 as lt,a4 as wt,u as F,l as J,t as We,i as Mt,a as qe,j as kt,k as ze,m as ae,a5 as ie,H as Ft,a6 as ne,a7 as He}from"./mermaid.core-D8igZDel.js";import"./app-D7uBbsY3.js";var Wt=function(){var t=d(function(pt,I,L,A){for(L=L||{},A=pt.length;A--;L[pt[A]]=I);return L},"o"),e=[1,2],o=[1,3],r=[1,4],a=[2,4],i=[1,9],c=[1,11],h=[1,13],p=[1,14],s=[1,16],f=[1,17],E=[1,18],g=[1,24],T=[1,25],m=[1,26],w=[1,27],k=[1,28],V=[1,29],M=[1,30],Y=[1,31],C=[1,32],z=[1,33],H=[1,34],Z=[1,35],et=[1,36],K=[1,37],U=[1,38],q=[1,39],R=[1,41],Q=[1,42],G=[1,43],j=[1,44],rt=[1,45],S=[1,46],y=[1,4,5,13,14,16,18,21,23,29,30,31,33,35,36,37,38,39,41,43,44,46,47,48,49,50,52,53,54,59,60,61,62,70],P=[4,5,16,50,52,53],$=[4,5,13,14,16,18,21,23,29,30,31,33,35,36,37,38,39,41,43,44,46,50,52,53,54,59,60,61,62,70],it=[4,5,13,14,16,18,21,23,29,30,31,33,35,36,37,38,39,41,43,44,46,49,50,52,53,54,59,60,61,62,70],N=[4,5,13,14,16,18,21,23,29,30,31,33,35,36,37,38,39,41,43,44,46,48,50,52,53,54,59,60,61,62,70],Jt=[4,5,13,14,16,18,21,23,29,30,31,33,35,36,37,38,39,41,43,44,46,47,50,52,53,54,59,60,61,62,70],ot=[68,69,70],dt=[1,122],Ct={trace:d(function(){},"trace"),yy:{},symbols_:{error:2,start:3,SPACE:4,NEWLINE:5,SD:6,document:7,line:8,statement:9,box_section:10,box_line:11,participant_statement:12,create:13,box:14,restOfLine:15,end:16,signal:17,autonumber:18,NUM:19,off:20,activate:21,actor:22,deactivate:23,note_statement:24,links_statement:25,link_statement:26,properties_statement:27,details_statement:28,title:29,legacy_title:30,acc_title:31,acc_title_value:32,acc_descr:33,acc_descr_value:34,acc_descr_multiline_value:35,loop:36,rect:37,opt:38,alt:39,else_sections:40,par:41,par_sections:42,par_over:43,critical:44,option_sections:45,break:46,option:47,and:48,else:49,participant:50,AS:51,participant_actor:52,destroy:53,note:54,placement:55,text2:56,over:57,actor_pair:58,links:59,link:60,properties:61,details:62,spaceList:63,",":64,left_of:65,right_of:66,signaltype:67,"+":68,"-":69,ACTOR:70,SOLID_OPEN_ARROW:71,DOTTED_OPEN_ARROW:72,SOLID_ARROW:73,BIDIRECTIONAL_SOLID_ARROW:74,DOTTED_ARROW:75,BIDIRECTIONAL_DOTTED_ARROW:76,SOLID_CROSS:77,DOTTED_CROSS:78,SOLID_POINT:79,DOTTED_POINT:80,TXT:81,$accept:0,$end:1},terminals_:{2:"error",4:"SPACE",5:"NEWLINE",6:"SD",13:"create",14:"box",15:"restOfLine",16:"end",18:"autonumber",19:"NUM",20:"off",21:"activate",23:"deactivate",29:"title",30:"legacy_title",31:"acc_title",32:"acc_title_value",33:"acc_descr",34:"acc_descr_value",35:"acc_descr_multiline_value",36:"loop",37:"rect",38:"opt",39:"alt",41:"par",43:"par_over",44:"critical",46:"break",47:"option",48:"and",49:"else",50:"participant",51:"AS",52:"participant_actor",53:"destroy",54:"note",57:"over",59:"links",60:"link",61:"properties",62:"details",64:",",65:"left_of",66:"right_of",68:"+",69:"-",70:"ACTOR",71:"SOLID_OPEN_ARROW",72:"DOTTED_OPEN_ARROW",73:"SOLID_ARROW",74:"BIDIRECTIONAL_SOLID_ARROW",75:"DOTTED_ARROW",76:"BIDIRECTIONAL_DOTTED_ARROW",77:"SOLID_CROSS",78:"DOTTED_CROSS",79:"SOLID_POINT",80:"DOTTED_POINT",81:"TXT"},productions_:[0,[3,2],[3,2],[3,2],[7,0],[7,2],[8,2],[8,1],[8,1],[10,0],[10,2],[11,2],[11,1],[11,1],[9,1],[9,2],[9,4],[9,2],[9,4],[9,3],[9,3],[9,2],[9,3],[9,3],[9,2],[9,2],[9,2],[9,2],[9,2],[9,1],[9,1],[9,2],[9,2],[9,1],[9,4],[9,4],[9,4],[9,4],[9,4],[9,4],[9,4],[9,4],[45,1],[45,4],[42,1],[42,4],[40,1],[40,4],[12,5],[12,3],[12,5],[12,3],[12,3],[24,4],[24,4],[25,3],[26,3],[27,3],[28,3],[63,2],[63,1],[58,3],[58,1],[55,1],[55,1],[17,5],[17,5],[17,4],[22,1],[67,1],[67,1],[67,1],[67,1],[67,1],[67,1],[67,1],[67,1],[67,1],[67,1],[56,1]],performAction:d(function(I,L,A,b,D,l,mt){var u=l.length-1;switch(D){case 3:return b.apply(l[u]),l[u];case 4:case 9:this.$=[];break;case 5:case 10:l[u-1].push(l[u]),this.$=l[u-1];break;case 6:case 7:case 11:case 12:this.$=l[u];break;case 8:case 13:this.$=[];break;case 15:l[u].type="createParticipant",this.$=l[u];break;case 16:l[u-1].unshift({type:"boxStart",boxData:b.parseBoxData(l[u-2])}),l[u-1].push({type:"boxEnd",boxText:l[u-2]}),this.$=l[u-1];break;case 18:this.$={type:"sequenceIndex",sequenceIndex:Number(l[u-2]),sequenceIndexStep:Number(l[u-1]),sequenceVisible:!0,signalType:b.LINETYPE.AUTONUMBER};break;case 19:this.$={type:"sequenceIndex",sequenceIndex:Number(l[u-1]),sequenceIndexStep:1,sequenceVisible:!0,signalType:b.LINETYPE.AUTONUMBER};break;case 20:this.$={type:"sequenceIndex",sequenceVisible:!1,signalType:b.LINETYPE.AUTONUMBER};break;case 21:this.$={type:"sequenceIndex",sequenceVisible:!0,signalType:b.LINETYPE.AUTONUMBER};break;case 22:this.$={type:"activeStart",signalType:b.LINETYPE.ACTIVE_START,actor:l[u-1].actor};break;case 23:this.$={type:"activeEnd",signalType:b.LINETYPE.ACTIVE_END,actor:l[u-1].actor};break;case 29:b.setDiagramTitle(l[u].substring(6)),this.$=l[u].substring(6);break;case 30:b.setDiagramTitle(l[u].substring(7)),this.$=l[u].substring(7);break;case 31:this.$=l[u].trim(),b.setAccTitle(this.$);break;case 32:case 33:this.$=l[u].trim(),b.setAccDescription(this.$);break;case 34:l[u-1].unshift({type:"loopStart",loopText:b.parseMessage(l[u-2]),signalType:b.LINETYPE.LOOP_START}),l[u-1].push({type:"loopEnd",loopText:l[u-2],signalType:b.LINETYPE.LOOP_END}),this.$=l[u-1];break;case 35:l[u-1].unshift({type:"rectStart",color:b.parseMessage(l[u-2]),signalType:b.LINETYPE.RECT_START}),l[u-1].push({type:"rectEnd",color:b.parseMessage(l[u-2]),signalType:b.LINETYPE.RECT_END}),this.$=l[u-1];break;case 36:l[u-1].unshift({type:"optStart",optText:b.parseMessage(l[u-2]),signalType:b.LINETYPE.OPT_START}),l[u-1].push({type:"optEnd",optText:b.parseMessage(l[u-2]),signalType:b.LINETYPE.OPT_END}),this.$=l[u-1];break;case 37:l[u-1].unshift({type:"altStart",altText:b.parseMessage(l[u-2]),signalType:b.LINETYPE.ALT_START}),l[u-1].push({type:"altEnd",signalType:b.LINETYPE.ALT_END}),this.$=l[u-1];break;case 38:l[u-1].unshift({type:"parStart",parText:b.parseMessage(l[u-2]),signalType:b.LINETYPE.PAR_START}),l[u-1].push({type:"parEnd",signalType:b.LINETYPE.PAR_END}),this.$=l[u-1];break;case 39:l[u-1].unshift({type:"parStart",parText:b.parseMessage(l[u-2]),signalType:b.LINETYPE.PAR_OVER_START}),l[u-1].push({type:"parEnd",signalType:b.LINETYPE.PAR_END}),this.$=l[u-1];break;case 40:l[u-1].unshift({type:"criticalStart",criticalText:b.parseMessage(l[u-2]),signalType:b.LINETYPE.CRITICAL_START}),l[u-1].push({type:"criticalEnd",signalType:b.LINETYPE.CRITICAL_END}),this.$=l[u-1];break;case 41:l[u-1].unshift({type:"breakStart",breakText:b.parseMessage(l[u-2]),signalType:b.LINETYPE.BREAK_START}),l[u-1].push({type:"breakEnd",optText:b.parseMessage(l[u-2]),signalType:b.LINETYPE.BREAK_END}),this.$=l[u-1];break;case 43:this.$=l[u-3].concat([{type:"option",optionText:b.parseMessage(l[u-1]),signalType:b.LINETYPE.CRITICAL_OPTION},l[u]]);break;case 45:this.$=l[u-3].concat([{type:"and",parText:b.parseMessage(l[u-1]),signalType:b.LINETYPE.PAR_AND},l[u]]);break;case 47:this.$=l[u-3].concat([{type:"else",altText:b.parseMessage(l[u-1]),signalType:b.LINETYPE.ALT_ELSE},l[u]]);break;case 48:l[u-3].draw="participant",l[u-3].type="addParticipant",l[u-3].description=b.parseMessage(l[u-1]),this.$=l[u-3];break;case 49:l[u-1].draw="participant",l[u-1].type="addParticipant",this.$=l[u-1];break;case 50:l[u-3].draw="actor",l[u-3].type="addParticipant",l[u-3].description=b.parseMessage(l[u-1]),this.$=l[u-3];break;case 51:l[u-1].draw="actor",l[u-1].type="addParticipant",this.$=l[u-1];break;case 52:l[u-1].type="destroyParticipant",this.$=l[u-1];break;case 53:this.$=[l[u-1],{type:"addNote",placement:l[u-2],actor:l[u-1].actor,text:l[u]}];break;case 54:l[u-2]=[].concat(l[u-1],l[u-1]).slice(0,2),l[u-2][0]=l[u-2][0].actor,l[u-2][1]=l[u-2][1].actor,this.$=[l[u-1],{type:"addNote",placement:b.PLACEMENT.OVER,actor:l[u-2].slice(0,2),text:l[u]}];break;case 55:this.$=[l[u-1],{type:"addLinks",actor:l[u-1].actor,text:l[u]}];break;case 56:this.$=[l[u-1],{type:"addALink",actor:l[u-1].actor,text:l[u]}];break;case 57:this.$=[l[u-1],{type:"addProperties",actor:l[u-1].actor,text:l[u]}];break;case 58:this.$=[l[u-1],{type:"addDetails",actor:l[u-1].actor,text:l[u]}];break;case 61:this.$=[l[u-2],l[u]];break;case 62:this.$=l[u];break;case 63:this.$=b.PLACEMENT.LEFTOF;break;case 64:this.$=b.PLACEMENT.RIGHTOF;break;case 65:this.$=[l[u-4],l[u-1],{type:"addMessage",from:l[u-4].actor,to:l[u-1].actor,signalType:l[u-3],msg:l[u],activate:!0},{type:"activeStart",signalType:b.LINETYPE.ACTIVE_START,actor:l[u-1].actor}];break;case 66:this.$=[l[u-4],l[u-1],{type:"addMessage",from:l[u-4].actor,to:l[u-1].actor,signalType:l[u-3],msg:l[u]},{type:"activeEnd",signalType:b.LINETYPE.ACTIVE_END,actor:l[u-4].actor}];break;case 67:this.$=[l[u-3],l[u-1],{type:"addMessage",from:l[u-3].actor,to:l[u-1].actor,signalType:l[u-2],msg:l[u]}];break;case 68:this.$={type:"addParticipant",actor:l[u]};break;case 69:this.$=b.LINETYPE.SOLID_OPEN;break;case 70:this.$=b.LINETYPE.DOTTED_OPEN;break;case 71:this.$=b.LINETYPE.SOLID;break;case 72:this.$=b.LINETYPE.BIDIRECTIONAL_SOLID;break;case 73:this.$=b.LINETYPE.DOTTED;break;case 74:this.$=b.LINETYPE.BIDIRECTIONAL_DOTTED;break;case 75:this.$=b.LINETYPE.SOLID_CROSS;break;case 76:this.$=b.LINETYPE.DOTTED_CROSS;break;case 77:this.$=b.LINETYPE.SOLID_POINT;break;case 78:this.$=b.LINETYPE.DOTTED_POINT;break;case 79:this.$=b.parseMessage(l[u].trim().substring(1));break}},"anonymous"),table:[{3:1,4:e,5:o,6:r},{1:[3]},{3:5,4:e,5:o,6:r},{3:6,4:e,5:o,6:r},t([1,4,5,13,14,18,21,23,29,30,31,33,35,36,37,38,39,41,43,44,46,50,52,53,54,59,60,61,62,70],a,{7:7}),{1:[2,1]},{1:[2,2]},{1:[2,3],4:i,5:c,8:8,9:10,12:12,13:h,14:p,17:15,18:s,21:f,22:40,23:E,24:19,25:20,26:21,27:22,28:23,29:g,30:T,31:m,33:w,35:k,36:V,37:M,38:Y,39:C,41:z,43:H,44:Z,46:et,50:K,52:U,53:q,54:R,59:Q,60:G,61:j,62:rt,70:S},t(y,[2,5]),{9:47,12:12,13:h,14:p,17:15,18:s,21:f,22:40,23:E,24:19,25:20,26:21,27:22,28:23,29:g,30:T,31:m,33:w,35:k,36:V,37:M,38:Y,39:C,41:z,43:H,44:Z,46:et,50:K,52:U,53:q,54:R,59:Q,60:G,61:j,62:rt,70:S},t(y,[2,7]),t(y,[2,8]),t(y,[2,14]),{12:48,50:K,52:U,53:q},{15:[1,49]},{5:[1,50]},{5:[1,53],19:[1,51],20:[1,52]},{22:54,70:S},{22:55,70:S},{5:[1,56]},{5:[1,57]},{5:[1,58]},{5:[1,59]},{5:[1,60]},t(y,[2,29]),t(y,[2,30]),{32:[1,61]},{34:[1,62]},t(y,[2,33]),{15:[1,63]},{15:[1,64]},{15:[1,65]},{15:[1,66]},{15:[1,67]},{15:[1,68]},{15:[1,69]},{15:[1,70]},{22:71,70:S},{22:72,70:S},{22:73,70:S},{67:74,71:[1,75],72:[1,76],73:[1,77],74:[1,78],75:[1,79],76:[1,80],77:[1,81],78:[1,82],79:[1,83],80:[1,84]},{55:85,57:[1,86],65:[1,87],66:[1,88]},{22:89,70:S},{22:90,70:S},{22:91,70:S},{22:92,70:S},t([5,51,64,71,72,73,74,75,76,77,78,79,80,81],[2,68]),t(y,[2,6]),t(y,[2,15]),t(P,[2,9],{10:93}),t(y,[2,17]),{5:[1,95],19:[1,94]},{5:[1,96]},t(y,[2,21]),{5:[1,97]},{5:[1,98]},t(y,[2,24]),t(y,[2,25]),t(y,[2,26]),t(y,[2,27]),t(y,[2,28]),t(y,[2,31]),t(y,[2,32]),t($,a,{7:99}),t($,a,{7:100}),t($,a,{7:101}),t(it,a,{40:102,7:103}),t(N,a,{42:104,7:105}),t(N,a,{7:105,42:106}),t(Jt,a,{45:107,7:108}),t($,a,{7:109}),{5:[1,111],51:[1,110]},{5:[1,113],51:[1,112]},{5:[1,114]},{22:117,68:[1,115],69:[1,116],70:S},t(ot,[2,69]),t(ot,[2,70]),t(ot,[2,71]),t(ot,[2,72]),t(ot,[2,73]),t(ot,[2,74]),t(ot,[2,75]),t(ot,[2,76]),t(ot,[2,77]),t(ot,[2,78]),{22:118,70:S},{22:120,58:119,70:S},{70:[2,63]},{70:[2,64]},{56:121,81:dt},{56:123,81:dt},{56:124,81:dt},{56:125,81:dt},{4:[1,128],5:[1,130],11:127,12:129,16:[1,126],50:K,52:U,53:q},{5:[1,131]},t(y,[2,19]),t(y,[2,20]),t(y,[2,22]),t(y,[2,23]),{4:i,5:c,8:8,9:10,12:12,13:h,14:p,16:[1,132],17:15,18:s,21:f,22:40,23:E,24:19,25:20,26:21,27:22,28:23,29:g,30:T,31:m,33:w,35:k,36:V,37:M,38:Y,39:C,41:z,43:H,44:Z,46:et,50:K,52:U,53:q,54:R,59:Q,60:G,61:j,62:rt,70:S},{4:i,5:c,8:8,9:10,12:12,13:h,14:p,16:[1,133],17:15,18:s,21:f,22:40,23:E,24:19,25:20,26:21,27:22,28:23,29:g,30:T,31:m,33:w,35:k,36:V,37:M,38:Y,39:C,41:z,43:H,44:Z,46:et,50:K,52:U,53:q,54:R,59:Q,60:G,61:j,62:rt,70:S},{4:i,5:c,8:8,9:10,12:12,13:h,14:p,16:[1,134],17:15,18:s,21:f,22:40,23:E,24:19,25:20,26:21,27:22,28:23,29:g,30:T,31:m,33:w,35:k,36:V,37:M,38:Y,39:C,41:z,43:H,44:Z,46:et,50:K,52:U,53:q,54:R,59:Q,60:G,61:j,62:rt,70:S},{16:[1,135]},{4:i,5:c,8:8,9:10,12:12,13:h,14:p,16:[2,46],17:15,18:s,21:f,22:40,23:E,24:19,25:20,26:21,27:22,28:23,29:g,30:T,31:m,33:w,35:k,36:V,37:M,38:Y,39:C,41:z,43:H,44:Z,46:et,49:[1,136],50:K,52:U,53:q,54:R,59:Q,60:G,61:j,62:rt,70:S},{16:[1,137]},{4:i,5:c,8:8,9:10,12:12,13:h,14:p,16:[2,44],17:15,18:s,21:f,22:40,23:E,24:19,25:20,26:21,27:22,28:23,29:g,30:T,31:m,33:w,35:k,36:V,37:M,38:Y,39:C,41:z,43:H,44:Z,46:et,48:[1,138],50:K,52:U,53:q,54:R,59:Q,60:G,61:j,62:rt,70:S},{16:[1,139]},{16:[1,140]},{4:i,5:c,8:8,9:10,12:12,13:h,14:p,16:[2,42],17:15,18:s,21:f,22:40,23:E,24:19,25:20,26:21,27:22,28:23,29:g,30:T,31:m,33:w,35:k,36:V,37:M,38:Y,39:C,41:z,43:H,44:Z,46:et,47:[1,141],50:K,52:U,53:q,54:R,59:Q,60:G,61:j,62:rt,70:S},{4:i,5:c,8:8,9:10,12:12,13:h,14:p,16:[1,142],17:15,18:s,21:f,22:40,23:E,24:19,25:20,26:21,27:22,28:23,29:g,30:T,31:m,33:w,35:k,36:V,37:M,38:Y,39:C,41:z,43:H,44:Z,46:et,50:K,52:U,53:q,54:R,59:Q,60:G,61:j,62:rt,70:S},{15:[1,143]},t(y,[2,49]),{15:[1,144]},t(y,[2,51]),t(y,[2,52]),{22:145,70:S},{22:146,70:S},{56:147,81:dt},{56:148,81:dt},{56:149,81:dt},{64:[1,150],81:[2,62]},{5:[2,55]},{5:[2,79]},{5:[2,56]},{5:[2,57]},{5:[2,58]},t(y,[2,16]),t(P,[2,10]),{12:151,50:K,52:U,53:q},t(P,[2,12]),t(P,[2,13]),t(y,[2,18]),t(y,[2,34]),t(y,[2,35]),t(y,[2,36]),t(y,[2,37]),{15:[1,152]},t(y,[2,38]),{15:[1,153]},t(y,[2,39]),t(y,[2,40]),{15:[1,154]},t(y,[2,41]),{5:[1,155]},{5:[1,156]},{56:157,81:dt},{56:158,81:dt},{5:[2,67]},{5:[2,53]},{5:[2,54]},{22:159,70:S},t(P,[2,11]),t(it,a,{7:103,40:160}),t(N,a,{7:105,42:161}),t(Jt,a,{7:108,45:162}),t(y,[2,48]),t(y,[2,50]),{5:[2,65]},{5:[2,66]},{81:[2,61]},{16:[2,47]},{16:[2,45]},{16:[2,43]}],defaultActions:{5:[2,1],6:[2,2],87:[2,63],88:[2,64],121:[2,55],122:[2,79],123:[2,56],124:[2,57],125:[2,58],147:[2,67],148:[2,53],149:[2,54],157:[2,65],158:[2,66],159:[2,61],160:[2,47],161:[2,45],162:[2,43]},parseError:d(function(I,L){if(L.recoverable)this.trace(I);else{var A=new Error(I);throw A.hash=L,A}},"parseError"),parse:d(function(I){var L=this,A=[0],b=[],D=[null],l=[],mt=this.table,u="",Lt=0,Zt=0,Pe=2,Qt=1,Ae=l.slice.call(arguments,1),W=Object.create(this.lexer),ut={yy:{}};for(var Ot in this.yy)Object.prototype.hasOwnProperty.call(this.yy,Ot)&&(ut.yy[Ot]=this.yy[Ot]);W.setInput(I,ut.yy),ut.yy.lexer=W,ut.yy.parser=this,typeof W.yylloc>"u"&&(W.yylloc={});var Bt=W.yylloc;l.push(Bt);var ke=W.options&&W.options.ranges;typeof ut.yy.parseError=="function"?this.parseError=ut.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function Ne(tt){A.length=A.length-2*tt,D.length=D.length-tt,l.length=l.length-tt}d(Ne,"popStack");function jt(){var tt;return tt=b.pop()||W.lex()||Qt,typeof tt!="number"&&(tt instanceof Array&&(b=tt,tt=b.pop()),tt=L.symbols_[tt]||tt),tt}d(jt,"lex");for(var X,gt,st,Vt,yt={},Pt,ht,$t,At;;){if(gt=A[A.length-1],this.defaultActions[gt]?st=this.defaultActions[gt]:((X===null||typeof X>"u")&&(X=jt()),st=mt[gt]&&mt[gt][X]),typeof st>"u"||!st.length||!st[0]){var Yt="";At=[];for(Pt in mt[gt])this.terminals_[Pt]&&Pt>Pe&&At.push("'"+this.terminals_[Pt]+"'");W.showPosition?Yt="Parse error on line "+(Lt+1)+`:
                                       `+W.showPosition()+`
                                       Expecting `+At.join(", ")+", got '"+(this.terminals_[X]||X)+"'":Yt="Parse error on line "+(Lt+1)+": Unexpected "+(X==Qt?"end of input":"'"+(this.terminals_[X]||X)+"'"),this.parseError(Yt,{text:W.match,token:this.terminals_[X]||X,line:W.yylineno,loc:Bt,expected:At})}if(st[0]instanceof Array&&st.length>1)throw new Error("Parse Error: multiple actions possible at state: "+gt+", token: "+X);switch(st[0]){case 1:A.push(X),D.push(W.yytext),l.push(W.yylloc),A.push(st[1]),X=null,Zt=W.yyleng,u=W.yytext,Lt=W.yylineno,Bt=W.yylloc;break;case 2:if(ht=this.productions_[st[1]][1],yt.$=D[D.length-ht],yt._$={first_line:l[l.length-(ht||1)].first_line,last_line:l[l.length-1].last_line,first_column:l[l.length-(ht||1)].first_column,last_column:l[l.length-1].last_column},ke&&(yt._$.range=[l[l.length-(ht||1)].range[0],l[l.length-1].range[1]]),Vt=this.performAction.apply(yt,[u,Zt,Lt,ut.yy,st[1],D,l].concat(Ae)),typeof Vt<"u")return Vt;ht&&(A=A.slice(0,-1*ht*2),D=D.slice(0,-1*ht),l=l.slice(0,-1*ht)),A.push(this.productions_[st[1]][0]),D.push(yt.$),l.push(yt._$),$t=mt[A[A.length-2]][A[A.length-1]],A.push($t);break;case 3:return!0}}return!0},"parse")},Le=function(){var pt={EOF:1,parseError:d(function(L,A){if(this.yy.parser)this.yy.parser.parseError(L,A);else throw new Error(L)},"parseError"),setInput:d(function(I,L){return this.yy=L||this.yy||{},this._input=I,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},"setInput"),input:d(function(){var I=this._input[0];this.yytext+=I,this.yyleng++,this.offset++,this.match+=I,this.matched+=I;var L=I.match(/(?:\r\n?|\n).*/g);return L?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),I},"input"),unput:d(function(I){var L=I.length,A=I.split(/(?:\r\n?|\n)/g);this._input=I+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-L),this.offset-=L;var b=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),A.length-1&&(this.yylineno-=A.length-1);var D=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:A?(A.length===b.length?this.yylloc.first_column:0)+b[b.length-A.length].length-A[0].length:this.yylloc.first_column-L},this.options.ranges&&(this.yylloc.range=[D[0],D[0]+this.yyleng-L]),this.yyleng=this.yytext.length,this},"unput"),more:d(function(){return this._more=!0,this},"more"),reject:d(function(){if(this.options.backtrack_lexer)this._backtrack=!0;else return this.parseError("Lexical error on line "+(this.yylineno+1)+`. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).
                                       `+this.showPosition(),{text:"",token:null,line:this.yylineno});return this},"reject"),less:d(function(I){this.unput(this.match.slice(I))},"less"),pastInput:d(function(){var I=this.matched.substr(0,this.matched.length-this.match.length);return(I.length>20?"...":"")+I.substr(-20).replace(/\n/g,"")},"pastInput"),upcomingInput:d(function(){var I=this.match;return I.length<20&&(I+=this._input.substr(0,20-I.length)),(I.substr(0,20)+(I.length>20?"...":"")).replace(/\n/g,"")},"upcomingInput"),showPosition:d(function(){var I=this.pastInput(),L=new Array(I.length+1).join("-");return I+this.upcomingInput()+`
                                      diff --git a/assets/shadowsocks.html-4Bp3Pe-I.js b/assets/shadowsocks.html-1_shLAxP.js
                                      similarity index 99%
                                      rename from assets/shadowsocks.html-4Bp3Pe-I.js
                                      rename to assets/shadowsocks.html-1_shLAxP.js
                                      index c97f7bf78f..9955de55dd 100644
                                      --- a/assets/shadowsocks.html-4Bp3Pe-I.js
                                      +++ b/assets/shadowsocks.html-1_shLAxP.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as p,r as o,o as r,c as d,a as n,b as e,d as s,w as c,e as l}from"./app-DBM4OJyw.js";const u={},h=e("h1",{id:"shadowsocks",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#shadowsocks"},[e("span",null,"Shadowsocks")])],-1),k={href:"https://en.wikipedia.org/wiki/Shadowsocks",target:"_blank",rel:"noopener noreferrer"},m=l('

                                      Supported Encryption Methods

                                      The currently supported methods are following:

                                      • Recommended encryption methods:
                                        • 2022-blake3-aes-128-gcm
                                        • 2022-blake3-aes-256-gcm
                                        • 2022-blake3-chacha20-poly1305
                                      • Other encryption methods:
                                        • aes-256-gcm
                                        • aes-128-gcm
                                        • chacha20-poly1305/chacha20-ietf-poly1305
                                        • xchacha20-poly1305/xchacha20-ietf-poly1305
                                        • none/plain

                                      The Shadowsocks 2022 new protocol format improves performance and includes complete replay protection, addressing the following security issues in the old protocol:

                                      ',4),b={href:"https://github.com/shadowsocks/shadowsocks-org/issues/183",target:"_blank",rel:"noopener noreferrer"},g=e("li",null,"Increasing false positive rate of the original TCP replay filter over time",-1),v=e("li",null,"Lack of UDP replay protection",-1),f=e("li",null,"TCP behaviors that can be used for active probing",-1),y=l(`

                                      Danger

                                      Traffic transmitted without encryption using the "none" method will be in plain text. Do not use it on public networks for security reasons.

                                      InboundConfigurationObject

                                      {
                                      +import{_ as p,r as o,o as r,c as d,a as n,b as e,d as s,w as c,e as l}from"./app-D7uBbsY3.js";const u={},h=e("h1",{id:"shadowsocks",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#shadowsocks"},[e("span",null,"Shadowsocks")])],-1),k={href:"https://en.wikipedia.org/wiki/Shadowsocks",target:"_blank",rel:"noopener noreferrer"},m=l('

                                      Supported Encryption Methods

                                      The currently supported methods are following:

                                      • Recommended encryption methods:
                                        • 2022-blake3-aes-128-gcm
                                        • 2022-blake3-aes-256-gcm
                                        • 2022-blake3-chacha20-poly1305
                                      • Other encryption methods:
                                        • aes-256-gcm
                                        • aes-128-gcm
                                        • chacha20-poly1305/chacha20-ietf-poly1305
                                        • xchacha20-poly1305/xchacha20-ietf-poly1305
                                        • none/plain

                                      The Shadowsocks 2022 new protocol format improves performance and includes complete replay protection, addressing the following security issues in the old protocol:

                                      ',4),b={href:"https://github.com/shadowsocks/shadowsocks-org/issues/183",target:"_blank",rel:"noopener noreferrer"},g=e("li",null,"Increasing false positive rate of the original TCP replay filter over time",-1),v=e("li",null,"Lack of UDP replay protection",-1),f=e("li",null,"TCP behaviors that can be used for active probing",-1),y=l(`

                                      Danger

                                      Traffic transmitted without encryption using the "none" method will be in plain text. Do not use it on public networks for security reasons.

                                      InboundConfigurationObject

                                      {
                                         "settings": {
                                           "clients": [],
                                           "password": "password",
                                      diff --git a/assets/shadowsocks.html-IdnyE_QW.js b/assets/shadowsocks.html-BFqzUOKa.js
                                      similarity index 99%
                                      rename from assets/shadowsocks.html-IdnyE_QW.js
                                      rename to assets/shadowsocks.html-BFqzUOKa.js
                                      index e58beba7ee..514791f359 100644
                                      --- a/assets/shadowsocks.html-IdnyE_QW.js
                                      +++ b/assets/shadowsocks.html-BFqzUOKa.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as r,r as a,o as i,c as u,a as o,b as s,d as n,w as p,e as l}from"./app-DBM4OJyw.js";const d={},k=s("h1",{id:"shadowsocks",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#shadowsocks"},[s("span",null,"Shadowsocks")])],-1),b={href:"https://ru.wikipedia.org/wiki/Shadowsocks",target:"_blank",rel:"noopener noreferrer"},v=l("

                                      Текущая совместимость:

                                      • Поддерживает пересылку пакетов TCP и UDP, при этом UDP можно выборочно отключить;
                                      • Рекомендуемые методы шифрования:
                                        • 2022-blake3-aes-128-gcm
                                        • 2022-blake3-aes-256-gcm
                                        • 2022-blake3-chacha20-poly1305
                                      • Другие методы шифрования:
                                        • aes-256-gcm
                                        • aes-128-gcm
                                        • chacha20-poly1305 или chacha20-ietf-poly1305
                                        • xchacha20-poly1305 или xchacha20-ietf-poly1305
                                        • none или plain

                                      Новый формат протокола Shadowsocks 2022 повышает производительность и обеспечивает полную защиту от повторов, решая следующие проблемы безопасности старого протокола:

                                      ",3),h={href:"https://github.com/shadowsocks/shadowsocks-org/issues/183",target:"_blank",rel:"noopener noreferrer"},q=s("li",null,"Возрастающий коэффициент ложных срабатываний исходного фильтра повторов TCP с течением времени",-1),m=s("li",null,"Отсутствие защиты от повторов UDP",-1),g=s("li",null,"Поведение TCP, которое можно использовать для активного зондирования",-1),_=l(`

                                      Предупреждение

                                      При использовании метода шифрования "none" трафик передается в открытом виде. В целях безопасности не используйте этот метод в общедоступных сетях.

                                      OutboundConfigurationObject

                                      {
                                      +import{_ as r,r as a,o as i,c as u,a as o,b as s,d as n,w as p,e as l}from"./app-D7uBbsY3.js";const d={},k=s("h1",{id:"shadowsocks",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#shadowsocks"},[s("span",null,"Shadowsocks")])],-1),b={href:"https://ru.wikipedia.org/wiki/Shadowsocks",target:"_blank",rel:"noopener noreferrer"},v=l("

                                      Текущая совместимость:

                                      • Поддерживает пересылку пакетов TCP и UDP, при этом UDP можно выборочно отключить;
                                      • Рекомендуемые методы шифрования:
                                        • 2022-blake3-aes-128-gcm
                                        • 2022-blake3-aes-256-gcm
                                        • 2022-blake3-chacha20-poly1305
                                      • Другие методы шифрования:
                                        • aes-256-gcm
                                        • aes-128-gcm
                                        • chacha20-poly1305 или chacha20-ietf-poly1305
                                        • xchacha20-poly1305 или xchacha20-ietf-poly1305
                                        • none или plain

                                      Новый формат протокола Shadowsocks 2022 повышает производительность и обеспечивает полную защиту от повторов, решая следующие проблемы безопасности старого протокола:

                                      ",3),h={href:"https://github.com/shadowsocks/shadowsocks-org/issues/183",target:"_blank",rel:"noopener noreferrer"},q=s("li",null,"Возрастающий коэффициент ложных срабатываний исходного фильтра повторов TCP с течением времени",-1),m=s("li",null,"Отсутствие защиты от повторов UDP",-1),g=s("li",null,"Поведение TCP, которое можно использовать для активного зондирования",-1),_=l(`

                                      Предупреждение

                                      При использовании метода шифрования "none" трафик передается в открытом виде. В целях безопасности не используйте этот метод в общедоступных сетях.

                                      OutboundConfigurationObject

                                      {
                                         "servers": [
                                           {
                                             "email": "love@xray.com",
                                      diff --git a/assets/shadowsocks.html-k_BIRk0d.js b/assets/shadowsocks.html-B_N0lWJn.js
                                      similarity index 99%
                                      rename from assets/shadowsocks.html-k_BIRk0d.js
                                      rename to assets/shadowsocks.html-B_N0lWJn.js
                                      index 301557d71a..17e918e306 100644
                                      --- a/assets/shadowsocks.html-k_BIRk0d.js
                                      +++ b/assets/shadowsocks.html-B_N0lWJn.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as i,r as t,o as u,c as d,a as o,b as s,d as n,w as p,e as a}from"./app-DBM4OJyw.js";const r={},k=s("h1",{id:"shadowsocks",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#shadowsocks"},[s("span",null,"Shadowsocks")])],-1),q={href:"https://ru.wikipedia.org/wiki/Shadowsocks",target:"_blank",rel:"noopener noreferrer"},h=a("

                                      Текущая совместимость:

                                      • Поддерживает пересылку пакетов TCP и UDP, при этом UDP можно выборочно отключить;
                                      • Рекомендуемые методы шифрования:
                                        • 2022-blake3-aes-128-gcm
                                        • 2022-blake3-aes-256-gcm
                                        • 2022-blake3-chacha20-poly1305
                                      • Другие методы шифрования:
                                        • aes-256-gcm
                                        • aes-128-gcm
                                        • chacha20-poly1305 или chacha20-ietf-poly1305
                                        • xchacha20-poly1305 или xchacha20-ietf-poly1305
                                        • none или plain

                                      Новый формат протокола Shadowsocks 2022 повышает производительность и обеспечивает полную защиту от повторов, решая следующие проблемы безопасности старого протокола:

                                      ",3),b={href:"https://github.com/shadowsocks/shadowsocks-org/issues/183",target:"_blank",rel:"noopener noreferrer"},m=s("li",null,"Возрастающий коэффициент ложных срабатываний исходного фильтра повторов TCP с течением времени",-1),v=s("li",null,"Отсутствие защиты от повторов UDP",-1),g=s("li",null,"Поведение TCP, которое можно использовать для активного зондирования",-1),_=a(`

                                      Предупреждение

                                      При использовании метода шифрования "none" трафик передается в открытом виде. В целях безопасности не используйте этот метод в общедоступных сетях.

                                      InboundConfigurationObject

                                      {
                                      +import{_ as i,r as t,o as u,c as d,a as o,b as s,d as n,w as p,e as a}from"./app-D7uBbsY3.js";const r={},k=s("h1",{id:"shadowsocks",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#shadowsocks"},[s("span",null,"Shadowsocks")])],-1),q={href:"https://ru.wikipedia.org/wiki/Shadowsocks",target:"_blank",rel:"noopener noreferrer"},h=a("

                                      Текущая совместимость:

                                      • Поддерживает пересылку пакетов TCP и UDP, при этом UDP можно выборочно отключить;
                                      • Рекомендуемые методы шифрования:
                                        • 2022-blake3-aes-128-gcm
                                        • 2022-blake3-aes-256-gcm
                                        • 2022-blake3-chacha20-poly1305
                                      • Другие методы шифрования:
                                        • aes-256-gcm
                                        • aes-128-gcm
                                        • chacha20-poly1305 или chacha20-ietf-poly1305
                                        • xchacha20-poly1305 или xchacha20-ietf-poly1305
                                        • none или plain

                                      Новый формат протокола Shadowsocks 2022 повышает производительность и обеспечивает полную защиту от повторов, решая следующие проблемы безопасности старого протокола:

                                      ",3),b={href:"https://github.com/shadowsocks/shadowsocks-org/issues/183",target:"_blank",rel:"noopener noreferrer"},m=s("li",null,"Возрастающий коэффициент ложных срабатываний исходного фильтра повторов TCP с течением времени",-1),v=s("li",null,"Отсутствие защиты от повторов UDP",-1),g=s("li",null,"Поведение TCP, которое можно использовать для активного зондирования",-1),_=a(`

                                      Предупреждение

                                      При использовании метода шифрования "none" трафик передается в открытом виде. В целях безопасности не используйте этот метод в общедоступных сетях.

                                      InboundConfigurationObject

                                      {
                                         "settings": {
                                           "network": "tcp,udp",
                                           "method": "aes-256-gcm",
                                      diff --git a/assets/shadowsocks.html-DTzQHKas.js b/assets/shadowsocks.html-Dn_DI_z1.js
                                      similarity index 99%
                                      rename from assets/shadowsocks.html-DTzQHKas.js
                                      rename to assets/shadowsocks.html-Dn_DI_z1.js
                                      index ffa31c7859..91874fc73e 100644
                                      --- a/assets/shadowsocks.html-DTzQHKas.js
                                      +++ b/assets/shadowsocks.html-Dn_DI_z1.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as r,r as a,o as i,c as u,a as o,b as s,d as n,w as p,e as l}from"./app-DBM4OJyw.js";const d={},k=s("h1",{id:"shadowsocks",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#shadowsocks"},[s("span",null,"Shadowsocks")])],-1),b={href:"https://zh.wikipedia.org/wiki/Shadowsocks",target:"_blank",rel:"noopener noreferrer"},v=l("

                                      目前兼容性如下:

                                      • 支持 TCP 和 UDP 数据包转发,其中 UDP 可选择性关闭;
                                      • 推荐的加密方式:
                                        • 2022-blake3-aes-128-gcm
                                        • 2022-blake3-aes-256-gcm
                                        • 2022-blake3-chacha20-poly1305
                                      • 其他加密方式
                                        • aes-256-gcm
                                        • aes-128-gcm
                                        • chacha20-poly1305 或称 chacha20-ietf-poly1305
                                        • xchacha20-poly1305 或称 xchacha20-ietf-poly1305
                                        • none 或 plain

                                      Shadowsocks 2022 新协议格式提升了性能并带有完整的重放保护,解决了旧协议的以下安全问题:

                                      ",3),h={href:"https://github.com/shadowsocks/shadowsocks-org/issues/183",target:"_blank",rel:"noopener noreferrer"},q=s("li",null,"原有 TCP 重放过滤器误报率随时间增加",-1),m=s("li",null,"没有 UDP 重放保护",-1),g=s("li",null,"可用于主动探测的 TCP 行为",-1),_=l(`

                                      警告

                                      "none" 不加密方式下流量将明文传输。为确保安全性, 不要在公共网络上使用。

                                      OutboundConfigurationObject

                                      {
                                      +import{_ as r,r as a,o as i,c as u,a as o,b as s,d as n,w as p,e as l}from"./app-D7uBbsY3.js";const d={},k=s("h1",{id:"shadowsocks",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#shadowsocks"},[s("span",null,"Shadowsocks")])],-1),b={href:"https://zh.wikipedia.org/wiki/Shadowsocks",target:"_blank",rel:"noopener noreferrer"},v=l("

                                      目前兼容性如下:

                                      • 支持 TCP 和 UDP 数据包转发,其中 UDP 可选择性关闭;
                                      • 推荐的加密方式:
                                        • 2022-blake3-aes-128-gcm
                                        • 2022-blake3-aes-256-gcm
                                        • 2022-blake3-chacha20-poly1305
                                      • 其他加密方式
                                        • aes-256-gcm
                                        • aes-128-gcm
                                        • chacha20-poly1305 或称 chacha20-ietf-poly1305
                                        • xchacha20-poly1305 或称 xchacha20-ietf-poly1305
                                        • none 或 plain

                                      Shadowsocks 2022 新协议格式提升了性能并带有完整的重放保护,解决了旧协议的以下安全问题:

                                      ",3),h={href:"https://github.com/shadowsocks/shadowsocks-org/issues/183",target:"_blank",rel:"noopener noreferrer"},q=s("li",null,"原有 TCP 重放过滤器误报率随时间增加",-1),m=s("li",null,"没有 UDP 重放保护",-1),g=s("li",null,"可用于主动探测的 TCP 行为",-1),_=l(`

                                      警告

                                      "none" 不加密方式下流量将明文传输。为确保安全性, 不要在公共网络上使用。

                                      OutboundConfigurationObject

                                      {
                                         "servers": [
                                           {
                                             "email": "love@xray.com",
                                      diff --git a/assets/shadowsocks.html-BQ1nQK54.js b/assets/shadowsocks.html-Dqj7OTrt.js
                                      similarity index 99%
                                      rename from assets/shadowsocks.html-BQ1nQK54.js
                                      rename to assets/shadowsocks.html-Dqj7OTrt.js
                                      index 8b3eeea555..2ed24cd6b3 100644
                                      --- a/assets/shadowsocks.html-BQ1nQK54.js
                                      +++ b/assets/shadowsocks.html-Dqj7OTrt.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as i,r as t,o as u,c as d,a as o,b as s,d as n,w as p,e as a}from"./app-DBM4OJyw.js";const r={},k=s("h1",{id:"shadowsocks",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#shadowsocks"},[s("span",null,"Shadowsocks")])],-1),h={href:"https://zh.wikipedia.org/wiki/Shadowsocks",target:"_blank",rel:"noopener noreferrer"},q=a("

                                      目前兼容性如下:

                                      • 支持 TCP 和 UDP 数据包转发,其中 UDP 可选择性关闭;
                                      • 推荐的加密方式:
                                        • 2022-blake3-aes-128-gcm
                                        • 2022-blake3-aes-256-gcm
                                        • 2022-blake3-chacha20-poly1305
                                      • 其他加密方式
                                        • aes-256-gcm
                                        • aes-128-gcm
                                        • chacha20-poly1305 或称 chacha20-ietf-poly1305
                                        • xchacha20-poly1305 或称 xchacha20-ietf-poly1305
                                        • none 或 plain

                                      Shadowsocks 2022 新协议格式提升了性能并带有完整的重放保护,解决了旧协议的以下安全问题:

                                      ",3),b={href:"https://github.com/shadowsocks/shadowsocks-org/issues/183",target:"_blank",rel:"noopener noreferrer"},m=s("li",null,"原有 TCP 重放过滤器误报率随时间增加",-1),v=s("li",null,"没有 UDP 重放保护",-1),g=s("li",null,"可用于主动探测的 TCP 行为",-1),_=a(`

                                      警告

                                      "none" 不加密方式下流量将明文传输。为确保安全性, 不要在公共网络上使用。

                                      InboundConfigurationObject

                                      {
                                      +import{_ as i,r as t,o as u,c as d,a as o,b as s,d as n,w as p,e as a}from"./app-D7uBbsY3.js";const r={},k=s("h1",{id:"shadowsocks",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#shadowsocks"},[s("span",null,"Shadowsocks")])],-1),h={href:"https://zh.wikipedia.org/wiki/Shadowsocks",target:"_blank",rel:"noopener noreferrer"},q=a("

                                      目前兼容性如下:

                                      • 支持 TCP 和 UDP 数据包转发,其中 UDP 可选择性关闭;
                                      • 推荐的加密方式:
                                        • 2022-blake3-aes-128-gcm
                                        • 2022-blake3-aes-256-gcm
                                        • 2022-blake3-chacha20-poly1305
                                      • 其他加密方式
                                        • aes-256-gcm
                                        • aes-128-gcm
                                        • chacha20-poly1305 或称 chacha20-ietf-poly1305
                                        • xchacha20-poly1305 或称 xchacha20-ietf-poly1305
                                        • none 或 plain

                                      Shadowsocks 2022 新协议格式提升了性能并带有完整的重放保护,解决了旧协议的以下安全问题:

                                      ",3),b={href:"https://github.com/shadowsocks/shadowsocks-org/issues/183",target:"_blank",rel:"noopener noreferrer"},m=s("li",null,"原有 TCP 重放过滤器误报率随时间增加",-1),v=s("li",null,"没有 UDP 重放保护",-1),g=s("li",null,"可用于主动探测的 TCP 行为",-1),_=a(`

                                      警告

                                      "none" 不加密方式下流量将明文传输。为确保安全性, 不要在公共网络上使用。

                                      InboundConfigurationObject

                                      {
                                         "settings": {
                                           "network": "tcp,udp",
                                           "method": "aes-256-gcm",
                                      diff --git a/assets/shadowsocks.html-CDcJbYW-.js b/assets/shadowsocks.html-nM24MAPY.js
                                      similarity index 99%
                                      rename from assets/shadowsocks.html-CDcJbYW-.js
                                      rename to assets/shadowsocks.html-nM24MAPY.js
                                      index 77499d90b0..5178294d23 100644
                                      --- a/assets/shadowsocks.html-CDcJbYW-.js
                                      +++ b/assets/shadowsocks.html-nM24MAPY.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as i,r as o,o as c,c as d,a as n,b as e,d as s,w as p,e as l}from"./app-DBM4OJyw.js";const u={},h=e("h1",{id:"shadowsocks",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#shadowsocks"},[e("span",null,"Shadowsocks")])],-1),k={href:"https://en.wikipedia.org/wiki/Shadowsocks",target:"_blank",rel:"noopener noreferrer"},m=l("

                                      Here are the features and compatibility of Shadowsocks:

                                      • It supports TCP and UDP packet forwarding, with the option to disable UDP.
                                      • Recommended encryption methods:
                                        • 2022-blake3-aes-128-gcm
                                        • 2022-blake3-aes-256-gcm
                                        • 2022-blake3-chacha20-poly1305
                                      • Other encryption methods:
                                        • aes-256-gcm
                                        • aes-128-gcm
                                        • chacha20-poly1305 (also known as chacha20-ietf-poly1305)
                                        • none or plain

                                      The new protocol format of Shadowsocks 2022 improves performance and includes full replay protection, addressing security issues present in the old protocol:

                                      ",3),b={href:"https://github.com/shadowsocks/shadowsocks-org/issues/183",target:"_blank",rel:"noopener noreferrer"},v=e("li",null,"Increasing false-positive rate of TCP replay filters over time",-1),q=e("li",null,"Lack of replay protection for UDP",-1),g=e("li",null,"TCP behaviors that can be used for active probing",-1),y=l(`

                                      Danger

                                      Using the "none" encryption method will transmit traffic in plaintext. It is not recommended to use "none" encryption on public networks to ensure security.

                                      OutboundConfigurationObject

                                      {
                                      +import{_ as i,r as o,o as c,c as d,a as n,b as e,d as s,w as p,e as l}from"./app-D7uBbsY3.js";const u={},h=e("h1",{id:"shadowsocks",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#shadowsocks"},[e("span",null,"Shadowsocks")])],-1),k={href:"https://en.wikipedia.org/wiki/Shadowsocks",target:"_blank",rel:"noopener noreferrer"},m=l("

                                      Here are the features and compatibility of Shadowsocks:

                                      • It supports TCP and UDP packet forwarding, with the option to disable UDP.
                                      • Recommended encryption methods:
                                        • 2022-blake3-aes-128-gcm
                                        • 2022-blake3-aes-256-gcm
                                        • 2022-blake3-chacha20-poly1305
                                      • Other encryption methods:
                                        • aes-256-gcm
                                        • aes-128-gcm
                                        • chacha20-poly1305 (also known as chacha20-ietf-poly1305)
                                        • none or plain

                                      The new protocol format of Shadowsocks 2022 improves performance and includes full replay protection, addressing security issues present in the old protocol:

                                      ",3),b={href:"https://github.com/shadowsocks/shadowsocks-org/issues/183",target:"_blank",rel:"noopener noreferrer"},v=e("li",null,"Increasing false-positive rate of TCP replay filters over time",-1),q=e("li",null,"Lack of replay protection for UDP",-1),g=e("li",null,"TCP behaviors that can be used for active probing",-1),y=l(`

                                      Danger

                                      Using the "none" encryption method will transmit traffic in plaintext. It is not recommended to use "none" encryption on public networks to ensure security.

                                      OutboundConfigurationObject

                                      {
                                         "servers": [
                                           {
                                             "email": "love@xray.com",
                                      diff --git a/assets/socks.html-D6GgkO4d.js b/assets/socks.html-BjLWN2Q8.js
                                      similarity index 98%
                                      rename from assets/socks.html-D6GgkO4d.js
                                      rename to assets/socks.html-BjLWN2Q8.js
                                      index dba09898fa..59edbd8b0f 100644
                                      --- a/assets/socks.html-D6GgkO4d.js
                                      +++ b/assets/socks.html-BjLWN2Q8.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as l,r as e,o as r,c as i,a as o,b as n,d as s,w as c,e as p}from"./app-DBM4OJyw.js";const d={},k=n("h1",{id:"socks",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#socks"},[n("span",null,"Socks")])],-1),b={href:"http://ftp.icm.edu.pl/packages/socks/socks4/SOCKS4.protocol",target:"_blank",rel:"noopener noreferrer"},q={href:"https://ftp.icm.edu.pl/packages/socks/socks4/SOCKS4A.protocol",target:"_blank",rel:"noopener noreferrer"},v=n("strong",null,"HTTP",-1),m=p(`

                                      警告

                                      Socks 协议没有对传输加密,不适宜经公网中传输

                                      Socks 入站更有意义的用法是在局域网或本机环境下监听,为其他程序提供本地服务。

                                      InboundConfigurationObject

                                      {
                                      +import{_ as l,r as e,o as r,c as i,a as o,b as n,d as s,w as c,e as p}from"./app-D7uBbsY3.js";const d={},k=n("h1",{id:"socks",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#socks"},[n("span",null,"Socks")])],-1),b={href:"http://ftp.icm.edu.pl/packages/socks/socks4/SOCKS4.protocol",target:"_blank",rel:"noopener noreferrer"},q={href:"https://ftp.icm.edu.pl/packages/socks/socks4/SOCKS4A.protocol",target:"_blank",rel:"noopener noreferrer"},v=n("strong",null,"HTTP",-1),m=p(`

                                      警告

                                      Socks 协议没有对传输加密,不适宜经公网中传输

                                      Socks 入站更有意义的用法是在局域网或本机环境下监听,为其他程序提供本地服务。

                                      InboundConfigurationObject

                                      {
                                         "auth": "noauth",
                                         "accounts": [
                                           {
                                      diff --git a/assets/socks.html-Bo00BDL8.js b/assets/socks.html-BqrlqbK0.js
                                      similarity index 99%
                                      rename from assets/socks.html-Bo00BDL8.js
                                      rename to assets/socks.html-BqrlqbK0.js
                                      index 088600b818..b03cba58b9 100644
                                      --- a/assets/socks.html-Bo00BDL8.js
                                      +++ b/assets/socks.html-BqrlqbK0.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as c,r as o,o as l,c as r,a as n,b as a,d as s,w as t,e as u}from"./app-DBM4OJyw.js";const i={},d=u(`

                                      Socks

                                      标准 Socks 协议实现,兼容 Socks 5。

                                      警告

                                      Socks 协议没有对传输加密,不适宜经公网中传输

                                      OutboundConfigurationObject

                                      {
                                      +import{_ as c,r as o,o as l,c as r,a as n,b as a,d as s,w as t,e as u}from"./app-D7uBbsY3.js";const i={},d=u(`

                                      Socks

                                      标准 Socks 协议实现,兼容 Socks 5。

                                      警告

                                      Socks 协议没有对传输加密,不适宜经公网中传输

                                      OutboundConfigurationObject

                                      {
                                         "servers": [
                                           {
                                             "address": "127.0.0.1",
                                      diff --git a/assets/socks.html-CMWA8dIs.js b/assets/socks.html-CXgansFd.js
                                      similarity index 99%
                                      rename from assets/socks.html-CMWA8dIs.js
                                      rename to assets/socks.html-CXgansFd.js
                                      index 50f0db791d..25775744a3 100644
                                      --- a/assets/socks.html-CMWA8dIs.js
                                      +++ b/assets/socks.html-CXgansFd.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as l,r as e,o as r,c as i,a as o,b as n,d as s,w as c,e as p}from"./app-DBM4OJyw.js";const d={},k=n("h1",{id:"socks",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#socks"},[n("span",null,"Socks")])],-1),b={href:"http://ftp.icm.edu.pl/packages/socks/socks4/SOCKS4.protocol",target:"_blank",rel:"noopener noreferrer"},q={href:"https://ftp.icm.edu.pl/packages/socks/socks4/SOCKS4A.protocol",target:"_blank",rel:"noopener noreferrer"},v=p(`

                                      Предупреждение

                                      Протокол Socks не обеспечивает шифрование передачи данных, поэтому он не подходит для передачи данных через общедоступные сети.

                                      Использование входящих соединений SOCKS более целесообразно в локальной сети или локальной среде, где он может быть использован для прослушивания входящих подключений и предоставления локальных сервисов другим программам.

                                      InboundConfigurationObject

                                      {
                                      +import{_ as l,r as e,o as r,c as i,a as o,b as n,d as s,w as c,e as p}from"./app-D7uBbsY3.js";const d={},k=n("h1",{id:"socks",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#socks"},[n("span",null,"Socks")])],-1),b={href:"http://ftp.icm.edu.pl/packages/socks/socks4/SOCKS4.protocol",target:"_blank",rel:"noopener noreferrer"},q={href:"https://ftp.icm.edu.pl/packages/socks/socks4/SOCKS4A.protocol",target:"_blank",rel:"noopener noreferrer"},v=p(`

                                      Предупреждение

                                      Протокол Socks не обеспечивает шифрование передачи данных, поэтому он не подходит для передачи данных через общедоступные сети.

                                      Использование входящих соединений SOCKS более целесообразно в локальной сети или локальной среде, где он может быть использован для прослушивания входящих подключений и предоставления локальных сервисов другим программам.

                                      InboundConfigurationObject

                                      {
                                         "auth": "noauth",
                                         "accounts": [
                                           {
                                      diff --git a/assets/socks.html-4M7JIsdb.js b/assets/socks.html-CdTGmIt-.js
                                      similarity index 98%
                                      rename from assets/socks.html-4M7JIsdb.js
                                      rename to assets/socks.html-CdTGmIt-.js
                                      index 75a835fa6b..e1d9ec5fb4 100644
                                      --- a/assets/socks.html-4M7JIsdb.js
                                      +++ b/assets/socks.html-CdTGmIt-.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as r,r as s,o as u,c as i,a as o,b as n,d as e,w as c,e as p}from"./app-DBM4OJyw.js";const d={},k=n("h1",{id:"socks",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#socks"},[n("span",null,"SOCKS")])],-1),h={href:"http://ftp.icm.edu.pl/packages/socks/socks4/SOCKS4.protocol",target:"_blank",rel:"noopener noreferrer"},v={href:"http://ftp.icm.edu.pl/packages/socks/socks4/SOCKS4.protocol",target:"_blank",rel:"noopener noreferrer"},b=p(`

                                      Danger

                                      The SOCKS protocol does not provide encryption for transport and is not suitable for transmitting data over public networks.

                                      The use of SOCKS inbound is more meaningful in a local area network or local environment, where it can be used to listen for incoming connections and provide local services to other programs.

                                      InboundConfigurationObject

                                      {
                                      +import{_ as r,r as s,o as u,c as i,a as o,b as n,d as e,w as c,e as p}from"./app-D7uBbsY3.js";const d={},k=n("h1",{id:"socks",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#socks"},[n("span",null,"SOCKS")])],-1),h={href:"http://ftp.icm.edu.pl/packages/socks/socks4/SOCKS4.protocol",target:"_blank",rel:"noopener noreferrer"},v={href:"http://ftp.icm.edu.pl/packages/socks/socks4/SOCKS4.protocol",target:"_blank",rel:"noopener noreferrer"},b=p(`

                                      Danger

                                      The SOCKS protocol does not provide encryption for transport and is not suitable for transmitting data over public networks.

                                      The use of SOCKS inbound is more meaningful in a local area network or local environment, where it can be used to listen for incoming connections and provide local services to other programs.

                                      InboundConfigurationObject

                                      {
                                         "auth": "noauth",
                                         "accounts": [
                                           {
                                      diff --git a/assets/socks.html-COrUwqQj.js b/assets/socks.html-Cf97X7VI.js
                                      similarity index 99%
                                      rename from assets/socks.html-COrUwqQj.js
                                      rename to assets/socks.html-Cf97X7VI.js
                                      index 14bbe3cab0..d4012cad65 100644
                                      --- a/assets/socks.html-COrUwqQj.js
                                      +++ b/assets/socks.html-Cf97X7VI.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as r,r as a,o as i,c as l,a as e,b as n,d as s,w as o,e as u}from"./app-DBM4OJyw.js";const d={},k=n("h1",{id:"socks",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#socks"},[n("span",null,"Socks")])],-1),v={href:"http://ftp.icm.edu.pl/packages/socks/socks4/SOCKS4.protocol",target:"_blank",rel:"noopener noreferrer"},b=u(`

                                      Danger

                                      The Socks protocol does not provide encryption for transmission and is not suitable for transmitting data over public networks.

                                      OutboundConfigurationObject

                                      {
                                      +import{_ as r,r as a,o as i,c as l,a as e,b as n,d as s,w as o,e as u}from"./app-D7uBbsY3.js";const d={},k=n("h1",{id:"socks",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#socks"},[n("span",null,"Socks")])],-1),v={href:"http://ftp.icm.edu.pl/packages/socks/socks4/SOCKS4.protocol",target:"_blank",rel:"noopener noreferrer"},b=u(`

                                      Danger

                                      The Socks protocol does not provide encryption for transmission and is not suitable for transmitting data over public networks.

                                      OutboundConfigurationObject

                                      {
                                         "servers": [
                                           {
                                             "address": "127.0.0.1",
                                      diff --git a/assets/socks.html-DN04JS2D.js b/assets/socks.html-D_fUXvUa.js
                                      similarity index 99%
                                      rename from assets/socks.html-DN04JS2D.js
                                      rename to assets/socks.html-D_fUXvUa.js
                                      index 3957f7428b..a206da4fe2 100644
                                      --- a/assets/socks.html-DN04JS2D.js
                                      +++ b/assets/socks.html-D_fUXvUa.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as l,r as e,o as r,c as u,a,b as n,d as s,w as p,e as i}from"./app-DBM4OJyw.js";const d={},k=n("h1",{id:"socks",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#socks"},[n("span",null,"Socks")])],-1),v={href:"http://ftp.icm.edu.pl/packages/socks/socks4/SOCKS4.protocol",target:"_blank",rel:"noopener noreferrer"},b={href:"https://ftp.icm.edu.pl/packages/socks/socks4/SOCKS4A.protocol",target:"_blank",rel:"noopener noreferrer"},m=i(`

                                      Предупреждение

                                      Протокол Socks не обеспечивает шифрования передачи, поэтому он не подходит для передачи данных через общедоступные сети.

                                      OutboundConfigurationObject

                                      {
                                      +import{_ as l,r as e,o as r,c as u,a,b as n,d as s,w as p,e as i}from"./app-D7uBbsY3.js";const d={},k=n("h1",{id:"socks",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#socks"},[n("span",null,"Socks")])],-1),v={href:"http://ftp.icm.edu.pl/packages/socks/socks4/SOCKS4.protocol",target:"_blank",rel:"noopener noreferrer"},b={href:"https://ftp.icm.edu.pl/packages/socks/socks4/SOCKS4A.protocol",target:"_blank",rel:"noopener noreferrer"},m=i(`

                                      Предупреждение

                                      Протокол Socks не обеспечивает шифрования передачи, поэтому он не подходит для передачи данных через общедоступные сети.

                                      OutboundConfigurationObject

                                      {
                                         "servers": [
                                           {
                                             "address": "127.0.0.1",
                                      diff --git a/assets/splithttp.html-C1SjdxYM.js b/assets/splithttp.html-B8IT_7av.js
                                      similarity index 92%
                                      rename from assets/splithttp.html-C1SjdxYM.js
                                      rename to assets/splithttp.html-B8IT_7av.js
                                      index de383a1689..5b5aed767a 100644
                                      --- a/assets/splithttp.html-C1SjdxYM.js
                                      +++ b/assets/splithttp.html-B8IT_7av.js
                                      @@ -1 +1 @@
                                      -const t=JSON.parse('{"key":"v-32d545e2","path":"/ru/config/transports/splithttp.html","title":"SplitHTTP","lang":"ru-RU","frontmatter":{},"headers":[{"level":2,"title":"SplitHttpObject","slug":"splithttpobject","link":"#splithttpobject","children":[]},{"level":2,"title":"Детали протокола","slug":"детали-протокола","link":"#детали-протокола","children":[]},{"level":2,"title":"BrowserDialer","slug":"browserdialer","link":"#browserdialer","children":[]}],"git":{"updatedTime":1721310056000,"contributors":[{"name":"Nikita Korotaev","email":"104270279+iambabyninja@users.noreply.github.com","commits":2}]},"filePathRelative":"ru/config/transports/splithttp.md","i18n":{"pathLocale":"/ru/","sourceLink":"/config/transports/splithttp.html","untranslated":false,"updatedTime":1721310056000,"sourceUpdatedTime":1726650704000,"outdated":true}}');export{t as data};
                                      +const t=JSON.parse('{"key":"v-32d545e2","path":"/ru/config/transports/splithttp.html","title":"SplitHTTP","lang":"ru-RU","frontmatter":{},"headers":[{"level":2,"title":"SplitHttpObject","slug":"splithttpobject","link":"#splithttpobject","children":[]},{"level":2,"title":"Детали протокола","slug":"детали-протокола","link":"#детали-протокола","children":[]},{"level":2,"title":"BrowserDialer","slug":"browserdialer","link":"#browserdialer","children":[]}],"git":{"updatedTime":1721310056000,"contributors":[{"name":"Nikita Korotaev","email":"104270279+iambabyninja@users.noreply.github.com","commits":2}]},"filePathRelative":"ru/config/transports/splithttp.md","i18n":{"pathLocale":"/ru/","sourceLink":"/config/transports/splithttp.html","untranslated":false,"updatedTime":1721310056000,"sourceUpdatedTime":1726657034000,"outdated":true}}');export{t as data};
                                      diff --git a/assets/splithttp.html-Ewo4WhOB.js b/assets/splithttp.html-BE0bqGcK.js
                                      similarity index 95%
                                      rename from assets/splithttp.html-Ewo4WhOB.js
                                      rename to assets/splithttp.html-BE0bqGcK.js
                                      index b61cd890d0..9ebbf8abe7 100644
                                      --- a/assets/splithttp.html-Ewo4WhOB.js
                                      +++ b/assets/splithttp.html-BE0bqGcK.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as l,r as n,o as p,c as d,a as t,b as e,d as o,w as u,e as i}from"./app-DBM4OJyw.js";const h={},m=e("h1",{id:"splithttp",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#splithttp"},[e("span",null,"SplitHTTP")])],-1),b=i(`

                                      Uses HTTP chunked-transfer encoding for download, and multiple HTTP requests for upload.

                                      Can be deployed on CDNs that do not support WebSocket. However, the CDN must support HTTP chunked transfer encoding in a streaming fashion, no response buffering.

                                      This transport serves the same purpose as Meek (support non-WS CDN). It has the above streaming requirement to the CDN so that download can be much faster than (v2fly) Meek, close to WebSocket performance. The upload is also optimized, but still much more limited than WebSocket.

                                      Like WebSocket transport, SplitHTTP parses the X-Forwarded-For header for logging.

                                      SplitHttpObject

                                      The SplitHttpObject corresponds to the splithttpSettings section under transport configurations.

                                      {
                                      +import{_ as l,r as n,o as p,c as d,a as t,b as e,d as o,w as u,e as i}from"./app-D7uBbsY3.js";const h={},m=e("h1",{id:"splithttp",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#splithttp"},[e("span",null,"SplitHTTP")])],-1),b=i(`

                                      Uses HTTP chunked-transfer encoding for download, and multiple HTTP requests for upload.

                                      Can be deployed on CDNs that do not support WebSocket. However, the CDN must support HTTP chunked transfer encoding in a streaming fashion, no response buffering.

                                      This transport serves the same purpose as Meek (support non-WS CDN). It has the above streaming requirement to the CDN so that download can be much faster than (v2fly) Meek, close to WebSocket performance. The upload is also optimized, but still much more limited than WebSocket.

                                      Like WebSocket transport, SplitHTTP parses the X-Forwarded-For header for logging.

                                      SplitHttpObject

                                      The SplitHttpObject corresponds to the splithttpSettings section under transport configurations.

                                      {
                                         "path": "/",
                                         "host": "xray.com",
                                         "headers": {
                                      @@ -10,10 +10,10 @@ import{_ as l,r as n,o as p,c as d,a as t,b as e,d as o,w as u,e as i}from"./app
                                         "noSSEHeader": false,
                                         "xPaddingBytes": "100-1000",
                                         "xmux": {
                                      -    "maxConnections": 0,
                                           "maxConcurrency": 0,
                                      +    "maxConnections": 0,
                                           "cMaxReuseTimes": 0,
                                           "cMaxLifetimeMs": 0
                                         }
                                       }
                                      -

                                      path: string

                                      HTTP path used by the connection. Defaults to "/".

                                      host: string

                                      HTTP Host sent by the connection. Empty by default. If this value is empty on the server, the host header sent by clients will not be validated.

                                      If the Host header has been defined on the server in any way, the server will validate if the Host header matches.

                                      The current priority of the Host header sent by clients: host > headers > address

                                      headers: map {string: string}

                                      Customized HTTP headers defined in key-value pairs. Defaults to empty.

                                      scMaxEachPostBytes: int/string

                                      The maximum size of upload chunks, in bytes. Defaults to 1MB.

                                      The size set by the client must be lower than this value, otherwise when the POST request is sent larger than the value set by the server, the request will be rejected.

                                      This value should be smaller than the maximum request body allowed by the CDN or other HTTP reverse proxy, otherwise an HTTP 413 error will be thrown.

                                      It can also be in the form of a string "1000000-2000000". The core will randomly select a value within the range each time to reduce fingerprints.

                                      scMaxConcurrentPosts: int/string

                                      The number of concurrent uploads to run. Defaults to 100 on the client, and 200 on the server.

                                      The value on the client must not be higher than on the server. Otherwise, connectivity issues will occur. In practice, the upload concurrency is also limited by minUploadIntervalMs, so the actual concurrency on the client side will be much lower.

                                      It can also be in the form of a string "100-200", and the core will randomly select a value within the range each time to reduce fingerprints.

                                      scMinPostsIntervalMs: int/string

                                      (Client-only) How much time to pass between upload requests at a minimum. Defaults to 30 (milliseconds).

                                      It can also be in the form of a string "10-50", and the core will randomly select a value within the range each time to reduce fingerprints.

                                      noSSEHeader

                                      (Server-only) Do not send the Content-Type: text/event-stream response header. Defaults to false (the header will be sent)

                                      xPaddingBytes

                                      Added in 1.8.24

                                      Control the padding of requests and responses. Defaults to "100-1000", meaning that each GET and POST will be padded with a random amount of bytes in that range.

                                      A value of -1 disables padding entirely.

                                      You can lower this to save bandwidth or increase it to improve censorship resistance. Too much padding may cause the CDN to reject traffic.

                                      xmux

                                      Added in 24.9.16

                                      Control the way that SplitHTTP distributes sub-connections (H2 stream or QUIC stream) on "physical" TCP/QUIC connections. The default behavior is to put all sub-connections of an outbound onto a single physical connection, which is basically equal to using mux.cool with concurrency=999999999.

                                      It is recommended to tweak this transport-specific xmux instead of the global mux key (mux.cool) for better performance, especially on QUIC/H3 connections. That said, either one may be useful to work around certain connectivity issues (and bugs in xray or other software).

                                      • maxConnections: Default 0 = infinite. The number of physical connections to open. Every sub-connection will open a new connection until this value is reached, only then connections will be reused. Mutually exclusive with maxConcurrency.

                                      • maxConcurrency: Default 0 = infinite. The maximum number of sub-connections to put onto a physical connection. New physical connections will be opened to stay under this limit overall. Mutually exclusive with maxConnections. Equivalent to mux.cool's concurrency.

                                      • cMaxReuseTimes: Default 0 = infinite. Stop re-using a physical connection after it has been used for this many sub-connections.

                                      • cMaxLifetimeMs: Default 0 = infinite. Stop re-using a physical connection after it has been open for this many milliseconds.

                                      HTTP versions

                                      Added in 1.8.21: HTTP/3 support

                                      SplitHTTP supports http/1.1, h2 and h3 ALPN values. If the value is not set, h2 (prior-knowledge) is assumed when TLS is enabled, and http/1.1 without TLS. If the value is set to h3, the client will attempt to connect as HTTP/3, so UDP instead of TCP.

                                      The server listens to HTTP/1.1 and h2 by default, but if h3 ALPN is set on the server, it will listen as HTTP/3.

                                      Please note that nginx, Caddy and all CDN will almost certainly translate client requests to a different HTTP version for forwarding, and so the server may have to be configured with a different ALPN value than the client. If you use a CDN, it is very unlikely that h3 is a correct value for the server, even if the client speaks h3.

                                      Troubleshooting

                                      • If a connection hangs, the CDN may not support streaming downloads. You can use curl -Nv https://example.com/abcdef to initiate a download and see for yourself (see protocol details).

                                        If you do not see 200 OK and a response body of ok, then the CDN is buffering the response body. Please ensure that all HTTP middleboxes along the path between client and server observe X-Accel-Buffering: no from their origin server. If your chain is xray -> nginx -> CDN -> xray, nginx may strip this response header and you have to re-add it.

                                      Browser Dialer

                                      `,47),f=e("h2",{id:"protocol-details",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#protocol-details"},[e("span",null,"Protocol details")])],-1),y={href:"https://github.com/XTLS/Xray-core/pull/3412",target:"_blank",rel:"noopener noreferrer"},v={href:"https://github.com/XTLS/Xray-core/pull/3462",target:"_blank",rel:"noopener noreferrer"},k=i("
                                      1. GET /<UUID> opens the download. The server immediately responds with 200 OK, and immediately sends the string ok (arbitrary length, such as ooook) to force HTTP middleboxes into flushing headers.

                                        The server will send these headers:

                                        • X-Accel-Buffering: no to prevent response buffering in nginx and CDN
                                        • Content-Type: text/event-stream to prevent response buffering in some CDN, can be disabled with noSSEHeader
                                        • Transfer-Encoding: chunked in HTTP/1.1 only
                                        • Cache-Control: no-store to disable any potential response caching.
                                      2. Client uploads using POST /<UUID>/<seq>. seq starts at 0 and can be used like TCP seq number, and multiple "packets" may be sent concurrently. The server has to reassemble the "packets" live. The sequence number never resets for simplicity reasons.

                                        The client may open upload and download in any order, either one starts a session. However, eventually GET needs to be opened (current deadline is hardcoded to 30 seconds) If not, the session will be terminated.

                                      3. The GET request is kept open until the tunneled connection has to be terminated. Either server or client can close.

                                        How this actually works depends on the HTTP version. For example, in HTTP/1.1 it is only possible to disrupt chunked-transfer by closing the TCP connection, in other versions the stream is closed or aborted.

                                      Recommendations:

                                      • Do not assume any custom headers are transferred correctly by the CDN. This transport is built for CDN who do not support WebSocket, these CDN tend to not be very modern (or good).

                                      • It should be assumed there is no streaming upload within a HTTP request, so the size of a packet should be chosen to optimize between latency, throughput, and any size limits imposed by the CDN (just like TCP, nagle's algorithm and MTU...)

                                      • HTTP/1.1 and h2 should be supported by server and client, and it should be expected that the CDN will translate arbitrarily between versions. A HTTP/1.1 server may indirectly end up talking to a h2 client, and vice versa.

                                      ",3);function T(g,q){const r=n("I18nTip"),s=n("Badge"),c=n("RouterLink"),a=n("ExternalLinkIcon");return p(),d("div",null,[t(r),m,t(s,{text:"v1.8.16+",type:"warning"}),b,t(s,{text:"v1.8.17+",type:"warning"}),e("p",null,[o("If uTLS is not enough, SplitHTTP's TLS can be handled by a browser using "),t(c,{to:"/en/config/features/browser_dialer.html"},{default:u(()=>[o("Browser Dialer")]),_:1})]),f,e("p",null,[o("See "),e("a",y,[o("#3412"),t(a)]),o(" and "),e("a",v,[o("#3462"),t(a)]),o(" for extensive discussion and revision of the protocol. Here is a summary, and the minimum needed to be compatible:")]),k])}const x=l(h,[["render",T],["__file","splithttp.html.vue"]]);export{x as default}; +

                                      path: string

                                      HTTP path used by the connection. Defaults to "/".

                                      host: string

                                      HTTP Host sent by the connection. Empty by default. If this value is empty on the server, the host header sent by clients will not be validated.

                                      If the Host header has been defined on the server in any way, the server will validate if the Host header matches.

                                      The current priority of the Host header sent by clients: host > headers > address

                                      headers: map {string: string}

                                      Customized HTTP headers defined in key-value pairs. Defaults to empty.

                                      scMaxEachPostBytes: int/string

                                      The maximum size of upload chunks, in bytes. Defaults to 1MB.

                                      The size set by the client must be lower than this value, otherwise when the POST request is sent larger than the value set by the server, the request will be rejected.

                                      This value should be smaller than the maximum request body allowed by the CDN or other HTTP reverse proxy, otherwise an HTTP 413 error will be thrown.

                                      It can also be in the form of a string "1000000-2000000". The core will randomly select a value within the range each time to reduce fingerprints.

                                      scMaxConcurrentPosts: int/string

                                      The number of concurrent uploads to run. Defaults to 100 on the client, and 200 on the server.

                                      The value on the client must not be higher than on the server. Otherwise, connectivity issues will occur. In practice, the upload concurrency is also limited by minUploadIntervalMs, so the actual concurrency on the client side will be much lower.

                                      It can also be in the form of a string "100-200", and the core will randomly select a value within the range each time to reduce fingerprints.

                                      scMinPostsIntervalMs: int/string

                                      (Client-only) How much time to pass between upload requests at a minimum. Defaults to 30 (milliseconds).

                                      It can also be in the form of a string "10-50", and the core will randomly select a value within the range each time to reduce fingerprints.

                                      noSSEHeader

                                      (Server-only) Do not send the Content-Type: text/event-stream response header. Defaults to false (the header will be sent)

                                      xPaddingBytes

                                      Added in 1.8.24

                                      Control the padding of requests and responses. Defaults to "100-1000", meaning that each GET and POST will be padded with a random amount of bytes in that range.

                                      A value of -1 disables padding entirely.

                                      You can lower this to save bandwidth or increase it to improve censorship resistance. Too much padding may cause the CDN to reject traffic.

                                      xmux

                                      Added in 24.9.16

                                      Control the way that SplitHTTP distributes sub-connections (H2 stream or QUIC stream) on "physical" TCP/QUIC connections. The default behavior is to put all sub-connections of an outbound onto a single physical connection, which is basically equal to using mux.cool with concurrency=999999999.

                                      It is recommended to tweak this transport-specific xmux instead of the global mux key (mux.cool) for better performance, especially on QUIC/H3 connections. That said, either one may be useful to work around certain connectivity issues (and bugs in xray or other software).

                                      • maxConcurrency: Default 0 = infinite. The maximum number of sub-connections to put onto a physical connection. New physical connections will be opened to stay under this limit overall. Mutually exclusive with maxConnections. Equivalent to mux.cool's concurrency.

                                      • maxConnections: Default 0 = infinite. The number of physical connections to open. Every sub-connection will open a new connection until this value is reached, only then connections will be reused. Mutually exclusive with maxConcurrency.

                                      • cMaxReuseTimes: Default 0 = infinite. Stop re-using a physical connection after it has been used for this many sub-connections.

                                      • cMaxLifetimeMs: Default 0 = infinite. Stop re-using a physical connection after it has been open for this many milliseconds.

                                      HTTP versions

                                      Added in 1.8.21: HTTP/3 support

                                      SplitHTTP supports http/1.1, h2 and h3 ALPN values. If the value is not set, h2 (prior-knowledge) is assumed when TLS is enabled, and http/1.1 without TLS. If the value is set to h3, the client will attempt to connect as HTTP/3, so UDP instead of TCP.

                                      The server listens to HTTP/1.1 and h2 by default, but if h3 ALPN is set on the server, it will listen as HTTP/3.

                                      Please note that nginx, Caddy and all CDN will almost certainly translate client requests to a different HTTP version for forwarding, and so the server may have to be configured with a different ALPN value than the client. If you use a CDN, it is very unlikely that h3 is a correct value for the server, even if the client speaks h3.

                                      Troubleshooting

                                      • If a connection hangs, the CDN may not support streaming downloads. You can use curl -Nv https://example.com/abcdef to initiate a download and see for yourself (see protocol details).

                                        If you do not see 200 OK and a response body of ok, then the CDN is buffering the response body. Please ensure that all HTTP middleboxes along the path between client and server observe X-Accel-Buffering: no from their origin server. If your chain is xray -> nginx -> CDN -> xray, nginx may strip this response header and you have to re-add it.

                                      Browser Dialer

                                      `,47),f=e("h2",{id:"protocol-details",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#protocol-details"},[e("span",null,"Protocol details")])],-1),y={href:"https://github.com/XTLS/Xray-core/pull/3412",target:"_blank",rel:"noopener noreferrer"},v={href:"https://github.com/XTLS/Xray-core/pull/3462",target:"_blank",rel:"noopener noreferrer"},k=i("
                                      1. GET /<UUID> opens the download. The server immediately responds with 200 OK, and immediately sends the string ok (arbitrary length, such as ooook) to force HTTP middleboxes into flushing headers.

                                        The server will send these headers:

                                        • X-Accel-Buffering: no to prevent response buffering in nginx and CDN
                                        • Content-Type: text/event-stream to prevent response buffering in some CDN, can be disabled with noSSEHeader
                                        • Transfer-Encoding: chunked in HTTP/1.1 only
                                        • Cache-Control: no-store to disable any potential response caching.
                                      2. Client uploads using POST /<UUID>/<seq>. seq starts at 0 and can be used like TCP seq number, and multiple "packets" may be sent concurrently. The server has to reassemble the "packets" live. The sequence number never resets for simplicity reasons.

                                        The client may open upload and download in any order, either one starts a session. However, eventually GET needs to be opened (current deadline is hardcoded to 30 seconds) If not, the session will be terminated.

                                      3. The GET request is kept open until the tunneled connection has to be terminated. Either server or client can close.

                                        How this actually works depends on the HTTP version. For example, in HTTP/1.1 it is only possible to disrupt chunked-transfer by closing the TCP connection, in other versions the stream is closed or aborted.

                                      Recommendations:

                                      • Do not assume any custom headers are transferred correctly by the CDN. This transport is built for CDN who do not support WebSocket, these CDN tend to not be very modern (or good).

                                      • It should be assumed there is no streaming upload within a HTTP request, so the size of a packet should be chosen to optimize between latency, throughput, and any size limits imposed by the CDN (just like TCP, nagle's algorithm and MTU...)

                                      • HTTP/1.1 and h2 should be supported by server and client, and it should be expected that the CDN will translate arbitrarily between versions. A HTTP/1.1 server may indirectly end up talking to a h2 client, and vice versa.

                                      ",3);function T(g,q){const r=n("I18nTip"),s=n("Badge"),c=n("RouterLink"),a=n("ExternalLinkIcon");return p(),d("div",null,[t(r),m,t(s,{text:"v1.8.16+",type:"warning"}),b,t(s,{text:"v1.8.17+",type:"warning"}),e("p",null,[o("If uTLS is not enough, SplitHTTP's TLS can be handled by a browser using "),t(c,{to:"/en/config/features/browser_dialer.html"},{default:u(()=>[o("Browser Dialer")]),_:1})]),f,e("p",null,[o("See "),e("a",y,[o("#3412"),t(a)]),o(" and "),e("a",v,[o("#3462"),t(a)]),o(" for extensive discussion and revision of the protocol. Here is a summary, and the minimum needed to be compatible:")]),k])}const x=l(h,[["render",T],["__file","splithttp.html.vue"]]);export{x as default}; diff --git a/assets/splithttp.html-CkMHeQ1D.js b/assets/splithttp.html-Cb2yAPj6.js similarity index 85% rename from assets/splithttp.html-CkMHeQ1D.js rename to assets/splithttp.html-Cb2yAPj6.js index 50e36e988b..c0613a7a2c 100644 --- a/assets/splithttp.html-CkMHeQ1D.js +++ b/assets/splithttp.html-Cb2yAPj6.js @@ -1 +1 @@ -const t=JSON.parse('{"key":"v-eeea2fb0","path":"/config/transports/splithttp.html","title":"SplitHTTP(H2、QUIC H3)","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"SplitHttpObject","slug":"splithttpobject","link":"#splithttpobject","children":[]},{"level":2,"title":"HTTP 版本","slug":"http-版本","link":"#http-版本","children":[{"level":3,"title":"客户端行为","slug":"客户端行为","link":"#客户端行为","children":[]},{"level":3,"title":"服务端行为","slug":"服务端行为","link":"#服务端行为","children":[]},{"level":3,"title":"小提示","slug":"小提示","link":"#小提示","children":[]}]},{"level":2,"title":"Browser Dialer","slug":"browser-dialer","link":"#browser-dialer","children":[]},{"level":2,"title":"协议细节","slug":"协议细节","link":"#协议细节","children":[]}],"git":{"updatedTime":1726650704000,"contributors":[{"name":"风扇滑翔翼","email":"Fangliding.fshxy@outlook.com","commits":16},{"name":"mmmray","email":"142015632+mmmray@users.noreply.github.com","commits":5},{"name":"MisCusi2023","email":"128662654+MisCusi2023@users.noreply.github.com","commits":1}]},"filePathRelative":"config/transports/splithttp.md","i18n":{"pathLocale":"/","sourceLink":"/config/transports/splithttp.html","untranslated":false,"updatedTime":1726650704000}}');export{t as data}; +const t=JSON.parse('{"key":"v-eeea2fb0","path":"/config/transports/splithttp.html","title":"SplitHTTP(H2、QUIC H3)","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"SplitHttpObject","slug":"splithttpobject","link":"#splithttpobject","children":[]},{"level":2,"title":"HTTP 版本","slug":"http-版本","link":"#http-版本","children":[{"level":3,"title":"客户端行为","slug":"客户端行为","link":"#客户端行为","children":[]},{"level":3,"title":"服务端行为","slug":"服务端行为","link":"#服务端行为","children":[]},{"level":3,"title":"小提示","slug":"小提示","link":"#小提示","children":[]}]},{"level":2,"title":"Browser Dialer","slug":"browser-dialer","link":"#browser-dialer","children":[]},{"level":2,"title":"协议细节","slug":"协议细节","link":"#协议细节","children":[]}],"git":{"updatedTime":1726657034000,"contributors":[{"name":"风扇滑翔翼","email":"Fangliding.fshxy@outlook.com","commits":16},{"name":"mmmray","email":"142015632+mmmray@users.noreply.github.com","commits":6},{"name":"MisCusi2023","email":"128662654+MisCusi2023@users.noreply.github.com","commits":1}]},"filePathRelative":"config/transports/splithttp.md","i18n":{"pathLocale":"/","sourceLink":"/config/transports/splithttp.html","untranslated":false,"updatedTime":1726657034000}}');export{t as data}; diff --git a/assets/splithttp.html-Bu9SdRS8.js b/assets/splithttp.html-Cs2Z785s.js similarity index 99% rename from assets/splithttp.html-Bu9SdRS8.js rename to assets/splithttp.html-Cs2Z785s.js index 5b0b5a7b7b..9adbd6521e 100644 --- a/assets/splithttp.html-Bu9SdRS8.js +++ b/assets/splithttp.html-Cs2Z785s.js @@ -1,4 +1,4 @@ -import{_ as r,r as n,o as d,c as i,a as t,b as o,d as e,w as u,e as a}from"./app-DBM4OJyw.js";const h={},T=o("h1",{id:"splithttp",tabindex:"-1"},[o("a",{class:"header-anchor",href:"#splithttp"},[o("span",null,"SplitHTTP")])],-1),k=a(`

                                      Используется для загрузки с помощью HTTP-фрагментированной передачи, загрузка осуществляется с помощью нескольких HTTP POST-запросов.

                                      Может использоваться через CDN, не поддерживающие WebSocket, но есть несколько требований:

                                      • CDN должен поддерживать HTTP-фрагментированную передачу и потоковые ответы без буферизации. Ядро будет отправлять X-Accel-Buffering: no и Content-Type: text/event-stream, чтобы сообщить CDN об этом, но CDN должен соблюдать этот заголовок. Если промежуточный сервер не поддерживает потоковые ответы и зависает, передача, скорее всего, не будет работать.

                                      Цель та же, что и у V2fly Meek, но благодаря использованию фрагментированной загрузки скорость загрузки выше, а скорость отдачи оптимизирована, но все еще очень ограничена, поэтому к HTTP-прокси предъявляются более высокие требования (см. выше).

                                      SplitHTTP также принимает заголовок X-Forwarded-For.

                                      SplitHttpObject

                                      SplitHttpObject соответствует элементу splithttpSettings в конфигурации транспорта.

                                      {
                                      +import{_ as r,r as n,o as d,c as i,a as t,b as o,d as e,w as u,e as a}from"./app-D7uBbsY3.js";const h={},T=o("h1",{id:"splithttp",tabindex:"-1"},[o("a",{class:"header-anchor",href:"#splithttp"},[o("span",null,"SplitHTTP")])],-1),k=a(`

                                      Используется для загрузки с помощью HTTP-фрагментированной передачи, загрузка осуществляется с помощью нескольких HTTP POST-запросов.

                                      Может использоваться через CDN, не поддерживающие WebSocket, но есть несколько требований:

                                      • CDN должен поддерживать HTTP-фрагментированную передачу и потоковые ответы без буферизации. Ядро будет отправлять X-Accel-Buffering: no и Content-Type: text/event-stream, чтобы сообщить CDN об этом, но CDN должен соблюдать этот заголовок. Если промежуточный сервер не поддерживает потоковые ответы и зависает, передача, скорее всего, не будет работать.

                                      Цель та же, что и у V2fly Meek, но благодаря использованию фрагментированной загрузки скорость загрузки выше, а скорость отдачи оптимизирована, но все еще очень ограничена, поэтому к HTTP-прокси предъявляются более высокие требования (см. выше).

                                      SplitHTTP также принимает заголовок X-Forwarded-For.

                                      SplitHttpObject

                                      SplitHttpObject соответствует элементу splithttpSettings в конфигурации транспорта.

                                      {
                                         "path": "/",
                                         "host": "xray.com",
                                         "headers": {
                                      diff --git a/assets/splithttp.html-Dz9QMH4-.js b/assets/splithttp.html-CyHPUrRH.js
                                      similarity index 95%
                                      rename from assets/splithttp.html-Dz9QMH4-.js
                                      rename to assets/splithttp.html-CyHPUrRH.js
                                      index a7b40fe13b..d29f324688 100644
                                      --- a/assets/splithttp.html-Dz9QMH4-.js
                                      +++ b/assets/splithttp.html-CyHPUrRH.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as r,r as s,o as i,c as d,a as o,b as e,d as n,w as u,e as a}from"./app-DBM4OJyw.js";const h={},k=e("h1",{id:"splithttp-h2、quic-h3",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#splithttp-h2、quic-h3"},[e("span",null,"SplitHTTP(H2、QUIC H3)")])],-1),T=a(`

                                      使用HTTP分块传输编码流式响应处理下载,使用多个HTTP POST请求进行上传。

                                      可以通过不支持WebSocket的CDN上,但仍有一些要求:

                                      • CDN必须支持HTTP分块传输,且支持流式响应而不会缓冲,核心将会发送各种信息以告知CDN,但是需要CDN遵守。如果中间盒不支持流式响应而导致连接被挂起,则该传输很可能无法工作。

                                      目的与V2fly Meek相同,由于使用了流式响应处理下载,下行速率更为优秀,上行也经过优化但仍非常有限,也因此对 HTTP 中间盒要求更高(见上)。

                                      SplitHTTP 也接受 X-Forwarded-For header。

                                      SplitHttpObject

                                      The SplitHttpObject 对应传输配置的 splithttpSettings 项。

                                      {
                                      +import{_ as r,r as s,o as i,c as d,a as o,b as e,d as n,w as u,e as a}from"./app-D7uBbsY3.js";const h={},k=e("h1",{id:"splithttp-h2、quic-h3",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#splithttp-h2、quic-h3"},[e("span",null,"SplitHTTP(H2、QUIC H3)")])],-1),T=a(`

                                      使用HTTP分块传输编码流式响应处理下载,使用多个HTTP POST请求进行上传。

                                      可以通过不支持WebSocket的CDN上,但仍有一些要求:

                                      • CDN必须支持HTTP分块传输,且支持流式响应而不会缓冲,核心将会发送各种信息以告知CDN,但是需要CDN遵守。如果中间盒不支持流式响应而导致连接被挂起,则该传输很可能无法工作。

                                      目的与V2fly Meek相同,由于使用了流式响应处理下载,下行速率更为优秀,上行也经过优化但仍非常有限,也因此对 HTTP 中间盒要求更高(见上)。

                                      SplitHTTP 也接受 X-Forwarded-For header。

                                      SplitHttpObject

                                      The SplitHttpObject 对应传输配置的 splithttpSettings 项。

                                      {
                                         "path": "/",
                                         "host": "xray.com",
                                         "headers": {
                                      @@ -10,10 +10,10 @@ import{_ as r,r as s,o as i,c as d,a as o,b as e,d as n,w as u,e as a}from"./app
                                         "noSSEHeader": false,
                                         "xPaddingBytes": "100-1000",
                                         "xmux": {
                                      -    "maxConnections": 0,
                                           "maxConcurrency": 0,
                                      +    "maxConnections": 0,
                                           "cMaxReuseTimes": 0,
                                           "cMaxLifetimeMs": 0
                                         }
                                       }
                                      -

                                      path: string

                                      SplitHTTP 所使用的 HTTP 协议路径,默认值为 "/"

                                      host: string

                                      SplitHTTP 的HTTP请求中所发送的host,默认值为空。若服务端值为空时,不验证客户端发送来的host值。

                                      当在服务端指定该值,或在 headers 中指定host,将会校验与客户端请求host是否一致。

                                      客户端选择发送的host优先级 host > headers > address

                                      headers: map {string: string}

                                      仅客户端,自定义 HTTP 头,一个键值对,每个键表示一个 HTTP 头的名称,对应的值是字符串。

                                      scMaxEachPostBytes: int/string

                                      上传分块的最大大小,单位为字节,默认值为 1000000, 即 1MB.

                                      客户端设置的大小必须低于该值,否则当发送的 POST 请求大于服务端设置的值时,请求会被拒绝。

                                      这个值应该小于CDN或其他HTTP反向代理所允许的最大请求体,否则将抛出 HTTP 413 错误。

                                      也可以是字符串 "500000-1000000" 的形式,核心每次会在范围内随机选择一个值,以减少指纹。

                                      scMaxConcurrentPosts: int/string

                                      单个连接上传post的最大并发数,默认为100.

                                      上传并发同时也受(也主要受) scMinPostsIntervalMs 控制,故该值仅做保险。

                                      客户端实际发起的数量必须低于服务端。(实际情况下由于上述很难达到上限,所以事实上客户端设置的值可以超过服务端,但不建议这么做)

                                      也可以是字符串 "50-100" 的形式,核心每次会在范围内随机选择一个值,以减少指纹。

                                      scMinPostsIntervalMs: int/string

                                      仅客户端,发起POST上传请求的最小间隔。默认值为 30.

                                      也可以是字符串 "10-50" 的形式,核心每次会在范围内随机选择一个值,以减少指纹。

                                      noSSEHeader: bool

                                      仅服务端,不发送 Content-Type: text/event-stream 响应头,默认 false (即会发送)

                                      xPaddingBytes int/string

                                      设置请求(出站)和响应(入站)的填充大小,用于减少请求指纹。单位byte, 默认为 "100-1000" 每次会在该范围中随机选择一个数字。 也可以是单个数字 "200"/200

                                      设置为 -1 将完全禁用填充

                                      xmux

                                      允许用户对 SplitHTTP 在 h2 与 h3 中的多路复用行为进行控制,如不设置,默认行为为将所有请求复用至一条 h2/QUIC 连接。

                                      与 mux.cool 不同,该复用工作于更低的等级,效率可能更好,如果有复用需求建议在此设置,不要启用 mux.cool.

                                      术语解释:

                                      • 流会复用物理连接,像这样 连接1(流1,流2,流3) 连接2(流4,流5,流6) .. 以此类推 在其他地方你可能看到 连接-子连接 这样的描述,都是一样的东西。
                                      • 下述所有字段类型均为 int/string 均支持固定值 16 或浮动值 "8-32" 的写法
                                      • maxConcurrency: 默认值为 0(即无限) 每个连接中复用的流的最大数量,连接中流的数量达到该值后核心会新建更多连接以容纳更多的流,类似于 mux.cool 的 concurrency.

                                      • maxConnections: 默认值为 0(即无限) 要打开的最大连接数,连接达到此值前核心会积极打开连接,对每一条流都新建一个连接,直到达到该值。然后核心会开始复用已经建立的连接。 与 maxConcurrency 冲突。

                                      • cMaxReuseTimes: 默认值为 0(即无限) 一个连接最多被复用几次,当达到该值后核心不会向该连接再分配流,其将在内部最后一条流关闭后断开。

                                      • cMaxLifetimeMs: 默认值为 0(即无限) 一个连接最多可以“存活”多久,当连接打开的时间超过该值后核心不会向该连接再分配流,其将在内部最后一条流关闭后断开。

                                      HTTP 版本

                                      客户端行为

                                      默认情况下,客户端将会默认在未启用 TLS 时使用 http/1.1, 启用 TLS 时,使用 h2.

                                      当启用 TLS 时,允许在 TLS 设置的 alpn 数组内设置 http/1.1 h2 h3 来指定具体的http版本(仅当该数组只有一个元素时生效,若填入多个元素则返回默认行为)

                                      服务端行为

                                      默认情况下,服务端将会默认监听 TCP, 此时可以处理 http/1.1 和 h2 流量。

                                      当启用 TLS 时,允许在 TLS 设置的 alpn 数组内设置 h3, 此时服务端将改为监听 UDP 端口, 处理 h3 流量。

                                      小提示

                                      由于该协议为标准的 HTTP 请求,所以对于 HTTP 版本的转换并不敏感,各种中间盒都可能转换 HTTP 版本。

                                      列如:你希望使用 h3 连接 Cloudflare, 但是Cloudflare 不会使用 h3 回源, 而是使用 http/1.1 或 h2 回源,此时客户端 alpn 应为 h3, 而服务端就不应为 h3, 因为发往服务端的请求不是 h3.

                                      Browser Dialer

                                      `,51),q=e("h2",{id:"协议细节",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#协议细节"},[e("span",null,"协议细节")])],-1),b={href:"https://github.com/XTLS/Xray-core/pull/3412",target:"_blank",rel:"noopener noreferrer"},m={href:"https://github.com/XTLS/Xray-core/pull/3462",target:"_blank",rel:"noopener noreferrer"},v=a('
                                      1. 使用 GET /<UUID> 开始下载。服务器立即回复 200 OKTransfer Encoding:chunked , 并立即发送一个两字节的有效负载,以强制HTTP中间盒刷新标头。

                                      现阶段服务器会发送以下标头

                                      • X-Accel-Buffering: no 禁用缓冲
                                      • Content-Type: text/event-stream 在部分中间盒中禁用缓冲,可以使用 "noSSEHeader" 选项关闭
                                      • Transfer-Encoding: chunked 分块传输,仅在 HTTP/1.1 中使用
                                      • Cache-Control: no-store to disable any potential response caching. 禁用CDN的缓存
                                      1. 使用 POST /<UUID>/<seq> 开始发送上行数据. seq 作用类似于 TCP 序列号,从0开始,数据包可以被同时发送,服务端必须按序列号将数据重组。序列号不应重置。

                                        客户端可以以任意决定打开上行与下行请求的顺序,任何一种都可以启动会话,但是必须要在30秒内打开 GET 连接,否则会话将被终止。

                                      2. GET 请求将一直保持在打开状态直到连接被终止,服务端和客户端都可以关闭连接。具体行为取决于HTTP版本。

                                      建议:

                                      • 不要期望CDN会正确传输所有标头,这个协议的目的是为了穿透不支持WS的CDN,而这些CDN的行为通常不怎么友好。

                                      • 应当假设所有HTTP连接都不支持流式请求,所以上行连接发送的的每个包的大小应该基于延迟、吞吐量以及中间盒本身的限制考虑(类似TCP的MTU与纳格算法)。

                                      ',6);function x(P,g){const p=s("I18nTip"),c=s("Badge"),l=s("RouterLink"),t=s("ExternalLinkIcon");return i(),d("div",null,[o(p),k,o(c,{text:"v1.8.16+",type:"warning"}),T,e("p",null,[n("如果使用HTTPS,该传输还支持 "),o(l,{to:"/config/features/browser_dialer.html"},{default:u(()=>[n("Browser Dialer")]),_:1})]),q,e("p",null,[n("讨论详见 "),e("a",b,[n("#3412"),o(t)]),n(" 和 "),e("a",m,[n("#3462"),o(t)]),n(" 以下是简述和简要兼容实现要求")]),v])}const f=r(h,[["render",x],["__file","splithttp.html.vue"]]);export{f as default}; +

                                      path: string

                                      SplitHTTP 所使用的 HTTP 协议路径,默认值为 "/"

                                      host: string

                                      SplitHTTP 的HTTP请求中所发送的host,默认值为空。若服务端值为空时,不验证客户端发送来的host值。

                                      当在服务端指定该值,或在 headers 中指定host,将会校验与客户端请求host是否一致。

                                      客户端选择发送的host优先级 host > headers > address

                                      headers: map {string: string}

                                      仅客户端,自定义 HTTP 头,一个键值对,每个键表示一个 HTTP 头的名称,对应的值是字符串。

                                      scMaxEachPostBytes: int/string

                                      上传分块的最大大小,单位为字节,默认值为 1000000, 即 1MB.

                                      客户端设置的大小必须低于该值,否则当发送的 POST 请求大于服务端设置的值时,请求会被拒绝。

                                      这个值应该小于CDN或其他HTTP反向代理所允许的最大请求体,否则将抛出 HTTP 413 错误。

                                      也可以是字符串 "500000-1000000" 的形式,核心每次会在范围内随机选择一个值,以减少指纹。

                                      scMaxConcurrentPosts: int/string

                                      单个连接上传post的最大并发数,默认为100.

                                      上传并发同时也受(也主要受) scMinPostsIntervalMs 控制,故该值仅做保险。

                                      客户端实际发起的数量必须低于服务端。(实际情况下由于上述很难达到上限,所以事实上客户端设置的值可以超过服务端,但不建议这么做)

                                      也可以是字符串 "50-100" 的形式,核心每次会在范围内随机选择一个值,以减少指纹。

                                      scMinPostsIntervalMs: int/string

                                      仅客户端,发起POST上传请求的最小间隔。默认值为 30.

                                      也可以是字符串 "10-50" 的形式,核心每次会在范围内随机选择一个值,以减少指纹。

                                      noSSEHeader: bool

                                      仅服务端,不发送 Content-Type: text/event-stream 响应头,默认 false (即会发送)

                                      xPaddingBytes int/string

                                      设置请求(出站)和响应(入站)的填充大小,用于减少请求指纹。单位byte, 默认为 "100-1000" 每次会在该范围中随机选择一个数字。 也可以是单个数字 "200"/200

                                      设置为 -1 将完全禁用填充

                                      xmux

                                      允许用户对 SplitHTTP 在 h2 与 h3 中的多路复用行为进行控制,如不设置,默认行为为将所有请求复用至一条 h2/QUIC 连接。

                                      与 mux.cool 不同,该复用工作于更低的等级,效率可能更好,如果有复用需求建议在此设置,不要启用 mux.cool.

                                      术语解释:

                                      • 流会复用物理连接,像这样 连接1(流1,流2,流3) 连接2(流4,流5,流6) .. 以此类推 在其他地方你可能看到 连接-子连接 这样的描述,都是一样的东西。
                                      • 下述所有字段类型均为 int/string 均支持固定值 16 或浮动值 "8-32" 的写法
                                      • maxConnections: 默认值为 0(即无限) 要打开的最大连接数,连接达到此值前核心会积极打开连接,对每一条流都新建一个连接,直到达到该值。然后核心会开始复用已经建立的连接。 与 maxConcurrency 冲突。

                                      • maxConcurrency: 默认值为 0(即无限) 每个连接中复用的流的最大数量,连接中流的数量达到该值后核心会新建更多连接以容纳更多的流,类似于 mux.cool 的 concurrency.

                                      • cMaxReuseTimes: 默认值为 0(即无限) 一个连接最多被复用几次,当达到该值后核心不会向该连接再分配流,其将在内部最后一条流关闭后断开。

                                      • cMaxLifetimeMs: 默认值为 0(即无限) 一个连接最多可以“存活”多久,当连接打开的时间超过该值后核心不会向该连接再分配流,其将在内部最后一条流关闭后断开。

                                      HTTP 版本

                                      客户端行为

                                      默认情况下,客户端将会默认在未启用 TLS 时使用 http/1.1, 启用 TLS 时,使用 h2.

                                      当启用 TLS 时,允许在 TLS 设置的 alpn 数组内设置 http/1.1 h2 h3 来指定具体的http版本(仅当该数组只有一个元素时生效,若填入多个元素则返回默认行为)

                                      服务端行为

                                      默认情况下,服务端将会默认监听 TCP, 此时可以处理 http/1.1 和 h2 流量。

                                      当启用 TLS 时,允许在 TLS 设置的 alpn 数组内设置 h3, 此时服务端将改为监听 UDP 端口, 处理 h3 流量。

                                      小提示

                                      由于该协议为标准的 HTTP 请求,所以对于 HTTP 版本的转换并不敏感,各种中间盒都可能转换 HTTP 版本。

                                      列如:你希望使用 h3 连接 Cloudflare, 但是Cloudflare 不会使用 h3 回源, 而是使用 http/1.1 或 h2 回源,此时客户端 alpn 应为 h3, 而服务端就不应为 h3, 因为发往服务端的请求不是 h3.

                                      Browser Dialer

                                      `,51),q=e("h2",{id:"协议细节",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#协议细节"},[e("span",null,"协议细节")])],-1),b={href:"https://github.com/XTLS/Xray-core/pull/3412",target:"_blank",rel:"noopener noreferrer"},m={href:"https://github.com/XTLS/Xray-core/pull/3462",target:"_blank",rel:"noopener noreferrer"},v=a('
                                      1. 使用 GET /<UUID> 开始下载。服务器立即回复 200 OKTransfer Encoding:chunked , 并立即发送一个两字节的有效负载,以强制HTTP中间盒刷新标头。

                                      现阶段服务器会发送以下标头

                                      • X-Accel-Buffering: no 禁用缓冲
                                      • Content-Type: text/event-stream 在部分中间盒中禁用缓冲,可以使用 "noSSEHeader" 选项关闭
                                      • Transfer-Encoding: chunked 分块传输,仅在 HTTP/1.1 中使用
                                      • Cache-Control: no-store to disable any potential response caching. 禁用CDN的缓存
                                      1. 使用 POST /<UUID>/<seq> 开始发送上行数据. seq 作用类似于 TCP 序列号,从0开始,数据包可以被同时发送,服务端必须按序列号将数据重组。序列号不应重置。

                                        客户端可以以任意决定打开上行与下行请求的顺序,任何一种都可以启动会话,但是必须要在30秒内打开 GET 连接,否则会话将被终止。

                                      2. GET 请求将一直保持在打开状态直到连接被终止,服务端和客户端都可以关闭连接。具体行为取决于HTTP版本。

                                      建议:

                                      • 不要期望CDN会正确传输所有标头,这个协议的目的是为了穿透不支持WS的CDN,而这些CDN的行为通常不怎么友好。

                                      • 应当假设所有HTTP连接都不支持流式请求,所以上行连接发送的的每个包的大小应该基于延迟、吞吐量以及中间盒本身的限制考虑(类似TCP的MTU与纳格算法)。

                                      ',6);function x(P,g){const p=s("I18nTip"),c=s("Badge"),l=s("RouterLink"),t=s("ExternalLinkIcon");return i(),d("div",null,[o(p),k,o(c,{text:"v1.8.16+",type:"warning"}),T,e("p",null,[n("如果使用HTTPS,该传输还支持 "),o(l,{to:"/config/features/browser_dialer.html"},{default:u(()=>[n("Browser Dialer")]),_:1})]),q,e("p",null,[n("讨论详见 "),e("a",b,[n("#3412"),o(t)]),n(" 和 "),e("a",m,[n("#3462"),o(t)]),n(" 以下是简述和简要兼容实现要求")]),v])}const f=r(h,[["render",x],["__file","splithttp.html.vue"]]);export{f as default}; diff --git a/assets/splithttp.html-DstjiOIY.js b/assets/splithttp.html-DZKLCVFH.js similarity index 79% rename from assets/splithttp.html-DstjiOIY.js rename to assets/splithttp.html-DZKLCVFH.js index 5e1ba43fa1..fa28ccfab2 100644 --- a/assets/splithttp.html-DstjiOIY.js +++ b/assets/splithttp.html-DZKLCVFH.js @@ -1 +1 @@ -const t=JSON.parse('{"key":"v-4df52c3c","path":"/en/config/transports/splithttp.html","title":"SplitHTTP","lang":"en-US","frontmatter":{},"headers":[{"level":2,"title":"SplitHttpObject","slug":"splithttpobject","link":"#splithttpobject","children":[]},{"level":2,"title":"HTTP versions","slug":"http-versions","link":"#http-versions","children":[]},{"level":2,"title":"Troubleshooting","slug":"troubleshooting","link":"#troubleshooting","children":[]},{"level":2,"title":"Browser Dialer","slug":"browser-dialer","link":"#browser-dialer","children":[]},{"level":2,"title":"Protocol details","slug":"protocol-details","link":"#protocol-details","children":[]}],"git":{"updatedTime":1726504310000,"contributors":[{"name":"mmmray","email":"142015632+mmmray@users.noreply.github.com","commits":15}]},"filePathRelative":"en/config/transports/splithttp.md","i18n":{"pathLocale":"/en/","sourceLink":"/config/transports/splithttp.html","untranslated":false,"updatedTime":1726504310000,"sourceUpdatedTime":1726650704000,"outdated":true}}');export{t as data}; +const t=JSON.parse('{"key":"v-4df52c3c","path":"/en/config/transports/splithttp.html","title":"SplitHTTP","lang":"en-US","frontmatter":{},"headers":[{"level":2,"title":"SplitHttpObject","slug":"splithttpobject","link":"#splithttpobject","children":[]},{"level":2,"title":"HTTP versions","slug":"http-versions","link":"#http-versions","children":[]},{"level":2,"title":"Troubleshooting","slug":"troubleshooting","link":"#troubleshooting","children":[]},{"level":2,"title":"Browser Dialer","slug":"browser-dialer","link":"#browser-dialer","children":[]},{"level":2,"title":"Protocol details","slug":"protocol-details","link":"#protocol-details","children":[]}],"git":{"updatedTime":1726657034000,"contributors":[{"name":"mmmray","email":"142015632+mmmray@users.noreply.github.com","commits":16}]},"filePathRelative":"en/config/transports/splithttp.md","i18n":{"pathLocale":"/en/","sourceLink":"/config/transports/splithttp.html","untranslated":false,"updatedTime":1726657034000,"sourceUpdatedTime":1726657034000}}');export{t as data}; diff --git a/assets/stateDiagram-N22R6T2Y-BFbyHmsw.js b/assets/stateDiagram-N22R6T2Y-ClLx8lyS.js similarity index 96% rename from assets/stateDiagram-N22R6T2Y-BFbyHmsw.js rename to assets/stateDiagram-N22R6T2Y-ClLx8lyS.js index fe3ac17504..ffd102dee9 100644 --- a/assets/stateDiagram-N22R6T2Y-BFbyHmsw.js +++ b/assets/stateDiagram-N22R6T2Y-ClLx8lyS.js @@ -1 +1 @@ -import{s as W,a as N,b as P}from"./chunk-SVGOEX7Z-7nrOxk8C.js";import{_ as u,d as t,j as H,l as S,k as C,e as z,a2 as U,a8 as F,u as O}from"./mermaid.core-DapiNGBY.js";import"./chunk-Z2VRG6XP-DsASRjJ5.js";import{G as J}from"./graph-Oq3lz9SV.js";import{l as X}from"./layout-7AWYeW5Q.js";import"./chunk-FUIDI54P-DcJSRBm9.js";import"./app-DBM4OJyw.js";import"./baseUniq-ZJgB7efo.js";import"./basePickBy-BXIHjUx3.js";var L={},D=u((e,i)=>{L[e]=i},"set"),Y=u(e=>L[e],"get"),G=u(()=>Object.keys(L),"keys"),I=u(()=>G().length,"size"),$={get:Y,set:D,keys:G,size:I},j=u(e=>e.append("circle").attr("class","start-state").attr("r",t().state.sizeUnit).attr("cx",t().state.padding+t().state.sizeUnit).attr("cy",t().state.padding+t().state.sizeUnit),"drawStartState"),q=u(e=>e.append("line").style("stroke","grey").style("stroke-dasharray","3").attr("x1",t().state.textHeight).attr("class","divider").attr("x2",t().state.textHeight*2).attr("y1",0).attr("y2",0),"drawDivider"),Z=u((e,i)=>{const d=e.append("text").attr("x",2*t().state.padding).attr("y",t().state.textHeight+2*t().state.padding).attr("font-size",t().state.fontSize).attr("class","state-title").text(i.id),o=d.node().getBBox();return e.insert("rect",":first-child").attr("x",t().state.padding).attr("y",t().state.padding).attr("width",o.width+2*t().state.padding).attr("height",o.height+2*t().state.padding).attr("rx",t().state.radius),d},"drawSimpleState"),K=u((e,i)=>{const d=u(function(l,B,m){const k=l.append("tspan").attr("x",2*t().state.padding).text(B);m||k.attr("dy",t().state.textHeight)},"addTspan"),n=e.append("text").attr("x",2*t().state.padding).attr("y",t().state.textHeight+1.3*t().state.padding).attr("font-size",t().state.fontSize).attr("class","state-title").text(i.descriptions[0]).node().getBBox(),g=n.height,p=e.append("text").attr("x",t().state.padding).attr("y",g+t().state.padding*.4+t().state.dividerMargin+t().state.textHeight).attr("class","state-description");let a=!0,s=!0;i.descriptions.forEach(function(l){a||(d(p,l,s),s=!1),a=!1});const y=e.append("line").attr("x1",t().state.padding).attr("y1",t().state.padding+g+t().state.dividerMargin/2).attr("y2",t().state.padding+g+t().state.dividerMargin/2).attr("class","descr-divider"),x=p.node().getBBox(),c=Math.max(x.width,n.width);return y.attr("x2",c+3*t().state.padding),e.insert("rect",":first-child").attr("x",t().state.padding).attr("y",t().state.padding).attr("width",c+2*t().state.padding).attr("height",x.height+g+2*t().state.padding).attr("rx",t().state.radius),e},"drawDescrState"),Q=u((e,i,d)=>{const o=t().state.padding,n=2*t().state.padding,g=e.node().getBBox(),p=g.width,a=g.x,s=e.append("text").attr("x",0).attr("y",t().state.titleShift).attr("font-size",t().state.fontSize).attr("class","state-title").text(i.id),x=s.node().getBBox().width+n;let c=Math.max(x,p);c===p&&(c=c+n);let l;const B=e.node().getBBox();i.doc,l=a-o,x>p&&(l=(p-c)/2+o),Math.abs(a-B.x)p&&(l=a-(x-p)/2);const m=1-t().state.textHeight;return e.insert("rect",":first-child").attr("x",l).attr("y",m).attr("class",d?"alt-composit":"composit").attr("width",c).attr("height",B.height+t().state.textHeight+t().state.titleShift+1).attr("rx","0"),s.attr("x",l+o),x<=p&&s.attr("x",a+(c-n)/2-x/2+o),e.insert("rect",":first-child").attr("x",l).attr("y",t().state.titleShift-t().state.textHeight-t().state.padding).attr("width",c).attr("height",t().state.textHeight*3).attr("rx",t().state.radius),e.insert("rect",":first-child").attr("x",l).attr("y",t().state.titleShift-t().state.textHeight-t().state.padding).attr("width",c).attr("height",B.height+3+2*t().state.textHeight).attr("rx",t().state.radius),e},"addTitleAndBox"),V=u(e=>(e.append("circle").attr("class","end-state-outer").attr("r",t().state.sizeUnit+t().state.miniPadding).attr("cx",t().state.padding+t().state.sizeUnit+t().state.miniPadding).attr("cy",t().state.padding+t().state.sizeUnit+t().state.miniPadding),e.append("circle").attr("class","end-state-inner").attr("r",t().state.sizeUnit).attr("cx",t().state.padding+t().state.sizeUnit+2).attr("cy",t().state.padding+t().state.sizeUnit+2)),"drawEndState"),tt=u((e,i)=>{let d=t().state.forkWidth,o=t().state.forkHeight;if(i.parentId){let n=d;d=o,o=n}return e.append("rect").style("stroke","black").style("fill","black").attr("width",d).attr("height",o).attr("x",t().state.padding).attr("y",t().state.padding)},"drawForkJoinState"),et=u((e,i,d,o)=>{let n=0;const g=o.append("text");g.style("text-anchor","start"),g.attr("class","noteText");let p=e.replace(/\r\n/g,"
                                      ");p=p.replace(/\n/g,"
                                      ");const a=p.split(z.lineBreakRegex);let s=1.25*t().state.noteMargin;for(const y of a){const x=y.trim();if(x.length>0){const c=g.append("tspan");if(c.text(x),s===0){const l=c.node().getBBox();s+=l.height}n+=s,c.attr("x",i+t().state.noteMargin),c.attr("y",d+n+1.25*t().state.noteMargin)}}return{textWidth:g.node().getBBox().width,textHeight:n}},"_drawLongText"),at=u((e,i)=>{i.attr("class","state-note");const d=i.append("rect").attr("x",0).attr("y",t().state.padding),o=i.append("g"),{textWidth:n,textHeight:g}=et(e,0,0,o);return d.attr("height",g+2*t().state.noteMargin),d.attr("width",n+t().state.noteMargin*2),d},"drawNote"),_=u(function(e,i){const d=i.id,o={id:d,label:i.id,width:0,height:0},n=e.append("g").attr("id",d).attr("class","stateGroup");i.type==="start"&&j(n),i.type==="end"&&V(n),(i.type==="fork"||i.type==="join")&&tt(n,i),i.type==="note"&&at(i.note.text,n),i.type==="divider"&&q(n),i.type==="default"&&i.descriptions.length===0&&Z(n,i),i.type==="default"&&i.descriptions.length>0&&K(n,i);const g=n.node().getBBox();return o.width=g.width+2*t().state.padding,o.height=g.height+2*t().state.padding,$.set(d,o),o},"drawState"),A=0,it=u(function(e,i,d){const o=u(function(s){switch(s){case N.relationType.AGGREGATION:return"aggregation";case N.relationType.EXTENSION:return"extension";case N.relationType.COMPOSITION:return"composition";case N.relationType.DEPENDENCY:return"dependency"}},"getRelationType");i.points=i.points.filter(s=>!Number.isNaN(s.y));const n=i.points,g=U().x(function(s){return s.x}).y(function(s){return s.y}).curve(F),p=e.append("path").attr("d",g(n)).attr("id","edge"+A).attr("class","transition");let a="";if(t().state.arrowMarkerAbsolute&&(a=window.location.protocol+"//"+window.location.host+window.location.pathname+window.location.search,a=a.replace(/\(/g,"\\("),a=a.replace(/\)/g,"\\)")),p.attr("marker-end","url("+a+"#"+o(N.relationType.DEPENDENCY)+"End)"),d.title!==void 0){const s=e.append("g").attr("class","stateLabel"),{x:y,y:x}=O.calcLabelPosition(i.points),c=z.getRows(d.title);let l=0;const B=[];let m=0,k=0;for(let f=0;f<=c.length;f++){const h=s.append("text").attr("text-anchor","middle").text(c[f]).attr("x",y).attr("y",x+l),w=h.node().getBBox();m=Math.max(m,w.width),k=Math.min(k,w.x),S.info(w.x,y,x+l),l===0&&(l=h.node().getBBox().height,S.info("Title height",l,x)),B.push(h)}let E=l*c.length;if(c.length>1){const f=(c.length-1)*l*.5;B.forEach((h,w)=>h.attr("y",x+w*l-f)),E=l*c.length}const r=s.node().getBBox();s.insert("rect",":first-child").attr("class","box").attr("x",y-m/2-t().state.padding/2).attr("y",x-E/2-t().state.padding/2-3.5).attr("width",m+t().state.padding).attr("height",E+t().state.padding),S.info(r)}A++},"drawEdge"),b,T={},rt=u(function(){},"setConf"),nt=u(function(e){e.append("defs").append("marker").attr("id","dependencyEnd").attr("refX",19).attr("refY",7).attr("markerWidth",20).attr("markerHeight",28).attr("orient","auto").append("path").attr("d","M 19,7 L9,13 L14,7 L9,1 Z")},"insertMarkers"),st=u(function(e,i,d,o){b=t().state;const n=t().securityLevel;let g;n==="sandbox"&&(g=H("#i"+i));const p=n==="sandbox"?H(g.nodes()[0].contentDocument.body):H("body"),a=n==="sandbox"?g.nodes()[0].contentDocument:document;S.debug("Rendering diagram "+e);const s=p.select(`[id='${i}']`);nt(s);const y=o.db.getRootDoc();R(y,s,void 0,!1,p,a,o);const x=b.padding,c=s.node().getBBox(),l=c.width+x*2,B=c.height+x*2,m=l*1.75;C(s,B,m,b.useMaxWidth),s.attr("viewBox",`${c.x-b.padding} ${c.y-b.padding} `+l+" "+B)},"draw"),dt=u(e=>e?e.length*b.fontSizeFactor:1,"getLabelWidth"),R=u((e,i,d,o,n,g,p)=>{const a=new J({compound:!0,multigraph:!0});let s,y=!0;for(s=0;s{const w=h.parentElement;let v=0,M=0;w&&(w.parentElement&&(v=w.parentElement.getBBox().width),M=parseInt(w.getAttribute("data-x-shift"),10),Number.isNaN(M)&&(M=0)),h.setAttribute("x1",0-M+8),h.setAttribute("x2",v-M-8)})):S.debug("No Node "+r+": "+JSON.stringify(a.node(r)))});let k=m.getBBox();a.edges().forEach(function(r){r!==void 0&&a.edge(r)!==void 0&&(S.debug("Edge "+r.v+" -> "+r.w+": "+JSON.stringify(a.edge(r))),it(i,a.edge(r),a.edge(r).relation))}),k=m.getBBox();const E={id:d||"root",label:d||"root",width:0,height:0};return E.width=k.width+2*b.padding,E.height=k.height+2*b.padding,S.debug("Doc rendered",E,a),E},"renderDoc"),ot={setConf:rt,draw:st},yt={parser:W,db:N,renderer:ot,styles:P,init:u(e=>{e.state||(e.state={}),e.state.arrowMarkerAbsolute=e.arrowMarkerAbsolute,N.clear()},"init")};export{yt as diagram}; +import{s as W,a as N,b as P}from"./chunk-SVGOEX7Z-FYkNEjJq.js";import{_ as u,d as t,j as H,l as S,k as C,e as z,a2 as U,a8 as F,u as O}from"./mermaid.core-D8igZDel.js";import"./chunk-Z2VRG6XP-CV0pyCU1.js";import{G as J}from"./graph-Cjb-DGHB.js";import{l as X}from"./layout-CHeuV-iP.js";import"./chunk-FUIDI54P-B3wdDwu1.js";import"./app-D7uBbsY3.js";import"./baseUniq-D0lZO5yp.js";import"./basePickBy-DpnmgMOi.js";var L={},D=u((e,i)=>{L[e]=i},"set"),Y=u(e=>L[e],"get"),G=u(()=>Object.keys(L),"keys"),I=u(()=>G().length,"size"),$={get:Y,set:D,keys:G,size:I},j=u(e=>e.append("circle").attr("class","start-state").attr("r",t().state.sizeUnit).attr("cx",t().state.padding+t().state.sizeUnit).attr("cy",t().state.padding+t().state.sizeUnit),"drawStartState"),q=u(e=>e.append("line").style("stroke","grey").style("stroke-dasharray","3").attr("x1",t().state.textHeight).attr("class","divider").attr("x2",t().state.textHeight*2).attr("y1",0).attr("y2",0),"drawDivider"),Z=u((e,i)=>{const d=e.append("text").attr("x",2*t().state.padding).attr("y",t().state.textHeight+2*t().state.padding).attr("font-size",t().state.fontSize).attr("class","state-title").text(i.id),o=d.node().getBBox();return e.insert("rect",":first-child").attr("x",t().state.padding).attr("y",t().state.padding).attr("width",o.width+2*t().state.padding).attr("height",o.height+2*t().state.padding).attr("rx",t().state.radius),d},"drawSimpleState"),K=u((e,i)=>{const d=u(function(l,B,m){const k=l.append("tspan").attr("x",2*t().state.padding).text(B);m||k.attr("dy",t().state.textHeight)},"addTspan"),n=e.append("text").attr("x",2*t().state.padding).attr("y",t().state.textHeight+1.3*t().state.padding).attr("font-size",t().state.fontSize).attr("class","state-title").text(i.descriptions[0]).node().getBBox(),g=n.height,p=e.append("text").attr("x",t().state.padding).attr("y",g+t().state.padding*.4+t().state.dividerMargin+t().state.textHeight).attr("class","state-description");let a=!0,s=!0;i.descriptions.forEach(function(l){a||(d(p,l,s),s=!1),a=!1});const y=e.append("line").attr("x1",t().state.padding).attr("y1",t().state.padding+g+t().state.dividerMargin/2).attr("y2",t().state.padding+g+t().state.dividerMargin/2).attr("class","descr-divider"),x=p.node().getBBox(),c=Math.max(x.width,n.width);return y.attr("x2",c+3*t().state.padding),e.insert("rect",":first-child").attr("x",t().state.padding).attr("y",t().state.padding).attr("width",c+2*t().state.padding).attr("height",x.height+g+2*t().state.padding).attr("rx",t().state.radius),e},"drawDescrState"),Q=u((e,i,d)=>{const o=t().state.padding,n=2*t().state.padding,g=e.node().getBBox(),p=g.width,a=g.x,s=e.append("text").attr("x",0).attr("y",t().state.titleShift).attr("font-size",t().state.fontSize).attr("class","state-title").text(i.id),x=s.node().getBBox().width+n;let c=Math.max(x,p);c===p&&(c=c+n);let l;const B=e.node().getBBox();i.doc,l=a-o,x>p&&(l=(p-c)/2+o),Math.abs(a-B.x)p&&(l=a-(x-p)/2);const m=1-t().state.textHeight;return e.insert("rect",":first-child").attr("x",l).attr("y",m).attr("class",d?"alt-composit":"composit").attr("width",c).attr("height",B.height+t().state.textHeight+t().state.titleShift+1).attr("rx","0"),s.attr("x",l+o),x<=p&&s.attr("x",a+(c-n)/2-x/2+o),e.insert("rect",":first-child").attr("x",l).attr("y",t().state.titleShift-t().state.textHeight-t().state.padding).attr("width",c).attr("height",t().state.textHeight*3).attr("rx",t().state.radius),e.insert("rect",":first-child").attr("x",l).attr("y",t().state.titleShift-t().state.textHeight-t().state.padding).attr("width",c).attr("height",B.height+3+2*t().state.textHeight).attr("rx",t().state.radius),e},"addTitleAndBox"),V=u(e=>(e.append("circle").attr("class","end-state-outer").attr("r",t().state.sizeUnit+t().state.miniPadding).attr("cx",t().state.padding+t().state.sizeUnit+t().state.miniPadding).attr("cy",t().state.padding+t().state.sizeUnit+t().state.miniPadding),e.append("circle").attr("class","end-state-inner").attr("r",t().state.sizeUnit).attr("cx",t().state.padding+t().state.sizeUnit+2).attr("cy",t().state.padding+t().state.sizeUnit+2)),"drawEndState"),tt=u((e,i)=>{let d=t().state.forkWidth,o=t().state.forkHeight;if(i.parentId){let n=d;d=o,o=n}return e.append("rect").style("stroke","black").style("fill","black").attr("width",d).attr("height",o).attr("x",t().state.padding).attr("y",t().state.padding)},"drawForkJoinState"),et=u((e,i,d,o)=>{let n=0;const g=o.append("text");g.style("text-anchor","start"),g.attr("class","noteText");let p=e.replace(/\r\n/g,"
                                      ");p=p.replace(/\n/g,"
                                      ");const a=p.split(z.lineBreakRegex);let s=1.25*t().state.noteMargin;for(const y of a){const x=y.trim();if(x.length>0){const c=g.append("tspan");if(c.text(x),s===0){const l=c.node().getBBox();s+=l.height}n+=s,c.attr("x",i+t().state.noteMargin),c.attr("y",d+n+1.25*t().state.noteMargin)}}return{textWidth:g.node().getBBox().width,textHeight:n}},"_drawLongText"),at=u((e,i)=>{i.attr("class","state-note");const d=i.append("rect").attr("x",0).attr("y",t().state.padding),o=i.append("g"),{textWidth:n,textHeight:g}=et(e,0,0,o);return d.attr("height",g+2*t().state.noteMargin),d.attr("width",n+t().state.noteMargin*2),d},"drawNote"),_=u(function(e,i){const d=i.id,o={id:d,label:i.id,width:0,height:0},n=e.append("g").attr("id",d).attr("class","stateGroup");i.type==="start"&&j(n),i.type==="end"&&V(n),(i.type==="fork"||i.type==="join")&&tt(n,i),i.type==="note"&&at(i.note.text,n),i.type==="divider"&&q(n),i.type==="default"&&i.descriptions.length===0&&Z(n,i),i.type==="default"&&i.descriptions.length>0&&K(n,i);const g=n.node().getBBox();return o.width=g.width+2*t().state.padding,o.height=g.height+2*t().state.padding,$.set(d,o),o},"drawState"),A=0,it=u(function(e,i,d){const o=u(function(s){switch(s){case N.relationType.AGGREGATION:return"aggregation";case N.relationType.EXTENSION:return"extension";case N.relationType.COMPOSITION:return"composition";case N.relationType.DEPENDENCY:return"dependency"}},"getRelationType");i.points=i.points.filter(s=>!Number.isNaN(s.y));const n=i.points,g=U().x(function(s){return s.x}).y(function(s){return s.y}).curve(F),p=e.append("path").attr("d",g(n)).attr("id","edge"+A).attr("class","transition");let a="";if(t().state.arrowMarkerAbsolute&&(a=window.location.protocol+"//"+window.location.host+window.location.pathname+window.location.search,a=a.replace(/\(/g,"\\("),a=a.replace(/\)/g,"\\)")),p.attr("marker-end","url("+a+"#"+o(N.relationType.DEPENDENCY)+"End)"),d.title!==void 0){const s=e.append("g").attr("class","stateLabel"),{x:y,y:x}=O.calcLabelPosition(i.points),c=z.getRows(d.title);let l=0;const B=[];let m=0,k=0;for(let f=0;f<=c.length;f++){const h=s.append("text").attr("text-anchor","middle").text(c[f]).attr("x",y).attr("y",x+l),w=h.node().getBBox();m=Math.max(m,w.width),k=Math.min(k,w.x),S.info(w.x,y,x+l),l===0&&(l=h.node().getBBox().height,S.info("Title height",l,x)),B.push(h)}let E=l*c.length;if(c.length>1){const f=(c.length-1)*l*.5;B.forEach((h,w)=>h.attr("y",x+w*l-f)),E=l*c.length}const r=s.node().getBBox();s.insert("rect",":first-child").attr("class","box").attr("x",y-m/2-t().state.padding/2).attr("y",x-E/2-t().state.padding/2-3.5).attr("width",m+t().state.padding).attr("height",E+t().state.padding),S.info(r)}A++},"drawEdge"),b,T={},rt=u(function(){},"setConf"),nt=u(function(e){e.append("defs").append("marker").attr("id","dependencyEnd").attr("refX",19).attr("refY",7).attr("markerWidth",20).attr("markerHeight",28).attr("orient","auto").append("path").attr("d","M 19,7 L9,13 L14,7 L9,1 Z")},"insertMarkers"),st=u(function(e,i,d,o){b=t().state;const n=t().securityLevel;let g;n==="sandbox"&&(g=H("#i"+i));const p=n==="sandbox"?H(g.nodes()[0].contentDocument.body):H("body"),a=n==="sandbox"?g.nodes()[0].contentDocument:document;S.debug("Rendering diagram "+e);const s=p.select(`[id='${i}']`);nt(s);const y=o.db.getRootDoc();R(y,s,void 0,!1,p,a,o);const x=b.padding,c=s.node().getBBox(),l=c.width+x*2,B=c.height+x*2,m=l*1.75;C(s,B,m,b.useMaxWidth),s.attr("viewBox",`${c.x-b.padding} ${c.y-b.padding} `+l+" "+B)},"draw"),dt=u(e=>e?e.length*b.fontSizeFactor:1,"getLabelWidth"),R=u((e,i,d,o,n,g,p)=>{const a=new J({compound:!0,multigraph:!0});let s,y=!0;for(s=0;s{const w=h.parentElement;let v=0,M=0;w&&(w.parentElement&&(v=w.parentElement.getBBox().width),M=parseInt(w.getAttribute("data-x-shift"),10),Number.isNaN(M)&&(M=0)),h.setAttribute("x1",0-M+8),h.setAttribute("x2",v-M-8)})):S.debug("No Node "+r+": "+JSON.stringify(a.node(r)))});let k=m.getBBox();a.edges().forEach(function(r){r!==void 0&&a.edge(r)!==void 0&&(S.debug("Edge "+r.v+" -> "+r.w+": "+JSON.stringify(a.edge(r))),it(i,a.edge(r),a.edge(r).relation))}),k=m.getBBox();const E={id:d||"root",label:d||"root",width:0,height:0};return E.width=k.width+2*b.padding,E.height=k.height+2*b.padding,S.debug("Doc rendered",E,a),E},"renderDoc"),ot={setConf:rt,draw:st},yt={parser:W,db:N,renderer:ot,styles:P,init:u(e=>{e.state||(e.state={}),e.state.arrowMarkerAbsolute=e.arrowMarkerAbsolute,N.clear()},"init")};export{yt as diagram}; diff --git a/assets/stateDiagram-v2-QXVA2PVL-C7QgvS5i.js b/assets/stateDiagram-v2-QXVA2PVL-C7QgvS5i.js deleted file mode 100644 index fc823eedfc..0000000000 --- a/assets/stateDiagram-v2-QXVA2PVL-C7QgvS5i.js +++ /dev/null @@ -1 +0,0 @@ -import{s as e,a as t,c as r,b as s}from"./chunk-SVGOEX7Z-7nrOxk8C.js";import{_ as i}from"./mermaid.core-DapiNGBY.js";import"./chunk-Z2VRG6XP-DsASRjJ5.js";import"./chunk-FUIDI54P-DcJSRBm9.js";import"./app-DBM4OJyw.js";var p={parser:e,db:t,renderer:r,styles:s,init:i(a=>{a.state||(a.state={}),a.state.arrowMarkerAbsolute=a.arrowMarkerAbsolute,t.clear()},"init")};export{p as diagram}; diff --git a/assets/stateDiagram-v2-QXVA2PVL-Cuqsw1mS.js b/assets/stateDiagram-v2-QXVA2PVL-Cuqsw1mS.js new file mode 100644 index 0000000000..0090bcfc03 --- /dev/null +++ b/assets/stateDiagram-v2-QXVA2PVL-Cuqsw1mS.js @@ -0,0 +1 @@ +import{s as e,a as t,c as r,b as s}from"./chunk-SVGOEX7Z-FYkNEjJq.js";import{_ as i}from"./mermaid.core-D8igZDel.js";import"./chunk-Z2VRG6XP-CV0pyCU1.js";import"./chunk-FUIDI54P-B3wdDwu1.js";import"./app-D7uBbsY3.js";var p={parser:e,db:t,renderer:r,styles:s,init:i(a=>{a.state||(a.state={}),a.state.arrowMarkerAbsolute=a.arrowMarkerAbsolute,t.clear()},"init")};export{p as diagram}; diff --git a/assets/stats.html-j3PBvFA5.js b/assets/stats.html-2bJtqbfP.js similarity index 97% rename from assets/stats.html-j3PBvFA5.js rename to assets/stats.html-2bJtqbfP.js index 8049313799..e27d9a8904 100644 --- a/assets/stats.html-j3PBvFA5.js +++ b/assets/stats.html-2bJtqbfP.js @@ -1,4 +1,4 @@ -import{_ as c,r as e,o,c as r,a as i,b as p,d as t,w as l,e as a}from"./app-DBM4OJyw.js";const d={},f=a(`

                                      Traffic Statistics

                                      Used to configure traffic statistics for Xray.

                                      StatsObject

                                      The StatsObject corresponds to the stats item in the configuration file.

                                      {
                                      +import{_ as c,r as e,o,c as r,a as i,b as p,d as t,w as l,e as a}from"./app-D7uBbsY3.js";const d={},f=a(`

                                      Traffic Statistics

                                      Used to configure traffic statistics for Xray.

                                      StatsObject

                                      The StatsObject corresponds to the stats item in the configuration file.

                                      {
                                         "stats": {}
                                       }
                                       

                                      Currently, no parameters are required for traffic statistics, and internal statistics will be enabled as long as the StatsObject item exists.

                                      `,6),g=a('

                                      Retrieving Traffic Statistics

                                      You can use the xray api command to retrieve traffic statistics.

                                      The current traffic statistics are as follows:

                                      • User Data

                                        • user>>>[email]>>>traffic>>>uplink

                                          The uplink traffic of a specific user, in bytes.

                                        • user>>>[email]>>>traffic>>>downlink

                                          The downlink traffic of a specific user, in bytes.

                                      Tip

                                      If the corresponding user does not have an email specified, statistics will not be enabled.

                                      • Global Data

                                        • inbound>>>[tag]>>>traffic>>>uplink

                                          The uplink traffic of a specific inbound, in bytes.

                                        • inbound>>>[tag]>>>traffic>>>downlink

                                          The downlink traffic of a specific inbound, in bytes.

                                        • outbound>>>[tag]>>>traffic>>>uplink

                                          The uplink traffic of a specific outbound, in bytes.

                                        • outbound>>>[tag]>>>traffic>>>downlink

                                          The downlink traffic of a specific outbound, in bytes.

                                      ',6);function u(h,b){const s=e("I18nTip"),n=e("RouterLink");return o(),r("div",null,[i(s),f,p("p",null,[t("After statistics are enabled, you only need to enable the corresponding items in the "),i(n,{to:"/en/config/policy.html"},{default:l(()=>[t("Policy")]),_:1}),t(" to collect the corresponding data.")]),g])}const k=c(d,[["render",u],["__file","stats.html.vue"]]);export{k as default}; diff --git a/assets/stats.html-Bop9jH-f.js b/assets/stats.html-Bm3zQ0hO.js similarity index 98% rename from assets/stats.html-Bop9jH-f.js rename to assets/stats.html-Bm3zQ0hO.js index 8f759fe5a8..5d36269ad8 100644 --- a/assets/stats.html-Bop9jH-f.js +++ b/assets/stats.html-Bm3zQ0hO.js @@ -1,4 +1,4 @@ -import{_ as c,r as e,o as p,c as i,a,b as l,d as t,w as d,e as n}from"./app-DBM4OJyw.js";const g={},r=n(`

                                      Статистика

                                      Используется для настройки сбора статистики трафика Xray.

                                      StatsObject

                                      StatsObject соответствует полю stats в конфигурационном файле.

                                      {
                                      +import{_ as c,r as e,o as p,c as i,a,b as l,d as t,w as d,e as n}from"./app-D7uBbsY3.js";const g={},r=n(`

                                      Статистика

                                      Используется для настройки сбора статистики трафика Xray.

                                      StatsObject

                                      StatsObject соответствует полю stats в конфигурационном файле.

                                      {
                                         "stats": {}
                                       }
                                       

                                      В настоящее время для статистики не требуется никаких параметров.
                                      Если поле StatsObject присутствует, внутренняя статистика включается.

                                      `,6),u=n('

                                      Получение статистики

                                      Вы можете получить статистику с помощью соответствующих команд xray api.

                                      В настоящее время доступна следующая статистика:

                                      • Данные пользователя

                                        • user>>>[email]>>>traffic>>>uplink

                                          Исходящий трафик для определенного пользователя в байтах.

                                        • user>>>[email]>>>traffic>>>downlink

                                          Входящий трафик для определенного пользователя в байтах.

                                      Подсказка

                                      Если для пользователя не указан email, статистика для него не будет собираться.

                                      • Глобальные данные

                                        • inbound>>>[tag]>>>traffic>>>uplink

                                          Исходящий трафик для определенного входящего подключения в байтах.

                                        • inbound>>>[tag]>>>traffic>>>downlink

                                          Входящий трафик для определенного входящего подключения в байтах.

                                        • outbound>>>[tag]>>>traffic>>>uplink

                                          Исходящий трафик для определенного исходящего подключения в байтах.

                                        • outbound>>>[tag]>>>traffic>>>downlink

                                          Входящий трафик для определенного исходящего подключения в байтах.

                                      ',6);function f(h,m){const s=e("I18nTip"),o=e("RouterLink");return p(),i("div",null,[a(s),r,l("p",null,[t("После включения статистики вам нужно только включить соответствующие параметры в разделе "),a(o,{to:"/ru/config/policy.html"},{default:d(()=>[t("Политики")]),_:1}),t(", чтобы начать сбор статистики.")]),u])}const b=c(g,[["render",f],["__file","stats.html.vue"]]);export{b as default}; diff --git a/assets/stats.html-B7OBry98.js b/assets/stats.html-Bx0KYi9t.js similarity index 97% rename from assets/stats.html-B7OBry98.js rename to assets/stats.html-Bx0KYi9t.js index 343bef9990..4c6c32c4f8 100644 --- a/assets/stats.html-B7OBry98.js +++ b/assets/stats.html-Bx0KYi9t.js @@ -1,4 +1,4 @@ -import{_ as c,r as a,o as i,c as p,a as e,b as l,d as t,w as d,e as n}from"./app-DBM4OJyw.js";const g={},u=n(`

                                      统计信息

                                      用于配置 Xray 流量数据的统计。

                                      StatsObject

                                      StatsObject 对应配置文件的 stats 项。

                                      {
                                      +import{_ as c,r as a,o as i,c as p,a as e,b as l,d as t,w as d,e as n}from"./app-D7uBbsY3.js";const g={},u=n(`

                                      统计信息

                                      用于配置 Xray 流量数据的统计。

                                      StatsObject

                                      StatsObject 对应配置文件的 stats 项。

                                      {
                                         "stats": {}
                                       }
                                       

                                      目前统计信息不需要任何参数,只要 StatsObject 项存在,内部的统计即会开启。

                                      `,6),r=n('

                                      获取统计信息

                                      可以用 xray api 的相关命令获取统计信息.

                                      目前已有的统计信息如下:

                                      • 用户数据

                                        • user>>>[email]>>>traffic>>>uplink

                                          特定用户的上行流量,单位字节。

                                        • user>>>[email]>>>traffic>>>downlink

                                          特定用户的下行流量,单位字节。

                                      提示

                                      如果对应用户没有指定 Email,则不会开启统计。

                                      • 全局数据

                                        • inbound>>>[tag]>>>traffic>>>uplink

                                          特定 inbound 的上行流量,单位字节。

                                        • inbound>>>[tag]>>>traffic>>>downlink

                                          特定 inbound 的下行流量,单位字节。

                                        • outbound>>>[tag]>>>traffic>>>uplink

                                          特定 outbound 的上行流量,单位字节。

                                        • outbound>>>[tag]>>>traffic>>>downlink

                                          特定 outbound 的下行流量,单位字节。

                                      ',6);function f(h,b){const o=a("I18nTip"),s=a("RouterLink");return i(),p("div",null,[e(o),u,l("p",null,[t("开启了统计以后, 只需在 "),e(s,{to:"/config/policy.html"},{default:d(()=>[t("Policy")]),_:1}),t(" 中开启对应的项,就可以统计对应的数据。")]),r])}const _=c(g,[["render",f],["__file","stats.html.vue"]]);export{_ as default}; diff --git a/assets/tcp.html-MnZXrAQL.js b/assets/tcp.html-CwUsir3D.js similarity index 99% rename from assets/tcp.html-MnZXrAQL.js rename to assets/tcp.html-CwUsir3D.js index 11dcb25b69..01536d7625 100644 --- a/assets/tcp.html-MnZXrAQL.js +++ b/assets/tcp.html-CwUsir3D.js @@ -1,4 +1,4 @@ -import{_ as c,r as a,o as u,c as l,a as e,b as s,d as n,e as o}from"./app-DBM4OJyw.js";const i={},r=o(`

                                      TCP

                                      Режим транспорта TCP — один из рекомендуемых в настоящее время режимов транспорта.

                                      Может использоваться в различных комбинациях с различными протоколами.

                                      TcpObject

                                      TcpObject соответствует элементу tcpSettings в конфигурации транспорта.

                                      {
                                      +import{_ as c,r as a,o as u,c as l,a as e,b as s,d as n,e as o}from"./app-D7uBbsY3.js";const i={},r=o(`

                                      TCP

                                      Режим транспорта TCP — один из рекомендуемых в настоящее время режимов транспорта.

                                      Может использоваться в различных комбинациях с различными протоколами.

                                      TcpObject

                                      TcpObject соответствует элементу tcpSettings в конфигурации транспорта.

                                      {
                                         "acceptProxyProtocol": false,
                                         "header": {
                                           "type": "none"
                                      diff --git a/assets/tcp.html-D_ggphrp.js b/assets/tcp.html-Cxfh7siK.js
                                      similarity index 99%
                                      rename from assets/tcp.html-D_ggphrp.js
                                      rename to assets/tcp.html-Cxfh7siK.js
                                      index d327a5258a..8671ac7644 100644
                                      --- a/assets/tcp.html-D_ggphrp.js
                                      +++ b/assets/tcp.html-Cxfh7siK.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as c,r as a,o as u,c as l,a as e,b as s,d as n,e as o}from"./app-DBM4OJyw.js";const i={},r=o(`

                                      TCP

                                      TCP 传输模式是目前推荐使用的传输模式之一.

                                      可以和各种协议有多种组合模式.

                                      TcpObject

                                      TcpObject 对应传输配置的 tcpSettings 项。

                                      {
                                      +import{_ as c,r as a,o as u,c as l,a as e,b as s,d as n,e as o}from"./app-D7uBbsY3.js";const i={},r=o(`

                                      TCP

                                      TCP 传输模式是目前推荐使用的传输模式之一.

                                      可以和各种协议有多种组合模式.

                                      TcpObject

                                      TcpObject 对应传输配置的 tcpSettings 项。

                                      {
                                         "acceptProxyProtocol": false,
                                         "header": {
                                           "type": "none"
                                      diff --git a/assets/tcp.html-D3RB1Z2i.js b/assets/tcp.html-HofSOy7q.js
                                      similarity index 99%
                                      rename from assets/tcp.html-D3RB1Z2i.js
                                      rename to assets/tcp.html-HofSOy7q.js
                                      index 0c65dfa7fa..a04f1076f2 100644
                                      --- a/assets/tcp.html-D3RB1Z2i.js
                                      +++ b/assets/tcp.html-HofSOy7q.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as c,r as e,o as r,c as l,a,b as s,d as n,e as t}from"./app-DBM4OJyw.js";const i={},u=t(`

                                      TCP

                                      TCP (Transmission Control Protocol) is currently one of the recommended transport protocols

                                      It can be combined with various protocols in multiple ways.

                                      TcpObject

                                      TcpObject corresponds to the tcpSettings item in the Transport Protocol.

                                      {
                                      +import{_ as c,r as e,o as r,c as l,a,b as s,d as n,e as t}from"./app-D7uBbsY3.js";const i={},u=t(`

                                      TCP

                                      TCP (Transmission Control Protocol) is currently one of the recommended transport protocols

                                      It can be combined with various protocols in multiple ways.

                                      TcpObject

                                      TcpObject corresponds to the tcpSettings item in the Transport Protocol.

                                      {
                                         "acceptProxyProtocol": false,
                                         "header": {
                                           "type": "none"
                                      diff --git a/assets/timeline-definition-SFF34UE4-Ct_WbDfR.js b/assets/timeline-definition-SFF34UE4-GwiTm9yo.js
                                      similarity index 99%
                                      rename from assets/timeline-definition-SFF34UE4-Ct_WbDfR.js
                                      rename to assets/timeline-definition-SFF34UE4-GwiTm9yo.js
                                      index dad1a151c1..44c0c88f09 100644
                                      --- a/assets/timeline-definition-SFF34UE4-Ct_WbDfR.js
                                      +++ b/assets/timeline-definition-SFF34UE4-GwiTm9yo.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as s,ah as xt,ai as kt,t as vt,j as q,d as _t,l as T,aa as bt,aj as wt,ak as St,al as Et}from"./mermaid.core-DapiNGBY.js";import{d as nt}from"./arc-CO2v8jBL.js";import"./app-DBM4OJyw.js";var X=function(){var n=s(function(f,i,a,d){for(a=a||{},d=f.length;d--;a[f[d]]=i);return a},"o"),t=[6,8,10,11,12,14,16,17,20,21],e=[1,9],l=[1,10],r=[1,11],h=[1,12],c=[1,13],g=[1,16],m=[1,17],p={trace:s(function(){},"trace"),yy:{},symbols_:{error:2,start:3,timeline:4,document:5,EOF:6,line:7,SPACE:8,statement:9,NEWLINE:10,title:11,acc_title:12,acc_title_value:13,acc_descr:14,acc_descr_value:15,acc_descr_multiline_value:16,section:17,period_statement:18,event_statement:19,period:20,event:21,$accept:0,$end:1},terminals_:{2:"error",4:"timeline",6:"EOF",8:"SPACE",10:"NEWLINE",11:"title",12:"acc_title",13:"acc_title_value",14:"acc_descr",15:"acc_descr_value",16:"acc_descr_multiline_value",17:"section",20:"period",21:"event"},productions_:[0,[3,3],[5,0],[5,2],[7,2],[7,1],[7,1],[7,1],[9,1],[9,2],[9,2],[9,1],[9,1],[9,1],[9,1],[18,1],[19,1]],performAction:s(function(i,a,d,u,y,o,S){var k=o.length-1;switch(y){case 1:return o[k-1];case 2:this.$=[];break;case 3:o[k-1].push(o[k]),this.$=o[k-1];break;case 4:case 5:this.$=o[k];break;case 6:case 7:this.$=[];break;case 8:u.getCommonDb().setDiagramTitle(o[k].substr(6)),this.$=o[k].substr(6);break;case 9:this.$=o[k].trim(),u.getCommonDb().setAccTitle(this.$);break;case 10:case 11:this.$=o[k].trim(),u.getCommonDb().setAccDescription(this.$);break;case 12:u.addSection(o[k].substr(8)),this.$=o[k].substr(8);break;case 15:u.addTask(o[k],0,""),this.$=o[k];break;case 16:u.addEvent(o[k].substr(2)),this.$=o[k];break}},"anonymous"),table:[{3:1,4:[1,2]},{1:[3]},n(t,[2,2],{5:3}),{6:[1,4],7:5,8:[1,6],9:7,10:[1,8],11:e,12:l,14:r,16:h,17:c,18:14,19:15,20:g,21:m},n(t,[2,7],{1:[2,1]}),n(t,[2,3]),{9:18,11:e,12:l,14:r,16:h,17:c,18:14,19:15,20:g,21:m},n(t,[2,5]),n(t,[2,6]),n(t,[2,8]),{13:[1,19]},{15:[1,20]},n(t,[2,11]),n(t,[2,12]),n(t,[2,13]),n(t,[2,14]),n(t,[2,15]),n(t,[2,16]),n(t,[2,4]),n(t,[2,9]),n(t,[2,10])],defaultActions:{},parseError:s(function(i,a){if(a.recoverable)this.trace(i);else{var d=new Error(i);throw d.hash=a,d}},"parseError"),parse:s(function(i){var a=this,d=[0],u=[],y=[null],o=[],S=this.table,k="",M=0,P=0,B=2,J=1,O=o.slice.call(arguments,1),v=Object.create(this.lexer),E={yy:{}};for(var b in this.yy)Object.prototype.hasOwnProperty.call(this.yy,b)&&(E.yy[b]=this.yy[b]);v.setInput(i,E.yy),E.yy.lexer=v,E.yy.parser=this,typeof v.yylloc>"u"&&(v.yylloc={});var L=v.yylloc;o.push(L);var A=v.options&&v.options.ranges;typeof E.yy.parseError=="function"?this.parseError=E.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function R(I){d.length=d.length-2*I,y.length=y.length-I,o.length=o.length-I}s(R,"popStack");function F(){var I;return I=u.pop()||v.lex()||J,typeof I!="number"&&(I instanceof Array&&(u=I,I=u.pop()),I=a.symbols_[I]||I),I}s(F,"lex");for(var w,C,N,K,z={},j,$,et,G;;){if(C=d[d.length-1],this.defaultActions[C]?N=this.defaultActions[C]:((w===null||typeof w>"u")&&(w=F()),N=S[C]&&S[C][w]),typeof N>"u"||!N.length||!N[0]){var Q="";G=[];for(j in S[C])this.terminals_[j]&&j>B&&G.push("'"+this.terminals_[j]+"'");v.showPosition?Q="Parse error on line "+(M+1)+`:
                                      +import{_ as s,ah as xt,ai as kt,t as vt,j as q,d as _t,l as T,aa as bt,aj as wt,ak as St,al as Et}from"./mermaid.core-D8igZDel.js";import{d as nt}from"./arc-9Itq1iXl.js";import"./app-D7uBbsY3.js";var X=function(){var n=s(function(f,i,a,d){for(a=a||{},d=f.length;d--;a[f[d]]=i);return a},"o"),t=[6,8,10,11,12,14,16,17,20,21],e=[1,9],l=[1,10],r=[1,11],h=[1,12],c=[1,13],g=[1,16],m=[1,17],p={trace:s(function(){},"trace"),yy:{},symbols_:{error:2,start:3,timeline:4,document:5,EOF:6,line:7,SPACE:8,statement:9,NEWLINE:10,title:11,acc_title:12,acc_title_value:13,acc_descr:14,acc_descr_value:15,acc_descr_multiline_value:16,section:17,period_statement:18,event_statement:19,period:20,event:21,$accept:0,$end:1},terminals_:{2:"error",4:"timeline",6:"EOF",8:"SPACE",10:"NEWLINE",11:"title",12:"acc_title",13:"acc_title_value",14:"acc_descr",15:"acc_descr_value",16:"acc_descr_multiline_value",17:"section",20:"period",21:"event"},productions_:[0,[3,3],[5,0],[5,2],[7,2],[7,1],[7,1],[7,1],[9,1],[9,2],[9,2],[9,1],[9,1],[9,1],[9,1],[18,1],[19,1]],performAction:s(function(i,a,d,u,y,o,S){var k=o.length-1;switch(y){case 1:return o[k-1];case 2:this.$=[];break;case 3:o[k-1].push(o[k]),this.$=o[k-1];break;case 4:case 5:this.$=o[k];break;case 6:case 7:this.$=[];break;case 8:u.getCommonDb().setDiagramTitle(o[k].substr(6)),this.$=o[k].substr(6);break;case 9:this.$=o[k].trim(),u.getCommonDb().setAccTitle(this.$);break;case 10:case 11:this.$=o[k].trim(),u.getCommonDb().setAccDescription(this.$);break;case 12:u.addSection(o[k].substr(8)),this.$=o[k].substr(8);break;case 15:u.addTask(o[k],0,""),this.$=o[k];break;case 16:u.addEvent(o[k].substr(2)),this.$=o[k];break}},"anonymous"),table:[{3:1,4:[1,2]},{1:[3]},n(t,[2,2],{5:3}),{6:[1,4],7:5,8:[1,6],9:7,10:[1,8],11:e,12:l,14:r,16:h,17:c,18:14,19:15,20:g,21:m},n(t,[2,7],{1:[2,1]}),n(t,[2,3]),{9:18,11:e,12:l,14:r,16:h,17:c,18:14,19:15,20:g,21:m},n(t,[2,5]),n(t,[2,6]),n(t,[2,8]),{13:[1,19]},{15:[1,20]},n(t,[2,11]),n(t,[2,12]),n(t,[2,13]),n(t,[2,14]),n(t,[2,15]),n(t,[2,16]),n(t,[2,4]),n(t,[2,9]),n(t,[2,10])],defaultActions:{},parseError:s(function(i,a){if(a.recoverable)this.trace(i);else{var d=new Error(i);throw d.hash=a,d}},"parseError"),parse:s(function(i){var a=this,d=[0],u=[],y=[null],o=[],S=this.table,k="",M=0,P=0,B=2,J=1,O=o.slice.call(arguments,1),v=Object.create(this.lexer),E={yy:{}};for(var b in this.yy)Object.prototype.hasOwnProperty.call(this.yy,b)&&(E.yy[b]=this.yy[b]);v.setInput(i,E.yy),E.yy.lexer=v,E.yy.parser=this,typeof v.yylloc>"u"&&(v.yylloc={});var L=v.yylloc;o.push(L);var A=v.options&&v.options.ranges;typeof E.yy.parseError=="function"?this.parseError=E.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function R(I){d.length=d.length-2*I,y.length=y.length-I,o.length=o.length-I}s(R,"popStack");function F(){var I;return I=u.pop()||v.lex()||J,typeof I!="number"&&(I instanceof Array&&(u=I,I=u.pop()),I=a.symbols_[I]||I),I}s(F,"lex");for(var w,C,N,K,z={},j,$,et,G;;){if(C=d[d.length-1],this.defaultActions[C]?N=this.defaultActions[C]:((w===null||typeof w>"u")&&(w=F()),N=S[C]&&S[C][w]),typeof N>"u"||!N.length||!N[0]){var Q="";G=[];for(j in S[C])this.terminals_[j]&&j>B&&G.push("'"+this.terminals_[j]+"'");v.showPosition?Q="Parse error on line "+(M+1)+`:
                                       `+v.showPosition()+`
                                       Expecting `+G.join(", ")+", got '"+(this.terminals_[w]||w)+"'":Q="Parse error on line "+(M+1)+": Unexpected "+(w==J?"end of input":"'"+(this.terminals_[w]||w)+"'"),this.parseError(Q,{text:v.match,token:this.terminals_[w]||w,line:v.yylineno,loc:L,expected:G})}if(N[0]instanceof Array&&N.length>1)throw new Error("Parse Error: multiple actions possible at state: "+C+", token: "+w);switch(N[0]){case 1:d.push(w),y.push(v.yytext),o.push(v.yylloc),d.push(N[1]),w=null,P=v.yyleng,k=v.yytext,M=v.yylineno,L=v.yylloc;break;case 2:if($=this.productions_[N[1]][1],z.$=y[y.length-$],z._$={first_line:o[o.length-($||1)].first_line,last_line:o[o.length-1].last_line,first_column:o[o.length-($||1)].first_column,last_column:o[o.length-1].last_column},A&&(z._$.range=[o[o.length-($||1)].range[0],o[o.length-1].range[1]]),K=this.performAction.apply(z,[k,P,M,E.yy,N[1],y,o].concat(O)),typeof K<"u")return K;$&&(d=d.slice(0,-1*$*2),y=y.slice(0,-1*$),o=o.slice(0,-1*$)),d.push(this.productions_[N[1]][0]),y.push(z.$),o.push(z._$),et=S[d[d.length-2]][d[d.length-1]],d.push(et);break;case 3:return!0}}return!0},"parse")},x=function(){var f={EOF:1,parseError:s(function(a,d){if(this.yy.parser)this.yy.parser.parseError(a,d);else throw new Error(a)},"parseError"),setInput:s(function(i,a){return this.yy=a||this.yy||{},this._input=i,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},"setInput"),input:s(function(){var i=this._input[0];this.yytext+=i,this.yyleng++,this.offset++,this.match+=i,this.matched+=i;var a=i.match(/(?:\r\n?|\n).*/g);return a?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),i},"input"),unput:s(function(i){var a=i.length,d=i.split(/(?:\r\n?|\n)/g);this._input=i+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-a),this.offset-=a;var u=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),d.length-1&&(this.yylineno-=d.length-1);var y=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:d?(d.length===u.length?this.yylloc.first_column:0)+u[u.length-d.length].length-d[0].length:this.yylloc.first_column-a},this.options.ranges&&(this.yylloc.range=[y[0],y[0]+this.yyleng-a]),this.yyleng=this.yytext.length,this},"unput"),more:s(function(){return this._more=!0,this},"more"),reject:s(function(){if(this.options.backtrack_lexer)this._backtrack=!0;else return this.parseError("Lexical error on line "+(this.yylineno+1)+`. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).
                                       `+this.showPosition(),{text:"",token:null,line:this.yylineno});return this},"reject"),less:s(function(i){this.unput(this.match.slice(i))},"less"),pastInput:s(function(){var i=this.matched.substr(0,this.matched.length-this.match.length);return(i.length>20?"...":"")+i.substr(-20).replace(/\n/g,"")},"pastInput"),upcomingInput:s(function(){var i=this.match;return i.length<20&&(i+=this._input.substr(0,20-i.length)),(i.substr(0,20)+(i.length>20?"...":"")).replace(/\n/g,"")},"upcomingInput"),showPosition:s(function(){var i=this.pastInput(),a=new Array(i.length+1).join("-");return i+this.upcomingInput()+`
                                      diff --git a/assets/tproxy.html-2EI4CZc5.js b/assets/tproxy.html-BuzTQD_L.js
                                      similarity index 99%
                                      rename from assets/tproxy.html-2EI4CZc5.js
                                      rename to assets/tproxy.html-BuzTQD_L.js
                                      index 78819196e3..b0f53be772 100644
                                      --- a/assets/tproxy.html-2EI4CZc5.js
                                      +++ b/assets/tproxy.html-BuzTQD_L.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as i,r as p,o as c,c as u,a,b as n,d as s,w as e,e as k}from"./app-DBM4OJyw.js";const d={},v=n("h1",{id:"руководство-по-настроике-прозрачного-проксирования-tproxy",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#руководство-по-настроике-прозрачного-проксирования-tproxy"},[n("span",null,"Руководство по настройке прозрачного проксирования (TProxy)")])],-1),m={href:"https://guide.v2fly.org/app/tproxy.html",target:"_blank",rel:"noopener noreferrer"},b=n("p",null,"Все конфигурации, представленные в этой статье, были успешно протестированы в средах Raspberry Pi 2B и Ubuntu 20.04. При использовании в других средах вам может потребоваться изменить конфигурацию.",-1),q=n("h2",{id:"перед-началом-работы",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#перед-началом-работы"},[n("span",null,"Перед началом работы")])],-1),g=n("p",null,"Убедитесь, что на вашем устройстве есть доступное сетевое подключение, сервер настроен, а клиент установлен.",-1),y={href:"https://github.com/XTLS/Xray-core/discussions/59",target:"_blank",rel:"noopener noreferrer"},f=n("p",null,[s("Хочу добавить, что многие руководства по настройке прозрачного проксирования используют Netfilter для разделения трафика, отправляя прямой трафик напрямую, минуя Xray. В этом случае необходимо включить переадресацию IP."),n("br"),s(" Другие руководства, например это, направляют весь трафик через Xray, где он разделяется модулем маршрутизации Xray. В этом случае переадресацию IP включать не нужно.")],-1),h=n("h2",{id:"настроика-xray",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#настроика-xray"},[n("span",null,"Настройка Xray")])],-1),R={href:"https://github.com/Loyalsoldier/v2ray-rules-dat",target:"_blank",rel:"noopener noreferrer"},_=k(`
                                      sudo curl -oL /usr/local/share/xray/geoip.dat https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat
                                      +import{_ as i,r as p,o as c,c as u,a,b as n,d as s,w as e,e as k}from"./app-D7uBbsY3.js";const d={},v=n("h1",{id:"руководство-по-настроике-прозрачного-проксирования-tproxy",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#руководство-по-настроике-прозрачного-проксирования-tproxy"},[n("span",null,"Руководство по настройке прозрачного проксирования (TProxy)")])],-1),m={href:"https://guide.v2fly.org/app/tproxy.html",target:"_blank",rel:"noopener noreferrer"},b=n("p",null,"Все конфигурации, представленные в этой статье, были успешно протестированы в средах Raspberry Pi 2B и Ubuntu 20.04. При использовании в других средах вам может потребоваться изменить конфигурацию.",-1),q=n("h2",{id:"перед-началом-работы",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#перед-началом-работы"},[n("span",null,"Перед началом работы")])],-1),g=n("p",null,"Убедитесь, что на вашем устройстве есть доступное сетевое подключение, сервер настроен, а клиент установлен.",-1),y={href:"https://github.com/XTLS/Xray-core/discussions/59",target:"_blank",rel:"noopener noreferrer"},f=n("p",null,[s("Хочу добавить, что многие руководства по настройке прозрачного проксирования используют Netfilter для разделения трафика, отправляя прямой трафик напрямую, минуя Xray. В этом случае необходимо включить переадресацию IP."),n("br"),s(" Другие руководства, например это, направляют весь трафик через Xray, где он разделяется модулем маршрутизации Xray. В этом случае переадресацию IP включать не нужно.")],-1),h=n("h2",{id:"настроика-xray",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#настроика-xray"},[n("span",null,"Настройка Xray")])],-1),R={href:"https://github.com/Loyalsoldier/v2ray-rules-dat",target:"_blank",rel:"noopener noreferrer"},_=k(`
                                      sudo curl -oL /usr/local/share/xray/geoip.dat https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat
                                       sudo curl -oL /usr/local/share/xray/geosite.dat https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat
                                       
                                      {
                                         "log": {
                                      diff --git a/assets/tproxy.html-DOLwYTgg.js b/assets/tproxy.html-CR4rpIqz.js
                                      similarity index 99%
                                      rename from assets/tproxy.html-DOLwYTgg.js
                                      rename to assets/tproxy.html-CR4rpIqz.js
                                      index a67d8049cc..7a3e015474 100644
                                      --- a/assets/tproxy.html-DOLwYTgg.js
                                      +++ b/assets/tproxy.html-CR4rpIqz.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as i,r as p,o as c,c as u,a,b as n,d as s,w as e,e as k}from"./app-DBM4OJyw.js";const d={},v=n("h1",{id:"透明代理-tproxy-配置教程",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#透明代理-tproxy-配置教程"},[n("span",null,"透明代理(TProxy)配置教程")])],-1),m={href:"https://guide.v2fly.org/app/tproxy.html",target:"_blank",rel:"noopener noreferrer"},b=n("p",null,"本文中所有配置已在 Raspberry Pi 2B、Ubuntu 20.04 环境下测试成功,如在其它环境中使用请自行调整配置。",-1),q=n("h2",{id:"开始之前",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#开始之前"},[n("span",null,"开始之前")])],-1),g=n("p",null,"请检查您的设备是否有可用的网络连接,且服务端已经配置成功,客户端已经安装完毕。",-1),y={href:"https://github.com/XTLS/Xray-core/discussions/59",target:"_blank",rel:"noopener noreferrer"},f=n("p",null,"这里我想要补充的是,很多透明代理教程会使用 Netfilter 进行分流,使直连流量直接发出而不经过 Xray,这时必须开启 IP 转发;也有的教程,如本文,会将所有流量导入 Xray 之中,由 Xray 的路由模块进行分流,这时无需开启 IP 转发。",-1),h=n("h2",{id:"xray-配置",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#xray-配置"},[n("span",null,"Xray 配置")])],-1),R={href:"https://github.com/Loyalsoldier/v2ray-rules-dat",target:"_blank",rel:"noopener noreferrer"},_=k(`
                                      sudo curl -oL /usr/local/share/xray/geoip.dat https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat
                                      +import{_ as i,r as p,o as c,c as u,a,b as n,d as s,w as e,e as k}from"./app-D7uBbsY3.js";const d={},v=n("h1",{id:"透明代理-tproxy-配置教程",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#透明代理-tproxy-配置教程"},[n("span",null,"透明代理(TProxy)配置教程")])],-1),m={href:"https://guide.v2fly.org/app/tproxy.html",target:"_blank",rel:"noopener noreferrer"},b=n("p",null,"本文中所有配置已在 Raspberry Pi 2B、Ubuntu 20.04 环境下测试成功,如在其它环境中使用请自行调整配置。",-1),q=n("h2",{id:"开始之前",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#开始之前"},[n("span",null,"开始之前")])],-1),g=n("p",null,"请检查您的设备是否有可用的网络连接,且服务端已经配置成功,客户端已经安装完毕。",-1),y={href:"https://github.com/XTLS/Xray-core/discussions/59",target:"_blank",rel:"noopener noreferrer"},f=n("p",null,"这里我想要补充的是,很多透明代理教程会使用 Netfilter 进行分流,使直连流量直接发出而不经过 Xray,这时必须开启 IP 转发;也有的教程,如本文,会将所有流量导入 Xray 之中,由 Xray 的路由模块进行分流,这时无需开启 IP 转发。",-1),h=n("h2",{id:"xray-配置",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#xray-配置"},[n("span",null,"Xray 配置")])],-1),R={href:"https://github.com/Loyalsoldier/v2ray-rules-dat",target:"_blank",rel:"noopener noreferrer"},_=k(`
                                      sudo curl -oL /usr/local/share/xray/geoip.dat https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat
                                       sudo curl -oL /usr/local/share/xray/geosite.dat https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat
                                       
                                      {
                                         "log": {
                                      diff --git a/assets/tproxy.html-D5vAMDfU.js b/assets/tproxy.html-CVfbj2d5.js
                                      similarity index 99%
                                      rename from assets/tproxy.html-D5vAMDfU.js
                                      rename to assets/tproxy.html-CVfbj2d5.js
                                      index a67d8049cc..7a3e015474 100644
                                      --- a/assets/tproxy.html-D5vAMDfU.js
                                      +++ b/assets/tproxy.html-CVfbj2d5.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as i,r as p,o as c,c as u,a,b as n,d as s,w as e,e as k}from"./app-DBM4OJyw.js";const d={},v=n("h1",{id:"透明代理-tproxy-配置教程",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#透明代理-tproxy-配置教程"},[n("span",null,"透明代理(TProxy)配置教程")])],-1),m={href:"https://guide.v2fly.org/app/tproxy.html",target:"_blank",rel:"noopener noreferrer"},b=n("p",null,"本文中所有配置已在 Raspberry Pi 2B、Ubuntu 20.04 环境下测试成功,如在其它环境中使用请自行调整配置。",-1),q=n("h2",{id:"开始之前",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#开始之前"},[n("span",null,"开始之前")])],-1),g=n("p",null,"请检查您的设备是否有可用的网络连接,且服务端已经配置成功,客户端已经安装完毕。",-1),y={href:"https://github.com/XTLS/Xray-core/discussions/59",target:"_blank",rel:"noopener noreferrer"},f=n("p",null,"这里我想要补充的是,很多透明代理教程会使用 Netfilter 进行分流,使直连流量直接发出而不经过 Xray,这时必须开启 IP 转发;也有的教程,如本文,会将所有流量导入 Xray 之中,由 Xray 的路由模块进行分流,这时无需开启 IP 转发。",-1),h=n("h2",{id:"xray-配置",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#xray-配置"},[n("span",null,"Xray 配置")])],-1),R={href:"https://github.com/Loyalsoldier/v2ray-rules-dat",target:"_blank",rel:"noopener noreferrer"},_=k(`
                                      sudo curl -oL /usr/local/share/xray/geoip.dat https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat
                                      +import{_ as i,r as p,o as c,c as u,a,b as n,d as s,w as e,e as k}from"./app-D7uBbsY3.js";const d={},v=n("h1",{id:"透明代理-tproxy-配置教程",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#透明代理-tproxy-配置教程"},[n("span",null,"透明代理(TProxy)配置教程")])],-1),m={href:"https://guide.v2fly.org/app/tproxy.html",target:"_blank",rel:"noopener noreferrer"},b=n("p",null,"本文中所有配置已在 Raspberry Pi 2B、Ubuntu 20.04 环境下测试成功,如在其它环境中使用请自行调整配置。",-1),q=n("h2",{id:"开始之前",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#开始之前"},[n("span",null,"开始之前")])],-1),g=n("p",null,"请检查您的设备是否有可用的网络连接,且服务端已经配置成功,客户端已经安装完毕。",-1),y={href:"https://github.com/XTLS/Xray-core/discussions/59",target:"_blank",rel:"noopener noreferrer"},f=n("p",null,"这里我想要补充的是,很多透明代理教程会使用 Netfilter 进行分流,使直连流量直接发出而不经过 Xray,这时必须开启 IP 转发;也有的教程,如本文,会将所有流量导入 Xray 之中,由 Xray 的路由模块进行分流,这时无需开启 IP 转发。",-1),h=n("h2",{id:"xray-配置",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#xray-配置"},[n("span",null,"Xray 配置")])],-1),R={href:"https://github.com/Loyalsoldier/v2ray-rules-dat",target:"_blank",rel:"noopener noreferrer"},_=k(`
                                      sudo curl -oL /usr/local/share/xray/geoip.dat https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat
                                       sudo curl -oL /usr/local/share/xray/geosite.dat https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat
                                       
                                      {
                                         "log": {
                                      diff --git a/assets/tproxy_ipv4_and_ipv6.html-LFerpS1d.js b/assets/tproxy_ipv4_and_ipv6.html-BDAlrSaS.js
                                      similarity index 99%
                                      rename from assets/tproxy_ipv4_and_ipv6.html-LFerpS1d.js
                                      rename to assets/tproxy_ipv4_and_ipv6.html-BDAlrSaS.js
                                      index 8c2ceb174d..cda6c42e50 100644
                                      --- a/assets/tproxy_ipv4_and_ipv6.html-LFerpS1d.js
                                      +++ b/assets/tproxy_ipv4_and_ipv6.html-BDAlrSaS.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as l,r as p,o as i,c as r,a,b as s,d as n,e as t}from"./app-DBM4OJyw.js";const c={},u=s("h1",{id:"руководство-по-настроике-прозрачного-проксирования-tproxy-ipv4-и-ipv6",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#руководство-по-настроике-прозрачного-проксирования-tproxy-ipv4-и-ipv6"},[s("span",null,"Руководство по настройке прозрачного проксирования TProxy (ipv4 и ipv6)")])],-1),d={href:"https://guide.v2fly.org/app/tproxy.html",target:"_blank",rel:"noopener noreferrer"},v={href:"https://xtls.github.io/document/level-2/tproxy.html#%E5%BC%80%E5%A7%8B%E4%B9%8B%E5%89%8D",target:"_blank",rel:"noopener noreferrer"},k={href:"https://xtls.github.io/document/level-2/iptables_gid.html",target:"_blank",rel:"noopener noreferrer"},m={href:"https://github.com/XTLS/Xray-examples",target:"_blank",rel:"noopener noreferrer"},b={href:"https://github.com/chika0801/Xray-examples",target:"_blank",rel:"noopener noreferrer"},q={href:"https://github.com/lxhao61/integrated-examples",target:"_blank",rel:"noopener noreferrer"},g=t('

                                      Внимание

                                      При использовании других конфигураций обратите особое внимание на часть outbound с тегом proxy в конфигурации клиента. Остальные части остаются неизменными.

                                      Конфигурация сервера также должна быть изменена соответственно.

                                      Эта конфигурация предназначена для решения проблемы, когда такие сайты, как Netflix, которые по умолчанию используют IPv6, не могут быть проксированы через пограничный маршрутизатор, или когда требуется проксирование IPv6.

                                      В данной статье используется сетевая структура с пограничным маршрутизатором с одним интерфейсом.

                                      Все конфигурации, представленные в этой статье, были успешно протестированы в среде Arch Linux (Kernel: 6.0.10). В других средах настройка аналогична.

                                      Убедитесь, что установлены необходимые программы: # sudo apt install iptables ip6tables или # sudo apt install nftables.

                                      ',5),y={href:"https://github.com/XTLS/Xray-core/releases/download/v1.7.0/Xray-linux-64.zip",target:"_blank",rel:"noopener noreferrer"},h={href:"https://github.com/XTLS/Xray-install/blob/main/install-release.sh",target:"_blank",rel:"noopener noreferrer"},f=s("code",null,"# chmod 700 install-release.sh",-1),x=s("code",null,"# ./install-release.sh --local Xray-linux-64.zip",-1),R=t(`

                                      Настройка Xray

                                      Конфигурация клиента

                                      {
                                      +import{_ as l,r as p,o as i,c as r,a,b as s,d as n,e as t}from"./app-D7uBbsY3.js";const c={},u=s("h1",{id:"руководство-по-настроике-прозрачного-проксирования-tproxy-ipv4-и-ipv6",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#руководство-по-настроике-прозрачного-проксирования-tproxy-ipv4-и-ipv6"},[s("span",null,"Руководство по настройке прозрачного проксирования TProxy (ipv4 и ipv6)")])],-1),d={href:"https://guide.v2fly.org/app/tproxy.html",target:"_blank",rel:"noopener noreferrer"},v={href:"https://xtls.github.io/document/level-2/tproxy.html#%E5%BC%80%E5%A7%8B%E4%B9%8B%E5%89%8D",target:"_blank",rel:"noopener noreferrer"},k={href:"https://xtls.github.io/document/level-2/iptables_gid.html",target:"_blank",rel:"noopener noreferrer"},m={href:"https://github.com/XTLS/Xray-examples",target:"_blank",rel:"noopener noreferrer"},b={href:"https://github.com/chika0801/Xray-examples",target:"_blank",rel:"noopener noreferrer"},q={href:"https://github.com/lxhao61/integrated-examples",target:"_blank",rel:"noopener noreferrer"},g=t('

                                      Внимание

                                      При использовании других конфигураций обратите особое внимание на часть outbound с тегом proxy в конфигурации клиента. Остальные части остаются неизменными.

                                      Конфигурация сервера также должна быть изменена соответственно.

                                      Эта конфигурация предназначена для решения проблемы, когда такие сайты, как Netflix, которые по умолчанию используют IPv6, не могут быть проксированы через пограничный маршрутизатор, или когда требуется проксирование IPv6.

                                      В данной статье используется сетевая структура с пограничным маршрутизатором с одним интерфейсом.

                                      Все конфигурации, представленные в этой статье, были успешно протестированы в среде Arch Linux (Kernel: 6.0.10). В других средах настройка аналогична.

                                      Убедитесь, что установлены необходимые программы: # sudo apt install iptables ip6tables или # sudo apt install nftables.

                                      ',5),y={href:"https://github.com/XTLS/Xray-core/releases/download/v1.7.0/Xray-linux-64.zip",target:"_blank",rel:"noopener noreferrer"},h={href:"https://github.com/XTLS/Xray-install/blob/main/install-release.sh",target:"_blank",rel:"noopener noreferrer"},f=s("code",null,"# chmod 700 install-release.sh",-1),x=s("code",null,"# ./install-release.sh --local Xray-linux-64.zip",-1),R=t(`

                                      Настройка Xray

                                      Конфигурация клиента

                                      {
                                         "log": {
                                           "loglevel": "warning"
                                         },
                                      diff --git a/assets/tproxy_ipv4_and_ipv6.html-CI5U13dZ.js b/assets/tproxy_ipv4_and_ipv6.html-CpYyYPCl.js
                                      similarity index 99%
                                      rename from assets/tproxy_ipv4_and_ipv6.html-CI5U13dZ.js
                                      rename to assets/tproxy_ipv4_and_ipv6.html-CpYyYPCl.js
                                      index aea2e23e71..0ab8ec95d8 100644
                                      --- a/assets/tproxy_ipv4_and_ipv6.html-CI5U13dZ.js
                                      +++ b/assets/tproxy_ipv4_and_ipv6.html-CpYyYPCl.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as l,r as p,o as i,c as r,a,b as s,d as n,e as t}from"./app-DBM4OJyw.js";const c={},u=s("h1",{id:"tproxy-透明代理-ipv4-and-ipv6-配置教程",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#tproxy-透明代理-ipv4-and-ipv6-配置教程"},[s("span",null,"TProxy 透明代理(ipv4 and ipv6)配置教程")])],-1),d={href:"https://guide.v2fly.org/app/tproxy.html",target:"_blank",rel:"noopener noreferrer"},v={href:"https://xtls.github.io/document/level-2/tproxy.html#%E5%BC%80%E5%A7%8B%E4%B9%8B%E5%89%8D",target:"_blank",rel:"noopener noreferrer"},k={href:"https://xtls.github.io/document/level-2/iptables_gid.html",target:"_blank",rel:"noopener noreferrer"},m={href:"https://github.com/XTLS/Xray-examples",target:"_blank",rel:"noopener noreferrer"},b={href:"https://github.com/chika0801/Xray-examples",target:"_blank",rel:"noopener noreferrer"},q={href:"https://github.com/lxhao61/integrated-examples",target:"_blank",rel:"noopener noreferrer"},g=t('

                                      注意

                                      若使用其他配置,你需要着重注意客户端配置中 outboundtagproxy 的部分,其他部分不变

                                      服务端配置也要同时改变

                                      此配置意在解决例如 Netflix 等默认使用 ipv6 连接的网站无法通过旁路由进行代理的问题,或对 ipv6 代理有需要。

                                      本文网络结构为单臂旁路由

                                      本文中所有配置已在 Arch Linux (Kernel: 6.0.10) 环境下测试成功,如在其它环境中同理

                                      注意安装相应程序 # sudo apt install iptables ip6tables# sudo apt install nftables

                                      ',5),y={href:"https://github.com/XTLS/Xray-core/releases/download/v1.7.0/Xray-linux-64.zip",target:"_blank",rel:"noopener noreferrer"},h={href:"https://github.com/XTLS/Xray-install/blob/main/install-release.sh",target:"_blank",rel:"noopener noreferrer"},f=s("code",null,"# chmod 700 install-release.sh",-1),x=s("code",null,"# ./install-release.sh --local Xray-linux-64.zip",-1),R=t(`

                                      Xray 配置

                                      客户端配置

                                      {
                                      +import{_ as l,r as p,o as i,c as r,a,b as s,d as n,e as t}from"./app-D7uBbsY3.js";const c={},u=s("h1",{id:"tproxy-透明代理-ipv4-and-ipv6-配置教程",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#tproxy-透明代理-ipv4-and-ipv6-配置教程"},[s("span",null,"TProxy 透明代理(ipv4 and ipv6)配置教程")])],-1),d={href:"https://guide.v2fly.org/app/tproxy.html",target:"_blank",rel:"noopener noreferrer"},v={href:"https://xtls.github.io/document/level-2/tproxy.html#%E5%BC%80%E5%A7%8B%E4%B9%8B%E5%89%8D",target:"_blank",rel:"noopener noreferrer"},k={href:"https://xtls.github.io/document/level-2/iptables_gid.html",target:"_blank",rel:"noopener noreferrer"},m={href:"https://github.com/XTLS/Xray-examples",target:"_blank",rel:"noopener noreferrer"},b={href:"https://github.com/chika0801/Xray-examples",target:"_blank",rel:"noopener noreferrer"},q={href:"https://github.com/lxhao61/integrated-examples",target:"_blank",rel:"noopener noreferrer"},g=t('

                                      注意

                                      若使用其他配置,你需要着重注意客户端配置中 outboundtagproxy 的部分,其他部分不变

                                      服务端配置也要同时改变

                                      此配置意在解决例如 Netflix 等默认使用 ipv6 连接的网站无法通过旁路由进行代理的问题,或对 ipv6 代理有需要。

                                      本文网络结构为单臂旁路由

                                      本文中所有配置已在 Arch Linux (Kernel: 6.0.10) 环境下测试成功,如在其它环境中同理

                                      注意安装相应程序 # sudo apt install iptables ip6tables# sudo apt install nftables

                                      ',5),y={href:"https://github.com/XTLS/Xray-core/releases/download/v1.7.0/Xray-linux-64.zip",target:"_blank",rel:"noopener noreferrer"},h={href:"https://github.com/XTLS/Xray-install/blob/main/install-release.sh",target:"_blank",rel:"noopener noreferrer"},f=s("code",null,"# chmod 700 install-release.sh",-1),x=s("code",null,"# ./install-release.sh --local Xray-linux-64.zip",-1),R=t(`

                                      Xray 配置

                                      客户端配置

                                      {
                                         "log": {
                                           "loglevel": "warning"
                                         },
                                      diff --git a/assets/tproxy_ipv4_and_ipv6.html-875AR2Id.js b/assets/tproxy_ipv4_and_ipv6.html-D1QYhYGk.js
                                      similarity index 99%
                                      rename from assets/tproxy_ipv4_and_ipv6.html-875AR2Id.js
                                      rename to assets/tproxy_ipv4_and_ipv6.html-D1QYhYGk.js
                                      index b0d59224a4..a7a6183f44 100644
                                      --- a/assets/tproxy_ipv4_and_ipv6.html-875AR2Id.js
                                      +++ b/assets/tproxy_ipv4_and_ipv6.html-D1QYhYGk.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as l,r as p,o as i,c as r,a,b as s,d as n,e as t}from"./app-DBM4OJyw.js";const c={},u=s("h1",{id:"tproxy-透明代理-ipv4-and-ipv6-配置教程",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#tproxy-透明代理-ipv4-and-ipv6-配置教程"},[s("span",null,"TProxy 透明代理(ipv4 and ipv6)配置教程")])],-1),d={href:"https://guide.v2fly.org/app/tproxy.html",target:"_blank",rel:"noopener noreferrer"},v={href:"https://xtls.github.io/document/level-2/tproxy.html#%E5%BC%80%E5%A7%8B%E4%B9%8B%E5%89%8D",target:"_blank",rel:"noopener noreferrer"},k={href:"https://xtls.github.io/document/level-2/iptables_gid.html",target:"_blank",rel:"noopener noreferrer"},m={href:"https://github.com/XTLS/Xray-examples",target:"_blank",rel:"noopener noreferrer"},b={href:"https://github.com/chika0801/Xray-examples",target:"_blank",rel:"noopener noreferrer"},q={href:"https://github.com/lxhao61/integrated-examples",target:"_blank",rel:"noopener noreferrer"},g=t('

                                      注意

                                      若使用其他配置,你需要着重注意客户端配置中 outboundtagproxy 的部分,其他部分不变

                                      服务端配置也要同时改变

                                      此配置意在解决例如 Netflix 等默认使用 ipv6 连接的网站无法通过旁路由进行代理的问题,或对 ipv6 代理有需要。

                                      本文网络结构为单臂旁路由

                                      本文中所有配置已在 Arch Linux (Kernel: 6.0.10) 环境下测试成功,如在其它环境中同理

                                      注意安装相应程序 # sudo apt install iptables ip6tables# sudo apt install nftables

                                      ',5),y={href:"https://github.com/XTLS/Xray-core/releases/download/v1.7.0/Xray-linux-64.zip",target:"_blank",rel:"noopener noreferrer"},h={href:"https://github.com/XTLS/Xray-install/blob/main/install-release.sh",target:"_blank",rel:"noopener noreferrer"},f=s("code",null,"# chmod 700 install-release.sh",-1),x=s("code",null,"# ./install-release.sh --local Xray-linux-64.zip",-1),R=t(`

                                      Xray 配置

                                      客户端配置

                                      {
                                      +import{_ as l,r as p,o as i,c as r,a,b as s,d as n,e as t}from"./app-D7uBbsY3.js";const c={},u=s("h1",{id:"tproxy-透明代理-ipv4-and-ipv6-配置教程",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#tproxy-透明代理-ipv4-and-ipv6-配置教程"},[s("span",null,"TProxy 透明代理(ipv4 and ipv6)配置教程")])],-1),d={href:"https://guide.v2fly.org/app/tproxy.html",target:"_blank",rel:"noopener noreferrer"},v={href:"https://xtls.github.io/document/level-2/tproxy.html#%E5%BC%80%E5%A7%8B%E4%B9%8B%E5%89%8D",target:"_blank",rel:"noopener noreferrer"},k={href:"https://xtls.github.io/document/level-2/iptables_gid.html",target:"_blank",rel:"noopener noreferrer"},m={href:"https://github.com/XTLS/Xray-examples",target:"_blank",rel:"noopener noreferrer"},b={href:"https://github.com/chika0801/Xray-examples",target:"_blank",rel:"noopener noreferrer"},q={href:"https://github.com/lxhao61/integrated-examples",target:"_blank",rel:"noopener noreferrer"},g=t('

                                      注意

                                      若使用其他配置,你需要着重注意客户端配置中 outboundtagproxy 的部分,其他部分不变

                                      服务端配置也要同时改变

                                      此配置意在解决例如 Netflix 等默认使用 ipv6 连接的网站无法通过旁路由进行代理的问题,或对 ipv6 代理有需要。

                                      本文网络结构为单臂旁路由

                                      本文中所有配置已在 Arch Linux (Kernel: 6.0.10) 环境下测试成功,如在其它环境中同理

                                      注意安装相应程序 # sudo apt install iptables ip6tables# sudo apt install nftables

                                      ',5),y={href:"https://github.com/XTLS/Xray-core/releases/download/v1.7.0/Xray-linux-64.zip",target:"_blank",rel:"noopener noreferrer"},h={href:"https://github.com/XTLS/Xray-install/blob/main/install-release.sh",target:"_blank",rel:"noopener noreferrer"},f=s("code",null,"# chmod 700 install-release.sh",-1),x=s("code",null,"# ./install-release.sh --local Xray-linux-64.zip",-1),R=t(`

                                      Xray 配置

                                      客户端配置

                                      {
                                         "log": {
                                           "loglevel": "warning"
                                         },
                                      diff --git a/assets/traffic_stats.html-mKRKbS-b.js b/assets/traffic_stats.html-BVpwRqGM.js
                                      similarity index 99%
                                      rename from assets/traffic_stats.html-mKRKbS-b.js
                                      rename to assets/traffic_stats.html-BVpwRqGM.js
                                      index 21e53dd0c7..09bf37214a 100644
                                      --- a/assets/traffic_stats.html-mKRKbS-b.js
                                      +++ b/assets/traffic_stats.html-BVpwRqGM.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as o,r as a,o as l,c as i,a as t,b as s,d as n,e as c}from"./app-DBM4OJyw.js";const u={},r=s("h1",{id:"руководство-по-настроике-статистики-трафика",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#руководство-по-настроике-статистики-трафика"},[s("span",null,"Руководство по настройке статистики трафика")])],-1),d={href:"https://guide.v2fly.org/advanced/traffic.html",target:"_blank",rel:"noopener noreferrer"},v=s("br",null,null,-1),k=c(`

                                      Просмотр статистики трафика

                                      Способ настройки такой же, как и для v2fly. Просмотр статистики трафика - одна из функций командной строки Xray. Порт api dokodemo-door, указанный в конфигурации, - это порт, используемый в параметре --server.

                                      xray api statsquery --server=127.0.0.1:10085 # Просмотр всей статистики трафика
                                      +import{_ as o,r as a,o as l,c as i,a as t,b as s,d as n,e as c}from"./app-D7uBbsY3.js";const u={},r=s("h1",{id:"руководство-по-настроике-статистики-трафика",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#руководство-по-настроике-статистики-трафика"},[s("span",null,"Руководство по настройке статистики трафика")])],-1),d={href:"https://guide.v2fly.org/advanced/traffic.html",target:"_blank",rel:"noopener noreferrer"},v=s("br",null,null,-1),k=c(`

                                      Просмотр статистики трафика

                                      Способ настройки такой же, как и для v2fly. Просмотр статистики трафика - одна из функций командной строки Xray. Порт api dokodemo-door, указанный в конфигурации, - это порт, используемый в параметре --server.

                                      xray api statsquery --server=127.0.0.1:10085 # Просмотр всей статистики трафика
                                       xray help api statsquery # statsquery - запрос соответствующих записей
                                       xray help api stats # stats - запрос одной записи
                                       

                                      Пример вывода:

                                      {
                                      diff --git a/assets/traffic_stats.html-BvcqGaeo.js b/assets/traffic_stats.html-B_7LVx9s.js
                                      similarity index 99%
                                      rename from assets/traffic_stats.html-BvcqGaeo.js
                                      rename to assets/traffic_stats.html-B_7LVx9s.js
                                      index b9252e80bb..b392f8c742 100644
                                      --- a/assets/traffic_stats.html-BvcqGaeo.js
                                      +++ b/assets/traffic_stats.html-B_7LVx9s.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as o,r as a,o as l,c as i,a as t,b as s,d as n,e as c}from"./app-DBM4OJyw.js";const u={},r=s("h1",{id:"流量统计配置教程",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#流量统计配置教程"},[s("span",null,"流量统计配置教程")])],-1),d={href:"https://guide.v2fly.org/advanced/traffic.html",target:"_blank",rel:"noopener noreferrer"},v=c(`

                                      查看流量信息

                                      配置方法与 v2fly 一致。 查看流量信息是 xray 命令行的其中一个功能。配置内设置的 api dokodemo-door 端口,即为 --server 参数的端口。

                                      xray api statsquery --server=127.0.0.1:10085 #查看所有流量
                                      +import{_ as o,r as a,o as l,c as i,a as t,b as s,d as n,e as c}from"./app-D7uBbsY3.js";const u={},r=s("h1",{id:"流量统计配置教程",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#流量统计配置教程"},[s("span",null,"流量统计配置教程")])],-1),d={href:"https://guide.v2fly.org/advanced/traffic.html",target:"_blank",rel:"noopener noreferrer"},v=c(`

                                      查看流量信息

                                      配置方法与 v2fly 一致。 查看流量信息是 xray 命令行的其中一个功能。配置内设置的 api dokodemo-door 端口,即为 --server 参数的端口。

                                      xray api statsquery --server=127.0.0.1:10085 #查看所有流量
                                       xray help api statsquery #statsquery 查询匹配的记录
                                       xray help api stats #stats 查询一个记录
                                       

                                      输出例子:

                                      {
                                      diff --git a/assets/traffic_stats.html--hyCQe7p.js b/assets/traffic_stats.html-DsMiCXCX.js
                                      similarity index 99%
                                      rename from assets/traffic_stats.html--hyCQe7p.js
                                      rename to assets/traffic_stats.html-DsMiCXCX.js
                                      index b9252e80bb..b392f8c742 100644
                                      --- a/assets/traffic_stats.html--hyCQe7p.js
                                      +++ b/assets/traffic_stats.html-DsMiCXCX.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as o,r as a,o as l,c as i,a as t,b as s,d as n,e as c}from"./app-DBM4OJyw.js";const u={},r=s("h1",{id:"流量统计配置教程",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#流量统计配置教程"},[s("span",null,"流量统计配置教程")])],-1),d={href:"https://guide.v2fly.org/advanced/traffic.html",target:"_blank",rel:"noopener noreferrer"},v=c(`

                                      查看流量信息

                                      配置方法与 v2fly 一致。 查看流量信息是 xray 命令行的其中一个功能。配置内设置的 api dokodemo-door 端口,即为 --server 参数的端口。

                                      xray api statsquery --server=127.0.0.1:10085 #查看所有流量
                                      +import{_ as o,r as a,o as l,c as i,a as t,b as s,d as n,e as c}from"./app-D7uBbsY3.js";const u={},r=s("h1",{id:"流量统计配置教程",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#流量统计配置教程"},[s("span",null,"流量统计配置教程")])],-1),d={href:"https://guide.v2fly.org/advanced/traffic.html",target:"_blank",rel:"noopener noreferrer"},v=c(`

                                      查看流量信息

                                      配置方法与 v2fly 一致。 查看流量信息是 xray 命令行的其中一个功能。配置内设置的 api dokodemo-door 端口,即为 --server 参数的端口。

                                      xray api statsquery --server=127.0.0.1:10085 #查看所有流量
                                       xray help api statsquery #statsquery 查询匹配的记录
                                       xray help api stats #stats 查询一个记录
                                       

                                      输出例子:

                                      {
                                      diff --git a/assets/transparent_proxy.html-CUyvRv2I.js b/assets/transparent_proxy.html-BipaDG8r.js
                                      similarity index 99%
                                      rename from assets/transparent_proxy.html-CUyvRv2I.js
                                      rename to assets/transparent_proxy.html-BipaDG8r.js
                                      index 75a8f13713..87c7da8044 100644
                                      --- a/assets/transparent_proxy.html-CUyvRv2I.js
                                      +++ b/assets/transparent_proxy.html-BipaDG8r.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as i,r as l,o as c,c as d,a as n,b as a,d as s,w as r,e as p}from"./app-DBM4OJyw.js";const u="/assets/netfilter-CUE6iAyE.png",b={},m=p('

                                      透明代理入门

                                      什么是透明代理

                                      透明代理简单地说就是不让被代理的设备感觉到自己被代理了。简单地说就是,被代理的设备上不需要运行任何代理软件(比如 Xray、V2RayNG 等),当你连接上网络时,你的设备已经被代理了。

                                      这也意味着,代理的软件运行在别的地方,比如运行在路由器中,通过路由器上网的设备就自动被代理了。

                                      透明代理的实现

                                      透明代理的实现目前主要有两种方式:

                                      tun2socks

                                      可用 Windows/Linux(包括安卓)实现。因为实现过程比较简单,很少有教程,我这里简单描述一下。

                                      Windows

                                      ',9),v={href:"https://github.com/NetchX/Netch/releases",target:"_blank",rel:"noopener noreferrer"},k=a("code",null,"[3] [TUN/TAP] 绕过局域网",-1),h=p("
                                    88. 开启热点

                                    89. 打开控制面板->网络和 Internet->网络和共享中心->更改适配器设置,找到TAP-Windows AdapterMicrosoft Wi-Fi Direct Virtual Adapter

                                    90. 鼠标右键点击TAP-Windows Adapter属性->共享,勾选允许其他网络用户通过此计算机的 Internet 连接来连接,在家庭网络连接中选择Microsoft Wi-Fi Direct Virtual Adapter的那个网络连接,点击确定。

                                    91. ",3),g=p('

                                      Android

                                      1. 配置连接 V2RayNG

                                      2. 开启热点

                                      3. 热点设置 -> 允许热点使用 VPN(部分安卓系统可能没有这个选项)

                                      iptables/nftables

                                      iptables 与 nftables 实现透明代理的原理相同,下文统一使用 iptables。

                                      基于 iptables 的透明代理实现只能用于 Linux 系统(包括 openwrt/安卓)。由于其比 tun2socks 更高效率以及适合在路由器中配置而广泛使用。

                                      ',5),R={href:"https://guide.v2fly.org/app/transparent_proxy.html",target:"_blank",rel:"noopener noreferrer"},A={href:"https://guide.v2fly.org/app/tproxy.html",target:"_blank",rel:"noopener noreferrer"},_=p('

                                      iptables 实现透明代理原理

                                      Linux 使用Netfilter来管理网络,Netfilter模型如下:

                                      Netfilter

                                      假设使用路由器作为网关(即我们平时的上网方式),那么:

                                      局域网设备通过路由器访问互联网的流量方向:

                                      PREROUTING链->FORWARD链->POSTINGROUTING链

                                      局域网设备访问路由器的流量(如登陆路由器 web 管理界面/ssh 连接路由器/访问路由器的 dns 服务器等)方向:

                                      PREROUTING链->INPUT链->网关本机

                                      路由器访问互联网的流量方向:

                                      网关本机->OUTPUT链->POSTINGROUTING链

                                      通过使用 iptables 操控PREROUTING链OUTPUT链的流量走向,转发到 Xray,就可以代理局域网设备和网关本机。

                                      透明代理难在哪里

                                      透明代理的难点就在于路由,所谓路由,就是区分哪些流量是直连的,哪些该被代理,所以我个人认为叫做分流更加合适。

                                      我们可以把路由由易到难分为以下几个阶段:

                                      1. 代理全部请求

                                      2. 本地局域网 IP/组播 IP 请求直连,其它请求代理

                                      3. 在 2 的基础上直连 Xray 发起的连接请求

                                      4. 在 3 的基础上直连指向中国大陆 IP 的连接请求,并对国内外域名选择国内外 DNS 服务器解析。

                                      上面说的三篇教程,都是在第四阶段。所以新手直接阅读可能显得有点难懂。

                                      从零开始一步步实现基于 iptables-tproxy 的透明代理

                                      在开始之前,你需要有一定的基础知识:

                                      1. 大概知道什么是 TCP/IP 协议、域名和 DNS 服务器

                                      2. 知道什么是 WAN 口,LAN 口,LAN_IP,WAN_IP 以及 DHCP 服务器。对于旁路由,只有一个网口,这里称其为 LAN 口

                                      3. 对 Linux 系统有最基础的了解(知道怎么运行命令)

                                      4. 能够手写客户端 json 文件配置,至少要能看懂

                                      前期准备工作

                                      注意

                                      在开始操作前,记得使用 sysctl -w net.ipv4.ip_forward=1 打开linux ipv4封包转发

                                      1. 准备一个运行 Linux 系统的网关

                                      比如,刷了 OpenWRT 的路由器

                                      2. 在网关(路由器)准备好 Xray 可执行文件以及配置文件

                                      配置文件监听 12345 端口,开启 tproxy:

                                      {
                                      +import{_ as i,r as l,o as c,c as d,a as n,b as a,d as s,w as r,e as p}from"./app-D7uBbsY3.js";const u="/assets/netfilter-CUE6iAyE.png",b={},m=p('

                                      透明代理入门

                                      什么是透明代理

                                      透明代理简单地说就是不让被代理的设备感觉到自己被代理了。简单地说就是,被代理的设备上不需要运行任何代理软件(比如 Xray、V2RayNG 等),当你连接上网络时,你的设备已经被代理了。

                                      这也意味着,代理的软件运行在别的地方,比如运行在路由器中,通过路由器上网的设备就自动被代理了。

                                      透明代理的实现

                                      透明代理的实现目前主要有两种方式:

                                      tun2socks

                                      可用 Windows/Linux(包括安卓)实现。因为实现过程比较简单,很少有教程,我这里简单描述一下。

                                      Windows

                                      ',9),v={href:"https://github.com/NetchX/Netch/releases",target:"_blank",rel:"noopener noreferrer"},k=a("code",null,"[3] [TUN/TAP] 绕过局域网",-1),h=p("
                                    92. 开启热点

                                    93. 打开控制面板->网络和 Internet->网络和共享中心->更改适配器设置,找到TAP-Windows AdapterMicrosoft Wi-Fi Direct Virtual Adapter

                                    94. 鼠标右键点击TAP-Windows Adapter属性->共享,勾选允许其他网络用户通过此计算机的 Internet 连接来连接,在家庭网络连接中选择Microsoft Wi-Fi Direct Virtual Adapter的那个网络连接,点击确定。

                                    95. ",3),g=p('

                                      Android

                                      1. 配置连接 V2RayNG

                                      2. 开启热点

                                      3. 热点设置 -> 允许热点使用 VPN(部分安卓系统可能没有这个选项)

                                      iptables/nftables

                                      iptables 与 nftables 实现透明代理的原理相同,下文统一使用 iptables。

                                      基于 iptables 的透明代理实现只能用于 Linux 系统(包括 openwrt/安卓)。由于其比 tun2socks 更高效率以及适合在路由器中配置而广泛使用。

                                      ',5),R={href:"https://guide.v2fly.org/app/transparent_proxy.html",target:"_blank",rel:"noopener noreferrer"},A={href:"https://guide.v2fly.org/app/tproxy.html",target:"_blank",rel:"noopener noreferrer"},_=p('

                                      iptables 实现透明代理原理

                                      Linux 使用Netfilter来管理网络,Netfilter模型如下:

                                      Netfilter

                                      假设使用路由器作为网关(即我们平时的上网方式),那么:

                                      局域网设备通过路由器访问互联网的流量方向:

                                      PREROUTING链->FORWARD链->POSTINGROUTING链

                                      局域网设备访问路由器的流量(如登陆路由器 web 管理界面/ssh 连接路由器/访问路由器的 dns 服务器等)方向:

                                      PREROUTING链->INPUT链->网关本机

                                      路由器访问互联网的流量方向:

                                      网关本机->OUTPUT链->POSTINGROUTING链

                                      通过使用 iptables 操控PREROUTING链OUTPUT链的流量走向,转发到 Xray,就可以代理局域网设备和网关本机。

                                      透明代理难在哪里

                                      透明代理的难点就在于路由,所谓路由,就是区分哪些流量是直连的,哪些该被代理,所以我个人认为叫做分流更加合适。

                                      我们可以把路由由易到难分为以下几个阶段:

                                      1. 代理全部请求

                                      2. 本地局域网 IP/组播 IP 请求直连,其它请求代理

                                      3. 在 2 的基础上直连 Xray 发起的连接请求

                                      4. 在 3 的基础上直连指向中国大陆 IP 的连接请求,并对国内外域名选择国内外 DNS 服务器解析。

                                      上面说的三篇教程,都是在第四阶段。所以新手直接阅读可能显得有点难懂。

                                      从零开始一步步实现基于 iptables-tproxy 的透明代理

                                      在开始之前,你需要有一定的基础知识:

                                      1. 大概知道什么是 TCP/IP 协议、域名和 DNS 服务器

                                      2. 知道什么是 WAN 口,LAN 口,LAN_IP,WAN_IP 以及 DHCP 服务器。对于旁路由,只有一个网口,这里称其为 LAN 口

                                      3. 对 Linux 系统有最基础的了解(知道怎么运行命令)

                                      4. 能够手写客户端 json 文件配置,至少要能看懂

                                      前期准备工作

                                      注意

                                      在开始操作前,记得使用 sysctl -w net.ipv4.ip_forward=1 打开linux ipv4封包转发

                                      1. 准备一个运行 Linux 系统的网关

                                      比如,刷了 OpenWRT 的路由器

                                      2. 在网关(路由器)准备好 Xray 可执行文件以及配置文件

                                      配置文件监听 12345 端口,开启 tproxy:

                                      {
                                         "log": {
                                           "loglevel": "warning"
                                         },
                                      diff --git a/assets/transparent_proxy.html-D_505nHB.js b/assets/transparent_proxy.html-BjCgSdfC.js
                                      similarity index 99%
                                      rename from assets/transparent_proxy.html-D_505nHB.js
                                      rename to assets/transparent_proxy.html-BjCgSdfC.js
                                      index 27ec846292..705a10987a 100644
                                      --- a/assets/transparent_proxy.html-D_505nHB.js
                                      +++ b/assets/transparent_proxy.html-BjCgSdfC.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as i,r as l,o as c,c as d,a as n,b as a,d as s,w as r,e as p}from"./app-DBM4OJyw.js";const u="/assets/netfilter-CUE6iAyE.png",b={},m=p('

                                      透明代理入门

                                      什么是透明代理

                                      透明代理简单地说就是不让被代理的设备感觉到自己被代理了。简单地说就是,被代理的设备上不需要运行任何代理软件(比如 Xray、V2RayNG 等),当你连接上网络时,你的设备已经被代理了。

                                      这也意味着,代理的软件运行在别的地方,比如运行在路由器中,通过路由器上网的设备就自动被代理了。

                                      透明代理的实现

                                      透明代理的实现目前主要有两种方式:

                                      tun2socks

                                      可用 Windows/Linux(包括安卓)实现。因为实现过程比较简单,很少有教程,我这里简单描述一下。

                                      Windows

                                      ',9),v={href:"https://github.com/NetchX/Netch/releases",target:"_blank",rel:"noopener noreferrer"},k=a("code",null,"[3] [TUN/TAP] 绕过局域网",-1),h=p("
                                    96. 开启热点

                                    97. 打开控制面板->网络和 Internet->网络和共享中心->更改适配器设置,找到TAP-Windows AdapterMicrosoft Wi-Fi Direct Virtual Adapter

                                    98. 鼠标右键点击TAP-Windows Adapter属性->共享,勾选允许其他网络用户通过此计算机的 Internet 连接来连接,在家庭网络连接中选择Microsoft Wi-Fi Direct Virtual Adapter的那个网络连接,点击确定。

                                    99. ",3),g=p('

                                      Android

                                      1. 配置连接 V2RayNG

                                      2. 开启热点

                                      3. 热点设置 -> 允许热点使用 VPN(部分安卓系统可能没有这个选项)

                                      iptables/nftables

                                      iptables 与 nftables 实现透明代理的原理相同,下文统一使用 iptables。

                                      基于 iptables 的透明代理实现只能用于 Linux 系统(包括 openwrt/安卓)。由于其比 tun2socks 更高效率以及适合在路由器中配置而广泛使用。

                                      ',5),R={href:"https://guide.v2fly.org/app/transparent_proxy.html",target:"_blank",rel:"noopener noreferrer"},A={href:"https://guide.v2fly.org/app/tproxy.html",target:"_blank",rel:"noopener noreferrer"},_=p('

                                      iptables 实现透明代理原理

                                      Linux 使用Netfilter来管理网络,Netfilter模型如下:

                                      Netfilter

                                      假设使用路由器作为网关(即我们平时的上网方式),那么:

                                      局域网设备通过路由器访问互联网的流量方向:

                                      PREROUTING链->FORWARD链->POSTINGROUTING链

                                      局域网设备访问路由器的流量(如登陆路由器 web 管理界面/ssh 连接路由器/访问路由器的 dns 服务器等)方向:

                                      PREROUTING链->INPUT链->网关本机

                                      路由器访问互联网的流量方向:

                                      网关本机->OUTPUT链->POSTINGROUTING链

                                      通过使用 iptables 操控PREROUTING链OUTPUT链的流量走向,转发到 Xray,就可以代理局域网设备和网关本机。

                                      透明代理难在哪里

                                      透明代理的难点就在于路由,所谓路由,就是区分哪些流量是直连的,哪些该被代理,所以我个人认为叫做分流更加合适。

                                      我们可以把路由由易到难分为以下几个阶段:

                                      1. 代理全部请求

                                      2. 本地局域网 IP/组播 IP 请求直连,其它请求代理

                                      3. 在 2 的基础上直连 Xray 发起的连接请求

                                      4. 在 3 的基础上直连指向中国大陆 IP 的连接请求,并对国内外域名选择国内外 DNS 服务器解析。

                                      上面说的三篇教程,都是在第四阶段。所以新手直接阅读可能显得有点难懂。

                                      从零开始一步步实现基于 iptables-tproxy 的透明代理

                                      在开始之前,你需要有一定的基础知识:

                                      1. 大概知道什么是 TCP/IP 协议、域名和 DNS 服务器

                                      2. 知道什么是 WAN 口,LAN 口,LAN_IP,WAN_IP 以及 DHCP 服务器。对于旁路由,只有一个网口,这里称其为 LAN 口

                                      3. 对 Linux 系统有最基础的了解(知道怎么运行命令)

                                      4. 能够手写客户端 json 文件配置,至少要能看懂

                                      前期准备工作

                                      1. 准备一个运行 Linux 系统的网关

                                      比如,刷了 OpenWRT 的路由器

                                      2. 在网关(路由器)准备好 Xray 可执行文件以及配置文件

                                      配置文件监听 12345 端口,开启 tproxy:

                                      {
                                      +import{_ as i,r as l,o as c,c as d,a as n,b as a,d as s,w as r,e as p}from"./app-D7uBbsY3.js";const u="/assets/netfilter-CUE6iAyE.png",b={},m=p('

                                      透明代理入门

                                      什么是透明代理

                                      透明代理简单地说就是不让被代理的设备感觉到自己被代理了。简单地说就是,被代理的设备上不需要运行任何代理软件(比如 Xray、V2RayNG 等),当你连接上网络时,你的设备已经被代理了。

                                      这也意味着,代理的软件运行在别的地方,比如运行在路由器中,通过路由器上网的设备就自动被代理了。

                                      透明代理的实现

                                      透明代理的实现目前主要有两种方式:

                                      tun2socks

                                      可用 Windows/Linux(包括安卓)实现。因为实现过程比较简单,很少有教程,我这里简单描述一下。

                                      Windows

                                      ',9),v={href:"https://github.com/NetchX/Netch/releases",target:"_blank",rel:"noopener noreferrer"},k=a("code",null,"[3] [TUN/TAP] 绕过局域网",-1),h=p("
                                    100. 开启热点

                                    101. 打开控制面板->网络和 Internet->网络和共享中心->更改适配器设置,找到TAP-Windows AdapterMicrosoft Wi-Fi Direct Virtual Adapter

                                    102. 鼠标右键点击TAP-Windows Adapter属性->共享,勾选允许其他网络用户通过此计算机的 Internet 连接来连接,在家庭网络连接中选择Microsoft Wi-Fi Direct Virtual Adapter的那个网络连接,点击确定。

                                    103. ",3),g=p('

                                      Android

                                      1. 配置连接 V2RayNG

                                      2. 开启热点

                                      3. 热点设置 -> 允许热点使用 VPN(部分安卓系统可能没有这个选项)

                                      iptables/nftables

                                      iptables 与 nftables 实现透明代理的原理相同,下文统一使用 iptables。

                                      基于 iptables 的透明代理实现只能用于 Linux 系统(包括 openwrt/安卓)。由于其比 tun2socks 更高效率以及适合在路由器中配置而广泛使用。

                                      ',5),R={href:"https://guide.v2fly.org/app/transparent_proxy.html",target:"_blank",rel:"noopener noreferrer"},A={href:"https://guide.v2fly.org/app/tproxy.html",target:"_blank",rel:"noopener noreferrer"},_=p('

                                      iptables 实现透明代理原理

                                      Linux 使用Netfilter来管理网络,Netfilter模型如下:

                                      Netfilter

                                      假设使用路由器作为网关(即我们平时的上网方式),那么:

                                      局域网设备通过路由器访问互联网的流量方向:

                                      PREROUTING链->FORWARD链->POSTINGROUTING链

                                      局域网设备访问路由器的流量(如登陆路由器 web 管理界面/ssh 连接路由器/访问路由器的 dns 服务器等)方向:

                                      PREROUTING链->INPUT链->网关本机

                                      路由器访问互联网的流量方向:

                                      网关本机->OUTPUT链->POSTINGROUTING链

                                      通过使用 iptables 操控PREROUTING链OUTPUT链的流量走向,转发到 Xray,就可以代理局域网设备和网关本机。

                                      透明代理难在哪里

                                      透明代理的难点就在于路由,所谓路由,就是区分哪些流量是直连的,哪些该被代理,所以我个人认为叫做分流更加合适。

                                      我们可以把路由由易到难分为以下几个阶段:

                                      1. 代理全部请求

                                      2. 本地局域网 IP/组播 IP 请求直连,其它请求代理

                                      3. 在 2 的基础上直连 Xray 发起的连接请求

                                      4. 在 3 的基础上直连指向中国大陆 IP 的连接请求,并对国内外域名选择国内外 DNS 服务器解析。

                                      上面说的三篇教程,都是在第四阶段。所以新手直接阅读可能显得有点难懂。

                                      从零开始一步步实现基于 iptables-tproxy 的透明代理

                                      在开始之前,你需要有一定的基础知识:

                                      1. 大概知道什么是 TCP/IP 协议、域名和 DNS 服务器

                                      2. 知道什么是 WAN 口,LAN 口,LAN_IP,WAN_IP 以及 DHCP 服务器。对于旁路由,只有一个网口,这里称其为 LAN 口

                                      3. 对 Linux 系统有最基础的了解(知道怎么运行命令)

                                      4. 能够手写客户端 json 文件配置,至少要能看懂

                                      前期准备工作

                                      1. 准备一个运行 Linux 系统的网关

                                      比如,刷了 OpenWRT 的路由器

                                      2. 在网关(路由器)准备好 Xray 可执行文件以及配置文件

                                      配置文件监听 12345 端口,开启 tproxy:

                                      {
                                         "log": {
                                           "loglevel": "warning"
                                         },
                                      diff --git a/assets/transparent_proxy.html-CN6RzNfw.js b/assets/transparent_proxy.html-Dbpkmzp6.js
                                      similarity index 99%
                                      rename from assets/transparent_proxy.html-CN6RzNfw.js
                                      rename to assets/transparent_proxy.html-Dbpkmzp6.js
                                      index 9ed2528ecc..d91cde0039 100644
                                      --- a/assets/transparent_proxy.html-CN6RzNfw.js
                                      +++ b/assets/transparent_proxy.html-Dbpkmzp6.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as i,r as t,o as c,c as d,a as n,b as a,d as s,w as r,e as p}from"./app-DBM4OJyw.js";const u="/assets/netfilter-CUE6iAyE.png",b={},m=p('

                                      Погружение в прозрачное проксирование

                                      Что такое прозрачное проксирование?

                                      Проще говоря, прозрачное проксирование не позволяет проксируемому устройству понять, что оно проксируется. Это означает, что на проксируемом устройстве не нужно запускать какое-либо программное обеспечение для проксирования (например, Xray, V2RayNG и т. д.). Когда вы подключаетесь к сети, ваше устройство уже проксируется.

                                      Это также означает, что программное обеспечение прокси работает в другом месте, например, на маршрутизаторе, и устройства, подключенные к Интернету через маршрутизатор, автоматически проксируются.

                                      Реализация прозрачного проксирования

                                      В настоящее время существует два основных способа реализации прозрачного проксирования:

                                      tun2socks

                                      Доступно для Windows/Linux (включая Android). Поскольку процесс реализации относительно прост, существует не так много руководств, поэтому я кратко опишу его здесь.

                                      Windows

                                      ',9),v={href:"https://github.com/NetchX/Netch/releases",target:"_blank",rel:"noopener noreferrer"},k=a("code",null,"[3] [TUN/TAP] Обход локальной сети",-1),h=p("
                                    104. Включите точку доступа.

                                    105. Откройте Панель управления -> Сеть и Интернет -> Центр управления сетями и общим доступом -> Изменение параметров адаптера, найдите TAP-Windows Adapter и Microsoft Wi-Fi Direct Virtual Adapter.

                                    106. Щелкните правой кнопкой мыши TAP-Windows Adapter, Свойства -> Доступ, установите флажок Разрешить другим пользователям сети подключаться к Интернету через это подключение к Интернету, в Домашнее сетевое подключение выберите сетевое подключение Microsoft Wi-Fi Direct Virtual Adapter, нажмите ОК.

                                    107. ",3),g=p('

                                      Android

                                      1. Настройте подключение V2RayNG.

                                      2. Включите точку доступа.

                                      3. Настройки точки доступа -> Разрешить использование VPN для точки доступа (эта опция может отсутствовать в некоторых системах Android).

                                      iptables/nftables

                                      iptables и nftables реализуют прозрачное проксирование по одному и тому же принципу, в дальнейшем мы будем использовать iptables.

                                      Реализация прозрачного проксирования на основе iptables применима только к системам Linux (включая openwrt/Android). Благодаря своей эффективности по сравнению с tun2socks и возможности настройки на маршрутизаторах, она получила широкое распространение.

                                      ',5),R={href:"https://guide.v2fly.org/app/transparent_proxy.html",target:"_blank",rel:"noopener noreferrer"},A={href:"https://guide.v2fly.org/app/tproxy.html",target:"_blank",rel:"noopener noreferrer"},D=p('

                                      Принцип реализации прозрачного проксирования с помощью iptables

                                      Linux использует Netfilter для управления сетью, модель Netfilter выглядит следующим образом:

                                      Netfilter

                                      Предположим, что в качестве шлюза используется маршрутизатор (т. е. наш обычный способ подключения к Интернету), тогда:

                                      Направление трафика от устройств локальной сети к Интернету через маршрутизатор:

                                      Цепочка PREROUTING -> Цепочка FORWARD -> Цепочка POSTINGROUTING

                                      Направление трафика от устройств локальной сети к маршрутизатору (например, вход в веб-интерфейс маршрутизатора/подключение к маршрутизатору по ssh/доступ к DNS-серверу маршрутизатора и т. д.):

                                      Цепочка PREROUTING -> Цепочка INPUT -> Хост шлюза

                                      Направление трафика от маршрутизатора к Интернету:

                                      Хост шлюза -> Цепочка OUTPUT -> Цепочка POSTINGROUTING

                                      Управляя направлением трафика цепочек PREROUTING и OUTPUT с помощью iptables и перенаправляя его на Xray, мы можем проксировать устройства локальной сети и хост шлюза.

                                      В чем сложность прозрачного проксирования?

                                      Сложность прозрачного проксирования заключается в маршрутизации, то есть в различении того, какой трафик должен быть прямым, а какой должен проксироваться, поэтому я лично считаю, что термин разделение трафика более уместен.

                                      Мы можем разделить маршрутизацию на следующие этапы по возрастанию сложности:

                                      1. Проксирование всех запросов.
                                      2. Прямое подключение для локальных IP-адресов/многоадресных IP-адресов, проксирование для остальных запросов.
                                      3. На основе пункта 2, прямое подключение для исходящих запросов, инициированных Xray.
                                      4. На основе пункта 3, прямое подключение для запросов, адресованных китайским IP-адресам, и выбор внутренних и внешних DNS-серверов для разрешения внутренних и внешних доменных имен.

                                      Три вышеупомянутых руководства описывают четвертый этап. Поэтому новичкам может быть сложно понять их, читая напрямую.

                                      Пошаговая реализация прозрачного проксирования на основе iptables-tproxy с нуля

                                      Прежде чем начать, вам необходимо иметь базовые знания:

                                      1. Примерное представление о протоколах TCP/IP, доменных именах и DNS-серверах.
                                      2. Знание того, что такое WAN-порт, LAN-порт, LAN_IP, WAN_IP и DHCP-сервер. Для пограничных маршрутизаторов есть только один сетевой порт, который мы будем называть LAN-портом.
                                      3. Базовое понимание системы Linux (знание того, как запускать команды).
                                      4. Умение писать конфигурационные файлы клиента в формате json или, по крайней мере, понимать их.

                                      Предварительная подготовка

                                      Внимание

                                      Перед началом работы не забудьте включить пересылку пакетов ipv4 в Linux с помощью команды sysctl -w net.ipv4.ip_forward=1

                                      1. Подготовьте шлюз под управлением Linux

                                      Например, маршрутизатор с прошивкой OpenWRT.

                                      2. Подготовьте исполняемый файл Xray и конфигурационный файл на шлюзе (маршрутизаторе)

                                      Конфигурационный файл прослушивает порт 12345 и включает tproxy:

                                      {
                                      +import{_ as i,r as t,o as c,c as d,a as n,b as a,d as s,w as r,e as p}from"./app-D7uBbsY3.js";const u="/assets/netfilter-CUE6iAyE.png",b={},m=p('

                                      Погружение в прозрачное проксирование

                                      Что такое прозрачное проксирование?

                                      Проще говоря, прозрачное проксирование не позволяет проксируемому устройству понять, что оно проксируется. Это означает, что на проксируемом устройстве не нужно запускать какое-либо программное обеспечение для проксирования (например, Xray, V2RayNG и т. д.). Когда вы подключаетесь к сети, ваше устройство уже проксируется.

                                      Это также означает, что программное обеспечение прокси работает в другом месте, например, на маршрутизаторе, и устройства, подключенные к Интернету через маршрутизатор, автоматически проксируются.

                                      Реализация прозрачного проксирования

                                      В настоящее время существует два основных способа реализации прозрачного проксирования:

                                      tun2socks

                                      Доступно для Windows/Linux (включая Android). Поскольку процесс реализации относительно прост, существует не так много руководств, поэтому я кратко опишу его здесь.

                                      Windows

                                      ',9),v={href:"https://github.com/NetchX/Netch/releases",target:"_blank",rel:"noopener noreferrer"},k=a("code",null,"[3] [TUN/TAP] Обход локальной сети",-1),h=p("
                                    108. Включите точку доступа.

                                    109. Откройте Панель управления -> Сеть и Интернет -> Центр управления сетями и общим доступом -> Изменение параметров адаптера, найдите TAP-Windows Adapter и Microsoft Wi-Fi Direct Virtual Adapter.

                                    110. Щелкните правой кнопкой мыши TAP-Windows Adapter, Свойства -> Доступ, установите флажок Разрешить другим пользователям сети подключаться к Интернету через это подключение к Интернету, в Домашнее сетевое подключение выберите сетевое подключение Microsoft Wi-Fi Direct Virtual Adapter, нажмите ОК.

                                    111. ",3),g=p('

                                      Android

                                      1. Настройте подключение V2RayNG.

                                      2. Включите точку доступа.

                                      3. Настройки точки доступа -> Разрешить использование VPN для точки доступа (эта опция может отсутствовать в некоторых системах Android).

                                      iptables/nftables

                                      iptables и nftables реализуют прозрачное проксирование по одному и тому же принципу, в дальнейшем мы будем использовать iptables.

                                      Реализация прозрачного проксирования на основе iptables применима только к системам Linux (включая openwrt/Android). Благодаря своей эффективности по сравнению с tun2socks и возможности настройки на маршрутизаторах, она получила широкое распространение.

                                      ',5),R={href:"https://guide.v2fly.org/app/transparent_proxy.html",target:"_blank",rel:"noopener noreferrer"},A={href:"https://guide.v2fly.org/app/tproxy.html",target:"_blank",rel:"noopener noreferrer"},D=p('

                                      Принцип реализации прозрачного проксирования с помощью iptables

                                      Linux использует Netfilter для управления сетью, модель Netfilter выглядит следующим образом:

                                      Netfilter

                                      Предположим, что в качестве шлюза используется маршрутизатор (т. е. наш обычный способ подключения к Интернету), тогда:

                                      Направление трафика от устройств локальной сети к Интернету через маршрутизатор:

                                      Цепочка PREROUTING -> Цепочка FORWARD -> Цепочка POSTINGROUTING

                                      Направление трафика от устройств локальной сети к маршрутизатору (например, вход в веб-интерфейс маршрутизатора/подключение к маршрутизатору по ssh/доступ к DNS-серверу маршрутизатора и т. д.):

                                      Цепочка PREROUTING -> Цепочка INPUT -> Хост шлюза

                                      Направление трафика от маршрутизатора к Интернету:

                                      Хост шлюза -> Цепочка OUTPUT -> Цепочка POSTINGROUTING

                                      Управляя направлением трафика цепочек PREROUTING и OUTPUT с помощью iptables и перенаправляя его на Xray, мы можем проксировать устройства локальной сети и хост шлюза.

                                      В чем сложность прозрачного проксирования?

                                      Сложность прозрачного проксирования заключается в маршрутизации, то есть в различении того, какой трафик должен быть прямым, а какой должен проксироваться, поэтому я лично считаю, что термин разделение трафика более уместен.

                                      Мы можем разделить маршрутизацию на следующие этапы по возрастанию сложности:

                                      1. Проксирование всех запросов.
                                      2. Прямое подключение для локальных IP-адресов/многоадресных IP-адресов, проксирование для остальных запросов.
                                      3. На основе пункта 2, прямое подключение для исходящих запросов, инициированных Xray.
                                      4. На основе пункта 3, прямое подключение для запросов, адресованных китайским IP-адресам, и выбор внутренних и внешних DNS-серверов для разрешения внутренних и внешних доменных имен.

                                      Три вышеупомянутых руководства описывают четвертый этап. Поэтому новичкам может быть сложно понять их, читая напрямую.

                                      Пошаговая реализация прозрачного проксирования на основе iptables-tproxy с нуля

                                      Прежде чем начать, вам необходимо иметь базовые знания:

                                      1. Примерное представление о протоколах TCP/IP, доменных именах и DNS-серверах.
                                      2. Знание того, что такое WAN-порт, LAN-порт, LAN_IP, WAN_IP и DHCP-сервер. Для пограничных маршрутизаторов есть только один сетевой порт, который мы будем называть LAN-портом.
                                      3. Базовое понимание системы Linux (знание того, как запускать команды).
                                      4. Умение писать конфигурационные файлы клиента в формате json или, по крайней мере, понимать их.

                                      Предварительная подготовка

                                      Внимание

                                      Перед началом работы не забудьте включить пересылку пакетов ipv4 в Linux с помощью команды sysctl -w net.ipv4.ip_forward=1

                                      1. Подготовьте шлюз под управлением Linux

                                      Например, маршрутизатор с прошивкой OpenWRT.

                                      2. Подготовьте исполняемый файл Xray и конфигурационный файл на шлюзе (маршрутизаторе)

                                      Конфигурационный файл прослушивает порт 12345 и включает tproxy:

                                      {
                                         "log": {
                                           "loglevel": "warning"
                                         },
                                      diff --git a/assets/transport.html-8xgD8RRD.js b/assets/transport.html-7DOFUUXD.js
                                      similarity index 99%
                                      rename from assets/transport.html-8xgD8RRD.js
                                      rename to assets/transport.html-7DOFUUXD.js
                                      index 0323807d0b..774eaffa7f 100644
                                      --- a/assets/transport.html-8xgD8RRD.js
                                      +++ b/assets/transport.html-7DOFUUXD.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as u,r as c,o as i,c as r,a as o,b as n,d as s,w as p,e as t}from"./app-DBM4OJyw.js";const d={},k=t(`

                                      Транспорт

                                      Транспорт (transport) - это способ, которым текущий узел Xray взаимодействует с другими узлами.

                                      Транспорт определяет способ передачи данных. Обычно оба конца сетевого подключения должны использовать одинаковый транспорт.
                                      Например, если один конец использует WebSocket, то другой конец также должен использовать WebSocket, иначе соединение не будет установлено.

                                      StreamSettingsObject

                                      StreamSettingsObject соответствует полю streamSettings во входящем или исходящем подключении.
                                      Каждое входящее или исходящее подключение может иметь свои собственные настройки транспорта.

                                      {
                                      +import{_ as u,r as c,o as i,c as r,a as o,b as n,d as s,w as p,e as t}from"./app-D7uBbsY3.js";const d={},k=t(`

                                      Транспорт

                                      Транспорт (transport) - это способ, которым текущий узел Xray взаимодействует с другими узлами.

                                      Транспорт определяет способ передачи данных. Обычно оба конца сетевого подключения должны использовать одинаковый транспорт.
                                      Например, если один конец использует WebSocket, то другой конец также должен использовать WebSocket, иначе соединение не будет установлено.

                                      StreamSettingsObject

                                      StreamSettingsObject соответствует полю streamSettings во входящем или исходящем подключении.
                                      Каждое входящее или исходящее подключение может иметь свои собственные настройки транспорта.

                                      {
                                         "network": "tcp",
                                         "security": "none",
                                         "tlsSettings": {},
                                      diff --git a/assets/transport.html-CoXY-KCW.js b/assets/transport.html-B2ArwUNN.js
                                      similarity index 99%
                                      rename from assets/transport.html-CoXY-KCW.js
                                      rename to assets/transport.html-B2ArwUNN.js
                                      index e8c2c4cd46..2c16d0716c 100644
                                      --- a/assets/transport.html-CoXY-KCW.js
                                      +++ b/assets/transport.html-B2ArwUNN.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as l,r as c,o as r,c as u,a as t,b as e,d as n,w as a,e as s}from"./app-DBM4OJyw.js";const d={},h=s(`

                                      Transport

                                      Transports specify how Xray communicates with peers.

                                      Transports specify how to achieve stable data transmission. Both ends of a connection often need to specify the same transport protocol to successfully establish a connection. Like, if one end uses WebSocket, the other end must also use WebSocket, or else the connection cannot be established.

                                      StreamSettingsObject

                                      StreamSettingsObject corresponds to the streamSettings property in the inbound or outbound config. Each inbound or outbound can be configured with different transports and can use streamSettings to specify local configs.

                                      {
                                      +import{_ as l,r as c,o as r,c as u,a as t,b as e,d as n,w as a,e as s}from"./app-D7uBbsY3.js";const d={},h=s(`

                                      Transport

                                      Transports specify how Xray communicates with peers.

                                      Transports specify how to achieve stable data transmission. Both ends of a connection often need to specify the same transport protocol to successfully establish a connection. Like, if one end uses WebSocket, the other end must also use WebSocket, or else the connection cannot be established.

                                      StreamSettingsObject

                                      StreamSettingsObject corresponds to the streamSettings property in the inbound or outbound config. Each inbound or outbound can be configured with different transports and can use streamSettings to specify local configs.

                                      {
                                         "network": "tcp",
                                         "security": "none",
                                         "tlsSettings": {},
                                      diff --git a/assets/transport.html-BsB3pOlv.js b/assets/transport.html-CBxA3wPn.js
                                      similarity index 99%
                                      rename from assets/transport.html-BsB3pOlv.js
                                      rename to assets/transport.html-CBxA3wPn.js
                                      index 46cc959890..78ff68c5ac 100644
                                      --- a/assets/transport.html-BsB3pOlv.js
                                      +++ b/assets/transport.html-CBxA3wPn.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as u,r as c,o as i,c as r,a as o,b as n,d as s,w as p,e as t}from"./app-DBM4OJyw.js";const d={},k=t(`

                                      传输方式(uTLS、REALITY)

                                      传输方式(transport)是当前 Xray 节点和其它节点对接的方式。

                                      传输方式指定了稳定的数据传输的方式。通常来说,一个网络连接的两端需要有对称的传输方式。比如一端用了 WebSocket,那么另一个端也必须使用 WebSocket,否则无法建立连接。

                                      StreamSettingsObject

                                      StreamSettingsObject 对应入站或出站中的 streamSettings 项。每一个入站或出站都可以分别配置不同的传输配置,都可以设置 streamSettings 来进行一些传输的配置。

                                      {
                                      +import{_ as u,r as c,o as i,c as r,a as o,b as n,d as s,w as p,e as t}from"./app-D7uBbsY3.js";const d={},k=t(`

                                      传输方式(uTLS、REALITY)

                                      传输方式(transport)是当前 Xray 节点和其它节点对接的方式。

                                      传输方式指定了稳定的数据传输的方式。通常来说,一个网络连接的两端需要有对称的传输方式。比如一端用了 WebSocket,那么另一个端也必须使用 WebSocket,否则无法建立连接。

                                      StreamSettingsObject

                                      StreamSettingsObject 对应入站或出站中的 streamSettings 项。每一个入站或出站都可以分别配置不同的传输配置,都可以设置 streamSettings 来进行一些传输的配置。

                                      {
                                         "network": "tcp",
                                         "security": "none",
                                         "tlsSettings": {},
                                      diff --git a/assets/trojan.html-2IKlUogk.js b/assets/trojan.html-C2P8Dv-p.js
                                      similarity index 98%
                                      rename from assets/trojan.html-2IKlUogk.js
                                      rename to assets/trojan.html-C2P8Dv-p.js
                                      index 7a97ef9426..118e08fa38 100644
                                      --- a/assets/trojan.html-2IKlUogk.js
                                      +++ b/assets/trojan.html-C2P8Dv-p.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as r,r as e,o as l,c as i,a,b as s,d as n,w as t,e as u}from"./app-DBM4OJyw.js";const d={},v=s("h1",{id:"trojan",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#trojan"},[s("span",null,"Trojan")])],-1),k={href:"https://trojan-gfw.github.io/trojan/protocol",target:"_blank",rel:"noopener noreferrer"},b=u(`

                                      警告

                                      Trojan 被设计工作在正确配置的加密 TLS 隧道

                                      OutboundConfigurationObject

                                      {
                                      +import{_ as r,r as e,o as l,c as i,a,b as s,d as n,w as t,e as u}from"./app-D7uBbsY3.js";const d={},v=s("h1",{id:"trojan",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#trojan"},[s("span",null,"Trojan")])],-1),k={href:"https://trojan-gfw.github.io/trojan/protocol",target:"_blank",rel:"noopener noreferrer"},b=u(`

                                      警告

                                      Trojan 被设计工作在正确配置的加密 TLS 隧道

                                      OutboundConfigurationObject

                                      {
                                         "servers": [
                                           {
                                             "address": "127.0.0.1",
                                      diff --git a/assets/trojan.html-1FTyRSM5.js b/assets/trojan.html-CeUnbQFN.js
                                      similarity index 98%
                                      rename from assets/trojan.html-1FTyRSM5.js
                                      rename to assets/trojan.html-CeUnbQFN.js
                                      index eef1ba6c61..07f3f43980 100644
                                      --- a/assets/trojan.html-1FTyRSM5.js
                                      +++ b/assets/trojan.html-CeUnbQFN.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as p,r as o,o as r,c as u,a,b as e,d as n,w as t,e as c}from"./app-DBM4OJyw.js";const d={},b=e("h1",{id:"trojan",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#trojan"},[e("span",null,"Trojan")])],-1),k={href:"https://trojan-gfw.github.io/trojan/protocol",target:"_blank",rel:"noopener noreferrer"},v=c(`

                                      Danger

                                      Trojan is designed to work with correctly configured encrypted TLS tunnels.

                                      InboundConfigurationObject

                                      {
                                      +import{_ as p,r as o,o as r,c as u,a,b as e,d as n,w as t,e as c}from"./app-D7uBbsY3.js";const d={},b=e("h1",{id:"trojan",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#trojan"},[e("span",null,"Trojan")])],-1),k={href:"https://trojan-gfw.github.io/trojan/protocol",target:"_blank",rel:"noopener noreferrer"},v=c(`

                                      Danger

                                      Trojan is designed to work with correctly configured encrypted TLS tunnels.

                                      InboundConfigurationObject

                                      {
                                         "clients": [
                                           {
                                             "password": "password",
                                      diff --git a/assets/trojan.html-UWktEtCO.js b/assets/trojan.html-DekTkRrf.js
                                      similarity index 98%
                                      rename from assets/trojan.html-UWktEtCO.js
                                      rename to assets/trojan.html-DekTkRrf.js
                                      index ac1e3f8e2b..71a7a7ce07 100644
                                      --- a/assets/trojan.html-UWktEtCO.js
                                      +++ b/assets/trojan.html-DekTkRrf.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as c,r as a,o as l,c as i,a as e,b as s,d as n,w as t,e as u}from"./app-DBM4OJyw.js";const d={},v=s("h1",{id:"trojan",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#trojan"},[s("span",null,"Trojan")])],-1),k={href:"https://trojan-gfw.github.io/trojan/protocol",target:"_blank",rel:"noopener noreferrer"},b=u(`

                                      Danger

                                      Trojan is designed to work with correctly configured encrypted TLS tunnels.

                                      OutboundConfigurationObject

                                      {
                                      +import{_ as c,r as a,o as l,c as i,a as e,b as s,d as n,w as t,e as u}from"./app-D7uBbsY3.js";const d={},v=s("h1",{id:"trojan",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#trojan"},[s("span",null,"Trojan")])],-1),k={href:"https://trojan-gfw.github.io/trojan/protocol",target:"_blank",rel:"noopener noreferrer"},b=u(`

                                      Danger

                                      Trojan is designed to work with correctly configured encrypted TLS tunnels.

                                      OutboundConfigurationObject

                                      {
                                         "servers": [
                                           {
                                             "address": "127.0.0.1",
                                      diff --git a/assets/trojan.html-BuFAAu0c.js b/assets/trojan.html-DwB8yBqZ.js
                                      similarity index 99%
                                      rename from assets/trojan.html-BuFAAu0c.js
                                      rename to assets/trojan.html-DwB8yBqZ.js
                                      index ed4dcde48d..83f4f7c904 100644
                                      --- a/assets/trojan.html-BuFAAu0c.js
                                      +++ b/assets/trojan.html-DwB8yBqZ.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as i,r as t,o as r,c as u,a,b as s,d as n,w as o,e as l}from"./app-DBM4OJyw.js";const d={},b=s("h1",{id:"trojan",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#trojan"},[s("span",null,"Trojan")])],-1),k={href:"https://trojan-gfw.github.io/trojan/protocol",target:"_blank",rel:"noopener noreferrer"},v=l(`

                                      Предупреждение

                                      Trojan предназначен для работы в правильно настроенном зашифрованном TLS-туннеле.

                                      InboundConfigurationObject

                                      {
                                      +import{_ as i,r as t,o as r,c as u,a,b as s,d as n,w as o,e as l}from"./app-D7uBbsY3.js";const d={},b=s("h1",{id:"trojan",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#trojan"},[s("span",null,"Trojan")])],-1),k={href:"https://trojan-gfw.github.io/trojan/protocol",target:"_blank",rel:"noopener noreferrer"},v=l(`

                                      Предупреждение

                                      Trojan предназначен для работы в правильно настроенном зашифрованном TLS-туннеле.

                                      InboundConfigurationObject

                                      {
                                         "clients": [
                                           {
                                             "password": "password",
                                      diff --git a/assets/trojan.html-6FO_V9lu.js b/assets/trojan.html-_w6ndVja.js
                                      similarity index 98%
                                      rename from assets/trojan.html-6FO_V9lu.js
                                      rename to assets/trojan.html-_w6ndVja.js
                                      index 7d3cb39bc4..414fff46d9 100644
                                      --- a/assets/trojan.html-6FO_V9lu.js
                                      +++ b/assets/trojan.html-_w6ndVja.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as i,r as t,o as r,c as u,a,b as s,d as n,w as o,e as c}from"./app-DBM4OJyw.js";const d={},b=s("h1",{id:"trojan",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#trojan"},[s("span",null,"Trojan")])],-1),k={href:"https://trojan-gfw.github.io/trojan/protocol",target:"_blank",rel:"noopener noreferrer"},v=c(`

                                      警告

                                      Trojan 被设计工作在正确配置的加密 TLS 隧道

                                      InboundConfigurationObject

                                      {
                                      +import{_ as i,r as t,o as r,c as u,a,b as s,d as n,w as o,e as c}from"./app-D7uBbsY3.js";const d={},b=s("h1",{id:"trojan",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#trojan"},[s("span",null,"Trojan")])],-1),k={href:"https://trojan-gfw.github.io/trojan/protocol",target:"_blank",rel:"noopener noreferrer"},v=c(`

                                      警告

                                      Trojan 被设计工作在正确配置的加密 TLS 隧道

                                      InboundConfigurationObject

                                      {
                                         "clients": [
                                           {
                                             "password": "password",
                                      diff --git a/assets/trojan.html-WioOgQKT.js b/assets/trojan.html-xViDkd9I.js
                                      similarity index 98%
                                      rename from assets/trojan.html-WioOgQKT.js
                                      rename to assets/trojan.html-xViDkd9I.js
                                      index 24ff6d27ec..701eaebc24 100644
                                      --- a/assets/trojan.html-WioOgQKT.js
                                      +++ b/assets/trojan.html-xViDkd9I.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as r,r as e,o as l,c as i,a,b as s,d as n,w as t,e as u}from"./app-DBM4OJyw.js";const d={},v=s("h1",{id:"trojan",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#trojan"},[s("span",null,"Trojan")])],-1),k={href:"https://trojan-gfw.github.io/trojan/protocol",target:"_blank",rel:"noopener noreferrer"},b=u(`

                                      Предупреждение

                                      Trojan предназначен для работы в правильно настроенном зашифрованном TLS-туннеле.

                                      OutboundConfigurationObject

                                      {
                                      +import{_ as r,r as e,o as l,c as i,a,b as s,d as n,w as t,e as u}from"./app-D7uBbsY3.js";const d={},v=s("h1",{id:"trojan",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#trojan"},[s("span",null,"Trojan")])],-1),k={href:"https://trojan-gfw.github.io/trojan/protocol",target:"_blank",rel:"noopener noreferrer"},b=u(`

                                      Предупреждение

                                      Trojan предназначен для работы в правильно настроенном зашифрованном TLS-туннеле.

                                      OutboundConfigurationObject

                                      {
                                         "servers": [
                                           {
                                             "address": "127.0.0.1",
                                      diff --git a/assets/vless.html-CVgOe_Ra.js b/assets/vless.html-B6mgaUnb.js
                                      similarity index 99%
                                      rename from assets/vless.html-CVgOe_Ra.js
                                      rename to assets/vless.html-B6mgaUnb.js
                                      index 3a4036978d..09985fe021 100644
                                      --- a/assets/vless.html-CVgOe_Ra.js
                                      +++ b/assets/vless.html-B6mgaUnb.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as i,r as a,o as u,c as r,a as e,b as n,d as s,w as t,e as p}from"./app-DBM4OJyw.js";const d={},v=n("h1",{id:"vless-xtls-vision-seed",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#vless-xtls-vision-seed"},[n("span",null,"VLESS(XTLS Vision Seed)")])],-1),k=n("div",{class:"custom-container danger"},[n("p",{class:"custom-container-title"},"警告"),n("p",null,"目前 VLESS 没有自带加密,请用于可靠信道,如 TLS。")],-1),b=n("p",null,"VLESS 是一个无状态的轻量传输协议,它分为入站和出站两部分,可以作为 Xray 客户端和服务器之间的桥梁。",-1),q=p(`

                                      OutboundConfigurationObject

                                      {
                                      +import{_ as i,r as a,o as u,c as r,a as e,b as n,d as s,w as t,e as p}from"./app-D7uBbsY3.js";const d={},v=n("h1",{id:"vless-xtls-vision-seed",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#vless-xtls-vision-seed"},[n("span",null,"VLESS(XTLS Vision Seed)")])],-1),k=n("div",{class:"custom-container danger"},[n("p",{class:"custom-container-title"},"警告"),n("p",null,"目前 VLESS 没有自带加密,请用于可靠信道,如 TLS。")],-1),b=n("p",null,"VLESS 是一个无状态的轻量传输协议,它分为入站和出站两部分,可以作为 Xray 客户端和服务器之间的桥梁。",-1),q=p(`

                                      OutboundConfigurationObject

                                      {
                                         "vnext": [
                                           {
                                             "address": "example.com",
                                      diff --git a/assets/vless.html-CvVYC0xa.js b/assets/vless.html-BCUjxVGw.js
                                      similarity index 99%
                                      rename from assets/vless.html-CvVYC0xa.js
                                      rename to assets/vless.html-BCUjxVGw.js
                                      index fb0a4b3308..5c0796fd84 100644
                                      --- a/assets/vless.html-CvVYC0xa.js
                                      +++ b/assets/vless.html-BCUjxVGw.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as l,r as t,o as r,c as u,a as s,b as n,d as e,w as a,e as i}from"./app-DBM4OJyw.js";const d={},v=n("h1",{id:"vless",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#vless"},[n("span",null,"VLESS")])],-1),h=n("div",{class:"custom-container danger"},[n("p",{class:"custom-container-title"},"Danger"),n("p",null,"Currently, VLESS does not have built-in encryption, please use it on a reliable channel, such as TLS.")],-1),b=n("p",null,"VLESS is a stateless lightweight transport protocol, which is divided into inbound and outbound parts, and can be used as a bridge between Xray clients and servers.",-1),m=i(`

                                      OutboundConfigurationObject

                                      {
                                      +import{_ as l,r as t,o as r,c as u,a as s,b as n,d as e,w as a,e as i}from"./app-D7uBbsY3.js";const d={},v=n("h1",{id:"vless",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#vless"},[n("span",null,"VLESS")])],-1),h=n("div",{class:"custom-container danger"},[n("p",{class:"custom-container-title"},"Danger"),n("p",null,"Currently, VLESS does not have built-in encryption, please use it on a reliable channel, such as TLS.")],-1),b=n("p",null,"VLESS is a stateless lightweight transport protocol, which is divided into inbound and outbound parts, and can be used as a bridge between Xray clients and servers.",-1),m=i(`

                                      OutboundConfigurationObject

                                      {
                                         "vnext": [
                                           {
                                             "address": "example.com",
                                      diff --git a/assets/vless.html-DPYoRUM4.js b/assets/vless.html-BYWxnSoj.js
                                      similarity index 99%
                                      rename from assets/vless.html-DPYoRUM4.js
                                      rename to assets/vless.html-BYWxnSoj.js
                                      index 42dc433140..9fc3835f3a 100644
                                      --- a/assets/vless.html-DPYoRUM4.js
                                      +++ b/assets/vless.html-BYWxnSoj.js
                                      @@ -1 +1 @@
                                      -import{_ as h,r as n,o as d,c,a as s,b as e,d as t,e as r}from"./app-DBM4OJyw.js";const l={},p=r('

                                      VLESS 协议

                                      VLESS 是一个无状态的轻量传输协议,可以作为 Xray 客户端和服务器之间的桥梁。

                                      Request & Response

                                      1 字节16 字节1 字节M 字节1 字节2 字节1 字节S 字节X 字节
                                      协议版本等价 UUID附加信息长度 M附加信息 ProtoBuf指令端口地址类型地址请求数据
                                      1 字节1 字节N 字节Y 字节
                                      协议版本,与请求的一致附加信息长度 N附加信息 ProtoBuf响应数据

                                      VLESS 早在第二个测试版 ALPHA 2 时就已经是上述结构了(BETA 是第五个测试版):

                                      ',6),i={href:"https://github.com/gogo/protobuf",target:"_blank",rel:"noopener noreferrer"},u=e("p",null,"我一直觉得“响应认证”不是必要的,ALPHA 时为了提升生成随机数的性能,还用 math/rand 替换 crypto/rand,而现在都不需要了。",-1),S=e("p",null,"“协议版本”不仅能起到“响应认证”的作用,还赋予了 VLESS 无痛升级协议结构的能力,带来无限的可能性。 “协议版本”在测试版本中均为 0,正式版本中为 1,以后若有不兼容的协议结构变更则应升级版本。",-1),_=e("p",null,"VLESS 服务端的设计是 switch version,即同时支持所有 VLESS 版本。若需要升级协议版本(可能到不了这一步),推荐的做法是服务端提前一个月支持,一个月后再改客户端。VMess 请求也有协议版本,但它的认证信息在外面,指令部分则高度耦合且有固定加密,导致里面的协议版本毫无意义,服务端也没有进行判断,响应则没有协议版本。Trojan 的协议结构中没有协议版本。",-1),f=e("p",null,"接下来是 UUID,我本来觉得 16 字节有点长,曾经考虑过缩短它,但后来看到 Trojan 用了 56 个可打印字符(56 字节),就彻底打消了这个念头。服务端每次都要验证 UUID,所以性能也很重要:VLESS 的 Validator 经历了多次重构/升级,相较于 VMess,它十分简洁且耗资源很少,可以同时支持非常多的用户,性能也十分强悍,验证速度极快(sync.Map)。API 动态增删用户则更高效顺滑。 https://github.com/XTLS/Xray-core/issues/158",-1),V=e("p",null,"引入 ProtoBuf 是一个创举,等下会详细讲解。“指令”到“地址”的结构目前与 VMess 完全相同,同样支持 Mux。",-1),b={href:"https://github.com/rprx/v2ray-vless/releases",target:"_blank",rel:"noopener noreferrer"},L=r('

                                      ProtoBuf

                                      似乎只有 VLESS 可选内嵌 ProtoBuf,它是一种数据交换格式,信息被紧密编码成二进制,TLV 结构(Tag Length Value)。

                                      起因是我看到一篇文章称 SS 有一些缺点,如没有设计错误回报机制,客户端没办法根据不同的错误采取进一步的动作。 (但我并不认同所有错误都要回报,不然防不了主动探测。下一个测试版中,服务器可以返回一串自定义信息。) 于是想到一个可扩展的结构是很重要的,未来它也可以承载如动态端口指令。不止响应,请求也需要类似的结构。 本来打算自己设计 TLV,接着发觉 ProtoBuf 就是此结构、现成的轮子,完全适合用来做这件事,各语言支持等也不错。

                                      目前“附加信息”只有 Scheduler 和 SchedulerV,它们是 MessName 和 MessSeed 的替代者,当你不需要它们时,“附加信息长度”为 0,也就不会有 ProtoBuf 序列化/反序列化的开销。其实我更愿意称这个过程为“拼接”,因为 pb 实际原理上也只是这么做而已,相关开销极小。拼接后的 bytes 十分紧凑,和 ALPHA 的方案相差无几,有兴趣的可以分别输出并对比。

                                      为了指示对附加信息(Addons,也可以理解成插件,以后可以有很多个插件)的不同支持程度,下个测试版会在“附加信息长度”前新增“附加信息版本”。256 - 1 = 255 字节是够用且合理的(65535 就太多了,还可能有人恶意填充),现有的只用了十分之一,以后也不会同时有那么多附加信息,且大多数情况下是完全没有附加信息的。真不够用的话,可以升级 VLESS 版本。

                                      为了减少逻辑判断等开销,暂定 Addons 不使用多级结构。一个月前出现过“可变协议格式”的想法,pb 是可以做到打乱顺序,但没必要,因为现代加密的设计不会让旁观者看出两次传输的头部相同。

                                      下面介绍 Schedulers 和 Encryption 的构想,它们都是可选的,一个应对流量时序特征问题,一个应对密码学上的问题。

                                      Schedulers Flow

                                      中文名暂称:流量调度器(2020-09-03 更新:中文名确定为“流控”),指令由 ProtoBuf 承载,控制的是数据部分。

                                      我之前发现,VMess 原有的 shake “元数据混淆”在 TLS 上完全不会带来有意义的改变,只会降低性能,所以 VLESS 弃用了它。并且,“混淆”这个表述容易被误解成伪装,也弃用了。顺便一提,我一直是不看好伪装的:做不到完全一样,那不就是强特征吗?做得到完全一样,那为什么不直接用伪装目标?我一开始用的是 SSR,后来发现它只是表面伪装骗运营商,就再也没用过了。

                                      那么,“流量调度器”要解决什么问题?它影响的是宏观流量时序特征,而不是微观特征,后者是加密要解决的事情。流量时序特征可以是协议带来的,比如 Socks5 over TLS 时的 Socks5 握手 ,TLS 上不同的这种特征对于监测者来说就是不同的协议,此时无限 Schedulers 就相当于无限协议(重新分配每次发送的数据量大小等)。流量时序特征也可以是行为带来的,比如访问 Google 首页时加载了多少文件、顺序、每个文件的大小,多套一层加密并不能有效掩盖这些信息。

                                      Schedulers 没必要像下面的 Encryption 一样整个套在外面,因为头部的一丁点数据相对于后面的数据量来说太微不足道了。

                                      BETA 2 预计推出两个初级的 Scheduler:Zstd 压缩、数据量动态扩充。进阶操作才是从宏观层面来控制、分配,暂时咕咕。

                                      Encryption

                                      与 VMess 的高度耦合不同,VLESS 的服务端、客户端不久后可以提前约定好加密方式,仅在外面套一层加密。这有点类似于使用 TLS,不影响承载的任何数据,也可以理解成底层就是从 TLS 换成预设约定加密。相对于高度耦合,这种方式更合理且灵活:一种加密方式出了安全性问题,直接扔掉并换用其它的就行了,十分方便。VLESS 服务端还会允许不同的加密方式共存。

                                      ',15),E={href:"https://github.com/rprx/v2fly-github-io/blob/master/docs/config/protocols/vless.md",target:"_blank",rel:"noopener noreferrer"},g=e("p",null,"加密支持两类形式,一类是加密完全独立,需要额外密码,适合私用,另一类是结合已有的 UUID 来加密,适合公用。 (若用第一类加密形式,且密码是以某种形式公开的,比如多人共用,那么中间人攻击就不远了) 重新设计的动态端口可能会随加密同时推出,指令由 ProtoBuf 承载,具体实现和 VMess 的动态端口也会有很多不同。",-1),y=e("p",null,"套现成加密是件很简单的事情,也就多一层 writer & reader。BETA 3 预计支持 SS 的 aes-128-gcm 和 chacha20-ietf-poly1305: 客户端的 encryption 可以填 “auto: ss_aes-128-gcm_0_123456, ss_chacha20-ietf-poly1305_0_987654”,auto 会选择最适合当前机器的,0 代表测试版,最后的是密码。服务端的 decryption 也是类似填法,收到请求时会逐一尝试解密。",-1),m=e("p",null,"并不是所有组合都需逐一尝试:VMess 的加密分为三段,第一段是认证信息,结合了 UUID、alterId、时间因素,第二段是指令部分,以固定算法加密,指令中含有数据部分使用的加密算法,第三段才是重要的数据部分。可以看出,VMess 的加解密方式实际上是多对一(服务端适配),而不仅是结合 UUID。但仅是结合 UUID 来加密也是件相对麻烦的事情,短时间内不会出,鉴于我们现在有 VMessAEAD 可用,也并不着急。若 VLESS 推出了结合 UUID 的加密方式,相当于重构了整个 VMess。",-1),T=e("h2",{id:"udp-issues",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#udp-issues"},[e("span",null,"UDP issues")])],-1),x={href:"https://github.com/XTLS/Xray-core/discussions/252",target:"_blank",rel:"noopener noreferrer"},A=r('

                                      客户端开发指引

                                      1. VLESS 协议本身还会有不兼容升级,但客户端配置文件参数基本上是只增不减的。iOS 客户端的协议实现则需紧跟升级。
                                      2. 视觉标准:UI 标识请统一用 VLESS,而不是 VLess / Vless / vless,配置文件不受影响,代码内则顺其自然。
                                      3. encryption 应做成输入框而不是选择框,新配置的默认值应为 none,若用户置空则应代填 none

                                      VLESS 分享链接标准

                                      ',3),M=e("img",{src:"https://avatars2.githubusercontent.com/u/7822648?s=32",width:"32px",height:"32px",alt:"a"},null,-1),U={href:"https://github.com/DuckSoft",target:"_blank",rel:"noopener noreferrer"},P={href:"https://github.com/XTLS/Xray-core/issues/91",target:"_blank",rel:"noopener noreferrer"};function v(B,k){const a=n("I18nTip"),o=n("ExternalLinkIcon");return d(),c("div",null,[s(a),p,e("blockquote",null,[e("p",null,[t("“响应认证”被替换为“协议版本”并移至最前,使 VLESS 可以升级换代,同时消除了生成伪随机数的开销。混淆相关结构被替换为附加信息(ProtoBuf)并前移,赋予协议本身可扩展性,相关开销也极小("),e("a",i,[t("gogo/protobuf"),s(o)]),t("),若无附加信息则无相关开销。")])]),u,S,_,f,V,e("p",null,[t("总体上,ALPHA 2 到 BETA 主要是:结构进化、清理整合、性能提升、更加完善。这些都是一点一滴的,详见 "),e("a",b,[t("VLESS Changes"),s(o)]),t("。")]),L,e("p",null,[t('对比 VMess,VLESS 相当于把 security 换成 encryption,把 disableInsecureEncryption 换成 decryption,就解决了所有问题。目前 encryption 和 decryption 只接受 "none" 且不能留空(即使以后有连接安全性检查),详见 '),e("a",E,[t("VLESS 配置文档"),s(o)]),t("。encryption 并不需要往外移一级,一是因为无法复用很多代码,二是因为会影响控制粒度,看未来的应用就明白了。")]),g,y,m,T,e("p",null,[e("a",x,[t("XUDP:VLESS & VMess & Mux UDP FullCone NAT"),s(o)])]),A,e("p",null,[t("感谢 "),M,t(),e("a",U,[t("@DuckSoft"),s(o)]),t(" 的提案!")]),e("p",null,[t("详情请见 "),e("a",P,[t("VMessAEAD / VLESS 分享链接标准提案"),s(o)])])])}const D=h(l,[["render",v],["__file","vless.html.vue"]]);export{D as default}; +import{_ as h,r as n,o as d,c,a as s,b as e,d as t,e as r}from"./app-D7uBbsY3.js";const l={},p=r('

                                      VLESS 协议

                                      VLESS 是一个无状态的轻量传输协议,可以作为 Xray 客户端和服务器之间的桥梁。

                                      Request & Response

                                      1 字节16 字节1 字节M 字节1 字节2 字节1 字节S 字节X 字节
                                      协议版本等价 UUID附加信息长度 M附加信息 ProtoBuf指令端口地址类型地址请求数据
                                      1 字节1 字节N 字节Y 字节
                                      协议版本,与请求的一致附加信息长度 N附加信息 ProtoBuf响应数据

                                      VLESS 早在第二个测试版 ALPHA 2 时就已经是上述结构了(BETA 是第五个测试版):

                                      ',6),i={href:"https://github.com/gogo/protobuf",target:"_blank",rel:"noopener noreferrer"},u=e("p",null,"我一直觉得“响应认证”不是必要的,ALPHA 时为了提升生成随机数的性能,还用 math/rand 替换 crypto/rand,而现在都不需要了。",-1),S=e("p",null,"“协议版本”不仅能起到“响应认证”的作用,还赋予了 VLESS 无痛升级协议结构的能力,带来无限的可能性。 “协议版本”在测试版本中均为 0,正式版本中为 1,以后若有不兼容的协议结构变更则应升级版本。",-1),_=e("p",null,"VLESS 服务端的设计是 switch version,即同时支持所有 VLESS 版本。若需要升级协议版本(可能到不了这一步),推荐的做法是服务端提前一个月支持,一个月后再改客户端。VMess 请求也有协议版本,但它的认证信息在外面,指令部分则高度耦合且有固定加密,导致里面的协议版本毫无意义,服务端也没有进行判断,响应则没有协议版本。Trojan 的协议结构中没有协议版本。",-1),f=e("p",null,"接下来是 UUID,我本来觉得 16 字节有点长,曾经考虑过缩短它,但后来看到 Trojan 用了 56 个可打印字符(56 字节),就彻底打消了这个念头。服务端每次都要验证 UUID,所以性能也很重要:VLESS 的 Validator 经历了多次重构/升级,相较于 VMess,它十分简洁且耗资源很少,可以同时支持非常多的用户,性能也十分强悍,验证速度极快(sync.Map)。API 动态增删用户则更高效顺滑。 https://github.com/XTLS/Xray-core/issues/158",-1),V=e("p",null,"引入 ProtoBuf 是一个创举,等下会详细讲解。“指令”到“地址”的结构目前与 VMess 完全相同,同样支持 Mux。",-1),b={href:"https://github.com/rprx/v2ray-vless/releases",target:"_blank",rel:"noopener noreferrer"},L=r('

                                      ProtoBuf

                                      似乎只有 VLESS 可选内嵌 ProtoBuf,它是一种数据交换格式,信息被紧密编码成二进制,TLV 结构(Tag Length Value)。

                                      起因是我看到一篇文章称 SS 有一些缺点,如没有设计错误回报机制,客户端没办法根据不同的错误采取进一步的动作。 (但我并不认同所有错误都要回报,不然防不了主动探测。下一个测试版中,服务器可以返回一串自定义信息。) 于是想到一个可扩展的结构是很重要的,未来它也可以承载如动态端口指令。不止响应,请求也需要类似的结构。 本来打算自己设计 TLV,接着发觉 ProtoBuf 就是此结构、现成的轮子,完全适合用来做这件事,各语言支持等也不错。

                                      目前“附加信息”只有 Scheduler 和 SchedulerV,它们是 MessName 和 MessSeed 的替代者,当你不需要它们时,“附加信息长度”为 0,也就不会有 ProtoBuf 序列化/反序列化的开销。其实我更愿意称这个过程为“拼接”,因为 pb 实际原理上也只是这么做而已,相关开销极小。拼接后的 bytes 十分紧凑,和 ALPHA 的方案相差无几,有兴趣的可以分别输出并对比。

                                      为了指示对附加信息(Addons,也可以理解成插件,以后可以有很多个插件)的不同支持程度,下个测试版会在“附加信息长度”前新增“附加信息版本”。256 - 1 = 255 字节是够用且合理的(65535 就太多了,还可能有人恶意填充),现有的只用了十分之一,以后也不会同时有那么多附加信息,且大多数情况下是完全没有附加信息的。真不够用的话,可以升级 VLESS 版本。

                                      为了减少逻辑判断等开销,暂定 Addons 不使用多级结构。一个月前出现过“可变协议格式”的想法,pb 是可以做到打乱顺序,但没必要,因为现代加密的设计不会让旁观者看出两次传输的头部相同。

                                      下面介绍 Schedulers 和 Encryption 的构想,它们都是可选的,一个应对流量时序特征问题,一个应对密码学上的问题。

                                      Schedulers Flow

                                      中文名暂称:流量调度器(2020-09-03 更新:中文名确定为“流控”),指令由 ProtoBuf 承载,控制的是数据部分。

                                      我之前发现,VMess 原有的 shake “元数据混淆”在 TLS 上完全不会带来有意义的改变,只会降低性能,所以 VLESS 弃用了它。并且,“混淆”这个表述容易被误解成伪装,也弃用了。顺便一提,我一直是不看好伪装的:做不到完全一样,那不就是强特征吗?做得到完全一样,那为什么不直接用伪装目标?我一开始用的是 SSR,后来发现它只是表面伪装骗运营商,就再也没用过了。

                                      那么,“流量调度器”要解决什么问题?它影响的是宏观流量时序特征,而不是微观特征,后者是加密要解决的事情。流量时序特征可以是协议带来的,比如 Socks5 over TLS 时的 Socks5 握手 ,TLS 上不同的这种特征对于监测者来说就是不同的协议,此时无限 Schedulers 就相当于无限协议(重新分配每次发送的数据量大小等)。流量时序特征也可以是行为带来的,比如访问 Google 首页时加载了多少文件、顺序、每个文件的大小,多套一层加密并不能有效掩盖这些信息。

                                      Schedulers 没必要像下面的 Encryption 一样整个套在外面,因为头部的一丁点数据相对于后面的数据量来说太微不足道了。

                                      BETA 2 预计推出两个初级的 Scheduler:Zstd 压缩、数据量动态扩充。进阶操作才是从宏观层面来控制、分配,暂时咕咕。

                                      Encryption

                                      与 VMess 的高度耦合不同,VLESS 的服务端、客户端不久后可以提前约定好加密方式,仅在外面套一层加密。这有点类似于使用 TLS,不影响承载的任何数据,也可以理解成底层就是从 TLS 换成预设约定加密。相对于高度耦合,这种方式更合理且灵活:一种加密方式出了安全性问题,直接扔掉并换用其它的就行了,十分方便。VLESS 服务端还会允许不同的加密方式共存。

                                      ',15),E={href:"https://github.com/rprx/v2fly-github-io/blob/master/docs/config/protocols/vless.md",target:"_blank",rel:"noopener noreferrer"},g=e("p",null,"加密支持两类形式,一类是加密完全独立,需要额外密码,适合私用,另一类是结合已有的 UUID 来加密,适合公用。 (若用第一类加密形式,且密码是以某种形式公开的,比如多人共用,那么中间人攻击就不远了) 重新设计的动态端口可能会随加密同时推出,指令由 ProtoBuf 承载,具体实现和 VMess 的动态端口也会有很多不同。",-1),y=e("p",null,"套现成加密是件很简单的事情,也就多一层 writer & reader。BETA 3 预计支持 SS 的 aes-128-gcm 和 chacha20-ietf-poly1305: 客户端的 encryption 可以填 “auto: ss_aes-128-gcm_0_123456, ss_chacha20-ietf-poly1305_0_987654”,auto 会选择最适合当前机器的,0 代表测试版,最后的是密码。服务端的 decryption 也是类似填法,收到请求时会逐一尝试解密。",-1),m=e("p",null,"并不是所有组合都需逐一尝试:VMess 的加密分为三段,第一段是认证信息,结合了 UUID、alterId、时间因素,第二段是指令部分,以固定算法加密,指令中含有数据部分使用的加密算法,第三段才是重要的数据部分。可以看出,VMess 的加解密方式实际上是多对一(服务端适配),而不仅是结合 UUID。但仅是结合 UUID 来加密也是件相对麻烦的事情,短时间内不会出,鉴于我们现在有 VMessAEAD 可用,也并不着急。若 VLESS 推出了结合 UUID 的加密方式,相当于重构了整个 VMess。",-1),T=e("h2",{id:"udp-issues",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#udp-issues"},[e("span",null,"UDP issues")])],-1),x={href:"https://github.com/XTLS/Xray-core/discussions/252",target:"_blank",rel:"noopener noreferrer"},A=r('

                                      客户端开发指引

                                      1. VLESS 协议本身还会有不兼容升级,但客户端配置文件参数基本上是只增不减的。iOS 客户端的协议实现则需紧跟升级。
                                      2. 视觉标准:UI 标识请统一用 VLESS,而不是 VLess / Vless / vless,配置文件不受影响,代码内则顺其自然。
                                      3. encryption 应做成输入框而不是选择框,新配置的默认值应为 none,若用户置空则应代填 none

                                      VLESS 分享链接标准

                                      ',3),M=e("img",{src:"https://avatars2.githubusercontent.com/u/7822648?s=32",width:"32px",height:"32px",alt:"a"},null,-1),U={href:"https://github.com/DuckSoft",target:"_blank",rel:"noopener noreferrer"},P={href:"https://github.com/XTLS/Xray-core/issues/91",target:"_blank",rel:"noopener noreferrer"};function v(B,k){const a=n("I18nTip"),o=n("ExternalLinkIcon");return d(),c("div",null,[s(a),p,e("blockquote",null,[e("p",null,[t("“响应认证”被替换为“协议版本”并移至最前,使 VLESS 可以升级换代,同时消除了生成伪随机数的开销。混淆相关结构被替换为附加信息(ProtoBuf)并前移,赋予协议本身可扩展性,相关开销也极小("),e("a",i,[t("gogo/protobuf"),s(o)]),t("),若无附加信息则无相关开销。")])]),u,S,_,f,V,e("p",null,[t("总体上,ALPHA 2 到 BETA 主要是:结构进化、清理整合、性能提升、更加完善。这些都是一点一滴的,详见 "),e("a",b,[t("VLESS Changes"),s(o)]),t("。")]),L,e("p",null,[t('对比 VMess,VLESS 相当于把 security 换成 encryption,把 disableInsecureEncryption 换成 decryption,就解决了所有问题。目前 encryption 和 decryption 只接受 "none" 且不能留空(即使以后有连接安全性检查),详见 '),e("a",E,[t("VLESS 配置文档"),s(o)]),t("。encryption 并不需要往外移一级,一是因为无法复用很多代码,二是因为会影响控制粒度,看未来的应用就明白了。")]),g,y,m,T,e("p",null,[e("a",x,[t("XUDP:VLESS & VMess & Mux UDP FullCone NAT"),s(o)])]),A,e("p",null,[t("感谢 "),M,t(),e("a",U,[t("@DuckSoft"),s(o)]),t(" 的提案!")]),e("p",null,[t("详情请见 "),e("a",P,[t("VMessAEAD / VLESS 分享链接标准提案"),s(o)])])])}const D=h(l,[["render",v],["__file","vless.html.vue"]]);export{D as default}; diff --git a/assets/vless.html-DH2x8Lsm.js b/assets/vless.html-BnbvG0no.js similarity index 99% rename from assets/vless.html-DH2x8Lsm.js rename to assets/vless.html-BnbvG0no.js index 413e3d1ef9..f4a9f32e88 100644 --- a/assets/vless.html-DH2x8Lsm.js +++ b/assets/vless.html-BnbvG0no.js @@ -1,4 +1,4 @@ -import{_ as p,r as a,o as r,c as u,a as s,b as n,d as e,w as t,e as l}from"./app-DBM4OJyw.js";const d={},h=n("h1",{id:"vless",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#vless"},[n("span",null,"VLESS")])],-1),b=n("div",{class:"custom-container danger"},[n("p",{class:"custom-container-title"},"Danger"),n("p",null,"Currently, VLESS does not provide built-in encryption. Please use it with a reliable channel, such as TLS.")],-1),v=n("p",null,"VLESS is a stateless lightweight transport protocol that consists of inbound and outbound parts. It can serve as a bridge between Xray clients and servers.",-1),m=l(`

                                      InboundConfigurationObject

                                      {
                                      +import{_ as p,r as a,o as r,c as u,a as s,b as n,d as e,w as t,e as l}from"./app-D7uBbsY3.js";const d={},h=n("h1",{id:"vless",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#vless"},[n("span",null,"VLESS")])],-1),b=n("div",{class:"custom-container danger"},[n("p",{class:"custom-container-title"},"Danger"),n("p",null,"Currently, VLESS does not provide built-in encryption. Please use it with a reliable channel, such as TLS.")],-1),v=n("p",null,"VLESS is a stateless lightweight transport protocol that consists of inbound and outbound parts. It can serve as a bridge between Xray clients and servers.",-1),m=l(`

                                      InboundConfigurationObject

                                      {
                                         "clients": [
                                           {
                                             "id": "5783a3e7-e373-51cd-8642-c83782b807c5",
                                      diff --git a/assets/vless.html-BlWWjzcK.js b/assets/vless.html-CeF81Ekr.js
                                      similarity index 99%
                                      rename from assets/vless.html-BlWWjzcK.js
                                      rename to assets/vless.html-CeF81Ekr.js
                                      index f039ad06e8..8f0f11b7bb 100644
                                      --- a/assets/vless.html-BlWWjzcK.js
                                      +++ b/assets/vless.html-CeF81Ekr.js
                                      @@ -1 +1 @@
                                      -import{_ as r,r as i,o as d,c as h,a as o,b as e,d as t,e as a}from"./app-DBM4OJyw.js";const l={},c=a('

                                      VLESS Protocol

                                      VLESS is a stateless lightweight transmission protocol that can be used as a bridge between Xray clients and servers.

                                      Request & Response

                                      1 byte16 bytes1 byteM bytes1 byte2 bytes1 byteS bytesX bytes
                                      Protocol VersionEquivalent UUIDAdditional Information Length MAdditional Information ProtoBufInstructionPortAddress TypeAddressRequest Data
                                      1 Byte1 ByteN BytesY Bytes
                                      Protocol Version, consistent with the requestLength of additional information NAdditional information in ProtoBufResponse data

                                      VLESS had the aforementioned structure as early as the second alpha test version (ALPHA 2), with BETA being the fifth test version.

                                      ',6),p=e("code",null,"Response authentication",-1),u=e("code",null,"Protocol version",-1),f=e("code",null,"Additional information",-1),m={href:"https://github.com/gogo/protobuf",target:"_blank",rel:"noopener noreferrer"},y=e("p",null,'I always thought that "response authentication" was not necessary, and ALPHA replaced crypto/rand with math/rand in order to improve the performance of random number generation, which is no longer needed.',-1),b=e("p",null,'The "Protocol Version" not only serves as "Response Authentication", but also gives VLESS the ability to upgrade the protocol structure seamlessly, bringing infinite possibilities. The "Protocol Version" is 0 in the test version and 1 in the official version. If there are any incompatible protocol structural changes in the future, the version should be upgraded.',-1),g=e("p",null,"The design of VLESS server is switch version, which supports all VLESS versions at the same time. If you need to upgrade the protocol version (which may not happen), it is recommended that the server support it one month in advance, and then change the client after one month. VMess requests also have protocol versions, but their authentication information is outside, and the instruction part is highly coupled and has fixed encryption, which makes the protocol version meaningless inside. The server does not judge it, and the response does not have a protocol version. Trojan's protocol structure does not have a protocol version.",-1),v=e("p",null,"The following is a UUID. I used to think that 16 bytes were a bit long and considered shortening it. However, I later saw that Trojan used 56 printable characters (56 bytes), which completely dispelled this idea. The server needs to verify the UUID every time, so performance is also very important: VLESS's Validator has undergone multiple refactoring/upgrades. Compared with VMess, it is very concise and consumes very few resources. It can support a large number of users at the same time, and its performance is also very strong. The verification speed is extremely fast (sync.Map). API dynamically adds and deletes users, making it more efficient and smooth. https://github.com/XTLS/Xray-core/issues/158",-1),w=e("p",null,'Introducing ProtoBuf is an innovation, which will be explained in detail later. The structure from "instruction" to "address" is currently identical to VMess and also supports Mux.',-1),S={href:"https://github.com/rprx/v2ray-vless/releases",target:"_blank",rel:"noopener noreferrer"},_=a('

                                      ProtoBuf

                                      It seems that only VLESS supports embedding ProtoBuf, which is a data exchange format that encodes information tightly into binary TLV (Tag Length Value) structures.

                                      The reason is that I saw an article that said that SS has some drawbacks, such as the lack of a design error reporting mechanism, and the client cannot take further action based on different errors. (But I don't agree that all errors should be reported, otherwise it can't prevent active probing. In the next beta version, the server can return a custom string of information.) So I think a scalable structure is important, and in the future, it can also carry dynamic port instructions. Not only the response, but the request also needs a similar structure. I originally planned to design TLV by myself, but then I found that ProtoBuf is the structure, ready-made, and it is completely suitable for this purpose, and the support for various languages is also good.

                                      Currently, "Additional Information" only has Scheduler and SchedulerV, which are substitutes for MessName and MessSeed. When you don't need them, the "Additional Information Length" is 0, so there is no ProtoBuf serialization/deserialization overhead. Actually, I prefer to call this process "concatenation" because that's all pb does in principle, and the related overhead is minimal. The concatenated bytes are very compact, similar to ALPHA's solution, and those who are interested can output and compare them separately.

                                      To indicate different levels of support for additional information (Addons, which can be understood as plugins and can have many plugins in the future), the next beta version will add "Addon Version" before "Addon Length". 256-1 = 255 bytes is enough and reasonable (65535 is too much and there may be malicious padding), and only one-tenth of the existing space is used. In the future, there will not be so many addons at the same time, and most of the time there will be no addons at all. If it is not enough, you can upgrade to a newer version of VLESS.

                                      To reduce logical judgment and other expenses, it is temporarily decided that Addons will not use a multi-level structure. A month ago, there was an idea of "variable protocol format". PB can shuffle the order, but it is not necessary because the design of modern encryption will not allow bystanders to see that the headers of the two transmissions are the same.

                                      Below is an introduction to the concepts of Schedulers and Encryption, both of which are optional. One is designed to address issues related to traffic timing, while the other is designed to address cryptographic issues.

                                      Flow

                                      Flow Control (Formerly Traffic Scheduler)

                                      The Flow Control command is carried by ProtoBuf and manages the data section.

                                      I previously discovered that VMess's original "metadata obfuscation" feature didn't provide any meaningful changes in TLS but only decreased performance. Consequently, VLESS has abandoned this feature. Moreover, the term "obfuscation" is often misinterpreted as camouflage, so it has been discarded.

                                      As for camouflage, if it can't be an exact match, wouldn't it be a noticeable characteristic? If it could be an exact match, why not use the intended target for camouflage directly? Initially, I used SSR but found it only provided superficial disguises, fooling operators. Thus, I stopped using it.

                                      Purpose of Flow Control

                                      Flow Control influences macro traffic temporal characteristics rather than micro characteristics addressed by encryption. Traffic temporal characteristics can be:

                                      1. Protocol-based, e.g., Socks5 handshake when using Socks5 over TLS. Different traits on TLS are considered different protocols for monitors. Infinite schedulers equate to infinite protocols (reallocating data sent each time).
                                      2. Behavior-based, e.g., loading files, their order, and size when accessing Google's homepage. Adding another encryption layer cannot effectively conceal this information.

                                      Schedulers don't require wrapping like encryption since the header data's tiny amount is negligible compared to the remaining data.

                                      BETA 2 is anticipated to introduce two basic schedulers: Zstd compression and dynamic data expansion. Advanced operations will control and distribute at a macro level, but for now, these remain under development.

                                      Encryption

                                      Unlike VMess, which is highly coupled, VLESS allows the server and client to pre-agree on an encryption method, which is only encrypted with an outer layer. This is somewhat similar to using TLS, which does not affect any of the data carried, and can be understood as replacing TLS with pre-agreed encryption at the bottom. Compared with high coupling, this approach is more reasonable and flexible: if there is a security issue with one encryption method, it can be discarded and another one can be used directly, which is very convenient. The VLESS server also allows for different encryption methods to coexist.

                                      Compared with VMess, VLESS replaces security with encryption and disableInsecureEncryption with decryption, which solves all the problems. Currently, encryption and decryption only accept "none" and cannot be left blank (even if there are connection security checks in the future), as detailed in the VLESS configuration document. Encryption does not need to be moved out one level, firstly because it cannot reuse a lot of code, and secondly because it will affect the control granularity, which will be understood by looking at future applications.

                                      Encryption supports two types of forms. One type is completely independent and requires an additional password, suitable for private use. The other type combines with the existing UUID for encryption, which is suitable for public use.

                                      (If the first type of encryption is used and the password is publicly available in some form, such as multiple people sharing it, then a man-in-the-middle attack is not far away.)

                                      A redesigned dynamic port may be released simultaneously with encryption, and the command is carried by ProtoBuf. The specific implementation and the dynamic port of VMess will also have many differences.

                                      It is very easy to cash out encrypted currency, which adds an extra layer of writer & reader. BETA 3 is expected to support SS's aes-128-gcm and chacha20-ietf-poly1305:

                                      The encryption on the client-side can be filled with "auto: ss_aes-128-gcm_0_123456, ss_chacha20-ietf-poly1305_0_987654". Auto will choose the most suitable one for the current machine, 0 represents the beta version, and the last one is the password. The decryption on the server-side is also filled in a similar way, and each decryption attempt will be made when the request is received.

                                      Not all combinations need to be tried one by one: VMess encryption is divided into three parts. The first part is the authentication information, which combines UUID, alterId, and time factors. The second part is the instruction part, which is encrypted using a fixed algorithm. The instruction contains the encryption algorithm used in the data part. The third part is the important data part. It can be seen that the VMess encryption and decryption method is actually many-to-one (adapted by the server), not just combining UUID. However, it is also a relatively difficult thing to encrypt only by combining UUID. It will not be available in a short time. Considering that we now have VMessAEAD available, there is no need to rush. If VLESS introduces an encryption method that combines UUID, it is equivalent to reconstructing the entire VMess.

                                      UDP issues

                                      ',27),T={href:"https://github.com/XTLS/Xray-core/discussions/252",target:"_blank",rel:"noopener noreferrer"},V=a('

                                      Client Development Guide

                                      1. The VLESS protocol itself may have incompatible upgrades, but the parameters in the client configuration file are basically only increased and not decreased. The protocol implementation of the iOS client needs to keep up with the upgrade.
                                      2. Visual standard: Please use VLESS as the UI identifier uniformly, instead of VLess / Vless / vless. The configuration file is not affected, and the code should follow naturally.
                                      3. Encryption should be made into an input box instead of a selection box. The default value of the new configuration should be none, and if the user leaves it blank, it should be filled in with none.
                                      ',3),I={href:"https://github.com/DuckSoft",target:"_blank",rel:"noopener noreferrer"},L={href:"https://github.com/XTLS/Xray-core/issues/91",target:"_blank",rel:"noopener noreferrer"};function A(x,E){const s=i("I18nTip"),n=i("ExternalLinkIcon");return d(),h("div",null,[o(s),c,e("p",null,[t('"'),p,t('" has been replaced with "'),u,t('" and moved to the front, allowing VLESS to upgrade and eliminate the overhead of generating pseudo-random numbers. The obfuscation-related structure has been replaced with "'),f,t('" (ProtoBuf) and moved forward, giving the protocol itself scalability, with minimal overhead ('),e("a",m,[t("gogo/protobuf"),o(n)]),t("). If there is no additional information, there is no relevant overhead.")]),y,b,g,v,w,e("p",null,[t("Overall, ALPHA 2 to BETA mainly includes: structural evolution, cleaning and integration, performance improvement, and more completeness. All of these are incremental improvements, please refer to "),e("a",S,[t("VLESS Changes"),o(n)]),t(" for details.")]),_,e("p",null,[e("a",T,[t("XUDP: VLESS & VMess & Mux UDP FullCone NAT"),o(n)])]),V,e("p",null,[t("Thank you to "),e("a",I,[t("@DuckSoft"),o(n)]),t(" for the proposal!")]),e("p",null,[t("Please see "),e("a",L,[t("VMessAEAD/VLESS Sharing Link Standard Proposal"),o(n)]),t(" for more details.")])])}const q=r(l,[["render",A],["__file","vless.html.vue"]]);export{q as default}; +import{_ as r,r as i,o as d,c as h,a as o,b as e,d as t,e as a}from"./app-D7uBbsY3.js";const l={},c=a('

                                      VLESS Protocol

                                      VLESS is a stateless lightweight transmission protocol that can be used as a bridge between Xray clients and servers.

                                      Request & Response

                                      1 byte16 bytes1 byteM bytes1 byte2 bytes1 byteS bytesX bytes
                                      Protocol VersionEquivalent UUIDAdditional Information Length MAdditional Information ProtoBufInstructionPortAddress TypeAddressRequest Data
                                      1 Byte1 ByteN BytesY Bytes
                                      Protocol Version, consistent with the requestLength of additional information NAdditional information in ProtoBufResponse data

                                      VLESS had the aforementioned structure as early as the second alpha test version (ALPHA 2), with BETA being the fifth test version.

                                      ',6),p=e("code",null,"Response authentication",-1),u=e("code",null,"Protocol version",-1),f=e("code",null,"Additional information",-1),m={href:"https://github.com/gogo/protobuf",target:"_blank",rel:"noopener noreferrer"},y=e("p",null,'I always thought that "response authentication" was not necessary, and ALPHA replaced crypto/rand with math/rand in order to improve the performance of random number generation, which is no longer needed.',-1),b=e("p",null,'The "Protocol Version" not only serves as "Response Authentication", but also gives VLESS the ability to upgrade the protocol structure seamlessly, bringing infinite possibilities. The "Protocol Version" is 0 in the test version and 1 in the official version. If there are any incompatible protocol structural changes in the future, the version should be upgraded.',-1),g=e("p",null,"The design of VLESS server is switch version, which supports all VLESS versions at the same time. If you need to upgrade the protocol version (which may not happen), it is recommended that the server support it one month in advance, and then change the client after one month. VMess requests also have protocol versions, but their authentication information is outside, and the instruction part is highly coupled and has fixed encryption, which makes the protocol version meaningless inside. The server does not judge it, and the response does not have a protocol version. Trojan's protocol structure does not have a protocol version.",-1),v=e("p",null,"The following is a UUID. I used to think that 16 bytes were a bit long and considered shortening it. However, I later saw that Trojan used 56 printable characters (56 bytes), which completely dispelled this idea. The server needs to verify the UUID every time, so performance is also very important: VLESS's Validator has undergone multiple refactoring/upgrades. Compared with VMess, it is very concise and consumes very few resources. It can support a large number of users at the same time, and its performance is also very strong. The verification speed is extremely fast (sync.Map). API dynamically adds and deletes users, making it more efficient and smooth. https://github.com/XTLS/Xray-core/issues/158",-1),w=e("p",null,'Introducing ProtoBuf is an innovation, which will be explained in detail later. The structure from "instruction" to "address" is currently identical to VMess and also supports Mux.',-1),S={href:"https://github.com/rprx/v2ray-vless/releases",target:"_blank",rel:"noopener noreferrer"},_=a('

                                      ProtoBuf

                                      It seems that only VLESS supports embedding ProtoBuf, which is a data exchange format that encodes information tightly into binary TLV (Tag Length Value) structures.

                                      The reason is that I saw an article that said that SS has some drawbacks, such as the lack of a design error reporting mechanism, and the client cannot take further action based on different errors. (But I don't agree that all errors should be reported, otherwise it can't prevent active probing. In the next beta version, the server can return a custom string of information.) So I think a scalable structure is important, and in the future, it can also carry dynamic port instructions. Not only the response, but the request also needs a similar structure. I originally planned to design TLV by myself, but then I found that ProtoBuf is the structure, ready-made, and it is completely suitable for this purpose, and the support for various languages is also good.

                                      Currently, "Additional Information" only has Scheduler and SchedulerV, which are substitutes for MessName and MessSeed. When you don't need them, the "Additional Information Length" is 0, so there is no ProtoBuf serialization/deserialization overhead. Actually, I prefer to call this process "concatenation" because that's all pb does in principle, and the related overhead is minimal. The concatenated bytes are very compact, similar to ALPHA's solution, and those who are interested can output and compare them separately.

                                      To indicate different levels of support for additional information (Addons, which can be understood as plugins and can have many plugins in the future), the next beta version will add "Addon Version" before "Addon Length". 256-1 = 255 bytes is enough and reasonable (65535 is too much and there may be malicious padding), and only one-tenth of the existing space is used. In the future, there will not be so many addons at the same time, and most of the time there will be no addons at all. If it is not enough, you can upgrade to a newer version of VLESS.

                                      To reduce logical judgment and other expenses, it is temporarily decided that Addons will not use a multi-level structure. A month ago, there was an idea of "variable protocol format". PB can shuffle the order, but it is not necessary because the design of modern encryption will not allow bystanders to see that the headers of the two transmissions are the same.

                                      Below is an introduction to the concepts of Schedulers and Encryption, both of which are optional. One is designed to address issues related to traffic timing, while the other is designed to address cryptographic issues.

                                      Flow

                                      Flow Control (Formerly Traffic Scheduler)

                                      The Flow Control command is carried by ProtoBuf and manages the data section.

                                      I previously discovered that VMess's original "metadata obfuscation" feature didn't provide any meaningful changes in TLS but only decreased performance. Consequently, VLESS has abandoned this feature. Moreover, the term "obfuscation" is often misinterpreted as camouflage, so it has been discarded.

                                      As for camouflage, if it can't be an exact match, wouldn't it be a noticeable characteristic? If it could be an exact match, why not use the intended target for camouflage directly? Initially, I used SSR but found it only provided superficial disguises, fooling operators. Thus, I stopped using it.

                                      Purpose of Flow Control

                                      Flow Control influences macro traffic temporal characteristics rather than micro characteristics addressed by encryption. Traffic temporal characteristics can be:

                                      1. Protocol-based, e.g., Socks5 handshake when using Socks5 over TLS. Different traits on TLS are considered different protocols for monitors. Infinite schedulers equate to infinite protocols (reallocating data sent each time).
                                      2. Behavior-based, e.g., loading files, their order, and size when accessing Google's homepage. Adding another encryption layer cannot effectively conceal this information.

                                      Schedulers don't require wrapping like encryption since the header data's tiny amount is negligible compared to the remaining data.

                                      BETA 2 is anticipated to introduce two basic schedulers: Zstd compression and dynamic data expansion. Advanced operations will control and distribute at a macro level, but for now, these remain under development.

                                      Encryption

                                      Unlike VMess, which is highly coupled, VLESS allows the server and client to pre-agree on an encryption method, which is only encrypted with an outer layer. This is somewhat similar to using TLS, which does not affect any of the data carried, and can be understood as replacing TLS with pre-agreed encryption at the bottom. Compared with high coupling, this approach is more reasonable and flexible: if there is a security issue with one encryption method, it can be discarded and another one can be used directly, which is very convenient. The VLESS server also allows for different encryption methods to coexist.

                                      Compared with VMess, VLESS replaces security with encryption and disableInsecureEncryption with decryption, which solves all the problems. Currently, encryption and decryption only accept "none" and cannot be left blank (even if there are connection security checks in the future), as detailed in the VLESS configuration document. Encryption does not need to be moved out one level, firstly because it cannot reuse a lot of code, and secondly because it will affect the control granularity, which will be understood by looking at future applications.

                                      Encryption supports two types of forms. One type is completely independent and requires an additional password, suitable for private use. The other type combines with the existing UUID for encryption, which is suitable for public use.

                                      (If the first type of encryption is used and the password is publicly available in some form, such as multiple people sharing it, then a man-in-the-middle attack is not far away.)

                                      A redesigned dynamic port may be released simultaneously with encryption, and the command is carried by ProtoBuf. The specific implementation and the dynamic port of VMess will also have many differences.

                                      It is very easy to cash out encrypted currency, which adds an extra layer of writer & reader. BETA 3 is expected to support SS's aes-128-gcm and chacha20-ietf-poly1305:

                                      The encryption on the client-side can be filled with "auto: ss_aes-128-gcm_0_123456, ss_chacha20-ietf-poly1305_0_987654". Auto will choose the most suitable one for the current machine, 0 represents the beta version, and the last one is the password. The decryption on the server-side is also filled in a similar way, and each decryption attempt will be made when the request is received.

                                      Not all combinations need to be tried one by one: VMess encryption is divided into three parts. The first part is the authentication information, which combines UUID, alterId, and time factors. The second part is the instruction part, which is encrypted using a fixed algorithm. The instruction contains the encryption algorithm used in the data part. The third part is the important data part. It can be seen that the VMess encryption and decryption method is actually many-to-one (adapted by the server), not just combining UUID. However, it is also a relatively difficult thing to encrypt only by combining UUID. It will not be available in a short time. Considering that we now have VMessAEAD available, there is no need to rush. If VLESS introduces an encryption method that combines UUID, it is equivalent to reconstructing the entire VMess.

                                      UDP issues

                                      ',27),T={href:"https://github.com/XTLS/Xray-core/discussions/252",target:"_blank",rel:"noopener noreferrer"},V=a('

                                      Client Development Guide

                                      1. The VLESS protocol itself may have incompatible upgrades, but the parameters in the client configuration file are basically only increased and not decreased. The protocol implementation of the iOS client needs to keep up with the upgrade.
                                      2. Visual standard: Please use VLESS as the UI identifier uniformly, instead of VLess / Vless / vless. The configuration file is not affected, and the code should follow naturally.
                                      3. Encryption should be made into an input box instead of a selection box. The default value of the new configuration should be none, and if the user leaves it blank, it should be filled in with none.
                                      ',3),I={href:"https://github.com/DuckSoft",target:"_blank",rel:"noopener noreferrer"},L={href:"https://github.com/XTLS/Xray-core/issues/91",target:"_blank",rel:"noopener noreferrer"};function A(x,E){const s=i("I18nTip"),n=i("ExternalLinkIcon");return d(),h("div",null,[o(s),c,e("p",null,[t('"'),p,t('" has been replaced with "'),u,t('" and moved to the front, allowing VLESS to upgrade and eliminate the overhead of generating pseudo-random numbers. The obfuscation-related structure has been replaced with "'),f,t('" (ProtoBuf) and moved forward, giving the protocol itself scalability, with minimal overhead ('),e("a",m,[t("gogo/protobuf"),o(n)]),t("). If there is no additional information, there is no relevant overhead.")]),y,b,g,v,w,e("p",null,[t("Overall, ALPHA 2 to BETA mainly includes: structural evolution, cleaning and integration, performance improvement, and more completeness. All of these are incremental improvements, please refer to "),e("a",S,[t("VLESS Changes"),o(n)]),t(" for details.")]),_,e("p",null,[e("a",T,[t("XUDP: VLESS & VMess & Mux UDP FullCone NAT"),o(n)])]),V,e("p",null,[t("Thank you to "),e("a",I,[t("@DuckSoft"),o(n)]),t(" for the proposal!")]),e("p",null,[t("Please see "),e("a",L,[t("VMessAEAD/VLESS Sharing Link Standard Proposal"),o(n)]),t(" for more details.")])])}const q=r(l,[["render",A],["__file","vless.html.vue"]]);export{q as default}; diff --git a/assets/vless.html-D5OyDM4i.js b/assets/vless.html-kZ8IonU8.js similarity index 99% rename from assets/vless.html-D5OyDM4i.js rename to assets/vless.html-kZ8IonU8.js index 0c3b8c7faf..cf8d272df3 100644 --- a/assets/vless.html-D5OyDM4i.js +++ b/assets/vless.html-kZ8IonU8.js @@ -1,4 +1,4 @@ -import{_ as i,r as t,o as u,c as r,a as e,b as n,d as s,w as a,e as l}from"./app-DBM4OJyw.js";const d={},k=n("h1",{id:"vless-xtls-vision-seed",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#vless-xtls-vision-seed"},[n("span",null,"VLESS(XTLS Vision Seed)")])],-1),b=n("div",{class:"custom-container danger"},[n("p",{class:"custom-container-title"},"警告"),n("p",null,"目前 VLESS 没有自带加密,请用于可靠信道,如 TLS。")],-1),v=n("p",null,"VLESS 是一个无状态的轻量传输协议,它分为入站和出站两部分,可以作为 Xray 客户端和服务器之间的桥梁。",-1),q=l(`

                                      InboundConfigurationObject

                                      {
                                      +import{_ as i,r as t,o as u,c as r,a as e,b as n,d as s,w as a,e as l}from"./app-D7uBbsY3.js";const d={},k=n("h1",{id:"vless-xtls-vision-seed",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#vless-xtls-vision-seed"},[n("span",null,"VLESS(XTLS Vision Seed)")])],-1),b=n("div",{class:"custom-container danger"},[n("p",{class:"custom-container-title"},"警告"),n("p",null,"目前 VLESS 没有自带加密,请用于可靠信道,如 TLS。")],-1),v=n("p",null,"VLESS 是一个无状态的轻量传输协议,它分为入站和出站两部分,可以作为 Xray 客户端和服务器之间的桥梁。",-1),q=l(`

                                      InboundConfigurationObject

                                      {
                                         "clients": [
                                           {
                                             "id": "5783a3e7-e373-51cd-8642-c83782b807c5",
                                      diff --git a/assets/vless.html-jHwTWi4h.js b/assets/vless.html-oiH3sQfV.js
                                      similarity index 99%
                                      rename from assets/vless.html-jHwTWi4h.js
                                      rename to assets/vless.html-oiH3sQfV.js
                                      index f373639ca6..17393f803c 100644
                                      --- a/assets/vless.html-jHwTWi4h.js
                                      +++ b/assets/vless.html-oiH3sQfV.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as i,r as a,o as u,c as r,a as e,b as s,d as n,w as t,e as p}from"./app-DBM4OJyw.js";const d={},v=s("h1",{id:"vless",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#vless"},[s("span",null,"VLESS")])],-1),k=s("div",{class:"custom-container danger"},[s("p",{class:"custom-container-title"},"Предупреждение"),s("p",null,"VLESS не предусматривает встроенного шифрования, поэтому обязательным условием для его использования является наличие надежного канала, такого как TLS или REALITY.")],-1),b=s("p",null,"VLESS - это легкий транспортный протокол без сохранения состояния, который разделен на входящую и исходящую части и может служить мостом между клиентом и сервером Xray.",-1),q=p(`

                                      OutboundConfigurationObject

                                      {
                                      +import{_ as i,r as a,o as u,c as r,a as e,b as s,d as n,w as t,e as p}from"./app-D7uBbsY3.js";const d={},v=s("h1",{id:"vless",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#vless"},[s("span",null,"VLESS")])],-1),k=s("div",{class:"custom-container danger"},[s("p",{class:"custom-container-title"},"Предупреждение"),s("p",null,"VLESS не предусматривает встроенного шифрования, поэтому обязательным условием для его использования является наличие надежного канала, такого как TLS или REALITY.")],-1),b=s("p",null,"VLESS - это легкий транспортный протокол без сохранения состояния, который разделен на входящую и исходящую части и может служить мостом между клиентом и сервером Xray.",-1),q=p(`

                                      OutboundConfigurationObject

                                      {
                                         "vnext": [
                                           {
                                             "address": "example.com",
                                      diff --git a/assets/vless.html-Bfk9b9AR.js b/assets/vless.html-syxK1TrS.js
                                      similarity index 99%
                                      rename from assets/vless.html-Bfk9b9AR.js
                                      rename to assets/vless.html-syxK1TrS.js
                                      index 42dc433140..9fc3835f3a 100644
                                      --- a/assets/vless.html-Bfk9b9AR.js
                                      +++ b/assets/vless.html-syxK1TrS.js
                                      @@ -1 +1 @@
                                      -import{_ as h,r as n,o as d,c,a as s,b as e,d as t,e as r}from"./app-DBM4OJyw.js";const l={},p=r('

                                      VLESS 协议

                                      VLESS 是一个无状态的轻量传输协议,可以作为 Xray 客户端和服务器之间的桥梁。

                                      Request & Response

                                      1 字节16 字节1 字节M 字节1 字节2 字节1 字节S 字节X 字节
                                      协议版本等价 UUID附加信息长度 M附加信息 ProtoBuf指令端口地址类型地址请求数据
                                      1 字节1 字节N 字节Y 字节
                                      协议版本,与请求的一致附加信息长度 N附加信息 ProtoBuf响应数据

                                      VLESS 早在第二个测试版 ALPHA 2 时就已经是上述结构了(BETA 是第五个测试版):

                                      ',6),i={href:"https://github.com/gogo/protobuf",target:"_blank",rel:"noopener noreferrer"},u=e("p",null,"我一直觉得“响应认证”不是必要的,ALPHA 时为了提升生成随机数的性能,还用 math/rand 替换 crypto/rand,而现在都不需要了。",-1),S=e("p",null,"“协议版本”不仅能起到“响应认证”的作用,还赋予了 VLESS 无痛升级协议结构的能力,带来无限的可能性。 “协议版本”在测试版本中均为 0,正式版本中为 1,以后若有不兼容的协议结构变更则应升级版本。",-1),_=e("p",null,"VLESS 服务端的设计是 switch version,即同时支持所有 VLESS 版本。若需要升级协议版本(可能到不了这一步),推荐的做法是服务端提前一个月支持,一个月后再改客户端。VMess 请求也有协议版本,但它的认证信息在外面,指令部分则高度耦合且有固定加密,导致里面的协议版本毫无意义,服务端也没有进行判断,响应则没有协议版本。Trojan 的协议结构中没有协议版本。",-1),f=e("p",null,"接下来是 UUID,我本来觉得 16 字节有点长,曾经考虑过缩短它,但后来看到 Trojan 用了 56 个可打印字符(56 字节),就彻底打消了这个念头。服务端每次都要验证 UUID,所以性能也很重要:VLESS 的 Validator 经历了多次重构/升级,相较于 VMess,它十分简洁且耗资源很少,可以同时支持非常多的用户,性能也十分强悍,验证速度极快(sync.Map)。API 动态增删用户则更高效顺滑。 https://github.com/XTLS/Xray-core/issues/158",-1),V=e("p",null,"引入 ProtoBuf 是一个创举,等下会详细讲解。“指令”到“地址”的结构目前与 VMess 完全相同,同样支持 Mux。",-1),b={href:"https://github.com/rprx/v2ray-vless/releases",target:"_blank",rel:"noopener noreferrer"},L=r('

                                      ProtoBuf

                                      似乎只有 VLESS 可选内嵌 ProtoBuf,它是一种数据交换格式,信息被紧密编码成二进制,TLV 结构(Tag Length Value)。

                                      起因是我看到一篇文章称 SS 有一些缺点,如没有设计错误回报机制,客户端没办法根据不同的错误采取进一步的动作。 (但我并不认同所有错误都要回报,不然防不了主动探测。下一个测试版中,服务器可以返回一串自定义信息。) 于是想到一个可扩展的结构是很重要的,未来它也可以承载如动态端口指令。不止响应,请求也需要类似的结构。 本来打算自己设计 TLV,接着发觉 ProtoBuf 就是此结构、现成的轮子,完全适合用来做这件事,各语言支持等也不错。

                                      目前“附加信息”只有 Scheduler 和 SchedulerV,它们是 MessName 和 MessSeed 的替代者,当你不需要它们时,“附加信息长度”为 0,也就不会有 ProtoBuf 序列化/反序列化的开销。其实我更愿意称这个过程为“拼接”,因为 pb 实际原理上也只是这么做而已,相关开销极小。拼接后的 bytes 十分紧凑,和 ALPHA 的方案相差无几,有兴趣的可以分别输出并对比。

                                      为了指示对附加信息(Addons,也可以理解成插件,以后可以有很多个插件)的不同支持程度,下个测试版会在“附加信息长度”前新增“附加信息版本”。256 - 1 = 255 字节是够用且合理的(65535 就太多了,还可能有人恶意填充),现有的只用了十分之一,以后也不会同时有那么多附加信息,且大多数情况下是完全没有附加信息的。真不够用的话,可以升级 VLESS 版本。

                                      为了减少逻辑判断等开销,暂定 Addons 不使用多级结构。一个月前出现过“可变协议格式”的想法,pb 是可以做到打乱顺序,但没必要,因为现代加密的设计不会让旁观者看出两次传输的头部相同。

                                      下面介绍 Schedulers 和 Encryption 的构想,它们都是可选的,一个应对流量时序特征问题,一个应对密码学上的问题。

                                      Schedulers Flow

                                      中文名暂称:流量调度器(2020-09-03 更新:中文名确定为“流控”),指令由 ProtoBuf 承载,控制的是数据部分。

                                      我之前发现,VMess 原有的 shake “元数据混淆”在 TLS 上完全不会带来有意义的改变,只会降低性能,所以 VLESS 弃用了它。并且,“混淆”这个表述容易被误解成伪装,也弃用了。顺便一提,我一直是不看好伪装的:做不到完全一样,那不就是强特征吗?做得到完全一样,那为什么不直接用伪装目标?我一开始用的是 SSR,后来发现它只是表面伪装骗运营商,就再也没用过了。

                                      那么,“流量调度器”要解决什么问题?它影响的是宏观流量时序特征,而不是微观特征,后者是加密要解决的事情。流量时序特征可以是协议带来的,比如 Socks5 over TLS 时的 Socks5 握手 ,TLS 上不同的这种特征对于监测者来说就是不同的协议,此时无限 Schedulers 就相当于无限协议(重新分配每次发送的数据量大小等)。流量时序特征也可以是行为带来的,比如访问 Google 首页时加载了多少文件、顺序、每个文件的大小,多套一层加密并不能有效掩盖这些信息。

                                      Schedulers 没必要像下面的 Encryption 一样整个套在外面,因为头部的一丁点数据相对于后面的数据量来说太微不足道了。

                                      BETA 2 预计推出两个初级的 Scheduler:Zstd 压缩、数据量动态扩充。进阶操作才是从宏观层面来控制、分配,暂时咕咕。

                                      Encryption

                                      与 VMess 的高度耦合不同,VLESS 的服务端、客户端不久后可以提前约定好加密方式,仅在外面套一层加密。这有点类似于使用 TLS,不影响承载的任何数据,也可以理解成底层就是从 TLS 换成预设约定加密。相对于高度耦合,这种方式更合理且灵活:一种加密方式出了安全性问题,直接扔掉并换用其它的就行了,十分方便。VLESS 服务端还会允许不同的加密方式共存。

                                      ',15),E={href:"https://github.com/rprx/v2fly-github-io/blob/master/docs/config/protocols/vless.md",target:"_blank",rel:"noopener noreferrer"},g=e("p",null,"加密支持两类形式,一类是加密完全独立,需要额外密码,适合私用,另一类是结合已有的 UUID 来加密,适合公用。 (若用第一类加密形式,且密码是以某种形式公开的,比如多人共用,那么中间人攻击就不远了) 重新设计的动态端口可能会随加密同时推出,指令由 ProtoBuf 承载,具体实现和 VMess 的动态端口也会有很多不同。",-1),y=e("p",null,"套现成加密是件很简单的事情,也就多一层 writer & reader。BETA 3 预计支持 SS 的 aes-128-gcm 和 chacha20-ietf-poly1305: 客户端的 encryption 可以填 “auto: ss_aes-128-gcm_0_123456, ss_chacha20-ietf-poly1305_0_987654”,auto 会选择最适合当前机器的,0 代表测试版,最后的是密码。服务端的 decryption 也是类似填法,收到请求时会逐一尝试解密。",-1),m=e("p",null,"并不是所有组合都需逐一尝试:VMess 的加密分为三段,第一段是认证信息,结合了 UUID、alterId、时间因素,第二段是指令部分,以固定算法加密,指令中含有数据部分使用的加密算法,第三段才是重要的数据部分。可以看出,VMess 的加解密方式实际上是多对一(服务端适配),而不仅是结合 UUID。但仅是结合 UUID 来加密也是件相对麻烦的事情,短时间内不会出,鉴于我们现在有 VMessAEAD 可用,也并不着急。若 VLESS 推出了结合 UUID 的加密方式,相当于重构了整个 VMess。",-1),T=e("h2",{id:"udp-issues",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#udp-issues"},[e("span",null,"UDP issues")])],-1),x={href:"https://github.com/XTLS/Xray-core/discussions/252",target:"_blank",rel:"noopener noreferrer"},A=r('

                                      客户端开发指引

                                      1. VLESS 协议本身还会有不兼容升级,但客户端配置文件参数基本上是只增不减的。iOS 客户端的协议实现则需紧跟升级。
                                      2. 视觉标准:UI 标识请统一用 VLESS,而不是 VLess / Vless / vless,配置文件不受影响,代码内则顺其自然。
                                      3. encryption 应做成输入框而不是选择框,新配置的默认值应为 none,若用户置空则应代填 none

                                      VLESS 分享链接标准

                                      ',3),M=e("img",{src:"https://avatars2.githubusercontent.com/u/7822648?s=32",width:"32px",height:"32px",alt:"a"},null,-1),U={href:"https://github.com/DuckSoft",target:"_blank",rel:"noopener noreferrer"},P={href:"https://github.com/XTLS/Xray-core/issues/91",target:"_blank",rel:"noopener noreferrer"};function v(B,k){const a=n("I18nTip"),o=n("ExternalLinkIcon");return d(),c("div",null,[s(a),p,e("blockquote",null,[e("p",null,[t("“响应认证”被替换为“协议版本”并移至最前,使 VLESS 可以升级换代,同时消除了生成伪随机数的开销。混淆相关结构被替换为附加信息(ProtoBuf)并前移,赋予协议本身可扩展性,相关开销也极小("),e("a",i,[t("gogo/protobuf"),s(o)]),t("),若无附加信息则无相关开销。")])]),u,S,_,f,V,e("p",null,[t("总体上,ALPHA 2 到 BETA 主要是:结构进化、清理整合、性能提升、更加完善。这些都是一点一滴的,详见 "),e("a",b,[t("VLESS Changes"),s(o)]),t("。")]),L,e("p",null,[t('对比 VMess,VLESS 相当于把 security 换成 encryption,把 disableInsecureEncryption 换成 decryption,就解决了所有问题。目前 encryption 和 decryption 只接受 "none" 且不能留空(即使以后有连接安全性检查),详见 '),e("a",E,[t("VLESS 配置文档"),s(o)]),t("。encryption 并不需要往外移一级,一是因为无法复用很多代码,二是因为会影响控制粒度,看未来的应用就明白了。")]),g,y,m,T,e("p",null,[e("a",x,[t("XUDP:VLESS & VMess & Mux UDP FullCone NAT"),s(o)])]),A,e("p",null,[t("感谢 "),M,t(),e("a",U,[t("@DuckSoft"),s(o)]),t(" 的提案!")]),e("p",null,[t("详情请见 "),e("a",P,[t("VMessAEAD / VLESS 分享链接标准提案"),s(o)])])])}const D=h(l,[["render",v],["__file","vless.html.vue"]]);export{D as default}; +import{_ as h,r as n,o as d,c,a as s,b as e,d as t,e as r}from"./app-D7uBbsY3.js";const l={},p=r('

                                      VLESS 协议

                                      VLESS 是一个无状态的轻量传输协议,可以作为 Xray 客户端和服务器之间的桥梁。

                                      Request & Response

                                      1 字节16 字节1 字节M 字节1 字节2 字节1 字节S 字节X 字节
                                      协议版本等价 UUID附加信息长度 M附加信息 ProtoBuf指令端口地址类型地址请求数据
                                      1 字节1 字节N 字节Y 字节
                                      协议版本,与请求的一致附加信息长度 N附加信息 ProtoBuf响应数据

                                      VLESS 早在第二个测试版 ALPHA 2 时就已经是上述结构了(BETA 是第五个测试版):

                                      ',6),i={href:"https://github.com/gogo/protobuf",target:"_blank",rel:"noopener noreferrer"},u=e("p",null,"我一直觉得“响应认证”不是必要的,ALPHA 时为了提升生成随机数的性能,还用 math/rand 替换 crypto/rand,而现在都不需要了。",-1),S=e("p",null,"“协议版本”不仅能起到“响应认证”的作用,还赋予了 VLESS 无痛升级协议结构的能力,带来无限的可能性。 “协议版本”在测试版本中均为 0,正式版本中为 1,以后若有不兼容的协议结构变更则应升级版本。",-1),_=e("p",null,"VLESS 服务端的设计是 switch version,即同时支持所有 VLESS 版本。若需要升级协议版本(可能到不了这一步),推荐的做法是服务端提前一个月支持,一个月后再改客户端。VMess 请求也有协议版本,但它的认证信息在外面,指令部分则高度耦合且有固定加密,导致里面的协议版本毫无意义,服务端也没有进行判断,响应则没有协议版本。Trojan 的协议结构中没有协议版本。",-1),f=e("p",null,"接下来是 UUID,我本来觉得 16 字节有点长,曾经考虑过缩短它,但后来看到 Trojan 用了 56 个可打印字符(56 字节),就彻底打消了这个念头。服务端每次都要验证 UUID,所以性能也很重要:VLESS 的 Validator 经历了多次重构/升级,相较于 VMess,它十分简洁且耗资源很少,可以同时支持非常多的用户,性能也十分强悍,验证速度极快(sync.Map)。API 动态增删用户则更高效顺滑。 https://github.com/XTLS/Xray-core/issues/158",-1),V=e("p",null,"引入 ProtoBuf 是一个创举,等下会详细讲解。“指令”到“地址”的结构目前与 VMess 完全相同,同样支持 Mux。",-1),b={href:"https://github.com/rprx/v2ray-vless/releases",target:"_blank",rel:"noopener noreferrer"},L=r('

                                      ProtoBuf

                                      似乎只有 VLESS 可选内嵌 ProtoBuf,它是一种数据交换格式,信息被紧密编码成二进制,TLV 结构(Tag Length Value)。

                                      起因是我看到一篇文章称 SS 有一些缺点,如没有设计错误回报机制,客户端没办法根据不同的错误采取进一步的动作。 (但我并不认同所有错误都要回报,不然防不了主动探测。下一个测试版中,服务器可以返回一串自定义信息。) 于是想到一个可扩展的结构是很重要的,未来它也可以承载如动态端口指令。不止响应,请求也需要类似的结构。 本来打算自己设计 TLV,接着发觉 ProtoBuf 就是此结构、现成的轮子,完全适合用来做这件事,各语言支持等也不错。

                                      目前“附加信息”只有 Scheduler 和 SchedulerV,它们是 MessName 和 MessSeed 的替代者,当你不需要它们时,“附加信息长度”为 0,也就不会有 ProtoBuf 序列化/反序列化的开销。其实我更愿意称这个过程为“拼接”,因为 pb 实际原理上也只是这么做而已,相关开销极小。拼接后的 bytes 十分紧凑,和 ALPHA 的方案相差无几,有兴趣的可以分别输出并对比。

                                      为了指示对附加信息(Addons,也可以理解成插件,以后可以有很多个插件)的不同支持程度,下个测试版会在“附加信息长度”前新增“附加信息版本”。256 - 1 = 255 字节是够用且合理的(65535 就太多了,还可能有人恶意填充),现有的只用了十分之一,以后也不会同时有那么多附加信息,且大多数情况下是完全没有附加信息的。真不够用的话,可以升级 VLESS 版本。

                                      为了减少逻辑判断等开销,暂定 Addons 不使用多级结构。一个月前出现过“可变协议格式”的想法,pb 是可以做到打乱顺序,但没必要,因为现代加密的设计不会让旁观者看出两次传输的头部相同。

                                      下面介绍 Schedulers 和 Encryption 的构想,它们都是可选的,一个应对流量时序特征问题,一个应对密码学上的问题。

                                      Schedulers Flow

                                      中文名暂称:流量调度器(2020-09-03 更新:中文名确定为“流控”),指令由 ProtoBuf 承载,控制的是数据部分。

                                      我之前发现,VMess 原有的 shake “元数据混淆”在 TLS 上完全不会带来有意义的改变,只会降低性能,所以 VLESS 弃用了它。并且,“混淆”这个表述容易被误解成伪装,也弃用了。顺便一提,我一直是不看好伪装的:做不到完全一样,那不就是强特征吗?做得到完全一样,那为什么不直接用伪装目标?我一开始用的是 SSR,后来发现它只是表面伪装骗运营商,就再也没用过了。

                                      那么,“流量调度器”要解决什么问题?它影响的是宏观流量时序特征,而不是微观特征,后者是加密要解决的事情。流量时序特征可以是协议带来的,比如 Socks5 over TLS 时的 Socks5 握手 ,TLS 上不同的这种特征对于监测者来说就是不同的协议,此时无限 Schedulers 就相当于无限协议(重新分配每次发送的数据量大小等)。流量时序特征也可以是行为带来的,比如访问 Google 首页时加载了多少文件、顺序、每个文件的大小,多套一层加密并不能有效掩盖这些信息。

                                      Schedulers 没必要像下面的 Encryption 一样整个套在外面,因为头部的一丁点数据相对于后面的数据量来说太微不足道了。

                                      BETA 2 预计推出两个初级的 Scheduler:Zstd 压缩、数据量动态扩充。进阶操作才是从宏观层面来控制、分配,暂时咕咕。

                                      Encryption

                                      与 VMess 的高度耦合不同,VLESS 的服务端、客户端不久后可以提前约定好加密方式,仅在外面套一层加密。这有点类似于使用 TLS,不影响承载的任何数据,也可以理解成底层就是从 TLS 换成预设约定加密。相对于高度耦合,这种方式更合理且灵活:一种加密方式出了安全性问题,直接扔掉并换用其它的就行了,十分方便。VLESS 服务端还会允许不同的加密方式共存。

                                      ',15),E={href:"https://github.com/rprx/v2fly-github-io/blob/master/docs/config/protocols/vless.md",target:"_blank",rel:"noopener noreferrer"},g=e("p",null,"加密支持两类形式,一类是加密完全独立,需要额外密码,适合私用,另一类是结合已有的 UUID 来加密,适合公用。 (若用第一类加密形式,且密码是以某种形式公开的,比如多人共用,那么中间人攻击就不远了) 重新设计的动态端口可能会随加密同时推出,指令由 ProtoBuf 承载,具体实现和 VMess 的动态端口也会有很多不同。",-1),y=e("p",null,"套现成加密是件很简单的事情,也就多一层 writer & reader。BETA 3 预计支持 SS 的 aes-128-gcm 和 chacha20-ietf-poly1305: 客户端的 encryption 可以填 “auto: ss_aes-128-gcm_0_123456, ss_chacha20-ietf-poly1305_0_987654”,auto 会选择最适合当前机器的,0 代表测试版,最后的是密码。服务端的 decryption 也是类似填法,收到请求时会逐一尝试解密。",-1),m=e("p",null,"并不是所有组合都需逐一尝试:VMess 的加密分为三段,第一段是认证信息,结合了 UUID、alterId、时间因素,第二段是指令部分,以固定算法加密,指令中含有数据部分使用的加密算法,第三段才是重要的数据部分。可以看出,VMess 的加解密方式实际上是多对一(服务端适配),而不仅是结合 UUID。但仅是结合 UUID 来加密也是件相对麻烦的事情,短时间内不会出,鉴于我们现在有 VMessAEAD 可用,也并不着急。若 VLESS 推出了结合 UUID 的加密方式,相当于重构了整个 VMess。",-1),T=e("h2",{id:"udp-issues",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#udp-issues"},[e("span",null,"UDP issues")])],-1),x={href:"https://github.com/XTLS/Xray-core/discussions/252",target:"_blank",rel:"noopener noreferrer"},A=r('

                                      客户端开发指引

                                      1. VLESS 协议本身还会有不兼容升级,但客户端配置文件参数基本上是只增不减的。iOS 客户端的协议实现则需紧跟升级。
                                      2. 视觉标准:UI 标识请统一用 VLESS,而不是 VLess / Vless / vless,配置文件不受影响,代码内则顺其自然。
                                      3. encryption 应做成输入框而不是选择框,新配置的默认值应为 none,若用户置空则应代填 none

                                      VLESS 分享链接标准

                                      ',3),M=e("img",{src:"https://avatars2.githubusercontent.com/u/7822648?s=32",width:"32px",height:"32px",alt:"a"},null,-1),U={href:"https://github.com/DuckSoft",target:"_blank",rel:"noopener noreferrer"},P={href:"https://github.com/XTLS/Xray-core/issues/91",target:"_blank",rel:"noopener noreferrer"};function v(B,k){const a=n("I18nTip"),o=n("ExternalLinkIcon");return d(),c("div",null,[s(a),p,e("blockquote",null,[e("p",null,[t("“响应认证”被替换为“协议版本”并移至最前,使 VLESS 可以升级换代,同时消除了生成伪随机数的开销。混淆相关结构被替换为附加信息(ProtoBuf)并前移,赋予协议本身可扩展性,相关开销也极小("),e("a",i,[t("gogo/protobuf"),s(o)]),t("),若无附加信息则无相关开销。")])]),u,S,_,f,V,e("p",null,[t("总体上,ALPHA 2 到 BETA 主要是:结构进化、清理整合、性能提升、更加完善。这些都是一点一滴的,详见 "),e("a",b,[t("VLESS Changes"),s(o)]),t("。")]),L,e("p",null,[t('对比 VMess,VLESS 相当于把 security 换成 encryption,把 disableInsecureEncryption 换成 decryption,就解决了所有问题。目前 encryption 和 decryption 只接受 "none" 且不能留空(即使以后有连接安全性检查),详见 '),e("a",E,[t("VLESS 配置文档"),s(o)]),t("。encryption 并不需要往外移一级,一是因为无法复用很多代码,二是因为会影响控制粒度,看未来的应用就明白了。")]),g,y,m,T,e("p",null,[e("a",x,[t("XUDP:VLESS & VMess & Mux UDP FullCone NAT"),s(o)])]),A,e("p",null,[t("感谢 "),M,t(),e("a",U,[t("@DuckSoft"),s(o)]),t(" 的提案!")]),e("p",null,[t("详情请见 "),e("a",P,[t("VMessAEAD / VLESS 分享链接标准提案"),s(o)])])])}const D=h(l,[["render",v],["__file","vless.html.vue"]]);export{D as default}; diff --git a/assets/vless.html-DAk5toqP.js b/assets/vless.html-zQehtVf0.js similarity index 99% rename from assets/vless.html-DAk5toqP.js rename to assets/vless.html-zQehtVf0.js index 42e75f3ace..158ec05995 100644 --- a/assets/vless.html-DAk5toqP.js +++ b/assets/vless.html-zQehtVf0.js @@ -1,4 +1,4 @@ -import{_ as i,r as t,o as u,c as r,a as e,b as n,d as s,w as a,e as l}from"./app-DBM4OJyw.js";const d={},k=n("h1",{id:"vless",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#vless"},[n("span",null,"VLESS")])],-1),b=n("div",{class:"custom-container danger"},[n("p",{class:"custom-container-title"},"Предупреждение"),n("p",null,"VLESS не предусматривает встроенного шифрования, поэтому обязательным условием для его использования является наличие надежного канала, такого как TLS или REALITY.")],-1),v=n("p",null,"VLESS - это легкий транспортный протокол без сохранения состояния, который разделен на входящую и исходящую части и может служить мостом между клиентом и сервером Xray.",-1),q=l(`

                                      InboundConfigurationObject

                                      {
                                      +import{_ as i,r as t,o as u,c as r,a as e,b as n,d as s,w as a,e as l}from"./app-D7uBbsY3.js";const d={},k=n("h1",{id:"vless",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#vless"},[n("span",null,"VLESS")])],-1),b=n("div",{class:"custom-container danger"},[n("p",{class:"custom-container-title"},"Предупреждение"),n("p",null,"VLESS не предусматривает встроенного шифрования, поэтому обязательным условием для его использования является наличие надежного канала, такого как TLS или REALITY.")],-1),v=n("p",null,"VLESS - это легкий транспортный протокол без сохранения состояния, который разделен на входящую и исходящую части и может служить мостом между клиентом и сервером Xray.",-1),q=l(`

                                      InboundConfigurationObject

                                      {
                                         "clients": [
                                           {
                                             "id": "5783a3e7-e373-51cd-8642-c83782b807c5",
                                      diff --git a/assets/vmess.html-CxHRDmLK.js b/assets/vmess.html-3nJoWs8G.js
                                      similarity index 99%
                                      rename from assets/vmess.html-CxHRDmLK.js
                                      rename to assets/vmess.html-3nJoWs8G.js
                                      index 14e3e0a3b2..58a591a0d0 100644
                                      --- a/assets/vmess.html-CxHRDmLK.js
                                      +++ b/assets/vmess.html-3nJoWs8G.js
                                      @@ -1 +1 @@
                                      -import{_ as s,r as a,o as r,c as d,a as l,b as t,d as e,e as n}from"./app-DBM4OJyw.js";const c={},o=n('

                                      VMess 协议

                                      VMess 是一个加密传输协议,可以作为 Xray 客户端和服务器之间的桥梁。

                                      版本

                                      当前版本号为 1。

                                      依赖

                                      底层协议

                                      VMess 是一个基于 TCP 的协议,所有数据使用 TCP 传输。

                                      用户 ID

                                      ',8),p={href:"https://en.wikipedia.org/wiki/Universally_unique_identifier",target:"_blank",rel:"noopener noreferrer"},x={href:"https://www.uuidgenerator.net/",target:"_blank",rel:"noopener noreferrer"},u=t("p",null,[e("用户 ID 可在"),t("a",{href:"../../config"},"配置文件"),e("中指定。")],-1),y=t("h3",{id:"函数",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#函数"},[t("span",null,"函数")])],-1),g={href:"https://en.wikipedia.org/wiki/MD5",target:"_blank",rel:"noopener noreferrer"},b=t("ul",null,[t("li",null,"输入参数为任意长度的 byte 数组"),t("li",null,"输出为一个 16 byte 的数组")],-1),_={href:"https://en.wikipedia.org/wiki/Hash-based_message_authentication_code",target:"_blank",rel:"noopener noreferrer"},M=t("ul",null,[t("li",null,[e("输入参数为: "),t("ul",null,[t("li",null,"H:散列函数"),t("li",null,"K:密钥,任意长度的 byte 数组"),t("li",null,"M:消息,任意长度的 byte 数组")])])],-1),f={href:"https://en.wikipedia.org/wiki/SHA-3",target:"_blank",rel:"noopener noreferrer"},V=t("ul",null,[t("li",null,"输入参数为任意长度的字符串"),t("li",null,"输出为任意长度的字符串")],-1),k=n('

                                      通讯过程

                                      VMess 是一个无状态协议,即客户端和服务器之间不需要握手即可直接传输数据,每一次数据传输对之前和之后的其它数据传输没有影响。

                                      VMess 的客户端发起一次请求,服务器判断该请求是否来自一个合法的客户端。如验证通过,则转发该请求,并把获得的响应发回给客户端。

                                      VMess 使用非对称格式,即客户端发出的请求和服务器端的响应使用了不同的格式。

                                      客户端请求

                                      16 字节X 字节余下部分
                                      认证信息指令部分数据部分

                                      认证信息

                                      认证信息是一个 16 字节的哈希(hash)值,它的计算方式如下:

                                      • H = MD5
                                      • K = 用户 ID (16 字节)
                                      • M = UTC 时间,精确到秒,取值为当前时间的前后 30 秒随机值(8 字节, Big Endian)
                                      • Hash = HMAC(H, K, M)

                                      指令部分

                                      指令部分经过 AES-128-CFB 加密:

                                      • Key:MD5(用户 ID + []byte('c48619fe-8f02-49e0-b9e9-edf763e17e21'))
                                      • IV:MD5(X + X + X + X),X = []byte(认证信息生成的时间) (8 字节, Big Endian)
                                      1 字节16 字节16 字节1 字节1 字节4 位4 位1 字节1 字节2 字节1 字节N 字节P 字节4 字节
                                      版本号 Ver数据加密 IV数据加密 Key响应认证 V选项 Opt余量 P加密方式 Sec保留指令 Cmd端口 Port地址类型 T地址 A随机值校验 F

                                      选项 Opt 细节:(当某一位为 1 时,表示该选项启用)

                                      01234567
                                      XXXXXMRS

                                      其中:

                                      • 版本号 Ver:始终为 1;
                                      • 数据加密 IV:随机值;
                                      • 数据加密 Key:随机值;
                                      • 响应认证 V:随机值;
                                      • 选项 Opt:
                                        • S (0x01):标准格式的数据流(建议开启);
                                        • R (0x02):客户端期待重用 TCP 连接(Xray 2.23+ 弃用);
                                          • 只有当 S 开启时,这一项才有效;
                                        • M (0x04):开启元数据混淆(建议开启);
                                          • 只有当 S 开启时,这一项才有效;
                                          • 当其项开启时,客户端和服务器端需要分别构造两个 Shake 实例,分别为 RequestMask = Shake(请求数据 IV), ResponseMask = Shake(响应数据 IV)。
                                        • X:保留
                                      • 余量 P:在校验值之前加入 P 字节的随机值;
                                      • 加密方式:指定数据部分的加密方式,可选的值有:
                                        • 0x00:AES-128-CFB;
                                        • 0x01:不加密;
                                        • 0x02:AES-128-GCM;
                                        • 0x03:ChaCha20-Poly1305;
                                      • 指令 Cmd:
                                        • 0x01:TCP 数据;
                                        • 0x02:UDP 数据;
                                      • 端口 Port:Big Endian 格式的整型端口号;
                                      • 地址类型 T:
                                        • 0x01:IPv4
                                        • 0x02:域名
                                        • 0x03:IPv6
                                      • 地址 A:
                                        • 当 T = 0x01 时,A 为 4 字节 IPv4 地址;
                                        • 当 T = 0x02 时,A 为 1 字节长度(L) + L 字节域名;
                                        • 当 T = 0x03 时,A 为 16 字节 IPv6 地址;
                                      • 校验 F:指令部分除 F 外所有内容的 FNV1a hash;

                                      数据部分

                                      当 Opt(S) 开启时,数据部分使用此格式。实际的请求数据被分割为若干个小块,每个小块的格式如下。服务器校验完所有的小块之后,再按基本格式的方式进行转发。

                                      2 字节L 字节
                                      长度 L数据包

                                      其中:

                                      • 长度 L:Big Endian 格式的整型,最大值为 2^14;
                                        • 当 Opt(M) 开启时,L 的值 = 真实值 xor Mask。Mask = (RequestMask.NextByte() << 8) + RequestMask.NextByte();
                                      • 数据包:由指定的加密方式加密过的数据包;

                                      在传输结束之前,数据包中必须有实际数据,即除了长度和认证数据之外的数据。当传输结束时,客户端必须发送一个空的数据包,即 L = 0(不加密) 或认证数据长度(有加密),来表示传输结束。

                                      按加密方式不同,数据包的格式如下:

                                      • 不加密:
                                        • L 字节:实际数据;
                                      • AES-128-CFB:整个数据部分使用 AES-128-CFB 加密
                                        • 4 字节:实际数据的 FNV1a hash;
                                        • L - 4 字节:实际数据;
                                      • AES-128-GCM:Key 为指令部分的 Key,IV = count (2 字节) + IV (10 字节)。count 从 0 开始递增,每个数据包加 1;IV 为 指令部分 IV 的第 3 至第 12 字节。
                                        • L - 16 字节:实际数据;
                                        • 16 字节:GCM 认证信息
                                      • ChaCha20-Poly1305:Key = MD5(指令部分 Key) + MD5(MD5(指令部分 Key)),IV = count (2 字节) + IV (10 字节)。count 从 0 开始递增,每个数据包加 1;IV 为 指令部分 IV 的第 3 至第 12 字节。
                                        • L - 16 字节:实际数据;
                                        • 16 字节:Poly1305 认证信息

                                      服务器应答

                                      应答头部数据使用 AES-128-CFB 加密,IV 为 MD5(数据加密 IV),Key 为 MD5(数据加密 Key)。实际应答数据视加密设置不同而不同。

                                      1 字节1 字节1 字节1 字节M 字节余下部分
                                      响应认证 V选项 Opt指令 Cmd指令长度 M指令内容实际应答数据

                                      其中:

                                      • 响应认证 V:必须和客户端请求中的响应认证 V 一致;
                                      • 选项 Opt:
                                        • 0x01:服务器端准备重用 TCP 连接(Xray 2.23+ 弃用);
                                      • 指令 Cmd:
                                        • 0x01:动态端口指令
                                      • 实际应答数据:
                                        • 如果请求中的 Opt(S) 开启,则使用标准格式,否则使用基本格式。
                                        • 格式均和请求数据相同。
                                          • 当 Opt(M) 开启时,长度 L 的值 = 真实值 xor Mask。Mask = (ResponseMask.NextByte() << 8) + ResponseMask.NextByte();

                                      动态端口指令

                                      1 字节2 字节16 字节2 字节1 字节1 字节
                                      保留端口 Port用户 IDAlterID用户等级有效时间 T

                                      其中:

                                      • 端口 Port:Big Endian 格式的整型端口号;
                                      • 有效时间 T:分钟数;

                                      客户端在收到动态端口指令时,服务器已开放新的端口用于通信,这时客户端可以将数据发往新的端口。在 T 分钟之后,这个端口将失效,客户端必须重新使用主端口进行通信。

                                      注释

                                      • 为确保向前兼容性,所有保留字段的值必须为 0。
                                      ',37);function I(C,D){const h=a("I18nTip"),i=a("ExternalLinkIcon");return r(),d("div",null,[l(h),o,t("p",null,[e("ID 等价于 "),t("a",p,[e("UUID"),l(i)]),e(",是一个 16 字节长的随机数,它的作用相当于一个令牌(Token)。 一个 ID 形如:de305d54-75b4-431b-adb2-eb6b9e546014,几乎完全随机,可以使用任何的 UUID 生成器来生成,比如"),t("a",x,[e("这个"),l(i)]),e("。")]),u,y,t("ul",null,[t("li",null,[e("MD5: "),t("a",g,[e("MD5 函数"),l(i)]),b]),t("li",null,[e("HMAC: "),t("a",_,[e("HMAC 函数"),l(i)]),M]),t("li",null,[e("Shake: "),t("a",f,[e("SHA3-Shake128 函数"),l(i)]),V])]),k])}const P=s(c,[["render",I],["__file","vmess.html.vue"]]);export{P as default}; +import{_ as s,r as a,o as r,c as d,a as l,b as t,d as e,e as n}from"./app-D7uBbsY3.js";const c={},o=n('

                                      VMess 协议

                                      VMess 是一个加密传输协议,可以作为 Xray 客户端和服务器之间的桥梁。

                                      版本

                                      当前版本号为 1。

                                      依赖

                                      底层协议

                                      VMess 是一个基于 TCP 的协议,所有数据使用 TCP 传输。

                                      用户 ID

                                      ',8),p={href:"https://en.wikipedia.org/wiki/Universally_unique_identifier",target:"_blank",rel:"noopener noreferrer"},x={href:"https://www.uuidgenerator.net/",target:"_blank",rel:"noopener noreferrer"},u=t("p",null,[e("用户 ID 可在"),t("a",{href:"../../config"},"配置文件"),e("中指定。")],-1),y=t("h3",{id:"函数",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#函数"},[t("span",null,"函数")])],-1),g={href:"https://en.wikipedia.org/wiki/MD5",target:"_blank",rel:"noopener noreferrer"},b=t("ul",null,[t("li",null,"输入参数为任意长度的 byte 数组"),t("li",null,"输出为一个 16 byte 的数组")],-1),_={href:"https://en.wikipedia.org/wiki/Hash-based_message_authentication_code",target:"_blank",rel:"noopener noreferrer"},M=t("ul",null,[t("li",null,[e("输入参数为: "),t("ul",null,[t("li",null,"H:散列函数"),t("li",null,"K:密钥,任意长度的 byte 数组"),t("li",null,"M:消息,任意长度的 byte 数组")])])],-1),f={href:"https://en.wikipedia.org/wiki/SHA-3",target:"_blank",rel:"noopener noreferrer"},V=t("ul",null,[t("li",null,"输入参数为任意长度的字符串"),t("li",null,"输出为任意长度的字符串")],-1),k=n('

                                      通讯过程

                                      VMess 是一个无状态协议,即客户端和服务器之间不需要握手即可直接传输数据,每一次数据传输对之前和之后的其它数据传输没有影响。

                                      VMess 的客户端发起一次请求,服务器判断该请求是否来自一个合法的客户端。如验证通过,则转发该请求,并把获得的响应发回给客户端。

                                      VMess 使用非对称格式,即客户端发出的请求和服务器端的响应使用了不同的格式。

                                      客户端请求

                                      16 字节X 字节余下部分
                                      认证信息指令部分数据部分

                                      认证信息

                                      认证信息是一个 16 字节的哈希(hash)值,它的计算方式如下:

                                      • H = MD5
                                      • K = 用户 ID (16 字节)
                                      • M = UTC 时间,精确到秒,取值为当前时间的前后 30 秒随机值(8 字节, Big Endian)
                                      • Hash = HMAC(H, K, M)

                                      指令部分

                                      指令部分经过 AES-128-CFB 加密:

                                      • Key:MD5(用户 ID + []byte('c48619fe-8f02-49e0-b9e9-edf763e17e21'))
                                      • IV:MD5(X + X + X + X),X = []byte(认证信息生成的时间) (8 字节, Big Endian)
                                      1 字节16 字节16 字节1 字节1 字节4 位4 位1 字节1 字节2 字节1 字节N 字节P 字节4 字节
                                      版本号 Ver数据加密 IV数据加密 Key响应认证 V选项 Opt余量 P加密方式 Sec保留指令 Cmd端口 Port地址类型 T地址 A随机值校验 F

                                      选项 Opt 细节:(当某一位为 1 时,表示该选项启用)

                                      01234567
                                      XXXXXMRS

                                      其中:

                                      • 版本号 Ver:始终为 1;
                                      • 数据加密 IV:随机值;
                                      • 数据加密 Key:随机值;
                                      • 响应认证 V:随机值;
                                      • 选项 Opt:
                                        • S (0x01):标准格式的数据流(建议开启);
                                        • R (0x02):客户端期待重用 TCP 连接(Xray 2.23+ 弃用);
                                          • 只有当 S 开启时,这一项才有效;
                                        • M (0x04):开启元数据混淆(建议开启);
                                          • 只有当 S 开启时,这一项才有效;
                                          • 当其项开启时,客户端和服务器端需要分别构造两个 Shake 实例,分别为 RequestMask = Shake(请求数据 IV), ResponseMask = Shake(响应数据 IV)。
                                        • X:保留
                                      • 余量 P:在校验值之前加入 P 字节的随机值;
                                      • 加密方式:指定数据部分的加密方式,可选的值有:
                                        • 0x00:AES-128-CFB;
                                        • 0x01:不加密;
                                        • 0x02:AES-128-GCM;
                                        • 0x03:ChaCha20-Poly1305;
                                      • 指令 Cmd:
                                        • 0x01:TCP 数据;
                                        • 0x02:UDP 数据;
                                      • 端口 Port:Big Endian 格式的整型端口号;
                                      • 地址类型 T:
                                        • 0x01:IPv4
                                        • 0x02:域名
                                        • 0x03:IPv6
                                      • 地址 A:
                                        • 当 T = 0x01 时,A 为 4 字节 IPv4 地址;
                                        • 当 T = 0x02 时,A 为 1 字节长度(L) + L 字节域名;
                                        • 当 T = 0x03 时,A 为 16 字节 IPv6 地址;
                                      • 校验 F:指令部分除 F 外所有内容的 FNV1a hash;

                                      数据部分

                                      当 Opt(S) 开启时,数据部分使用此格式。实际的请求数据被分割为若干个小块,每个小块的格式如下。服务器校验完所有的小块之后,再按基本格式的方式进行转发。

                                      2 字节L 字节
                                      长度 L数据包

                                      其中:

                                      • 长度 L:Big Endian 格式的整型,最大值为 2^14;
                                        • 当 Opt(M) 开启时,L 的值 = 真实值 xor Mask。Mask = (RequestMask.NextByte() << 8) + RequestMask.NextByte();
                                      • 数据包:由指定的加密方式加密过的数据包;

                                      在传输结束之前,数据包中必须有实际数据,即除了长度和认证数据之外的数据。当传输结束时,客户端必须发送一个空的数据包,即 L = 0(不加密) 或认证数据长度(有加密),来表示传输结束。

                                      按加密方式不同,数据包的格式如下:

                                      • 不加密:
                                        • L 字节:实际数据;
                                      • AES-128-CFB:整个数据部分使用 AES-128-CFB 加密
                                        • 4 字节:实际数据的 FNV1a hash;
                                        • L - 4 字节:实际数据;
                                      • AES-128-GCM:Key 为指令部分的 Key,IV = count (2 字节) + IV (10 字节)。count 从 0 开始递增,每个数据包加 1;IV 为 指令部分 IV 的第 3 至第 12 字节。
                                        • L - 16 字节:实际数据;
                                        • 16 字节:GCM 认证信息
                                      • ChaCha20-Poly1305:Key = MD5(指令部分 Key) + MD5(MD5(指令部分 Key)),IV = count (2 字节) + IV (10 字节)。count 从 0 开始递增,每个数据包加 1;IV 为 指令部分 IV 的第 3 至第 12 字节。
                                        • L - 16 字节:实际数据;
                                        • 16 字节:Poly1305 认证信息

                                      服务器应答

                                      应答头部数据使用 AES-128-CFB 加密,IV 为 MD5(数据加密 IV),Key 为 MD5(数据加密 Key)。实际应答数据视加密设置不同而不同。

                                      1 字节1 字节1 字节1 字节M 字节余下部分
                                      响应认证 V选项 Opt指令 Cmd指令长度 M指令内容实际应答数据

                                      其中:

                                      • 响应认证 V:必须和客户端请求中的响应认证 V 一致;
                                      • 选项 Opt:
                                        • 0x01:服务器端准备重用 TCP 连接(Xray 2.23+ 弃用);
                                      • 指令 Cmd:
                                        • 0x01:动态端口指令
                                      • 实际应答数据:
                                        • 如果请求中的 Opt(S) 开启,则使用标准格式,否则使用基本格式。
                                        • 格式均和请求数据相同。
                                          • 当 Opt(M) 开启时,长度 L 的值 = 真实值 xor Mask。Mask = (ResponseMask.NextByte() << 8) + ResponseMask.NextByte();

                                      动态端口指令

                                      1 字节2 字节16 字节2 字节1 字节1 字节
                                      保留端口 Port用户 IDAlterID用户等级有效时间 T

                                      其中:

                                      • 端口 Port:Big Endian 格式的整型端口号;
                                      • 有效时间 T:分钟数;

                                      客户端在收到动态端口指令时,服务器已开放新的端口用于通信,这时客户端可以将数据发往新的端口。在 T 分钟之后,这个端口将失效,客户端必须重新使用主端口进行通信。

                                      注释

                                      • 为确保向前兼容性,所有保留字段的值必须为 0。
                                      ',37);function I(C,D){const h=a("I18nTip"),i=a("ExternalLinkIcon");return r(),d("div",null,[l(h),o,t("p",null,[e("ID 等价于 "),t("a",p,[e("UUID"),l(i)]),e(",是一个 16 字节长的随机数,它的作用相当于一个令牌(Token)。 一个 ID 形如:de305d54-75b4-431b-adb2-eb6b9e546014,几乎完全随机,可以使用任何的 UUID 生成器来生成,比如"),t("a",x,[e("这个"),l(i)]),e("。")]),u,y,t("ul",null,[t("li",null,[e("MD5: "),t("a",g,[e("MD5 函数"),l(i)]),b]),t("li",null,[e("HMAC: "),t("a",_,[e("HMAC 函数"),l(i)]),M]),t("li",null,[e("Shake: "),t("a",f,[e("SHA3-Shake128 函数"),l(i)]),V])]),k])}const P=s(c,[["render",I],["__file","vmess.html.vue"]]);export{P as default}; diff --git a/assets/vmess.html-9ma69iWT.js b/assets/vmess.html-B3TZl91-.js similarity index 99% rename from assets/vmess.html-9ma69iWT.js rename to assets/vmess.html-B3TZl91-.js index 59e4a6b944..1b2d4e8cb5 100644 --- a/assets/vmess.html-9ma69iWT.js +++ b/assets/vmess.html-B3TZl91-.js @@ -1 +1 @@ -import{_ as r,r as i,o,c as h,a as n,b as t,d as e,e as s}from"./app-DBM4OJyw.js";const d={},c=s('

                                      VMess Protocol

                                      VMess is an encrypted transmission protocol that can serve as a bridge between the Xray client and server.

                                      Version

                                      The current version number is 1.

                                      Dependencies

                                      Underlying Protocol

                                      VMess is a TCP-based protocol where all data is transmitted over TCP.

                                      User ID

                                      ',8),u={href:"https://en.wikipedia.org/wiki/Universally_unique_identifier",target:"_blank",rel:"noopener noreferrer"},p=t("code",null,"de305d54-75b4-431b-adb2-eb6b9e546014",-1),y={href:"https://www.uuidgenerator.net/",target:"_blank",rel:"noopener noreferrer"},m=t("p",null,[e("User ID can be specified in the "),t("a",{href:"../../config"},"configuration file"),e(".")],-1),b=t("h3",{id:"functions",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#functions"},[t("span",null,"Functions")])],-1),f={href:"https://en.wikipedia.org/wiki/MD5",target:"_blank",rel:"noopener noreferrer"},g=t("ul",null,[t("li",null,"Input parameter is any length byte array"),t("li",null,"Output is a 16-byte array")],-1),x={href:"https://en.wikipedia.org/wiki/Hash-based_message_authentication_code",target:"_blank",rel:"noopener noreferrer"},v=t("ul",null,[t("li",null,[e("Input parameters are: "),t("ul",null,[t("li",null,"H: Hash function"),t("li",null,"K: Key, any length byte array"),t("li",null,"M: Message, any length byte array")])])],-1),k={href:"https://en.wikipedia.org/wiki/SHA-3",target:"_blank",rel:"noopener noreferrer"},_=t("ul",null,[t("li",null,"Input parameter is any length string"),t("li",null,"Output is any length string")],-1),I=s('

                                      Communication Process

                                      VMess is a stateless protocol, which means that data can be transmitted directly between the client and the server without the need for a handshake. Each data transmission has no impact on other data transmissions before or after it.

                                      When a VMess client initiates a request, the server checks whether the request comes from a legitimate client. If the validation passes, the server forwards the request and sends the obtained response back to the client.

                                      VMess uses an asymmetric format, meaning that the requests sent by the client and the responses from the server use different formats.

                                      Client Request

                                      16 BytesX BytesRemaining
                                      Authentication InformationInstruction PartData Part

                                      Authentication Information

                                      The authentication information is a 16-byte hash (hash) value, which is calculated as follows:

                                      • H = MD5
                                      • K = User ID (16 bytes)
                                      • M = UTC time accurate to seconds, with a random value of ±30 seconds from the current time (8 bytes, Big Endian)
                                      • Hash = HMAC(H, K, M)

                                      Command Section

                                      The instruction part is encrypted using AES-128-CFB.

                                      • Key: MD5(user ID + []byte('c48619fe-8f02-49e0-b9e9-edf763e17e21'))
                                      • IV: MD5(X + X + X + X), X = []byte(time generated by authentication information) (8 bytes, Big Endian)
                                      1 Byte16 Bytes16 Bytes1 Byte1 Byte4 bits4 bits1 Byte1 Byte2 Bytes1 ByteN BytesP Bytes4 Bytes
                                      VersionData Encryption IVData Encryption KeyResponse Authentication ValueOptionsReservedEncryption MethodReservedCommandPortAddress TypeAddressRandom ValueChecksum

                                      Options Opt Details: (When a bit is 1, it means the option is enabled)

                                      01234567
                                      XXXXXMRS

                                      of which:

                                      • Version Number Ver: Always 1;
                                      • Data Encryption IV: Random value;
                                      • Data Encryption Key: Random value;
                                      • Response Authentication V: Random value;
                                      • Option Opt:
                                        • S (0x01): Standard format data stream (recommended);
                                        • R (0x02): Client expects to reuse TCP connection (deprecated in Xray 2.23+);
                                          • This item only takes effect when S is enabled;
                                        • M (0x04): Enable metadata obfuscation (recommended);
                                          • This item only takes effect when S is enabled;
                                          • When this item is enabled, the client and server need to construct two Shake instances respectively, RequestMask = Shake (request data IV), ResponseMask = Shake (response data IV).
                                        • X: Reserved
                                      • Redundancy P: Random value added before checksum value;
                                      • Encryption Method: Specify the encryption method for the data part, and the optional values are:
                                        • 0x00: AES-128-CFB;
                                        • 0x01: No encryption;
                                        • 0x02: AES-128-GCM;
                                        • 0x03: ChaCha20-Poly1305;
                                      • Instruction Cmd:
                                        • 0x01: TCP data;
                                        • 0x02: UDP data;
                                      • Port Port: Integer port number in Big Endian format;
                                      • Address Type T:
                                        • 0x01: IPv4
                                        • 0x02: Domain name
                                        • 0x03: IPv6
                                      • Address A:
                                        • When T = 0x01, A is a 4-byte IPv4 address;
                                        • When T = 0x02, A is a 1-byte length (L) + L-byte domain name;
                                        • When T = 0x03, A is a 16-byte IPv6 address;
                                      • Check F: FNV1a hash of all content in the instruction except F.

                                      Data Section

                                      When Opt(S) is enabled, this format is used for the data section. The actual request data is divided into several small chunks, and each chunk has the following format. After the server verifies all the small chunks, it will be forwarded in the basic format.

                                      2 BytesL Bytes
                                      Length LData Packet

                                      in which:

                                      • Length L: A big-endian integer with a maximum value of 2^14.
                                        • When Opt(M) is enabled, the value of L is equal to the true value xor Mask. Mask = (RequestMask.NextByte() << 8) + RequestMask.NextByte();
                                      • Packet: A data packet encrypted by the specified encryption method.

                                      Before the transmission is completed, the data packet must contain actual data, in addition to the length and authentication data. When the transmission is complete, the client must send an empty data packet, that is, L = 0 (unencrypted) or the length of the authentication data (encrypted), to indicate the end of the transmission.

                                      The packets are formatted as follows, depending on the encryption method:

                                      • Unencrypted:   - L bytes: actual data;
                                      • AES-128-CFB: The entire data section is encrypted using AES-128-CFB.   - 4 bytes: FNV1a hash of actual data;   - L - 4 bytes: actual data;
                                      • AES-128-GCM: Key is the Key of the instruction section, IV = count (2 bytes) + IV (10 bytes). count starts at 0 and increases by 1 for each packet; IV is the 3rd to 12th byte of the instruction section IV.   - L - 16 bytes: actual data;   - 16 bytes: GCM authentication information
                                      • ChaCha20-Poly1305: Key = MD5 (instruction part Key) + MD5 (MD5 (instruction part Key)), IV = count (2 bytes) + IV (10 bytes). count starts at 0 and increases by 1 for each packet; IV is the 3rd to 12th byte of the instruction section IV.   - L - 16 bytes: actual data;   - 16 bytes: Poly1305 authentication information

                                      Server Response

                                      The header data is encrypted using AES-128-CFB encryption. The IV is MD5 of the data encryption IV, and the Key is MD5 of the data encryption Key. The actual response data varies depending on the encryption settings.

                                      1 Byte1 Byte1 Byte1 ByteM BytesRemaining Part
                                      Response Authentication VOption OptCommand CmdCommand Length MCommand ContentActual Response Data

                                      in which:

                                      • Response Authentication V: must match the response authentication V in the client request.
                                      • Option Opt:
                                        • 0x01: server prepares to reuse TCP connections (deprecated in Xray 2.23+).
                                      • Command Cmd:
                                        • 0x01: dynamic port command.
                                      • Actual response data:
                                        • If Opt(S) in the request is enabled, the standard format is used. Otherwise, the basic format is used.
                                        • Both formats are identical to the request data.
                                          • When Opt(M) is enabled, the value of length L is equal to the true value XOR Mask. Mask = (ResponseMask.NextByte() << 8) + ResponseMask.NextByte().

                                      Dynamic Port Instructions

                                      1 Byte2 Bytes16 Bytes2 Bytes1 Byte1 Byte
                                      ReservedPortUser IDAlterIDUser levelValidity period T

                                      in which:

                                      • Port: Integer port number in Big Endian format
                                      • T: Number of minutes as integer value.

                                      When the client receives a dynamic port command, the server opens a new port for communication. The client can then send data to the new port. After T minutes, the port will expire, and the client must use the main port to communicate again.

                                      Comment

                                      • To ensure forward compatibility, the values of all reserved fields must be 0.
                                      ',37);function B(M,w){const l=i("I18nTip"),a=i("ExternalLinkIcon");return o(),h("div",null,[n(l),c,t("p",null,[e("An ID is equivalent to a "),t("a",u,[e("UUID"),n(a)]),e(", which is a 16-byte long random number. Its function is similar to a token. An ID looks like: "),p,e(", it is almost entirely random and can be generated using any UUID generator, such as "),t("a",y,[e("this one"),n(a)]),e(".")]),m,b,t("ul",null,[t("li",null,[e("MD5: "),t("a",f,[e("MD5 Function"),n(a)]),g]),t("li",null,[e("HMAC: "),t("a",x,[e("HMAC Function"),n(a)]),v]),t("li",null,[e("Shake: "),t("a",k,[e("SHA3-Shake128 Function"),n(a)]),_])]),I])}const V=r(d,[["render",B],["__file","vmess.html.vue"]]);export{V as default}; +import{_ as r,r as i,o,c as h,a as n,b as t,d as e,e as s}from"./app-D7uBbsY3.js";const d={},c=s('

                                      VMess Protocol

                                      VMess is an encrypted transmission protocol that can serve as a bridge between the Xray client and server.

                                      Version

                                      The current version number is 1.

                                      Dependencies

                                      Underlying Protocol

                                      VMess is a TCP-based protocol where all data is transmitted over TCP.

                                      User ID

                                      ',8),u={href:"https://en.wikipedia.org/wiki/Universally_unique_identifier",target:"_blank",rel:"noopener noreferrer"},p=t("code",null,"de305d54-75b4-431b-adb2-eb6b9e546014",-1),y={href:"https://www.uuidgenerator.net/",target:"_blank",rel:"noopener noreferrer"},m=t("p",null,[e("User ID can be specified in the "),t("a",{href:"../../config"},"configuration file"),e(".")],-1),b=t("h3",{id:"functions",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#functions"},[t("span",null,"Functions")])],-1),f={href:"https://en.wikipedia.org/wiki/MD5",target:"_blank",rel:"noopener noreferrer"},g=t("ul",null,[t("li",null,"Input parameter is any length byte array"),t("li",null,"Output is a 16-byte array")],-1),x={href:"https://en.wikipedia.org/wiki/Hash-based_message_authentication_code",target:"_blank",rel:"noopener noreferrer"},v=t("ul",null,[t("li",null,[e("Input parameters are: "),t("ul",null,[t("li",null,"H: Hash function"),t("li",null,"K: Key, any length byte array"),t("li",null,"M: Message, any length byte array")])])],-1),k={href:"https://en.wikipedia.org/wiki/SHA-3",target:"_blank",rel:"noopener noreferrer"},_=t("ul",null,[t("li",null,"Input parameter is any length string"),t("li",null,"Output is any length string")],-1),I=s('

                                      Communication Process

                                      VMess is a stateless protocol, which means that data can be transmitted directly between the client and the server without the need for a handshake. Each data transmission has no impact on other data transmissions before or after it.

                                      When a VMess client initiates a request, the server checks whether the request comes from a legitimate client. If the validation passes, the server forwards the request and sends the obtained response back to the client.

                                      VMess uses an asymmetric format, meaning that the requests sent by the client and the responses from the server use different formats.

                                      Client Request

                                      16 BytesX BytesRemaining
                                      Authentication InformationInstruction PartData Part

                                      Authentication Information

                                      The authentication information is a 16-byte hash (hash) value, which is calculated as follows:

                                      • H = MD5
                                      • K = User ID (16 bytes)
                                      • M = UTC time accurate to seconds, with a random value of ±30 seconds from the current time (8 bytes, Big Endian)
                                      • Hash = HMAC(H, K, M)

                                      Command Section

                                      The instruction part is encrypted using AES-128-CFB.

                                      • Key: MD5(user ID + []byte('c48619fe-8f02-49e0-b9e9-edf763e17e21'))
                                      • IV: MD5(X + X + X + X), X = []byte(time generated by authentication information) (8 bytes, Big Endian)
                                      1 Byte16 Bytes16 Bytes1 Byte1 Byte4 bits4 bits1 Byte1 Byte2 Bytes1 ByteN BytesP Bytes4 Bytes
                                      VersionData Encryption IVData Encryption KeyResponse Authentication ValueOptionsReservedEncryption MethodReservedCommandPortAddress TypeAddressRandom ValueChecksum

                                      Options Opt Details: (When a bit is 1, it means the option is enabled)

                                      01234567
                                      XXXXXMRS

                                      of which:

                                      • Version Number Ver: Always 1;
                                      • Data Encryption IV: Random value;
                                      • Data Encryption Key: Random value;
                                      • Response Authentication V: Random value;
                                      • Option Opt:
                                        • S (0x01): Standard format data stream (recommended);
                                        • R (0x02): Client expects to reuse TCP connection (deprecated in Xray 2.23+);
                                          • This item only takes effect when S is enabled;
                                        • M (0x04): Enable metadata obfuscation (recommended);
                                          • This item only takes effect when S is enabled;
                                          • When this item is enabled, the client and server need to construct two Shake instances respectively, RequestMask = Shake (request data IV), ResponseMask = Shake (response data IV).
                                        • X: Reserved
                                      • Redundancy P: Random value added before checksum value;
                                      • Encryption Method: Specify the encryption method for the data part, and the optional values are:
                                        • 0x00: AES-128-CFB;
                                        • 0x01: No encryption;
                                        • 0x02: AES-128-GCM;
                                        • 0x03: ChaCha20-Poly1305;
                                      • Instruction Cmd:
                                        • 0x01: TCP data;
                                        • 0x02: UDP data;
                                      • Port Port: Integer port number in Big Endian format;
                                      • Address Type T:
                                        • 0x01: IPv4
                                        • 0x02: Domain name
                                        • 0x03: IPv6
                                      • Address A:
                                        • When T = 0x01, A is a 4-byte IPv4 address;
                                        • When T = 0x02, A is a 1-byte length (L) + L-byte domain name;
                                        • When T = 0x03, A is a 16-byte IPv6 address;
                                      • Check F: FNV1a hash of all content in the instruction except F.

                                      Data Section

                                      When Opt(S) is enabled, this format is used for the data section. The actual request data is divided into several small chunks, and each chunk has the following format. After the server verifies all the small chunks, it will be forwarded in the basic format.

                                      2 BytesL Bytes
                                      Length LData Packet

                                      in which:

                                      • Length L: A big-endian integer with a maximum value of 2^14.
                                        • When Opt(M) is enabled, the value of L is equal to the true value xor Mask. Mask = (RequestMask.NextByte() << 8) + RequestMask.NextByte();
                                      • Packet: A data packet encrypted by the specified encryption method.

                                      Before the transmission is completed, the data packet must contain actual data, in addition to the length and authentication data. When the transmission is complete, the client must send an empty data packet, that is, L = 0 (unencrypted) or the length of the authentication data (encrypted), to indicate the end of the transmission.

                                      The packets are formatted as follows, depending on the encryption method:

                                      • Unencrypted:   - L bytes: actual data;
                                      • AES-128-CFB: The entire data section is encrypted using AES-128-CFB.   - 4 bytes: FNV1a hash of actual data;   - L - 4 bytes: actual data;
                                      • AES-128-GCM: Key is the Key of the instruction section, IV = count (2 bytes) + IV (10 bytes). count starts at 0 and increases by 1 for each packet; IV is the 3rd to 12th byte of the instruction section IV.   - L - 16 bytes: actual data;   - 16 bytes: GCM authentication information
                                      • ChaCha20-Poly1305: Key = MD5 (instruction part Key) + MD5 (MD5 (instruction part Key)), IV = count (2 bytes) + IV (10 bytes). count starts at 0 and increases by 1 for each packet; IV is the 3rd to 12th byte of the instruction section IV.   - L - 16 bytes: actual data;   - 16 bytes: Poly1305 authentication information

                                      Server Response

                                      The header data is encrypted using AES-128-CFB encryption. The IV is MD5 of the data encryption IV, and the Key is MD5 of the data encryption Key. The actual response data varies depending on the encryption settings.

                                      1 Byte1 Byte1 Byte1 ByteM BytesRemaining Part
                                      Response Authentication VOption OptCommand CmdCommand Length MCommand ContentActual Response Data

                                      in which:

                                      • Response Authentication V: must match the response authentication V in the client request.
                                      • Option Opt:
                                        • 0x01: server prepares to reuse TCP connections (deprecated in Xray 2.23+).
                                      • Command Cmd:
                                        • 0x01: dynamic port command.
                                      • Actual response data:
                                        • If Opt(S) in the request is enabled, the standard format is used. Otherwise, the basic format is used.
                                        • Both formats are identical to the request data.
                                          • When Opt(M) is enabled, the value of length L is equal to the true value XOR Mask. Mask = (ResponseMask.NextByte() << 8) + ResponseMask.NextByte().

                                      Dynamic Port Instructions

                                      1 Byte2 Bytes16 Bytes2 Bytes1 Byte1 Byte
                                      ReservedPortUser IDAlterIDUser levelValidity period T

                                      in which:

                                      • Port: Integer port number in Big Endian format
                                      • T: Number of minutes as integer value.

                                      When the client receives a dynamic port command, the server opens a new port for communication. The client can then send data to the new port. After T minutes, the port will expire, and the client must use the main port to communicate again.

                                      Comment

                                      • To ensure forward compatibility, the values of all reserved fields must be 0.
                                      ',37);function B(M,w){const l=i("I18nTip"),a=i("ExternalLinkIcon");return o(),h("div",null,[n(l),c,t("p",null,[e("An ID is equivalent to a "),t("a",u,[e("UUID"),n(a)]),e(", which is a 16-byte long random number. Its function is similar to a token. An ID looks like: "),p,e(", it is almost entirely random and can be generated using any UUID generator, such as "),t("a",y,[e("this one"),n(a)]),e(".")]),m,b,t("ul",null,[t("li",null,[e("MD5: "),t("a",f,[e("MD5 Function"),n(a)]),g]),t("li",null,[e("HMAC: "),t("a",x,[e("HMAC Function"),n(a)]),v]),t("li",null,[e("Shake: "),t("a",k,[e("SHA3-Shake128 Function"),n(a)]),_])]),I])}const V=r(d,[["render",B],["__file","vmess.html.vue"]]);export{V as default}; diff --git a/assets/vmess.html-BQ6qtjqJ.js b/assets/vmess.html-Btr59-Cl.js similarity index 99% rename from assets/vmess.html-BQ6qtjqJ.js rename to assets/vmess.html-Btr59-Cl.js index 25322eb283..2ec7536c99 100644 --- a/assets/vmess.html-BQ6qtjqJ.js +++ b/assets/vmess.html-Btr59-Cl.js @@ -1,4 +1,4 @@ -import{_ as p,r as a,o as r,c as u,a as s,b as e,w as o,d as n,e as l}from"./app-DBM4OJyw.js";const d={},h=e("h1",{id:"vmess",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#vmess"},[e("span",null,"VMess")])],-1),v=l(`

                                      Danger

                                      VMess relies on system time. Please ensure that the system UTC time used by Xray is within 120 seconds of the actual time, regardless of time zone. On Linux systems, you can install the ntp service to automatically synchronize the system time.

                                      InboundConfigurationObject

                                      {
                                      +import{_ as p,r as a,o as r,c as u,a as s,b as e,w as o,d as n,e as l}from"./app-D7uBbsY3.js";const d={},h=e("h1",{id:"vmess",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#vmess"},[e("span",null,"VMess")])],-1),v=l(`

                                      Danger

                                      VMess relies on system time. Please ensure that the system UTC time used by Xray is within 120 seconds of the actual time, regardless of time zone. On Linux systems, you can install the ntp service to automatically synchronize the system time.

                                      InboundConfigurationObject

                                      {
                                         "clients": [
                                           {
                                             "id": "5783a3e7-e373-51cd-8642-c83782b807c5",
                                      diff --git a/assets/vmess.html-ILF_tpZ9.js b/assets/vmess.html-C2MIBK-h.js
                                      similarity index 99%
                                      rename from assets/vmess.html-ILF_tpZ9.js
                                      rename to assets/vmess.html-C2MIBK-h.js
                                      index 4f6c0fdcaf..2378b99a83 100644
                                      --- a/assets/vmess.html-ILF_tpZ9.js
                                      +++ b/assets/vmess.html-C2MIBK-h.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as l,r as a,o as i,c as r,a as e,b as s,w as t,d as n,e as c}from"./app-DBM4OJyw.js";const d={},q=s("h1",{id:"vmess",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#vmess"},[s("span",null,"VMess")])],-1),v=c(`

                                      警告

                                      VMess 依赖于系统时间,请确保使用 Xray 的系统 UTC 时间误差在 120 秒之内,时区无关。在 Linux 系统中可以安装ntp服务来自动同步系统时间。

                                      OutboundConfigurationObject

                                      {
                                      +import{_ as l,r as a,o as i,c as r,a as e,b as s,w as t,d as n,e as c}from"./app-D7uBbsY3.js";const d={},q=s("h1",{id:"vmess",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#vmess"},[s("span",null,"VMess")])],-1),v=c(`

                                      警告

                                      VMess 依赖于系统时间,请确保使用 Xray 的系统 UTC 时间误差在 120 秒之内,时区无关。在 Linux 系统中可以安装ntp服务来自动同步系统时间。

                                      OutboundConfigurationObject

                                      {
                                         "vnext": [
                                           {
                                             "address": "127.0.0.1",
                                      diff --git a/assets/vmess.html-D8fkP4-1.js b/assets/vmess.html-CDBIkJMN.js
                                      similarity index 99%
                                      rename from assets/vmess.html-D8fkP4-1.js
                                      rename to assets/vmess.html-CDBIkJMN.js
                                      index 41f7d260ff..5dfaa939b7 100644
                                      --- a/assets/vmess.html-D8fkP4-1.js
                                      +++ b/assets/vmess.html-CDBIkJMN.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as p,r as t,o as u,c as l,a as s,b as n,w as a,d as e,e as c}from"./app-DBM4OJyw.js";const d={},h=n("h1",{id:"vmess",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#vmess"},[n("span",null,"VMess")])],-1),m=c(`

                                      Danger

                                      VMess relies on system time. Please ensure that the UTC time of your system, when using Xray, has an error within 120 seconds, regardless of the time zone. On Linux systems, you can install the ntp service to automatically synchronize the system time.

                                      OutboundConfigurationObject

                                      {
                                      +import{_ as p,r as t,o as u,c as l,a as s,b as n,w as a,d as e,e as c}from"./app-D7uBbsY3.js";const d={},h=n("h1",{id:"vmess",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#vmess"},[n("span",null,"VMess")])],-1),m=c(`

                                      Danger

                                      VMess relies on system time. Please ensure that the UTC time of your system, when using Xray, has an error within 120 seconds, regardless of the time zone. On Linux systems, you can install the ntp service to automatically synchronize the system time.

                                      OutboundConfigurationObject

                                      {
                                         "vnext": [
                                           {
                                             "address": "127.0.0.1",
                                      diff --git a/assets/vmess.html-BR7lDLGa.js b/assets/vmess.html-CktEh3JK.js
                                      similarity index 99%
                                      rename from assets/vmess.html-BR7lDLGa.js
                                      rename to assets/vmess.html-CktEh3JK.js
                                      index 7acbdba4b5..89d8ef49b9 100644
                                      --- a/assets/vmess.html-BR7lDLGa.js
                                      +++ b/assets/vmess.html-CktEh3JK.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as i,r as t,o as u,c as d,a as e,b as n,w as o,d as s,e as l}from"./app-DBM4OJyw.js";const r={},v=n("h1",{id:"vmess",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#vmess"},[n("span",null,"VMess")])],-1),b=l(`

                                      Предупреждение

                                      VMess полагается на системное время. Убедитесь, что системное время UTC, используемое Xray, находится в пределах 120 секунд от фактического времени, независимо от часового пояса. В системах Linux вы можете установить службу ntp для автоматической синхронизации системного времени.

                                      InboundConfigurationObject

                                      {
                                      +import{_ as i,r as t,o as u,c as d,a as e,b as n,w as o,d as s,e as l}from"./app-D7uBbsY3.js";const r={},v=n("h1",{id:"vmess",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#vmess"},[n("span",null,"VMess")])],-1),b=l(`

                                      Предупреждение

                                      VMess полагается на системное время. Убедитесь, что системное время UTC, используемое Xray, находится в пределах 120 секунд от фактического времени, независимо от часового пояса. В системах Linux вы можете установить службу ntp для автоматической синхронизации системного времени.

                                      InboundConfigurationObject

                                      {
                                         "clients": [
                                           {
                                             "id": "5783a3e7-e373-51cd-8642-c83782b807c5",
                                      diff --git a/assets/vmess.html-zYdoLiG_.js b/assets/vmess.html-D8plPLT5.js
                                      similarity index 99%
                                      rename from assets/vmess.html-zYdoLiG_.js
                                      rename to assets/vmess.html-D8plPLT5.js
                                      index 14e3e0a3b2..58a591a0d0 100644
                                      --- a/assets/vmess.html-zYdoLiG_.js
                                      +++ b/assets/vmess.html-D8plPLT5.js
                                      @@ -1 +1 @@
                                      -import{_ as s,r as a,o as r,c as d,a as l,b as t,d as e,e as n}from"./app-DBM4OJyw.js";const c={},o=n('

                                      VMess 协议

                                      VMess 是一个加密传输协议,可以作为 Xray 客户端和服务器之间的桥梁。

                                      版本

                                      当前版本号为 1。

                                      依赖

                                      底层协议

                                      VMess 是一个基于 TCP 的协议,所有数据使用 TCP 传输。

                                      用户 ID

                                      ',8),p={href:"https://en.wikipedia.org/wiki/Universally_unique_identifier",target:"_blank",rel:"noopener noreferrer"},x={href:"https://www.uuidgenerator.net/",target:"_blank",rel:"noopener noreferrer"},u=t("p",null,[e("用户 ID 可在"),t("a",{href:"../../config"},"配置文件"),e("中指定。")],-1),y=t("h3",{id:"函数",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#函数"},[t("span",null,"函数")])],-1),g={href:"https://en.wikipedia.org/wiki/MD5",target:"_blank",rel:"noopener noreferrer"},b=t("ul",null,[t("li",null,"输入参数为任意长度的 byte 数组"),t("li",null,"输出为一个 16 byte 的数组")],-1),_={href:"https://en.wikipedia.org/wiki/Hash-based_message_authentication_code",target:"_blank",rel:"noopener noreferrer"},M=t("ul",null,[t("li",null,[e("输入参数为: "),t("ul",null,[t("li",null,"H:散列函数"),t("li",null,"K:密钥,任意长度的 byte 数组"),t("li",null,"M:消息,任意长度的 byte 数组")])])],-1),f={href:"https://en.wikipedia.org/wiki/SHA-3",target:"_blank",rel:"noopener noreferrer"},V=t("ul",null,[t("li",null,"输入参数为任意长度的字符串"),t("li",null,"输出为任意长度的字符串")],-1),k=n('

                                      通讯过程

                                      VMess 是一个无状态协议,即客户端和服务器之间不需要握手即可直接传输数据,每一次数据传输对之前和之后的其它数据传输没有影响。

                                      VMess 的客户端发起一次请求,服务器判断该请求是否来自一个合法的客户端。如验证通过,则转发该请求,并把获得的响应发回给客户端。

                                      VMess 使用非对称格式,即客户端发出的请求和服务器端的响应使用了不同的格式。

                                      客户端请求

                                      16 字节X 字节余下部分
                                      认证信息指令部分数据部分

                                      认证信息

                                      认证信息是一个 16 字节的哈希(hash)值,它的计算方式如下:

                                      • H = MD5
                                      • K = 用户 ID (16 字节)
                                      • M = UTC 时间,精确到秒,取值为当前时间的前后 30 秒随机值(8 字节, Big Endian)
                                      • Hash = HMAC(H, K, M)

                                      指令部分

                                      指令部分经过 AES-128-CFB 加密:

                                      • Key:MD5(用户 ID + []byte('c48619fe-8f02-49e0-b9e9-edf763e17e21'))
                                      • IV:MD5(X + X + X + X),X = []byte(认证信息生成的时间) (8 字节, Big Endian)
                                      1 字节16 字节16 字节1 字节1 字节4 位4 位1 字节1 字节2 字节1 字节N 字节P 字节4 字节
                                      版本号 Ver数据加密 IV数据加密 Key响应认证 V选项 Opt余量 P加密方式 Sec保留指令 Cmd端口 Port地址类型 T地址 A随机值校验 F

                                      选项 Opt 细节:(当某一位为 1 时,表示该选项启用)

                                      01234567
                                      XXXXXMRS

                                      其中:

                                      • 版本号 Ver:始终为 1;
                                      • 数据加密 IV:随机值;
                                      • 数据加密 Key:随机值;
                                      • 响应认证 V:随机值;
                                      • 选项 Opt:
                                        • S (0x01):标准格式的数据流(建议开启);
                                        • R (0x02):客户端期待重用 TCP 连接(Xray 2.23+ 弃用);
                                          • 只有当 S 开启时,这一项才有效;
                                        • M (0x04):开启元数据混淆(建议开启);
                                          • 只有当 S 开启时,这一项才有效;
                                          • 当其项开启时,客户端和服务器端需要分别构造两个 Shake 实例,分别为 RequestMask = Shake(请求数据 IV), ResponseMask = Shake(响应数据 IV)。
                                        • X:保留
                                      • 余量 P:在校验值之前加入 P 字节的随机值;
                                      • 加密方式:指定数据部分的加密方式,可选的值有:
                                        • 0x00:AES-128-CFB;
                                        • 0x01:不加密;
                                        • 0x02:AES-128-GCM;
                                        • 0x03:ChaCha20-Poly1305;
                                      • 指令 Cmd:
                                        • 0x01:TCP 数据;
                                        • 0x02:UDP 数据;
                                      • 端口 Port:Big Endian 格式的整型端口号;
                                      • 地址类型 T:
                                        • 0x01:IPv4
                                        • 0x02:域名
                                        • 0x03:IPv6
                                      • 地址 A:
                                        • 当 T = 0x01 时,A 为 4 字节 IPv4 地址;
                                        • 当 T = 0x02 时,A 为 1 字节长度(L) + L 字节域名;
                                        • 当 T = 0x03 时,A 为 16 字节 IPv6 地址;
                                      • 校验 F:指令部分除 F 外所有内容的 FNV1a hash;

                                      数据部分

                                      当 Opt(S) 开启时,数据部分使用此格式。实际的请求数据被分割为若干个小块,每个小块的格式如下。服务器校验完所有的小块之后,再按基本格式的方式进行转发。

                                      2 字节L 字节
                                      长度 L数据包

                                      其中:

                                      • 长度 L:Big Endian 格式的整型,最大值为 2^14;
                                        • 当 Opt(M) 开启时,L 的值 = 真实值 xor Mask。Mask = (RequestMask.NextByte() << 8) + RequestMask.NextByte();
                                      • 数据包:由指定的加密方式加密过的数据包;

                                      在传输结束之前,数据包中必须有实际数据,即除了长度和认证数据之外的数据。当传输结束时,客户端必须发送一个空的数据包,即 L = 0(不加密) 或认证数据长度(有加密),来表示传输结束。

                                      按加密方式不同,数据包的格式如下:

                                      • 不加密:
                                        • L 字节:实际数据;
                                      • AES-128-CFB:整个数据部分使用 AES-128-CFB 加密
                                        • 4 字节:实际数据的 FNV1a hash;
                                        • L - 4 字节:实际数据;
                                      • AES-128-GCM:Key 为指令部分的 Key,IV = count (2 字节) + IV (10 字节)。count 从 0 开始递增,每个数据包加 1;IV 为 指令部分 IV 的第 3 至第 12 字节。
                                        • L - 16 字节:实际数据;
                                        • 16 字节:GCM 认证信息
                                      • ChaCha20-Poly1305:Key = MD5(指令部分 Key) + MD5(MD5(指令部分 Key)),IV = count (2 字节) + IV (10 字节)。count 从 0 开始递增,每个数据包加 1;IV 为 指令部分 IV 的第 3 至第 12 字节。
                                        • L - 16 字节:实际数据;
                                        • 16 字节:Poly1305 认证信息

                                      服务器应答

                                      应答头部数据使用 AES-128-CFB 加密,IV 为 MD5(数据加密 IV),Key 为 MD5(数据加密 Key)。实际应答数据视加密设置不同而不同。

                                      1 字节1 字节1 字节1 字节M 字节余下部分
                                      响应认证 V选项 Opt指令 Cmd指令长度 M指令内容实际应答数据

                                      其中:

                                      • 响应认证 V:必须和客户端请求中的响应认证 V 一致;
                                      • 选项 Opt:
                                        • 0x01:服务器端准备重用 TCP 连接(Xray 2.23+ 弃用);
                                      • 指令 Cmd:
                                        • 0x01:动态端口指令
                                      • 实际应答数据:
                                        • 如果请求中的 Opt(S) 开启,则使用标准格式,否则使用基本格式。
                                        • 格式均和请求数据相同。
                                          • 当 Opt(M) 开启时,长度 L 的值 = 真实值 xor Mask。Mask = (ResponseMask.NextByte() << 8) + ResponseMask.NextByte();

                                      动态端口指令

                                      1 字节2 字节16 字节2 字节1 字节1 字节
                                      保留端口 Port用户 IDAlterID用户等级有效时间 T

                                      其中:

                                      • 端口 Port:Big Endian 格式的整型端口号;
                                      • 有效时间 T:分钟数;

                                      客户端在收到动态端口指令时,服务器已开放新的端口用于通信,这时客户端可以将数据发往新的端口。在 T 分钟之后,这个端口将失效,客户端必须重新使用主端口进行通信。

                                      注释

                                      • 为确保向前兼容性,所有保留字段的值必须为 0。
                                      ',37);function I(C,D){const h=a("I18nTip"),i=a("ExternalLinkIcon");return r(),d("div",null,[l(h),o,t("p",null,[e("ID 等价于 "),t("a",p,[e("UUID"),l(i)]),e(",是一个 16 字节长的随机数,它的作用相当于一个令牌(Token)。 一个 ID 形如:de305d54-75b4-431b-adb2-eb6b9e546014,几乎完全随机,可以使用任何的 UUID 生成器来生成,比如"),t("a",x,[e("这个"),l(i)]),e("。")]),u,y,t("ul",null,[t("li",null,[e("MD5: "),t("a",g,[e("MD5 函数"),l(i)]),b]),t("li",null,[e("HMAC: "),t("a",_,[e("HMAC 函数"),l(i)]),M]),t("li",null,[e("Shake: "),t("a",f,[e("SHA3-Shake128 函数"),l(i)]),V])]),k])}const P=s(c,[["render",I],["__file","vmess.html.vue"]]);export{P as default}; +import{_ as s,r as a,o as r,c as d,a as l,b as t,d as e,e as n}from"./app-D7uBbsY3.js";const c={},o=n('

                                      VMess 协议

                                      VMess 是一个加密传输协议,可以作为 Xray 客户端和服务器之间的桥梁。

                                      版本

                                      当前版本号为 1。

                                      依赖

                                      底层协议

                                      VMess 是一个基于 TCP 的协议,所有数据使用 TCP 传输。

                                      用户 ID

                                      ',8),p={href:"https://en.wikipedia.org/wiki/Universally_unique_identifier",target:"_blank",rel:"noopener noreferrer"},x={href:"https://www.uuidgenerator.net/",target:"_blank",rel:"noopener noreferrer"},u=t("p",null,[e("用户 ID 可在"),t("a",{href:"../../config"},"配置文件"),e("中指定。")],-1),y=t("h3",{id:"函数",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#函数"},[t("span",null,"函数")])],-1),g={href:"https://en.wikipedia.org/wiki/MD5",target:"_blank",rel:"noopener noreferrer"},b=t("ul",null,[t("li",null,"输入参数为任意长度的 byte 数组"),t("li",null,"输出为一个 16 byte 的数组")],-1),_={href:"https://en.wikipedia.org/wiki/Hash-based_message_authentication_code",target:"_blank",rel:"noopener noreferrer"},M=t("ul",null,[t("li",null,[e("输入参数为: "),t("ul",null,[t("li",null,"H:散列函数"),t("li",null,"K:密钥,任意长度的 byte 数组"),t("li",null,"M:消息,任意长度的 byte 数组")])])],-1),f={href:"https://en.wikipedia.org/wiki/SHA-3",target:"_blank",rel:"noopener noreferrer"},V=t("ul",null,[t("li",null,"输入参数为任意长度的字符串"),t("li",null,"输出为任意长度的字符串")],-1),k=n('

                                      通讯过程

                                      VMess 是一个无状态协议,即客户端和服务器之间不需要握手即可直接传输数据,每一次数据传输对之前和之后的其它数据传输没有影响。

                                      VMess 的客户端发起一次请求,服务器判断该请求是否来自一个合法的客户端。如验证通过,则转发该请求,并把获得的响应发回给客户端。

                                      VMess 使用非对称格式,即客户端发出的请求和服务器端的响应使用了不同的格式。

                                      客户端请求

                                      16 字节X 字节余下部分
                                      认证信息指令部分数据部分

                                      认证信息

                                      认证信息是一个 16 字节的哈希(hash)值,它的计算方式如下:

                                      • H = MD5
                                      • K = 用户 ID (16 字节)
                                      • M = UTC 时间,精确到秒,取值为当前时间的前后 30 秒随机值(8 字节, Big Endian)
                                      • Hash = HMAC(H, K, M)

                                      指令部分

                                      指令部分经过 AES-128-CFB 加密:

                                      • Key:MD5(用户 ID + []byte('c48619fe-8f02-49e0-b9e9-edf763e17e21'))
                                      • IV:MD5(X + X + X + X),X = []byte(认证信息生成的时间) (8 字节, Big Endian)
                                      1 字节16 字节16 字节1 字节1 字节4 位4 位1 字节1 字节2 字节1 字节N 字节P 字节4 字节
                                      版本号 Ver数据加密 IV数据加密 Key响应认证 V选项 Opt余量 P加密方式 Sec保留指令 Cmd端口 Port地址类型 T地址 A随机值校验 F

                                      选项 Opt 细节:(当某一位为 1 时,表示该选项启用)

                                      01234567
                                      XXXXXMRS

                                      其中:

                                      • 版本号 Ver:始终为 1;
                                      • 数据加密 IV:随机值;
                                      • 数据加密 Key:随机值;
                                      • 响应认证 V:随机值;
                                      • 选项 Opt:
                                        • S (0x01):标准格式的数据流(建议开启);
                                        • R (0x02):客户端期待重用 TCP 连接(Xray 2.23+ 弃用);
                                          • 只有当 S 开启时,这一项才有效;
                                        • M (0x04):开启元数据混淆(建议开启);
                                          • 只有当 S 开启时,这一项才有效;
                                          • 当其项开启时,客户端和服务器端需要分别构造两个 Shake 实例,分别为 RequestMask = Shake(请求数据 IV), ResponseMask = Shake(响应数据 IV)。
                                        • X:保留
                                      • 余量 P:在校验值之前加入 P 字节的随机值;
                                      • 加密方式:指定数据部分的加密方式,可选的值有:
                                        • 0x00:AES-128-CFB;
                                        • 0x01:不加密;
                                        • 0x02:AES-128-GCM;
                                        • 0x03:ChaCha20-Poly1305;
                                      • 指令 Cmd:
                                        • 0x01:TCP 数据;
                                        • 0x02:UDP 数据;
                                      • 端口 Port:Big Endian 格式的整型端口号;
                                      • 地址类型 T:
                                        • 0x01:IPv4
                                        • 0x02:域名
                                        • 0x03:IPv6
                                      • 地址 A:
                                        • 当 T = 0x01 时,A 为 4 字节 IPv4 地址;
                                        • 当 T = 0x02 时,A 为 1 字节长度(L) + L 字节域名;
                                        • 当 T = 0x03 时,A 为 16 字节 IPv6 地址;
                                      • 校验 F:指令部分除 F 外所有内容的 FNV1a hash;

                                      数据部分

                                      当 Opt(S) 开启时,数据部分使用此格式。实际的请求数据被分割为若干个小块,每个小块的格式如下。服务器校验完所有的小块之后,再按基本格式的方式进行转发。

                                      2 字节L 字节
                                      长度 L数据包

                                      其中:

                                      • 长度 L:Big Endian 格式的整型,最大值为 2^14;
                                        • 当 Opt(M) 开启时,L 的值 = 真实值 xor Mask。Mask = (RequestMask.NextByte() << 8) + RequestMask.NextByte();
                                      • 数据包:由指定的加密方式加密过的数据包;

                                      在传输结束之前,数据包中必须有实际数据,即除了长度和认证数据之外的数据。当传输结束时,客户端必须发送一个空的数据包,即 L = 0(不加密) 或认证数据长度(有加密),来表示传输结束。

                                      按加密方式不同,数据包的格式如下:

                                      • 不加密:
                                        • L 字节:实际数据;
                                      • AES-128-CFB:整个数据部分使用 AES-128-CFB 加密
                                        • 4 字节:实际数据的 FNV1a hash;
                                        • L - 4 字节:实际数据;
                                      • AES-128-GCM:Key 为指令部分的 Key,IV = count (2 字节) + IV (10 字节)。count 从 0 开始递增,每个数据包加 1;IV 为 指令部分 IV 的第 3 至第 12 字节。
                                        • L - 16 字节:实际数据;
                                        • 16 字节:GCM 认证信息
                                      • ChaCha20-Poly1305:Key = MD5(指令部分 Key) + MD5(MD5(指令部分 Key)),IV = count (2 字节) + IV (10 字节)。count 从 0 开始递增,每个数据包加 1;IV 为 指令部分 IV 的第 3 至第 12 字节。
                                        • L - 16 字节:实际数据;
                                        • 16 字节:Poly1305 认证信息

                                      服务器应答

                                      应答头部数据使用 AES-128-CFB 加密,IV 为 MD5(数据加密 IV),Key 为 MD5(数据加密 Key)。实际应答数据视加密设置不同而不同。

                                      1 字节1 字节1 字节1 字节M 字节余下部分
                                      响应认证 V选项 Opt指令 Cmd指令长度 M指令内容实际应答数据

                                      其中:

                                      • 响应认证 V:必须和客户端请求中的响应认证 V 一致;
                                      • 选项 Opt:
                                        • 0x01:服务器端准备重用 TCP 连接(Xray 2.23+ 弃用);
                                      • 指令 Cmd:
                                        • 0x01:动态端口指令
                                      • 实际应答数据:
                                        • 如果请求中的 Opt(S) 开启,则使用标准格式,否则使用基本格式。
                                        • 格式均和请求数据相同。
                                          • 当 Opt(M) 开启时,长度 L 的值 = 真实值 xor Mask。Mask = (ResponseMask.NextByte() << 8) + ResponseMask.NextByte();

                                      动态端口指令

                                      1 字节2 字节16 字节2 字节1 字节1 字节
                                      保留端口 Port用户 IDAlterID用户等级有效时间 T

                                      其中:

                                      • 端口 Port:Big Endian 格式的整型端口号;
                                      • 有效时间 T:分钟数;

                                      客户端在收到动态端口指令时,服务器已开放新的端口用于通信,这时客户端可以将数据发往新的端口。在 T 分钟之后,这个端口将失效,客户端必须重新使用主端口进行通信。

                                      注释

                                      • 为确保向前兼容性,所有保留字段的值必须为 0。
                                      ',37);function I(C,D){const h=a("I18nTip"),i=a("ExternalLinkIcon");return r(),d("div",null,[l(h),o,t("p",null,[e("ID 等价于 "),t("a",p,[e("UUID"),l(i)]),e(",是一个 16 字节长的随机数,它的作用相当于一个令牌(Token)。 一个 ID 形如:de305d54-75b4-431b-adb2-eb6b9e546014,几乎完全随机,可以使用任何的 UUID 生成器来生成,比如"),t("a",x,[e("这个"),l(i)]),e("。")]),u,y,t("ul",null,[t("li",null,[e("MD5: "),t("a",g,[e("MD5 函数"),l(i)]),b]),t("li",null,[e("HMAC: "),t("a",_,[e("HMAC 函数"),l(i)]),M]),t("li",null,[e("Shake: "),t("a",f,[e("SHA3-Shake128 函数"),l(i)]),V])]),k])}const P=s(c,[["render",I],["__file","vmess.html.vue"]]);export{P as default}; diff --git a/assets/vmess.html-Bgid-6Wa.js b/assets/vmess.html-DUx4NlE2.js similarity index 99% rename from assets/vmess.html-Bgid-6Wa.js rename to assets/vmess.html-DUx4NlE2.js index fe70707e06..a143cb4d83 100644 --- a/assets/vmess.html-Bgid-6Wa.js +++ b/assets/vmess.html-DUx4NlE2.js @@ -1,4 +1,4 @@ -import{_ as l,r as a,o as i,c as r,a as e,b as s,w as t,d as n,e as p}from"./app-DBM4OJyw.js";const d={},q=s("h1",{id:"vmess",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#vmess"},[s("span",null,"VMess")])],-1),v=p(`

                                      Предупреждение

                                      VMess полагается на системное время. Убедитесь, что системное время UTC, используемое Xray, находится в пределах 120 секунд от фактического времени, независимо от часового пояса. В системах Linux вы можете установить службу ntp для автоматической синхронизации системного времени.

                                      OutboundConfigurationObject

                                      {
                                      +import{_ as l,r as a,o as i,c as r,a as e,b as s,w as t,d as n,e as p}from"./app-D7uBbsY3.js";const d={},q=s("h1",{id:"vmess",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#vmess"},[s("span",null,"VMess")])],-1),v=p(`

                                      Предупреждение

                                      VMess полагается на системное время. Убедитесь, что системное время UTC, используемое Xray, находится в пределах 120 секунд от фактического времени, независимо от часового пояса. В системах Linux вы можете установить службу ntp для автоматической синхронизации системного времени.

                                      OutboundConfigurationObject

                                      {
                                         "vnext": [
                                           {
                                             "address": "127.0.0.1",
                                      diff --git a/assets/vmess.html-uLwk-fUW.js b/assets/vmess.html-RimzC-nX.js
                                      similarity index 99%
                                      rename from assets/vmess.html-uLwk-fUW.js
                                      rename to assets/vmess.html-RimzC-nX.js
                                      index ff904e72e4..632b507cf0 100644
                                      --- a/assets/vmess.html-uLwk-fUW.js
                                      +++ b/assets/vmess.html-RimzC-nX.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as i,r as t,o as u,c as d,a as s,b as e,w as o,d as n,e as c}from"./app-DBM4OJyw.js";const r={},b=e("h1",{id:"vmess",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#vmess"},[e("span",null,"VMess")])],-1),v=c(`

                                      警告

                                      VMess 依赖于系统时间,请确保使用 Xray 的系统 UTC 时间误差在 120 秒之内,时区无关。在 Linux 系统中可以安装ntp服务来自动同步系统时间。

                                      InboundConfigurationObject

                                      {
                                      +import{_ as i,r as t,o as u,c as d,a as s,b as e,w as o,d as n,e as c}from"./app-D7uBbsY3.js";const r={},b=e("h1",{id:"vmess",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#vmess"},[e("span",null,"VMess")])],-1),v=c(`

                                      警告

                                      VMess 依赖于系统时间,请确保使用 Xray 的系统 UTC 时间误差在 120 秒之内,时区无关。在 Linux 系统中可以安装ntp服务来自动同步系统时间。

                                      InboundConfigurationObject

                                      {
                                         "clients": [
                                           {
                                             "id": "5783a3e7-e373-51cd-8642-c83782b807c5",
                                      diff --git a/assets/warp.html-DjzUs3nN.js b/assets/warp.html-Ck2P9Tg0.js
                                      similarity index 99%
                                      rename from assets/warp.html-DjzUs3nN.js
                                      rename to assets/warp.html-Ck2P9Tg0.js
                                      index fb123cda96..58ce3ef9bc 100644
                                      --- a/assets/warp.html-DjzUs3nN.js
                                      +++ b/assets/warp.html-Ck2P9Tg0.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as l,r as p,o as c,c as u,a,b as n,d as s,e}from"./app-DBM4OJyw.js";const i={},r=n("h1",{id:"повышение-безопасности-проксирования-с-помощью-cloudflare-warp",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#повышение-безопасности-проксирования-с-помощью-cloudflare-warp"},[n("span",null,"Повышение безопасности проксирования с помощью Cloudflare Warp")])],-1),d=n("p",null,"В Xray (1.6.5+) добавлен исходящий WireGuard. Хотя это увеличивает размер ядра из-за дополнительных кода и зависимостей, мы считаем, что это важная новая функция по трем причинам:",-1),k={href:"https://github.com/net4people/bbs/issues/129#issuecomment-1308102504",target:"_blank",rel:"noopener noreferrer"},v=n("br",null,null,-1),q=n("br",null,null,-1),m=n("br",null,null,-1),b=n("li",null,[s("Как известно, большинство VPN-провайдеров ведут журналы посещенных пользователями доменов, а некоторые даже проверяют и блокируют определенный трафик."),n("br"),s(" Один из способов защиты конфиденциальности пользователей - использовать цепочку прокси-серверов на клиенте."),n("br"),s(" Warp использует легкий VPN-протокол WireGuard, который добавляет дополнительный уровень шифрования."),n("br"),s(" Для VPN-провайдера весь трафик пользователя будет направляться на Warp, что обеспечивает максимальную защиту конфиденциальности.")],-1),g=n("li",null,[s("Простота использования."),n("br"),s(" Для настройки разделения трафика, WireGuard-туннеля и цепочки прокси-серверов достаточно одного ядра.")],-1),y=e('

                                      Создание аккаунта Warp

                                      Спасибо Cloudflare за содействие свободному интернету! Теперь вы можете бесплатно пользоваться услугами Warp. При подключении автоматически выбирается ближайший сервер.

                                      Метод 1:

                                      ',3),h={href:"https://github.com/ViRb3/wgcf/releases",target:"_blank",rel:"noopener noreferrer"},_=n("li",null,[s("Запустите "),n("code",null,"wgcf register"),s(", чтобы создать файл "),n("code",null,"wgcf-account.toml"),s(".")],-1),f=n("li",null,[s("Запустите "),n("code",null,"wgcf generate"),s(", чтобы создать файл "),n("code",null,"wgcf-profile.conf"),s(". Скопируйте его содержимое:")],-1),w=e(`
                                      [Interface]
                                      +import{_ as l,r as p,o as c,c as u,a,b as n,d as s,e}from"./app-D7uBbsY3.js";const i={},r=n("h1",{id:"повышение-безопасности-проксирования-с-помощью-cloudflare-warp",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#повышение-безопасности-проксирования-с-помощью-cloudflare-warp"},[n("span",null,"Повышение безопасности проксирования с помощью Cloudflare Warp")])],-1),d=n("p",null,"В Xray (1.6.5+) добавлен исходящий WireGuard. Хотя это увеличивает размер ядра из-за дополнительных кода и зависимостей, мы считаем, что это важная новая функция по трем причинам:",-1),k={href:"https://github.com/net4people/bbs/issues/129#issuecomment-1308102504",target:"_blank",rel:"noopener noreferrer"},v=n("br",null,null,-1),q=n("br",null,null,-1),m=n("br",null,null,-1),b=n("li",null,[s("Как известно, большинство VPN-провайдеров ведут журналы посещенных пользователями доменов, а некоторые даже проверяют и блокируют определенный трафик."),n("br"),s(" Один из способов защиты конфиденциальности пользователей - использовать цепочку прокси-серверов на клиенте."),n("br"),s(" Warp использует легкий VPN-протокол WireGuard, который добавляет дополнительный уровень шифрования."),n("br"),s(" Для VPN-провайдера весь трафик пользователя будет направляться на Warp, что обеспечивает максимальную защиту конфиденциальности.")],-1),g=n("li",null,[s("Простота использования."),n("br"),s(" Для настройки разделения трафика, WireGuard-туннеля и цепочки прокси-серверов достаточно одного ядра.")],-1),y=e('

                                      Создание аккаунта Warp

                                      Спасибо Cloudflare за содействие свободному интернету! Теперь вы можете бесплатно пользоваться услугами Warp. При подключении автоматически выбирается ближайший сервер.

                                      Метод 1:

                                      ',3),h={href:"https://github.com/ViRb3/wgcf/releases",target:"_blank",rel:"noopener noreferrer"},_=n("li",null,[s("Запустите "),n("code",null,"wgcf register"),s(", чтобы создать файл "),n("code",null,"wgcf-account.toml"),s(".")],-1),f=n("li",null,[s("Запустите "),n("code",null,"wgcf generate"),s(", чтобы создать файл "),n("code",null,"wgcf-profile.conf"),s(". Скопируйте его содержимое:")],-1),w=e(`
                                      [Interface]
                                       PrivateKey = Мой закрытый ключ
                                       Address = 172.16.0.2/32
                                       Address = 2606:4700:110:8949:fed8:2642:a640:c8e1/128
                                      diff --git a/assets/warp.html-BFiya00c.js b/assets/warp.html-CqXxUSeb.js
                                      similarity index 99%
                                      rename from assets/warp.html-BFiya00c.js
                                      rename to assets/warp.html-CqXxUSeb.js
                                      index 3d6ff3d409..98bc1339c0 100644
                                      --- a/assets/warp.html-BFiya00c.js
                                      +++ b/assets/warp.html-CqXxUSeb.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as p,r as t,o as i,c as l,a,b as n,d as s,e as c}from"./app-DBM4OJyw.js";const r={},u=n("h1",{id:"enhancing-proxy-security-with-cloudflare-warp",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#enhancing-proxy-security-with-cloudflare-warp"},[n("span",null,"Enhancing Proxy Security with Cloudflare Warp")])],-1),d=n("p",null,"Xray (1.6.5+) has added outbound WireGuard support. Although the added code and dependencies will increase the core size, we believe that this is a necessary new feature for three reasons:",-1),v={href:"https://github.com/net4people/bbs/issues/129#issuecomment-1308102504",target:"_blank",rel:"noopener noreferrer"},k=n("li",null,"As we all know, most airports will log the domain names visited by users, and some airports will even audit and block some user traffic. One way to protect user privacy is to use chain proxies on the client side. The WireGuard lightweight VPN protocol used by Warp adds an extra layer of encryption within the proxy layer. For airports, the target of all user traffic is Warp, thereby maximizing privacy protection.",-1),m=n("li",null,"It is easy to use, and only one core is needed to complete the split, Wireguard Tun, and chain proxy settings.",-1),b=n("h2",{id:"applying-for-a-warp-account",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#applying-for-a-warp-account"},[n("span",null,"Applying for a Warp Account")])],-1),q=n("li",null,"Thank you Cloudflare for promoting a free internet. Now you can use the Warp service for free, and the nearest server will be automatically selected based on the exit.",-1),h={href:"https://github.com/ViRb3/wgcf/releases",target:"_blank",rel:"noopener noreferrer"},g=n("li",null,[s("Run "),n("code",null,"wgcf register"),s(" to generate "),n("code",null,"wgcf-account.toml"),s(".")],-1),y=n("li",null,[s("Run "),n("code",null,"wgcf generate"),s(" to generate "),n("code",null,"wgcf-profile.conf"),s(". Copy the following content:")],-1),f=c(`
                                      [Interface]
                                      +import{_ as p,r as t,o as i,c as l,a,b as n,d as s,e as c}from"./app-D7uBbsY3.js";const r={},u=n("h1",{id:"enhancing-proxy-security-with-cloudflare-warp",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#enhancing-proxy-security-with-cloudflare-warp"},[n("span",null,"Enhancing Proxy Security with Cloudflare Warp")])],-1),d=n("p",null,"Xray (1.6.5+) has added outbound WireGuard support. Although the added code and dependencies will increase the core size, we believe that this is a necessary new feature for three reasons:",-1),v={href:"https://github.com/net4people/bbs/issues/129#issuecomment-1308102504",target:"_blank",rel:"noopener noreferrer"},k=n("li",null,"As we all know, most airports will log the domain names visited by users, and some airports will even audit and block some user traffic. One way to protect user privacy is to use chain proxies on the client side. The WireGuard lightweight VPN protocol used by Warp adds an extra layer of encryption within the proxy layer. For airports, the target of all user traffic is Warp, thereby maximizing privacy protection.",-1),m=n("li",null,"It is easy to use, and only one core is needed to complete the split, Wireguard Tun, and chain proxy settings.",-1),b=n("h2",{id:"applying-for-a-warp-account",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#applying-for-a-warp-account"},[n("span",null,"Applying for a Warp Account")])],-1),q=n("li",null,"Thank you Cloudflare for promoting a free internet. Now you can use the Warp service for free, and the nearest server will be automatically selected based on the exit.",-1),h={href:"https://github.com/ViRb3/wgcf/releases",target:"_blank",rel:"noopener noreferrer"},g=n("li",null,[s("Run "),n("code",null,"wgcf register"),s(" to generate "),n("code",null,"wgcf-account.toml"),s(".")],-1),y=n("li",null,[s("Run "),n("code",null,"wgcf generate"),s(" to generate "),n("code",null,"wgcf-profile.conf"),s(". Copy the following content:")],-1),f=c(`
                                      [Interface]
                                       PrivateKey = my private key
                                       Address = 172.16.0.2/32
                                       Address = 2606:4700:110:8949:fed8:2642:a640:c8e1/128
                                      diff --git a/assets/warp.html-B33XWZbi.js b/assets/warp.html-mob0uukM.js
                                      similarity index 99%
                                      rename from assets/warp.html-B33XWZbi.js
                                      rename to assets/warp.html-mob0uukM.js
                                      index 225ce95ecb..1424d22401 100644
                                      --- a/assets/warp.html-B33XWZbi.js
                                      +++ b/assets/warp.html-mob0uukM.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as l,r as p,o as c,c as u,a,b as n,d as s,e}from"./app-DBM4OJyw.js";const i={},r=n("h1",{id:"通过-cloudflare-warp-增强代理安全性",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#通过-cloudflare-warp-增强代理安全性"},[n("span",null,"通过 Cloudflare Warp 增强代理安全性")])],-1),d=n("p",null,"Xray(1.6.5+)新加入了 WireGuard 出站,虽然增加的代码和依赖会增大 core 体积,但是我们认为这是一个很有必要的新功能,原因有三:",-1),k={href:"https://github.com/net4people/bbs/issues/129#issuecomment-1308102504",target:"_blank",rel:"noopener noreferrer"},v=n("li",null,"众所周知,大部分机场会记录用户访问域名的日志,某些机场还会审计和阻断一些用户流量。保护用户私密性的一个方法,就是在客户端使用链式代理。 Warp 使用的 WireGuard 轻量级 VPN 协议会在代理层内增加一层加密。对于机场而言,用户所有流量的目标都是 Warp,从而最大程度保护自己的隐私。",-1),q=n("li",null,"方便使用,只需要一个 core 即可完成分流,Wireguard Tun,链式代理的设置。",-1),m=e('

                                      申请 Warp 账户

                                      感谢 Cloudflare 推动自由的互联网,现在你可以免费使用 Warp 服务,连接的时候会根据出口自动选择最近的服务器

                                      方法 1:

                                      ',3),b={href:"https://github.com/ViRb3/wgcf/releases",target:"_blank",rel:"noopener noreferrer"},g=n("li",null,[s("运行 "),n("code",null,"wgcf register"),s(" 生成 "),n("code",null,"wgcf-account.toml")],-1),y=n("li",null,[s("运行 "),n("code",null,"wgcf generate"),s(" 生成 "),n("code",null,"wgcf-profile.conf"),s(" 拷贝内容如下:")],-1),h=e(`
                                      [Interface]
                                      +import{_ as l,r as p,o as c,c as u,a,b as n,d as s,e}from"./app-D7uBbsY3.js";const i={},r=n("h1",{id:"通过-cloudflare-warp-增强代理安全性",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#通过-cloudflare-warp-增强代理安全性"},[n("span",null,"通过 Cloudflare Warp 增强代理安全性")])],-1),d=n("p",null,"Xray(1.6.5+)新加入了 WireGuard 出站,虽然增加的代码和依赖会增大 core 体积,但是我们认为这是一个很有必要的新功能,原因有三:",-1),k={href:"https://github.com/net4people/bbs/issues/129#issuecomment-1308102504",target:"_blank",rel:"noopener noreferrer"},v=n("li",null,"众所周知,大部分机场会记录用户访问域名的日志,某些机场还会审计和阻断一些用户流量。保护用户私密性的一个方法,就是在客户端使用链式代理。 Warp 使用的 WireGuard 轻量级 VPN 协议会在代理层内增加一层加密。对于机场而言,用户所有流量的目标都是 Warp,从而最大程度保护自己的隐私。",-1),q=n("li",null,"方便使用,只需要一个 core 即可完成分流,Wireguard Tun,链式代理的设置。",-1),m=e('

                                      申请 Warp 账户

                                      感谢 Cloudflare 推动自由的互联网,现在你可以免费使用 Warp 服务,连接的时候会根据出口自动选择最近的服务器

                                      方法 1:

                                      ',3),b={href:"https://github.com/ViRb3/wgcf/releases",target:"_blank",rel:"noopener noreferrer"},g=n("li",null,[s("运行 "),n("code",null,"wgcf register"),s(" 生成 "),n("code",null,"wgcf-account.toml")],-1),y=n("li",null,[s("运行 "),n("code",null,"wgcf generate"),s(" 生成 "),n("code",null,"wgcf-profile.conf"),s(" 拷贝内容如下:")],-1),h=e(`
                                      [Interface]
                                       PrivateKey = 我的私钥
                                       Address = 172.16.0.2/32
                                       Address = 2606:4700:110:8949:fed8:2642:a640:c8e1/128
                                      diff --git a/assets/websocket.html-BZsgtVoW.js b/assets/websocket.html-2zGXYi2c.js
                                      similarity index 98%
                                      rename from assets/websocket.html-BZsgtVoW.js
                                      rename to assets/websocket.html-2zGXYi2c.js
                                      index b67abfb12c..36a39d4632 100644
                                      --- a/assets/websocket.html-BZsgtVoW.js
                                      +++ b/assets/websocket.html-2zGXYi2c.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as d,r as t,o as p,c as i,a as s,b as o,d as e,w as l,e as n}from"./app-DBM4OJyw.js";const h={},u=n(`

                                      WebSocket

                                      Uses standard WebSocket for data transmission.

                                      WebSocket connections can be proxied by other web servers (like NGINX) or by VLESS fallback paths.

                                      Tip

                                      WebSocket inbounds will parse the X-Forwarded-For header received, overriding the source address with a higher priority than the source address got from PROXY protocol.

                                      WebSocketObject

                                      WebSocketObject corresponds to the wsSettings property of the transport configs.

                                      {
                                      +import{_ as d,r as t,o as p,c as i,a as s,b as o,d as e,w as l,e as n}from"./app-D7uBbsY3.js";const h={},u=n(`

                                      WebSocket

                                      Uses standard WebSocket for data transmission.

                                      WebSocket connections can be proxied by other web servers (like NGINX) or by VLESS fallback paths.

                                      Tip

                                      WebSocket inbounds will parse the X-Forwarded-For header received, overriding the source address with a higher priority than the source address got from PROXY protocol.

                                      WebSocketObject

                                      WebSocketObject corresponds to the wsSettings property of the transport configs.

                                      {
                                         "acceptProxyProtocol": false,
                                         "path": "/",
                                         "host": "xray.com",
                                      diff --git a/assets/websocket.html-MgdanL8C.js b/assets/websocket.html-DvhOz-O4.js
                                      similarity index 98%
                                      rename from assets/websocket.html-MgdanL8C.js
                                      rename to assets/websocket.html-DvhOz-O4.js
                                      index 251a5c8e5e..00d7bde2b6 100644
                                      --- a/assets/websocket.html-MgdanL8C.js
                                      +++ b/assets/websocket.html-DvhOz-O4.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as r,r as s,o as l,c as d,a as t,b as o,d as e,w as i,e as a}from"./app-DBM4OJyw.js";const u={},k=a(`

                                      WebSocket

                                      使用标准的 WebSocket 来传输数据。

                                      WebSocket 连接可以被其它 HTTP 服务器(如 Nginx)分流,也可以被 VLESS fallbacks path 分流。

                                      提示

                                      Websocket 会识别 HTTP 请求的 X-Forwarded-For 头来覆写流量的源地址,优先级高于 PROXY protocol。

                                      WebSocketObject

                                      WebSocketObject 对应传输配置的 wsSettings 项。

                                      {
                                      +import{_ as r,r as s,o as l,c as d,a as t,b as o,d as e,w as i,e as a}from"./app-D7uBbsY3.js";const u={},k=a(`

                                      WebSocket

                                      使用标准的 WebSocket 来传输数据。

                                      WebSocket 连接可以被其它 HTTP 服务器(如 Nginx)分流,也可以被 VLESS fallbacks path 分流。

                                      提示

                                      Websocket 会识别 HTTP 请求的 X-Forwarded-For 头来覆写流量的源地址,优先级高于 PROXY protocol。

                                      WebSocketObject

                                      WebSocketObject 对应传输配置的 wsSettings 项。

                                      {
                                         "acceptProxyProtocol": false,
                                         "path": "/",
                                         "host": "xray.com",
                                      diff --git a/assets/websocket.html-D2_1H1Lb.js b/assets/websocket.html-XpyUndOJ.js
                                      similarity index 98%
                                      rename from assets/websocket.html-D2_1H1Lb.js
                                      rename to assets/websocket.html-XpyUndOJ.js
                                      index 00c5d484b9..2132bcb06b 100644
                                      --- a/assets/websocket.html-D2_1H1Lb.js
                                      +++ b/assets/websocket.html-XpyUndOJ.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as r,r as s,o as l,c as d,a as t,b as o,d as e,w as i,e as n}from"./app-DBM4OJyw.js";const u={},k=n(`

                                      WebSocket

                                      Использует стандартный WebSocket для передачи данных.

                                      Подключение WebSocket может быть проксировано другими HTTP-серверами (например, Nginx) и VLESS fallbacks path.

                                      Подсказка

                                      WebSocket распознает заголовок X-Forwarded-For в HTTP-запросе для перезаписи исходного адреса трафика, приоритет выше, чем у PROXY protocol.

                                      WebSocketObject

                                      WebSocketObject соответствует элементу wsSettings в конфигурации транспорта.

                                      {
                                      +import{_ as r,r as s,o as l,c as d,a as t,b as o,d as e,w as i,e as n}from"./app-D7uBbsY3.js";const u={},k=n(`

                                      WebSocket

                                      Использует стандартный WebSocket для передачи данных.

                                      Подключение WebSocket может быть проксировано другими HTTP-серверами (например, Nginx) и VLESS fallbacks path.

                                      Подсказка

                                      WebSocket распознает заголовок X-Forwarded-For в HTTP-запросе для перезаписи исходного адреса трафика, приоритет выше, чем у PROXY protocol.

                                      WebSocketObject

                                      WebSocketObject соответствует элементу wsSettings в конфигурации транспорта.

                                      {
                                         "acceptProxyProtocol": false,
                                         "path": "/",
                                         "host": "xray.com",
                                      diff --git a/assets/wireguard.html-AcuxmEqH.js b/assets/wireguard.html-B6z9zn0C.js
                                      similarity index 99%
                                      rename from assets/wireguard.html-AcuxmEqH.js
                                      rename to assets/wireguard.html-B6z9zn0C.js
                                      index 28949cc2d8..da6d2d4162 100644
                                      --- a/assets/wireguard.html-AcuxmEqH.js
                                      +++ b/assets/wireguard.html-B6z9zn0C.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as c,r as s,o as l,c as u,a as n,b as t,d as e,w as p,e as o}from"./app-DBM4OJyw.js";const d={},v=o(`

                                      Wireguard

                                      Wireguard is a standard implementation of the Wireguard protocol.

                                      Danger

                                      The Wireguard protocol is not specifically designed for circumvention purposes. If used as the outer layer for circumvention, its characteristics may lead to server blocking.

                                      OutboundConfigurationObject

                                      {
                                      +import{_ as c,r as s,o as l,c as u,a as n,b as t,d as e,w as p,e as o}from"./app-D7uBbsY3.js";const d={},v=o(`

                                      Wireguard

                                      Wireguard is a standard implementation of the Wireguard protocol.

                                      Danger

                                      The Wireguard protocol is not specifically designed for circumvention purposes. If used as the outer layer for circumvention, its characteristics may lead to server blocking.

                                      OutboundConfigurationObject

                                      {
                                         "secretKey": "PRIVATE_KEY",
                                         "address": [
                                           // optional, default ["10.0.0.1", "fd59:7153:2388:b5fd:0000:0000:0000:0001"]
                                      diff --git a/assets/wireguard.html-BRdIxC_E.js b/assets/wireguard.html-BSlNcaJF.js
                                      similarity index 99%
                                      rename from assets/wireguard.html-BRdIxC_E.js
                                      rename to assets/wireguard.html-BSlNcaJF.js
                                      index 390dcd26b5..9ce2f761e8 100644
                                      --- a/assets/wireguard.html-BRdIxC_E.js
                                      +++ b/assets/wireguard.html-BSlNcaJF.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as u,r as a,o as r,c as i,a as e,b as s,d as n,w as l,e as o}from"./app-DBM4OJyw.js";const d={},v=o(`

                                      Wireguard

                                      标准 Wireguard 协议实现。

                                      警告

                                      Wireguard 协议并非专门为翻墙而设计,若在最外层过墙,存在特征可能导致服务器被封锁

                                      OutboundConfigurationObject

                                      {
                                      +import{_ as u,r as a,o as r,c as i,a as e,b as s,d as n,w as l,e as o}from"./app-D7uBbsY3.js";const d={},v=o(`

                                      Wireguard

                                      标准 Wireguard 协议实现。

                                      警告

                                      Wireguard 协议并非专门为翻墙而设计,若在最外层过墙,存在特征可能导致服务器被封锁

                                      OutboundConfigurationObject

                                      {
                                         "secretKey": "PRIVATE_KEY",
                                         "address": [
                                           // optional, default ["10.0.0.1", "fd59:7153:2388:b5fd:0000:0000:0000:0001"]
                                      diff --git a/assets/wireguard.html--TSe5kNc.js b/assets/wireguard.html-C7TRB15X.js
                                      similarity index 97%
                                      rename from assets/wireguard.html--TSe5kNc.js
                                      rename to assets/wireguard.html-C7TRB15X.js
                                      index f1f4d5e830..6c3c55d3e8 100644
                                      --- a/assets/wireguard.html--TSe5kNc.js
                                      +++ b/assets/wireguard.html-C7TRB15X.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as e,r as s,o as a,c as t,a as o,e as i}from"./app-DBM4OJyw.js";const p={},c=i(`

                                      Wireguard

                                      User-space implementation of the Wireguard protocol.

                                      Danger

                                      The Wireguard protocol is not specifically designed for circumvention purposes. If used as the outer layer for circumvention, its characteristics may lead to server blocking.

                                      InboundConfigurationObject

                                      {
                                      +import{_ as e,r as s,o as a,c as t,a as o,e as i}from"./app-D7uBbsY3.js";const p={},c=i(`

                                      Wireguard

                                      User-space implementation of the Wireguard protocol.

                                      Danger

                                      The Wireguard protocol is not specifically designed for circumvention purposes. If used as the outer layer for circumvention, its characteristics may lead to server blocking.

                                      InboundConfigurationObject

                                      {
                                         "secretKey": "PRIVATE_KEY",
                                         "peers": [
                                           {
                                      diff --git a/assets/wireguard.html-D8U2MJad.js b/assets/wireguard.html-CAQPxeg-.js
                                      similarity index 97%
                                      rename from assets/wireguard.html-D8U2MJad.js
                                      rename to assets/wireguard.html-CAQPxeg-.js
                                      index e62e74d708..152cba4e15 100644
                                      --- a/assets/wireguard.html-D8U2MJad.js
                                      +++ b/assets/wireguard.html-CAQPxeg-.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as e,r as s,o as a,c as t,a as o,e as i}from"./app-DBM4OJyw.js";const p={},c=i(`

                                      Wireguard

                                      User-space implementation of the Wireguard protocol.

                                      Предупреждение

                                      The Wireguard protocol is not specifically designed for circumvention purposes. If used as the outer layer for circumvention, its characteristics may lead to server blocking.

                                      InboundConfigurationObject

                                      {
                                      +import{_ as e,r as s,o as a,c as t,a as o,e as i}from"./app-D7uBbsY3.js";const p={},c=i(`

                                      Wireguard

                                      User-space implementation of the Wireguard protocol.

                                      Предупреждение

                                      The Wireguard protocol is not specifically designed for circumvention purposes. If used as the outer layer for circumvention, its characteristics may lead to server blocking.

                                      InboundConfigurationObject

                                      {
                                         "secretKey": "PRIVATE_KEY",
                                         "peers": [
                                           {
                                      diff --git a/assets/wireguard.html-C7zjxZ_o.js b/assets/wireguard.html-CTyw04SG.js
                                      similarity index 97%
                                      rename from assets/wireguard.html-C7zjxZ_o.js
                                      rename to assets/wireguard.html-CTyw04SG.js
                                      index 862d8bcb12..de6756986c 100644
                                      --- a/assets/wireguard.html-C7zjxZ_o.js
                                      +++ b/assets/wireguard.html-CTyw04SG.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as s,r as a,o as e,c as t,a as o,e as p}from"./app-DBM4OJyw.js";const i={},c=p(`

                                      Wireguard

                                      User-space Wireguard 协议实现。

                                      警告

                                      Wireguard 协议并非专门为翻墙而设计,若在最外层过墙,存在特征可能导致服务器被封锁

                                      InboundConfigurationObject

                                      {
                                      +import{_ as s,r as a,o as e,c as t,a as o,e as p}from"./app-D7uBbsY3.js";const i={},c=p(`

                                      Wireguard

                                      User-space Wireguard 协议实现。

                                      警告

                                      Wireguard 协议并非专门为翻墙而设计,若在最外层过墙,存在特征可能导致服务器被封锁

                                      InboundConfigurationObject

                                      {
                                         "secretKey": "PRIVATE_KEY",
                                         "peers": [
                                           {
                                      diff --git a/assets/wireguard.html-Da2wnVY_.js b/assets/wireguard.html-CtnQlY0W.js
                                      similarity index 99%
                                      rename from assets/wireguard.html-Da2wnVY_.js
                                      rename to assets/wireguard.html-CtnQlY0W.js
                                      index edfda53820..e354dc0297 100644
                                      --- a/assets/wireguard.html-Da2wnVY_.js
                                      +++ b/assets/wireguard.html-CtnQlY0W.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as r,r as a,o as u,c as i,a as e,b as s,d as n,w as l,e as o}from"./app-DBM4OJyw.js";const d={},v=o(`

                                      WireGuard

                                      Стандартная реализация протокола WireGuard.

                                      Предупреждение

                                      Протокол WireGuard не предназначен для обхода блокировок, и его использование может привести к блокировке сервера из-за наличия характерных признаков.

                                      OutboundConfigurationObject

                                      {
                                      +import{_ as r,r as a,o as u,c as i,a as e,b as s,d as n,w as l,e as o}from"./app-D7uBbsY3.js";const d={},v=o(`

                                      WireGuard

                                      Стандартная реализация протокола WireGuard.

                                      Предупреждение

                                      Протокол WireGuard не предназначен для обхода блокировок, и его использование может привести к блокировке сервера из-за наличия характерных признаков.

                                      OutboundConfigurationObject

                                      {
                                         "secretKey": "PRIVATE_KEY",
                                         "address": [
                                           // необязательно, по умолчанию ["10.0.0.1", "fd59:7153:2388:b5fd:0000:0000:0000:0001"]
                                      diff --git a/assets/work.html-SMvM6VpF.js b/assets/work.html-BzVygHoH.js
                                      similarity index 98%
                                      rename from assets/work.html-SMvM6VpF.js
                                      rename to assets/work.html-BzVygHoH.js
                                      index 30ec35b613..0ef0f9d02f 100644
                                      --- a/assets/work.html-SMvM6VpF.js
                                      +++ b/assets/work.html-BzVygHoH.js
                                      @@ -1 +1 @@
                                      -import{_ as t,r as l,o as d,c as s,a as e,b as n,d as a}from"./app-DBM4OJyw.js";const A={},E=n("h1",{id:"xray-的工作模式",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#xray-的工作模式"},[n("span",null,"Xray 的工作模式")])],-1),i=n("h2",{id:"单服务器模式",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#单服务器模式"},[n("span",null,"单服务器模式")])],-1),u=n("p",null,"与其它的网络代理工具一样,你需要一台配置了 Xray 的服务器,然后在自己的设备上安装并配置 Xray 客户端,然后即可流畅地访问互联网。",-1),c=n("p",null,"一个 Xray 服务器可同时支持多台设备使用不同的代理协议访问。同时,经过合理的配置,Xray 可以识别并区分需要代理以及不需要代理的流量,直连的流量不需要绕路。",-1),_=n("h2",{id:"桥接模式",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#桥接模式"},[n("span",null,"桥接模式")])],-1),h=n("p",null,"如果你不想在每一台设备上都配置路由,你也可以设置一台中转服务器,用于接收客户端发来的所有流量,然后在服务器中进行转发判断。",-1),B=n("h2",{id:"工作原理",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#工作原理"},[n("span",null,"工作原理")])],-1),p=n("p",null,"在配置 Xray 之前,不妨先来看一下 Xray 的工作原理,以下是单个 Xray 进程的内部结构示意图。多个 Xray 之间相互独立,互不影响。",-1),D=n("ul",null,[n("li",null,[a("需要配置至少一个入站连接(Inbound)和一个出站连接(Outbound)才可以正常工作。 "),n("ul",null,[n("li",null,[a("入站连接负责与客户端(如浏览器)通信: "),n("ul",null,[n("li",null,"入站连接通常可以配置用户认证,如 ID 和密码等;"),n("li",null,"入站连接收到数据之后,会交给分发器(Dispatcher)进行分发;")])]),n("li",null,"出站连接负责将数据发给服务器,如另一台主机上的 Xray。")])]),n("li",null,[a("当有多个出站连接时,可以配置路由(Routing)来指定某一类流量由某一个出站连接发出。 "),n("ul",null,[n("li",null,"路由会在必要时查询 DNS 以获取更多信息来进行判断。")])])],-1);function m(b,y){const r=l("I18nTip"),o=l("Mermaid");return d(),s("div",null,[e(r),E,i,u,e(o,{id:"mermaid-11",code:"graph%20LR;%0AA(PC)%20-.-%20B(%E9%98%B2%E7%81%AB%E5%A2%99);%0AB%20-.-%3E%20C(%E5%A2%99%E5%A4%96%E7%BD%91%E7%AB%99);%0AA%20--%3E%20D(Xray/VPS);%0AD%20--%3E%20C;%0AA%20--%3E%20E(%E5%A2%99%E5%86%85%E7%BD%91%E7%AB%99);%0A"}),c,_,h,e(o,{id:"mermaid-21",code:"graph%20LR;%0AA(PC)%20-.-%3E%20B(%E9%98%B2%E7%81%AB%E5%A2%99);%0AB%20-.-%3E%20C(%E5%A2%99%E5%A4%96%E7%BD%91%E7%AB%99);%0AA%20--%3E%20D(%E5%A2%99%E5%86%85%20VPS);%0AD%20--%3E%20E(%E5%A2%99%E5%A4%96%20VPS);%0AE%20--%3E%20C;%0AD%20--%3E%20F(%E5%A2%99%E5%86%85%E7%BD%91%E7%AB%99);%0A"}),B,p,e(o,{id:"mermaid-28",code:"graph%20LR;%0AA1(inbound)%20--%3E%20D(Dispatcher%20/%20Router%20/%20DNS);%0AA2(inbound)%20--%3E%20D;%0AA3(inbound)%20--%3E%20D;%0AA4(inbound)%20--%3E%20D;%0AD%20--%3E%20B1(outbound);%0AD%20--%3E%20B2(outbound);%0AD%20--%3E%20B3(outbound);%0AD%20--%3E%20B4(outbound);%0A"}),D])}const X=t(A,[["render",m],["__file","work.html.vue"]]);export{X as default};
                                      +import{_ as t,r as l,o as d,c as s,a as e,b as n,d as a}from"./app-D7uBbsY3.js";const A={},E=n("h1",{id:"xray-的工作模式",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#xray-的工作模式"},[n("span",null,"Xray 的工作模式")])],-1),i=n("h2",{id:"单服务器模式",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#单服务器模式"},[n("span",null,"单服务器模式")])],-1),u=n("p",null,"与其它的网络代理工具一样,你需要一台配置了 Xray 的服务器,然后在自己的设备上安装并配置 Xray 客户端,然后即可流畅地访问互联网。",-1),c=n("p",null,"一个 Xray 服务器可同时支持多台设备使用不同的代理协议访问。同时,经过合理的配置,Xray 可以识别并区分需要代理以及不需要代理的流量,直连的流量不需要绕路。",-1),_=n("h2",{id:"桥接模式",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#桥接模式"},[n("span",null,"桥接模式")])],-1),h=n("p",null,"如果你不想在每一台设备上都配置路由,你也可以设置一台中转服务器,用于接收客户端发来的所有流量,然后在服务器中进行转发判断。",-1),B=n("h2",{id:"工作原理",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#工作原理"},[n("span",null,"工作原理")])],-1),p=n("p",null,"在配置 Xray 之前,不妨先来看一下 Xray 的工作原理,以下是单个 Xray 进程的内部结构示意图。多个 Xray 之间相互独立,互不影响。",-1),D=n("ul",null,[n("li",null,[a("需要配置至少一个入站连接(Inbound)和一个出站连接(Outbound)才可以正常工作。 "),n("ul",null,[n("li",null,[a("入站连接负责与客户端(如浏览器)通信: "),n("ul",null,[n("li",null,"入站连接通常可以配置用户认证,如 ID 和密码等;"),n("li",null,"入站连接收到数据之后,会交给分发器(Dispatcher)进行分发;")])]),n("li",null,"出站连接负责将数据发给服务器,如另一台主机上的 Xray。")])]),n("li",null,[a("当有多个出站连接时,可以配置路由(Routing)来指定某一类流量由某一个出站连接发出。 "),n("ul",null,[n("li",null,"路由会在必要时查询 DNS 以获取更多信息来进行判断。")])])],-1);function m(b,y){const r=l("I18nTip"),o=l("Mermaid");return d(),s("div",null,[e(r),E,i,u,e(o,{id:"mermaid-11",code:"graph%20LR;%0AA(PC)%20-.-%20B(%E9%98%B2%E7%81%AB%E5%A2%99);%0AB%20-.-%3E%20C(%E5%A2%99%E5%A4%96%E7%BD%91%E7%AB%99);%0AA%20--%3E%20D(Xray/VPS);%0AD%20--%3E%20C;%0AA%20--%3E%20E(%E5%A2%99%E5%86%85%E7%BD%91%E7%AB%99);%0A"}),c,_,h,e(o,{id:"mermaid-21",code:"graph%20LR;%0AA(PC)%20-.-%3E%20B(%E9%98%B2%E7%81%AB%E5%A2%99);%0AB%20-.-%3E%20C(%E5%A2%99%E5%A4%96%E7%BD%91%E7%AB%99);%0AA%20--%3E%20D(%E5%A2%99%E5%86%85%20VPS);%0AD%20--%3E%20E(%E5%A2%99%E5%A4%96%20VPS);%0AE%20--%3E%20C;%0AD%20--%3E%20F(%E5%A2%99%E5%86%85%E7%BD%91%E7%AB%99);%0A"}),B,p,e(o,{id:"mermaid-28",code:"graph%20LR;%0AA1(inbound)%20--%3E%20D(Dispatcher%20/%20Router%20/%20DNS);%0AA2(inbound)%20--%3E%20D;%0AA3(inbound)%20--%3E%20D;%0AA4(inbound)%20--%3E%20D;%0AD%20--%3E%20B1(outbound);%0AD%20--%3E%20B2(outbound);%0AD%20--%3E%20B3(outbound);%0AD%20--%3E%20B4(outbound);%0A"}),D])}const X=t(A,[["render",m],["__file","work.html.vue"]]);export{X as default};
                                      diff --git a/assets/work.html-CmnVL4Vh.js b/assets/work.html-C4aNtZOg.js
                                      similarity index 98%
                                      rename from assets/work.html-CmnVL4Vh.js
                                      rename to assets/work.html-C4aNtZOg.js
                                      index e416c07ec4..98fa601a9a 100644
                                      --- a/assets/work.html-CmnVL4Vh.js
                                      +++ b/assets/work.html-C4aNtZOg.js
                                      @@ -1 +1 @@
                                      -import{_ as B,r as a,o as r,c as t,a as n,b as D,d as o}from"./app-DBM4OJyw.js";const d={},s=D("h1",{id:"режимы-работы-xray",tabindex:"-1"},[D("a",{class:"header-anchor",href:"#режимы-работы-xray"},[D("span",null,"Режимы работы Xray")])],-1),i=D("h2",{id:"режим-одного-сервера",tabindex:"-1"},[D("a",{class:"header-anchor",href:"#режим-одного-сервера"},[D("span",null,"Режим одного сервера")])],-1),u=D("p",null,"Как и в случае с другими прокси-инструментами, вам понадобится сервер с настроенным Xray, а затем установить и настроить клиент Xray на вашем устройстве, после чего вы сможете свободно пользоваться Интернетом.",-1),c=D("p",null,"Один сервер Xray может одновременно обслуживать несколько устройств, использующих разные протоколы проксирования. При правильной настройке Xray может распознавать и различать трафик, который нужно проксировать, и трафик, который можно отправлять напрямую, без проксирования.",-1),_=D("h2",{id:"режим-моста",tabindex:"-1"},[D("a",{class:"header-anchor",href:"#режим-моста"},[D("span",null,"Режим моста")])],-1),h=D("p",null,"Если вы не хотите настраивать маршрутизацию на каждом устройстве, вы можете настроить промежуточный сервер, который будет принимать весь трафик от клиентов и перенаправлять его в зависимости от настроек.",-1),A=D("h2",{id:"принцип-работы",tabindex:"-1"},[D("a",{class:"header-anchor",href:"#принцип-работы"},[D("span",null,"Принцип работы")])],-1),p=D("p",null,"Перед настройкой Xray давайте рассмотрим, как он работает. Ниже представлена схема внутреннего устройства одного процесса Xray. Несколько процессов Xray работают независимо друг от друга.",-1),E=D("ul",null,[D("li",null,[o("Для нормальной работы необходимо настроить как минимум одно входящее соединение (Inbound) и одно исходящее соединение (Outbound). "),D("ul",null,[D("li",null,[o("Входящее соединение отвечает за связь с клиентом (например, браузером): "),D("ul",null,[D("li",null,"Входящее соединение обычно можно настроить с аутентификацией пользователя, например, с использованием ID и пароля;"),D("li",null,"После получения данных входящее соединение передает их диспетчеру (Dispatcher) для распределения.")])]),D("li",null,"Исходящее соединение отвечает за отправку данных на сервер, например, на другой Xray, работающий на другом хосте.")])]),D("li",null,[o("При наличии нескольких исходящих соединений можно настроить маршрутизацию (Routing) для указания, какое исходящее соединение должно использоваться для определенного типа трафика. "),D("ul",null,[D("li",null,"При необходимости маршрутизатор обращается к DNS для получения дополнительной информации для принятия решения.")])])],-1);function m(b,y){const l=a("I18nTip"),e=a("Mermaid");return r(),t("div",null,[n(l),s,i,u,n(e,{id:"mermaid-11",code:"graph%20LR;%0AA(%D0%9F%D0%9A)%20-.-%20B(%D0%91%D1%80%D0%B0%D0%BD%D0%B4%D0%BC%D0%B0%D1%83%D1%8D%D1%80);%0AB%20-.-%3E%20C(%D0%92%D0%BD%D0%B5%D1%88%D0%BD%D0%B8%D0%B9%20%D1%81%D0%B0%D0%B9%D1%82);%0AA%20--%3E%20D(Xray/VPS);%0AD%20--%3E%20C;%0AA%20--%3E%20E(%D0%92%D0%BD%D1%83%D1%82%D1%80%D0%B5%D0%BD%D0%BD%D0%B8%D0%B9%20%D1%81%D0%B0%D0%B9%D1%82);%0A"}),c,_,h,n(e,{id:"mermaid-21",code:"graph%20LR;%0AA(%D0%9F%D0%9A)%20-.-%3E%20B(%D0%91%D1%80%D0%B0%D0%BD%D0%B4%D0%BC%D0%B0%D1%83%D1%8D%D1%80);%0AB%20-.-%3E%20C(%D0%92%D0%BD%D0%B5%D1%88%D0%BD%D0%B8%D0%B9%20%D1%81%D0%B0%D0%B9%D1%82);%0AA%20--%3E%20D(%D0%92%D0%BD%D1%83%D1%82%D1%80%D0%B5%D0%BD%D0%BD%D0%B8%D0%B9%20VPS);%0AD%20--%3E%20E(%D0%92%D0%BD%D0%B5%D1%88%D0%BD%D0%B8%D0%B9%20VPS);%0AE%20--%3E%20C;%0AD%20--%3E%20F(%D0%92%D0%BD%D1%83%D1%82%D1%80%D0%B5%D0%BD%D0%BD%D0%B8%D0%B9%20%D1%81%D0%B0%D0%B9%D1%82);%0A"}),A,p,n(e,{id:"mermaid-28",code:"graph%20LR;%0AA1(inbound)%20--%3E%20D(Dispatcher%20/%20Router%20/%20DNS);%0AA2(inbound)%20--%3E%20D;%0AA3(inbound)%20--%3E%20D;%0AA4(inbound)%20--%3E%20D;%0AD%20--%3E%20B1(outbound);%0AD%20--%3E%20B2(outbound);%0AD%20--%3E%20B3(outbound);%0AD%20--%3E%20B4(outbound);%0A"}),E])}const x=B(d,[["render",m],["__file","work.html.vue"]]);export{x as default};
                                      +import{_ as B,r as a,o as r,c as t,a as n,b as D,d as o}from"./app-D7uBbsY3.js";const d={},s=D("h1",{id:"режимы-работы-xray",tabindex:"-1"},[D("a",{class:"header-anchor",href:"#режимы-работы-xray"},[D("span",null,"Режимы работы Xray")])],-1),i=D("h2",{id:"режим-одного-сервера",tabindex:"-1"},[D("a",{class:"header-anchor",href:"#режим-одного-сервера"},[D("span",null,"Режим одного сервера")])],-1),u=D("p",null,"Как и в случае с другими прокси-инструментами, вам понадобится сервер с настроенным Xray, а затем установить и настроить клиент Xray на вашем устройстве, после чего вы сможете свободно пользоваться Интернетом.",-1),c=D("p",null,"Один сервер Xray может одновременно обслуживать несколько устройств, использующих разные протоколы проксирования. При правильной настройке Xray может распознавать и различать трафик, который нужно проксировать, и трафик, который можно отправлять напрямую, без проксирования.",-1),_=D("h2",{id:"режим-моста",tabindex:"-1"},[D("a",{class:"header-anchor",href:"#режим-моста"},[D("span",null,"Режим моста")])],-1),h=D("p",null,"Если вы не хотите настраивать маршрутизацию на каждом устройстве, вы можете настроить промежуточный сервер, который будет принимать весь трафик от клиентов и перенаправлять его в зависимости от настроек.",-1),A=D("h2",{id:"принцип-работы",tabindex:"-1"},[D("a",{class:"header-anchor",href:"#принцип-работы"},[D("span",null,"Принцип работы")])],-1),p=D("p",null,"Перед настройкой Xray давайте рассмотрим, как он работает. Ниже представлена схема внутреннего устройства одного процесса Xray. Несколько процессов Xray работают независимо друг от друга.",-1),E=D("ul",null,[D("li",null,[o("Для нормальной работы необходимо настроить как минимум одно входящее соединение (Inbound) и одно исходящее соединение (Outbound). "),D("ul",null,[D("li",null,[o("Входящее соединение отвечает за связь с клиентом (например, браузером): "),D("ul",null,[D("li",null,"Входящее соединение обычно можно настроить с аутентификацией пользователя, например, с использованием ID и пароля;"),D("li",null,"После получения данных входящее соединение передает их диспетчеру (Dispatcher) для распределения.")])]),D("li",null,"Исходящее соединение отвечает за отправку данных на сервер, например, на другой Xray, работающий на другом хосте.")])]),D("li",null,[o("При наличии нескольких исходящих соединений можно настроить маршрутизацию (Routing) для указания, какое исходящее соединение должно использоваться для определенного типа трафика. "),D("ul",null,[D("li",null,"При необходимости маршрутизатор обращается к DNS для получения дополнительной информации для принятия решения.")])])],-1);function m(b,y){const l=a("I18nTip"),e=a("Mermaid");return r(),t("div",null,[n(l),s,i,u,n(e,{id:"mermaid-11",code:"graph%20LR;%0AA(%D0%9F%D0%9A)%20-.-%20B(%D0%91%D1%80%D0%B0%D0%BD%D0%B4%D0%BC%D0%B0%D1%83%D1%8D%D1%80);%0AB%20-.-%3E%20C(%D0%92%D0%BD%D0%B5%D1%88%D0%BD%D0%B8%D0%B9%20%D1%81%D0%B0%D0%B9%D1%82);%0AA%20--%3E%20D(Xray/VPS);%0AD%20--%3E%20C;%0AA%20--%3E%20E(%D0%92%D0%BD%D1%83%D1%82%D1%80%D0%B5%D0%BD%D0%BD%D0%B8%D0%B9%20%D1%81%D0%B0%D0%B9%D1%82);%0A"}),c,_,h,n(e,{id:"mermaid-21",code:"graph%20LR;%0AA(%D0%9F%D0%9A)%20-.-%3E%20B(%D0%91%D1%80%D0%B0%D0%BD%D0%B4%D0%BC%D0%B0%D1%83%D1%8D%D1%80);%0AB%20-.-%3E%20C(%D0%92%D0%BD%D0%B5%D1%88%D0%BD%D0%B8%D0%B9%20%D1%81%D0%B0%D0%B9%D1%82);%0AA%20--%3E%20D(%D0%92%D0%BD%D1%83%D1%82%D1%80%D0%B5%D0%BD%D0%BD%D0%B8%D0%B9%20VPS);%0AD%20--%3E%20E(%D0%92%D0%BD%D0%B5%D1%88%D0%BD%D0%B8%D0%B9%20VPS);%0AE%20--%3E%20C;%0AD%20--%3E%20F(%D0%92%D0%BD%D1%83%D1%82%D1%80%D0%B5%D0%BD%D0%BD%D0%B8%D0%B9%20%D1%81%D0%B0%D0%B9%D1%82);%0A"}),A,p,n(e,{id:"mermaid-28",code:"graph%20LR;%0AA1(inbound)%20--%3E%20D(Dispatcher%20/%20Router%20/%20DNS);%0AA2(inbound)%20--%3E%20D;%0AA3(inbound)%20--%3E%20D;%0AA4(inbound)%20--%3E%20D;%0AD%20--%3E%20B1(outbound);%0AD%20--%3E%20B2(outbound);%0AD%20--%3E%20B3(outbound);%0AD%20--%3E%20B4(outbound);%0A"}),E])}const x=B(d,[["render",m],["__file","work.html.vue"]]);export{x as default};
                                      diff --git a/assets/work.html-DS7NfRpF.js b/assets/work.html-CmqVWG7K.js
                                      similarity index 98%
                                      rename from assets/work.html-DS7NfRpF.js
                                      rename to assets/work.html-CmqVWG7K.js
                                      index 30ec35b613..0ef0f9d02f 100644
                                      --- a/assets/work.html-DS7NfRpF.js
                                      +++ b/assets/work.html-CmqVWG7K.js
                                      @@ -1 +1 @@
                                      -import{_ as t,r as l,o as d,c as s,a as e,b as n,d as a}from"./app-DBM4OJyw.js";const A={},E=n("h1",{id:"xray-的工作模式",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#xray-的工作模式"},[n("span",null,"Xray 的工作模式")])],-1),i=n("h2",{id:"单服务器模式",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#单服务器模式"},[n("span",null,"单服务器模式")])],-1),u=n("p",null,"与其它的网络代理工具一样,你需要一台配置了 Xray 的服务器,然后在自己的设备上安装并配置 Xray 客户端,然后即可流畅地访问互联网。",-1),c=n("p",null,"一个 Xray 服务器可同时支持多台设备使用不同的代理协议访问。同时,经过合理的配置,Xray 可以识别并区分需要代理以及不需要代理的流量,直连的流量不需要绕路。",-1),_=n("h2",{id:"桥接模式",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#桥接模式"},[n("span",null,"桥接模式")])],-1),h=n("p",null,"如果你不想在每一台设备上都配置路由,你也可以设置一台中转服务器,用于接收客户端发来的所有流量,然后在服务器中进行转发判断。",-1),B=n("h2",{id:"工作原理",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#工作原理"},[n("span",null,"工作原理")])],-1),p=n("p",null,"在配置 Xray 之前,不妨先来看一下 Xray 的工作原理,以下是单个 Xray 进程的内部结构示意图。多个 Xray 之间相互独立,互不影响。",-1),D=n("ul",null,[n("li",null,[a("需要配置至少一个入站连接(Inbound)和一个出站连接(Outbound)才可以正常工作。 "),n("ul",null,[n("li",null,[a("入站连接负责与客户端(如浏览器)通信: "),n("ul",null,[n("li",null,"入站连接通常可以配置用户认证,如 ID 和密码等;"),n("li",null,"入站连接收到数据之后,会交给分发器(Dispatcher)进行分发;")])]),n("li",null,"出站连接负责将数据发给服务器,如另一台主机上的 Xray。")])]),n("li",null,[a("当有多个出站连接时,可以配置路由(Routing)来指定某一类流量由某一个出站连接发出。 "),n("ul",null,[n("li",null,"路由会在必要时查询 DNS 以获取更多信息来进行判断。")])])],-1);function m(b,y){const r=l("I18nTip"),o=l("Mermaid");return d(),s("div",null,[e(r),E,i,u,e(o,{id:"mermaid-11",code:"graph%20LR;%0AA(PC)%20-.-%20B(%E9%98%B2%E7%81%AB%E5%A2%99);%0AB%20-.-%3E%20C(%E5%A2%99%E5%A4%96%E7%BD%91%E7%AB%99);%0AA%20--%3E%20D(Xray/VPS);%0AD%20--%3E%20C;%0AA%20--%3E%20E(%E5%A2%99%E5%86%85%E7%BD%91%E7%AB%99);%0A"}),c,_,h,e(o,{id:"mermaid-21",code:"graph%20LR;%0AA(PC)%20-.-%3E%20B(%E9%98%B2%E7%81%AB%E5%A2%99);%0AB%20-.-%3E%20C(%E5%A2%99%E5%A4%96%E7%BD%91%E7%AB%99);%0AA%20--%3E%20D(%E5%A2%99%E5%86%85%20VPS);%0AD%20--%3E%20E(%E5%A2%99%E5%A4%96%20VPS);%0AE%20--%3E%20C;%0AD%20--%3E%20F(%E5%A2%99%E5%86%85%E7%BD%91%E7%AB%99);%0A"}),B,p,e(o,{id:"mermaid-28",code:"graph%20LR;%0AA1(inbound)%20--%3E%20D(Dispatcher%20/%20Router%20/%20DNS);%0AA2(inbound)%20--%3E%20D;%0AA3(inbound)%20--%3E%20D;%0AA4(inbound)%20--%3E%20D;%0AD%20--%3E%20B1(outbound);%0AD%20--%3E%20B2(outbound);%0AD%20--%3E%20B3(outbound);%0AD%20--%3E%20B4(outbound);%0A"}),D])}const X=t(A,[["render",m],["__file","work.html.vue"]]);export{X as default};
                                      +import{_ as t,r as l,o as d,c as s,a as e,b as n,d as a}from"./app-D7uBbsY3.js";const A={},E=n("h1",{id:"xray-的工作模式",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#xray-的工作模式"},[n("span",null,"Xray 的工作模式")])],-1),i=n("h2",{id:"单服务器模式",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#单服务器模式"},[n("span",null,"单服务器模式")])],-1),u=n("p",null,"与其它的网络代理工具一样,你需要一台配置了 Xray 的服务器,然后在自己的设备上安装并配置 Xray 客户端,然后即可流畅地访问互联网。",-1),c=n("p",null,"一个 Xray 服务器可同时支持多台设备使用不同的代理协议访问。同时,经过合理的配置,Xray 可以识别并区分需要代理以及不需要代理的流量,直连的流量不需要绕路。",-1),_=n("h2",{id:"桥接模式",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#桥接模式"},[n("span",null,"桥接模式")])],-1),h=n("p",null,"如果你不想在每一台设备上都配置路由,你也可以设置一台中转服务器,用于接收客户端发来的所有流量,然后在服务器中进行转发判断。",-1),B=n("h2",{id:"工作原理",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#工作原理"},[n("span",null,"工作原理")])],-1),p=n("p",null,"在配置 Xray 之前,不妨先来看一下 Xray 的工作原理,以下是单个 Xray 进程的内部结构示意图。多个 Xray 之间相互独立,互不影响。",-1),D=n("ul",null,[n("li",null,[a("需要配置至少一个入站连接(Inbound)和一个出站连接(Outbound)才可以正常工作。 "),n("ul",null,[n("li",null,[a("入站连接负责与客户端(如浏览器)通信: "),n("ul",null,[n("li",null,"入站连接通常可以配置用户认证,如 ID 和密码等;"),n("li",null,"入站连接收到数据之后,会交给分发器(Dispatcher)进行分发;")])]),n("li",null,"出站连接负责将数据发给服务器,如另一台主机上的 Xray。")])]),n("li",null,[a("当有多个出站连接时,可以配置路由(Routing)来指定某一类流量由某一个出站连接发出。 "),n("ul",null,[n("li",null,"路由会在必要时查询 DNS 以获取更多信息来进行判断。")])])],-1);function m(b,y){const r=l("I18nTip"),o=l("Mermaid");return d(),s("div",null,[e(r),E,i,u,e(o,{id:"mermaid-11",code:"graph%20LR;%0AA(PC)%20-.-%20B(%E9%98%B2%E7%81%AB%E5%A2%99);%0AB%20-.-%3E%20C(%E5%A2%99%E5%A4%96%E7%BD%91%E7%AB%99);%0AA%20--%3E%20D(Xray/VPS);%0AD%20--%3E%20C;%0AA%20--%3E%20E(%E5%A2%99%E5%86%85%E7%BD%91%E7%AB%99);%0A"}),c,_,h,e(o,{id:"mermaid-21",code:"graph%20LR;%0AA(PC)%20-.-%3E%20B(%E9%98%B2%E7%81%AB%E5%A2%99);%0AB%20-.-%3E%20C(%E5%A2%99%E5%A4%96%E7%BD%91%E7%AB%99);%0AA%20--%3E%20D(%E5%A2%99%E5%86%85%20VPS);%0AD%20--%3E%20E(%E5%A2%99%E5%A4%96%20VPS);%0AE%20--%3E%20C;%0AD%20--%3E%20F(%E5%A2%99%E5%86%85%E7%BD%91%E7%AB%99);%0A"}),B,p,e(o,{id:"mermaid-28",code:"graph%20LR;%0AA1(inbound)%20--%3E%20D(Dispatcher%20/%20Router%20/%20DNS);%0AA2(inbound)%20--%3E%20D;%0AA3(inbound)%20--%3E%20D;%0AA4(inbound)%20--%3E%20D;%0AD%20--%3E%20B1(outbound);%0AD%20--%3E%20B2(outbound);%0AD%20--%3E%20B3(outbound);%0AD%20--%3E%20B4(outbound);%0A"}),D])}const X=t(A,[["render",m],["__file","work.html.vue"]]);export{X as default};
                                      diff --git a/assets/xtls.html-C840N25V.js b/assets/xtls.html-7ni9fSNN.js
                                      similarity index 79%
                                      rename from assets/xtls.html-C840N25V.js
                                      rename to assets/xtls.html-7ni9fSNN.js
                                      index f38ac94107..0787a64d51 100644
                                      --- a/assets/xtls.html-C840N25V.js
                                      +++ b/assets/xtls.html-7ni9fSNN.js
                                      @@ -1 +1 @@
                                      -import{_ as t,r as o,o as l,c as r,a as n,b as e}from"./app-DBM4OJyw.js";const c={},i=e("h1",{id:"deep-analysis-of-xtls",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#deep-analysis-of-xtls"},[e("span",null,"Deep analysis of XTLS")])],-1),_=e("blockquote",null,[e("p",null,[e("strong",null,`"XTLS is the original black technology of Xray, and also the core driving force that makes Xray's performance far superior."`)])],-1);function d(p,f){const a=o("I18nTip"),s=o("Badge");return l(),r("div",null,[n(a),i,_,n(s,{text:"WIP",type:"warning"})])}const m=t(c,[["render",d],["__file","xtls.html.vue"]]);export{m as default};
                                      +import{_ as t,r as o,o as l,c as r,a as n,b as e}from"./app-D7uBbsY3.js";const c={},i=e("h1",{id:"deep-analysis-of-xtls",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#deep-analysis-of-xtls"},[e("span",null,"Deep analysis of XTLS")])],-1),_=e("blockquote",null,[e("p",null,[e("strong",null,`"XTLS is the original black technology of Xray, and also the core driving force that makes Xray's performance far superior."`)])],-1);function d(p,f){const a=o("I18nTip"),s=o("Badge");return l(),r("div",null,[n(a),i,_,n(s,{text:"WIP",type:"warning"})])}const m=t(c,[["render",d],["__file","xtls.html.vue"]]);export{m as default};
                                      diff --git a/assets/xtls.html-BK7C9n7n.js b/assets/xtls.html-CX-lgDou.js
                                      similarity index 83%
                                      rename from assets/xtls.html-BK7C9n7n.js
                                      rename to assets/xtls.html-CX-lgDou.js
                                      index a1c80a250b..fc50c31dd9 100644
                                      --- a/assets/xtls.html-BK7C9n7n.js
                                      +++ b/assets/xtls.html-CX-lgDou.js
                                      @@ -1 +1 @@
                                      -import{_ as a,r as t,o as c,c as l,a as n,b as e}from"./app-DBM4OJyw.js";const r={},_=e("h1",{id:"глубокое-погружение-в-xtls",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#глубокое-погружение-в-xtls"},[e("span",null,"Глубокое погружение в XTLS")])],-1),d=e("blockquote",null,[e("p",null,[e("strong",null,"XTLS - это оригинальная технология Xray, которая является ключевым фактором высокой производительности Xray.")])],-1);function i(p,u){const o=t("I18nTip"),s=t("Badge");return c(),l("div",null,[n(o),_,d,n(s,{text:"WIP",type:"warning"})])}const m=a(r,[["render",i],["__file","xtls.html.vue"]]);export{m as default};
                                      +import{_ as a,r as t,o as c,c as l,a as n,b as e}from"./app-D7uBbsY3.js";const r={},_=e("h1",{id:"глубокое-погружение-в-xtls",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#глубокое-погружение-в-xtls"},[e("span",null,"Глубокое погружение в XTLS")])],-1),d=e("blockquote",null,[e("p",null,[e("strong",null,"XTLS - это оригинальная технология Xray, которая является ключевым фактором высокой производительности Xray.")])],-1);function i(p,u){const o=t("I18nTip"),s=t("Badge");return c(),l("div",null,[n(o),_,d,n(s,{text:"WIP",type:"warning"})])}const m=a(r,[["render",i],["__file","xtls.html.vue"]]);export{m as default};
                                      diff --git a/assets/xtls.html-DYo3Adlx.js b/assets/xtls.html-DkIUVXSC.js
                                      similarity index 77%
                                      rename from assets/xtls.html-DYo3Adlx.js
                                      rename to assets/xtls.html-DkIUVXSC.js
                                      index 71481a45cb..93cc91afda 100644
                                      --- a/assets/xtls.html-DYo3Adlx.js
                                      +++ b/assets/xtls.html-DkIUVXSC.js
                                      @@ -1 +1 @@
                                      -import{_ as a,r as t,o as c,c as l,a as n,b as e}from"./app-DBM4OJyw.js";const r={},_=e("h1",{id:"xtls-深度剖析",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#xtls-深度剖析"},[e("span",null,"XTLS 深度剖析")])],-1),d=e("blockquote",null,[e("p",null,[e("strong",null,"XTLS 是 Xray 的原创黑科技, 也是使 Xray 性能一骑绝尘的核心动力")])],-1);function i(p,u){const o=t("I18nTip"),s=t("Badge");return c(),l("div",null,[n(o),_,d,n(s,{text:"WIP",type:"warning"})])}const m=a(r,[["render",i],["__file","xtls.html.vue"]]);export{m as default};
                                      +import{_ as a,r as t,o as c,c as l,a as n,b as e}from"./app-D7uBbsY3.js";const r={},_=e("h1",{id:"xtls-深度剖析",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#xtls-深度剖析"},[e("span",null,"XTLS 深度剖析")])],-1),d=e("blockquote",null,[e("p",null,[e("strong",null,"XTLS 是 Xray 的原创黑科技, 也是使 Xray 性能一骑绝尘的核心动力")])],-1);function i(p,u){const o=t("I18nTip"),s=t("Badge");return c(),l("div",null,[n(o),_,d,n(s,{text:"WIP",type:"warning"})])}const m=a(r,[["render",i],["__file","xtls.html.vue"]]);export{m as default};
                                      diff --git a/assets/xychartDiagram-BZZU7QT5-VXQiVXRw.js b/assets/xychartDiagram-BZZU7QT5-v7lh-lWp.js
                                      similarity index 99%
                                      rename from assets/xychartDiagram-BZZU7QT5-VXQiVXRw.js
                                      rename to assets/xychartDiagram-BZZU7QT5-v7lh-lWp.js
                                      index 3e152f2332..4951990394 100644
                                      --- a/assets/xychartDiagram-BZZU7QT5-VXQiVXRw.js
                                      +++ b/assets/xychartDiagram-BZZU7QT5-v7lh-lWp.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as a,aD as ui,l as Ft,a2 as Bt,a1 as gi,H as At,G as Xt,F as xi,i as di,r as Nt,s as pi,g as fi,q as mi,b as yi,c as bi,t as Ai,K as wi,k as Ci}from"./mermaid.core-DapiNGBY.js";import{i as Si}from"./init-Gi6I4Gst.js";import{o as _i}from"./ordinal-Cboi1Yqb.js";import{l as Wt}from"./linear-D4Bza9R9.js";import"./app-DBM4OJyw.js";function ki(e,t,i){e=+e,t=+t,i=(n=arguments.length)<2?(t=e,e=0,1):n<3?1:+i;for(var s=-1,n=Math.max(0,Math.ceil((t-e)/i))|0,o=new Array(n);++s"u"&&(T.yylloc={});var gt=T.yylloc;r.push(gt);var li=T.options&&T.options.ranges;typeof W.yy.parseError=="function"?this.parseError=W.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function ci(L){g.length=g.length-2*L,A.length=A.length-L,r.length=r.length-L}a(ci,"popStack");function Mt(){var L;return L=x.pop()||T.lex()||It,typeof L!="number"&&(L instanceof Array&&(x=L,L=x.pop()),L=c.symbols_[L]||L),L}a(Mt,"lex");for(var P,O,M,xt,z={},at,V,Vt,rt;;){if(O=g[g.length-1],this.defaultActions[O]?M=this.defaultActions[O]:((P===null||typeof P>"u")&&(P=Mt()),M=N[O]&&N[O][P]),typeof M>"u"||!M.length||!M[0]){var dt="";rt=[];for(at in N[O])this.terminals_[at]&&at>oi&&rt.push("'"+this.terminals_[at]+"'");T.showPosition?dt="Parse error on line "+(nt+1)+`:
                                      +import{_ as a,aD as ui,l as Ft,a2 as Bt,a1 as gi,H as At,G as Xt,F as xi,i as di,r as Nt,s as pi,g as fi,q as mi,b as yi,c as bi,t as Ai,K as wi,k as Ci}from"./mermaid.core-D8igZDel.js";import{i as Si}from"./init-Gi6I4Gst.js";import{o as _i}from"./ordinal-Cboi1Yqb.js";import{l as Wt}from"./linear-hDJDjKgB.js";import"./app-D7uBbsY3.js";function ki(e,t,i){e=+e,t=+t,i=(n=arguments.length)<2?(t=e,e=0,1):n<3?1:+i;for(var s=-1,n=Math.max(0,Math.ceil((t-e)/i))|0,o=new Array(n);++s"u"&&(T.yylloc={});var gt=T.yylloc;r.push(gt);var li=T.options&&T.options.ranges;typeof W.yy.parseError=="function"?this.parseError=W.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function ci(L){g.length=g.length-2*L,A.length=A.length-L,r.length=r.length-L}a(ci,"popStack");function Mt(){var L;return L=x.pop()||T.lex()||It,typeof L!="number"&&(L instanceof Array&&(x=L,L=x.pop()),L=c.symbols_[L]||L),L}a(Mt,"lex");for(var P,O,M,xt,z={},at,V,Vt,rt;;){if(O=g[g.length-1],this.defaultActions[O]?M=this.defaultActions[O]:((P===null||typeof P>"u")&&(P=Mt()),M=N[O]&&N[O][P]),typeof M>"u"||!M.length||!M[0]){var dt="";rt=[];for(at in N[O])this.terminals_[at]&&at>oi&&rt.push("'"+this.terminals_[at]+"'");T.showPosition?dt="Parse error on line "+(nt+1)+`:
                                       `+T.showPosition()+`
                                       Expecting `+rt.join(", ")+", got '"+(this.terminals_[P]||P)+"'":dt="Parse error on line "+(nt+1)+": Unexpected "+(P==It?"end of input":"'"+(this.terminals_[P]||P)+"'"),this.parseError(dt,{text:T.match,token:this.terminals_[P]||P,line:T.yylineno,loc:gt,expected:rt})}if(M[0]instanceof Array&&M.length>1)throw new Error("Parse Error: multiple actions possible at state: "+O+", token: "+P);switch(M[0]){case 1:g.push(P),A.push(T.yytext),r.push(T.yylloc),g.push(M[1]),P=null,Et=T.yyleng,d=T.yytext,nt=T.yylineno,gt=T.yylloc;break;case 2:if(V=this.productions_[M[1]][1],z.$=A[A.length-V],z._$={first_line:r[r.length-(V||1)].first_line,last_line:r[r.length-1].last_line,first_column:r[r.length-(V||1)].first_column,last_column:r[r.length-1].last_column},li&&(z._$.range=[r[r.length-(V||1)].range[0],r[r.length-1].range[1]]),xt=this.performAction.apply(z,[d,Et,nt,W.yy,M[1],A,r].concat(hi)),typeof xt<"u")return xt;V&&(g=g.slice(0,-1*V*2),A=A.slice(0,-1*V),r=r.slice(0,-1*V)),g.push(this.productions_[M[1]][0]),A.push(z.$),r.push(z._$),Vt=N[g[g.length-2]][g[g.length-1]],g.push(Vt);break;case 3:return!0}}return!0},"parse")},ri=function(){var B={EOF:1,parseError:a(function(c,g){if(this.yy.parser)this.yy.parser.parseError(c,g);else throw new Error(c)},"parseError"),setInput:a(function(h,c){return this.yy=c||this.yy||{},this._input=h,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},"setInput"),input:a(function(){var h=this._input[0];this.yytext+=h,this.yyleng++,this.offset++,this.match+=h,this.matched+=h;var c=h.match(/(?:\r\n?|\n).*/g);return c?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),h},"input"),unput:a(function(h){var c=h.length,g=h.split(/(?:\r\n?|\n)/g);this._input=h+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-c),this.offset-=c;var x=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),g.length-1&&(this.yylineno-=g.length-1);var A=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:g?(g.length===x.length?this.yylloc.first_column:0)+x[x.length-g.length].length-g[0].length:this.yylloc.first_column-c},this.options.ranges&&(this.yylloc.range=[A[0],A[0]+this.yyleng-c]),this.yyleng=this.yytext.length,this},"unput"),more:a(function(){return this._more=!0,this},"more"),reject:a(function(){if(this.options.backtrack_lexer)this._backtrack=!0;else return this.parseError("Lexical error on line "+(this.yylineno+1)+`. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).
                                       `+this.showPosition(),{text:"",token:null,line:this.yylineno});return this},"reject"),less:a(function(h){this.unput(this.match.slice(h))},"less"),pastInput:a(function(){var h=this.matched.substr(0,this.matched.length-this.match.length);return(h.length>20?"...":"")+h.substr(-20).replace(/\n/g,"")},"pastInput"),upcomingInput:a(function(){var h=this.match;return h.length<20&&(h+=this._input.substr(0,20-h.length)),(h.substr(0,20)+(h.length>20?"...":"")).replace(/\n/g,"")},"upcomingInput"),showPosition:a(function(){var h=this.pastInput(),c=new Array(h.length+1).join("-");return h+this.upcomingInput()+`
                                      diff --git a/config/api.html b/config/api.html
                                      index ef411f1b59..eb72c147fb 100644
                                      --- a/config/api.html
                                      +++ b/config/api.html
                                      @@ -24,8 +24,8 @@
                                           
                                           API 接口 | Project X
                                           
                                      -    
                                      -    
                                      +    
                                      +    
                                         
                                         
                                           

                                      API 接口

                                      API 接口配置提供了一些基于 gRPCopen in new tag的 API 接口供远程调用。

                                      可以通过 api 配置模块开启接口。当 api 配置开启时,Xray 会自建一个和 tag 同名的出站代理,须手动将所有的 API 入站连接通过 路由规则配置 指向这一出站代理。请参考本节中的 相关配置

                                      v1.8.12open in new tag 起支持简易配置模式,只配置 ApiObject 即可,不需要配置 inbounds 和 routing。但是使用简易配置时,流量统计功能不统计 API 入站连接的流量。

                                      注意

                                      大多数用户并不会用到此 API,新手可以直接忽略这一项。

                                      ApiObject

                                      ApiObject 对应配置文件的 api 项。

                                      {
                                      @@ -70,6 +70,6 @@
                                       xray.app.proxyman.command.HandlerService
                                       xray.app.stats.command.StatsService
                                       

                                      API 调用示例

                                      Xray-API-documentsopen in new tag @crossfw

                                      - + diff --git a/config/dns.html b/config/dns.html index b80b33fc93..9f17bc7647 100644 --- a/config/dns.html +++ b/config/dns.html @@ -24,8 +24,8 @@ 内置 DNS 服务器 | Project X - - + +

                                      内置 DNS 服务器

                                      DNS 服务器

                                      Xray 内置的 DNS 模块,主要有两大用途:

                                      • 在路由阶段, 解析域名为 IP, 并且根据域名解析得到的 IP 进行规则匹配以分流. 是否解析域名及分流和路由配置模块中 domainStrategy 的值有关, 只有在设置以下两种值时,才会使用内置 DNS 服务器进行 DNS 查询:

                                        • "IPIfNonMatch", 请求一个域名时,进行路由里面的 domain 进行匹配,若无法匹配到结果,则对这个域名使用内置 DNS 服务器进行 DNS 查询,并且使用查询返回的 IP 地址再重新进行 IP 路由匹配。
                                        • "IPOnDemand", 当匹配时碰到任何基于 IP 的规则,将域名立即解析为 IP 进行匹配。
                                      • 解析目标地址进行连接。

                                        • 如 在 freedom 出站中,将 domainStrategy 设置为 UseIP, 由此出站发出的请求, 会先将域名通过内置服务器解析成 IP, 然后进行连接。
                                        • 如 在 sockopt 中,将 domainStrategy 设置为 UseIP, 此出站发起的系统连接,将先由内置服务器解析为 IP, 然后进行连接。

                                      TIP 1

                                      内置 DNS 服务器所发出的 DNS 查询请求,会自动根据路由配置进行转发。

                                      TIP 2

                                      只支持最基本的 IP 查询(A 和 AAAA 记录),CNAME 记录将会重复查询直至返回 A/AAAA 记录为止。其他查询不会进入内置 DNS 服务器。

                                      DNS 处理流程

                                      若当前要查询的域名:

                                      • 命中了 hosts 中的「域名 - IP」、「域名 - IP 数组」映射,则将该 IP 或 IP 数组作为 DNS 解析结果返回。
                                      • 命中了 hosts 中的「域名 - 域名」映射,则该映射的值(另一个域名)将作为当前要查询的域名,进入 DNS 处理流程,直到解析出 IP 后返回,或返回空解析。
                                      • 没有命中 hosts,但命中了某(几)个 DNS 服务器中的 domains 域名列表,则按照命中的规则的优先级,依次使用该规则对应的 DNS 服务器进行查询。若命中的 DNS 服务器查询失败或 expectIPs 不匹配,则使用下一个命中的 DNS 服务器进行查询;否则返回解析得到的 IP。若所有命中的 DNS 服务器均查询失败或 expectIPs 不匹配,此时 DNS 组件:
                                        • 默认会进行 「DNS 回退(fallback)查询」:使用「上一轮失败查询中未被使用的、且 skipFallback 为默认值 false 的 DNS 服务器」依次查询。若查询失败或 expectIPs 不匹配,返回空解析;否则返回解析得到的 IP。
                                        • disableFallback 设置为 true,则不会进行「DNS 回退(fallback)查询」。
                                      • 既没有命中 hosts,又没有命中 DNS 服务器中的 domains 域名列表,则:
                                        • 默认使用「skipFallback 为默认值 false 的 DNS 服务器」依次查询。若第一个被选中的 DNS 服务器查询失败或 expectIPs 不匹配,则使用下一个被选中的 DNS 服务器进行查询;否则返回解析得到的 IP。若所有被选中的 DNS 服务器均查询失败或 expectIPs 不匹配,返回空解析。
                                        • 若「skipFallback 为默认值 false 的 DNS 服务器」数量为 0 或 disableFallback 设置为 true,则使用 DNS 配置中的第一个 DNS 服务器进行查询。查询失败或 expectIPs 不匹配,返回空解析;否则返回解析得到的 IP。

                                      DnsObject

                                      DnsObject 对应配置文件的 dns 项。

                                      {
                                      @@ -116,6 +116,6 @@
                                         "clientIP": "1.2.3.4"
                                       }
                                       

                                      address: address

                                      一个 DNS 服务器列表,支持的类型有两种:DNS 地址(字符串形式)和 ServerObject 。

                                      当值为 "localhost" 时,表示使用本机预设的 DNS 配置。

                                      当它的值是一个 DNS "IP" 地址时,如 "8.8.8.8",Xray 会使用此地址的指定 UDP 端口进行 DNS 查询。该查询遵循路由规则。默认使用 53 端口。

                                      当值是 "tcp://host" 的形式,如 "tcp://8.8.8.8",Xray 会使用 DNS over TCP 进行查询。该查询遵循路由规则。默认使用 53 端口。

                                      当值是 "tcp+local://host" 的形式,如 "tcp+local://8.8.8.8",Xray 会使用 TCP 本地模式 (TCPL) 进行查询。即 DNS 请求不会经过路由组件,直接通过 Freedom outbound 对外请求,以降低耗时。不指定端口时,默认使用 53 端口。

                                      当值是 "https://host:port/dns-query" 的形式,如 "https://dns.google/dns-query",Xray 会使用 DNS over HTTPS (RFC8484, 简称 DOH) 进行查询。有些服务商拥有 IP 别名的证书,可以直接写 IP 形式,比如 https://1.1.1.1/dns-query。也可使用非标准端口和路径,如 "https://a.b.c.d:8443/my-dns-query"

                                      当值是 "https+local://host:port/dns-query" 的形式,如 "https+local://dns.google/dns-query",Xray 会使用 DOH 本地模式 (DOHL) 进行查询,即 DOH 请求不会经过路由组件,直接通过 Freedom outbound 对外请求,以降低耗时。一般适合在服务端使用。也可使用非标端口和路径。

                                      当值是 "quic+local://host:port" 的形式,如 "quic+local://dns.adguard.com",Xray 会使用 DOQ 本地模式 (DOQL) 进行查询,即 DNS 请求不会经过路由组件,直接通过 Freedom outbound 对外请求。该方式需要 DNS 服务器支持 DNS over QUIC。默认使用 853 端口进行查询,可以使用非标端口。

                                      当值是 fakedns 时,将使用 FakeDNS 功能进行查询。

                                      port: number

                                      DNS 服务器端口,如 53。此项缺省时默认为 53。当使用 DOH、DOHL、DOQL 模式时该项无效,非标端口应在 URL 中指定。

                                      domains: [string]

                                      一个域名列表,此列表包含的域名,将优先使用此服务器进行查询。域名格式和 路由配置 中相同。

                                      expectIPs:[string]

                                      一个 IP 范围列表,格式和 路由配置 中相同。

                                      当配置此项时,Xray DNS 会对返回的 IP 的进行校验,只返回包含 expectIPs 列表中的地址。

                                      如果未配置此项,会原样返回 IP 地址。

                                      skipFallback: true | false

                                      true,在进行 DNS fallback 查询时将跳过此服务器, 默认为 false,即不跳过。

                                      - + diff --git a/config/fakedns.html b/config/fakedns.html index 6f7a5f9267..4b0dd055c4 100644 --- a/config/fakedns.html +++ b/config/fakedns.html @@ -24,8 +24,8 @@ FakeDNS | Project X - - + +

                                      FakeDNS

                                      FakeDNS 通过伪造 DNS 以获取目标域名,能够降低 DNS 查询时的延迟、配合透明代理获取目标域名。

                                      注意

                                      FakeDNS 有可能会污染本地 DNS,导致 Xray 关闭后“无法访问网络”。

                                      FakeDNSObject

                                      FakeDNSObject 对应配置文件的 fakedns 项。

                                      {
                                      @@ -130,6 +130,6 @@
                                         ]
                                       }
                                       
                                      - + diff --git a/config/features/browser_dialer.html b/config/features/browser_dialer.html index 55e60780ec..7c21b7d9f5 100644 --- a/config/features/browser_dialer.html +++ b/config/features/browser_dialer.html @@ -24,11 +24,11 @@ Browser Dialer | Project X - - + +

                                      Browser Dialer

                                      背景

                                      通过 uTLS,Xray 可以模拟主流浏览器的 TLS 握手指纹(具体参见 TLS 中 fingerprint 选项)。但是仍然不能保证在任意时刻 uTLS 模拟浏览器行为完全一致。

                                      对此 浏览器转发(browser dialer)open in new tag应运而生。用户在自己的浏览器中打开一个页面至 localhost:8080,这个页面利用原生 JS 充当 Xray 的网络栈,与代理服务端建立 TLS,HTTP 连接。

                                      这个方法简洁的实现了真实的浏览器的 TLS 指纹、行为特征。最大程度抗检测与抗封锁。

                                      不过目前的浏览器转发有以下缺点:

                                      • 用户需要手动开浏览器
                                      • 浏览器发出的连接必须直连 使用 tun 的用户需要特别注意容易形成死循环
                                      • 浏览器只能发出 HTTP 连接 所以目前仅支持 WebSocketSplitHTTP 传输方式
                                      • 当浏览器从 localhost:8080 页面连接至代理服务端,需要考虑 CORSopen in new tag
                                      • 因为中间经过 JS 处理数据,会有一些性能损耗
                                      • 不能使用自定义 SNI 或者 Host,也就是说 SNI == host == address。自定义 HTTP 头以及其它 tlsSettings 项会被忽略

                                      配置方法

                                      1. 准备一份 WebSocket 或 SplitHTTP 配置,注意 address 必须填域名,若需要指定 IP,请配置 DNS 或系统 hosts
                                      2. 使用环境变量启动 Xray XRAY_BROWSER_DIALER=127.0.0.1:8080。Windows 上命令为 set XRAY_BROWSER_DIALER=127.0.0.1:8080 Linux 上命令为 XRAY_BROWSER_DIALER=127.0.0.1:8080 ./xray -c config.json
                                      3. 确保浏览器直连(或者在路由中将服务端地址直接由 freedom 发出),打开页面 localhost:8080,还可以 F12ConsoleNetwork
                                      4. 浏览器会限制发出的连接数,所以建议开启 Mux.Cool

                                      内部通信机制

                                      • Xray 监听地址端口 http://127.0.0.1:8080,作为 HTTP 服务,浏览器访问地址,加载网页中的 JS。
                                      • JS 主动向 http://127.0.0.1:8080 建立 WebSocket 连接,成功后,Xray 将连接发给 channel。
                                      • 需要建立连接时,Xray 从 channel 接收一个可用的连接,并发送目标 URL 和可选的 early data。
                                      • JS 成功连接到目标后告知 Xray,并继续用这个 conn 全双工双向转发数据,连接关闭行为同步。
                                      • 连接使用后就会被关闭,但 JS 会确保始终有新空闲连接可用。

                                      WebSocket

                                      v1.4.1+

                                      根据浏览器的需求,对 early data 机制进行了如下调整:

                                      • 服务端响应头会带有请求的 Sec-WebSocket-Protocol,这也初步混淆了 WSS 握手响应的长度特征。
                                      • 用于浏览器的 early data 编码是 base64.RawURLEncoding 而不是 StdEncoding,服务端做了兼容。
                                      • 此外,由于 Xray-core#375open in new tag 推荐 ?ed=2048,这个 PR 顺便将服务端一处 MaxHeaderBytes 扩至了 4096。 (虽然好像不改也没问题)

                                      SplitHTTP

                                      v1.8.19+

                                      SplitHTTP 本身支持 QUIC,如果想使用浏览器自己的 QUIC 网络栈,Chrome 可以在 chrome://flags 中设定。其它浏览器也有相关选项。

                                      原理上说 tlsSettings 项会被忽略,使用哪个 HTTP 版本将完全由浏览器决定。

                                      - + diff --git a/config/features/env.html b/config/features/env.html index 6b79f26060..ef7c2e597c 100644 --- a/config/features/env.html +++ b/config/features/env.html @@ -24,14 +24,14 @@ 环境变量 | Project X - - + +

                                      环境变量

                                      Xray 提供以下环境变量以供修改 Xray 的一些底层配置。

                                      资源文件路径

                                      • 名称:xray.location.assetXRAY_LOCATION_ASSET
                                      • 默认值:特定 FHSopen in new tag 目录或 Xray 文件同路径。

                                      这个环境变量指定了一个文件夹位置,这个文件夹应当包含 geoip.dat 和 geosite.dat 文件。 若无指定变量值,程序将会按以下顺序寻找资源文件:

                                      ./
                                       /usr/local/share/xray
                                       /usr/share/xray
                                       

                                      配置文件位置

                                      • 名称:xray.location.configXRAY_LOCATION_CONFIG
                                      • 默认值:和 Xray 文件同路径。

                                      这个环境变量指定了一个文件夹位置,这个文件夹应当包含 config.json 文件。

                                      多配置目录

                                      • 名称:xray.location.confdirXRAY_LOCATION_CONFDIR
                                      • 默认值:""

                                      这个目录内的 .json 文件会按文件名顺序读取,作为多配置选项。

                                      - + diff --git a/config/features/fallback.html b/config/features/fallback.html index a80629d83d..2eebe26ebc 100644 --- a/config/features/fallback.html +++ b/config/features/fallback.html @@ -24,8 +24,8 @@ Fallback 回落 | Project X - - + +

                                      Fallback 回落

                                      Fallback 是 Xray 的最强大功能之一, 可有效防止主动探测, 自由配置常用端口多服务共享

                                      fallback 为 Xray 提供了高强度的防主动探测性, 并且具有独创的首包回落机制.

                                      fallback 也可以将不同类型的流量根据 path 进行分流, 从而实现一个端口, 多种服务共享.

                                      目前您可以在使用 VLESS 或者 trojan 协议时, 通过配置 fallbacks 来使用回落这一特性, 并且创造出非常丰富的组合玩法.

                                      fallbacks 配置

                                        "fallbacks": [
                                      @@ -41,6 +41,6 @@
                                         "xver": 0
                                       }
                                       

                                      fallbacks 是一个数组,这里是其中一个子元素的配置说明。

                                      fallbacks 项是可选的,只能用于 TCP+TLS 传输组合

                                      • 该项有子元素时,Inbound TLS 需设置 "alpn":["http/1.1"]。**

                                      通常,你需要先设置一组 alpnpath 均省略或为空的默认回落,然后再按需配置其它分流。

                                      VLESS 会把 TLS 解密后首包长度 < 18 或协议版本无效、身份认证失败的流量转发到 dest 指定的地址。

                                      其它传输组合必须删掉 fallbacks 项或所有子元素,此时也不会开启 Fallback,VLESS 会等待读够所需长度,协议版本无效或身份认证失败时,将直接断开连接。

                                      name: string

                                      尝试匹配 TLS SNI(Server Name Indication),空为任意,默认为 ""

                                      alpn: string

                                      尝试匹配 TLS ALPN 协商结果,空为任意,默认为 ""

                                      有需要时,VLESS 才会尝试读取 TLS ALPN 协商结果,若成功,输出 info realAlpn = 到日志。 用途:解决了 Nginx 的 h2c 服务不能同时兼容 http/1.1 的问题,Nginx 需要写两行 listen,分别用于 1.1 和 h2c。 注意:fallbacks alpn 存在 "h2" 时,Inbound TLS 需设置 "alpn":["h2","http/1.1"],以支持 h2 访问。

                                      提示

                                      Fallback 内设置的 alpn 是匹配实际协商出的 ALPN,而 Inbound TLS 设置的 alpn 是握手时可选的 ALPN 列表,两者含义不同。

                                      path: string

                                      尝试匹配首包 HTTP PATH,空为任意,默认为空,非空则必须以 / 开头,不支持 h2c。

                                      智能:有需要时,VLESS 才会尝试看一眼 PATH(不超过 55 个字节;最快算法,并不完整解析 HTTP),若成功,输出 INFO 日志 realPath =。 用途:分流其它 inbound 的 WebSocket 流量或 HTTP 伪装流量,没有多余处理、纯粹转发流量,理论性能比 Nginx 更强。

                                      注意:fallbacks 所在入站本身必须是 TCP+TLS,这是分流至其它 WS 入站用的,被分流的入站则无需配置 TLS。

                                      dest: string | number

                                      决定 TLS 解密后 TCP 流量的去向,目前支持两类地址:(该项必填,否则无法启动)

                                      1. TCP,格式为 "addr:port",其中 addr 支持 IPv4、域名、IPv6,若填写域名,也将直接发起 TCP 连接(而不走内置的 DNS)。
                                      2. Unix domain socket,格式为绝对路径,形如 "/dev/shm/domain.socket",可在开头加 @ 代表 abstractopen in new tag@@ 则代表带 padding 的 abstract。

                                      若只填 port,数字或字符串均可,形如 80"80",通常指向一个明文 http 服务(addr 会被补为 "127.0.0.1")。

                                      xver: number

                                      发送 PROXY protocolopen in new tag,专用于传递请求的真实来源 IP 和端口,填版本 1 或 2,默认为 0,即不发送。若有需要建议填 1。

                                      目前填 1 或 2,功能完全相同,只是结构不同,且前者可打印,后者为二进制。Xray 的 TCP 和 WS 入站均已支持接收 PROXY protocol。

                                      注意

                                      若你正在 配置 Nginx 接收 PROXY protocolopen in new tag,除了设置 proxy_protocol 外,还需设置 set_real_ip_from,否则可能会出问题。

                                      补充说明

                                      • 将匹配到最精确的子元素,与子元素的排列顺序无关。若配置了几个 alpn 和 path 均相同的子元素,则会以最后的为准。
                                      • 回落分流均是解密后 TCP 层的转发,而不是 HTTP 层,只在必要时检查首包 PATH。
                                      • 您可以查看更多的关于 Fallbacks 的使用技巧和心得

                                      Fallbacks 设计理论 WIP

                                      - + diff --git a/config/features/multiple.html b/config/features/multiple.html index 04f60d83ce..ad377fb7f7 100644 --- a/config/features/multiple.html +++ b/config/features/multiple.html @@ -24,8 +24,8 @@ 多文件配置 | Project X - - + +

                                      多文件配置

                                      Xray 程序支持使用多个配置文件。

                                      多配置文件的主要作用在于分散不同作用模块配置,便于管理和维护。

                                      该功能主要考虑是为了丰富 Xray 的生态链,比如对于 GUI 的客户端,一般只实现节点选择等固定的功能,对于太复杂的配置难以图形化实现;只需留一个 confdir 的自定义配置目录供配置复杂的功能;对于服务器的部署脚本,只需往 confdir 添加文件即可实现配置多种协议。

                                      多文件启动

                                      提示

                                      启动信息中会提示依次读入的每个配置文件,留意启动信息是否符合你预设的顺序。可以在每个文件名前面增加前缀数字的方式控制顺序。如 01_文件名, 02_文件名,数字越大排序越靠后。

                                      $ xray run -confdir /etc/xray/confs
                                      @@ -103,6 +103,6 @@
                                         ]
                                       }
                                       

                                      提示

                                      可以使用 xray run -confdir=./confs -dump 命令查看合并后的配置。但是因为 core 内部使用 protobuf 数据格式,所以 -dump 选项输出的配置格式会有所不同。

                                      - + diff --git a/config/features/xtls.html b/config/features/xtls.html index fe0fb214d3..bee2ba4b5a 100644 --- a/config/features/xtls.html +++ b/config/features/xtls.html @@ -24,11 +24,11 @@ XTLS 深度剖析 | Project X - - + + - + diff --git a/config/inbound.html b/config/inbound.html index 08022ce1af..ace221aa17 100644 --- a/config/inbound.html +++ b/config/inbound.html @@ -24,8 +24,8 @@ 入站代理 | Project X - - + +

                                      入站代理

                                      入站连接用于接收发来的数据,可用的协议请见入站协议

                                      InboundObject

                                      InboundObject 对应配置文件中 inbounds 项的一个子元素。

                                      {
                                      @@ -68,6 +68,6 @@
                                         "concurrency": 3
                                       }
                                       

                                      strategy: "always" | "random"

                                      端口分配策略。

                                      • "always" 表示总是分配所有已指定的端口,port 中指定了多少个端口,Xray 就会监听这些端口。
                                      • "random" 表示随机开放端口,每隔 refresh 分钟在 port 范围中随机选取 concurrency 个端口来监听。

                                      refresh: number

                                      随机端口刷新间隔,单位为分钟。最小值为 2,建议值为 5。这个属性仅当 strategy 设置为 "random" 时有效。

                                      concurrency: number

                                      随机端口数量。最小值为 1,最大值为 port 范围的三分之一。建议值为 3

                                      - + diff --git a/config/inbounds/dokodemo.html b/config/inbounds/dokodemo.html index 503da7d9b9..a921388237 100644 --- a/config/inbounds/dokodemo.html +++ b/config/inbounds/dokodemo.html @@ -24,8 +24,8 @@ Dokodemo-Door | Project X - - + +

                                      Dokodemo-Door

                                      Dokodemo door(任意门)可以监听一个本地端口,并把所有进入此端口的数据发送至指定服务器的一个端口,从而达到端口映射的效果。

                                      InboundConfigurationObject

                                      {
                                      @@ -49,6 +49,6 @@
                                         "tag": "mc"
                                       }
                                       

                                      这时候核心会监听 127.0.0.1:25565 并通过默认出站转发至 mc.hypixel.net:25565 (一个MC服务器), 这时候再通过 Minecraft 客户端连接 127.0.0.1:25565, 就相当于通过代理连接了 Hypixel 服务器。

                                      透明代理配置样例

                                      此部分请参考透明代理(TProxy)配置教程

                                      - + diff --git a/config/inbounds/http.html b/config/inbounds/http.html index b779e0070a..cf48633172 100644 --- a/config/inbounds/http.html +++ b/config/inbounds/http.html @@ -24,8 +24,8 @@ HTTP | Project X - - + +

                                      HTTP

                                      HTTP 协议。

                                      警告

                                      http 协议没有对传输加密,不适宜经公网中传输,更容易成为被人用作攻击的肉鸡。

                                      http 入站更有意义的用法是在局域网或本机环境下监听,为其他程序提供本地服务。

                                      TIP 1

                                      http proxy 只能代理 tcp 协议,udp 系的协议均不能通过。

                                      TIP 2

                                      在 Linux 中使用以下环境变量即可在当前 session 使用全局 HTTP 代理(很多软件都支持这一设置,也有不支持的)。

                                      • export http_proxy=http://127.0.0.1:8080/ (地址须改成你配置的 HTTP 入站代理地址)
                                      • export https_proxy=$http_proxy

                                      InboundConfigurationObject

                                      {
                                      @@ -43,6 +43,6 @@
                                         "pass": "my-password"
                                       }
                                       

                                      user: string

                                      用户名,字符串类型。必填。

                                      pass: string

                                      密码,字符串类型。必填。

                                      - + diff --git a/config/inbounds/shadowsocks.html b/config/inbounds/shadowsocks.html index 5bdddcf24d..d6126aa151 100644 --- a/config/inbounds/shadowsocks.html +++ b/config/inbounds/shadowsocks.html @@ -24,8 +24,8 @@ Shadowsocks | Project X - - + +

                                      Shadowsocks

                                      Shadowsocksopen in new tag 协议,兼容大部分其它版本的实现。

                                      目前兼容性如下:

                                      • 支持 TCP 和 UDP 数据包转发,其中 UDP 可选择性关闭;
                                      • 推荐的加密方式:
                                        • 2022-blake3-aes-128-gcm
                                        • 2022-blake3-aes-256-gcm
                                        • 2022-blake3-chacha20-poly1305
                                      • 其他加密方式
                                        • aes-256-gcm
                                        • aes-128-gcm
                                        • chacha20-poly1305 或称 chacha20-ietf-poly1305
                                        • xchacha20-poly1305 或称 xchacha20-ietf-poly1305
                                        • none 或 plain

                                      Shadowsocks 2022 新协议格式提升了性能并带有完整的重放保护,解决了旧协议的以下安全问题:

                                      警告

                                      "none" 不加密方式下流量将明文传输。为确保安全性, 不要在公共网络上使用。

                                      InboundConfigurationObject

                                      {
                                      @@ -50,6 +50,6 @@
                                         "email": "love@xray.com"
                                       }
                                       

                                      当存在此选项时,代表启用多用户模式.

                                      当 InboundConfigurationObject 中的 method 不为SS2022选项时,可以在此为每个用户指定 "method"。("method"中也仅支持非SS2022选项)与"password"(与此同时 InboundConfigurationObject 中的设置的 "password" 将会被忽略)。

                                      当 InboundConfigurationObject 中的 method 为SS2022选项时,出于安全考量,不再支持为单个用户设置 "method",统一为 InboundConfigurationObject 所指定的"method"

                                      注意SS2022并不会像旧SS一样忽略上层 "password", 客户端的正确密码写法应为, ServerPassword:UserPassword。如:"password": "114514:1919810"

                                      其余选项与 InboundConfigurationObject 中的含义一致。

                                      - + diff --git a/config/inbounds/socks.html b/config/inbounds/socks.html index 3d095c4f6a..76fc9b03f4 100644 --- a/config/inbounds/socks.html +++ b/config/inbounds/socks.html @@ -24,8 +24,8 @@ Socks | Project X - - + +

                                      Socks

                                      标准 Socks 协议实现,兼容 Socks 4open in new tagSocks 4aopen in new tag Socks 5, 以及 HTTP

                                      警告

                                      Socks 协议没有对传输加密,不适宜经公网中传输

                                      Socks 入站更有意义的用法是在局域网或本机环境下监听,为其他程序提供本地服务。

                                      InboundConfigurationObject

                                      {
                                      @@ -45,6 +45,6 @@
                                         "pass": "my-password"
                                       }
                                       

                                      user: string

                                      用户名,字符串类型。必填。

                                      pass: string

                                      密码,字符串类型。必填。

                                      - + diff --git a/config/inbounds/trojan.html b/config/inbounds/trojan.html index 91abf7cbad..2f69464246 100644 --- a/config/inbounds/trojan.html +++ b/config/inbounds/trojan.html @@ -24,8 +24,8 @@ Trojan | Project X - - + +

                                      Trojan

                                      Trojanopen in new tag 协议

                                      警告

                                      Trojan 被设计工作在正确配置的加密 TLS 隧道

                                      InboundConfigurationObject

                                      {
                                      @@ -48,6 +48,6 @@
                                         "level": 0
                                       }
                                       

                                      password: string

                                      必填,任意字符串。

                                      email: string

                                      邮件地址,可选,用于标识用户

                                      警告

                                      如果存在多个 ClientObject, 请注意 email 不可以重复。

                                      level: number

                                      用户等级,连接会使用这个用户等级对应的 本地策略

                                      userLevel 的值, 对应 policylevel 的值。 如不指定, 默认为 0。

                                      - + diff --git a/config/inbounds/vless.html b/config/inbounds/vless.html index cd507217ee..9978cc6994 100644 --- a/config/inbounds/vless.html +++ b/config/inbounds/vless.html @@ -24,8 +24,8 @@ VLESS(XTLS Vision Seed) | Project X - - + +

                                      VLESS(XTLS Vision Seed)

                                      警告

                                      目前 VLESS 没有自带加密,请用于可靠信道,如 TLS。

                                      VLESS 是一个无状态的轻量传输协议,它分为入站和出站两部分,可以作为 Xray 客户端和服务器之间的桥梁。

                                      VMess 不同,VLESS 不依赖于系统时间,认证方式同样为 UUID。

                                      InboundConfigurationObject

                                      {
                                      @@ -51,6 +51,6 @@
                                         "flow": "xtls-rprx-vision"
                                       }
                                       

                                      id: string

                                      VLESS 的用户 ID,可以是任意小于 30 字节的字符串, 也可以是一个合法的 UUID. 自定义字符串和其映射的 UUID 是等价的, 这意味着你将可以这样在配置文件中写 id 来标识同一用户,即

                                      • "id": "我爱🍉老师1314",
                                      • 或写 "id": "5783a3e7-e373-51cd-8642-c83782b807c5" (此 UUID 是 我爱🍉老师1314 的 UUID 映射)

                                      其映射标准在 VLESS UUID 映射标准:将自定义字符串映射为一个 UUIDv5open in new tag

                                      你可以使用命令 xray uuid -i "自定义字符串" 生成自定义字符串所映射的的 UUID。

                                      也可以使用命令 xray uuid 生成随机的 UUID.

                                      level: number

                                      用户等级,连接会使用这个用户等级对应的 本地策略

                                      level 的值, 对应 policylevel 的值。 如不指定, 默认为 0。

                                      email: string

                                      用户邮箱,用于区分不同用户的流量(会体现在日志、统计中)。

                                      flow: string

                                      流控模式,用于选择 XTLS 的算法。

                                      目前入站协议中有以下流控模式可选:

                                      • flow 或者 空字符: 使用普通 TLS 代理
                                      • xtls-rprx-vision:使用新 XTLS 模式 包含内层握手随机填充

                                      此外,目前 XTLS 仅支持 TCP+TLS/Reality

                                      - + diff --git a/config/inbounds/vmess.html b/config/inbounds/vmess.html index bc0c76aa8f..6d8d7f5a37 100644 --- a/config/inbounds/vmess.html +++ b/config/inbounds/vmess.html @@ -24,8 +24,8 @@ VMess | Project X - - + +

                                      VMess

                                      VMess 是一个加密传输协议,通常作为 Xray 客户端和服务器之间的桥梁。

                                      警告

                                      VMess 依赖于系统时间,请确保使用 Xray 的系统 UTC 时间误差在 120 秒之内,时区无关。在 Linux 系统中可以安装ntp服务来自动同步系统时间。

                                      InboundConfigurationObject

                                      {
                                      @@ -55,6 +55,6 @@
                                         "level": 0
                                       }
                                       

                                      level: number

                                      用户等级,连接会使用这个用户等级对应的 本地策略

                                      level 的值, 对应 policylevel 的值。 如不指定, 默认为 0。

                                      - + diff --git a/config/inbounds/wireguard.html b/config/inbounds/wireguard.html index 9aeb0f0b0c..9296c2be1c 100644 --- a/config/inbounds/wireguard.html +++ b/config/inbounds/wireguard.html @@ -24,8 +24,8 @@ Wireguard | Project X - - + +

                                      Wireguard

                                      User-space Wireguard 协议实现。

                                      警告

                                      Wireguard 协议并非专门为翻墙而设计,若在最外层过墙,存在特征可能导致服务器被封锁

                                      InboundConfigurationObject

                                      {
                                      @@ -51,6 +51,6 @@
                                         "allowedIPs": ["0.0.0.0/0"] // optional, default ["0.0.0.0/0", "::/0"]
                                       }
                                       

                                      publicKey: string

                                      公钥,用于验证

                                      allowedIPs: string array

                                      允许的源IP

                                      - + diff --git a/config/index.html b/config/index.html index d325e5be70..a9a94ca382 100644 --- a/config/index.html +++ b/config/index.html @@ -24,8 +24,8 @@ 配置文件 | Project X - - + +

                                      这个章节将告诉您所有的 Xray 配置细节,掌握这些内容,在您手中 Xray 将发挥更大威力。

                                      概述

                                      Xray 的配置文件为 json 格式, 客户端和服务端的配置格式没有区别, 只是实际的配置内容不一样。
                                      形式如下:

                                      {
                                      @@ -45,6 +45,6 @@
                                         "burstObservatory": {}
                                       }
                                       

                                      注意

                                      如果你刚接触 Xray, 您可以先点击查看快速入门中的配置运行, 学习最基本的配置方式, 然后查看本章节内容以掌握所有 Xray 的配置方式。

                                      基础配置模块

                                      log:LogObject

                                      日志配置,控制 Xray 输出日志的方式.

                                      api:ApiObject

                                      提供了一些 API 接口供远程调用。

                                      dns: DnsObject

                                      内置的 DNS 服务器. 如果没有配置此项,则使用系统的 DNS 设置。

                                      routing: RoutingObject

                                      路由功能。可以设置规则分流数据从不同的 outbound 发出.

                                      policy: PolicyObject

                                      本地策略,可以设置不同的用户等级和对应的策略设置。

                                      inbounds: [ InboundObject ]

                                      一个数组,每个元素是一个入站连接配置。

                                      outbounds: [ OutboundObject ]

                                      一个数组,每个元素是一个出站连接配置。

                                      transport: TransportObject

                                      用于配置 Xray 其它服务器建立和使用网络连接的方式。

                                      stats: StatsObject

                                      用于配置流量数据的统计。

                                      reverse: ReverseObject

                                      反向代理。可以把服务器端的流量向客户端转发,即逆向流量转发。

                                      fakedns: FakeDnsObject

                                      FakeDNS 配置。可配合透明代理使用,以获取实际域名。

                                      metrics: metricsObject

                                      metrics 配置。更直接(希望更好)的统计导出方式。

                                      observatory: ObservatoryObject

                                      后台连接观测。探测出站代理的连接状态。

                                      burstObservatory: BurstObservatoryObject

                                      并发连接观测。探测出站代理的连接状态。

                                      - + diff --git a/config/log.html b/config/log.html index eb6c4e6c90..4b697a7773 100644 --- a/config/log.html +++ b/config/log.html @@ -24,8 +24,8 @@ 日志配置 | Project X - - + +

                                      日志配置

                                      日志配置,控制 Xray 输出日志的方式.

                                      Xray 有两种日志, 访问日志和错误日志, 你可以分别配置两种日志的输出方式.

                                      LogObject

                                      LogObject 对应配置文件的 log 项。

                                      {
                                      @@ -38,6 +38,6 @@
                                         }
                                       }
                                       

                                      access: string

                                      访问日志的文件地址,其值是一个合法的文件地址,如"/var/log/Xray/access.log"(Linux)或者"C:\\Temp\\Xray\\_access.log"(Windows)。当此项不指定或为空值时,表示将日志输出至 stdout。

                                      • 特殊值none,即关闭 access log。

                                      error: string

                                      错误日志的文件地址,其值是一个合法的文件地址,如"/var/log/Xray/error.log"(Linux)或者"C:\\Temp\\Xray\\_error.log"(Windows)。当此项不指定或为空值时,表示将日志输出至 stdout。

                                      • 特殊值none,即关闭 error log。

                                      loglevel: "debug" | "info" | "warning" | "error" | "none"

                                      error 日志的级别, 指示 error 日志需要记录的信息. 默认值为 "warning"

                                      • "debug":调试程序时用到的输出信息。同时包含所有 "info" 内容。
                                      • "info":运行时的状态信息等,不影响正常使用。同时包含所有 "warning" 内容。
                                      • "warning":发生了一些并不影响正常运行的问题时输出的信息,但有可能影响用户的体验。同时包含所有 "error" 内容。
                                      • "error":Xray 遇到了无法正常运行的问题,需要立即解决。
                                      • "none":不记录任何内容。

                                      dnsLog: bool

                                      是否启用 DNS 查询日志,例如:DOH//doh.server got answer: domain.com -> [ip1, ip2] 2.333ms

                                      maskAddress: string

                                      IP地址遮罩,启用后将自动替换log中出现的IP地址,用于在分享日志时保护隐私,默认为空即不启用。

                                      目前可选等级 quarter half full 遮罩形式对应如下

                                      • ipv4 1.2.*.* 1.*.*.* [Masked IPv4]
                                      • ipv6 1234:5678::/32 1234::/16 [Masked IPv6]
                                      - + diff --git a/config/metrics.html b/config/metrics.html index 83ab727d3d..bd8b01c1f6 100644 --- a/config/metrics.html +++ b/config/metrics.html @@ -24,8 +24,8 @@ Metrics | Project X - - + +

                                      Metrics

                                      更直接(希望更好)的统计导出方式。

                                      相关配置

                                      可以在 inbounds 配置中增加一个 metrics 的 inbound

                                          "inbounds": [
                                      @@ -242,6 +242,6 @@
                                                  id: udp
                                                  expvar_type: int
                                       

                                      And you will get a nice plot like this:

                                      160428235-2988bf69-5d6c-41ec-8267-1bd512508aa8

                                      Additional

                                      Maybe reusing the empty object stats in config file is better than adding metrics here?

                                      Edit: removed prometheus related things and added usage about expvars

                                      - + diff --git a/config/observatory.html b/config/observatory.html index 7a19fc7cdc..859091d237 100644 --- a/config/observatory.html +++ b/config/observatory.html @@ -24,8 +24,8 @@ 连接观测 | Project X - - + +

                                      连接观测

                                      连接观测组件使用 HTTPing 的方式探测出站代理的连接状态。观测结果可以被其他组件使用,如负载均衡器。目前有 observatory (后台连接观测)和 burstObservatory (并发连接观测)两种。按需选择其中之一就行。

                                      ObservatoryObject

                                      {
                                      @@ -50,6 +50,6 @@
                                         "timeout": "30s"
                                       }
                                       

                                      destination: string

                                      用于探测出站代理连接状态的网址。这个网址应该返回 HTTP 204 成功状态码。

                                      connectivity: string

                                      用于检测本地网络连通性的网址。空字符串表示不检测本地网络连通性。

                                      interval: string

                                      在指定时间内探测全部匹配的出站代理,每个出站代理探测 sampling + 1 次。时间格式为数字 + 单位,比如 "10s", "2h45m",支持的时间单位有 ns, us, ms, s, m, h, 分别对应纳秒、微秒、毫秒、秒、分、时。

                                      sampling: number

                                      保留最近探测结果的数量。

                                      timeout: string

                                      探测超时时间。格式和上面的 interval 相同。

                                      - + diff --git a/config/outbound.html b/config/outbound.html index ba18cc4d41..dc5d476fbd 100644 --- a/config/outbound.html +++ b/config/outbound.html @@ -24,8 +24,8 @@ 出站代理(Mux、XUDP) | Project X - - + +

                                      出站代理(Mux、XUDP)

                                      出站连接用于发送数据,可用的协议请见 出站协议

                                      OutboundObject

                                      OutboundObject 对应配置文件中 outbounds 项的一个子元素。

                                      提示

                                      列表中的第一个元素作为主 outbound。当路由匹配不存在或没有匹配成功时,流量由主 outbound 发出。

                                      {
                                      @@ -53,6 +53,6 @@
                                         "xudpProxyUDP443": "reject"
                                       }
                                       

                                      enabled: true | false

                                      是否启用 Mux 转发请求,默认值 false

                                      concurrency: number

                                      最大并发连接数。最小值 1,最大值 1024。省略或者填 0 时都等于 8

                                      这个数值表示了一个 TCP 连接上最多承载的子连接数量。比如设置 concurrency=8 时,当客户端发出了 8 个 TCP 请求,Xray 只会发出一条实际的 TCP 连接,客户端的 8 个请求全部由这个 TCP 连接传输。

                                      提示

                                      填负数时,如 -1,不使用 Mux 模块承载 TCP 流量。

                                      xudpConcurrency: number

                                      使用新 XUDP 聚合隧道(也就是另一条 Mux 连接)代理 UDP 流量,填写最大并发子 UoT 数量。最小值 1,最大值 1024。 省略或者填 0 时,将与 TCP 流量走同一条路,也就是传统的行为。

                                      提示

                                      填负数时,如 -1,不使用 Mux 模块承载 UDP 流量。将使用代理协议原本的 UDP 传输方式。例如 Shadowsocks 会使用原生 UDP,VLESS 会使用 UoT。

                                      xudpProxyUDP443: string

                                      控制 Mux 对于被代理的 UDP/443(QUIC)流量的处理方式:

                                      • 默认 reject 拒绝流量(一般浏览器会自动回落到 TCP HTTP2)
                                      • allow 允许走 Mux 连接。
                                      • skip 时,不使用 Mux 模块承载 UDP 443 流量。将使用代理协议原本的 UDP 传输方式。例如 Shadowsocks 会使用原生 UDP,VLESS 会使用 UoT。
                                      - + diff --git a/config/outbounds/blackhole.html b/config/outbounds/blackhole.html index 950414249e..30f6479dd5 100644 --- a/config/outbounds/blackhole.html +++ b/config/outbounds/blackhole.html @@ -24,8 +24,8 @@ Blackhole | Project X - - + +

                                      Blackhole

                                      Blackhole(黑洞)是一个出站数据协议,它会阻碍所有数据的出站,配合 路由配置 一起使用,可以达到禁止访问某些网站的效果。

                                      OutboundConfigurationObject

                                      {
                                      @@ -37,6 +37,6 @@
                                         "type": "none"
                                       }
                                       

                                      type: "http" | "none"

                                      type"none"(默认值)时,Blackhole 将直接关闭连接。

                                      type"http" 时,Blackhole 会发回一个简单的 HTTP 403 数据包,然后关闭连接。

                                      - + diff --git a/config/outbounds/dns.html b/config/outbounds/dns.html index 4e0cd98e66..3773a9c01a 100644 --- a/config/outbounds/dns.html +++ b/config/outbounds/dns.html @@ -24,8 +24,8 @@ DNS | Project X - - + +

                                      DNS

                                      DNS 是一个出站协议,主要用于拦截和转发 DNS 查询。

                                      此出站协议只能接收 DNS 流量(包含基于 UDP 和 TCP 协议的查询),其它类型的流量会导致错误。

                                      在处理 DNS 查询时,此出站协议会将 IP 查询(即 A 和 AAAA)转发给内置的 DNS 服务器。其它类型的查询流量见下的 nonIPQuery

                                      OutboundConfigurationObject

                                      {
                                      @@ -36,6 +36,6 @@
                                         "blockTypes":[]
                                       }
                                       

                                      network: "tcp" | "udp"

                                      修改 DNS 流量的传输层协议,可选的值有 "tcp""udp"。当不指定时,保持来源的传输方式不变。

                                      address: address

                                      修改 DNS 服务器地址。当不指定时,保持来源中指定的地址不变。

                                      port: number

                                      修改 DNS 服务器端口。当不指定时,保持来源中指定的端口不变。

                                      nonIPQuery: string

                                      控制非 IP 查询(非 A 和 AAAA),"drop" 丢弃或者 "skip" 不由内置 DNS 服务器处理,将转发给目标。默认为 "drop"

                                      blockTypes: array

                                      为一个int数组,屏蔽数组中的查询类型,如 "blockTypes":[65,28] 表示屏蔽type 65(HTTPS) 和 28(AAAA)

                                      由于 nonIPQuery 默认 drop 所有非 A 和 AAAA 查询, 所以需要将其设置为 skip 本选项才能进一步发挥作用。当然也可以不修改,单纯用来屏蔽A或者AAAA来屏蔽 ipv4/ipv6 查询, 但非常不推荐那么做,建议在内置DNS的 queryStrategy 对相关内容进行设置。

                                      DNS 配置实例 WIP

                                      - + diff --git a/config/outbounds/freedom.html b/config/outbounds/freedom.html index 3a2a851171..e7b35d01c1 100644 --- a/config/outbounds/freedom.html +++ b/config/outbounds/freedom.html @@ -24,8 +24,8 @@ Freedom(fragment、noises) | Project X - - + +

                                      Freedom(fragment、noises)

                                      Freedom 是一个出站协议,可以用来向任意网络发送(正常的) TCP 或 UDP 数据。

                                      OutboundConfigurationObject

                                      {
                                      @@ -47,6 +47,6 @@
                                         "proxyProtocol": 0
                                       }
                                       

                                      domainStrategy: "AsIs"
                                      "UseIP" | "UseIPv6v4" | "UseIPv6" | "UseIPv4v6" | "UseIPv4"
                                      "ForceIP" | "ForceIPv6v4" | "ForceIPv6" | "ForceIPv4v6" | "ForceIPv4"

                                      默认值 "AsIs"

                                      当目标地址为域名时,配置相应的值,Freedom 的行为模式如下:

                                      • 当使用 "AsIs" 时,Xray将直接使用系统栈发起连接,优先级与选择IP取决于系统设置。出于一些原因,UDP连接如果使用域名会无视系统设置优先IPv4。
                                      • 当填写其他值时,将使用 Xray-core 内置 DNS 服务器 服务器进行解析。若不存在DNSObject,则使用系统DNS。若有多个符合条件的IP地址时,核心会随机选择一个IP作为目标IP。
                                      • "IPv4" 代表尝试仅使用IPv4进行连接,"IPv4v6" 代表尝试使用IPv4或IPv6连接,但对于双栈域名,使用IPv4。(v4v6调换后同理,不再赘述)
                                      • 当在内置DNS设置了 "queryStrategy" 后,实际行为将会与这个选项取并,只有都被包含的IP类型才会被解析,如 "queryStrategy": "UseIPv4" "domainStrategy": "UseIP",实际上等同于 "domainStrategy": "UseIPv4"
                                      • 当使用 "Use" 开头的选项时,若解析结果不符合要求(如,域名只有IPv4解析结果但使用了UseIPv6),则会回落回AsIs。
                                      • 当使用 "Force" 开头的选项时,若解析结果不符合要求,则该连接会无法建立。

                                      TIP 1

                                      当使用 "UseIP""ForceIP" 模式时,并且 出站连接配置 中指定了 sendThrough 时,Freedom 会根据 sendThrough 的值自动判断所需的 IP 类型,IPv4 或 IPv6。若手动指定了单种IP类型(如UseIPv4),但与 sendThrough 指定的本地地址不匹配,将会导致连接失败。

                                      redirect: address_port

                                      Freedom 会强制将所有数据发送到指定地址(而不是 inbound 指定的地址)。

                                      其值为一个字符串,样例:"127.0.0.1:80"":1234"

                                      当地址不指定时,如 ":443",Freedom 不会修改原先的目标地址。 当端口为 0 时,如 "xray.com: 0",Freedom 不会修改原先的端口。

                                      userLevel: number

                                      用户等级,连接会使用这个用户等级对应的 本地策略

                                      userLevel 的值, 对应 policylevel 的值。 如不指定, 默认为 0。

                                      fragment: map

                                      一些键值对配置项,用于控制发出的 TCP 分片,在某些情况下可以欺骗审查系统,比如绕过 SNI 黑名单。

                                      "packets":支持两种分片方式 "1-3" 是 TCP 的流切片,应用于客户端第 1 至第 3 次写数据。"tlshello" 是 TLS 握手包切片。

                                      "length":分片包长 (byte)

                                      "interval":分片间隔(ms)

                                      当其为 0 且设置 "packets": "tlshello" 时,被分片的 Client Hello 将会在一个TCP包中发送(如果其原始大小未超过MSS或MTU导致被系统自动分片)

                                      noise: array

                                      UDP noise, 用于在发出UDP连接前发出一些随机数据作为“噪声”,出现该结构体则视为启用,可能可以欺骗嗅探器,也可能破坏正常连接。Use at your own risk. 出于这个原因,它会绕过53端口因为这会破坏 DNS

                                      为一个数组,可以定义多个要发出的噪声数据包,数组中单个元素定义如下

                                      "type": 噪声数据包类型,目前支持"rand"(随机数据), "str"(用户自定义字符串), "base64"(base64编码过的自定义二进制数据)

                                      "packet": 基于前面的 type 要发送的数据包内容

                                      • type 为 rand 时,这里指定随机数据的长度 可以是固定值 "100" 或者浮动值 "50-150"
                                      • type 为 str 时,这里指定要发送的字符串
                                      • type 为 base64 时,这里指定base64过的二进制数据

                                      "delay": 延迟,单位毫秒。发送该噪声包后核心会等待该时间后再发送下一个噪声包或真实数据,默认不等待,可以设置为 int 如 100 或者设置为一个字符串类型填入浮动值如 "50-150"

                                      proxyProtocol: number

                                      PROXY protocol 通常配合 redirect 重定向到开启了 PROXY protocol 协议的 Nginx 或其他后端服务中。如果后端服务不支持 PROXY protocol 协议,连接将会被断开。

                                      proxyProtocol 的值为 PROXY protocol 版本号,可选 12,如不指定,默认为 0 不启用。

                                      - + diff --git a/config/outbounds/http.html b/config/outbounds/http.html index 71a9173c9d..2497ff23c3 100644 --- a/config/outbounds/http.html +++ b/config/outbounds/http.html @@ -24,8 +24,8 @@ HTTP | Project X - - + +

                                      HTTP

                                      HTTP 协议。

                                      警告

                                      http 协议没有对传输加密,不适宜经公网中传输,更容易成为被人用作攻击的肉鸡。

                                      提示

                                      http 只能代理 tcp 协议,udp 系的协议均不能通过。

                                      OutboundConfigurationObject

                                      {
                                      @@ -61,6 +61,6 @@
                                         "pass": "my-password"
                                       }
                                       

                                      user: string

                                      用户名,字符串类型。必填。

                                      pass: string

                                      密码,字符串类型。必填。

                                      - + diff --git a/config/outbounds/loopback.html b/config/outbounds/loopback.html index 55bdd53e19..7481d6dd66 100644 --- a/config/outbounds/loopback.html +++ b/config/outbounds/loopback.html @@ -24,8 +24,8 @@ Loopback | Project X - - + + - + diff --git a/config/outbounds/shadowsocks.html b/config/outbounds/shadowsocks.html index 3856458440..53bdfd5958 100644 --- a/config/outbounds/shadowsocks.html +++ b/config/outbounds/shadowsocks.html @@ -24,8 +24,8 @@ Shadowsocks | Project X - - + +

                                      Shadowsocks

                                      Shadowsocksopen in new tag 协议,兼容大部分其它版本的实现。

                                      目前兼容性如下:

                                      • 支持 TCP 和 UDP 数据包转发,其中 UDP 可选择性关闭;
                                      • 推荐的加密方式:
                                        • 2022-blake3-aes-128-gcm
                                        • 2022-blake3-aes-256-gcm
                                        • 2022-blake3-chacha20-poly1305
                                      • 其他加密方式
                                        • aes-256-gcm
                                        • aes-128-gcm
                                        • chacha20-poly1305 或称 chacha20-ietf-poly1305
                                        • xchacha20-poly1305 或称 xchacha20-ietf-poly1305
                                        • none 或 plain

                                      Shadowsocks 2022 新协议格式提升了性能并带有完整的重放保护,解决了旧协议的以下安全问题:

                                      警告

                                      "none" 不加密方式下流量将明文传输。为确保安全性, 不要在公共网络上使用。

                                      OutboundConfigurationObject

                                      {
                                      @@ -53,6 +53,6 @@
                                         "level": 0
                                       }
                                       

                                      email: string

                                      邮件地址,可选,用于标识用户

                                      address: address

                                      Shadowsocks 服务端地址,支持 IPv4、IPv6 和域名。必填。

                                      port: number

                                      Shadowsocks 服务端端口。必填。

                                      method: string

                                      必填。

                                      password: string

                                      必填。

                                      uot: bool

                                      启用udp over tcp

                                      UoTVersion: number

                                      UDP over TCP 的实现版本。

                                      当前可选值:1, 2

                                      • Shadowsocks 2022

                                      使用与 WireGuard 类似的预共享密钥作为密码。

                                      使用 openssl rand -base64 <长度> 以生成与 shadowsocks-rust 兼容的密钥,长度取决于所使用的加密方法。

                                      加密方法密钥长度
                                      2022-blake3-aes-128-gcm16
                                      2022-blake3-aes-256-gcm32
                                      2022-blake3-chacha20-poly130532

                                      在 Go 实现中,32 位密钥始终工作。

                                      • 其他加密方法

                                      任意字符串。不限制密码长度,但短密码会更可能被破解,建议使用 16 字符或更长的密码。

                                      level: number

                                      用户等级,连接会使用这个用户等级对应的 本地策略

                                      level 的值, 对应 policylevel 的值。 如不指定, 默认为 0。

                                      - + diff --git a/config/outbounds/socks.html b/config/outbounds/socks.html index b5d25238c1..88f5a05163 100644 --- a/config/outbounds/socks.html +++ b/config/outbounds/socks.html @@ -24,8 +24,8 @@ Socks | Project X - - + +

                                      Socks

                                      标准 Socks 协议实现,兼容 Socks 5。

                                      警告

                                      Socks 协议没有对传输加密,不适宜经公网中传输

                                      OutboundConfigurationObject

                                      {
                                      @@ -60,6 +60,6 @@
                                         "level": 0
                                       }
                                       

                                      user: string

                                      用户名,字符串类型。必填。

                                      pass: string

                                      密码,字符串类型。必填。

                                      level: number

                                      用户等级,连接会使用这个用户等级对应的 本地策略

                                      userLevel 的值, 对应 policylevel 的值。 如不指定, 默认为 0。

                                      - + diff --git a/config/outbounds/trojan.html b/config/outbounds/trojan.html index 2ce509a680..697949a010 100644 --- a/config/outbounds/trojan.html +++ b/config/outbounds/trojan.html @@ -24,8 +24,8 @@ Trojan | Project X - - + +

                                      Trojan

                                      Trojanopen in new tag 协议

                                      警告

                                      Trojan 被设计工作在正确配置的加密 TLS 隧道

                                      OutboundConfigurationObject

                                      {
                                      @@ -47,6 +47,6 @@
                                         "level": 0
                                       }
                                       

                                      address: address

                                      服务端地址,支持 IPv4、IPv6 和域名。必填。

                                      port: number

                                      服务端端口,通常与服务端监听的端口相同。

                                      password: string

                                      密码. 必填,任意字符串。

                                      email: string

                                      邮件地址,可选,用于标识用户

                                      level: number

                                      用户等级,连接会使用这个用户等级对应的 本地策略

                                      level 的值, 对应 policylevel 的值。 如不指定, 默认为 0。

                                      - + diff --git a/config/outbounds/vless.html b/config/outbounds/vless.html index f2bd87497d..7c4a83101c 100644 --- a/config/outbounds/vless.html +++ b/config/outbounds/vless.html @@ -24,8 +24,8 @@ VLESS(XTLS Vision Seed) | Project X - - + +

                                      VLESS(XTLS Vision Seed)

                                      警告

                                      目前 VLESS 没有自带加密,请用于可靠信道,如 TLS。

                                      VLESS 是一个无状态的轻量传输协议,它分为入站和出站两部分,可以作为 Xray 客户端和服务器之间的桥梁。

                                      VMess 不同,VLESS 不依赖于系统时间,认证方式同样为 UUID。

                                      OutboundConfigurationObject

                                      {
                                      @@ -63,6 +63,6 @@
                                         "level": 0
                                       }
                                       

                                      id: string

                                      VLESS 的用户 ID,可以是任意小于 30 字节的字符串, 也可以是一个合法的 UUID. 自定义字符串和其映射的 UUID 是等价的, 这意味着你将可以这样在配置文件中写 id 来标识同一用户,即

                                      • "id": "我爱🍉老师1314",
                                      • 或写 "id": "5783a3e7-e373-51cd-8642-c83782b807c5" (此 UUID 是 我爱🍉老师1314 的 UUID 映射)

                                      其映射标准在 VLESS UUID 映射标准:将自定义字符串映射为一个 UUIDv5open in new tag

                                      你可以使用命令 xray uuid -i "自定义字符串" 生成自定义字符串所映射的的 UUID,也可以使用命令 xray uuid 生成随机的 UUID。

                                      encryption: "none"

                                      需要填 "none",不能留空。

                                      该要求是为了提醒使用者没有加密,也为了以后出加密方式时,防止使用者填错属性名或填错位置导致裸奔。

                                      若未正确设置 encryption 的值,使用 Xray 或 -test 时会收到错误信息。

                                      flow: string

                                      流控模式,用于选择 XTLS 的算法。

                                      目前出站协议中有以下流控模式可选:

                                      • flow 或者 空字符: 使用普通 TLS 代理
                                      • xtls-rprx-vision:使用新 XTLS 模式 包含内层握手随机填充 支持 uTLS 模拟客户端指纹
                                      • xtls-rprx-vision-udp443:同 xtls-rprx-vision, 但是不会拦截目标为 443 端口的 UDP 流量

                                      此外,目前 XTLS 仅支持 TCP+TLS/Reality。

                                      关于 xtls-rprx-*-udp443 流控模式

                                      启用了 Xray-core 的 XTLS 时,通往 UDP 443 端口的流量默认会被拦截(一般情况下为 QUIC),这样应用就不会使用 QUIC 而会使用 TLS,XTLS 才会真正生效。实际上,QUIC 本身也不适合被代理,因为 QUIC 自带了 TCP 的功能,它作为 UDP 流量在通过 VLESS 协议传输时,底层协议为 TCP,就相当于两层阻塞控制了。

                                      若不需要拦截,请在客户端填写 xtls-rprx-*-udp443,服务端不变。

                                      关于 Splice 模式

                                      Splice 是 Linux Kernel 提供的函数,系统内核直接转发 TCP,不再经过 Xray 的内存,大大减少了数据拷贝、CPU 上下文切换的次数。

                                      Splice 模式的的使用限制:

                                      • Linux 环境
                                      • 入站协议为 Dokodemo doorSocksHTTP 等纯净的 TCP 连接, 或其它使用了 XTLS 的入站协议
                                      • 出站协议为 VLESS + XTLS

                                      此外,使用 Splice 时网速显示会滞后,这是特性,不是 bug。

                                      使用 Vision 模式 如果满足上述条件 会自动启用 Splice

                                      level: number

                                      用户等级,连接会使用这个用户等级对应的 本地策略

                                      level 的值, 对应 policylevel 的值。 如不指定, 默认为 0。

                                      - + diff --git a/config/outbounds/vmess.html b/config/outbounds/vmess.html index 623b328048..96e47d495f 100644 --- a/config/outbounds/vmess.html +++ b/config/outbounds/vmess.html @@ -24,8 +24,8 @@ VMess | Project X - - + +

                                      VMess

                                      VMess 是一个加密传输协议,通常作为 Xray 客户端和服务器之间的桥梁。

                                      警告

                                      VMess 依赖于系统时间,请确保使用 Xray 的系统 UTC 时间误差在 120 秒之内,时区无关。在 Linux 系统中可以安装ntp服务来自动同步系统时间。

                                      OutboundConfigurationObject

                                      {
                                      @@ -56,6 +56,6 @@
                                         "experiments": ""
                                       }
                                       

                                      id:string

                                      Vmess 的用户 ID,可以是任意小于 30 字节的字符串, 也可以是一个合法的 UUID.

                                      自定义字符串和其映射的 UUID 是等价的, 这意味着你将可以这样在配置文件中写 id 来标识同一用户,即

                                      • "id": "我爱🍉老师1314",
                                      • 或写 "id": "5783a3e7-e373-51cd-8642-c83782b807c5" (此 UUID 是 我爱🍉老师1314 的 UUID 映射)

                                      其映射标准在 VLESS UUID 映射标准:将自定义字符串映射为一个 UUIDv5open in new tag

                                      你可以使用命令 xray uuid -i "自定义字符串" 生成自定义字符串所映射的的 UUID, 也可以使用命令 xray uuid 生成随机的 UUID。

                                      level: number

                                      用户等级,连接会使用这个用户等级对应的 本地策略

                                      level 的值, 对应 policylevel 的值。 如不指定, 默认为 0。

                                      security: "aes-128-gcm" | "chacha20-poly1305" | "auto" | "none" | "zero"

                                      加密方式,客户端将使用配置的加密方式发送数据,服务器端自动识别,无需配置。

                                      • "aes-128-gcm":推荐在 PC 上使用
                                      • "chacha20-poly1305":推荐在手机端使用
                                      • "auto":默认值,自动选择(运行框架为 AMD64、ARM64 或 s390x 时为 aes-128-gcm 加密方式,其他情况则为 Chacha20-Poly1305 加密方式)
                                      • "none":不加密
                                      • "zero":不加密,也不进行消息认证 (v1.4.0+)

                                      提示

                                      推荐使用"auto"加密方式,这样可以永久保证安全性和兼容性。

                                      "none" 伪加密方式会计算并验证数据包的校验数据,由于认证算法没有硬件支持,在部分平台可能速度比有硬件加速的 "aes-128-gcm" 还慢。

                                      "zero" 伪加密方式不会加密消息也不会计算数据的校验数据,因此理论上速度会高于其他任何加密方式。实际速度可能受到其他因素影响。

                                      不推荐在未开启 TLS 加密并强制校验证书的情况下使用 "none" "zero" 伪加密方式。 如果使用 CDN 或其他会解密 TLS 的中转平台或网络环境建立连接,不建议使用 "none" "zero" 伪加密方式。

                                      无论使用哪种加密方式, VMess 的包头都会受到加密和认证的保护。

                                      experiments: string

                                      启用的 VMess 协议实验性功能。(此处的功能为不稳定功能, 可能随时被移除)多个启用的实验之间可以用 | 字符分割,如 "AuthenticatedLength|NoTerminationSignal" 。

                                      "AuthenticatedLength" 启用认证的数据包长度实验。此实验需要同时在客户端与服务器端同时开启,并运行相同版本的程序。

                                      "NoTerminationSignal" 启用不发送断开连接标致实验。此实验可能会影响被代理的连接的稳定性。

                                      - + diff --git a/config/outbounds/wireguard.html b/config/outbounds/wireguard.html index 90eccd9585..f7fa421852 100644 --- a/config/outbounds/wireguard.html +++ b/config/outbounds/wireguard.html @@ -24,8 +24,8 @@ Wireguard | Project X - - + +

                                      Wireguard

                                      标准 Wireguard 协议实现。

                                      警告

                                      Wireguard 协议并非专门为翻墙而设计,若在最外层过墙,存在特征可能导致服务器被封锁

                                      OutboundConfigurationObject

                                      {
                                      @@ -77,6 +77,6 @@
                                         "allowedIPs": ["0.0.0.0/0"] // optional, default ["0.0.0.0/0", "::/0"]
                                       }
                                       

                                      endpoint: address

                                      服务器地址, 必填

                                      URL:端口 格式,例如 engage.cloudflareclient.com:2408
                                      IP:端口 格式,例如 162.159.192.1:2408[2606:4700:d0::a29f:c001]:2408

                                      提示

                                      当目标地址类型为 URL 时,将使用 Xray-core 内置 DNS 查询 URL 以获取 IP,IPv4 或 IPv6 优先级由 domainStrategy 的值控制。
                                      若没写 "dns" 配置,使用系统 DNS 查询 URL 以获取 IP,IPv4 或 IPv6 优先级由系统控制。

                                      publicKey: string

                                      服务器公钥,用于验证, 必填

                                      preSharedKey: string

                                      额外的对称加密密钥

                                      keepAlive: int

                                      心跳包时间间隔,单位为秒,默认为 0 表示无心跳

                                      allowedIPs: string array

                                      Wireguard 仅允许特定源 IP 的流量

                                      - + diff --git a/config/policy.html b/config/policy.html index 3a72458ce1..a6f84ca55d 100644 --- a/config/policy.html +++ b/config/policy.html @@ -24,8 +24,8 @@ 本地策略 | Project X - - + +

                                      本地策略

                                      本地策略,可以设置不同的用户等级和对应的策略设置,比如连接超时设置。Xray 处理的每一个连接都对应一个用户,按照用户的等级(level)应用不同的策略。

                                      PolicyObject

                                      PolicyObject 对应配置文件的 policy 项。

                                      {
                                      @@ -65,6 +65,6 @@
                                         "statsOutboundDownlink": false
                                       }
                                       

                                      statsInboundUplink: true | false

                                      当值为 true 时,开启所有入站代理的上行流量统计。

                                      statsInboundDownlink: true | false

                                      当值为 true 时,开启所有入站代理的下行流量统计。

                                      statsOutboundUplink: true | false

                                      当值为 true 时,开启所有出站代理的上行流量统计。

                                      statsOutboundDownlink: true | false

                                      当值为 true 时,开启所有出站代理的下行流量统计。

                                      - + diff --git a/config/reverse.html b/config/reverse.html index 5f73a57c96..8a9651d69c 100644 --- a/config/reverse.html +++ b/config/reverse.html @@ -24,8 +24,8 @@ 反向代理 | Project X - - + +

                                      反向代理

                                      反向代理可以把服务器端的流量向客户端转发,即逆向流量转发。

                                      反向代理的大致工作原理如下:

                                      • 假设在主机 A 中有一个网页服务器,这台主机没有公网 IP,无法在公网上直接访问。另有一台主机 B,它可以由公网访问。现在我们需要把 B 作为入口,把流量从 B 转发到 A。
                                      • 在主机 A 中配置 Xray,称为bridge,在 B 中也配置 Xray,称为 portal
                                      • bridge 会向 portal 主动建立连接,此连接的目标地址可以自行设定。portal 会收到两种连接,一是由 bridge 发来的连接,二是公网用户发来的连接。portal 会自动将两类连接合并。于是 bridge 就可以收到公网流量了。
                                      • bridge 在收到公网流量之后,会将其原封不动地发给主机 A 中的网页服务器。当然,这一步需要路由的协作。
                                      • bridge 会根据流量的大小进行动态的负载均衡。

                                      提示

                                      反向代理默认已开启 Mux,请不要在其用到的 outbound 上再次开启 Mux。

                                      注意

                                      反向代理功能尚处于测试阶段,可能会有一些问题。

                                      ReverseObject

                                      ReverseObject 对应配置文件的 reverse 项。

                                      {
                                      @@ -144,6 +144,6 @@
                                         ]
                                       }
                                       
                                      - + diff --git a/config/routing.html b/config/routing.html index a642991434..13033e9b60 100644 --- a/config/routing.html +++ b/config/routing.html @@ -24,8 +24,8 @@ 路由 | Project X - - + +

                                      路由

                                      路由功能模块可以将入站数据按不同规则由不同的出站连接发出,以达到按需代理的目的。

                                      如常见用法是分流国内外流量,Xray 可以通过内部机制判断不同地区的流量,然后将它们发送到不同的出站代理。

                                      有关路由功能更详细的解析:路由 (routing) 功能简析

                                      RoutingObject

                                      RoutingObject 对应配置文件的 routing 项。

                                      {
                                      @@ -103,6 +103,6 @@
                                               }
                                           ]
                                       

                                      预定义域名列表

                                      此列表预置于每一个 Xray 的安装包中,文件名为 geosite.dat。这个文件包含了一些常见的域名,使用方式:geosite:filename,如 geosite:google 表示对文件内符合 google 内包含的域名,进行路由筛选或 DNS 筛选。

                                      常见的域名有:

                                      • category-ads:包含了常见的广告域名。
                                      • category-ads-all:包含了常见的广告域名,以及广告提供商的域名。
                                      • cn:相当于 geolocation-cntld-cn 的合集。
                                      • apple:包含了 Apple 旗下绝大部分域名。
                                      • google:包含了 Google 旗下绝大部分域名。
                                      • microsoft:包含了 Microsoft 旗下绝大部分域名。
                                      • facebook:包含了 Facebook 旗下绝大部分域名。
                                      • twitter:包含了 Twitter 旗下绝大部分域名。
                                      • telegram:包含了 Telegram 旗下绝大部分域名。
                                      • geolocation-cn:包含了常见的大陆站点域名。
                                      • geolocation-!cn:包含了常见的非大陆站点域名。
                                      • tld-cn:包含了 CNNIC 管理的用于中国大陆的顶级域名,如以 .cn.中国 结尾的域名。
                                      • tld-!cn:包含了非中国大陆使用的顶级域名,如以 .tw(台湾)、.jp(日本)、.sg(新加坡)、.us(美国).ca(加拿大)等结尾的域名。

                                      你也可以在这里查看完整的域名列表 Domain list communityopen in new tag

                                      - + diff --git a/config/stats.html b/config/stats.html index 499261a925..8ea3d5b7d0 100644 --- a/config/stats.html +++ b/config/stats.html @@ -24,14 +24,14 @@ 统计信息 | Project X - - + +

                                      统计信息

                                      用于配置 Xray 流量数据的统计。

                                      StatsObject

                                      StatsObject 对应配置文件的 stats 项。

                                      {
                                         "stats": {}
                                       }
                                       

                                      目前统计信息不需要任何参数,只要 StatsObject 项存在,内部的统计即会开启。

                                      开启了统计以后, 只需在 Policy 中开启对应的项,就可以统计对应的数据。

                                      获取统计信息

                                      可以用 xray api 的相关命令获取统计信息.

                                      目前已有的统计信息如下:

                                      • 用户数据

                                        • user>>>[email]>>>traffic>>>uplink

                                          特定用户的上行流量,单位字节。

                                        • user>>>[email]>>>traffic>>>downlink

                                          特定用户的下行流量,单位字节。

                                      提示

                                      如果对应用户没有指定 Email,则不会开启统计。

                                      • 全局数据

                                        • inbound>>>[tag]>>>traffic>>>uplink

                                          特定 inbound 的上行流量,单位字节。

                                        • inbound>>>[tag]>>>traffic>>>downlink

                                          特定 inbound 的下行流量,单位字节。

                                        • outbound>>>[tag]>>>traffic>>>uplink

                                          特定 outbound 的上行流量,单位字节。

                                        • outbound>>>[tag]>>>traffic>>>downlink

                                          特定 outbound 的下行流量,单位字节。

                                      - + diff --git a/config/transport.html b/config/transport.html index 8628bd49f4..610469d308 100644 --- a/config/transport.html +++ b/config/transport.html @@ -24,8 +24,8 @@ 传输方式(uTLS、REALITY) | Project X - - + +

                                      传输方式(uTLS、REALITY)

                                      传输方式(transport)是当前 Xray 节点和其它节点对接的方式。

                                      传输方式指定了稳定的数据传输的方式。通常来说,一个网络连接的两端需要有对称的传输方式。比如一端用了 WebSocket,那么另一个端也必须使用 WebSocket,否则无法建立连接。

                                      StreamSettingsObject

                                      StreamSettingsObject 对应入站或出站中的 streamSettings 项。每一个入站或出站都可以分别配置不同的传输配置,都可以设置 streamSettings 来进行一些传输的配置。

                                      {
                                      @@ -173,6 +173,6 @@
                                         }
                                       ]
                                       

                                      type: ""

                                      必填,设置的类型,目前可选int或str.

                                      level: ""

                                      可选,协议级别,用于指定生效范围,默认为6, 即TCP.

                                      opt: ""

                                      操作的选项名称,使用十进制(此处示例为 TCP_CONGESTION 的值 定义为 0xd 转换为10进制即为13)

                                      value: ""

                                      要设置的选项值,此处示例为设置为bbr.

                                      当 type 指定为 int 时需要使用十进制数字。

                                      最近更改:
                                      Contributors: 风扇滑翔翼, JimhHan, xqzr, Jim Han, yuhan6665, ちか, mmmray, tdjnodj, Binbin Qian, Chuei Kan, Daniel Ding, Kobe Arthur Scofield, KoriIku, Lumière Élevé, Mikhail Samodurov, WaterLemons2k, Winston2084, Yang Lu, chika0801, flowerinsnow, lelemka0, lxsq, mayampi01, pvqogw
                                      - + diff --git a/config/transports/grpc.html b/config/transports/grpc.html index 641f0d7334..f8e6c15eea 100644 --- a/config/transports/grpc.html +++ b/config/transports/grpc.html @@ -24,8 +24,8 @@ gRPC | Project X - - + +

                                      gRPC

                                      基于 gRPC 的传输方式。

                                      它基于 HTTP/2 协议,理论上可以通过其它支持 HTTP/2 的服务器(如 Nginx)进行中转。 gRPC(HTTP/2)内置多路复用,不建议使用 gRPC 与 HTTP/2 时启用 mux.cool。

                                      ⚠⚠⚠

                                      • gRPC 不支持指定 Host。请在出站代理地址中填写 正确的域名 ,或在 (x)tlsSettings 中填写 ServerName,否则无法连接。
                                      • gRPC 不支持回落到其他服务。
                                      • gRPC 服务存在被主动探测的风险。建议使用 Caddy 或 Nginx 等反向代理工具,通过 Path 前置分流。

                                      提示

                                      如果您使用 Caddy 或 Nginx 等反向代理,请注意下列事项:

                                      • 请确定反向代理服务器开启了 HTTP/2
                                      • 请使用 HTTP/2 或 h2c (Caddy),grpc_pass (Nginx) 连接到 Xray。
                                      • 普通模式的 Path 为 /${serviceName}/Tun, Multi 模式为 /${serviceName}/TunMulti
                                      • 如果需要接收客户端 IP,可以通过由 Caddy / Nginx 发送 X-Real-IP header 来传递客户端 IP。

                                      提示

                                      如果你正在使用回落,请注意下列事项:

                                      • 不建议回落到 gRPC,存在被主动探测的风险。
                                      • 请确认h2 位于 (x)tlsSettings.alpn 中的第一顺位,否则 gRPC(HTTP/2)可能无法完成 TLS 握手。
                                      • gRPC 无法通过进行 Path 分流。

                                      GRPCObject

                                      GRPCObject 对应传输配置的 grpcSettings 项。

                                      {
                                      @@ -39,6 +39,6 @@
                                         "initial_windows_size": 0
                                       }
                                       

                                      authority: string

                                      一个字符串,可以当 Host 来用,实现一些其它用途。

                                      serviceName: string

                                      一个字符串,指定服务名称,类似于 HTTP/2 中的 Path。 客户端会使用此名称进行通信,服务端会验证服务名称是否匹配。

                                      提示

                                      serviceName 起始为斜杠时可以自定义 path,至少要两个斜杠。
                                      例如在服务端填写 "serviceName": "/my/sample/path1|path2",客户端可填写 "serviceName": "/my/sample/path1""/my/sample/path2"

                                      user_agent: string

                                      提示

                                      只需出站客户端)配置。

                                      设置 gRPC 的用户代理,可能能防止某些 CDN 阻止 gRPC 流量。

                                      multiMode: true | false BETA

                                      true 启用 multiMode,默认值为: false

                                      这是一个 实验性 选项,可能不会被长期保留,也不保证跨版本兼容。此模式在 测试环境中 能够带来约 20% 的性能提升,实际效果因传输速率不同而不同。

                                      提示

                                      只需出站客户端)配置。

                                      idle_timeout: number

                                      单位秒,当这段时间内没有数据传输时,将会进行健康检查。如果此值设置为 10 以下,将会使用 10,即最小值。

                                      提示

                                      如果没有使用 Caddy 或 Nginx 等反向代理工具(通常不会),设为 60 以下,服务端可能发送意外的 h2 GOAWAY 帧以关闭现有连接。

                                      健康检查默认不启用

                                      提示

                                      只需出站客户端)配置。

                                      提示

                                      可能会解决一些“断流”问题。

                                      health_check_timeout: number

                                      单位秒,健康检查的超时时间。如果在这段时间内没有完成健康检查,且仍然没有数据传输时,即认为健康检查失败。默认值为 20

                                      提示

                                      只需出站客户端)配置。

                                      permit_without_stream: true | false

                                      true 允许在没有子连接时进行健康检查。默认值为 false

                                      提示

                                      只需出站客户端)配置。

                                      initial_windows_size: number

                                      h2 Stream 初始窗口大小。当值小于等于 0 时,此功能不生效。当值大于 65535 时,动态窗口机制(Dynamic Window)会被禁用。默认值为 0,即不生效。

                                      提示

                                      只需出站客户端)配置。

                                      提示

                                      通过 Cloudflare CDN 时,可将值设为 65536 及以上,即禁用动态窗口机制(Dynamic Window),可防止 Cloudflare CDN 发送意外的 h2 GOAWAY 帧以关闭现有连接。

                                      - + diff --git a/config/transports/h2.html b/config/transports/h2.html index 2fe074f5b4..fdcb554d59 100644 --- a/config/transports/h2.html +++ b/config/transports/h2.html @@ -24,8 +24,8 @@ HTTP/2 | Project X - - + +

                                      HTTP/2

                                      基于 HTTP/2 的传输方式。

                                      它完整按照 HTTP/2 标准实现,可以通过其它的 HTTP 服务器(如 Nginx)进行中转。

                                      由 HTTP/2 的建议,客户端和服务器必须同时开启 TLS 才可以正常使用这个传输方式。

                                      HTTP/2 内置多路复用,不建议使用 HTTP/2 时启用 mux.cool。

                                      提示

                                      当前版本的 HTTP/2 的传输方式并不强制要求入站服务端)有 TLS 配置. 这使得可以在特殊用途的分流部署环境中,由外部网关组件完成 TLS 层对话,Xray 作为后端应用,网关和 Xray 间使用称为 h2c 的明文 http/2 进行通讯。

                                      注意

                                      ⚠️ 如果你正在使用回落,请注意下列事项:

                                      • 请确认 (x)tlsSettings.alpn 中包含 h2,否则 HTTP/2 无法完成 TLS 握手。
                                      • HTTP/2 无法通过 Path 进行分流,建议使用 SNI 分流。

                                      HttpObject

                                      HttpObject 对应传输配置的 httpSettings 项。

                                      {
                                      @@ -39,6 +39,6 @@
                                         }
                                       }
                                       

                                      host: [string]

                                      一个字符串数组,每一个元素是一个域名。

                                      客户端会随机从列表中选出一个域名进行通信,服务器会验证域名是否在列表中。

                                      提示

                                      若不写 "httpSettings""host": [] 值留空时,会使用默认值 "www.example.com",需要两端 "host" 值一致才能连接成功。"host": [""] 不是值留空。

                                      path: string

                                      HTTP 路径,由 / 开头, 客户端和服务器必须一致。

                                      默认值为 "/"

                                      read_idle_timeout: number

                                      单位秒,当这段时间内没有接收到数据时,将会进行健康检查。

                                      健康检查默认不启用

                                      提示

                                      只需出站客户端)配置。

                                      提示

                                      可能会解决一些“断流”问题。

                                      health_check_timeout: number

                                      单位秒,健康检查的超时时间。如果在这段时间内没有完成健康检查,即认为健康检查失败。默认值为 15

                                      提示

                                      只需出站客户端)配置。

                                      method: string

                                      HTTP 方法。默认值为 "PUT"

                                      设置时应参照此处open in new tag列出值。

                                      headers: map{ string: [string] }

                                      仅客户端,自定义 HTTP 头,一个键值对,每个键表示一个 HTTP 头名称,对应值为一个数组。

                                      - + diff --git a/config/transports/httpupgrade.html b/config/transports/httpupgrade.html index 9c8209a19f..487bf5eec5 100644 --- a/config/transports/httpupgrade.html +++ b/config/transports/httpupgrade.html @@ -24,8 +24,8 @@ HTTPUpgrade | Project X - - + +

                                      HTTPUpgrade

                                      一个实现了类似于 WebSocket 进行 HTTP 1.1 升级请求和响应的协议,这使得它可以像 WebSocket 一样可以被CDN或者Nginx进行反代,但无需实现 WebSocket 协议的其他部分,所以具有更高的效率。 其设计不推荐单独使用,而是和TLS等安全协议一起工作。

                                      HttpUpgradeObject

                                      HttpUpgradeObject 对应传输配置的 httpupgradeSettings 项。

                                      {
                                      @@ -37,6 +37,6 @@
                                         }
                                       }
                                       

                                      acceptProxyProtocol: true | false

                                      仅用于 inbound,指示是否接收 PROXY protocol。

                                      PROXY protocolopen in new tag 专用于传递请求的真实来源 IP 和端口,若你不了解它,请先忽略该项

                                      常见的反代软件(如 HAProxy、Nginx)都可以配置发送它,VLESS fallbacks xver 也可以发送它。

                                      填写 true 时,最底层 TCP 连接建立后,请求方必须先发送 PROXY protocol v1 或 v2,否则连接会被关闭。

                                      path: string

                                      HTTPUpgrade 所使用的 HTTP 协议路径,默认值为 "/"

                                      如果客户端路径中包含 ed 参数(如 /mypath?ed=2560),将会启用 Early Data 以降低延迟,其值为首包长度阈值。如果首包长度超过此值,就不会启用 Early Data。建议的值为2560。

                                      host: string

                                      HTTPUpgrade 的HTTP请求中所发送的host,默认值为空。若服务端值为空时,不验证客户端发送来的host值。

                                      当在服务端指定该值,或在 headers 中指定host,将会校验与客户端请求host是否一致。

                                      客户端选择发送的host优先级 host > headers > address

                                      headers: map {string: string}

                                      仅客户端,自定义 HTTP 头,一个键值对,每个键表示一个 HTTP 头的名称,对应的值是字符串。

                                      默认值为空。

                                      - + diff --git a/config/transports/mkcp.html b/config/transports/mkcp.html index 9b56a909c1..f9850ee3de 100644 --- a/config/transports/mkcp.html +++ b/config/transports/mkcp.html @@ -24,8 +24,8 @@ mKCP | Project X - - + +

                                      mKCP

                                      mKCP 使用 UDP 来模拟 TCP 连接。

                                      mKCP 牺牲带宽来降低延迟。传输同样的内容,mKCP 一般比 TCP 消耗更多的流量。

                                      提示

                                      请确定主机上的防火墙配置正确

                                      KcpObject

                                      KcpObject 对应传输配置的 kcpSettings 项。

                                      {
                                      @@ -47,6 +47,6 @@
                                         "domain": "example.com"
                                       }
                                       

                                      type: string

                                      伪装类型,可选的值有:

                                      • "none":默认值,不进行伪装,发送的数据是没有特征的数据包。
                                      • "srtp":伪装成 SRTP 数据包,会被识别为视频通话数据(如 FaceTime)。
                                      • "utp":伪装成 uTP 数据包,会被识别为 BT 下载数据。
                                      • "wechat-video":伪装成微信视频通话的数据包。
                                      • "dtls":伪装成 DTLS 1.2 数据包。
                                      • "wireguard":伪装成 WireGuard 数据包。(并不是真正的 WireGuard 协议)
                                      • "dns":某些校园网在未登录的情况下允许DNS查询,给KCP添加DNS头,把流量伪装成dns请求,可以绕过某些校园网登录。

                                      domain: string

                                      配合伪装类型 "dns" 使用,可随便填一个域名。

                                      鸣谢

                                      对 KCP 协议的改进

                                      更小的协议头

                                      原生 KCP 协议使用了 24 字节的固定头部,而 mKCP 修改为数据包 18 字节,确认(ACK)包 16 字节。更小的头部有助于躲避特征检查,并加快传输速度。

                                      另外,原生 KCP 的单个确认包只能确认一个数据包已收到,也就是说当 KCP 需要确认 100 个数据已收到时,它会发出 24 * 100 = 2400 字节的数据。其中包含了大量重复的头部数据,造成带宽的浪费。mKCP 会对多个确认包进行压缩,100 个确认包只需要 16 + 2 + 100 * 4 = 418 字节,相当于原生的六分之一。

                                      确认包重传

                                      原生 KCP 协议的确认(ACK)包只发送一次,如果确认包丢失,则一定会导致数据重传,造成不必要的带宽浪费。而 mKCP 会以一定的频率重发确认包,直到发送方确认为止。单个确认包的大小为 22 字节,相比起数据包的 1000 字节以上,重传确认包的代价要小得多。

                                      连接状态控制

                                      mKCP 可以有效地开启和关闭连接。当远程主机主动关闭连接时,连接会在两秒钟之内释放;当远程主机断线时,连接会在最多 30 秒内释放。

                                      原生 KCP 不支持这个场景。

                                      - + diff --git a/config/transports/splithttp.html b/config/transports/splithttp.html index 72e84a1d4f..310345e43d 100644 --- a/config/transports/splithttp.html +++ b/config/transports/splithttp.html @@ -24,8 +24,8 @@ SplitHTTP(H2、QUIC H3) | Project X - - + +

                                      SplitHTTP(H2、QUIC H3)

                                      v1.8.16+

                                      使用HTTP分块传输编码流式响应处理下载,使用多个HTTP POST请求进行上传。

                                      可以通过不支持WebSocket的CDN上,但仍有一些要求:

                                      • CDN必须支持HTTP分块传输,且支持流式响应而不会缓冲,核心将会发送各种信息以告知CDN,但是需要CDN遵守。如果中间盒不支持流式响应而导致连接被挂起,则该传输很可能无法工作。

                                      目的与V2fly Meek相同,由于使用了流式响应处理下载,下行速率更为优秀,上行也经过优化但仍非常有限,也因此对 HTTP 中间盒要求更高(见上)。

                                      SplitHTTP 也接受 X-Forwarded-For header。

                                      SplitHttpObject

                                      The SplitHttpObject 对应传输配置的 splithttpSettings 项。

                                      {
                                      @@ -40,13 +40,13 @@
                                         "noSSEHeader": false,
                                         "xPaddingBytes": "100-1000",
                                         "xmux": {
                                      -    "maxConnections": 0,
                                           "maxConcurrency": 0,
                                      +    "maxConnections": 0,
                                           "cMaxReuseTimes": 0,
                                           "cMaxLifetimeMs": 0
                                         }
                                       }
                                      -

                                      path: string

                                      SplitHTTP 所使用的 HTTP 协议路径,默认值为 "/"

                                      host: string

                                      SplitHTTP 的HTTP请求中所发送的host,默认值为空。若服务端值为空时,不验证客户端发送来的host值。

                                      当在服务端指定该值,或在 headers 中指定host,将会校验与客户端请求host是否一致。

                                      客户端选择发送的host优先级 host > headers > address

                                      headers: map {string: string}

                                      仅客户端,自定义 HTTP 头,一个键值对,每个键表示一个 HTTP 头的名称,对应的值是字符串。

                                      scMaxEachPostBytes: int/string

                                      上传分块的最大大小,单位为字节,默认值为 1000000, 即 1MB.

                                      客户端设置的大小必须低于该值,否则当发送的 POST 请求大于服务端设置的值时,请求会被拒绝。

                                      这个值应该小于CDN或其他HTTP反向代理所允许的最大请求体,否则将抛出 HTTP 413 错误。

                                      也可以是字符串 "500000-1000000" 的形式,核心每次会在范围内随机选择一个值,以减少指纹。

                                      scMaxConcurrentPosts: int/string

                                      单个连接上传post的最大并发数,默认为100.

                                      上传并发同时也受(也主要受) scMinPostsIntervalMs 控制,故该值仅做保险。

                                      客户端实际发起的数量必须低于服务端。(实际情况下由于上述很难达到上限,所以事实上客户端设置的值可以超过服务端,但不建议这么做)

                                      也可以是字符串 "50-100" 的形式,核心每次会在范围内随机选择一个值,以减少指纹。

                                      scMinPostsIntervalMs: int/string

                                      仅客户端,发起POST上传请求的最小间隔。默认值为 30.

                                      也可以是字符串 "10-50" 的形式,核心每次会在范围内随机选择一个值,以减少指纹。

                                      noSSEHeader: bool

                                      仅服务端,不发送 Content-Type: text/event-stream 响应头,默认 false (即会发送)

                                      xPaddingBytes int/string

                                      设置请求(出站)和响应(入站)的填充大小,用于减少请求指纹。单位byte, 默认为 "100-1000" 每次会在该范围中随机选择一个数字。 也可以是单个数字 "200"/200

                                      设置为 -1 将完全禁用填充

                                      xmux

                                      允许用户对 SplitHTTP 在 h2 与 h3 中的多路复用行为进行控制,如不设置,默认行为为将所有请求复用至一条 h2/QUIC 连接。

                                      与 mux.cool 不同,该复用工作于更低的等级,效率可能更好,如果有复用需求建议在此设置,不要启用 mux.cool.

                                      术语解释:

                                      • 流会复用物理连接,像这样 连接1(流1,流2,流3) 连接2(流4,流5,流6) .. 以此类推 在其他地方你可能看到 连接-子连接 这样的描述,都是一样的东西。
                                      • 下述所有字段类型均为 int/string 均支持固定值 16 或浮动值 "8-32" 的写法
                                      • maxConcurrency: 默认值为 0(即无限) 每个连接中复用的流的最大数量,连接中流的数量达到该值后核心会新建更多连接以容纳更多的流,类似于 mux.cool 的 concurrency.

                                      • maxConnections: 默认值为 0(即无限) 要打开的最大连接数,连接达到此值前核心会积极打开连接,对每一条流都新建一个连接,直到达到该值。然后核心会开始复用已经建立的连接。 与 maxConcurrency 冲突。

                                      • cMaxReuseTimes: 默认值为 0(即无限) 一个连接最多被复用几次,当达到该值后核心不会向该连接再分配流,其将在内部最后一条流关闭后断开。

                                      • cMaxLifetimeMs: 默认值为 0(即无限) 一个连接最多可以“存活”多久,当连接打开的时间超过该值后核心不会向该连接再分配流,其将在内部最后一条流关闭后断开。

                                      HTTP 版本

                                      客户端行为

                                      默认情况下,客户端将会默认在未启用 TLS 时使用 http/1.1, 启用 TLS 时,使用 h2.

                                      当启用 TLS 时,允许在 TLS 设置的 alpn 数组内设置 http/1.1 h2 h3 来指定具体的http版本(仅当该数组只有一个元素时生效,若填入多个元素则返回默认行为)

                                      服务端行为

                                      默认情况下,服务端将会默认监听 TCP, 此时可以处理 http/1.1 和 h2 流量。

                                      当启用 TLS 时,允许在 TLS 设置的 alpn 数组内设置 h3, 此时服务端将改为监听 UDP 端口, 处理 h3 流量。

                                      小提示

                                      由于该协议为标准的 HTTP 请求,所以对于 HTTP 版本的转换并不敏感,各种中间盒都可能转换 HTTP 版本。

                                      列如:你希望使用 h3 连接 Cloudflare, 但是Cloudflare 不会使用 h3 回源, 而是使用 http/1.1 或 h2 回源,此时客户端 alpn 应为 h3, 而服务端就不应为 h3, 因为发往服务端的请求不是 h3.

                                      Browser Dialer

                                      如果使用HTTPS,该传输还支持 Browser Dialer

                                      协议细节

                                      讨论详见 #3412open in new tag#3462open in new tag 以下是简述和简要兼容实现要求

                                      1. 使用 GET /<UUID> 开始下载。服务器立即回复 200 OKTransfer Encoding:chunked , 并立即发送一个两字节的有效负载,以强制HTTP中间盒刷新标头。

                                      现阶段服务器会发送以下标头

                                      • X-Accel-Buffering: no 禁用缓冲
                                      • Content-Type: text/event-stream 在部分中间盒中禁用缓冲,可以使用 "noSSEHeader" 选项关闭
                                      • Transfer-Encoding: chunked 分块传输,仅在 HTTP/1.1 中使用
                                      • Cache-Control: no-store to disable any potential response caching. 禁用CDN的缓存
                                      1. 使用 POST /<UUID>/<seq> 开始发送上行数据. seq 作用类似于 TCP 序列号,从0开始,数据包可以被同时发送,服务端必须按序列号将数据重组。序列号不应重置。

                                        客户端可以以任意决定打开上行与下行请求的顺序,任何一种都可以启动会话,但是必须要在30秒内打开 GET 连接,否则会话将被终止。

                                      2. GET 请求将一直保持在打开状态直到连接被终止,服务端和客户端都可以关闭连接。具体行为取决于HTTP版本。

                                      建议:

                                      • 不要期望CDN会正确传输所有标头,这个协议的目的是为了穿透不支持WS的CDN,而这些CDN的行为通常不怎么友好。

                                      • 应当假设所有HTTP连接都不支持流式请求,所以上行连接发送的的每个包的大小应该基于延迟、吞吐量以及中间盒本身的限制考虑(类似TCP的MTU与纳格算法)。

                                      - +

                                      path: string

                                      SplitHTTP 所使用的 HTTP 协议路径,默认值为 "/"

                                      host: string

                                      SplitHTTP 的HTTP请求中所发送的host,默认值为空。若服务端值为空时,不验证客户端发送来的host值。

                                      当在服务端指定该值,或在 headers 中指定host,将会校验与客户端请求host是否一致。

                                      客户端选择发送的host优先级 host > headers > address

                                      headers: map {string: string}

                                      仅客户端,自定义 HTTP 头,一个键值对,每个键表示一个 HTTP 头的名称,对应的值是字符串。

                                      scMaxEachPostBytes: int/string

                                      上传分块的最大大小,单位为字节,默认值为 1000000, 即 1MB.

                                      客户端设置的大小必须低于该值,否则当发送的 POST 请求大于服务端设置的值时,请求会被拒绝。

                                      这个值应该小于CDN或其他HTTP反向代理所允许的最大请求体,否则将抛出 HTTP 413 错误。

                                      也可以是字符串 "500000-1000000" 的形式,核心每次会在范围内随机选择一个值,以减少指纹。

                                      scMaxConcurrentPosts: int/string

                                      单个连接上传post的最大并发数,默认为100.

                                      上传并发同时也受(也主要受) scMinPostsIntervalMs 控制,故该值仅做保险。

                                      客户端实际发起的数量必须低于服务端。(实际情况下由于上述很难达到上限,所以事实上客户端设置的值可以超过服务端,但不建议这么做)

                                      也可以是字符串 "50-100" 的形式,核心每次会在范围内随机选择一个值,以减少指纹。

                                      scMinPostsIntervalMs: int/string

                                      仅客户端,发起POST上传请求的最小间隔。默认值为 30.

                                      也可以是字符串 "10-50" 的形式,核心每次会在范围内随机选择一个值,以减少指纹。

                                      noSSEHeader: bool

                                      仅服务端,不发送 Content-Type: text/event-stream 响应头,默认 false (即会发送)

                                      xPaddingBytes int/string

                                      设置请求(出站)和响应(入站)的填充大小,用于减少请求指纹。单位byte, 默认为 "100-1000" 每次会在该范围中随机选择一个数字。 也可以是单个数字 "200"/200

                                      设置为 -1 将完全禁用填充

                                      xmux

                                      允许用户对 SplitHTTP 在 h2 与 h3 中的多路复用行为进行控制,如不设置,默认行为为将所有请求复用至一条 h2/QUIC 连接。

                                      与 mux.cool 不同,该复用工作于更低的等级,效率可能更好,如果有复用需求建议在此设置,不要启用 mux.cool.

                                      术语解释:

                                      • 流会复用物理连接,像这样 连接1(流1,流2,流3) 连接2(流4,流5,流6) .. 以此类推 在其他地方你可能看到 连接-子连接 这样的描述,都是一样的东西。
                                      • 下述所有字段类型均为 int/string 均支持固定值 16 或浮动值 "8-32" 的写法
                                      • maxConnections: 默认值为 0(即无限) 要打开的最大连接数,连接达到此值前核心会积极打开连接,对每一条流都新建一个连接,直到达到该值。然后核心会开始复用已经建立的连接。 与 maxConcurrency 冲突。

                                      • maxConcurrency: 默认值为 0(即无限) 每个连接中复用的流的最大数量,连接中流的数量达到该值后核心会新建更多连接以容纳更多的流,类似于 mux.cool 的 concurrency.

                                      • cMaxReuseTimes: 默认值为 0(即无限) 一个连接最多被复用几次,当达到该值后核心不会向该连接再分配流,其将在内部最后一条流关闭后断开。

                                      • cMaxLifetimeMs: 默认值为 0(即无限) 一个连接最多可以“存活”多久,当连接打开的时间超过该值后核心不会向该连接再分配流,其将在内部最后一条流关闭后断开。

                                      HTTP 版本

                                      客户端行为

                                      默认情况下,客户端将会默认在未启用 TLS 时使用 http/1.1, 启用 TLS 时,使用 h2.

                                      当启用 TLS 时,允许在 TLS 设置的 alpn 数组内设置 http/1.1 h2 h3 来指定具体的http版本(仅当该数组只有一个元素时生效,若填入多个元素则返回默认行为)

                                      服务端行为

                                      默认情况下,服务端将会默认监听 TCP, 此时可以处理 http/1.1 和 h2 流量。

                                      当启用 TLS 时,允许在 TLS 设置的 alpn 数组内设置 h3, 此时服务端将改为监听 UDP 端口, 处理 h3 流量。

                                      小提示

                                      由于该协议为标准的 HTTP 请求,所以对于 HTTP 版本的转换并不敏感,各种中间盒都可能转换 HTTP 版本。

                                      列如:你希望使用 h3 连接 Cloudflare, 但是Cloudflare 不会使用 h3 回源, 而是使用 http/1.1 或 h2 回源,此时客户端 alpn 应为 h3, 而服务端就不应为 h3, 因为发往服务端的请求不是 h3.

                                      Browser Dialer

                                      如果使用HTTPS,该传输还支持 Browser Dialer

                                      协议细节

                                      讨论详见 #3412open in new tag#3462open in new tag 以下是简述和简要兼容实现要求

                                      1. 使用 GET /<UUID> 开始下载。服务器立即回复 200 OKTransfer Encoding:chunked , 并立即发送一个两字节的有效负载,以强制HTTP中间盒刷新标头。

                                      现阶段服务器会发送以下标头

                                      • X-Accel-Buffering: no 禁用缓冲
                                      • Content-Type: text/event-stream 在部分中间盒中禁用缓冲,可以使用 "noSSEHeader" 选项关闭
                                      • Transfer-Encoding: chunked 分块传输,仅在 HTTP/1.1 中使用
                                      • Cache-Control: no-store to disable any potential response caching. 禁用CDN的缓存
                                      1. 使用 POST /<UUID>/<seq> 开始发送上行数据. seq 作用类似于 TCP 序列号,从0开始,数据包可以被同时发送,服务端必须按序列号将数据重组。序列号不应重置。

                                        客户端可以以任意决定打开上行与下行请求的顺序,任何一种都可以启动会话,但是必须要在30秒内打开 GET 连接,否则会话将被终止。

                                      2. GET 请求将一直保持在打开状态直到连接被终止,服务端和客户端都可以关闭连接。具体行为取决于HTTP版本。

                                      建议:

                                      • 不要期望CDN会正确传输所有标头,这个协议的目的是为了穿透不支持WS的CDN,而这些CDN的行为通常不怎么友好。

                                      • 应当假设所有HTTP连接都不支持流式请求,所以上行连接发送的的每个包的大小应该基于延迟、吞吐量以及中间盒本身的限制考虑(类似TCP的MTU与纳格算法)。

                                      + diff --git a/config/transports/tcp.html b/config/transports/tcp.html index 3e0549f742..251033a6fb 100644 --- a/config/transports/tcp.html +++ b/config/transports/tcp.html @@ -24,8 +24,8 @@ TCP | Project X - - + +

                                      TCP

                                      TCP 传输模式是目前推荐使用的传输模式之一.

                                      可以和各种协议有多种组合模式.

                                      TcpObject

                                      TcpObject 对应传输配置的 tcpSettings 项。

                                      {
                                      @@ -69,6 +69,6 @@
                                         }
                                       }
                                       

                                      version: string

                                      HTTP 版本,默认值为 "1.1"

                                      status: string

                                      HTTP 状态,默认值为 "200"

                                      reason: string

                                      HTTP 状态说明,默认值为 "OK"

                                      headers: map {string, [ string ]}

                                      HTTP 头,一个键值对,每个键表示一个 HTTP 头的名称,对应的值是一个数组。

                                      每次请求会附上所有的键,并随机选择一个对应的值。默认值见上方示例。

                                      - + diff --git a/config/transports/websocket.html b/config/transports/websocket.html index ec0d842e7b..51c7a68c9b 100644 --- a/config/transports/websocket.html +++ b/config/transports/websocket.html @@ -24,8 +24,8 @@ WebSocket | Project X - - + +

                                      WebSocket

                                      使用标准的 WebSocket 来传输数据。

                                      WebSocket 连接可以被其它 HTTP 服务器(如 Nginx)分流,也可以被 VLESS fallbacks path 分流。

                                      提示

                                      Websocket 会识别 HTTP 请求的 X-Forwarded-For 头来覆写流量的源地址,优先级高于 PROXY protocol。

                                      WebSocketObject

                                      WebSocketObject 对应传输配置的 wsSettings 项。

                                      {
                                      @@ -37,6 +37,6 @@
                                         }
                                       }
                                       

                                      acceptProxyProtocol: true | false

                                      仅用于 inbound,指示是否接收 PROXY protocol。

                                      PROXY protocolopen in new tag 专用于传递请求的真实来源 IP 和端口,若你不了解它,请先忽略该项

                                      常见的反代软件(如 HAProxy、Nginx)都可以配置发送它,VLESS fallbacks xver 也可以发送它。

                                      填写 true 时,最底层 TCP 连接建立后,请求方必须先发送 PROXY protocol v1 或 v2,否则连接会被关闭。

                                      path: string

                                      WebSocket 所使用的 HTTP 协议路径,默认值为 "/"

                                      如果客户端路径中包含 ed 参数(如 /mypath?ed=2560),将会启用 Early Data 以降低延迟,在升级的同时使用 Sec-WebSocket-Protocol 头承载首包数据,其值为首包长度阈值。如果首包长度超过此值,就不会启用 Early Data。推荐值为 2560,最大值为8192,过大的值可能导致部分兼容问题,如果遇到兼容性问题,可以尝试调低阈值。

                                      host: string

                                      WebSocket 的HTTP请求中所发送的host,默认值为空。若服务端值为空时,不验证客户端发送来的host值。

                                      当在服务端指定该值,或在 headers 中指定host,将会校验与客户端请求host是否一致。

                                      客户端选择发送的host优先级 host > headers > address

                                      headers: map {string: string}

                                      仅客户端,自定义 HTTP 头,一个键值对,每个键表示一个 HTTP 头的名称,对应的值是字符串。

                                      默认值为空。

                                      Browser Dialer

                                      使用浏览器处理 TLS,详见 Browser Dialer

                                      - + diff --git a/development/index.html b/development/index.html index 40a7982102..49788bfe2d 100644 --- a/development/index.html +++ b/development/index.html @@ -24,11 +24,11 @@ 开发指南 | Project X - - + +

                                      开发指南

                                      编译文档

                                      Xray 支持各种平台, 您可以在多种平台上自行进行交叉编译。

                                      请点击编译文档以查看具体编译相关内容。

                                      设计思路

                                      Xray 内核提供了一个平台,在其之上可以进二次开发。

                                      这个章节阐述了 Xray 的设计目标和架构。

                                      请点击设计思路以了解 Xray 的设计目标和架构。

                                      开发规范

                                      这个章节阐述了获取代码,进行开发,提交 PR 的流程中需要遵循的准则, 以及相关的编码规范。

                                      请点击开发规范查看 Xray 开发中应遵循的准则。

                                      协议详解

                                      Xray 用到了很多种协议, 您可以通过各种途径获得协议的详细描述。

                                      VLESS 协议

                                      VLESS 是一个无状态的轻量传输协议,可以作为 Xray 客户端和服务器之间的桥梁。

                                      VMess 协议

                                      VMess 是一个加密传输协议,可以作为 Xray 客户端和服务器之间的桥梁。

                                      Mux.Cool 协议

                                      Mux.Cool 协议是一个多路复用传输协议,用于在一条已建立的数据流中传输多个各自独立的数据流。

                                      mKCP 协议

                                      mKCP 是流式传输协议,由 KCP 协议open in new tag修改而来,可以按顺序传输任意的数据流。

                                      - + diff --git a/development/intro/compile.html b/development/intro/compile.html index a6c69b54d2..8a23ef8cca 100644 --- a/development/intro/compile.html +++ b/development/intro/compile.html @@ -24,8 +24,8 @@ 编译文档 | Project X - - + +

                                      编译文档

                                      前序工作

                                      Xray 使用 Golangopen in new tag 作为编程语言,你需要先安装最新版本 Golang 才能够编译。

                                      如果你不幸使用 Windows, 请 务必 使用 Powershell

                                      拉取 Xray 源代码

                                      git clone https://github.com/XTLS/Xray-core.git
                                      @@ -40,6 +40,6 @@
                                       
                                       go build -o xray -trimpath -ldflags "-s -w -buildid=" ./main
                                       

                                      上传到服务器后,记得在服务器终端内执行 chmod +x xray

                                      提示

                                      执行 go tool dist list 查看所有支持的系统与架构。

                                      可复现构建:

                                      按照上述步骤,能够编译与 Release 中完全相同的二进制文件。

                                      注意

                                      请先确认您使用的 Golang 版本与编译 Release 的一致。

                                      - + diff --git a/development/intro/design.html b/development/intro/design.html index 1b18351de8..3c074f975d 100644 --- a/development/intro/design.html +++ b/development/intro/design.html @@ -24,11 +24,11 @@ 设计目标 | Project X - - + +

                                      设计目标

                                      • Xray 内核提供了一个平台,支持必要的网络代理功能,在其之上可以进二次开发,以提供更好的用户体验;
                                      • 以跨平台为首要原则,以减少二次开发的成本;

                                      架构

                                      Architecture

                                      内核分为三层:应用层、代理层和传输层。

                                      每一层内包含数个模块,模块间互相独立,同类型的模块可无缝替换。

                                      应用层

                                      应用层包含一些代理层中常用的功能,这些功能被抽象出来,以便在不同的代理模块中复用。

                                      应用层的模块应为纯软件实现,与硬件或平台相关的技术无关。

                                      重要模块列表:

                                      • Dispatcher: 用于把入站代理所接收到的数据,传送给出站代理;
                                      • Router: 路由模块,详见 路由配置
                                      • DNS: 内置的 DNS 服务器模块;
                                      • Proxy Manager: 代理管理器;

                                      代理层

                                      代理层分为两部分:入站代理(Inbound Proxy)和出站代理(Outbound Proxy)。

                                      两部分相互独立,入站代理不依赖于某个特定的出站代理,反之亦然。

                                      入站代理

                                      出站代理

                                      传输层

                                      传输层提供一些网络数据传输相关的工具模块。

                                      - + diff --git a/development/intro/guide.html b/development/intro/guide.html index cdb9924d01..973f275092 100644 --- a/development/intro/guide.html +++ b/development/intro/guide.html @@ -24,8 +24,8 @@ 开发规范 | Project X - - + +

                                      开发规范

                                      基本

                                      版本控制

                                      Project X 的代码被托管在 github 上:

                                      您可以使用 Gitopen in new tag 来获取代码。

                                      分支(Branch)

                                      • 本项目的主干分支为 main,
                                      • 本项目的发布主分支同为 main,
                                      • 需要确保 main 在任一时刻都是可编译,且可正常使用的。
                                      • 如果需要开发新的功能,请新建分支进行开发,在开发完成并且经过充分测试后,合并回主干分支。
                                      • 已经合并入主干且没有必要存在的分支,请删除。

                                      发布(Release)

                                      WIP
                                      • 建立尝鲜版本和稳定版本两个发布通道
                                        • 尝鲜版本,可以为 daily build,主要用于特定情况的测试,尝鲜和获得即时反馈和再改进。
                                        • 稳定版本,为定时更新(比如月更),合并稳定的修改并发布。

                                      引用其它项目

                                      • Golang
                                        • 产品代码建议使用 Golang 标准库和 golang.org/x/open in new tag 下的库;
                                        • 如需引用其它项目,请事先创建 issue 讨论;
                                      • 其它
                                        • 不违反双方的协议,且对项目有帮助的工具,都可以使用。

                                      开发流程

                                      写代码之前

                                      发现任何问题,或对项目有任何想法,请创建 issueopen in new tag 讨论以减少重复劳动和消耗在代码上的时间。

                                      修改代码

                                      • Golang
                                        • 请参考 Effective Goopen in new tag
                                        • 每一次 push 之前,请运行:go generate core/format.go
                                        • 如果需要修改 protobuf,例如增加新配置项,请运行:go generate core/proto.go
                                        • 提交 pull request 之前,建议测试通过:go test ./...
                                        • 提交 pull request 之前,建议新增代码有超过 70% 的代码覆盖率(code coverage);
                                      • 其它
                                        • 请注意代码的可读性。

                                      Pull Request

                                      • 提交 PR 之前,请先运行 git pull https://github.com/XTLS/Xray-core.git 以确保 merge 可顺利进行;
                                      • 一个 PR 只做一件事,如有对多个 bug 的修复,请对每一个 bug 提交一个 PR;
                                      • 由于 Golang 的特殊需求(Package path),Go 项目的 PR 流程和其它项目有所不同,建议流程如下:
                                        1. 先 Fork 本项目,创建你自己的 github.com/<your_name>/Xray-core.git 仓库;
                                        2. 克隆你自己的 Xray 仓库到本地:git clone https://github.com/<your_name>/Xray-core.git
                                        3. 基于 main 分支创建新的分支,例如 git branch issue24 main
                                        4. 在新创建的分支上作修改并提交修改(commit);
                                        5. 在推送(push)修改完成的分支到自己的仓库前,先切换到 main 分支,运行 git pull https://github.com/XTLS/Xray-core.git 拉取最新的远端代码;
                                        6. 如果上一步拉取得到了新的远端代码,则切换到之前自己创建的分支,运行 git rebase main 执行分支合并操作。如遇到文件冲突,则需要解决冲突;
                                        7. 上一步处理完毕后,就可以把自己创建的分支推送到自己的仓库:git push -u origin your-branch
                                        8. 最后,把自己仓库的新推送的分支往 XTLS/Xray-coremain 分支发 PR 即可;
                                        9. 请在 PR 的标题和正文中,完整表述此次 PR 解决的问题 / 新增的功能 / 代码所做的修改的用意等;
                                        10. 耐心等待开发者的回应。

                                      对代码的修改

                                      功能性问题

                                      请提交至少一个测试用例(Test Case)来验证对现有功能的改动。

                                      性能相关

                                      请提交必要的测试数据来证明现有代码的性能缺陷,或是新增代码的性能提升。

                                      新功能

                                      • 如果新增功能对已有功能不影响,请提供可以开启/关闭的开关(如 flag),并使新功能保持默认关闭的状态;
                                      • 大型新功能(比如增加一个新的协议)开发之前,请先提交一个 issue,讨论完毕之后再进行开发。

                                      其它

                                      视具体情况而定。

                                      Xray 编码规范

                                      以下内容适用于 Xray 中的 Golang 代码。

                                      代码结构

                                      Xray-core
                                      @@ -40,6 +40,6 @@
                                       │   ├── vmess
                                       ├── transport  // 传输模块
                                       

                                      编码规范

                                      基本与 Golang 官方所推荐做法一致,有一些例外。写在这里以方便大家熟悉 Golang。

                                      命名

                                      • 文件和目录名尽量使用单个英文单词,比如 hello.go;
                                        • 如果实在没办法,则目录使用连接线/文件名使用下划线连接两个(或多个单词),比如 hello-world/hello_again.go;
                                        • 测试代码使用 _test.go 结尾;
                                      • 类型使用 Pascal 命名法,比如 ConnectionHandler;
                                        • 对缩写不强制小写,即 HTML 不必写成 Html;
                                      • 公开成员变量也使用 Pascal 命名法;
                                      • 私有成员变量使用 小驼峰式命名法open in new tag ,如 privateAttribute
                                      • 为了方便重构,方法建议全部使用 Pascal 命名法;
                                        • 完全私有的类型放入 internal

                                      内容组织

                                      • 一个文件包含一个主要类型,及其相关的私有函数等;
                                      • 测试相关的文件,如 Mock 等工具类,放入 testing 子目录。
                                      - + diff --git a/development/protocols/mkcp.html b/development/protocols/mkcp.html index eedfce2549..676c17a2ff 100644 --- a/development/protocols/mkcp.html +++ b/development/protocols/mkcp.html @@ -24,11 +24,11 @@ mKCP 协议 | Project X - - + +

                                      mKCP 协议

                                      mKCP 是流式传输协议,由 KCP 协议open in new tag 修改而来,可以按顺序传输任意的数据流。

                                      版本

                                      mKCP 没有版本号,不保证版本之间兼容性。

                                      依赖

                                      底层协议

                                      mKCP 是一个基于 UDP 的协议,所有通讯使用 UDP 传输。

                                      函数

                                      • fnv: FNV-1aopen in new tag 哈希函数
                                        • 输入参数为任意长度的字符串;
                                        • 输入出一个 32 位无符号整数;

                                      通讯过程

                                      1. mKCP 将数据流拆成若干个数据包进行发送。一个数据流有一个唯一标识,用以区分不同的数据流。数据流中的每一个数据包都携带了同样的标识。
                                      2. mKCP 没有握手过程,当收到一个数据包时,根据其携带的数据流的标识来判断是否为新的通话,或是正在进行中的通话。
                                      3. 每一个数据包中包含若干个片段(Segment),片段分为三类:数据(Data)、确认(ACK)、心跳(Ping)。每个片段需要单独处理。

                                      数据格式

                                      数据包

                                      4 字节2 字节L 字节
                                      认证信息 A数据长度 L片段部分

                                      其中:

                                      • 认证信息 A = fnv(片段部分),big endian;
                                      • 片段部分可能包含多个片段;

                                      数据片段

                                      2 字节1 字节1 字节4 字节4 字节4 字节2 字节Len 字节
                                      标识 Conv指令 Cmd选项 Opt时间戳 Ts序列号 Sn未确认序列号 Una长度 Len数据

                                      其中:

                                      • 标识 Conv: mKCP 数据流的标识
                                      • 指令 Cmd: 常量 0x01
                                      • 选项 Opt: 可选的值有:
                                        • 0x00: 空选项
                                        • 0x01: 对方已发出所有数据
                                      • 时间戳 Ts: 当前片段从远端发送出来时的时间,big endian
                                      • 序列号 Sn: 该数据片段时数据流中的位置,起始片段的序列号为 0,之后每个新片段按顺序加 1
                                      • 未确认序列号 Una: 远端主机正在发送的,且尚未收到确认的最小的 Sn

                                      确认片段

                                      2 字节1 字节1 字节4 字节4 字节4 字节2 字节Len * 4 字节
                                      标识 Conv指令 Cmd选项 Opt窗口 Wnd下一接收序列号 Sn时间戳 Ts长度 Len已收到的序列号

                                      其中:

                                      • 标识 Conv: mKCP 数据流的标识
                                      • 指令 Cmd: 常量 0x00
                                      • 选项 Opt: 同上
                                      • 窗口 Wnd: 远端主机可以接收的最大序列号
                                      • 下一接收序列号 Sn: 远端主机未收到的数据片段中的最小序列号
                                      • 时间戳 Ts: 远端主机最新收到的数据片段的时间戳,可用于计算延迟
                                      • 已收到的序列号: 每个 4 字节,表示此序列号的数据已经确认收到

                                      注释:

                                      • 远程主机期待收到序列号 [Sn, Wnd) 范围内的数据

                                      心跳片段

                                      2 字节1 字节1 字节4 字节4 字节4 字节
                                      标识 Conv指令 Cmd选项 Opt未确认序列号 Una下一接收序列号 Sn延迟 Rto

                                      其中:

                                      • 标识 Conv: mKCP 数据流的标识
                                      • 指令 Cmd: 可选的值有
                                        • 0x02: 远端主机强行终止会话
                                        • 0x03: 正常心跳
                                      • 选项 Opt: 同上
                                      • 未确认序列号 Una: 同数据片段的 Una
                                      • 下一接收序列号 Sn: 同确认片段的 Sn
                                      • 延迟 Rto: 远端主机自己计算出的延迟
                                      - + diff --git a/development/protocols/muxcool.html b/development/protocols/muxcool.html index 83622d9cba..1d2e3103e5 100644 --- a/development/protocols/muxcool.html +++ b/development/protocols/muxcool.html @@ -24,11 +24,11 @@ Mux.Cool 协议 | Project X - - + +

                                      Mux.Cool 协议

                                      Mux.Cool 协议是一个多路复用传输协议,用于在一条已建立的数据流中传输多个各自独立的数据流。

                                      版本

                                      当前版本是 1 Beta。

                                      依赖

                                      底层协议

                                      Mux.Cool 必须运行在一个已建立的可靠数据流之上。

                                      通讯过程

                                      一个 Mux.Cool 连接中可传输若干个子连接,每个子连接有一个独立的 ID 和状态。传输过程由帧(Frame)组成,每一帧用于传输一个特定的子连接的数据。

                                      客户端行为

                                      当有连接需求时并且没有现有可用的连接时,客户端向服务器发起一个新连接,以下称为“主连接”。

                                      1. 一个主连接可用于发送若干个子连接。客户端可自主决定主连接可承载的子连接数量。
                                      2. 对于一个新的子连接,客户端必须发送状态New以通知服务器建立子连接,然后使用状态Keep来传送数据。
                                      3. 当子连接结束时,客户端发送End状态来通知服务器关闭子连接。
                                      4. 客户端可自行决定何时关闭主连接,但必须确定服务器也同时保持连接。
                                      5. 客户端可使用 KeepAlive 状态来避免服务器关闭主连接。

                                      服务器端行为

                                      当服务器端接收到新的子连接时,服务器应当按正常的连接来处理。

                                      1. 当收到状态End时,服务器端可以关闭对目标地址的上行连接。
                                      2. 在服务器的响应中,必须使用与请求相同的 ID 来传输子连接的数据。
                                      3. 服务器不能使用New状态。
                                      4. 服务器可使用 KeepAlive 状态来避免客户端关闭主连接。

                                      传输格式

                                      Mux.Cool 使用对称传输格式,即客户端和服务器发送和接收相同格式的数据。

                                      帧格式

                                      2 字节L 字节X 字节
                                      元数据长度 L元数据额外数据

                                      元数据

                                      元数据有若干种类型。所有类型的元数据都包含 ID 和 Opt 两项,其含义为:

                                      • ID: 子连接的唯一标识
                                      • Opt:
                                        • D(0x01): 有额外数据

                                      当选项 Opt(D) 开启时,额外数据格式如下:

                                      2 字节X-2 字节
                                      长度 X-2数据

                                      新建子连接 (New)

                                      2 字节1 字节1 字节1 字节2 字节1 字节A 字节8 字节
                                      ID0x01选项 Opt网络类型 N端口地址类型 T地址 AGlobal ID (XUDP)

                                      其中:

                                      • 网络类型 N:
                                        • 0x01:TCP,表示当前子连接的流量应当以 TCP 的方式发送至目标。
                                        • 0x02:UDP,表示当前子连接的流量应当以 UDP 的方式发送至目标。
                                      • 地址类型 T:
                                        • 0x01:IPv4
                                        • 0x02:域名
                                        • 0x03:IPv6
                                      • 地址 A:
                                        • 当 T = 0x01 时,A 为 4 字节 IPv4 地址;
                                        • 当 T = 0x02 时,A 为 1 字节长度(L) + L 字节域名;
                                        • 当 T = 0x03 时,A 为 16 字节 IPv6 地址;
                                      • Global ID (XUDP):
                                        • 客户端计算出 UDP 来源二元组的全局独特 ID,服务端用以确保当 XUDP 断线重连时,仍使用同一个端口与目标通信。

                                      在新建子连接时,若 Opt(D) 开启,则这一帧所带的数据需要被发往目标主机。

                                      保持子连接 (Keep)

                                      TCP

                                      2 字节1 字节1 字节
                                      ID0x02选项 Opt

                                      UDP

                                      2 字节1 字节1 字节1 字节2 字节1 字节A 字节
                                      ID0x02选项 Opt网络类型 N端口地址类型 T地址 A

                                      在保持子连接时,若 Opt(D) 开启,则这一帧所带的数据需要被发往目标主机。 XUDP 在 Opt(D) 之后加 UDP 地址,格式同新建子连接,但没有 Global ID。

                                      关闭子连接 (End)

                                      2 字节1 字节1 字节
                                      ID0x03选项 Opt

                                      在保持子连接时,若 Opt(D) 开启,则这一帧所带的数据需要被发往目标主机。

                                      保持连接 (KeepAlive)

                                      2 字节1 字节1 字节
                                      ID0x04选项 Opt

                                      在保持连接时:

                                      • 若 Opt(D) 开启,则这一帧所带的数据必须被丢弃。
                                      • ID 可为随机值。

                                      应用

                                      Mux.Cool 协议与底层协议无关,理论上可以使用任何可靠的流式连接来传输 Mux.Cool 的协议数据。

                                      在目标导向的协议如 Shadowsocks 和 VMess 协议中,连接建立时必须包含一个指定的地址。 为了保持兼容性,Mux.Cool 协议指定地址为“v1.mux.cool”。即当主连接的目标地址与之匹配时,则进行 Mux.Cool 方式的转发,否则按传统方式进行转发。(注:这是一个程序内的标记,VMess 和 VLESS 并不会在数据包中发送“v1.mux.cool”地址)

                                      - + diff --git a/development/protocols/vless.html b/development/protocols/vless.html index aae1b5a248..51a7bd990b 100644 --- a/development/protocols/vless.html +++ b/development/protocols/vless.html @@ -24,11 +24,11 @@ VLESS 协议 | Project X - - + +

                                      VLESS 协议

                                      VLESS 是一个无状态的轻量传输协议,可以作为 Xray 客户端和服务器之间的桥梁。

                                      Request & Response

                                      1 字节16 字节1 字节M 字节1 字节2 字节1 字节S 字节X 字节
                                      协议版本等价 UUID附加信息长度 M附加信息 ProtoBuf指令端口地址类型地址请求数据
                                      1 字节1 字节N 字节Y 字节
                                      协议版本,与请求的一致附加信息长度 N附加信息 ProtoBuf响应数据

                                      VLESS 早在第二个测试版 ALPHA 2 时就已经是上述结构了(BETA 是第五个测试版):

                                      “响应认证”被替换为“协议版本”并移至最前,使 VLESS 可以升级换代,同时消除了生成伪随机数的开销。混淆相关结构被替换为附加信息(ProtoBuf)并前移,赋予协议本身可扩展性,相关开销也极小(gogo/protobufopen in new tag),若无附加信息则无相关开销。

                                      我一直觉得“响应认证”不是必要的,ALPHA 时为了提升生成随机数的性能,还用 math/rand 替换 crypto/rand,而现在都不需要了。

                                      “协议版本”不仅能起到“响应认证”的作用,还赋予了 VLESS 无痛升级协议结构的能力,带来无限的可能性。 “协议版本”在测试版本中均为 0,正式版本中为 1,以后若有不兼容的协议结构变更则应升级版本。

                                      VLESS 服务端的设计是 switch version,即同时支持所有 VLESS 版本。若需要升级协议版本(可能到不了这一步),推荐的做法是服务端提前一个月支持,一个月后再改客户端。VMess 请求也有协议版本,但它的认证信息在外面,指令部分则高度耦合且有固定加密,导致里面的协议版本毫无意义,服务端也没有进行判断,响应则没有协议版本。Trojan 的协议结构中没有协议版本。

                                      接下来是 UUID,我本来觉得 16 字节有点长,曾经考虑过缩短它,但后来看到 Trojan 用了 56 个可打印字符(56 字节),就彻底打消了这个念头。服务端每次都要验证 UUID,所以性能也很重要:VLESS 的 Validator 经历了多次重构/升级,相较于 VMess,它十分简洁且耗资源很少,可以同时支持非常多的用户,性能也十分强悍,验证速度极快(sync.Map)。API 动态增删用户则更高效顺滑。 https://github.com/XTLS/Xray-core/issues/158

                                      引入 ProtoBuf 是一个创举,等下会详细讲解。“指令”到“地址”的结构目前与 VMess 完全相同,同样支持 Mux。

                                      总体上,ALPHA 2 到 BETA 主要是:结构进化、清理整合、性能提升、更加完善。这些都是一点一滴的,详见 VLESS Changesopen in new tag

                                      ProtoBuf

                                      似乎只有 VLESS 可选内嵌 ProtoBuf,它是一种数据交换格式,信息被紧密编码成二进制,TLV 结构(Tag Length Value)。

                                      起因是我看到一篇文章称 SS 有一些缺点,如没有设计错误回报机制,客户端没办法根据不同的错误采取进一步的动作。 (但我并不认同所有错误都要回报,不然防不了主动探测。下一个测试版中,服务器可以返回一串自定义信息。) 于是想到一个可扩展的结构是很重要的,未来它也可以承载如动态端口指令。不止响应,请求也需要类似的结构。 本来打算自己设计 TLV,接着发觉 ProtoBuf 就是此结构、现成的轮子,完全适合用来做这件事,各语言支持等也不错。

                                      目前“附加信息”只有 Scheduler 和 SchedulerV,它们是 MessName 和 MessSeed 的替代者,当你不需要它们时,“附加信息长度”为 0,也就不会有 ProtoBuf 序列化/反序列化的开销。其实我更愿意称这个过程为“拼接”,因为 pb 实际原理上也只是这么做而已,相关开销极小。拼接后的 bytes 十分紧凑,和 ALPHA 的方案相差无几,有兴趣的可以分别输出并对比。

                                      为了指示对附加信息(Addons,也可以理解成插件,以后可以有很多个插件)的不同支持程度,下个测试版会在“附加信息长度”前新增“附加信息版本”。256 - 1 = 255 字节是够用且合理的(65535 就太多了,还可能有人恶意填充),现有的只用了十分之一,以后也不会同时有那么多附加信息,且大多数情况下是完全没有附加信息的。真不够用的话,可以升级 VLESS 版本。

                                      为了减少逻辑判断等开销,暂定 Addons 不使用多级结构。一个月前出现过“可变协议格式”的想法,pb 是可以做到打乱顺序,但没必要,因为现代加密的设计不会让旁观者看出两次传输的头部相同。

                                      下面介绍 Schedulers 和 Encryption 的构想,它们都是可选的,一个应对流量时序特征问题,一个应对密码学上的问题。

                                      Schedulers Flow

                                      中文名暂称:流量调度器(2020-09-03 更新:中文名确定为“流控”),指令由 ProtoBuf 承载,控制的是数据部分。

                                      我之前发现,VMess 原有的 shake “元数据混淆”在 TLS 上完全不会带来有意义的改变,只会降低性能,所以 VLESS 弃用了它。并且,“混淆”这个表述容易被误解成伪装,也弃用了。顺便一提,我一直是不看好伪装的:做不到完全一样,那不就是强特征吗?做得到完全一样,那为什么不直接用伪装目标?我一开始用的是 SSR,后来发现它只是表面伪装骗运营商,就再也没用过了。

                                      那么,“流量调度器”要解决什么问题?它影响的是宏观流量时序特征,而不是微观特征,后者是加密要解决的事情。流量时序特征可以是协议带来的,比如 Socks5 over TLS 时的 Socks5 握手 ,TLS 上不同的这种特征对于监测者来说就是不同的协议,此时无限 Schedulers 就相当于无限协议(重新分配每次发送的数据量大小等)。流量时序特征也可以是行为带来的,比如访问 Google 首页时加载了多少文件、顺序、每个文件的大小,多套一层加密并不能有效掩盖这些信息。

                                      Schedulers 没必要像下面的 Encryption 一样整个套在外面,因为头部的一丁点数据相对于后面的数据量来说太微不足道了。

                                      BETA 2 预计推出两个初级的 Scheduler:Zstd 压缩、数据量动态扩充。进阶操作才是从宏观层面来控制、分配,暂时咕咕。

                                      Encryption

                                      与 VMess 的高度耦合不同,VLESS 的服务端、客户端不久后可以提前约定好加密方式,仅在外面套一层加密。这有点类似于使用 TLS,不影响承载的任何数据,也可以理解成底层就是从 TLS 换成预设约定加密。相对于高度耦合,这种方式更合理且灵活:一种加密方式出了安全性问题,直接扔掉并换用其它的就行了,十分方便。VLESS 服务端还会允许不同的加密方式共存。

                                      对比 VMess,VLESS 相当于把 security 换成 encryption,把 disableInsecureEncryption 换成 decryption,就解决了所有问题。目前 encryption 和 decryption 只接受 "none" 且不能留空(即使以后有连接安全性检查),详见 VLESS 配置文档open in new tag。encryption 并不需要往外移一级,一是因为无法复用很多代码,二是因为会影响控制粒度,看未来的应用就明白了。

                                      加密支持两类形式,一类是加密完全独立,需要额外密码,适合私用,另一类是结合已有的 UUID 来加密,适合公用。 (若用第一类加密形式,且密码是以某种形式公开的,比如多人共用,那么中间人攻击就不远了) 重新设计的动态端口可能会随加密同时推出,指令由 ProtoBuf 承载,具体实现和 VMess 的动态端口也会有很多不同。

                                      套现成加密是件很简单的事情,也就多一层 writer & reader。BETA 3 预计支持 SS 的 aes-128-gcm 和 chacha20-ietf-poly1305: 客户端的 encryption 可以填 “auto: ss_aes-128-gcm_0_123456, ss_chacha20-ietf-poly1305_0_987654”,auto 会选择最适合当前机器的,0 代表测试版,最后的是密码。服务端的 decryption 也是类似填法,收到请求时会逐一尝试解密。

                                      并不是所有组合都需逐一尝试:VMess 的加密分为三段,第一段是认证信息,结合了 UUID、alterId、时间因素,第二段是指令部分,以固定算法加密,指令中含有数据部分使用的加密算法,第三段才是重要的数据部分。可以看出,VMess 的加解密方式实际上是多对一(服务端适配),而不仅是结合 UUID。但仅是结合 UUID 来加密也是件相对麻烦的事情,短时间内不会出,鉴于我们现在有 VMessAEAD 可用,也并不着急。若 VLESS 推出了结合 UUID 的加密方式,相当于重构了整个 VMess。

                                      UDP issues

                                      XUDP:VLESS & VMess & Mux UDP FullCone NATopen in new tag

                                      客户端开发指引

                                      1. VLESS 协议本身还会有不兼容升级,但客户端配置文件参数基本上是只增不减的。iOS 客户端的协议实现则需紧跟升级。
                                      2. 视觉标准:UI 标识请统一用 VLESS,而不是 VLess / Vless / vless,配置文件不受影响,代码内则顺其自然。
                                      3. encryption 应做成输入框而不是选择框,新配置的默认值应为 none,若用户置空则应代填 none

                                      VLESS 分享链接标准

                                      感谢 a @DuckSoftopen in new tag 的提案!

                                      详情请见 VMessAEAD / VLESS 分享链接标准提案open in new tag

                                      - + diff --git a/development/protocols/vmess.html b/development/protocols/vmess.html index c85ca4c305..26148c4519 100644 --- a/development/protocols/vmess.html +++ b/development/protocols/vmess.html @@ -24,11 +24,11 @@ VMess 协议 | Project X - - + +

                                      VMess 协议

                                      VMess 是一个加密传输协议,可以作为 Xray 客户端和服务器之间的桥梁。

                                      版本

                                      当前版本号为 1。

                                      依赖

                                      底层协议

                                      VMess 是一个基于 TCP 的协议,所有数据使用 TCP 传输。

                                      用户 ID

                                      ID 等价于 UUIDopen in new tag,是一个 16 字节长的随机数,它的作用相当于一个令牌(Token)。 一个 ID 形如:de305d54-75b4-431b-adb2-eb6b9e546014,几乎完全随机,可以使用任何的 UUID 生成器来生成,比如这个open in new tag

                                      用户 ID 可在配置文件中指定。

                                      函数

                                      通讯过程

                                      VMess 是一个无状态协议,即客户端和服务器之间不需要握手即可直接传输数据,每一次数据传输对之前和之后的其它数据传输没有影响。

                                      VMess 的客户端发起一次请求,服务器判断该请求是否来自一个合法的客户端。如验证通过,则转发该请求,并把获得的响应发回给客户端。

                                      VMess 使用非对称格式,即客户端发出的请求和服务器端的响应使用了不同的格式。

                                      客户端请求

                                      16 字节X 字节余下部分
                                      认证信息指令部分数据部分

                                      认证信息

                                      认证信息是一个 16 字节的哈希(hash)值,它的计算方式如下:

                                      • H = MD5
                                      • K = 用户 ID (16 字节)
                                      • M = UTC 时间,精确到秒,取值为当前时间的前后 30 秒随机值(8 字节, Big Endian)
                                      • Hash = HMAC(H, K, M)

                                      指令部分

                                      指令部分经过 AES-128-CFB 加密:

                                      • Key:MD5(用户 ID + []byte('c48619fe-8f02-49e0-b9e9-edf763e17e21'))
                                      • IV:MD5(X + X + X + X),X = []byte(认证信息生成的时间) (8 字节, Big Endian)
                                      1 字节16 字节16 字节1 字节1 字节4 位4 位1 字节1 字节2 字节1 字节N 字节P 字节4 字节
                                      版本号 Ver数据加密 IV数据加密 Key响应认证 V选项 Opt余量 P加密方式 Sec保留指令 Cmd端口 Port地址类型 T地址 A随机值校验 F

                                      选项 Opt 细节:(当某一位为 1 时,表示该选项启用)

                                      01234567
                                      XXXXXMRS

                                      其中:

                                      • 版本号 Ver:始终为 1;
                                      • 数据加密 IV:随机值;
                                      • 数据加密 Key:随机值;
                                      • 响应认证 V:随机值;
                                      • 选项 Opt:
                                        • S (0x01):标准格式的数据流(建议开启);
                                        • R (0x02):客户端期待重用 TCP 连接(Xray 2.23+ 弃用);
                                          • 只有当 S 开启时,这一项才有效;
                                        • M (0x04):开启元数据混淆(建议开启);
                                          • 只有当 S 开启时,这一项才有效;
                                          • 当其项开启时,客户端和服务器端需要分别构造两个 Shake 实例,分别为 RequestMask = Shake(请求数据 IV), ResponseMask = Shake(响应数据 IV)。
                                        • X:保留
                                      • 余量 P:在校验值之前加入 P 字节的随机值;
                                      • 加密方式:指定数据部分的加密方式,可选的值有:
                                        • 0x00:AES-128-CFB;
                                        • 0x01:不加密;
                                        • 0x02:AES-128-GCM;
                                        • 0x03:ChaCha20-Poly1305;
                                      • 指令 Cmd:
                                        • 0x01:TCP 数据;
                                        • 0x02:UDP 数据;
                                      • 端口 Port:Big Endian 格式的整型端口号;
                                      • 地址类型 T:
                                        • 0x01:IPv4
                                        • 0x02:域名
                                        • 0x03:IPv6
                                      • 地址 A:
                                        • 当 T = 0x01 时,A 为 4 字节 IPv4 地址;
                                        • 当 T = 0x02 时,A 为 1 字节长度(L) + L 字节域名;
                                        • 当 T = 0x03 时,A 为 16 字节 IPv6 地址;
                                      • 校验 F:指令部分除 F 外所有内容的 FNV1a hash;

                                      数据部分

                                      当 Opt(S) 开启时,数据部分使用此格式。实际的请求数据被分割为若干个小块,每个小块的格式如下。服务器校验完所有的小块之后,再按基本格式的方式进行转发。

                                      2 字节L 字节
                                      长度 L数据包

                                      其中:

                                      • 长度 L:Big Endian 格式的整型,最大值为 2^14;
                                        • 当 Opt(M) 开启时,L 的值 = 真实值 xor Mask。Mask = (RequestMask.NextByte() << 8) + RequestMask.NextByte();
                                      • 数据包:由指定的加密方式加密过的数据包;

                                      在传输结束之前,数据包中必须有实际数据,即除了长度和认证数据之外的数据。当传输结束时,客户端必须发送一个空的数据包,即 L = 0(不加密) 或认证数据长度(有加密),来表示传输结束。

                                      按加密方式不同,数据包的格式如下:

                                      • 不加密:
                                        • L 字节:实际数据;
                                      • AES-128-CFB:整个数据部分使用 AES-128-CFB 加密
                                        • 4 字节:实际数据的 FNV1a hash;
                                        • L - 4 字节:实际数据;
                                      • AES-128-GCM:Key 为指令部分的 Key,IV = count (2 字节) + IV (10 字节)。count 从 0 开始递增,每个数据包加 1;IV 为 指令部分 IV 的第 3 至第 12 字节。
                                        • L - 16 字节:实际数据;
                                        • 16 字节:GCM 认证信息
                                      • ChaCha20-Poly1305:Key = MD5(指令部分 Key) + MD5(MD5(指令部分 Key)),IV = count (2 字节) + IV (10 字节)。count 从 0 开始递增,每个数据包加 1;IV 为 指令部分 IV 的第 3 至第 12 字节。
                                        • L - 16 字节:实际数据;
                                        • 16 字节:Poly1305 认证信息

                                      服务器应答

                                      应答头部数据使用 AES-128-CFB 加密,IV 为 MD5(数据加密 IV),Key 为 MD5(数据加密 Key)。实际应答数据视加密设置不同而不同。

                                      1 字节1 字节1 字节1 字节M 字节余下部分
                                      响应认证 V选项 Opt指令 Cmd指令长度 M指令内容实际应答数据

                                      其中:

                                      • 响应认证 V:必须和客户端请求中的响应认证 V 一致;
                                      • 选项 Opt:
                                        • 0x01:服务器端准备重用 TCP 连接(Xray 2.23+ 弃用);
                                      • 指令 Cmd:
                                        • 0x01:动态端口指令
                                      • 实际应答数据:
                                        • 如果请求中的 Opt(S) 开启,则使用标准格式,否则使用基本格式。
                                        • 格式均和请求数据相同。
                                          • 当 Opt(M) 开启时,长度 L 的值 = 真实值 xor Mask。Mask = (ResponseMask.NextByte() << 8) + ResponseMask.NextByte();

                                      动态端口指令

                                      1 字节2 字节16 字节2 字节1 字节1 字节
                                      保留端口 Port用户 IDAlterID用户等级有效时间 T

                                      其中:

                                      • 端口 Port:Big Endian 格式的整型端口号;
                                      • 有效时间 T:分钟数;

                                      客户端在收到动态端口指令时,服务器已开放新的端口用于通信,这时客户端可以将数据发往新的端口。在 T 分钟之后,这个端口将失效,客户端必须重新使用主端口进行通信。

                                      注释

                                      • 为确保向前兼容性,所有保留字段的值必须为 0。
                                      - + diff --git a/document/command.html b/document/command.html index a99d6c222a..0002ec684e 100644 --- a/document/command.html +++ b/document/command.html @@ -24,8 +24,8 @@ 命令参数 | Project X - - + +

                                      命令参数

                                      提示

                                      Xray 使用 Go 风格的命令及参数

                                      获取基本命令

                                      您可以运行 xray help 来获得所有 xray 最基础的用法, 以及可用的命令及说明。

                                      Xray is a platform for building proxies.
                                      @@ -116,6 +116,6 @@
                                       

                                      xray x25519

                                      生成 x25519 密钥对。

                                      使用方法:

                                      xray x25519 [-i "(base64.RawURLEncoding)" --std-encoding ]
                                       

                                      xray wg

                                      生成 wireguard curve25519 密钥对。

                                      使用方法:

                                      xray wg [-i "(base64.StdEncoding)"]
                                       

                                      提示

                                      -config 没有指定时,Xray 将先后尝试从以下路径加载 config.json :

                                      • 工作目录(Working Directory)
                                      • 环境变量Xray.location.asset 所指定的路径
                                      - + diff --git a/document/config.html b/document/config.html index 719e5fba58..eaa6f5106c 100644 --- a/document/config.html +++ b/document/config.html @@ -24,8 +24,8 @@ 配置运行 | Project X - - + +

                                      配置运行

                                      下载并安装 了 Xray 之后,您需要对它进行一下配置。

                                      为了演示,这里只介绍简单的配置方式。更多的模板: Xray-examplesopen in new tag

                                      如需配置更复杂的功能,请参考更详细的 配置文件 中相关说明。

                                      警告

                                      为了避免你的流量被解密,
                                      你应该使用 xray uuiduuidgen 生成一个独一无二的uuid
                                      在服务端上,放入 inbounds[0].settings.clients[0].id
                                      在客户端内,放入 outbounds[0].settings.vnext[0].users[0].id

                                      服务端配置

                                      你需要一台防火墙外的服务器,来运行服务器端的 Xray。配置如下:

                                      {
                                      @@ -93,6 +93,6 @@
                                         }
                                       }
                                       

                                      上述配置唯一要更改的地方是你的服务器 IP 和用户 uuid,配置中已注明。上述配置会把除局域网(比如访问路由器)和国内IP段(比如访问bilibili、acfun)以外的所有流量转发至你的服务器。

                                      运行

                                      • 在 Windows 和 macOS 中,配置文件通常是 Xray 同目录下的 config.json 文件。
                                        • 直接运行 XrayXray.exe 即可。
                                      • 在 Linux 中,配置文件通常位于 /etc/xray//usr/local/etc/xray/ 目录下。
                                        • 运行 xray run -c /etc/xray/config.json
                                        • 或使用 systemd 等工具将 Xray 作为服务在后台运行。

                                      更多详细的说明可以参考 配置文档小小白话文

                                      - + diff --git a/document/document.html b/document/document.html index 1e20d04aaa..4091d8f592 100644 --- a/document/document.html +++ b/document/document.html @@ -24,14 +24,14 @@ 为 Project X 的文档贡献 | Project X - - + +

                                      为 Project X 的文档贡献

                                      欢迎您为 Project X 的文档做出贡献,我们感谢每一位 Contributor 的贡献!是你们让 Xray 更加强大!

                                      改进文档

                                      Project X 的文档托管在 GitHubopen in new tag 上.

                                      您可以通过以下步骤, 提交您对文档的改动:

                                      1. Project X 文档仓库open in new tag 打开仓库, 点击右上角的 fork, fork 一份文档仓库的镜像到您自己的 github 仓库.

                                      2. 使用任何您喜欢的工具, 从您克隆的仓库获得文档的克隆, 如:

                                      git clone https://github.com/XTLS/Xray-docs-next.git
                                       
                                      1. 基于 main 分支创建新的分支, 如:
                                      git checkout -b your-branch
                                       
                                      1. 在新分支上做修改。

                                        注:推荐 中文文案排版指北open in new tag

                                      2. 修改完成后,请使用 Prettieropen in new tag 格式化您的更改。

                                        注:存在格式问题的 PR,将有可能被拒绝。

                                      3. 提交修改,并推送到您的仓库中

                                      git push -u origin your-branch
                                       
                                      1. 打开 GitHub, 点击 'Pull request' 向 Project X 文档仓库open in new tag 提交 PR。

                                      2. 请在 PR 的标题和正文中,概述此次 PR 新增/修改的内容等;

                                      3. 等待回应, 如果 PR 被 merge, 您做的修改将直接呈现在 Project X 文档网站open in new tag

                                      发现问题?

                                      如果您发现文档出错,可以改进文档或提交一个 Issue。

                                      - + diff --git a/document/index.html b/document/index.html index 4f0e602f27..d0e2cb4551 100644 --- a/document/index.html +++ b/document/index.html @@ -24,11 +24,11 @@ 快速入门 | Project X - - + +

                                      快速入门

                                      这个章节将告诉您如何用最简单的方式获得 Xray,并且开始使用 Xray。

                                      下载安装

                                      Xray 支持各种平台,并且您可以从多种渠道和方式获得 Xray 的各种版本。

                                      请点击 下载安装 以获取 Xray

                                      配置运行

                                      下载并安装 Xray 后,只需对他进行配置即可使用。

                                      请点击 配置运行 以学习最简单的配置方式。

                                      命令参数

                                      Xray 有多种命令和参数可用,因此变得灵活和强大。

                                      请点击 命令参数 查看 Xray 的更多命令和参数用法。

                                      改进文档

                                      如果你有兴趣,请点击 使用文档 帮助我们改进文档,或者点击页面下方的 帮助我们改善此页面!

                                      我们十分感谢每一位 Contributor 作出的贡献!是你们让 Project X 变得更加强大!

                                      小小白白话文

                                      给予新手指导的使用心得

                                      请点击 小小白白话文 以进行查看。

                                      入门技巧

                                      具备了基础之后,你就可以通过 入门技巧 来探索更多的使用方式了。

                                      进阶文档

                                      给予进阶用户指导的使用技巧

                                      点击 进阶文档 以进行查看

                                      感谢

                                      非常感谢大家无私分享使用技巧和心得, 使得 Xray 日益强大。

                                      - + diff --git a/document/install.html b/document/install.html index 1c3a81e97a..162cf99e23 100644 --- a/document/install.html +++ b/document/install.html @@ -24,11 +24,11 @@ 下载安装 | Project X - - + +

                                      下载安装

                                      平台支持

                                      Xray 在以下平台中可用:

                                      • Windows 7 及之后版本(x86 / amd64 / arm32 / arm64);
                                        • Windows 7 中使用 1.8.4、1.8.6 的常规版本以及 1.8.18 以后的 win7 版本需要系统安装有 KB4474419 更新方可使用;推荐同时安装 KB4490628 以便联网后接受后续的操作系统安全更新。
                                      • macOS 10.10 Yosemite 及之后版本(amd64 / arm64);
                                      • Linux 2.6.23 及之后版本(x86 / amd64 / arm / arm64 / mips64 / mips / ppc64 / s390x / riscv64);
                                        • 包括但不限于 Debian 7 / 8、Ubuntu 12.04 / 14.04 及后续版本、CentOS 7 / 8、Arch Linux 等;
                                      • FreeBSD (x86 / amd64);
                                      • OpenBSD (x86 / amd64);

                                      下载 Xray

                                      预编译的二进制 ZIP 格式压缩包可在 Github Releasesopen in new tag 中找到。

                                      下载对应平台的压缩包,解压后即可使用。

                                      验证安装包

                                      Xray 提供两种验证方式:

                                      • ZIP 压缩包的 SHA1 / SHA256 摘要
                                      • 可复现构建:请参照 编译 Xray

                                      Windows 安装方式

                                      macOS 安装方式

                                      Linux 安装方式

                                      安装脚本

                                      Arch Linux

                                      Arch User Repository

                                      需要使用 AUR helpersopen in new tag,以 yayopen in new tag 为例,可通过 yay -S xray 安装。

                                      Arch Linux CN

                                      首先添加 Arch Linux CN 仓库open in new tag,然后在 root 用户下使用 pacman -S xray 安装。

                                      Linuxbrew

                                      Linuxbrew 包管理器的使用方式与 Homebrew 一致:brew install xray

                                      Debian WIP

                                      Gentoo

                                      目前有三个第三方 Overlay 提供 Portage 安装脚本:

                                      使用 layman 或 eselect-repository 添加 Overlay 至本地,然后即可安装。

                                      Docker 安装方式

                                      Docker image 的文件结构

                                      • /etc/xray/config.json:配置文件
                                      • /usr/bin/xray:Xray 主程序
                                      • /usr/share/xray/geoip.dat:IP 数据文件
                                      • /usr/share/xray/geosite.dat:域名数据文件

                                      图形化客户端

                                      UUID 生成器

                                      第三方的 UUID 生成器 uuidgenerator.netopen in new tag

                                      - + diff --git a/document/level-0/ch01-preface.html b/document/level-0/ch01-preface.html index baab41cecb..c1f3690ddb 100644 --- a/document/level-0/ch01-preface.html +++ b/document/level-0/ch01-preface.html @@ -24,11 +24,11 @@ 【第 1 章】 小小白白话文 | Project X - - + +

                                      【第 1 章】 小小白白话文

                                      1.1 这篇文档是写给谁的?

                                      一句话:写给 ① 零基础 ② 希望学习自建 VPS 的新人。

                                      1.2 这篇文档不是写给谁的?

                                      包括但不限于:各路大神大能、懒得自己折腾的小白、已经会折腾的高手、确定要用机场的土豪、确定要用一键脚本的逍遥派...... 总之只要有技术基础、或不愿不想自建的同学,您直接关闭本文即可,因为这篇文章大概是入不了您的法眼的,更可能会让您生一肚子闲气,那多划不来。

                                      1.3 郑重声明及其他声明

                                      郑重声明:

                                      鄙人技术奇菜无比,故本文必然挂一漏万破绽百出。您若发现问题还请温柔提醒,莫要人参公鸡。

                                      免责声明:

                                      本文内容请您自行判断是否可信可靠可用,若您根据本文内容建立和使用 VPS 服务器时出了任何问题和不良结果,鄙人概不负责。

                                      啰嗦声明:

                                      基于本文【零基础用户】的目标受众,许多内容会尽力详尽说明,所以语言偏啰嗦,请做好心理准备。

                                      1.4 为什么自建是个难题?

                                      要回答这个问题,就需要稍微多说一点背景信息了。

                                      一、科学上网这件事

                                      科学上网这件事情,说来已经发展了近二十年(震惊!!!.jpg)。最初,自己稍微动动手即可(改改 host、连一下 ssh)、后来需要找一个网页代理,再后来需要写一个私有协议(比如 Shadowsocks)等等。

                                      随着 GFW 技术这十几年来不断的迭代升级,若要完成【自己动手科学上网】这个目标,需要做的事情已经包括但不限于:

                                      • 了解 Linux 系统基本命令
                                      • 了解网络传输协议
                                      • 有技术和经济能力完成 VPS 购买及管理
                                      • 有技术和经济能力完成域名购买及管理
                                      • 有技术能力完成 TLS 证书申请 等等。

                                      这就让【自建 VPS 科学上网】这个曾经简单的行为逐渐变成了令新人望而生畏的挑战。

                                      二、零基础用户的无奈

                                      零基础的非技术用户,如果完成上面这一连串的操作,势必要学习大量的知识,但稍微搜索之后,新人只怕会更加迷茫:大量的信息散布在互联网的各个角落:博客、问答网站、群组、论坛、GitHub、Telegram、YouTube 等等等等)。这些信息纷乱复杂、水平良莠不齐、甚至可能互相矛盾。基本上就是不把新人彻底弄晕誓不罢休。

                                      面对这些杂乱无章的信息,新人突然就从【信息匮乏】变成了【信息过剩】。若是几番连蒙带猜的折腾以失败告终(大概率如此)的话,他的积极性势必大受挫折。在这个过程中,若他又恰好去了一些不太友好的地方去求助,恐怕还要雪上加霜的被嘲讽一番:“这么菜,用机场不就行了,瞎折腾什么啊!”、“先去学会 Linux 再回来问吧”。

                                      这时候,大概也只有一声“呵呵”可以表达心情了。

                                      1.5 “用机场不就行了?”

                                      首先,我想反问一下那些冷嘲热讽的人:“用机场”真的就是万灵药吗?

                                      其次,我认为“不懂”和“不想懂”是有本质区别的。态度恶劣的巨婴伸手党自然惹人厌烦,但真心自学却不得要领的人不该受到无端的白眼和歧视,也正是这种对新人不加区分的恶劣社区氛围促使我写下本文。那么闲话少说,我们来看看机场的优势与劣势究竟如何:

                                      一、“机场“的优势

                                      所谓“机场”,就是“线路提供商”。他负责完成 1.4 提到的那一串技术操作和管理,用户则付费获得使用权。所以,它的优点至少有:

                                      1. 用户操作简单:扫码操作、一键添加规则等
                                      2. 线路选择多:可解锁不同国家、地区的网络服务;比如 iplc 等专线服务、游戏加速服务等
                                      3. 接入节点多:所以抵抗节点封锁的能力强一些,封了一个就换下一个

                                      二、“机场”的风险

                                      “方便”这枚硬币的另一面就是“风险”,基于“机场”的技术特点和市场情况,它的风险至少有:

                                      1. “机场”可完全获得用户信息:用户在网上的所有痕迹,都【必然】经过且【非常可能】长期存储在其服务器上,这些记录无法受到任何具备法律效力的用户隐私协议的约束(窥视、记录你的一举一动
                                      2. “机场”缺乏市场管理:不可避免存在着以欺诈为目标的恶意商家(主动跑路
                                      3. “机场”面临监管压力:大机场相对有保障的同时,也无法避免树大招风。2020 年间,已经有几个大机场停运、跑路的事件发生,用户的正常使用受到严重干扰(被动跑路
                                      4. “机场”技术水平难以确定:线路质量良莠不齐,挂羊头卖狗肉的现象屡见不鲜(速度慢、掉线多、连不上

                                      1.6 那么你到底要不要自建呢?

                                      现在,你已经看到了机场的优势和风险,要用什么,就请各位充分思考并自行决定。毕竟,最适合你的方案才是最好的方案。

                                      It's Your Choice!

                                      1. 如果决定使用机场的话,现在,你可以关闭本文了。

                                      2. 如果你决定自建,那就请继续阅读后面的章节吧!!

                                      总之,本文的目标就是成为零基础用户的知识起点,提供对每一步充分的讲解和演示,清清楚楚(甚至婆婆妈妈、絮絮叨叨、啰啰嗦嗦)的协助新人完成【从输入第一条命令开始,完成 VPS 服务器部署,并成功在客户端完成科学上网】的全程。并在这个过程中帮助新人逐步接触和熟悉 Linux 的基础操作,为之后的进一步自学打下基础。

                                      1.7 题外啰嗦几句

                                      1. 墙外的信息泥沙俱下,请务必学会理性、独立的思辨,不要随意站队,不要轻信猎奇的信息。

                                      2. 衷心希望大家获得更顺畅的网络后,可以获取更新鲜的知识、更丰富的娱乐、接触更美好的世界、结交更多志同道合的朋友,但不要成为任何有不可告人目的之人的替罪羊。

                                      3. 你的互联网身份依然是你的身份,绝对的匿名化是极为困难的,所以请务必遵守你个人所在地区和 IP 所在地区的相关法律法规。无论何时,自我保护都是最基本的底线。

                                      1.8 你的进度

                                      ⬛⬜⬜⬜⬜⬜⬜⬜ 12.5%

                                      - + diff --git a/document/level-0/ch02-preparation.html b/document/level-0/ch02-preparation.html index 93fbe007ec..6f287928e9 100644 --- a/document/level-0/ch02-preparation.html +++ b/document/level-0/ch02-preparation.html @@ -24,11 +24,11 @@ 【第 2 章】原料准备篇 | Project X - - + +

                                      【第 2 章】原料准备篇

                                      这一章比较特殊,因为涉及到金钱交易行为,本文基于项目的中立立场,不做具体的推荐。我能做的,是告诉你需要准备哪些东西。

                                      2.1 获取一台 VPS

                                      你需要获取一台健康的、IP 没有被墙的 VPS,并在管理后台做下面这些基础准备:

                                      1. 在 VPS 的后台安装 Debian 10 64bit 系统
                                      2. 小本本记下 VPS 的 IP 地址(本文会用 "100.200.300.400" 来表示)

                                        提示

                                        这是一个故意写错的非法 IP,请替换成你的真实 IP)

                                      3. 小本本记下 VPS 的 SSH 远程登陆端口(Port)
                                      4. 小本本记下 SSH 远程登录的用户名和密码

                                      购买 VPS 是一个比较复杂的事情,建议先去学习一下相关知识,选择适合自己的经济能力和线路需求的即可。另外可以选择薅一些国际大厂的羊毛(比如甲骨文和谷歌提供的永久免费或限时免费的套餐)。总之,务必量力而行。

                                      说明

                                      关于选择 Debian 10 作为操作系统,这里稍微多说一句:不管你在网上听说了什么,不管哪个大神告诉你 XXX 版的 Linux 更好、XXX 版的 Linux 更牛,这些 Linux 的派系之争跟现在的你半毛钱关系也没有!使用 Debian 10 足以让你的 VPS 服务器在安全、稳健运行的同时得到足够的优化(如 cloud 专用内核、及时的 bbr 支持等)。等你对 Linux 熟悉之后,再回头去尝试其他的 Linux 发行版也不迟。

                                      2.2 获取一个心仪的域名

                                      你需要获取一个域名、并在 DNS 设置中添加一条 A 记录,指向你 VPS 的 IP 地址

                                      1. 请选择靠谱的国际域名服务商。选择一些常见的域名后缀就行,注意不要用 .cn 后缀。
                                      2. 在 DNS 设置中,添加一条指向你 VPS 的 IP 地址的 A 记录(A 记录的名字可以随便起,本文会用 "a-name" 来表示。完整的域名则会用 "二级域名.你的域名.com" 或者 "a-name.yourdomain.com" 来表示)。效果如下图:

                                      添加A记录

                                      提示

                                      不是一个真实可用的网址,请替换成你的真实网址

                                      2.3 你本地电脑上需要安装的软件

                                      1. SSH 远程登录工具

                                      2. 远程文件拷贝工具

                                      3. 靠谱的文本编辑器

                                      2.4 你的进度

                                      如果上面的原材料你都准备好了的话,你已经拿到了开启新世界大门的钥匙。那还等什么,让我们快点进入下一章,走进这扇门吧!

                                      ⬛⬛⬜⬜⬜⬜⬜⬜ 25%

                                      - + diff --git a/document/level-0/ch03-ssh.html b/document/level-0/ch03-ssh.html index 33d8733e51..a15683eacb 100644 --- a/document/level-0/ch03-ssh.html +++ b/document/level-0/ch03-ssh.html @@ -24,13 +24,13 @@ 【第 3 章】远程登录篇 | Project X - - + +

                                      【第 3 章】远程登录篇

                                      3.1 远程登录 VPS (PuTTY)

                                      首先,鉴于零基础人群中 Windows 的用户基数最大,所以本文以 Windows 为例进行展示。

                                      其次,虽然 Windows 10 之后的 PowerShell 和 WSL 也可以达到很好的 SSH 操作体验。但是因为并非所有版本的 Windows 都有最新的组件,故本文还是以老牌的 PuTTY 为例,进行 SSH 远程登录的操作详解。(使用其他工具的话、在 SSH 登陆之后的操作都是一样的)

                                      下面就跟我一步步操作吧。

                                      1. 进入 PuTTY 的官网open in new tag,选择适合你操作系统的版本下载。(本文以 64 位版本为例)

                                        下载PuTTY

                                      2. 安装运行后,将会看到 PuTTY 的主界面。现在请拿出你上一章记东西的小本本,在下图的对应位置填入你 VPS 的IP 地址(VPS IP)端口(VPS PORT)。为了方便以后使用时不用重复输入,我们可以保存会话 (Saved Sessions),未来使用时只要按 Load 即可一键载入设置。

                                        设置PuTTY

                                      3. 我建议将 Connection 中的 keepalive 设置为 60 秒,防止你一段时间没有操作之后 SSH 自动断线。另外务必再次保存设置。

                                        防止频繁断线

                                      注意

                                      对 PuTTY 的任何设置更新都要再次手动保存 Session,不然关闭后就会丢失

                                      1. 点击 Open 就会进入 SSH 连接窗口,对应下图输入用户名与密码,与你的 VPS 远程主机建立连接。(本文假设默认用户名是 root,另外,在 Linux 系统输入密码的时候,是不会出现 ****** 这种提示符的,这样可以避免密码长度泄漏,不是你的键盘坏掉了哦!)

                                        SSH远程登录

                                      3.2 成功登录 SSH!初识命令行界面!

                                      1. 如果你的信息都填写正确,你将会看到类似下图的界面,说明已登录成功:

                                        初次登录VPS

                                        这个界面,就等于远程服务器的【桌面】,但它没有你熟悉的图标和鼠标,没有绚丽的色彩,有的只是简单文字,这就是【命令行界面】- Command Line Interface,或者缩写为 CLI

                                        接下来的所有操作,都需要你像电影里的黑客一样,在这个命令行界面中完成。也许你会觉得陌生,但请相信我,使用命令行既不可怕,也不神秘。说到底,它只不过是把你习惯的鼠标操作变成了文字指令而已,你说一句,它做一句

                                      2. 现在,你可以稍微观察并熟悉一下命令行环境,这个界面其实已经告诉了你一些有用的信息了,比如系统内核版本(比如图内是 4.19.37-5)、上次登录时间及 IP 等。当然根据 VPS 的不同,你看到的界面可能会略有不同。

                                      3. 请注意命令行最下面一行,闪动的光标左边,有一串字符。图中显示的是root@vps-server:~#,这一串要怎么理解呢?很简单:

                                        • 现在的用户是 root
                                        • root 所在的服务器是 vps-server
                                        • root 现在所在的文件夹是 ~
                                        • # 之后是你可以输入命令的地方

                                        前两个很直观,无需多说。第三个是关于 Linux 的文件夹系统,现在也不需要过于深入,你只需要知道,"~"就是【当前用户的大本营】。第四个,提示符#,你也不用管,只需要知道,未来文章中会写一些需要你输入的命令,都会以 "#" 或者 "$" 开头,提示你后面是你输入命令的地方。(所以你复制命令的时候,只需要复制后面的内容,不要复制提示符)

                                      3.3 第一次更新 Linux 的软件!

                                      1. 正如你的手机,无论安卓还是 iPhone,为了 APP 及时更新(获取安全补丁和新功能),都会时不时从应用商店获得更新信息,并且提示你有多少个 APP 可更新。Linux 系统也有逻辑十分类似的更新机制。所以只要你会更新手机 APP,就能学会更新 Linux 软件!

                                      2. Linux 下,每个 APP 都叫做一个“包” (package)。管理 APP 的程序自然就叫做“包管理器”(Package Manager)。你可以通过它安装、更新、卸载各种软件、甚至更新 Linux 系统本身。Linux 下的包管理器非常强大,此处按下不表,现在你只需要知道 Debian 系统的包管理器叫做 apt 即可。接下来,我们就先使用 apt 做一次软件的全面更新,让你熟悉它的基本操作。

                                      3. 小小白白 Linux 基础命令:

                                        编号命令名称命令说明
                                        cmd-01apt update查询软件更新
                                        cmd-02apt upgrade执行软件更新
                                      4. 现在请输入第一条命令,获取更新信息

                                        apt update
                                         
                                      5. 然后请输入第二条命令,并在询问是否继续安装 (Y/n) 时输入 y 并回车确认,开始安装

                                        apt upgrade
                                         
                                      6. 完整流程演示如下:

                                        初次软件更新流程演示

                                      3.4 你的进度

                                      恭喜你又迈出了坚实的一步! 现在,你已经可以通过 SSH 来登录你的远程服务器了!那登录进去之后,除了升级软件之外,应该再做点什么呢?敬请进入下一章一探究竟吧!

                                      ⬛⬛⬛⬜⬜⬜⬜⬜ 37.5%

                                      - + diff --git a/document/level-0/ch04-security.html b/document/level-0/ch04-security.html index d5e80b0713..80e96fa7ee 100644 --- a/document/level-0/ch04-security.html +++ b/document/level-0/ch04-security.html @@ -24,8 +24,8 @@ 【第 4 章】安全防护篇 | Project X - - + +

                                      【第 4 章】安全防护篇

                                      4.1 为什么要做安全防护

                                      Linux 服务器的安全防护是一个纷繁复杂的巨大课题。无数的网站、APP、服务、甚至线下基础设施都建立在 Linux 的基石之上,这背后牵涉到巨大的经济利益和商业价值,当然也就就意味着黑灰产有巨大的攻击动力。但是这些服务是如此重要、根本不允许出现重大的安全漏洞。于是无数的运维专业人员都在安全攻防的战场上拼搏努力,这才让大家能享受到基本稳定的现代化数字生活。

                                      现在,你拥有了一台 VPS,并且将会敞开他的数据访问渠道来达到流量转发的目标,那就相当于你已经置身于安全攻防战场的第一线、直面所有风险。但与此同时,新人由于知识和信息的不足,看待安全问题是总是难免两极分化:要么觉得轻如鸿毛和自己没有半点关系,要么觉得重于泰山甚至惶惶不可终日。

                                      • 对于前者,我的建议是:安全无小事,尽量多查一些安全方面的信息,免得自己真的受了损失才后悔莫及

                                      • 对于后者,我的建议是:不用紧张,我们的服务器仍不具有太高的价值、一般不会吸引到高水平的攻击,需要面对的基本都是一些自动化脚本的恶意扫描和登录尝试,跟着本文做一些基础的防护即可

                                      4.2 具体的风险到底是什么

                                      就像我们在《远程登录篇》配置的一样,任何人只需要知道【IP 地址】+【端口】+【用户名】+【密码】这四个要素,就能登录你的 VPS 服务器。那很显然,这四要素的安全就是我们要防护的底线。我们来逐一分析:

                                      1. 【IP 地址】:恶意脚本会随机尝试和扫描 IP 段,可以简单认为是公开信息、无法隐藏

                                      2. 【端口】:如果使用默认端口,那么【端口 = 22

                                      3. 【用户名】:如果使用默认用户,那么【用户名 = root

                                      4. 【密码】:密码不存在默认值,一定是由 VPS 后台随机生成或由你自行设置的。也就是说,如果你的服务器都是默认设置,则四要素中的三个已经是已知的,那么你整个服务器的安全,就全部寄托在一串小小的密码上了。这时有几种情况:

                                        • 如果你用了 VPS 管理后台随机生成密码,它一般包含随机的十几个大小写混杂的字母和符号,相对比较安全

                                        • 如果你为了好记、把密码改成了类似123456这种超弱的密码,破解你的 VPS 服务器可谓不费吹灰之力

                                        • 如果你为了好记、把密码改成了比较复杂、但在别的地方用过的密码,其实也并不安全。你要明白黑客手里有作弊器,比如说密码表,包含数万、数十万、数百万甚至更多曾经泄漏的真实密码)

                                      5. 但你要明白,没有哪个黑客真的要坐在电脑前一次一次的尝试你的密码,全部的攻击尝试都是恶意脚本自动进行的,它会 24 小时不眠不休的工作。也许每天你酣睡之时,你的服务器都在经受着一轮又一轮的冲击。

                                        一旦密码被成功撞破,意味着你的四要素全部被攻击者掌握,恶意脚本就会快速登录服务器、获取服务器的最高 root 控制权、安装部署它的恶意服务,然后就可以用你的服务器来 24 小时做各种坏事(比如挖矿、传播病毒、发送垃圾邮件、欺诈邮件、做 BT 中继、甚至暗网公众节点等等等等)。如果恶意脚本比较克制,其实可以做到相当的隐蔽性。而新人一般也不会去观察留意 VPS 的登录记录、进程变化、CPU 占用变化、流量变化等指标,你其实就很难发现自己被黑了。直到你的 VPS 服务商封禁你的账号、或者收到律师函为止。

                                      6. 别忘了,你获得 VPS 时大概率需要使用真实的支付信息,你登录各种网站、社交平台时也会留下你的 IP 地址,这些都与你的身份有直接或者间接的关系。于是,一旦这些坏事发生,它们就不可避免的与你产生了关联。

                                      4.3 我们要做的安全防护有哪些

                                      基于上述分析,我们要做的,自然就是对【端口】、【用户名】、【密码】这三要素进行加强,来降低被攻破的风险:

                                      1. 【端口】:将 SSH 远程登录端口修改为【非 22 端口】 (4.4)
                                      2. 【用户名】:建立【非 root】的新用户、并禁用 root 用户 SSH 远程登录 (4.5、4.6)
                                      3. 【密码】:SSH 启用 RSA 密钥验证登录、同时禁用密码验证登录 (4.7)

                                      记得按顺序来,别把自己锁在门外了。

                                      4.4 将 SSH 远程登录端口修改为非 22 端口

                                      现在,我们来解决【端口 = 22】的问题。(注意:有些 VPS 服务商,默认的端口已经是非 22 端口,那么你可以忽略这一步,当然也可以跟着本文改成别的端口)

                                      1. 小小白白 Linux 基础命令:

                                        编号命令名称命令说明
                                        cmd-03nano文本编辑器
                                        cmd-04systemctl restart重启某个服务
                                      2. 小小白白 Linux 基础配置文件

                                        编号配置文件位置文件说明
                                        conf-01/etc/ssh/sshd_configSSH 远程登录程序设置
                                      3. 我们要做的第一件事,当然就是【用nano这个文本编辑器打开SSH远程登录程序设置】,在 Windows 下,你会【找到文件并双击】,在 Linux 下该怎么办呢?仔细看看上面的命令说明,是不是就很简单了?没错,就是:

                                        nano /etc/ssh/sshd_config
                                        @@ -40,6 +40,6 @@
                                         
                                      4. 修改 SSH 配置。这个我们已经用了很多次,但现在我们已经从无所不能的root变成了普通用户vpsadmin,此时的我们是没有权限直接编辑 SSH 配置的。这时候就需要使用sudo命令了:

                                        sudo nano /etc/ssh/sshd_config
                                         
                                      5. 找到(ctrl+w) PasswordAuthentication 改成 no

                                      6. 找到(ctrl+w) PubkeyAuthentication 改成 yes,然后保存(ctrl+o)退出(ctrl+x)

                                      7. 重启 SSH 服务。(啰嗦君:别忘了现在需要使用sudo来获得权限)

                                        sudo systemctl restart ssh
                                         
                                      8. 完整流程如下:

                                        SSH开启密钥验证并禁用密码验证

                                    112. VPS 端已经设置好了公钥,现在要给 PuTTY 指定私钥位置供登录时使用(啰嗦君:别忘了保存 Session)

                                      PuTTY指定私钥位置

                                    113. 至此,【密钥登录】已成功开启、【密码验证】已成功关闭、并且还给 PuTTY 保存了默认的登录用户名和私钥。未来使用 PuTTY 登录时,载入VPS-SERVER配置后,点击Open就可以一键登录了。

                                      如果你给私钥设置了密码保护,登录时当然还需要输入这个密码才能使用密钥,如下图:

                                      输入私钥密码

                                    114. 别忘了给WinSCP也做对应的密钥设置,否则之后想要传输文件时就无法登录了:

                                      WinSCP指定私钥位置

                                    注意

                                    任何需要借助 SSH 进行登录的软件都需要密钥验证了,软件过多,无法逐一展示,请根据你的需要自行设置好哦

                                    4.8 你的进度

                                    到这里为止,你的 VPS 已经完成了【端口】、【用户名】、【密码】这三要素的基本安全保障,虽然远称不上固若金汤,但一般的恶意脚本应该已经无法对你造成伤害了!

                                    现在我们终于有了一个安全的系统基础,下一章,我们就可以开始逐步安装配置 Xray 需要的基础设施了!(什么基础设施呢?一个网页,一张证书)

                                    ⬛⬛⬛⬛⬜⬜⬜⬜ 50%

                                - + diff --git a/document/level-0/ch05-webpage.html b/document/level-0/ch05-webpage.html index 98808e85bf..dc5e9c344c 100644 --- a/document/level-0/ch05-webpage.html +++ b/document/level-0/ch05-webpage.html @@ -24,8 +24,8 @@ 【第 5 章】网站建设篇 | Project X - - + +

                                【第 5 章】网站建设篇

                                5.1 为什么要做一个网站?

                                新人也许会迷惑,为什么科学上网还要建一个网站?我不会编程啊,是不是特别麻烦?

                                先回答第一个问题,建网站的原因有:

                                1. 申请合法的 TLS 证书(非常重要)
                                2. 提供合理的回落,防止主动探测攻击,提高安全性
                                3. 建设一个伪装站(如博客、私人网盘、多媒体网站、游戏网站等),直接访问时有合理的前台,使流量使用看上去更合理。

                                再回答第二个问题:

                                1. 本文作为演示,仅仅使用了一个最简单的【单文件 html 页面 + Nginx】来搭建,以此完成上面的目标,所以【非常简单】
                                2. 这个网站完全可以不仅仅是伪装,而是真的做大做强,这个复杂性就完全取决于你了
                                3. 对于“伪装”和“网站运营”这个目标,需要的就是各不相同、秀出真我,需要的同学可以自行搜索学习。这个内容已经完全偏离了科学上网,本文就不深入解析了。

                                5.2 登录 VPS、安装运行 Nginx

                                1. 这里用到的,都是之前已经详解过的命令,所以就不重复讲解了。看不懂的同学可以看看前面的章节哦。

                                  sudo apt update && sudo apt install nginx
                                  @@ -90,6 +90,6 @@
                                           }
                                   

                                  特别注意!

                                  如我在【第 3 步】中的提示所说,请务必确保 /home/vpsadmin/www/webpage 改成你的实际文件路径。

                                2. nginx 重新载入配置使其生效

                                  sudo systemctl reload nginx
                                   
                                3. 完整的设置流程如下:

                                  网页设置演示

                                4. 此时如果你访问 http://二级域名.你的域名.com,你看到这样的页面则说明成功:

                                  http网页成功

                              5.4 常见错误的说明

                              首先,如果你一路按照文章的说明来操作,并且足够细心,那肯定不会出错。所以,我并不打算修改本文的写法。

                              那为什么依然有很多同学卡在了这一步,网页怎么也打不开呢?基本上就是两个字:粗心。因为这里配置可能出现的问题只有两种,原因也只有两个。

                              一、两种问题:

                              • nginx.conf 里面的 /home/vpsadmin/www/webpage 这一条,与你的实际文件路径不符,nginx 找不到文件
                              • 路径正确,但 nginx 无权读取

                              二、两个原因:

                              • 使用了【非 root 用户】,但仍然直接拷贝文中的命令不加修改。(这基本就等于抄答案时把同学的名字一起抄过去了)
                              • 坚持使用【 root 用户】

                              碰到错误的同学,就回过头仔细看一下【5.3】中【第 3 步】和【第 5-2 步】的说明吧。

                              注意

                              本文前期已经用了大量篇幅说明了使用【非 root 用户】对安全的重要性,全文也是基于此而写。所以,因使用【 root 用户】而导致的问题并不在本文的设计范围里。

                              但我相信,坚持使用【 root 用户】的同学应该是有主见、动手能力强、或者有一定 Linux 基础的同学。问题的症结我已经全部说明了,我相信你一定可以自行解决。

                              5.5 你的进度

                              至此,Xray 的第一个基础设施【网页】已经就位,我们马上就进入第二个基础设施【证书】吧!

                              ⬛⬛⬛⬛⬛⬜⬜⬜ 62.5%

                          - + diff --git a/document/level-0/ch06-certificates.html b/document/level-0/ch06-certificates.html index 4aeb053892..994148777f 100644 --- a/document/level-0/ch06-certificates.html +++ b/document/level-0/ch06-certificates.html @@ -24,8 +24,8 @@ 【第 6 章】证书管理篇 | Project X - - + +

                          【第 6 章】证书管理篇

                          6.1 申请 TLS 证书

                          接下来我们要做的,是为我们的域名申请一个真实的 TLS 证书,使网站具备标准 TLS 加密的能力及 HTTPS 访问的能力。这就是 Xray 等现阶段安全代理工具确保流量充分加密最重要的工具。

                          注意

                          请不要轻易使用自签证书。它并没有让操作简单太多,但增加了无谓的风险(如中间人攻击)。

                          这里我会使用一个叫做 acme.shopen in new tag 的证书管理工具,它简单、轻量、高效,并可完成证书自动更新。

                          另外,我相信,现在你已经逐渐熟悉了 Linux 的基础操作,所以已经多次出现的命令从本章开始不再重复截图、只做简单的描述。如果实在想不起来怎么用的话,就稍微复习一下前面的章节吧。

                          6.2 安装 acme.sh

                          1. 小小白白 Linux 基础命令:

                            编号命令名称命令说明
                            cmd-12wget访问(或下载)某个网页文件
                            cmd-13acme.shacme.sh 证书管理相关的命令
                          2. 运行安装脚本

                            wget -O -  https://get.acme.sh | sh
                            @@ -136,6 +136,6 @@
                             [Mon 14 Feb 2022 03:00:25 PM CST] Installing key to: /etc/xray/cert/cert.key
                             [Mon 14 Feb 2022 03:00:25 PM CST] Installing full chain to: /etc/xray/cert/fullchain.crt
                             

                          6.6 你的进度

                          至此,Xray 所需要的两个基础设施终于全部就位!千呼万唤始出来的 Xray 马上就要揭开面纱,我们终于要进入最激动人心章节啦!

                          ⬛⬛⬛⬛⬛⬛⬜⬜ 75%

                          - + diff --git a/document/level-0/ch07-xray-server.html b/document/level-0/ch07-xray-server.html index aac97a3c41..9b27e2903a 100644 --- a/document/level-0/ch07-xray-server.html +++ b/document/level-0/ch07-xray-server.html @@ -24,8 +24,8 @@ 【第 7 章】Xray 服务器篇 | Project X - - + +

                          【第 7 章】Xray 服务器篇

                          7.1 博观而约取,厚积而薄发

                          本文撰写过程中,大佬开玩笑的吐槽到:你这教程,居然连载了 6 章都还没到 Xray,不知道的还以为你是“手把手教你建网站”教程呢。(我竟无法反驳.jpg!)

                          其实这样的结构是我多番思考之后的决定,毕竟只有打好基础,才能在后面事半功倍快速反超。我在群里看到许多新人连nano都无法正确使用,也不会用WinSCP,远程手写编辑出来的config.json自然错误百出,连查错也变得举步维艰。

                          注意

                          经过了前 6 章的准备,各位已经跟我一起翻越了 Linux 基本操作、VPS 远程管理、网页搭建、域名管理、证书申请等等几座大山。是不是回头看看,觉得其实非常简单呢?现在我们有了如此扎实的准备,接下来安装和配置 Xray 时会有一种【水到渠成】的轻快感觉。

                          后面要做的事情非常简单:

                          1. 安装
                          2. 配置(如安装 TLS 证书、config.json
                          3. 运行
                          4. 优化(如更新内核、开启bbr、网站http访问自动跳转https等)

                          7.2 安装 Xray

                          首先,Xray 的官方载体,就是 xray-coreopen in new tag 开源项目(基于 MPL 2.0 开源协议)生成的二进制程序。你把这个二进制放在服务器运行,它就是服务器端;你把它下载到本地电脑运行,它就是客户端。主要区别来源于【配置】。

                          安装时,直接使用官方安装脚本就很简单直接。它提供了多种安装选项,有兴趣的可以去官方的安装脚本仓库open in new tag中看看脚本的说明,本文使用的是【非 root 用户】安装模式

                          写本文时,安装脚本在使用非 root 账户时有一些小 bug,所以我决定正好把这几步分开操作,可以顺便说明一下 Linux 下的删除命令。

                          1. 小小白白 Linux 基础命令:

                            编号命令名称命令说明
                            cmd-14rm删除命令
                          2. 将安装脚本下载至本地:

                            wget https://github.com/XTLS/Xray-install/raw/main/install-release.sh
                            @@ -188,6 +188,6 @@
                             
                            1. 修改 Xray 的回落设置,将回落从 80 端口改为 8080 端口。(找到 "dest": 80, 并改成 "dest": 8080
                            sudo nano /usr/local/etc/xray/config.json
                             
                            1. 重启 Xray 服务,即完成了设置
                            sudo systemctl restart xray
                             
                            1. 完整流程演示如下:

                            http自动跳转https

                            1. 当你输入 http://a-name.yourdomain.com的时候,它应该已经会自动跳转 https 了

                            http自动跳转https生效

                            7.9 服务器优化之三:更丰富的回落

                            如果你需要更丰富的回落功能,可以参考 《回落 (fallbacks) 功能简析》

                            7.10 你的进度

                            恭喜!!到这一步,你已经拥有了可以正常科学上网的服务器、同时也有了可以防止主动探测攻击的伪装网站。接下来,只要给你的客户端装上合适的软件,就可以享受顺畅的网络了!

                            ⬛⬛⬛⬛⬛⬛⬛⬜ 87.5%

                            7.11 重要勘误

                            1. 初版中Xray配置文件config.json文件夹位置错误。若你已经根据之前的位置进行了操作,Xray会无法正确启动。故勘误说明于此,请自查,造成不便十分抱歉!
                            • 正确位置:/usr/local/etc/xray/config.json
                            • 错误位置:/usr/local/etc/config.json

                            受影响章节:

                            • 7.4 配置Xray - 3. 使用nano创建Xray的配置文件
                            • 7.8 服务器优化之二 - 6. 修改Xray的回落设置
                            1. 初版中修改Nginx配置文件nginx.conf时内容错误(网页文件夹位置错误),若你已经根据之前的位置进行了操作,Nginx会无法找到正确的网站。请自查,造成不便十分抱歉!
                            • 正确文件夹位置:root /home/vpsadmin/www/webpage;
                            • 错误文件夹位置:root /var/www/website/html

                            受影响章节:

                            • 7.8 服务器优化之二 - 4. 在与 80 端口同级的位置增加一个本地端口监听来提供网页展示
                          - + diff --git a/document/level-0/ch08-xray-clients.html b/document/level-0/ch08-xray-clients.html index db8e7d9fcf..c4c6003e27 100644 --- a/document/level-0/ch08-xray-clients.html +++ b/document/level-0/ch08-xray-clients.html @@ -24,8 +24,8 @@ 【第 8 章】Xray 客户端篇 | Project X - - + +

                          【第 8 章】Xray 客户端篇

                          8.1 Xray 的工作原理简述

                          要正确的配置和使用Xray,就需要正确的理解其工作原理,对于新人,可以先看看下面简化的示意图(省略了许多复杂的设置):

                          Xray数据流向

                          这其中的关键点是:

                          1. APP 要主动或借助转发工具,将数据【流入(inbounds)】Xray 客户端

                          2. 流量进入客户端后,会被【客户端路由(routing)】按规则处理后,向不同方向【流出(outbounds)Xray 客户端。比如:

                            1. 国内流量直连(direct
                            2. 国外流量转发 VPS(proxy
                            3. 广告流量屏蔽(block
                          3. 向 VPS 转发的国外流量,会跨过防火墙,【流入(inbounds)】 Xray 服务器端

                          4. 流量进入服务器端后,与客户端一样,会被【服务器端路由(routing)】按规则处理后,向不同方向【流出(outbounds)】:

                            1. 因为已经在防火墙之外,所以流量默认直连,你就可以访问到不存在网站们了(direct
                            2. 如果需要在不同的 VPS 之间做链式转发,就可以继续配置转发规则(proxy
                            3. 你可以在服务器端继续禁用各种你想禁用的流量,如广告、BT 下载等(block

                          注意

                          请务必记得,Xray 的路由配置非常灵活,上面的说明只是无限可能性中的一种。

                          借助 geosite.datgeoip.dat 这两个文件,可以很灵活的从【域名】和【IP】这两个角度、不留死角的控制流量流出的方向。这比曾经单一笼统的 GFWList 强大很多很多,可以做到非常细致的微调:比如可以指定 Apple 域名直连或转发、指定亚马逊域名代理或转发,百度的域名屏蔽等等。。。)

                          现在,《路由 (routing) 功能简析》 已经上线,我建议对路由功能有兴趣的同学,先继续跟着本文完成客户端的基础配置,之后再去这里详细学习。

                          8.2 客户端与服务器端正确连接

                          现在你已经理解了 Xray 的工作原理,那么接下来的配置,其实就是【告诉你的客户端如何连接 VPS 服务器】。这和你已经很熟悉的、告诉PuTTY如何远程连接服务器是一样的。只不过 Xray 连接时的要素不止是【IP 地址】+【端口】+【用户名】+【密码】这四要素了。

                          实际上,Xray的连接要素是由不同的协议决定的。本文在第 7 章的配置文件 config.json 里,我们使用 Xray 下独特而强大的 VLESS 协议 + XTLS 流控。所以看看那个配置文件的内容就能知道,这个协议组合的连接要素有:

                          • 服务器【地址】: a-name.yourdomain.com
                          • 服务器【端口】: 443
                          • 连接的【协议】: vless
                          • 连接的【流控】: xtls-rprx-vision (vision 模式适合全平台)
                          • 连接的【验证】: uuiduuid-uuid-uuid-uuiduuiduuid
                          • 连接的【安全】: "allowInsecure": false

                          鉴于新人一般都会使用手机 APP 或者电脑的 GUI 客户端,我就把常用的客户端罗列在下面。每个客户端都有自己独特的配置界面,逐一截图展示并不现实,所以请你务必仔细阅读这些客户端的说明、然后把上述要素填入合适的地方即可。

                          注意

                          许多工具其实是同时支持 xray-corev2fly-core 的,但默认内置的不一定是哪个,所以别忘记检查一下是否是你想要的那个在工作哦!

                          到这一步,你的全套配置就已经可以正常使用啦!

                          8.3 附加题 1:在 PC 端手工配置 xray-core

                          虽然到上面一步已经可以结束了,但是如果你是个好奇心强、记忆力好的的同学,一定会想起来我在上一章说过,你把xray-core 的二进制文件“放在服务器运行,它就是服务器端;你把它下载到本地电脑运行,它就是客户端。” 那究竟要怎样直接使用 xray-core 做客户端呢?

                          为了回答这个问题,我加入了附加题章节,有一点点超纲,有一点点麻烦,但费这个笔墨是因为这个方式有它的优势:

                          • 第一时间获得最新版而无需等待 APP 升级适配

                          • 灵活自由的路由配置能力(当然 GUI 客户端中 Qv2ray 的高级路由编辑器非常强大,也可以完整实现 xray-core 的路由配置功能)

                          • 节约系统资源 (GUI 界面一定会有资源消耗,消耗的多少则取决于客户端的实现)

                          它的劣势应该就是【需要手写配置文件】有点麻烦了。但其实,你想想,服务器上你已经成功的写过一次了,现在又有什么区别呢?接下来,还是老样子,我们分解一下步骤:

                          1. 首先请从 Xray 官方的 GitHub 仓库 Release 页面open in new tag 获取对应平台的版本,并解压缩到合适的文件夹

                          2. 在合适的文件夹建立空白配置文件:config.json (自己常用平台下新建文件大家肯定都会,这就真不用啰嗦了)

                          3. 至于什么是“合适的文件夹”?这就取决于具体的平台了~

                          4. 填写客户端配置

                            • 我就以 8.1 原理说明里展示的基本三类分流(国内流量直连、国际流量转发 VPS、广告流量屏蔽),结合 8.2 的连接要素,写成一个配置文件
                            • 请将 uuid 替换成与你服务器一致的 uuid
                            • 请将 address 替换成你的真实域名
                            • 请将 serverName 替换成你的真实域名
                            • 各个配置模块的说明我都已经(很啰嗦的)放在对应的配置点上了
                            // REFERENCE:
                            @@ -181,6 +181,6 @@
                             

                          8.4 附加题 2:在 PC 端手工运行 xray-core

                          写好了配置文件该,要怎么让 xray-core 运行起来呢?双击好像并没有反应啊?

                          首先,你要找到电脑上的【命令行界面】。

                          1. Linux 桌面、macOS 系统的同学肯定已经比较熟悉了,搜索 Console 或者 Terminal 就可以
                          2. Windows 就可以搜索使用 Cmd 或者 Powershell 等程序(WSL 的同学你坐下,你的 Console 当然也可以)

                          其次,我们要做的事情是【让 xray 找到并读取配置文件 config.json,然后运行】,所以:

                          1. 在 Windows 下,假设你的 Xray 程序位置是 C:\Xray-windows-64\xray.exe,配置文件位置是C:\Xray-windows-64\config.json,那么正确的启动命令就是:

                            C:\Xray-windows-64\xray.exe -c C:\Xray-windows-64\config.json
                             

                            说明

                            这里的 -c 就是指定配置文件路径的参数,告诉 xray 去后面的位置找配置文件

                          2. 相似的,在 Linux 和 macOS 下,假设你的 Xray 程序位置是 /usr/local/bin/xray,配置文件位置是/usr/local/etc/xray/config.json,那么正确的启动命令就是

                            /usr/local/bin/xray -c /usr/local/etc/xray/config.json
                             

                            说明

                            每个系统都有系统路径变量,所以写 Xray 程序时不一定要写绝对路径。但是写了肯定没错,所以我就如此演示了。

                          8.5 附加题 3:在 PC 端开机自动运行 xray-core

                          如果你真的尝试了手动运行 xray-core,你一定会发现这个方式还有点小问题:

                          1. 每次运行 Xray 都要出现一个黑乎乎的窗口,很丑
                          2. 不能开机自动运行,每次都要手工输入,十分不方便

                          我可以肯定的告诉你:完全可以解决。但是具体的解决方式,就当作课外作业留给大家吧!(友情提示,文档站的问答区有线索哦)

                          8.6 圆满完成!

                          我相信,有耐心看到这里的同学,都是兼具好奇心和行动力的学习派!我现在要郑重的恭喜你,因为到了这里,你已经完完整整的【从第一条命令开始,完成了 VPS 服务器部署,并成功的在客户端配置使用 Xray】了!这毫无疑问是一个巨大的胜利!

                          我相信,你现在一定对Linux不再恐惧,对Xray不再陌生了吧!

                          至此,小小白白话文圆满结束!

                          ⬛⬛⬛⬛⬛⬛⬛⬛ 100%

                          8.7 TO INFINITY AND BEYOND!

                          但现在你看到的,远远不是 Xray 的全貌。

                          Xray是一个强大而丰富的网络工具集合,平台化的提供了众多模块,可以像瑞士军刀一样,通过灵活的配置组合解决各种不同的问题。而本文,仅仅蜻蜓点水的用了最简单最直观的配置来做基础演示

                          如果你觉得现在已经完全够用了,那就好好的享受它给你带来的信息自由。但如果你的好奇心依然不能停歇,那就去继续挖掘它无限的可能性吧!

                          需要更多信息,可以到这里寻找:

                          1. xtls.github.ioopen in new tag - 官方文档站
                          2. 官方 Telegram 群组open in new tag - 活跃而友善的官方讨论社区

                          TO INFINITY AND BEYOND!

                          不算后记的后记

                          希望我陪你走过的这一段小小的旅程,可以成为你网络生活中的一份小小助力。

                          这篇文章里的工具和信息难免会一点点的陈旧过时,但你一定会逐渐成长为大佬。未来的某个时间,若你能偶尔想起这篇教程、想起我写下本文的初衷,那我衷心希望你能够薪火相传、把最新的知识分享给后来人,让这一份小小的助力在社区里坚定的传递下去。

                          这是个大雪封山乌云密布的世界,人们孤独的走在各自的路上试图寻找阳光,如果大家偶尔交汇时不能守望相助互相鼓励,那最终剩下的,恐怕只有【千山鸟飞绝 万径人踪灭】的凄凉了吧。

                          - + diff --git a/document/level-0/ch09-appendix.html b/document/level-0/ch09-appendix.html index 676a792a7f..b43e12bdaa 100644 --- a/document/level-0/ch09-appendix.html +++ b/document/level-0/ch09-appendix.html @@ -24,11 +24,11 @@ 【第 9 章】附录 | Project X - - + +

                          【第 9 章】附录

                          1. 小小白白 Linux 基础命令索引

                          编号命令名称命令说明出现篇章
                          cmd-01apt update查询软件更新《远程登录篇》
                          cmd-02apt upgrade执行软件更新《远程登录篇》
                          cmd-03nano文本编辑器《安全防护篇》
                          cmd-04systemctl restart重启某个服务《安全防护篇》
                          cmd-05adduser给系统新增用户《安全防护篇》
                          cmd-06apt install安装某个软件《安全防护篇》
                          cmd-07visudo修改 sudo 权限设置专用编辑器《安全防护篇》
                          cmd-08sudoroot权限运行某个命令《安全防护篇》
                          cmd-09chmod修改目标文件/文件夹的权限《安全防护篇》
                          cmd-10mkdir新建文件夹《网站建设篇》
                          cmd-11systemctl reload重新加载某个服务《网站建设篇》
                          cmd-12wget访问(或下载)某个网页文件《证书管理篇》
                          cmd-13acme.shacme.sh 证书管理相关的命令《证书管理篇》
                          cmd-14rm删除命令《Xray 服务器篇》
                          cmd-15crontab -e编辑当前用户的定时任务《Xray 服务器篇》
                          cmd-16touch建立空白文件《Xray 服务器篇》
                          cmd-17systemctlsystemd基本服务管理命令《Xray 服务器篇》
                          cmd-18reboot重启 Linux 系统《Xray 服务器篇》

                          2. 小小白白 Linux 重要配置文件索引

                          编号配置文件位置文件说明出现篇章
                          conf-01/etc/ssh/sshd_configSSH 远程登录程序设置《远程登录篇》
                          conf-02/etc/nginx/nginx.confNginx 程序设置《网站建设篇》
                          conf-03/etc/apt/sources.listapt 软件源列表《Xray 服务器篇》
                          conf-04/etc/apt/sources.list.d/vpsadmin.list用户自定义软件源列表列表《Xray 服务器篇》
                          conf-05crontab -e当前用户的定时任务《Xray 服务器篇》
                          conf-06/etc/sysctl.conf手动设置 kernel 参数《Xray 服务器篇》
                          conf-07/etc/sysctl.d/vpsadmin.conf用户自定义 kernel 参数配置文件《Xray 服务器篇》

                          3. 小小白白 Xray 重要文件索引

                          编号配置文件位置文件说明出现篇章
                          xray-01/usr/local/etc/xray/config.jsonXray 程序设置《Xray 服务器篇》
                          xray-02/home/vpsadmin/xray_cert/xray.certTLS 证书《Xray 服务器篇》
                          xray-03/home/vpsadmin/xray_cert/xray.keyTLS 私钥《Xray 服务器篇》
                          xray-04/home/vpsadmin/xray_log/access.logXray 访问日志《Xray 服务器篇》
                          xray-05/home/vpsadmin/xray_log/error.logXray 错误日志《Xray 服务器篇》
                          - + diff --git a/document/level-0/index.html b/document/level-0/index.html index 5ee0b6ebad..2ca337d7a3 100644 --- a/document/level-0/index.html +++ b/document/level-0/index.html @@ -24,11 +24,11 @@ 小小白白话文 | Project X - - + +

                          小小白白话文

                          这个章节是【从零开始】的基础课,新来的同学好好看好好学哦

                          提示

                          Made with ❤️ by @ricuhkaenopen in new tag

                          【第 1 章】 前言罗嗦篇 - 机场还是自建?这是个问题

                          【第 2 章】 原料准备篇 - 工欲善其事,必先利其器

                          【第 3 章】 远程登录篇 - 一桥飞架南北,天堑变通途

                          【第 4 章】 安全防护篇 - 安全不注意,亲人两行泪

                          【第 5 章】 网站建设篇 - 秀出你的美

                          【第 6 章】 证书管理篇 - 领证的才是合法的

                          【第 7 章】 Xray 服务器篇 - 终于等到你

                          【第 8 章】 Xray 客户端篇 - 新的开始

                          【第 9 章】 附录 - 考点都在这里

                          - + diff --git a/document/level-1/fallbacks-lv1.html b/document/level-1/fallbacks-lv1.html index 01830fdcca..0a07515c50 100644 --- a/document/level-1/fallbacks-lv1.html +++ b/document/level-1/fallbacks-lv1.html @@ -24,8 +24,8 @@ 回落 (fallbacks) 功能简析 | Project X - - + +

                          回落 (fallbacks) 功能简析

                          在使用 Xray 的过程中,你一定无数次的听说了【回落】这个功能。本文就稍微说明一下这个功能的逻辑以及使用方式。

                          1. 回顾《小小白白话文》中的回落

                          如果你用了《小小白白话文》中的Xray 配置,并完成了HTTP 自动跳转 HTTPS 优化,那么你已经有了基于 VLESS 协议的简易回落:

                          {
                          @@ -200,6 +200,6 @@
                             }
                           }
                           
                        4. 至此,我们就能够完整的画出模板的回落路线了:

                        6. 结语

                        至此,Xray 的【回落】功能就介绍完了。希望本文能够对你理解 Xray 的强大有所帮助。

                        7. 附加题

                        我再无耻的留一个附加题:本文详解的 VLESS-TCP-XTLS-WHATEVERopen in new tag 模板?是否有可以优化的地方?

                        提示:HTTP 自动跳转 HTTPS

                  - + diff --git a/document/level-1/fallbacks-with-sni.html b/document/level-1/fallbacks-with-sni.html index 427a46d482..4e2d17ef06 100644 --- a/document/level-1/fallbacks-with-sni.html +++ b/document/level-1/fallbacks-with-sni.html @@ -24,8 +24,8 @@ SNI 回落 | Project X - - + +

                  通过 SNI 回落功能实现伪装与按域名分流

                  VLESS 是一种很轻的协议,和 Trojan 一样,不对流量进行复杂的加密和混淆,而是大隐隐于市,通过 TLS 协议加密,混杂在其他 HTTPS 流量中,在墙内外穿进穿出。为了更好的伪装以应对主动探测,Fallbacks 回落功能随 VLESS 同时出现。这篇教程将演示如何使用 Xray 中 VLESS 入站协议的回落功能配合 Nginx 或 Caddy 在保证伪装完全的前提下实现按域名分流。

                  应用情景

                  由于 XTLS,Xray 需要监听 443 端口,这导致如果之前有网站运行在服务器上,那么此时网站无法运行或需要运行在其他端口上,这显然是不合理的。有以下三种方案可以解决这个问题:

                  • Xray 监听其他常用端口(如 22、3389、8443)

                    这个方案是最简单的,但不够完美。

                  • Nginx 或 HAProxy 监听 443 端口,通过 SNI 分流做 L4 反向代理,实现端口复用

                    这个方案比较复杂,需要对 Nginx 或 HAProxy 的使用有一定了解,此处不作过多解释。

                  • Xray 监听 443 端口,通过 Fallbacks 功能 SNI 分流将网站流量回落到 Nginx 或 Caddy

                    这个方案难度适中,也是此教程接下来想要演示的方案。

                  SNI 简介

                  服务器名称指示(英语:Server Name Indication,缩写:SNI)是 TLS 的一个扩展协议。熟悉反向代理的朋友都知道,如果想要通过域名将流量代理到正确的内容上,需要以下配置:

                  proxy_set_header Host 主机名;
                  @@ -210,6 +210,6 @@
                       redir https://{host}{uri} permanent
                   }
                   

                  参考

                  1. 服务器名称指示 - 维基百科,自由的百科全书open in new tag
                  2. Home · acmesh-official/acme.sh Wikiopen in new tag
                  3. HTTP/2 - 维基百科,自由的百科全书open in new tag

                  引用


                  1. 常见问题 - Let's Encrypt - 免费的 SSL/TLS 证书open in new tag ↩︎

                  2. Proxy Protocol - HAProxy Technologiesopen in new tag ↩︎

                  3. proxy protocol 介绍及 nginx 配置 - 简书open in new tag ↩︎

                  4. v2fly-github-io/vless.md at master · rprx/v2fly-github-ioopen in new tag ↩︎

                  - + diff --git a/document/level-1/index.html b/document/level-1/index.html index f20224aa7c..321cf2d144 100644 --- a/document/level-1/index.html +++ b/document/level-1/index.html @@ -24,11 +24,11 @@ 入门技巧 | Project X - - + +
                  - + diff --git a/document/level-1/routing-lv1-part1.html b/document/level-1/routing-lv1-part1.html index 679100c543..5a3c77c9f8 100644 --- a/document/level-1/routing-lv1-part1.html +++ b/document/level-1/routing-lv1-part1.html @@ -24,8 +24,8 @@ 路由 (routing) 功能简析(上) | Project X - - + +

                  路由 (routing) 功能简析(上)

                  如果说 Xray 的【强大】主要体现在它极致的速度和广泛的兼容性。那么 Xray 的【灵活】,则主要应该归功于它巧妙的【路由】功能。本文就稍微说明一下这个功能的逻辑以及使用方式。

                  1. 初识【路由】三兄弟

                  要理解路由,就要理解完整的路由功能需要有三兄弟来合力完成:1. 入站;2. 路由;3. 出站

                  路由三兄弟

                  三兄弟桃园结义,不求同年同月同日生,但求同年同月同日死。

                  所以谨记:任何一个元素错误,就可能导致路由功能无法正常工作。

                  因为路由的灵活性非常高,只看技术文档很容易把自己绕晕,所以本文我们用几个具体的示例来逐层讲解。

                  啰嗦君

                  路由功能实在过于灵活,所以本文的示例,都是为了讲解对应的概念,实际使用时请根据自己的需求进行调整。

                  2. 基本功: “兄弟一条心”

                  下图的示例,就是在客户端的 Xray 入站接收 APP 数据、在路由 100%转发给出站,并从出站流向 VPS。

                  下面我们来逐个分析:

                  2.1 入站

                  提示

                  入站: 就是流量如何流入 Xray

                  下面的入站配置示例,用大白话说就是:数据按照 socks 协议,通过 10808 端口,从本机 127.0.0.1 流入Xray。同时,Xray 将这个入站用 [tag] 命名为 inbound-10808

                  {
                  @@ -141,6 +141,6 @@
                     ]
                   }
                   

                  此时,路由规则其实变成了:

                  这就是路由功能的灵活之处了,你可以自由的改变它的顺序来实现不同的设计。

                  至此,我们已经解释完了 【如何利用 geosite.dat 文件,通过路由规则,根据【域名】来分流网络流量】。

                  5. 攻城略池 - 多种路由匹配条件

                  请确保你已经读懂了上面的内容,因为这样,你就已经理解了【路由】功能的工作逻辑。有了这个基础,我们就可以继续分析【路由】功能更多更详细的配置方式和匹配条件了。

                  等你看完后面的内容,就完全可以自由的定制属于自己的路由规则啦!还等什么,让我们一起进入 《路由 (routing) 功能简析(下)》 吧!

                  - + diff --git a/document/level-1/routing-lv1-part2.html b/document/level-1/routing-lv1-part2.html index e1f39a7789..59a4d7e4e2 100644 --- a/document/level-1/routing-lv1-part2.html +++ b/document/level-1/routing-lv1-part2.html @@ -24,8 +24,8 @@ 路由 (routing) 功能简析(下) | Project X - - + +

                  路由 (routing) 功能简析(下)

                  欢迎继续学习 Xray 的【路由】功能!

                  《路由 (routing) 功能简析(上)》 中,我们已经对【路由】功能的工作逻辑有了清晰的理解,也基于 geosite.dat 文件做了简单的域名分流配置。

                  如前面所说,域名分流仅仅是【路由】功能的牛刀小试而已。下面就让我们来看看除了域名之外,还什么可以用做分流依据的东西吧!

                  5. 攻城略池 - 多种路由匹配条件

                  [域名], [IP], [协议], etc.

                  基于域名的分流,已经可以让我们对网络流量进行基本合理的分流。为什么说【基本合理】呢?

                  因为【三分天下】虽然是正确的战略方向,但如果只用【域名】来实现这个战略,其实漏洞百出,比如:

                  1. 我读了《小小白白话文》后,给 VPS 新申请了一个 proxy.yourdomain.com 的域名, 我希望它无论如何都代理,geosite.dat 里面有吗?
                  2. 如果我还有个 direct.yourdomain.com 的域名,我希望它无论如何都直连, geosite.dat 里面有吗?
                  3. 本机 127.0.0.1 的内部流量,是否正确直连了?(比如 docker 等)
                  4. 路由器、本地局域网 192.168.*.* 的流量,是否正确直连了?(比如路由器、群晖等)
                  5. 我的国内 DNS 查询(如 223.5.5.5)是否正确直连了?
                  6. 我的国外 DNS 查询(如 1.1.1.1)是否正确代理了?
                  7. 其他类似国内公共 DNS 一样没有域名、只有 IP 地址的国内网站,是否正确直连了?
                  8. 其他类似国外公共 DNS 一样没有域名、只有 IP 地址的国外网站,是否正确代理了?
                  9. BT 下载的流量,虽然来源是国外,但如果通过 VPS 下载很可能导致违规使用被封,这该如何强制直连?
                  10. ......

                  我之所以说只用【域名分流】会漏洞百出,是因为 geosite.dat 文件内只包含了一部分常用的域名。换言之,仅仅依赖它,则会:

                  • 无法匹配文件里没有的新域名
                  • 无法匹配基于 IP 地址的规则
                  • 无法匹配基于网络协议的规则

                  啰嗦君

                  那我们来复习一下,当上面这些情况无法匹配时,会发生什么?对了,会触发隐藏路由规则,即【转发给第一个出站 】。这其实就是说:

                  • 当你的第一个出站是 [direct-out] 时:需要直连的都正确了,但需要代理的则都错误
                  • 当你的第一个出站是 [proxy-out-vless] 时:需要代理的都正确了,但需要直连的则都错误

                  所以,我们需要一个办法,让我们鱼与熊掌兼得。这样的办法是否存在呢?当然存在! 我们需要的只是【域名】之外更多的【分流判断依据】而已。

                  5.1 基于指定域名分流:[domain], [full]

                  1. 如果需要匹配某个子域名,如 a-name.yourdomain.com,我们使用 full: "a-name.yourdomain.com"
                  2. 前面的 问题1问题2,就可以通过给 proxy.yourdomain.com 指定 [proxy-out-vless] 出站,给 direct.yourdomain.com 指定 [direct-out] 出站来解决
                  3. 如果需要匹配 yourdomain.com 的所有子域名,我们使用 domain: "yourdomain.com" 实现
                  4. 上述两个可以成为两个独立的路由规则,达到某些子域名直连,其他子域名代理的配置
                  5. 另外,[domain] 还支持正则表达式等匹配方式。详情请参考 《基础配置模块 - 路由》文档

                  上述配置如下:

                  {
                  @@ -187,6 +187,6 @@
                     }
                   }
                   

                  其实,第 6 点已经是我整理过的规则了,原则就是【相同的匹配依据可以合并,不同的匹配依据保持独立】。

                  8. 明修栈道、暗渡陈仓

                  [domain] 转化 [ip] 的密道:domainStrategy

                  我们在 5.4 中提交了多种流量判断的【依据】,其中一种是域名 [domain]、一种是 [IP]

                  如果你初步了解过 DNS 的运作过程,就会知道,我们对一个域名 [domain] 发起访问请求时,其实需要先向 DNS 发起请求来解析域名 [domain] 对应的 [IP],在得到 [IP] 后再向它发起实际请求。

                  所以,面对入站的一次域名请求,Xray 其实有两次机会去判断它的类型。那么,究竟是否要用这两次机会呢?这就是由 domainStrategy 这个配置来决定的。它有三个选项:

                  • AsIs
                  • IPIfNonMatch
                  • IPOnDemand

                  按么我们逐个来解释一下:

                  8.1 域名策略: "AsIs"

                  就是 "As Domain Is",也就是说 【域名什么样,就什么样,不多折腾】。

                  简单粗暴理解就是说【仅用 [domain] 来匹配】。

                  提示

                  AsIs 的实际意义为 【如原先所示,不加修改】,🍉 老师这里描述的不是很恰当。

                  这个方式的处理都在 Xray 内部完成,没有与外界的数据往来,所以速度最快。它的兜底策略也很清晰:即前面所说的、无法匹配的域名自动转入第一条出站处理。所以,对于常规使用路由功能这最推荐的策略。

                  8.2 域名策略: "IPIfNonMatch"

                  就是 "lookup IP if (there's) no matching rule",也就是说【如果其他所有规则都匹配不上,那就转化成 IP 去匹配 IP 规则】。

                  简单粗暴理解就是说【先把访问目标和其他所有类型规则匹配,如果匹配不上,那就通过 DNS 查询转化成 IP,再从头和所有规则匹配一次】。

                  该策略下没有命中任何规则的这一部分域名,会需要再经历 DNS 查询过程、以及第二轮规则匹配的过程,其耗时会多于 AsIs 策略,所以并不是首选推荐的策略。

                  8.3 域名策略: "IPOnDemand"

                  这里其实说 Demand IP 更准确些,也就是说【当匹配时碰到任何基于 IP 的规则,将域名立即解析为 IP 进行匹配】。

                  简单粗暴理解就是说【只要路由规则中有 IP 类规则,那么所有基于域名 [domain] 的请求都要解析成 [IP] 然后去匹配 [IP] 类规则】。

                  它要对所有首次域名访问进行 DNS 解析,所以首次查询比较耗时。虽然由于 XrayDNS 缓存机制的存在,后续对相同域名的访问速度会重回巅峰,但总体来说也不是首选推荐的策略。

                  啰嗦君

                  domainStrategy 仅对域名生效,不要搞混了哦~

                  9. 思考题

                  迄今为止,我们都是在【单入站】和【单出站】的基础上,讲解【路由】内部的各种配置逻辑。

                  但是,如你所知,Xray 本身是支持多端口,多协议的。那么,如果我问你:

                  1. 我希望 VLESS 协议将我日常的网页浏览和 APP 流量转发给美国的大流量服务器
                  2. 我希望 trojan 协议将我的所有 Netflix 流量转发给日本的服务器解锁各种二次元
                  3. 我希望 shadowsocks 协议将我所有的游戏流量转发给香港的服务器达到最低的延迟
                  4. 我希望有一个独立的端口,能够把 telegram 的流量全都转发给 VPS
                  5. 我希望有一个独立的端口,能够把 bittorrent 下载流量全都转发给欧洲大盘鸡
                  6. 我希望......

                  这些想法,是否能通过【路由】功能配置实现呢?

                  答案当然是 【完全可以】 啦! 但是这些对于 level-1 来说已经超纲了,就留给各位自由的探索吧!

                  10. 结语

                  至此,Xray 的【路由】功能就介绍完了。希望本文能够对你理解 Xray 的灵活有所帮助。

                  11. 尾注

                  • 现在你可以重新阅读一遍 路由,看看是否有更加深刻的理解。
                  • 🍉🍉🍉🍉🍉 😄
                  - + diff --git a/document/level-1/work.html b/document/level-1/work.html index c8f79238be..4d7bb6d181 100644 --- a/document/level-1/work.html +++ b/document/level-1/work.html @@ -24,11 +24,11 @@ Xray 的工作模式 | Project X - - + +

                  Xray 的工作模式

                  单服务器模式

                  与其它的网络代理工具一样,你需要一台配置了 Xray 的服务器,然后在自己的设备上安装并配置 Xray 客户端,然后即可流畅地访问互联网。

                  一个 Xray 服务器可同时支持多台设备使用不同的代理协议访问。同时,经过合理的配置,Xray 可以识别并区分需要代理以及不需要代理的流量,直连的流量不需要绕路。

                  桥接模式

                  如果你不想在每一台设备上都配置路由,你也可以设置一台中转服务器,用于接收客户端发来的所有流量,然后在服务器中进行转发判断。

                  工作原理

                  在配置 Xray 之前,不妨先来看一下 Xray 的工作原理,以下是单个 Xray 进程的内部结构示意图。多个 Xray 之间相互独立,互不影响。

                  • 需要配置至少一个入站连接(Inbound)和一个出站连接(Outbound)才可以正常工作。
                    • 入站连接负责与客户端(如浏览器)通信:
                      • 入站连接通常可以配置用户认证,如 ID 和密码等;
                      • 入站连接收到数据之后,会交给分发器(Dispatcher)进行分发;
                    • 出站连接负责将数据发给服务器,如另一台主机上的 Xray。
                  • 当有多个出站连接时,可以配置路由(Routing)来指定某一类流量由某一个出站连接发出。
                    • 路由会在必要时查询 DNS 以获取更多信息来进行判断。
                  - + diff --git a/document/level-2/index.html b/document/level-2/index.html index 1b9140fd93..816aa94f0e 100644 --- a/document/level-2/index.html +++ b/document/level-2/index.html @@ -24,11 +24,11 @@ 进阶文档 | Project X - - + +

                  进阶文档

                  这个章节包含进阶级的 Xray 使用心得分享, 如果您已经熟悉 Xray, 那么这里的经验可以让您更加发挥 Xray 的威力

                  透明代理入门 by a @kirinopen in new tag

                  透明代理的入门篇章。

                  透明代理(TProxy)配置教程 by a @BioniCosmosopen in new tag

                  基于 Xray 的透明代理(TProxy)配置完整教程。

                  TProxy 透明代理(ipv4 and ipv6)配置教程 by a @SQLimitopen in new tag

                  基于 Xray 的 TProxy 透明代理(ipv4 and ipv6)配置教程

                  Nginx 或 Haproxy 搭建 TLS 隧道隐藏指纹 by a @SQLimitopen in new tag

                  双端使用 Nginx 或 Haproxy 搭建 TLS 隧道隐藏指纹

                  [透明代理]通过 gid 规避 Xray 流量 by a @kirinopen in new tag

                  在 iptables/nftables 实现的透明代理中,一种新的规避 Xray 流量的方式。

                  通过 Xray 将特定的流量指向特定出口,实现全局路由“分流” by a @Zzz3mopen in new tag

                  将 Xray 玩出花:基于 fwmark 、 sendThrough 或 sockopt.interface 方式实现“分流”。

                  通过 Cloudflare Warp 增强代理安全性 by a @yuhan6665open in new tag

                  Xray v1.6.5 新增 WireGuard 出站的使用介绍。

                  Xray 流量统计 by a @yuhan6665open in new tag

                  适配 Xray 的流量统计和脚本。

                  - + diff --git a/document/level-2/iptables_gid.html b/document/level-2/iptables_gid.html index 0a4387102e..1556f1a113 100644 --- a/document/level-2/iptables_gid.html +++ b/document/level-2/iptables_gid.html @@ -24,8 +24,8 @@ GID 透明代理 | Project X - - + +

                  透明代理通过 gid 规避 Xray 流量

                  在现有的 iptables 透明代理白话文(新 V2Ray 白话文指南-透明代理open in new tag新 V2Ray 白话文指南-透明代理(TPROXY)open in new tag透明代理(TProxy)配置教程)教程中,对 Xray 流量的规避处理是打 mark 实现的。即对 Xray 出站流量打 mark,通过设置 iptables 规则对对应 mark 的流量直连,来规避 Xray 流量,防止回环。

                  这么做有以下几个问题:

                  1. 莫名流量进入 PREROUTING 链open in new tag

                  2. 安卓系统有自己的 mark 机制,该方案在安卓上不可用

                  本教程的方案不需要设置 mark,理论性能更高,同时也不存在上述问题。

                  思路

                  tproxy 流量只能被 root 权限用户(uid==0)或其他有 CAP_NET_ADMIN 权限的用户接收。

                  iptables 规则可以通过 uid(用户 id)和 gid(用户组 id)分流。

                  让 Xray 运行在一个 uid==0 但 gid!=0 的用户上,设置 iptables 规则不代理该 gid 的流量来规避 Xray 流量。

                  配置过程

                  1. 前期准备

                  安卓系统

                  1. 系统已 root

                  2. 安装 busyboxopen in new tag

                  3. 有一个可以执行命令的终端,可以使用 adb shell,termux 等。

                  其它 Linux 系统

                  需要依赖 sudo,iptables 的 tproxy 模块和 extra 模块。

                  一般系统都有自带,openwrt 运行:

                  opkg install sudo iptables-mod-tproxy iptables-mod-extra
                  @@ -126,6 +126,6 @@
                   ip6tables -t mangle -A OUTPUT -p tcp -j XRAY6_MASK
                   ip6tables -t mangle -A OUTPUT -p udp -j XRAY6_MASK
                   
                  - + diff --git a/document/level-2/nginx_or_haproxy_tls_tunnel.html b/document/level-2/nginx_or_haproxy_tls_tunnel.html index ea8c1e0eb9..8467e531d4 100644 --- a/document/level-2/nginx_or_haproxy_tls_tunnel.html +++ b/document/level-2/nginx_or_haproxy_tls_tunnel.html @@ -24,8 +24,8 @@ Nginx 或 Haproxy 搭建 TLS 隧道隐藏指纹 | Project X - - + +

                  Nginx 或 Haproxy 实现的 HTTPS 隧道、HTTP/2 over HTTPS 隧道、WebSocket over HTTP/2 over HTTPS 隧道、gRPC over HTTP/2 over HTTPS 隧道以及自签证书双端认证的 gRPC over HTTP/2 over HTTPS 隧道

                  客户端服务端 Nginx 构建 HTTPS 隧道隐藏指纹

                  网路结构:

                  xray_client ---tcp--- nginx_client ---HTTPS--- nginx_sever ---tcp--- xray_server

                  编译 nginx --with-stream

                  在客户端及服务端均编译

                  curl -O -L http://nginx.org/download/nginx-1.22.1.tar.gz

                  tar -zxvf nginx-1.22.1.tar.gz

                  cd nginx-1.22.1

                  apt install gcc make //编译依赖 gcc 以及 make

                  ./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_v2_module --with-stream --with-stream_ssl_module //此步需要依赖一些库,根据报错安装相应 lib

                  make && make install

                  编译之后 nginx 文件夹位于 /usr/local/nginx

                  配置 nginx

                  编辑 nginx 配置文件 nginx.conf

                  vim /usr/local/nginx/conf/nginx.conf

                  服务端加入如下配置

                  服务器申请证书不再赘述,参考白话文

                  stream {
                  @@ -548,6 +548,6 @@
                   backend web
                       server web /dev/shm/h1h2c.sock
                   

                  xray 配置

                  简单的 gRPC 配置,无需 TLS,配置见文档,配置的 serviceName 可用于分流。

                  - + diff --git a/document/level-2/redirect.html b/document/level-2/redirect.html index a40592491d..36e47522a7 100644 --- a/document/level-2/redirect.html +++ b/document/level-2/redirect.html @@ -24,8 +24,8 @@ 出站流量重定向 | Project X - - + +

                  基于 fwmark 或 sendThrough 的流量重定向

                  通过 Xray 将特定的流量指向特定出口,实现全局路由“分流”

                  前言

                  之前在网络上看到许多代理或者 VPN 会接管全局路由,如果与 Xray 同时安装,会导致 Xray 失效。参考了网络上许多教程,及时分流,也是通过维护一张或者多张 CIDR 路由表来实现的。这种情况下并不优雅,如果我想可以任意替换,实现按需分流,那有没有更好的办法呢?有!

                  通过 fwmark 或 Xray 的 sendThrough/sockopt.interface,再简单配合路由表功能即可实现:

                  1. Xray 可设置指定的 Tag、域名等走指定接口。如果您的接口是双栈的,可以指定 IPV4 或者 IPV6
                  2. 其余用户则走原 IPV4 或者 IPV6

                  具体设置如下(以 Debian10 为例):

                  1、安装代理或者 VPN 软件(例如 Wireguard、IPsec 等)

                  根据不同系统和不同软件,请参考官方安装方法

                  2、编辑 VPN 配置文件(以 WireGuard 为例)

                  原始文件:

                  [Interface]
                  @@ -168,6 +168,6 @@
                   

                  开机自启

                  systemctl enable wg-quick@wg0
                   systemctl start wg-quick@wg0
                   

                  验证 IPv4/IPv6

                  在代理上 运行 curl ip-api.com -4/-6 / 浏览器访问ip-api.com

                  后记

                  本文本意是可以避免的多余的流量浪费,将路由和分流的功能交给 Xray 处理。避免了维护路由表的繁琐工作。顺便技术提升 UP。

                  感谢

                  XTLS/Xray-coreopen in new tag; v2fly/v2ray-coreopen in new tag; WireGuardopen in new tag; @p3terxopen in new tag; @w; @Hiram; @Luminous; @Ln; @JackChou;

                  - + diff --git a/document/level-2/tproxy.html b/document/level-2/tproxy.html index 3d79ce1f05..46747f5a23 100644 --- a/document/level-2/tproxy.html +++ b/document/level-2/tproxy.html @@ -24,8 +24,8 @@ TProxy 透明代理 | Project X - - + +

                  透明代理(TProxy)配置教程

                  本配置基于TProxy 透明代理的新 V2Ray 白话文教程open in new tag,加入了 Xray 的新特性,使用 VLESS + XTLS Vision 方案,并将旧教程中默认出站代理的分流方式改为默认出站直连,使用者请按照实际情况进行修改。

                  本文中所有配置已在 Raspberry Pi 2B、Ubuntu 20.04 环境下测试成功,如在其它环境中使用请自行调整配置。

                  开始之前

                  请检查您的设备是否有可用的网络连接,且服务端已经配置成功,客户端已经安装完毕。

                  需注意的是,目前很多透明代理教程都会将 Linux 系统的 IP 转发打开,但这样会导致 Splice 性能下降。详情请参考大案牍术破案纪实第三篇--我们是如何破解 Splice 性能下降甚至低于 Direct 之谜的open in new tag

                  这里我想要补充的是,很多透明代理教程会使用 Netfilter 进行分流,使直连流量直接发出而不经过 Xray,这时必须开启 IP 转发;也有的教程,如本文,会将所有流量导入 Xray 之中,由 Xray 的路由模块进行分流,这时无需开启 IP 转发。

                  Xray 配置

                  为了更好的分流体验,请替换默认路由规则文件为 Loyalsoldier/v2ray-rules-datopen in new tag,否则 Xray-core 将无法加载本配置。

                  sudo curl -oL /usr/local/share/xray/geoip.dat https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat
                  @@ -281,6 +281,6 @@
                   [Install]
                   WantedBy=multi-user.target
                   
            - + diff --git a/document/level-2/tproxy_ipv4_and_ipv6.html b/document/level-2/tproxy_ipv4_and_ipv6.html index 34f5056c1d..f3ee2f6260 100644 --- a/document/level-2/tproxy_ipv4_and_ipv6.html +++ b/document/level-2/tproxy_ipv4_and_ipv6.html @@ -24,8 +24,8 @@ TProxy 透明代理 (ipv4 and ipv6) | Project X - - + +

            TProxy 透明代理(ipv4 and ipv6)配置教程

            本配置参考了TProxy 透明代理的新 V2Ray 白话文教程open in new tag透明代理(TProxy)配置教程open in new tag以及透明代理通过 gid 规避 Xray 流量open in new tag,加入了透明代理对 ipv6 的支持,并且使用 VLESS-TCP-XTLS-RPRX-Vision 方案对抗封锁 (推荐使用 1.7.2 及之后版本)。

            关于 Xray 的配置并不是本文重点,使用者可依实际情况进行修改,具体可以参考官方文档示例open in new tag或其他优秀示例 比如@chika0801open in new tag 又如@lxhao61open in new tag

            注意

            若使用其他配置,你需要着重注意客户端配置中 outboundtagproxy 的部分,其他部分不变

            服务端配置也要同时改变

            此配置意在解决例如 Netflix 等默认使用 ipv6 连接的网站无法通过旁路由进行代理的问题,或对 ipv6 代理有需要。

            本文网络结构为单臂旁路由

            本文中所有配置已在 Arch Linux (Kernel: 6.0.10) 环境下测试成功,如在其它环境中同理

            注意安装相应程序 # sudo apt install iptables ip6tables# sudo apt install nftables

            若旁路由未安装 xray 程序,可以手动下载相应 xray 程序如 Xray-linux-64.zipopen in new tag ,然后复制 install-release.shopen in new tag 文件到旁路由,赋予可执行权限 # chmod 700 install-release.sh,然后使用 # ./install-release.sh --local Xray-linux-64.zip 根据提示进行本地安装。

            Xray 配置

            客户端配置

            {
            @@ -429,6 +429,6 @@
             [Install]
             WantedBy=multi-user.target
             
            1. 最后执行 systemctl enable tproxyrules 命令。

            tproxyrules.service

            注意其中主路由器 IP 地址,根据实际修改

            ExecStartPre=/bin/sh -c 'until ping -c1 192.168.31.1; do sleep 1; done;' 命令为确保获得 IP 地址后再执行命令,否则会诡异报错,其中 IP 地址为主路由器地址,根据实际修改。

            注意

            如果通过 dhcpcd 等设置了静态 IP 及网关,则上述相关 ip route add/del 设置需删除

            局域网设备上网设置

            此处假定旁路由 ipv4, ipv6 地址分别为192.168.31.100, fd00:6868:6868::8866, 旁路由的 ipv4, ipv6 地址可由命令ip add获得。

            方法一

            局域网设备上网有两种方式,第一种就是在使用设备上进行静态 IP 的配置,将网关指向旁路由 IP。注意绝大部分手机仅支持手动配置 ipv4 网关,不支持手动配置 ipv6 网关,除非 root 后进行相关设置。

            以 windows 设备为例,可以先开启 DHCP 记录自动分配的 IP 以参考,然后手写静态配置。

            DNS 设置

            此配置劫持 DNS 流量,DNS 可以随便写

            建议设置为旁路由 IP,防止 DNS 泄露

            image image

            方法二

            局域网设备上网的第二种方式,是在路由器上进行网关设置,这种方法对于连接到此路由器的设备无需做任何设置即可科学上网,但注意有些路由器不支持 ipv6 的网关设置,有 ipv6 需求的设备仍需在所需设备上单独手动配置 ipv6 相关设置参考方法一。

            image

            Finally

            按照以上方法设置后设备即可双栈访问,进入测试网站比如 https://ipv6-test.com/ 可以看到如下结果 (需要代理此网站才能看到如下结果)

            image

            写在最后

            如今 ipv6 并未完全普及,我们日常访问的流量 99%仍为 ipv4 流量;很多 VPS 商家虽然提供 ipv6 地址,但线路优化非常垃圾,甚至处于不可用状态,为何要加入 ipV6 的设置?

            可以看到目前 ipv6 处于很尴尬的境地,各种设备对于 ipv6 的支持很烂,但是都在逐步完善,同时 Windows 系统对于 ipv6 的优先级也在提高,很多浏览器也会优先进行 ipv6 的解析以及访问,很多网站也开始默认使用 ipv6 进行访问(比如 Netflix, 如果没有配置 ipv6, 浏览器打开 Netflix 会显示 Not Available 是因为没有代理 Netflix 的 ipv6 请求,当然可以选择禁用 Windows 的 ipv6,但支持 ipv6 的 pt 站就无法使用)

            这种情况下 ipv4 无法完全胜任网络冲浪的需求,即使是那 1%的流量,遇到了也会让人头疼不已。

            而可以预见 ipv6 也会逐步与 ipv4 分庭抗礼,所以有必要加入 ipv6 的设置。

            - + diff --git a/document/level-2/traffic_stats.html b/document/level-2/traffic_stats.html index cb34e44347..1856a577a7 100644 --- a/document/level-2/traffic_stats.html +++ b/document/level-2/traffic_stats.html @@ -24,8 +24,8 @@ 流量统计 | Project X - - + +

            流量统计配置教程

            请熟悉流量统计 白话文教程open in new tag,本文在其基础上适配了 Xray(1.5.9+)。

            查看流量信息

            配置方法与 v2fly 一致。 查看流量信息是 xray 命令行的其中一个功能。配置内设置的 api dokodemo-door 端口,即为 --server 参数的端口。

            xray api statsquery --server=127.0.0.1:10085 #查看所有流量
            @@ -120,6 +120,6 @@
             print_sum "$DATA" "user"
             echo "-----------------------------"
             
            - + diff --git a/document/level-2/transparent_proxy/transparent_proxy.html b/document/level-2/transparent_proxy/transparent_proxy.html index 462140b1e2..e58851abea 100644 --- a/document/level-2/transparent_proxy/transparent_proxy.html +++ b/document/level-2/transparent_proxy/transparent_proxy.html @@ -24,8 +24,8 @@ 透明代理入门 | Project X - - + +

            透明代理入门

            什么是透明代理

            透明代理简单地说就是不让被代理的设备感觉到自己被代理了。简单地说就是,被代理的设备上不需要运行任何代理软件(比如 Xray、V2RayNG 等),当你连接上网络时,你的设备已经被代理了。

            这也意味着,代理的软件运行在别的地方,比如运行在路由器中,通过路由器上网的设备就自动被代理了。

            透明代理的实现

            透明代理的实现目前主要有两种方式:

            tun2socks

            可用 Windows/Linux(包括安卓)实现。因为实现过程比较简单,很少有教程,我这里简单描述一下。

            Windows

            1. 安装 Netchopen in new tag ,使用模式[3] [TUN/TAP] 绕过局域网启动。

            2. 开启热点

            3. 打开控制面板->网络和 Internet->网络和共享中心->更改适配器设置,找到TAP-Windows AdapterMicrosoft Wi-Fi Direct Virtual Adapter

            4. 鼠标右键点击TAP-Windows Adapter属性->共享,勾选允许其他网络用户通过此计算机的 Internet 连接来连接,在家庭网络连接中选择Microsoft Wi-Fi Direct Virtual Adapter的那个网络连接,点击确定。

            Android

            1. 配置连接 V2RayNG

            2. 开启热点

            3. 热点设置 -> 允许热点使用 VPN(部分安卓系统可能没有这个选项)

            iptables/nftables

            iptables 与 nftables 实现透明代理的原理相同,下文统一使用 iptables。

            基于 iptables 的透明代理实现只能用于 Linux 系统(包括 openwrt/安卓)。由于其比 tun2socks 更高效率以及适合在路由器中配置而广泛使用。

            现存的三篇白话文透明代理教程其实讲的都是基于这种方案的透明代理实现,它们是: 新 V2Ray 白话文指南-透明代理open in new tag新 V2Ray 白话文指南-透明代理(TPROXY)open in new tag透明代理(TProxy)配置教程 。其中第一篇是基于 iptables-redirect 模式,已经过时了,不建议使用,仅供参考。第二篇和第三篇讲的都是基于 iptables-tproxy 模式的透明代理实现。

            iptables 实现透明代理原理

            Linux 使用Netfilter来管理网络,Netfilter模型如下:

            Netfilter

            假设使用路由器作为网关(即我们平时的上网方式),那么:

            局域网设备通过路由器访问互联网的流量方向:

            PREROUTING链->FORWARD链->POSTINGROUTING链

            局域网设备访问路由器的流量(如登陆路由器 web 管理界面/ssh 连接路由器/访问路由器的 dns 服务器等)方向:

            PREROUTING链->INPUT链->网关本机

            路由器访问互联网的流量方向:

            网关本机->OUTPUT链->POSTINGROUTING链

            通过使用 iptables 操控PREROUTING链OUTPUT链的流量走向,转发到 Xray,就可以代理局域网设备和网关本机。

            透明代理难在哪里

            透明代理的难点就在于路由,所谓路由,就是区分哪些流量是直连的,哪些该被代理,所以我个人认为叫做分流更加合适。

            我们可以把路由由易到难分为以下几个阶段:

            1. 代理全部请求

            2. 本地局域网 IP/组播 IP 请求直连,其它请求代理

            3. 在 2 的基础上直连 Xray 发起的连接请求

            4. 在 3 的基础上直连指向中国大陆 IP 的连接请求,并对国内外域名选择国内外 DNS 服务器解析。

            上面说的三篇教程,都是在第四阶段。所以新手直接阅读可能显得有点难懂。

            从零开始一步步实现基于 iptables-tproxy 的透明代理

            在开始之前,你需要有一定的基础知识:

            1. 大概知道什么是 TCP/IP 协议、域名和 DNS 服务器

            2. 知道什么是 WAN 口,LAN 口,LAN_IP,WAN_IP 以及 DHCP 服务器。对于旁路由,只有一个网口,这里称其为 LAN 口

            3. 对 Linux 系统有最基础的了解(知道怎么运行命令)

            4. 能够手写客户端 json 文件配置,至少要能看懂

            前期准备工作

            注意

            在开始操作前,记得使用 sysctl -w net.ipv4.ip_forward=1 打开linux ipv4封包转发

            1. 准备一个运行 Linux 系统的网关

            比如,刷了 OpenWRT 的路由器

            2. 在网关(路由器)准备好 Xray 可执行文件以及配置文件

            配置文件监听 12345 端口,开启 tproxy:

            {
            @@ -111,6 +111,6 @@
             iptables -t mangle -A OUTPUT -p tcp -j XRAY_MASK
             iptables -t mangle -A OUTPUT -p udp -j XRAY_MASK
             

            但是这么配置有个缺点,如果使用 CDN 或者 VPS 很多的话,就不好写规则了。

            1. 通过 mark 规避

            三个白话文教程都是使用这种方法规避,自行参考,这里不再赘述。

            1. 通过 gid 规避(推荐)

            参考 [透明代理]通过 gid 规避 Xray 流量

            这样就完成了第三阶段的代理,也就是平时说的全局代理。但是记得把网关的 DNS 服务器设置为国外的 DNS 服务器,否则可能依然返回被污染的结果。

            第四阶段

            其实,并不是所有人都需要实现第四阶段。全局代理对于大部分情况已经适用。

            特别是对于旁路由而言。需要代理时,将网关调成旁路由的 IP,不需要代理时,将网关换回主路由 IP。

            至于第四阶段的具体实现,那三篇白话文教程讲的都是。在理解了上面的内容后,再去看那三篇白话文教程,就比较容易理解了。

            代理 ipv6

            上面的规则只对 ipv4 生效,如果还想要代理 ipv6 请求,则使用 ip6tables 命令,用法与 iptables 基本相同。参考 [透明代理]通过 gid 规避 Xray 流量#4-设置 iptables 规则

            iptables 透明代理的其它注意事项

            1. 如果作为代理的网关作为主路由,要在PREROUTING链规则中加一条iptables -t mangle -A XRAY ! -s 网关LAN_IP地址段 -j RETURN,即在第一阶段使用、第二阶段被删除的指令。如果不写,WAN 口中同网段的其它人可以将网关填写成你的 WAN_IP,从而蹭你的透明代理用,还可能带来一定的危险性。

            2. 新 V2Ray 白话文指南-透明代理(TPROXY)#设置网关open in new tag 中的第三条说:手动配置 PC 的网络,将默认网关指向树莓派的地址即 192.168.1.22。此时 PC 应当能正常上网(由于还没设置代理,“正常”是指可以上国内的网站)。实际上,Ubuntu、CentOS、debian 等系统就算开启了 IP 转发,PC 也不能正常上网,这是正常的。事实上只有 OpenWRT 能做到文中所描述的那样,据 @BioniCosmosopen in new tag 点拨,这是由于一般的 Linux 系统没有 Masquery 规则。

            3. too many open files 问题open in new tag ,解决方法见 [透明代理]通过 gid 规避 Xray 流量-配置最大文件大开数&运行 Xray 客户端

            4. 避免已有连接的包二次通过 TPROXY ,待补充...

            5. 主路由、单臂路由与旁路由,待补充...

            - + diff --git a/document/level-2/warp.html b/document/level-2/warp.html index e21dc05b0d..2561a2ca36 100644 --- a/document/level-2/warp.html +++ b/document/level-2/warp.html @@ -24,8 +24,8 @@ 通过 Cloudflare Warp 增强代理安全性 | Project X - - + +

            通过 Cloudflare Warp 增强代理安全性

            Xray(1.6.5+)新加入了 WireGuard 出站,虽然增加的代码和依赖会增大 core 体积,但是我们认为这是一个很有必要的新功能,原因有三:

            1. 通过近期的一些讨论和实验open in new tag,我们知道代理回国流量是不安全的。一种应对方式是将回国流量路由至黑洞,它的缺点是由于 geosite 和 geoip 更新的不及时或者新手不知道如何在客户端适当分流,结果流量进入黑洞,影响使用体验。 这时我们只需要将回国流量导入 Cloudflare Warp,可以在不影响使用体验的情况下达到同样的安全性。
            2. 众所周知,大部分机场会记录用户访问域名的日志,某些机场还会审计和阻断一些用户流量。保护用户私密性的一个方法,就是在客户端使用链式代理。 Warp 使用的 WireGuard 轻量级 VPN 协议会在代理层内增加一层加密。对于机场而言,用户所有流量的目标都是 Warp,从而最大程度保护自己的隐私。
            3. 方便使用,只需要一个 core 即可完成分流,Wireguard Tun,链式代理的设置。

            申请 Warp 账户

            感谢 Cloudflare 推动自由的互联网,现在你可以免费使用 Warp 服务,连接的时候会根据出口自动选择最近的服务器

            方法 1:

            1. 使用一台 vps,下载 wgcfopen in new tag
            2. 运行 wgcf register 生成 wgcf-account.toml
            3. 运行 wgcf generate 生成 wgcf-profile.conf 拷贝内容如下:
            [Interface]
            @@ -187,6 +187,6 @@
                ]
             }
             
            - + diff --git a/en/about/news.html b/en/about/news.html index 848af0c9ca..84a782e0a9 100644 --- a/en/about/news.html +++ b/en/about/news.html @@ -24,11 +24,11 @@ The Great Chronicles | Project X - - + +

            The Great Chronicles

            2024.9.12

            The Great Chronicles Return to the Scene?!

            2024.9.7 v24.9.7open in new tag

            First release after abandoning semantic versioning.

            • This time, QUIC and DomainSocket transports were removed, along with two pieces of legacy code.
              • The binary size is 1MB smaller than v1.8.24.
            • As always, there are essential bug fixes.

            2024.8.30 v1.8.24open in new tag

            While waiting for the SplitHTTP multiplex controller, the main branch had accumulated many important updates, so we decided to release a version first.

            • The Socks inbound now supports HTTP proxy requests by default.
            • UDP noise (preview)
            • And some other improvements.

            Due to the existence of semantic versioning, planning features and scheduling for each release have severely hindered the development, merging, and release of new features. Therefore, we decided to abandon semantic versioning starting with the next release and use the release date as the version number, such as v24.8.30, and cancel version planning, fully adopting continuous updates. Features will be merged and released as soon as they are ready, with a version released at the end of each month.

            After all, as a software aiming to help people bypass censorship, instead of maintaining a long-term stable version, it's more important to adapt new features and keep updating monthly.

            The next version will remove some legacy code no longer in used, add warning log for using deprecated features/configs, and for sure, some breaking changes. Be aware that future versions will be released once we consider something new is ready for a release.

            We believe that with your donations and the reform of the release format, the Xray-core project will develop even better.

            2024.8.26

            The Project VLESS group was established.

            We have created Project VLESSopen in new tag for non-Chinese users (mainly Russian).

            2024.8.3

            The first Project X NFTopen in new tag is officially released! Just as Xray has made history, releasing an NFT is also an unprecedented move in this field. These NFTs are highly commemorative and even historically significant, far beyond their current initial price. In time, they will undoubtedly become priceless. Once again, thank you for your support of Project X.

            2024.7.29 v1.8.23open in new tag

            • Congratulations to @mmmrayopen in new tag for contributing the 1000th commit to Xray-core!
            • Optimized the stability of SplitHTTP upstream, and the server must be upgraded to this version to support the new client.
            • More changes on SplitHTTP.

            2024.7.22 v1.8.21open in new tag

            It seems to have returned to the original state of rapid-fire releases...

            As foreshadowed in v1.8.16, SplitHTTP now preliminarily supports HTTP/3 (QUIC). Undoubtedly, SplitHTTP H3 has ushered in a new era.

            • SplitHTTP H3 is the first QUIC-based proxy fully compliant with standard H3, supporting CDN passthrough, and can be concealed using reverse proxy or Browser Dialer.

            2024.7.16

            Project X documentation now has a Russian version! Thanks to @iambabyninjaopen in new tag for the translation!

            Привет, друзья из России!

            2024.7.15

            Through known information and efforts, Xray-core now supports Windows 7 again! In subsequent releases, Windows 7 users can enjoy it by downloading and extracting the Xray-win7-32.zip or Xray-win7-64.zip packages. Thank you for your support! For specific usage, please click here

            Although Windows 7 will eventually be phased out with future upgrades, we can now delay that time a little.

            2024.6.18 v1.8.16open in new tag

            A new transport has arrived, currently called SplitHTTP.

            • There are two completely opposite ways to achieve further traffic obfuscation: multiplexing and splitting connections.
            • It can achieve the same goals as Meek through CDNs that do not support WebSocket or gRPC, and SplitHTTP is simpler and more efficient than Meek.
            • SplitHTTP does not have WebSocket's ALPN issues, which is a major advantage, and it will support HTTP/3 (QUIC) in the future.
            • SplitHTTP has also been added to the sharing link package.

            2024.6.2

            A new transport method is being developed...

            2024.4.26 v1.8.11open in new tag

            • Now there is a tool to generate ECH keys.
            • Enhancements, fixes, and some obsolete code removal.

            2024.4.20

            We now have issue templates, thanks to @Fanglidingopen in new tag!

            2024.4.13

            VLESS Seed is ready, waiting for the right moment.

            2024.3.18 v1.8.10open in new tag

            Like WebSocket, HTTPUpgrade now also has 0-RTT.

            2024.3.11 v1.8.9open in new tag

            Added HTTPUpgrade transport, said to be lighter than WebSocket.

            • Already added to the sharing link package.

            2024.2.29

            gRPC transport now also has a Host-like configuration field! It's called authority. Now gRPC can also "domain front," without ALPN issues.

            2024.2.25 v1.8.8open in new tag

            • Now XUDP traffic is uniformly padded with Vision, come and experience it.
            • Added leastLoad balancer.
            • Fixed errors, optimized performance...

            2024.1.9

            Shocked to hear that Win7 cannot run the new version of Xray-core? Upon exploration, it was discovered that Go has dropped support for Win7. Is there a way to continue supporting this somewhat ancient but still elegant operating system?

            2023.11.21

            The paperopen in new tag published at the USENIX top conference confirms that XTLS Vision has achieved its design goals. And XTLS will not stop there, breaking through towering walls like X-rays.

            2023.11.18 v1.8.6open in new tag

            • WireGuard now also has a corresponding inbound. Freedom outbound finally has splice.
            • The domainStrategy for outbound has also been unified.
            • More delicious little treats.
            • Due to force majeure feature changes, Dragonfly BSD support has quietly left the stage.
            • Are we really saying goodbye to the classic Windows 7?

            2023.9.30

            Designed a brand new color scheme for v2rayNG, install the latest Pre-release version to experience it.

            2023.8.29 v1.8.4open in new tag

            After half a year of polishing, 1.8.x has finally reached its first recognized official version. Likewise, there are many integrated improvements this time, come and taste it!

            2023.7.22

            Another historical HTTP/2 transport issue has been fixed.

            2023.7.7

            Vision will soon have Seed support.

            2023.6.30

            The next XTLS flow control: xtls-rprx-switch 🍪

            • XTLS's 0-RTT has been teased for months, originally to maintain some mystery.
            • Compared to the existing XTLS Vision and Mux, it has even better advantages.

            2023.6.27

            How to choose a REALITY target domain? Check here to help you achieve twice the result with half the effort!open in new tag

            2023.6.19 v1.8.3open in new tag

            • The first version after the code streamlining plan, VMess (MD5), MTProto, and Starlark-related code have been removed. Going light.
            • Code refactoring is also part of going light.
            • We have also not forgotten to add some enhancements and fix vulnerabilities.
            • v2rayNG has not yet supported Xray, and the new sharing link format cannot be used yet.

            2023.6.6

            Good News: The next XTLS flow control will not be called Vision. 🍪

            2023.4.21

            Maybe we can leverage RealiTLScanneropen in new tag……

            2023.4.20

            After years of development and countless lines of code... The code simplification planopen in new tag has been proposed!

            2023.4.19

            xtls-0rtt-vision(-udp443) 🍪

            2023.4.18 v1.8.1open in new tag

            The upgraded XUDP is here!

            • Now XUDP features connection migration and port reuse, with a global Session ID , so mom doesn't have to worry about what to do when there is an unexpected disconnection anymore.
            • We’ve also added control settings for XUDP, giving you better control~
            • The new XUDP paired with XTLS Vision offers an even better experience~
            • As usual, there’s a little treat, enjoy~

            2023.4.6

            XUDP is also quietly upgrading...

            2023.3.29

            PLUX protocol 🍪

            2023.3.19

            The sharing link standard for REALITY has also emerged.

            2023.3.9 v1.8.0open in new tag

            THE NEXT FUTURE, REALITY is NOW release on Xray-core

            REALITY has been implemented and released! Welcome to try it out! XTLS Vision has also been improved, please upgrade both ends to the latest version for the best experience.

            • Due to changes in the Vision padding algorithm, there may be compatibility issues between old and new versions of XTLS Vision.
            • HTTP/2 transport has also been improved, enjoy the smooth experience with the new version~
            • There are many other small improvements, feel free to explore~

            2023.3.4

            Legends never die, they become a part of you VLESS.

            They simply fade away.

            2023.3.2

            Some lingering issues with HTTP/2 transport have been improved. Enjoy the smooth experience when testing with REALITY~

            2023.2.16

            THE NEXT FUTURE becomes THE REALITY NOW!

            2023.2.9

            REALITY is reality now!

            2023.2.8 v1.7.5open in new tag

            Keep riding and never look back.

            • Congratulations to @yuhan6665open in new tag for contributing the 500th commit to Xray-core!
            • XTLS Vision flow control is nearly complete and will soon be practical.
            • Now there are more options for uTLS fingerprint simulation, which one suits you?
            • Sharing links now also support sharing uTLS fingerprint configurations.
            • There are more feature enhancements and fixes.
            • This version will also be the last time to see XTLS Origin, Direct, and Splice flow control. A bit nostalgic, isn’t it?

            2023.1.29

            Winter cannot cover the NEXT FUTURE...

            2022.12.26 v1.7.0open in new tag

            Due to a slip of the hand, this version number jumped directly up, thanks for everyone's support!

            • From now on, Semantic Versioning will be strictly followed.

            2022.11.28 v1.6.5open in new tag

            This time we have WireGuard outbound.

            • Using WireGuard with CF WARP can unlock some fun new ways to play.
            • Of course, there are also security updates and fixes.

            2022.11.7 v1.6.3open in new tag

            Now Vision flow control can also use uTLS fingerprint simulation, is this the benefit brought by tlsSettings!

            2022.10.29 v1.6.2open in new tag

            The first release with Vision flow control is out! Welcome to try it and give feedback!

            2022.10.22 v1.6.1open in new tag

            • Brought uTLS fingerprint support for WebSocket, HTTP/2, and gRPC transport!
              • The option that was previously only available under regular TLS for TCP transport is now better.
            • On Linux, TCP congestion control can be set independently for ingress and egress.

            2022.10.3

            The weather is getting cooler, but the pace of development hasn’t slowed down. Blocks fall from the sky, but progress can’t be stopped...

            • A new XTLS flow control is brewing...
              • Addressing existing flow control issues;
              • Direct splice activation for TLS 1.3;
              • Added TLS handshake length obfuscation;
              • Simplified code, using tlsSettings instead of xtlsSettings...

            2022.8.28 v1.5.10open in new tag

            Underlying transport now supports more reasonable TCP Keepalive settings.

            2022.6.20 v1.5.8open in new tag

            Now Shadowsocks-2022 relay is also supported.

            2022.5.29 v1.5.6open in new tag

            Shadowsocks-2022 protocol has come to Xray-core!

            Shadowsocks-2022 is a newly designed protocol:

            • It addresses security issues like replay attacks while retaining native udp support from Shadowsocks (using timestamps similar to vmess, so client and server need synchronized time).
            • Supports multi-user on a single port, and implements session mechanisms similar to quic and wireguard to reduce encryption overhead and ensure seamless migration during network changes.

            2022.4.24 v1.5.5open in new tag

            This time we brought a convenient visual data detection interface! Come and experience it!

            • We also fixed some issues affecting user experience.

            2022.3.13 v1.5.4open in new tag

            Added a wxray.exe file for Windows platform with no black windows popping up, and brought enhancements for UDS listening.

            2022.1.29 v1.5.3open in new tag

            Farewell to the year of the Ox, and leap into the new year of the Tiger. 🧨

            • This time we brought improvements to stream allocation for QUIC transport, making QUIC transport smoother.

            2021.12.24 v1.5.2open in new tag

            Added a new option for gRPC, making it even better when used through a CDN.

            2021.12.15 v1.5.1open in new tag

            “A transitional, phased maintenance version”

            • New features, enhancements, and a lot of fixes are coming in.
            • Remember to remove alterID from your VMess configuration!

            2021.10.20 v1.5.0open in new tag

            A really big change!

            • Refactored the DNS component, with more supported protocols and detailed configurations.
            • Enhanced gRPC transport and FakeDNS.
            • Finally supports Windows ARM64.
            • More new features and improvements await you.

            2021.9.23 v1.4.5open in new tag

            Happy Mid-Autumn Festival, wishing you a joyful reunion.

            • Fixed a bug where the version number was too low and unlucky.
            • This update removed the insecure encryption methods from Shadowsocks. Please migrate to AEAD encryption as soon as possible.
            • This update fixed a longstanding issue from ancient times: enabling traffic statistics could cause a performance drop. Simply put, enabling statistics now will not impact performance regardless of the configuration.
            • Also included are security updates for XTLS and numerous other fixes.
            • By the way, due to the TLS library update, cipherSuites can no longer specify the order of cipher suites, and preferServerCipherSuites has been completely deprecated. In fact, these changes were already present in Xray-core v1.4.3.

            2021.9.16

            2021.9.8 v1.4.3open in new tag

            This is a maintenance release. Development continues…

            • A large number of improvements and new features have accumulated during this period.
            • Added a new DomainMatcher, improving domain rule matching performance.
            • Added health checks for HTTP/2 and gRPC transports, improved handling of unknown SNI, and fixed a bunch of bugs.

            Helden sterben nicht!

            2021.7.14

            • AnXray's expensively designed new icon is now live!
              • The new icon is now more recognizable.
            • Over the past three weeks, AnXray has accumulated 600 stars, 2K+ channel subscriptions, and 11K+ GitHub downloads. Thank you for your support.
            • AX is short for AnXray. We recommend using AX to refer to AnXray—it's short and convenient.

            2021.6.21

            Now, an open-source, free Android client based on Xray-core is available—AnXrayopen in new tag! Maintained by @nekohasekaiopen in new tag.

            • Supports numerous protocols and plugins.
            • Chief visual designer @RPRXopen in new tag designed an X-style logo, slogan, and a unique black-and-white material theme.
            • There's also a small Easter egg waiting to be discovered in the app.

            Spent the last few days refining details from morning till night. We hope you'll star and follow the project.

            2021.5.1

            Improvements to tun2socks have appeared in v2rayNG.

            2021.4.26

            Brought an improvement to tun2socks. You might get to enjoy it in the future~

            2021.4.12

            Let's foresee X-flutter; looking forward to what it might be like~ 🍪

            2021.4.6

            • VuePress Next.
            • With Dark Mode.

            2021.4.4

            • This document has a new homepage.
            • This document now has a dark mode.
            • Of course, dark mode still has various issues. Specific content will need to be gradually adjusted.
            • Additionally, the Telegram group chat has surpassed 5,000 members! An Anti-Spam bot has also been added!
            • 🎉🎉🎉

            2021.4.1 v1.4.2open in new tag

            • Not an April Fool's joke, updated today.
            • Added Browser Dialer to modify TLS fingerprints and behavior.
            • Added uTLS to modify the TLS Client Hello fingerprint.
            • Also fixed a bunch of strange issues; see the changelog for details.

            2021.3.25

            Yes, it’s still changing. -_-

            2021.3.15

            The documentation site is quietly undergoing some mysterious changes..., 🙊🙊🙊

            2021.3.14 v1.4.0open in new tag

            • Happy Pi-Day!
            • This is a major update:
              • Introduced transport layer support for chained proxies.
              • Introduced Domain Strategy for the Dialer, solving strange DNS issues.
              • Added gRPC transport method and a slightly faster Multi Mode.
              • Added WebSocket Early-Data feature, reducing WebSocket latency.
              • Added FakeDNS.
              • Also fixed a series of issues and added various features. For details, see the changelog.
            • VuePress is still more enjoyable~

            2021.3.3 1.3.1open in new tag

            • This version uses Golang 1.16, officially supporting Apple Silicon natively.
            • Also fixed a bug that could cause a panic. Holmium_ thinks this is deceit, a sneak attack.
            • Fixed several legacy issues.

            2021.2.14 1.3.0open in new tag

            • Happy 🐮 Year 🎉!
            • v1.3.0 implemented FullCone for all V protocols using a very clever mechanism, while ensuring some compatibility.
            • OHHHHHHHHHHHH!

            2021.01.31 1.2.4open in new tag

            • Resolved two longstanding issues where “connecting to a standard Socks server might result in errors.”
            • It seems there’s not much change in this version, but it’s just the calm before the storm.
            • (Yes, I’m a prophet)

              You fool, you’re holding a UNO card.

            2021.01.25

            2021.01.22 1.2.3open in new tag

            • Yet again, support for the SS protocol has been strengthened, now supporting multi-user on a single port!
            • Yet again, support for the trojan protocol has been strengthened, with new SNI-based routing for trojan fallback!
            • (VLESS: sobbing)
            • The weird UDP bugs have been fixed, making it “stable” in one word.
            • Sniffing can now exclude domains you don't want to sniff, opening up some new possibilities.
            • Salute to the big shot @Bohan Yangopen in new tag who discovers issues -> opens an issue -> tests on their own -> analyzes on their own -> finds the issue on their own -> fixes it on their own -> and then submits a PR upstream and downstream!
            • Other tasty cherries—just update and taste them.

            2021.01.19

            • Some numbers:
              • 10 tags released
              • 100 issues resolved
              • 300 forks created
              • 2000 stars given
              • 3000 members in the group

            2021.01.17

            2021.01.15 1.2.2open in new tag

            • Fallback routing has unlocked a new strange trick! You can now route based on SNI in the fallback!
            • The previously announced UUID modification is officially live. (Scroll down, scroll down)
            • The logs now look a bit more pleasing to the eye than last time.
            • Remote DOH has learned to use routing just like other DNS modes.
            • And of course, various other little candies. (Just update and taste them)
            • Oh, and, the first person to run Xray on an M1 Mac is Anthony TSE.

            2021.01.12

            • Upcoming UUID modification supports mapping between custom strings and UUIDs. This means you can write the id like this in the configuration file to correspond to users.
              • Client writes "id": "I love 🍉 teacher 1314",
              • Server writes "id": "5783a3e7-e373-51cd-8642-c83782b807c5" (This UUID is the UUID mapping of I love 🍉 teacher 1314)
            • The Simple White Language by 🍉 teacher concludes with a grand finale, throwing flowers.

            2021.01.10 1.2.1open in new tag

            • A lot of UDP-related fixes, now you can even play Rainbow Six Siege on Ubisoft's potato servers!
            • Google Voice should now work properly when making calls with v2rayNG.
            • Logs now look more pleasing to the eye.

            2021.01.07

            • Courtesy and respect should be fundamental principles that don’t need to be explicitly stated in the community.

            2021.01.05

            • The documentation website is quietly undergoing some mysterious changes..., 🙊🙊🙊

            2021.01.03

            2021.01.01

            [Happy New Year, Happy “Cow” Year!] 🎆🎇🎆 1.2.0open in new tag

            🎁 In the last few minutes of New Year's Day, v1.2.0 arrived, continuing the tradition of Friday updates, bringing the hard work of all contributors and the dark circles of @rprxx—living up to expectations!

            • The New Year's gift 🎁 following the Christmas gift v1.1.5, a great benefit for gamers, full FullCone support.
            • (UDP will continue to be enhanced!)
            • If you’ve already opened your Christmas gift, this time there’s an even more beautifully wrapped package and little candies. (As always, no need to ask, just update and taste it)
            • (No, what's below is not an ad, but a milestone.)
            • Xray is the first unrestricted multi-protocol platform: Xray alone solves the problem, without relying on other implementations.
              • One person handles everything! Supports all major mainstream protocols!
              • Unparalleled performance!
              • Continuously improving features!
              • Incredible vitality and community affinity!
            • Xray will continue to move forward! Therefore, Xray needs more heroes!!open in new tag!
            • PS: Please taste, taste every line of the release notesopen in new tag carefully. It seems there's a small secret Easter egg. (Ah, someone’s knocking at the door... I’ll tell you later)

            2020.12.29

            Good news for gamers using transparent proxy! Xray-core TProxy inbound, SOCKS outbound UDP FullCone beta, TG groupopen in new tag is hotly testing.

            2020.12.25 1.1.5open in new tag

            Merry Christmas!

            • A Christmas gift for gamers! You can now enjoy gaming with Xray! Thanks to SS/trojan UDP FullCone.
            • You can now write configuration files in your preferred format, such as YAML or TOML...
            • (VLESS’s UDP FullCone and more enhancements are coming soon!)
            • No need to worry about certificate validation being blocked anymore, OCSP stapling is now online!
            • Kirin brought a wave of script updates. Scripts hereopen in new tag.
            • And more delicious little cherries! (No need to ask, just update and taste it)

            2020.12.24

            For some unspeakable reasons, Xray’s documentation website was sneakily launched before the release date. The URL is: Yes, what you’re looking atopen in new tag.

            Everyone is welcome to check various contents and correct any errors/suggestions (can be submitted to the issue area of the documentation GitHub repository).

            The documentation website needs continuous improvement and content addition, as well as design refinement. Therefore, everyone is welcome to contribute to the construction of the documentation together. Documentation Repositoryopen in new tag.

            There’s a brief tutorial in the repository's README explaining how to help Xray improve the documentation website. Everyone is welcome to check it out, correct errors, modify, and add experiences.

            2020.12.23

            Xray-core Shadowsocks UDP FullCone beta, TG groupopen in new tag is hotly testing.

            2020.12.21

            • Project X group member count exceeds 2000.
            • The group messages (including game groups) surpass 10,000 daily.

            2020.12.18 1.1.4open in new tag

            • Lower startup memory usage and memory usage optimization.
            • Customize TLS at will to improve your SSL rating.
            • Added Splice support for XTLS inbound and support for trojan XTLS.
            • Also, best usage mode suggestions for Splice on your router.

            2020.12.17

            Given the growing number of group members and gaming needs, the TG game groupopen in new tag has been launched.

            2020.12.15

            Installation script dev branchopen in new tag is now open and features are being continuously updated.

            2020.12.11 1.1.3open in new tag

            • Full version of REDIRECT transparent proxy mode.
            • Optimization suggestions for Splice flow control mode on soft routers.

            2020.12.06 1.1.2open in new tag

            • Added splice mode for flow control, Linux exclusive, with unparalleled performance.
            • Enhanced API compatibility.

            2020.12.04

            Added splice mode.

            2020.11.27

            • Project X's GitHub main repository Xray-core has now received 500+ stars.
            • Featured on GitHub Trending.
            • Project X group members exceeded 1000, and channel subscribers reached 500+.

            2020.11.25 1.0.0open in new tag

            Xray’s first version.

            • Based on v2ray-core with significant modifications.
            • Comprehensive enhancements, excellent performance, fully compatible.

            2020.11.23

            project X start

            When the dream begins

            - + diff --git a/en/config/api.html b/en/config/api.html index fcf4629571..320a512142 100644 --- a/en/config/api.html +++ b/en/config/api.html @@ -24,8 +24,8 @@ API Interface | Project X - - + +

            API Interface

            API interface configuration provides a set of APIs based on gRPCopen in new tag for remote invocation.

            The interface can be enabled through the api configuration module. When the api configuration is enabled, Xray will create an outbound proxy automatically. All incoming API connections need to be manually routed to this outbound proxy through routing rule configuration.

            Please refer to the related configuration in this section.

            Warning

            Most users do not need to use this API. Novices can ignore this page entirely.

            ApiObject

            ApiObject corresponds to the api item in the configuration file.

            {
            @@ -70,6 +70,6 @@
             xray.app.proxyman.command.HandlerService
             xray.app.stats.command.StatsService
             

            API Calling Example

            Xray-API-documentsopen in new tag @crossfw

            - + diff --git a/en/config/dns.html b/en/config/dns.html index 9fdf43b96c..61197ab763 100644 --- a/en/config/dns.html +++ b/en/config/dns.html @@ -24,8 +24,8 @@ Built-in DNS Server | Project X - - + +

            Built-in DNS Server

            DNS Server

            The DNS module built into Xray has two main purposes:

            • During the routing phase, it resolves domain names to IP addresses and performs traffic splitting based on the results of domain name resolution and the value of domainStrategy in the routing configuration module. The built-in DNS server is only used for DNS queries when either of the following values is set:
              • "IPIfNonMatch": When a domain name is requested, it first tries to match it against the domain entries in the routing configuration. If no match is found, the built-in DNS server is used to perform a DNS query for the domain name, and the returned IP address is used to perform IP routing matching again.
              • "IPOnDemand": When a domain name is matched against any IP-based rule, it is immediately resolved to an IP address for matching.
            • It resolves the target address for connection.
              • In the freedom outbound setting, if domainStrategy is set to UseIP, requests made through the outbound proxy will first resolve the domain name to an IP address using the built-in server before making the connection.
              • In the sockopt setting, if domainStrategy is set to UseIP, system connections initiated through the outbound proxy will first be resolved to an IP address using the built-in server before making the connection.

            TIP 1

            DNS queries sent by the built-in DNS server are automatically forwarded based on the routing configuration.

            TIP 2

            Only basic IP queries (A and AAAA records) are supported. CNAME records will be queried repeatedly until an A/AAAA record is returned. Other queries will not enter the built-in DNS server.

            DNS Processing Flow

            If the domain name to be queried:

            • Matches the mapping of "domain name - IP" or "domain name - IP array" in the hosts, then the IP or IP array will be returned as the DNS resolution result.

            • Matches the mapping of "domain name - domain name" in the hosts, then the value of this mapping (another domain name) will be used as the domain name to be queried, and enter the DNS processing flow until an IP is resolved and returned, or an empty resolution is returned.

            • Does not match hosts, but matches the domains list in one or more DNS servers, then according to the priority of the matching rule, use the DNS server corresponding to the rule to perform the query in sequence. If the DNS server that is hit fails to query or expectIPs does not match, then use the next hit DNS server to perform the query. Otherwise, return the resolved IP. If all hit DNS servers fail to query or expectIPs does not match, then the DNS component:

              • By default, it will perform "DNS fallback query": use the "DNS server that has not been used in the last failed query and has a default value of false for skipFallback" to perform the query in sequence. If the query fails or expectIPs does not match, return an empty resolution; otherwise, return the resolved IP.
              • If disableFallback is set to true, "DNS fallback query" will not be performed.
            • If neither hosts nor the domains list in DNS servers matches, then:

              • By default, use the "DNS server that has a default value of false for skipFallback" to perform the query in sequence. If the first selected DNS server fails to query or expectIPs does not match, then use the next selected DNS server to perform the query. Otherwise, return the resolved IP. If all selected DNS servers fail to query or expectIPs does not match, return an empty resolution.
              • If the number of "DNS servers that have a default value of false for skipFallback" is 0 or disableFallback is set to true, use the first DNS server in the DNS configuration to perform the query. If the query fails or expectIPs does not match, return an empty resolution; otherwise, return the resolved IP.

            DnsObject

            DnsObject corresponds to the dns section in the configuration file.

            {
            @@ -116,6 +116,6 @@
               "clientIP": "1.2.3.4"
             }
             

            address: address

            A list of DNS servers, which can be either DNS addresses (in string form) or ServerObjects.

            When the value is "localhost", it means using the local DNS configuration.

            When the value is a DNS "IP" address, such as "8.8.8.8", Xray will use the specified UDP port of this address for DNS queries. The query follows routing rules. By default, port 53 is used.

            When the value is in the form of "tcp://host", such as "tcp://8.8.8.8", Xray will use DNS over TCP for the query. The query follows routing rules. By default, port 53 is used.

            When the value is in the form of "tcp+local://host", such as "tcp+local://8.8.8.8", Xray will use TCP local mode (TCPL) for the query. That is, the DNS request will not go through the routing component and will be sent directly through the Freedom outbound to reduce latency. When no port is specified, port 53 is used by default.

            When the value is in the form of "https://host:port/dns-query", such as "https://dns.google/dns-query", Xray will use DNS over HTTPS (RFC8484, abbreviated as DOH) for the query. Some service providers have IP alias certificates, which can be directly written in IP form, such as https://1.1.1.1/dns-query. Non-standard ports and paths can also be used, such as "https://a.b.c.d:8443/my-dns-query".

            When the value is in the form of "https+local://host:port/dns-query", such as "https+local://dns.google/dns-query", Xray will use DOH local mode (DOHL) for the query, which means that the DOH request will not go through the routing component and will be sent directly through the Freedom outbound to reduce latency. This is generally suitable for server-side use. Non-standard ports and paths can also be used.

            When the value is in the form of "quic+local://host:port", such as "quic+local://dns.adguard.com", Xray will use DOQ local mode (DOQL) for the query, which means that the DNS request will not go through the routing component and will be sent directly through the Freedom outbound. This method requires DNS server support for DNS over QUIC. By default, port 853 is used for the query, and non-standard ports can be used.

            When the value is fakedns, FakeDNS functionality will be used for the query.

            port: number

            The port number of the DNS server, such as 53. If not specified, the default is 53. This item is not applicable when using DOH, DOHL, or DOQL modes, and non-standard ports should be specified in the URL.

            domains: [string]

            A list of domain names. The domain names in this list will be queried using this server first. The format of domain names is the same as in routing configuration.

            expectIPs: [string]

            A list of IP ranges in the same format as in routing configuration.

            When this item is configured, Xray DNS will verify the returned IP addresses and only return addresses that are included in the expectIPs list.

            If this item is not configured, the IP address will be returned as is.

            skipFallback: true | false

            true means to skip this server when performing DNS fallback queries, and the default is false, which means not to skip.

            - + diff --git a/en/config/fakedns.html b/en/config/fakedns.html index 4554057c08..01fe393b2e 100644 --- a/en/config/fakedns.html +++ b/en/config/fakedns.html @@ -24,8 +24,8 @@ FakeDNS | Project X - - + +

            FakeDNS

            FakeDNS is used to obtain target domain names by forging DNS, which can reduce the delay in DNS queries and work with transparent proxies to obtain target domain names.

            Warning

            FakeDNS may contaminate the local DNS and cause "network unreachable" after Xray is closed.

            FakeDNSObject

            FakeDNSObject corresponds to the fakedns item in the configuration file.

            {
            @@ -130,6 +130,6 @@
               ]
             }
             
            - + diff --git a/en/config/features/browser_dialer.html b/en/config/features/browser_dialer.html index ba2d17a6ca..a672f5530a 100644 --- a/en/config/features/browser_dialer.html +++ b/en/config/features/browser_dialer.html @@ -24,11 +24,11 @@ Browser Dialer | Project X - - + +

            Warning

            This translation was modified on 18 July 2024 and an updated version (20 July 2024) is available on the source page. View the original page

            Browser Dialer

            BETA v1.4.1+

            Background

            Xray generally uses uTLS to mimic the behavior of popular browsers, and it can be controlled through the fingerprint setting. However, the fingerprints produced by uTLS are an imperfect replica of the real thing, and because uTLS is a popular library, they may be targeted themselves.

            So the idea of browser dialeropen in new tag is that Xray uses a real browser to establish TLS connections. The way this works is that Xray hosts a small website on localhost:8080, the user opens this website in a browser of their choice, and JavaScript on that page will act as Xray's networking stack (HTTP client, TLS client).

            The TLS fingerprinting behavior is perfect this way, and so it may be possible to revive servers that open fine as websites in the browser, but do not connect using any proxying software.

            However, there are many drawbacks:

            • The user has to launch a browser next to the Xray client just for opening the proxy connection.
            • The browser dialer must not be tunneled through the proxy itself, otherwise there is a loop. TUN users should be cautious.
            • The browser can only speak standard HTTP, which means that only WebSocket and SplitHTTP are supported
            • CORSopen in new tag needs to be considered when making requests from one website (localhost:8080) to another (proxy.example.com:443)
            • The browser tunnels your traffic using JavaScript, so there is a significant performance penalty (or, battery drain)
            • The configuration to be used with browser dialer cannot use custom SNI or host headers. SNI == host == address. Custom HTTP headers and tlsSettings are ignored entirely.

            Configuration

            1. Prepare a usable WebSocket or SplitHTTP configuration. Be aware of the above restrictions.
            2. Launch Xray with XRAY_BROWSER_DIALER=127.0.0.1:8080. On Windows, this can be done as set XRAY_BROWSER_DIALER=... and then launching the core from the console, on Linux the core can be launched as XRAY_BROWSER_DIALER=127.0.0.1:8080 ./xray -c config.json.
            3. Open a browser that is not tunneled through the proxy, or modify the config's routing such that the Xray server's domain goes to freedom directly from the client. Browse to localhost:8080, and open the developer console with F12 to monitor for errors.
            4. For better performance and to bypass arbitrary connection limits enforced by the browser, it is recommended to enable Mux.Cool.

            Inner workings

            • Xray listens on http://127.0.0.1:8080, and the browser accesses http://127.0.0.1:8080 to load the JS in the webpage.
            • The JS actively establishes a WebSocket connection to http://127.0.0.1:8080. Xray will use this connection to send instructions, but for now it goes into a connection pool (implemented as Go channel).
            • When a connection needs to be established, Xray receives an available connection from the pool and sends the protocol name, target URL and optional early data.
            • Once the JS successfully connects to the target, it informs Xray and continues to use this conn to bi-directionally forward data.
            • After the connection to the server is closed, the connection to localhost is also closed, but the JS ensures that there is always at least one idle connection available.

            WebSocket

            v1.4.1+

            According to the browser's needs, the early data mechanism has been adjusted as follows:

            • The server response header will contain the requested Sec-WebSocket-Protocol, which also initially obfuscates the length characteristic of the WSS handshake response.
            • The encoding used for early data for browsers is base64.RawURLEncoding instead of StdEncoding, and the server has made it compatible.
            • In addition, due to Xray-core#375open in new tag recommendations for ?ed=2048, this PR also increased server MaxHeaderBytes by 4096. (Although it seems like it would work without modification.)

            SplitHTTP

            v1.8.19+

            SplitHTTP supports QUIC, but the browser's own QUIC stack may be used as well. In Chrome this can be done through chrome://flags, in other browsers it may already be enabled or need a different flag.

            In general, tlsSettings are completely ignored when Browser Dialer is used. Xray does not have any control over which HTTP version the browser selects.

            - + diff --git a/en/config/features/env.html b/en/config/features/env.html index 40fd18f86c..f46cd3b4cc 100644 --- a/en/config/features/env.html +++ b/en/config/features/env.html @@ -24,14 +24,14 @@ Environment Variables | Project X - - + +

            Environment Variables

            Xray provides the following environment variables for modifying some of its underlying configurations.

            Xray Asset Location

            • Name:xray.location.asset or XRAY_LOCATION_ASSET
            • Default value:specified FHSopen in new tag directory or the same path as the Xray file.

            This environment variable specifies a folder location that should contain the geoip.dat and geosite.dat files. If no variable value is specified, the program will search for resource files in the following order:

            ./
             /usr/local/share/xray
             /usr/share/xray
             

            Configuration File Location

            • Name:xray.location.config or XRAY_LOCATION_CONFIG
            • Default value: Same path as the Xray file.

            This environment variable specifies a folder location that should contain the config.json file.

            Multiple Configuration Directories

            • Name:xray.location.confdir or XRAY_LOCATION_CONFDIR
            • Default value:""

            The .json files in this directory will be read in alphabetical order by filename and used as options for multiple configurations.

            - + diff --git a/en/config/features/fallback.html b/en/config/features/fallback.html index 80db2bfea1..d7304610d5 100644 --- a/en/config/features/fallback.html +++ b/en/config/features/fallback.html @@ -24,8 +24,8 @@ Fallback | Project X - - + +

            Fallback

            Fallback is one of the most powerful features of Xray, which can effectively prevent active probing and allows you to use one port for multiple services

            Fallback provides Xray with high-strength anti-active probing capabilities and has a unique first-packet fallback mechanism.

            Fallback can also divide traffic of different types based on path for multi-service sharing on a single port.

            Currently, you can use the fallback feature by configuring fallbacks when using VLESS or Trojan protocols, thus creating an unimaginable combo of services becomes REALITY.

            fallbacks configuration

              "fallbacks": [
            @@ -41,6 +41,6 @@
               "xver": 0
             }
             

            The fallbacks object is optional and can only be used for the TCP+TLS transport combination.

            • When fallbacks configure with any child elements,"alpn":["http/1.1"] needs to be configured in Inbound TLS.

            Usually, you need to set up a default fallback with both alpn and path omitted or empty, and then configure other routing rules as needed.

            VLESS will forward traffic with TLS decrypted first packet length <18, invalid protocol version, or failed authentication to the address specified by dest.

            For other transport combinations, you must remove the fallbacks object or all its child elements. At this point, no fallbacks will be enabled, and VLESS will wait until it reads enough data. If the protocol version is invalid or authentication fails, the connection will be terminated directly.

            name: string

            Attempt to match the TLS SNI (Server Name Indication), where an empty value matches any SNI. The default value is "", which means empty value.

            alpn: string

            Attempt to match the result of TLS ALPN negotiation, where an empty value matches any ALPN result. The default value is "" , which means empty value.

            VLESS will read the TLS ALPN negotiation result only when necessary. If successful, it will output realAlpn = info to the log. Purpose: To solve the problem of Nginx's inability to simultaneously support http/1.1 and h2c services. Nginx needs to write two lines of listen, one for 1.1 and one for h2c. Note: When "h2" is included in fallbacks alpn, the Inbound TLS needs to be set as "alpn":["h2","http/1.1"] to support h2 access.

            Tip

            The alpn set in the Fallback is used to match the actual negotiated ALPN, while the alpn set in the Inbound TLS represents the list of optional ALPNs during the handshake. These two have different meanings.

            path: string

            Attempt to match the first packet HTTP PATH, where an empty value matches any PATH and a default value is empty. If non-empty, it must start with /, and h2c is not supported.

            Smart: VLESS will only attempt to check the PATH (no more than 55 bytes; the fastest algorithm that does not fully parse HTTP) when necessary. If successful, it will output realPath = in the INFO log. Purpose: To route other inbound WebSocket traffic or HTTP disguised traffic, without additional processing, purely forwarding traffic, and theoretically better performance than Nginx.

            Note: The inbound where fallbacks is located must be TCP+TLS. This is for routing to other WebSocket inbound, while the inbound being routed doesn't need to configure TLS.

            dest: string | number

            Determines the destination of decrypted TLS TCP traffic, which currently supports two types of addresses: (this field is required, otherwise it cannot be started)

            1. TCP, in the format of "addr:port", where addr supports IPv4, domain names, and IPv6. If a domain name is entered, a direct TCP connection will be made (rather than using the built-in DNS resolver).
            2. Unix domain socket, in the format of an absolute path, such as "/dev/shm/domain.socket", which can be prefixed with @ to represent abstractopen in new tag, and @@ to represent padded abstract.

            If only the port is specified, both numbers and strings are accepted, such as 80 or "80". This usually points to a plaintext HTTP service (and the addr will be filled in as "127.0.0.1").

            xver: number

            Sends the PROXY protocolopen in new tag protocol, which is used to transmit the real source IP and port of the request. The version can be set to 1 or 2, with a default value of 0, which means no PROXY protocol is sent. Version 1 is recommended if needed.

            Currently, versions 1 and 2 have the same functionality but different structures, where version 1 is printable while version 2 is binary. Xray's TCP and WebSocket inbound already support receiving the PROXY protocol.

            Warning

            If you are configuring Nginx to receive the PROXY protocolopen in new tag, you need to not only set proxy_protocol, but also set_real_ip_from to avoid potential issues.

            Additional Information

            • Matches the most precise sub-element, regardless of the order of arrangement of the sub-elements. If several sub-elements have the same alpn and path configurations, the last one specified will be used.
            • Fallback routing is performed at the decrypted TCP layer rather than the HTTP layer, and the first packet PATH is only checked when necessary.
            • You can learn more about tips and experiences in using Fallbacks by visiting

            Fallbacks design theory WIP

            - + diff --git a/en/config/features/multiple.html b/en/config/features/multiple.html index 89ef51ad35..5382713fd3 100644 --- a/en/config/features/multiple.html +++ b/en/config/features/multiple.html @@ -24,8 +24,8 @@ Multi-file configuration | Project X - - + +

            Multi-file configuration

            The Xray program supports the use of multiple configuration files.

            The main purpose of using multiple configuration files is to distribute different module configurations, making it easier to manage and maintain.

            This feature is mainly designed to enrich the Xray ecosystem. For example, for GUI-based clients, only fixed functions such as node selection are usually implemented, and complex configurations are difficult to implement graphically. By leaving a custom confdir configuration directory for complex functions, server deployment scripts can simply add files to confdir to implement multiple protocol configurations.

            Multi-file startup

            Tip

            The startup information will indicate each configuration file being read in sequence. Please pay attention to whether the startup information matches the order you have set.

            $ xray run -confdir /etc/xray/confs
            @@ -103,6 +103,6 @@
             
             0 directories, 10 files
             
            - + diff --git a/en/config/features/xtls.html b/en/config/features/xtls.html index 0dcd30ea5e..434a0d3324 100644 --- a/en/config/features/xtls.html +++ b/en/config/features/xtls.html @@ -24,11 +24,11 @@ Deep analysis of XTLS | Project X - - + + - + diff --git a/en/config/inbound.html b/en/config/inbound.html index 266c0cbbaa..25ff1ea2c1 100644 --- a/en/config/inbound.html +++ b/en/config/inbound.html @@ -24,8 +24,8 @@ Inbound Proxy | Project X - - + +

            Warning

            This translation was modified on 12 March 2023 and an updated version (11 September 2024) is available on the source page. View the original page

            Inbound Proxy

            Inbound connections are used to receive incoming data and the available protocols are listed in inbound protocols.

            InboundObject

            The InboundObject corresponds to a subelement of the inbounds item in the configuration file.

            {
            @@ -62,6 +62,6 @@
               "concurrency": 3
             }
             

            strategy: "always" | "random"

            The port allocation strategy.

            • "always" means all specified ports in port will be allocated, and Xray will listen on these ports.
            • "random" means ports will be randomly selected from the port range every refresh minutes, and concurrency ports will be listened on.

            refresh: number

            The interval for refreshing randomly allocated ports in minutes. The minimum value is 2, and it is recommended to set to 5. This property is only effective when strategy is set to "random".

            concurrency: number

            The number of randomly allocated ports. The minimum value is 1, and the maximum value is one-third of the port range. It is recommended to set to 3.

            - + diff --git a/en/config/inbounds/dokodemo.html b/en/config/inbounds/dokodemo.html index 50dc9ac578..20987a10c6 100644 --- a/en/config/inbounds/dokodemo.html +++ b/en/config/inbounds/dokodemo.html @@ -24,8 +24,8 @@ Dokodemo-Door | Project X - - + +

            Dokodemo-Door

            Dokodemo door (Anywhere Door) can listen to a local port and forward all incoming data on this port to a specified server's port, achieving the effect of port mapping.

            InboundConfigurationObject

            {
            @@ -49,6 +49,6 @@
               "tag": "mc"
             }
             

            The core will listen at 127.0.0.1:25565, and the traffic coming in through this inbound will be send to mc.hypixel.net:25565 (a Minecraft server) through the default outbound. Then you can connect the Minecraft client to the Hypixel server through the proxy by set the game server to 127.0.0.1:25565 in the Minecraft client.

            Transparent Proxy Configuration Example

            Please refer to the Transparent Proxy (TProxy) Configuration Tutorial for this section.

            - + diff --git a/en/config/inbounds/http.html b/en/config/inbounds/http.html index 134bd8bff8..1ddb4a1e8b 100644 --- a/en/config/inbounds/http.html +++ b/en/config/inbounds/http.html @@ -24,8 +24,8 @@ HTTP | Project X - - + +

            HTTP

            HTTP protocol.

            Warning

            The HTTP protocol does not provide encryption for transmission and is not suitable for transmission over public networks, as it can easily be used as a target for attacks.

            The more meaningful use of http inbound is to listen in a local network or on the local machine to provide local services for other programs.

            TIP 1

            http proxy can only proxy the TCP protocol and cannot handle protocols based on UDP.

            TIP 2

            In Linux, you can use the following environment variables to enable global HTTP proxy for the current session (many software support this setting, but some may not).

            • export http_proxy=http://127.0.0.1:8080/ (Change the address to the configured inbound HTTP proxy address)
            • export https_proxy=$http_proxy
            • :::

            InboundConfigurationObject

            {
            @@ -43,6 +43,6 @@
               "pass": "my-password"
             }
             

            user: string

            The username. It is a string and is required.

            pass: string

            The password. It is a string and is required.

            - + diff --git a/en/config/inbounds/shadowsocks.html b/en/config/inbounds/shadowsocks.html index 57013c6a1c..3bef1f82fc 100644 --- a/en/config/inbounds/shadowsocks.html +++ b/en/config/inbounds/shadowsocks.html @@ -24,8 +24,8 @@ Shadowsocks | Project X - - + +

            Warning

            This translation was modified on 18 August 2023 and an updated version (1 June 2024) is available on the source page. View the original page

            Shadowsocks

            The Shadowsocksopen in new tag protocol is compatible with most other implementations of Shadowsocks. The server supports TCP and UDP packet forwarding, with an option to selectively disable UDP.

            Supported Encryption Methods

            The currently supported methods are following:

            • Recommended encryption methods:
              • 2022-blake3-aes-128-gcm
              • 2022-blake3-aes-256-gcm
              • 2022-blake3-chacha20-poly1305
            • Other encryption methods:
              • aes-256-gcm
              • aes-128-gcm
              • chacha20-poly1305/chacha20-ietf-poly1305
              • xchacha20-poly1305/xchacha20-ietf-poly1305
              • none/plain

            The Shadowsocks 2022 new protocol format improves performance and includes complete replay protection, addressing the following security issues in the old protocol:

            Danger

            Traffic transmitted without encryption using the "none" method will be in plain text. Do not use it on public networks for security reasons.

            InboundConfigurationObject

            {
            @@ -47,6 +47,6 @@
             

            method: string, any of the supported methods

            Required.

            password: string

            Required. For Shadowsocks 2022 a pre-shared base64 random key similar to WireGuard's keys should be used as the password. The command

            openssl rand -base64 <length>
             

            could used to generate a key. The length of the required key for shadowsocks-rust implementation depends on the encryption method:

            Encryption MethodKey Length
            2022-blake3-aes-128-gcm16
            2022-blake3-aes-256-gcm32
            2022-blake3-chacha20-poly130532

            In the go-shadowsocks implementation written in Golang, a 32-byte key always works.

            For any other encryption method any string could be used. There is no limitation on the password length, but shorter passwords are more susceptible to cracking. It is recommended to use a random-generated password of 16 characters or longer. The following example generates 40-characters length password:

            sudo strings /dev/urandom | grep -o '[[:alnum:]]' | head -n 40 | tr -d '\n'; echo
             

            level: number

            The user level that the connection will use to determine the corresponding Local Policy.

            The value of level corresponds to the value of level in the policy. If not specified, the default value is 0.

            email: string

            The user's email, used to differentiate traffic from different users for logs or statistics.

            - + diff --git a/en/config/inbounds/socks.html b/en/config/inbounds/socks.html index 94d103daa7..c77f64fe5a 100644 --- a/en/config/inbounds/socks.html +++ b/en/config/inbounds/socks.html @@ -24,8 +24,8 @@ SOCKS | Project X - - + +

            Warning

            This translation was modified on 14 June 2023 and an updated version (15 August 2024) is available on the source page. View the original page

            SOCKS

            The standard SOCKS protocol implementation is compatible with SOCKS 4open in new tag, SOCKS 4a, and SOCKS 5open in new tag.

            Danger

            The SOCKS protocol does not provide encryption for transport and is not suitable for transmitting data over public networks.

            The use of SOCKS inbound is more meaningful in a local area network or local environment, where it can be used to listen for incoming connections and provide local services to other programs.

            InboundConfigurationObject

            {
            @@ -45,6 +45,6 @@
               "pass": "my-password"
             }
             

            user: string

            The username as a string. Required.

            pass: string

            The password as a string. Required.

            - + diff --git a/en/config/inbounds/trojan.html b/en/config/inbounds/trojan.html index 77a6461b6b..904ce61ac9 100644 --- a/en/config/inbounds/trojan.html +++ b/en/config/inbounds/trojan.html @@ -24,8 +24,8 @@ Trojan | Project X - - + +

            Trojan

            The Trojanopen in new tag protocol.

            Danger

            Trojan is designed to work with correctly configured encrypted TLS tunnels.

            InboundConfigurationObject

            {
            @@ -48,6 +48,6 @@
               "level": 0
             }
             

            password: string

            Required. Any string.

            email: string

            Email address. Optional. Used to identify the user.

            Danger

            If there are multiple ClientObjects, please make sure that the email addresses are not duplicated.

            level: number

            The user level that the connection will use to determine the corresponding Local Policy.

            The value of level corresponds to the value of level in the policy. If not specified, the default value is 0.

            - + diff --git a/en/config/inbounds/vless.html b/en/config/inbounds/vless.html index 468dbb1549..254f98dfd3 100644 --- a/en/config/inbounds/vless.html +++ b/en/config/inbounds/vless.html @@ -24,8 +24,8 @@ VLESS | Project X - - + +

            Warning

            This translation was modified on 27 July 2024 and an updated version (7 August 2024) is available on the source page. View the original page

            VLESS

            Danger

            Currently, VLESS does not provide built-in encryption. Please use it with a reliable channel, such as TLS.

            VLESS is a stateless lightweight transport protocol that consists of inbound and outbound parts. It can serve as a bridge between Xray clients and servers.

            Unlike VMess, VLESS does not rely on system time. The authentication method is still UUID-based.

            InboundConfigurationObject

            {
            @@ -51,6 +51,6 @@
               "flow": "xtls-rprx-vision"
             }
             

            id: string

            The user ID for VLESS. It can be any string less than 30 bytes or a valid UUID. Custom strings and their corresponding UUIDs are equivalent, which means you can use either of the following in the configuration file to identify the same user:

            • "id": "我爱🍉老师1314"
            • "id": "5783a3e7-e373-51cd-8642-c83782b807c5" (This UUID is the mapping of the string "我爱 🍉 老师 1314")

            The mapping standard is described in the VLESS UUID Mapping Standard: Mapping a Custom String to a UUIDv5open in new tag.

            You can use the command xray uuid -i "custom string" to generate the UUID corresponding to a custom string.

            You can also use the command xray uuid to generate a random UUID.

            level: number

            The user level that the connection will use to determine the corresponding Local Policy.

            The value of level corresponds to the value of level in the policy. If not specified, the default value is 0.

            email: string

            User email address used to differentiate traffic from different users (reflected in logs and statistics).

            flow: string

            Flow control mode used to select the XTLS algorithm.

            Currently, the following flow control modes are available for inbound protocols:

            • No flow or empty string: Use regular TLS proxy.
            • xtls-rprx-vision: Use the new XTLS mode, including inner-handshake random padding.

            Additionally, XTLS currently only supports TCP+TLS/Reality.

            - + diff --git a/en/config/inbounds/vmess.html b/en/config/inbounds/vmess.html index 1b600fcd84..0ed1ffe708 100644 --- a/en/config/inbounds/vmess.html +++ b/en/config/inbounds/vmess.html @@ -24,8 +24,8 @@ VMess | Project X - - + +

            VMess

            VMess is an encrypted transport protocol that is commonly used as a bridge between Xray clients and servers.

            Danger

            VMess relies on system time. Please ensure that the system UTC time used by Xray is within 120 seconds of the actual time, regardless of time zone. On Linux systems, you can install the ntp service to automatically synchronize the system time.

            InboundConfigurationObject

            {
            @@ -55,6 +55,6 @@
               "level": 0
             }
             

            level: number

            The user level that the connection will use to determine the corresponding Local Policy.

            The value of level corresponds to the value of level in the policy. If not specified, the default value is 0.

          - + diff --git a/en/config/inbounds/wireguard.html b/en/config/inbounds/wireguard.html index 0a8c1d260c..834645bf5e 100644 --- a/en/config/inbounds/wireguard.html +++ b/en/config/inbounds/wireguard.html @@ -24,8 +24,8 @@ Wireguard | Project X - - + +

          Wireguard

          User-space implementation of the Wireguard protocol.

          Danger

          The Wireguard protocol is not specifically designed for circumvention purposes. If used as the outer layer for circumvention, its characteristics may lead to server blocking.

          InboundConfigurationObject

          {
          @@ -51,6 +51,6 @@
             "allowedIPs": ["0.0.0.0/0"] // optional, default ["0.0.0.0/0", "::/0"]
           }
           

          publicKey: string

          Public key, used for verification.

          allowedIPs: string array

          Allowed source IPs.

          - + diff --git a/en/config/index.html b/en/config/index.html index 04e624f30c..52165268a7 100644 --- a/en/config/index.html +++ b/en/config/index.html @@ -24,8 +24,8 @@ Configurations | Project X - - + +

          This section will tell you all the details of Xray configuration. By mastering these contents, Xray will unleash its full power in your hands.

          Overview

          The configuration file of Xray is in JSON format, and the configuration format for the client and server is the same, except for the actual configuration content. It takes the following form:

          {
          @@ -45,6 +45,6 @@
             "burstObservatory": {}
           }
           

          Warning

          If you are new to Xray, you can first click to view configuration and running in the Quick Start guide, to learn the most basic configuration method, and then refer to the contents of this section to master all the configuration methods of Xray.

          Basic Configuration Modules

          log:LogObject

          Log configurations, controlling how Xray emits logs.

          api:ApiObject

          Configures how Xray provides API interfaces for calling remotely.

          dns: DnsObject

          Configures the built-in DNS server. System DNS will be used if not configured.

          routing: RoutingObject

          Configures routing. Specify rules to route connections through different outbounds.

          policy: PolicyObject

          Local policy configurations, specifying different user levels and corresponding policies.

          inbounds: [ InboundObject ]

          An array of inbound connection configurations.

          outbounds: [ OutboundObject ]

          An array of outbound connection configurations.

          transport: TransportObject

          Configures how Xray establishes and uses network connections to other servers.

          stats: StatsObject

          Configures traffic statistics.

          reverse: ReverseObject

          Configures the built-in reverse proxy. You can forward server traffic to the client, effectively achieving reverse proxying.

          fakedns: FakeDnsObject

          FakeDNS configuration. Can be used with a transparent proxy to obtain the actual domains.

          metrics: metricsObject

          Metrics configuration. A more straightforward (and hopefully better) way to export metrics.

          observatory: ObservatoryObject

          Background connection observation. Detect the connection status of outbound proxies.

          burstObservatory: BurstObservatoryObject

          Concurrent connection observation. Detect the connection status of outbound proxies.

          - + diff --git a/en/config/log.html b/en/config/log.html index 4ccef46af5..c58f967326 100644 --- a/en/config/log.html +++ b/en/config/log.html @@ -24,8 +24,8 @@ Log Configuration | Project X - - + +

          Warning

          This translation was modified on 12 March 2023 and an updated version (11 September 2024) is available on the source page. View the original page

          Log Configuration

          Log configuration controls how Xray outputs logs.

          Xray has two types of logs: access logs and error logs. You can configure the output method for each type of log separately.

          LogObject

          LogObject corresponds to the log item in the configuration file.

          {
          @@ -37,6 +37,6 @@
             }
           }
           

          access: string

          The file path for the access log. The value is a valid file path, such as "/var/log/Xray/access.log" (Linux) or "C:\\Temp\\Xray\\_access.log" (Windows). When this item is not specified or is an empty value, the log is output to stdout.

          • The special value none disables access logs.

          error: string

          The file path for the error log. The value is a valid file path, such as "/var/log/Xray/error.log" (Linux) or "C:\\Temp\\Xray\\_error.log" (Windows). When this item is not specified or is an empty value, the log is output to stdout.

          • The special value none disables error logs.

          loglevel: "debug" | "info" | "warning" | "error" | "none"

          The log level for error logs, indicating the information that needs to be recorded. The default value is "warning".

          • "debug": Output information used for debugging the program. Includes all "info" content.
          • "info": Runtime status information, etc., which does not affect normal use. Includes all "warning" content.
          • "warning": Information output when there are some problems that do not affect normal operation but may affect user experience. Includes all "error" content.
          • "error": Xray encountered a problem that cannot be run normally and needs to be resolved immediately.
          • "none": Do not record any content.

          dnsLog: bool

          Whether to enable DNS query logs, for example: DOH//doh.server got answer: domain.com -> [ip1, ip2] 2.333ms.

          - + diff --git a/en/config/metrics.html b/en/config/metrics.html index 1285d8b6ac..3ed7aa5a13 100644 --- a/en/config/metrics.html +++ b/en/config/metrics.html @@ -24,8 +24,8 @@ Metrics | Project X - - + +

          Metrics

          A more straightforward (and hopefully better) way to export metrics.

          It's possible to add a metrics inbound among inbounds.

              "inbounds": [
          @@ -242,6 +242,6 @@
                      id: udp
                      expvar_type: int
           

          And you will get a nice plot like this:

          160428235-2988bf69-5d6c-41ec-8267-1bd512508aa8

          Additional

          Maybe reusing the empty object stats in config file is better than adding metrics here?

          Edit: removed prometheus related things and added usage about expvars

          - + diff --git a/en/config/observatory.html b/en/config/observatory.html index 1d44f51b1e..11241077ae 100644 --- a/en/config/observatory.html +++ b/en/config/observatory.html @@ -24,8 +24,8 @@ Connection Monitoring | Project X - - + +

          Connection Monitoring

          The connection monitoring component uses HTTPing to detect the connection status of outbound proxies. The monitoring results can be used by other components, such as load balancers. There are currently two options: observatory (background connection monitoring) and burstObservatory (concurrent connection monitoring). You can choose one of them as needed.

          ObservatoryObject

          {
          @@ -50,6 +50,6 @@
             "timeout": "30s"
           }
           

          destination: string

          The URL used to detect the connection status of the outbound proxy. This URL should return an HTTP 204 success status code.

          connectivity: string

          The URL used to check local network connectivity. An empty string means that local network connectivity is not checked.

          interval: string

          Within the specified time, probe all matching outbound proxies, probing each proxy sampling + 1 times. The time format is a number followed by a unit, such as "10s", "2h45m". Supported time units include ns, us, ms, s, m, h, corresponding to nanoseconds, microseconds, milliseconds, seconds, minutes, and hours, respectively.

          sampling: number

          The number of recent probe results to retain.

          timeout: string

          The probe timeout period. The format is the same as the interval above.

          - + diff --git a/en/config/outbound.html b/en/config/outbound.html index 65e3ff6016..d3072d2722 100644 --- a/en/config/outbound.html +++ b/en/config/outbound.html @@ -24,8 +24,8 @@ Outbound Proxies | Project X - - + +

          Outbound Proxies

          Outbound connections are used for sending data and can use any of the available protocols listed in outbound protocols.

          OutboundObject

          The OutboundObject corresponds to a sub-element of the outbounds item in the configuration file.

          Tip

          The first element in the list serves as the main outbound. When there is no match or no successful match for the routing, the traffic is sent out by the main outbound.

          {
          @@ -51,6 +51,6 @@
             "concurrency": 8
           }
           

          enabled: true | false

          Whether to enable Mux forwarding requests, default is false.

          concurrency: number

          Maximum concurrent connections. Minimum value is 1, maximum value is 1024. If this parameter is omitted or equal to 0, the value will be 8.

          This value represents the maximum number of Mux connections that can be carried on a TCP connection. For example, when concurrency=8 is set, if the client sends 8 TCP requests, Xray will only send one actual TCP connection, and all 8 requests from the client will be transmitted through this TCP connection.

          Tip

          When filling in a negative number, such as -1, the mux module is not loaded.

          xudpConcurrency: number

          Use a new XUDP aggregate tunnel (that is, another Mux connection) to proxy UDP traffic and fill in the maximum number of concurrent sub-UoTs. minimum value 1, the maximum value 1024. If this parameter is omitted or equal to 0, UDP traffic will use the same path as TCP traffic.

          Tip

          When filling in negative numbers, such as -1, UDP will not be transmitted via Mux. The original UDP transmission method of the proxy protocol will be used. For example, Shadowsocks will use native UDP, VLESS will use UoT.

          xudpProxyUDP443: string

          Control how Mux handles proxied UDP/443 (QUIC) traffic:

          • Default reject: Deny traffic (generaly, browsers will fall back to to TCP HTTP/2)
          • allow: Allow connections.
          • skip: The Mux module is not used to carry UDP 443 traffic. The original UDP transmission method of the proxy protocol will be used. For example, Shadowsocks will use native UDP, VLESS will use UoT.
          - + diff --git a/en/config/outbounds/blackhole.html b/en/config/outbounds/blackhole.html index b10469c7e8..2614b722e7 100644 --- a/en/config/outbounds/blackhole.html +++ b/en/config/outbounds/blackhole.html @@ -24,8 +24,8 @@ Blackhole | Project X - - + +

          Blackhole

          Blackhole is an outbound data protocol that blocks all outbound data. When used in conjunction with routing configurations, it can be used to block access to certain websites.

          OutboundConfigurationObject

          {
          @@ -37,6 +37,6 @@
             "type": "none"
           }
           

          type: "http" | "none"

          When type is set to "none" (default value), the blackhole will simply close the connection.

          When type is set to "http", the blackhole will send a simple HTTP 403 packet as the response and then close the connection.

          - + diff --git a/en/config/outbounds/dns.html b/en/config/outbounds/dns.html index 44820d459d..ebb29863ac 100644 --- a/en/config/outbounds/dns.html +++ b/en/config/outbounds/dns.html @@ -24,8 +24,8 @@ DNS | Project X - - + +

          Warning

          This translation was modified on 3 July 2023 and an updated version (15 September 2024) is available on the source page. View the original page

          DNS

          DNS is an outbound protocol used for intercepting and forwarding DNS queries.

          This outbound protocol can only handle DNS traffic, including queries based on UDP and TCP protocols. Other types of traffic will result in an error.

          When handling DNS queries, this outbound protocol will forward IP queries (A and AAAA) to the built-in DNS server. Other types of query traffic will be forwarded to their original destination addresses.

          OutboundConfigurationObject

          {
          @@ -35,6 +35,6 @@
             "nonIPQuery": "drop"
           }
           

          network: "tcp" | "udp"

          Modifies the transport layer protocol for DNS traffic. The possible values are "tcp" and "udp". When not specified, the original transport method will be retained.

          address: address

          Modifies the DNS server address. When not specified, the original address specified in the source will be retained.

          port: number

          Modifies the DNS server port. When not specified, the original port specified in the source will be retained.

          nonIPQuery: string

          Control non IP queries (neither A or AAAA), "drop" this request or "skip" processing in DNS module,the request will be forwarded to target. By default is "drop".

          DNS Configuration Example WIP

          - + diff --git a/en/config/outbounds/freedom.html b/en/config/outbounds/freedom.html index 783926d232..5f3be60273 100644 --- a/en/config/outbounds/freedom.html +++ b/en/config/outbounds/freedom.html @@ -24,8 +24,8 @@ Freedom | Project X - - + +

          Warning

          This translation was modified on 16 September 2024 and an updated version (17 September 2024) is available on the source page. View the original page

          Freedom

          Freedom is an outbound protocol that can be used to send (normal) TCP or UDP data to any network.

          OutboundConfigurationObject

          {
          @@ -57,6 +57,6 @@
             "proxyProtocol": 0
           }
           

          domainStrategy: "AsIs" | "UseIP" | "UseIPv4" | "UseIPv6"

          When the destination address is a domain name, configure the corresponding value for Freedom's behavior:

          • "AsIs": Freedom resolves the domain name using the system DNS server and connects to it.
          • "UseIP", "UseIPv4", and "UseIPv6": Xray resolves the domain name using the built-in DNS server and connects to it. The default value is "AsIs".

          TIP 1

          When using the "UseIP" mode and the sendThrough field is specified in the outbound connection configuration, Freedom will automatically determine the required IP type, IPv4 or IPv6, based on the value of sendThrough.

          TIP 2

          When using the "UseIPv4" or "UseIPv6" mode, Freedom will only use the corresponding IPv4 or IPv6 address. If sendThrough specifies a mismatched local address, the connection will fail.

          redirect: address_port

          Freedom will force all data to be sent to the specified address (instead of the address specified in the inbound).

          It is a string value, for example: "127.0.0.1:80", ":1234".

          When the address is not specified, such as ":443", Freedom will not modify the original destination address. When the port is 0, such as "xray.com:0", Freedom will not modify the original port.

          userLevel: number

          User level. The connection will use the corresponding local policy for this user level.

          The value of userLevel corresponds to the value of level in the policy. If not specified, the default value is 0.

          fragment: map

          A key-value map used to control TCP fragmentation,under some circumstances it can cheat the censor system, like bypass a SNI blacklist.

          "packets":support two different methods. "1-3" is for segmentation at TCP layer, applying to the beginning 1 to 3 data writes by the client. "tlshello" is for TLS client hello packet fragmentation.

          "length": length to make the cut

          "interval": time between fragments(ms)

          Warning

          ⚠️ "noise":{} is deptecated,only "noises":[{}] is supported in 24.9.16 and later

          noises: [ noiseObject ]

          A Array used to control UDP noise,under some circumstances it can bypass some udp based protocol restrictions. xray will loop through this array and send each noise packet one by one

          "type":Three types are supported. "rand" generates a random byte , "str" uses a user input string, "base64" uses a user input base64 encoded string

          "packet":If type is set to "rand" this field will take a range "50-100" or a single value "50"

          if type is set to "str" this field will take a string

          if type is set to "base64" this field will take a base64 encoded string

          "delay":delay before sending real data (ms). can be a string range like "10-20" or a single integer

          If not specified, the default value is 0.

          proxyProtocol: number

          The value of proxyProtocol represents the PROXY Protocol version. default value is 0.

          - + diff --git a/en/config/outbounds/http.html b/en/config/outbounds/http.html index 8439b7fc10..183a7bdc60 100644 --- a/en/config/outbounds/http.html +++ b/en/config/outbounds/http.html @@ -24,8 +24,8 @@ HTTP | Project X - - + +

          HTTP

          HTTP is a protocol that is used for communication over the internet. Please note that HTTP does not provide encryption for data transmission and is not suitable for transmitting sensitive information over public networks, as it can be easily targeted for attacks.

          Danger

          The HTTP protocol does not provide encryption for transmission, making it unsuitable for transmitting over public networks and more susceptible to being used as a compromised host for attacks.

          Tip

          HTTP can only proxy TCP protocols, and cannot handle UDP-based protocols.

          OutboundConfigurationObject

          {
          @@ -57,6 +57,6 @@
             "pass": "my-password"
           }
           

          user: string

          The username. Required.

          pass: string

          The password. Required.

          - + diff --git a/en/config/outbounds/loopback.html b/en/config/outbounds/loopback.html index 57e95a2536..305b4bcf59 100644 --- a/en/config/outbounds/loopback.html +++ b/en/config/outbounds/loopback.html @@ -24,8 +24,8 @@ Loopback | Project X - - + + - + diff --git a/en/config/outbounds/shadowsocks.html b/en/config/outbounds/shadowsocks.html index 5628323e6c..4f9e4cfc06 100644 --- a/en/config/outbounds/shadowsocks.html +++ b/en/config/outbounds/shadowsocks.html @@ -24,8 +24,8 @@ Shadowsocks | Project X - - + +

          Warning

          This translation was modified on 14 June 2023 and an updated version (14 July 2023) is available on the source page. View the original page

          Shadowsocks

          Shadowsocksopen in new tag protocol is compatible with most other implementations.

          Here are the features and compatibility of Shadowsocks:

          • It supports TCP and UDP packet forwarding, with the option to disable UDP.
          • Recommended encryption methods:
            • 2022-blake3-aes-128-gcm
            • 2022-blake3-aes-256-gcm
            • 2022-blake3-chacha20-poly1305
          • Other encryption methods:
            • aes-256-gcm
            • aes-128-gcm
            • chacha20-poly1305 (also known as chacha20-ietf-poly1305)
            • none or plain

          The new protocol format of Shadowsocks 2022 improves performance and includes full replay protection, addressing security issues present in the old protocol:

          Danger

          Using the "none" encryption method will transmit traffic in plaintext. It is not recommended to use "none" encryption on public networks to ensure security.

          OutboundConfigurationObject

          {
          @@ -51,6 +51,6 @@
             "level": 0
           }
           

          email: string

          Email address (optional) used to identify the user.

          address: address

          The address of the Shadowsocks server, supporting IPv4, IPv6, and domain names. Required.

          port: number

          The port of the Shadowsocks server. Required.

          method: string

          Encryption method. Required.

          password: string

          Password. Required.

          uot: bool

          When enabled, UDP over TCP (UOT) will be used.

          • Shadowsocks 2022

          Use a pre-shared key (PSK) similar to WireGuard as the password.

          To generate a compatible key with shadowsocks-rust, use openssl rand -base64 <length>, where the length depends on the encryption method used.

          Encryption MethodKey Length
          2022-blake3-aes-128-gcm16
          2022-blake3-aes-256-gcm32
          2022-blake3-chacha20-poly130532

          In the Go implementation, a 32-byte key always works.

          • Other encryption methods

          Any string can be used as a password. There is no limit on the password length, but shorter passwords are more susceptible to cracking. It is recommended to use a password of 16 characters or longer.

          level: number

          User level. Connections will use the corresponding local policy associated with this user level.

          The level value corresponds to the level value in the policy. If not specified, the default value is 0.

          - + diff --git a/en/config/outbounds/socks.html b/en/config/outbounds/socks.html index 25227c1b52..b789536c49 100644 --- a/en/config/outbounds/socks.html +++ b/en/config/outbounds/socks.html @@ -24,8 +24,8 @@ Socks | Project X - - + +

          Socks

          The Socks protocol is a standard protocol implementation that is compatible with Socks 5open in new tag.

          Danger

          The Socks protocol does not provide encryption for transmission and is not suitable for transmitting data over public networks.

          OutboundConfigurationObject

          {
          @@ -60,6 +60,6 @@
             "level": 0
           }
           

          user: string

          The username. Required.

          pass: string

          The password. Required.

          level: number

          The user level. Connections will use the corresponding local policy associated with this user level.

          The level value corresponds to the level value in the policy. If not specified, the default value is 0.

          - + diff --git a/en/config/outbounds/trojan.html b/en/config/outbounds/trojan.html index 06f2e17b80..3c24a502f6 100644 --- a/en/config/outbounds/trojan.html +++ b/en/config/outbounds/trojan.html @@ -24,8 +24,8 @@ Trojan | Project X - - + +

          Trojan

          Trojanopen in new tag protocol

          Danger

          Trojan is designed to work with correctly configured encrypted TLS tunnels.

          OutboundConfigurationObject

          {
          @@ -47,6 +47,6 @@
             "level": 0
           }
           

          address: address

          The server address, which can be an IPv4, IPv6, or domain name. Required.

          port: number

          The server port, usually the same port that the server is listening on.

          password: string

          The password for authentication. Required. It can be any string.

          email: string

          The email address, optional, used to identify the user.

          level: number

          The user level. Connections will use the corresponding local policy associated with this user level.

          The level value corresponds to the level value in the policy. If not specified, the default value is 0.

          - + diff --git a/en/config/outbounds/vless.html b/en/config/outbounds/vless.html index 84f33f88e7..e247fe21cb 100644 --- a/en/config/outbounds/vless.html +++ b/en/config/outbounds/vless.html @@ -24,8 +24,8 @@ VLESS | Project X - - + +

          Warning

          This translation was modified on 27 July 2024 and an updated version (7 August 2024) is available on the source page. View the original page

          VLESS

          Danger

          Currently, VLESS does not have built-in encryption, please use it on a reliable channel, such as TLS.

          VLESS is a stateless lightweight transport protocol, which is divided into inbound and outbound parts, and can be used as a bridge between Xray clients and servers.

          Unlike VMess, VLESS does not rely on system time, and the authentication method is also UUID.

          OutboundConfigurationObject

          {
          @@ -63,6 +63,6 @@
             "level": 0
           }
           

          id: string

          The user ID of VLESS, which can be any string less than 30 bytes, or a valid UUID. Custom strings and their mapped UUIDs are equivalent, which means you can write an id in the configuration file to identify the same user, i.e.

          • Write "id": "I love 🍉 teacher 1314",
          • Or write "id": "5783a3e7-e373-51cd-8642-c83782b807c5" (this UUID is the UUID mapping of I love 🍉 teacher 1314)

          The mapping standard is in VLESS UUID mapping standard: mapping custom strings to a UUIDv5open in new tag

          You can use the command xray uuid -i "custom string" to generate the UUID mapped by the custom string, or use the command xray uuid to generate a random UUID.

          encryption: "none"

          Need to fill in "none", cannot be left empty.

          This requirement is to remind users that there is no encryption and to prevent users from filling in the wrong attribute name or location, causing exposure when encryption methods come out in the future.

          If the value of encryption is not set correctly, an error message will be received when using Xray or -test.

          flow: string

          Flow control mode, used to select the XTLS algorithm.

          Currently, there are the following flow control modes available in the outbound protocol:

          • No flow or empty string: Use regular TLS proxy.
          • xtls-rprx-vision: using the new XTLS mode includes inner handshake random padding supports uTLS client fingerprint simulation
          • xtls-rprx-vision-udp443: same as xtls-rprx-vision, but allows UDP traffic with a destination of port 443

          Additionally, XTLS currently only supports TCP+TLS/Reality.

          About xtls-rprx-*-udp443 flow control mode

          When using Xray-core's XTLS, traffic to UDP port 443 is blocked by default (generally for QUIC), so the application will use TLS instead of QUIC, and XTLS will take effect. In fact, QUIC itself is not suitable for proxying because it has its own TCP functionality. When it is transmitted as UDP traffic through the VLESS protocol, the underlying protocol is TCP, which is equivalent to two layers of TCP.

          If you do not need to block it, please fill in xtls-rprx-*-udp443 on the client side and do not change the server side.

          About Splice mode

          Splice is a function provided by the Linux Kernel. The system kernel directly forwards TCP without going through Xray's memory, greatly reducing the number of data copies and CPU context switches.

          The usage restrictions of Splice mode are:

          • Linux environment
          • Inbound protocols are Dokodemo door, Socks, HTTP, etc., pure TCP connections, or other inbound protocols that use XTLS
          • Outbound protocol is VLESS + XTLS
          • It is worth noting that when using the mKCP protocol, Splice will not be used (yes, although there is no error, it is not used at all)

          In addition, when using Splice, the speed display will lag behind, which is a feature, not a bug.

          Using Vision mode will automatically enable Splice if the above conditions are met.

          level: number

          User level, the connection will use the local policy corresponding to this user level.

          The value of level corresponds to the value of level in policy. If not specified, the default is 0.

          - + diff --git a/en/config/outbounds/vmess.html b/en/config/outbounds/vmess.html index e92db3b757..5e65d02658 100644 --- a/en/config/outbounds/vmess.html +++ b/en/config/outbounds/vmess.html @@ -24,8 +24,8 @@ VMess | Project X - - + +

          Warning

          This translation was modified on 3 July 2023 and an updated version (7 January 2024) is available on the source page. View the original page

          VMess

          VMess is an encrypted transport protocol commonly used as a bridge between Xray clients and servers.

          Danger

          VMess relies on system time. Please ensure that the UTC time of your system, when using Xray, has an error within 120 seconds, regardless of the time zone. On Linux systems, you can install the ntp service to automatically synchronize the system time.

          OutboundConfigurationObject

          {
          @@ -54,6 +54,6 @@
             "level": 0
           }
           

          id: string

          The user ID for VMess, which can be any string less than 30 bytes or a valid UUID.

          Custom strings and their corresponding UUIDs are equivalent. This means that you can use either a custom string or its corresponding UUID to identify the same user in the configuration file. For example:

          • Write "id": "我爱🍉老师1314",
          • Or write "id": "5783a3e7-e373-51cd-8642-c83782b807c5" (this UUID is the mapping of the custom string "我爱 🍉 老师 1314")

          The mapping standard is described in the VLESS UUID Mapping Standard: Mapping a Custom String to a UUIDv5open in new tag.

          You can use the command xray uuid -i "custom string" to generate the UUID corresponding to a custom string, or use the command xray uuid to generate a random UUID.

          level: number

          The user level. Connections will use the corresponding local policy associated with this user level.

          The level value corresponds to the level value in the policy. If not specified, the default value is 0.

          security: "aes-128-gcm" | "chacha20-poly1305" | "auto" | "none" | "zero"

          The encryption method. The client will use the configured encryption method to send data, and the server will automatically recognize it without the need for configuration.

          • "aes-128-gcm": Recommended for use on PCs.
          • "chacha20-poly1305": Recommended for use on mobile devices.
          • "auto": Default value. Automatically selects the encryption method (uses aes-128-gcm when running on AMD64, ARM64, or s390x architecture, and Chacha20-Poly1305 in other cases).
          • "none": No encryption.
          • "zero": No encryption and no message authentication (v1.4.0+).

          Tip

          It is recommended to use the "auto" encryption method as it ensures long-term security and compatibility.

          The "none" pseudo-encryption method calculates and verifies the packet's checksum. However, due to the lack of hardware support for the authentication algorithm, it may be slower than the hardware-accelerated "aes-128-gcm" on some platforms.

          The "zero" pseudo-encryption method neither encrypts the message nor calculates the checksum, theoretically providing higher speed than any other encryption method. The actual speed may be influenced by other factors.

          It is not recommended to use the "none" or "zero" pseudo-encryption methods without enabling TLS encryption and forcibly verifying certificates. If you use a CDN or other intermediate platforms or network environments that decrypt TLS connections, it is not recommended to use the "none" or "zero" pseudo-encryption methods.

          Regardless of the encryption method used, the VMess packet header is protected by encryption and authentication.

          - + diff --git a/en/config/outbounds/wireguard.html b/en/config/outbounds/wireguard.html index 23cc78935f..0b368db66b 100644 --- a/en/config/outbounds/wireguard.html +++ b/en/config/outbounds/wireguard.html @@ -24,8 +24,8 @@ Wireguard | Project X - - + +

          Warning

          This translation was modified on 26 December 2023 and an updated version (3 February 2024) is available on the source page. View the original page

          Wireguard

          Wireguard is a standard implementation of the Wireguard protocol.

          Danger

          The Wireguard protocol is not specifically designed for circumvention purposes. If used as the outer layer for circumvention, its characteristics may lead to server blocking.

          OutboundConfigurationObject

          {
          @@ -69,6 +69,6 @@
             "allowedIPs": ["0.0.0.0/0"] // optional, default ["0.0.0.0/0", "::/0"]
           }
           

          endpoint: address

          The server address. Required.

          URL:port format, e.g. engage.cloudflareclient.com:2408.
          IP:port format, e.g. 162.159.192.1:2408 or [2606:4700:d0::a29f:c001]:2408.

          publicKey: string

          The server's public key used for verification. Required.

          preSharedKey: string

          An additional symmetric encryption key.

          keepAlive: int

          The interval of keep-alive packets in seconds. The default is 0, which means no keep-alive.

          allowedIPs: string array

          Only allow traffic from specific source IP addresses in Wireguard.

          - + diff --git a/en/config/policy.html b/en/config/policy.html index 27bf468e65..5c49434920 100644 --- a/en/config/policy.html +++ b/en/config/policy.html @@ -24,8 +24,8 @@ Local Policy | Project X - - + +

          Local Policy

          Local policy can be used to set different policy settings for different user levels, such as connection timeout settings. Each connection handled by Xray corresponds to a user, and different policies are applied based on the user's level.

          PolicyObject

          PolicyObject corresponds to the policy field in the configuration file.

          {
          @@ -65,6 +65,6 @@
             "statsOutboundDownlink": false
           }
           

          statsInboundUplink: true | false

          When set to true, enables upstream traffic statistics for all inbound proxies.

          statsInboundDownlink: true | false

          When set to true, enables downstream traffic statistics for all inbound proxies.

          statsOutboundUplink: true | false

          When set to true, enables upstream traffic statistics for all outbound proxies.

          statsOutboundDownlink: true | false

          When set to true, enables downstream traffic statistics for all outbound proxies.

          - + diff --git a/en/config/reverse.html b/en/config/reverse.html index b333379f42..35b540cffb 100644 --- a/en/config/reverse.html +++ b/en/config/reverse.html @@ -24,8 +24,8 @@ Reverse Proxy | Project X - - + +

          Reverse Proxy

          A reverse proxy forwards traffic from a server to a client, which is known as reverse traffic forwarding.

          Here's how a reverse proxy generally works:

          • Suppose there is a web server in host A, which does not have a public IP address and cannot be accessed directly on the Internet. There is another host B that can be accessed via the public network. Now we need to use B as the entry point to forward traffic from B to A.
          • Configure Xray in host A as a bridge, and also configure Xray in B as a portal.
          • Bridge will actively establish a connection to portal, and the destination address of this connection can be set by itself. Portal will receive two types of connections: one is the connection sent by bridge, and the other is the connection sent by public network users. Portal will automatically merge the two types of connections. So bridge can receive public network traffic.
          • After receiving the public network traffic, bridge will forward it unchanged to the web server in host A. Of course, this step requires the cooperation of routing.
          • Bridge will dynamically load balance according to the size of the traffic.

          Tip

          Reverse proxy has Mux enabled by default, so please do not enable Mux again on the outbound it uses.

          Warning

          The reverse proxy function is still in the testing phase and may have some issues.

          ReverseObject

          ReverseObject corresponds to the reverse field in the configuration file.

          {
          @@ -144,6 +144,6 @@
             ]
           }
           
          - + diff --git a/en/config/routing.html b/en/config/routing.html index 14067b1e33..88c5e849dd 100644 --- a/en/config/routing.html +++ b/en/config/routing.html @@ -24,8 +24,8 @@ Routing | Project X - - + +

          Warning

          This translation was modified on 2 September 2024 and an updated version (13 September 2024) is available on the source page. View the original page

          Routing

          The routing module can send inbound data through different outbound connections according to different rules to achieve on-demand proxying.

          A common use case is to split domestic and foreign traffic. Xray can use its internal mechanisms to determine the traffic from different regions and then send them to different outbound proxies.

          For a more detailed analysis of the routing function, please refer to Routing Function Analysis.

          RoutingObject

          RoutingObject corresponds to the routing item in the configuration file.

          {
          @@ -57,6 +57,6 @@
             "selector": []
           }
           

          tag: string

          The identifier of this load balancer, used to match balancerTag in RuleObject.

          selector: [ string ]

          An array of strings, each of which will be used to match the prefix of the outbound identifier. For example, in the following outbound identifiers: [ "a", "ab", "c", "ba" ], "selector": ["a"] will match [ "a", "ab" ].

          If multiple outbounds are matched, the load balancer currently selects one randomly as the final outbound.

          Predefined Domain Lists

          This list is included in every Xray installation package, and the file name is geosite.dat. This file contains some common domain names, which can be used as geosite:filename to perform routing or DNS filtering for domain names that match those in the file.

          Common domain lists include:

          • category-ads: Contains common advertising domain names.
          • category-ads-all: Contains common advertising domain names and advertising provider domain names.
          • cn: Equivalent to the combination of geolocation-cn and tld-cn.
          • apple: Contains most of the domain names under Apple.
          • google: Contains most of the domain names under Google.
          • microsoft: Contains most of the domain names under Microsoft.
          • facebook: Contains most of the domain names under Facebook.
          • twitter: Contains most of the domain names under Twitter.
          • telegram: Contains most of the domain names under Telegram.
          • geolocation-cn: Contains common domain names of mainland Chinese websites.
          • geolocation-!cn: Contains common domain names of non-mainland Chinese websites.
          • tld-cn: Contains top-level domain names managed by CNNIC for mainland China, such as domain names ending in .cn and .中国.
          • tld-!cn: Contains top-level domain names used outside mainland China, such as domain names ending in .tw (Taiwan), .jp (Japan), .sg (Singapore), .us (United States), and .ca (Canada).

          You can also find the complete list of domain names here: Domain list communityopen in new tag.

          - + diff --git a/en/config/stats.html b/en/config/stats.html index 0ceb4501fe..70046e42e0 100644 --- a/en/config/stats.html +++ b/en/config/stats.html @@ -24,14 +24,14 @@ Traffic Statistics | Project X - - + +

          Traffic Statistics

          Used to configure traffic statistics for Xray.

          StatsObject

          The StatsObject corresponds to the stats item in the configuration file.

          {
             "stats": {}
           }
           

          Currently, no parameters are required for traffic statistics, and internal statistics will be enabled as long as the StatsObject item exists.

          After statistics are enabled, you only need to enable the corresponding items in the Policy to collect the corresponding data.

          Retrieving Traffic Statistics

          You can use the xray api command to retrieve traffic statistics.

          The current traffic statistics are as follows:

          • User Data

            • user>>>[email]>>>traffic>>>uplink

              The uplink traffic of a specific user, in bytes.

            • user>>>[email]>>>traffic>>>downlink

              The downlink traffic of a specific user, in bytes.

          Tip

          If the corresponding user does not have an email specified, statistics will not be enabled.

          • Global Data

            • inbound>>>[tag]>>>traffic>>>uplink

              The uplink traffic of a specific inbound, in bytes.

            • inbound>>>[tag]>>>traffic>>>downlink

              The downlink traffic of a specific inbound, in bytes.

            • outbound>>>[tag]>>>traffic>>>uplink

              The uplink traffic of a specific outbound, in bytes.

            • outbound>>>[tag]>>>traffic>>>downlink

              The downlink traffic of a specific outbound, in bytes.

          - + diff --git a/en/config/transport.html b/en/config/transport.html index 93f81e951f..cf6c979c59 100644 --- a/en/config/transport.html +++ b/en/config/transport.html @@ -24,8 +24,8 @@ Transport | Project X - - + +

          Warning

          This translation was modified on 3 September 2024 and an updated version (8 September 2024) is available on the source page. View the original page

          Transport

          Transports specify how Xray communicates with peers.

          Transports specify how to achieve stable data transmission. Both ends of a connection often need to specify the same transport protocol to successfully establish a connection. Like, if one end uses WebSocket, the other end must also use WebSocket, or else the connection cannot be established.

          StreamSettingsObject

          StreamSettingsObject corresponds to the streamSettings property in the inbound or outbound config. Each inbound or outbound can be configured with different transports and can use streamSettings to specify local configs.

          {
          @@ -167,6 +167,6 @@
             }
           ]
           

          type: ""

          Required, the type of setting, valid values are int or str.

          level: ""

          Optional, protocol level, used to specify the effective range, the default is 6, which is TCP.

          opt: ""

          The option name of the operation, using decimal (the example here is that the value of TCP_CONGESTION is defined as 0xd and converted to decimal is 13)

          value: ""

          The option value to be set, the example here is set to bbr.

          Decimal numbers are required when type is specified as int.

          - + diff --git a/en/config/transports/grpc.html b/en/config/transports/grpc.html index 16b00a76be..d011521ef7 100644 --- a/en/config/transports/grpc.html +++ b/en/config/transports/grpc.html @@ -24,8 +24,8 @@ gRPC | Project X - - + +

          Warning

          This translation was modified on 28 March 2023 and an updated version (27 March 2024) is available on the source page. View the original page

          gRPC

          An modified transport protocol based on gRPC.

          gRPC is based on the HTTP/2 protocol and can theoretically be relayed by other servers that support HTTP/2, such as Nginx.

          gRPC and HTTP/2 has built-in multiplexing, so it is not recommended to enable mux.cool when using gRPC or HTTP/2.

          ⚠⚠⚠

          • gRPC doesn't support specifying the Host. Please enter the correct domain name in the outbound proxy address, or fill in ServerName in (x)tlsSettings, otherwise connection cannot be established.
          • gRPC doesn't support fallback to other services.
          • gRPC services are at risk of being actively probed. It is recommended to use reverse proxy tools such as Caddy or Nginx to perform path-based routing.

          Tip

          If you are using a reverse proxy such as Caddy or Nginx, please note the following:

          • Make sure that the reverse proxy server has enabled HTTP/2.
          • Use HTTP/2 or h2c (Caddy), grpc_pass (Nginx) to connect to Xray.
          • The path for regular mode is /${serviceName}/Tun, and for Multi mode it is /${serviceName}/TunMulti.
          • If you need to receive the client IP address, you can use the X-Real-IP header sent by Caddy / Nginx to pass the client IP.

          Tip

          If you are using fallback, please note the following:

          • Fallback to gRPC is not recommended, as there is a risk of being actively probed.
          • Please make sure that h2 is the first priority in (x)tlsSettings.alpn, otherwise gRPC (HTTP/2) may not be able to complete TLS handshake.
          • gRPC cannot perform path-based routing by Xray.

          GRPCObject

          GRPCObject corresponds to the grpcSettings item.

          {
          @@ -37,6 +37,6 @@
             "initial_windows_size": 0
           }
           

          serviceName: string

          A string that specifies the service name, similar to the path in HTTP/2.

          The client will use this name for communication, and the server will verify whether the service name matches.

          multiMode: true | false BETA

          true enables multiMode, with a default value of false.

          This is an experimental option that may not be retained for the long term, and cross-version compatibility is not guaranteed. This mode can bring about a performance improvement of around 20% in test environments, but actual effects may vary depending on the transmission rate.

          Tip

          Only need to be configured in outbound (client).

          idle_timeout: number

          The health check is performed when no data transmission occurs for a certain period of time, measured in seconds. If this value is set to less than 10, 10 will be used as the minimum value.

          Tip

          If you are not using reverse proxy tools such as Caddy or Nginx (which is usually the case), if this value is set to less than 60, the server may send "unexpected h2 GOAWAY" frames to close existing connections.

          By default, the health check is not enabled.

          Tip

          Only need to be configured in outbound (client).

          Tip

          Enabling health checks may help solve some "connection drop" issues.

          health_check_timeout: number

          The timeout for the health check, measured in seconds. If the health check is not completed within this time period, it is considered to have failed. The default value is 20

          Tip

          Only need to be configured in outbound (client).

          permit_without_stream: true | false

          true allows health checks to be performed when there are no sub-connections. The default value is false.

          Tip

          Only need to be configured in outbound (client).

          initial_windows_size: number

          The initial window size of the h2 stream. When the value is less than or equal to 0, this feature does not take effect. When the value is greater than 65535, the Dynamic Window mechanism will be disabled. The default value is 0, which means it is not effective.

          Tip

          Only need to be configured in outbound (client).

          Tip

          When using Cloudflare CDN, set the value to 35536 or higher to disable the Dynamic Window mechanism and prevent Cloudflare CDN from sending "unexpected h2 GOAWAY" frames to close existing connections.

          - + diff --git a/en/config/transports/h2.html b/en/config/transports/h2.html index 89405da853..5756ab6d4b 100644 --- a/en/config/transports/h2.html +++ b/en/config/transports/h2.html @@ -24,8 +24,8 @@ HTTP/2 | Project X - - + +

          Warning

          This translation was modified on 28 March 2023 and an updated version (29 July 2024) is available on the source page. View the original page

          HTTP/2

          The transmission mode based on HTTP/2 fully implements the HTTP/2 standard and can be relayed by other HTTP servers (such as Nginx).

          Based on the recommendations of HTTP/2, both the client and server must enable TLS to use this transmission mode normally.

          HTTP/2 has built-in multiplexing, so it is not recommended to enable mux.cool when using HTTP/2.

          Tip

          The current version of the transmission mode based on HTTP/2 does not require TLS configuration for inbound (server-side).

          This makes it possible to use a plaintext HTTP/2 protocol called h2c for communication between the gateway and Xray, with external gateway components handling the TLS layer conversation in special-purpose load-balancing deployment environments.

          Warning

          ⚠️ If you are using fallback, please note the following:

          • Please make sure that h2 is included in (x)tlsSettings.alpn, otherwise HTTP/2 cannot complete TLS handshake.
          • HTTP/2 cannot perform path-based routing, so it is recommended to use SNI-based routing.

          HttpObject

          HttpObject corresponds to the httpSettings in the Transport Protocol,

          {
          @@ -39,6 +39,6 @@
             }
           }
           

          host: [string]

          A string array, where each element is a domain name.

          The client will randomly select a domain name from the list for communication, and the server will verify whether the domain name is in the list.

          path: string

          The HTTP path starts with / and must be the same value between the client and server.

          The default value is /

          read_idle_timeout: number

          The connection health check is performed when no data has been received for a certain period of time, measured in seconds.

          By default, the health check is disabled.

          Tip

          Only need to be configured in outbound (client).

          Tip

          Enabling health checks may help solve some "connection drop" issues.

          health_check_timeout: number

          The timeout for the health check, measured in seconds. If the health check is not completed within this time period, it is considered to have failed. The default value is 15

          Tip

          Only need to be configured in outbound (client).

          method: string

          HTTP request method. The default value is PUT

          Please refer this thisopen in new tag when configure.

          headers: map{ string: [string] }

          Custom HTTP headers, defined as key-value pairs. Each key represents an HTTP header name and its corresponding value is an array.

          - + diff --git a/en/config/transports/httpupgrade.html b/en/config/transports/httpupgrade.html index e22d2dda22..6182a57bb0 100644 --- a/en/config/transports/httpupgrade.html +++ b/en/config/transports/httpupgrade.html @@ -24,8 +24,8 @@ HTTPUpgrade | Project X - - + +

          Warning

          This translation was modified on 30 March 2024 and an updated version (29 July 2024) is available on the source page. View the original page

          HTTPUpgrade

          A WebSocket-like transport protocol implementing the HTTP/1.1 upgrade and response, allowing it to be reverse proxied by web servers or CDNs just like WebSocket, but without the need to implement the remaining portions of the WebSocket protocol, yielding better performance.

          Standalone usage is not recommended, but rather in conjunction with other security protocols like TLS.

          HttpUpgradeObject

          The HttpUpgradeObject corresponds to the httpupgradeSettings section under transport configurations.

          {
          @@ -37,6 +37,6 @@
             }
           }
           

          acceptProxyProtocol: true | false

          For inbounds only. Specifies whether to accept the PROXY protocol.

          The PROXY protocolopen in new tag is used to pass the real IP address and port of a connection along. Ignore it if you have no knowledge regarding this.

          Common reverse proxies (e.g. HAProxy, NGINX) and VLESS fallbacks xver can be configured for its inclusion.

          When true, the downstream must first send PROXY protocol version 1 or 2 after establishing the underlying TCP connection, or the connection will be closed.

          path: string

          HTTP path used by the HTTPUpgrade connection. Defaults to "/".

          If the path property include an ed query field (e.g. /mypath?ed=2560), "early data" will be used to decrease latency, with the value defining the threshold of the first packet's size. If the size of the first packet exceeds the defined value, "early data" will not be applied. The recommended value is 2560.

          host: string

          HTTP Host sent by the HTTPUpgrade connection. Empty by default. If this value is empty on the server, the host header sent by clients will not be validated.

          If the Host header has been defined on the server in any way, the server will validate if the Host header matches.

          The current priority of the Host header sent by clients: host > headers > address

          headers: map {string: string}

          Customized HTTP headers defined in key-value pairs. Defaults to empty.

          - + diff --git a/en/config/transports/mkcp.html b/en/config/transports/mkcp.html index c89c311ee8..6765d0fafd 100644 --- a/en/config/transports/mkcp.html +++ b/en/config/transports/mkcp.html @@ -24,8 +24,8 @@ mKCP | Project X - - + +

          Warning

          This translation was modified on 1 April 2023 and an updated version (2 January 2024) is available on the source page. View the original page

          mKCP

          mKCP uses UDP to emulate TCP connections.

          mKCP sacrifices bandwidth to reduce latency. To transmit the same content, mKCP generally consumes more data than TCP.

          Tip

          Make sure the firewall on the host is configured correctly.

          KcpObject

          KcpObject corresponds to the kcpSettings in the Transport Protocol,

          {
          @@ -45,6 +45,6 @@
             "type": "none"
           }
           

          type: string

          Type of obfuscation. Corresponding inbound and outbound must have the same value. Choices are:

          • "none":Default value. No obfuscation is used.
          • "srtp":Obfuscated as SRTP traffic. It may be recognized as video calls such as Facetime.
          • "utp":Obfuscated as uTP traffic. It may be recognized as Bittorrent traffic.
          • "wechat-video":Obfuscated to WeChat traffic.
          • "dtls":Obfuscated as DTLS 1.2 packets.
          • "wireguard":Obfuscated as WireGuard packets. (NOT true WireGuard protocol)

          Special Thanks

          Improvements to the KCP protocol

          smaller protocol header

          The original KCP protocol uses a fixed header of 24 bytes, while mKCP modifies it to 18 bytes for data packets and 16 bytes for acknowledgement (ACK) packets. A smaller header helps evade feature detection and speeds up transmission.

          In addition, the original KCP can only confirm that one packet has been received with a single ACK packet. This means that when KCP needs to confirm that 100 packets have been received, it will send out 2400 bytes of data (24 x 100), including a large amount of repeated header information that wastes bandwidth. mKCP compresses multiple ACK packets, so 100 ACK packets only require 418 bytes (16 + 2 + 100 x 4), which is equivalent to one-sixth of the original KCP.

          ACK packet retransmission

          In the original KCP protocol, an ACK packet is only sent once. If an ACK packet is lost, it will cause unnecessary bandwidth waste due to data retransmission. In contrast, mKCP retransmits ACK packets at a certain frequency until they are confirmed by the sender. The size of a single ACK packet is 22 bytes, much smaller than the data packets which are over 1000 bytes. Therefore, the cost of retransmitting ACK packets is much lower.

          Connection state control

          mKCP can effectively initiate and close connections. When the remote host initiates disconnection, the connection will be released within two seconds. When the remote host lost connection, the connection will be released within a maximum of 30 seconds.

          The original KCP does not support this scenario.

          - + diff --git a/en/config/transports/splithttp.html b/en/config/transports/splithttp.html index 75d601ac29..b9ac487f03 100644 --- a/en/config/transports/splithttp.html +++ b/en/config/transports/splithttp.html @@ -24,11 +24,11 @@ SplitHTTP | Project X - - + + -

          Warning

          This translation was modified on 16 September 2024 and an updated version (18 September 2024) is available on the source page. View the original page

          SplitHTTP

          v1.8.16+

          Uses HTTP chunked-transfer encoding for download, and multiple HTTP requests for upload.

          Can be deployed on CDNs that do not support WebSocket. However, the CDN must support HTTP chunked transfer encoding in a streaming fashion, no response buffering.

          This transport serves the same purpose as Meek (support non-WS CDN). It has the above streaming requirement to the CDN so that download can be much faster than (v2fly) Meek, close to WebSocket performance. The upload is also optimized, but still much more limited than WebSocket.

          Like WebSocket transport, SplitHTTP parses the X-Forwarded-For header for logging.

          SplitHttpObject

          The SplitHttpObject corresponds to the splithttpSettings section under transport configurations.

          {
          +    

          SplitHTTP

          v1.8.16+

          Uses HTTP chunked-transfer encoding for download, and multiple HTTP requests for upload.

          Can be deployed on CDNs that do not support WebSocket. However, the CDN must support HTTP chunked transfer encoding in a streaming fashion, no response buffering.

          This transport serves the same purpose as Meek (support non-WS CDN). It has the above streaming requirement to the CDN so that download can be much faster than (v2fly) Meek, close to WebSocket performance. The upload is also optimized, but still much more limited than WebSocket.

          Like WebSocket transport, SplitHTTP parses the X-Forwarded-For header for logging.

          SplitHttpObject

          The SplitHttpObject corresponds to the splithttpSettings section under transport configurations.

          {
             "path": "/",
             "host": "xray.com",
             "headers": {
          @@ -40,13 +40,13 @@
             "noSSEHeader": false,
             "xPaddingBytes": "100-1000",
             "xmux": {
          -    "maxConnections": 0,
               "maxConcurrency": 0,
          +    "maxConnections": 0,
               "cMaxReuseTimes": 0,
               "cMaxLifetimeMs": 0
             }
           }
          -

          path: string

          HTTP path used by the connection. Defaults to "/".

          host: string

          HTTP Host sent by the connection. Empty by default. If this value is empty on the server, the host header sent by clients will not be validated.

          If the Host header has been defined on the server in any way, the server will validate if the Host header matches.

          The current priority of the Host header sent by clients: host > headers > address

          headers: map {string: string}

          Customized HTTP headers defined in key-value pairs. Defaults to empty.

          scMaxEachPostBytes: int/string

          The maximum size of upload chunks, in bytes. Defaults to 1MB.

          The size set by the client must be lower than this value, otherwise when the POST request is sent larger than the value set by the server, the request will be rejected.

          This value should be smaller than the maximum request body allowed by the CDN or other HTTP reverse proxy, otherwise an HTTP 413 error will be thrown.

          It can also be in the form of a string "1000000-2000000". The core will randomly select a value within the range each time to reduce fingerprints.

          scMaxConcurrentPosts: int/string

          The number of concurrent uploads to run. Defaults to 100 on the client, and 200 on the server.

          The value on the client must not be higher than on the server. Otherwise, connectivity issues will occur. In practice, the upload concurrency is also limited by minUploadIntervalMs, so the actual concurrency on the client side will be much lower.

          It can also be in the form of a string "100-200", and the core will randomly select a value within the range each time to reduce fingerprints.

          scMinPostsIntervalMs: int/string

          (Client-only) How much time to pass between upload requests at a minimum. Defaults to 30 (milliseconds).

          It can also be in the form of a string "10-50", and the core will randomly select a value within the range each time to reduce fingerprints.

          noSSEHeader

          (Server-only) Do not send the Content-Type: text/event-stream response header. Defaults to false (the header will be sent)

          xPaddingBytes

          Added in 1.8.24

          Control the padding of requests and responses. Defaults to "100-1000", meaning that each GET and POST will be padded with a random amount of bytes in that range.

          A value of -1 disables padding entirely.

          You can lower this to save bandwidth or increase it to improve censorship resistance. Too much padding may cause the CDN to reject traffic.

          xmux

          Added in 24.9.16

          Control the way that SplitHTTP distributes sub-connections (H2 stream or QUIC stream) on "physical" TCP/QUIC connections. The default behavior is to put all sub-connections of an outbound onto a single physical connection, which is basically equal to using mux.cool with concurrency=999999999.

          It is recommended to tweak this transport-specific xmux instead of the global mux key (mux.cool) for better performance, especially on QUIC/H3 connections. That said, either one may be useful to work around certain connectivity issues (and bugs in xray or other software).

          • maxConnections: Default 0 = infinite. The number of physical connections to open. Every sub-connection will open a new connection until this value is reached, only then connections will be reused. Mutually exclusive with maxConcurrency.

          • maxConcurrency: Default 0 = infinite. The maximum number of sub-connections to put onto a physical connection. New physical connections will be opened to stay under this limit overall. Mutually exclusive with maxConnections. Equivalent to mux.cool's concurrency.

          • cMaxReuseTimes: Default 0 = infinite. Stop re-using a physical connection after it has been used for this many sub-connections.

          • cMaxLifetimeMs: Default 0 = infinite. Stop re-using a physical connection after it has been open for this many milliseconds.

          HTTP versions

          Added in 1.8.21: HTTP/3 support

          SplitHTTP supports http/1.1, h2 and h3 ALPN values. If the value is not set, h2 (prior-knowledge) is assumed when TLS is enabled, and http/1.1 without TLS. If the value is set to h3, the client will attempt to connect as HTTP/3, so UDP instead of TCP.

          The server listens to HTTP/1.1 and h2 by default, but if h3 ALPN is set on the server, it will listen as HTTP/3.

          Please note that nginx, Caddy and all CDN will almost certainly translate client requests to a different HTTP version for forwarding, and so the server may have to be configured with a different ALPN value than the client. If you use a CDN, it is very unlikely that h3 is a correct value for the server, even if the client speaks h3.

          Troubleshooting

          • If a connection hangs, the CDN may not support streaming downloads. You can use curl -Nv https://example.com/abcdef to initiate a download and see for yourself (see protocol details).

            If you do not see 200 OK and a response body of ok, then the CDN is buffering the response body. Please ensure that all HTTP middleboxes along the path between client and server observe X-Accel-Buffering: no from their origin server. If your chain is xray -> nginx -> CDN -> xray, nginx may strip this response header and you have to re-add it.

          Browser Dialer

          v1.8.17+

          If uTLS is not enough, SplitHTTP's TLS can be handled by a browser using Browser Dialer

          Protocol details

          See #3412open in new tag and #3462open in new tag for extensive discussion and revision of the protocol. Here is a summary, and the minimum needed to be compatible:

          1. GET /<UUID> opens the download. The server immediately responds with 200 OK, and immediately sends the string ok (arbitrary length, such as ooook) to force HTTP middleboxes into flushing headers.

            The server will send these headers:

            • X-Accel-Buffering: no to prevent response buffering in nginx and CDN
            • Content-Type: text/event-stream to prevent response buffering in some CDN, can be disabled with noSSEHeader
            • Transfer-Encoding: chunked in HTTP/1.1 only
            • Cache-Control: no-store to disable any potential response caching.
          2. Client uploads using POST /<UUID>/<seq>. seq starts at 0 and can be used like TCP seq number, and multiple "packets" may be sent concurrently. The server has to reassemble the "packets" live. The sequence number never resets for simplicity reasons.

            The client may open upload and download in any order, either one starts a session. However, eventually GET needs to be opened (current deadline is hardcoded to 30 seconds) If not, the session will be terminated.

          3. The GET request is kept open until the tunneled connection has to be terminated. Either server or client can close.

            How this actually works depends on the HTTP version. For example, in HTTP/1.1 it is only possible to disrupt chunked-transfer by closing the TCP connection, in other versions the stream is closed or aborted.

          Recommendations:

          • Do not assume any custom headers are transferred correctly by the CDN. This transport is built for CDN who do not support WebSocket, these CDN tend to not be very modern (or good).

          • It should be assumed there is no streaming upload within a HTTP request, so the size of a packet should be chosen to optimize between latency, throughput, and any size limits imposed by the CDN (just like TCP, nagle's algorithm and MTU...)

          • HTTP/1.1 and h2 should be supported by server and client, and it should be expected that the CDN will translate arbitrarily between versions. A HTTP/1.1 server may indirectly end up talking to a h2 client, and vice versa.

          - +

          path: string

          HTTP path used by the connection. Defaults to "/".

          host: string

          HTTP Host sent by the connection. Empty by default. If this value is empty on the server, the host header sent by clients will not be validated.

          If the Host header has been defined on the server in any way, the server will validate if the Host header matches.

          The current priority of the Host header sent by clients: host > headers > address

          headers: map {string: string}

          Customized HTTP headers defined in key-value pairs. Defaults to empty.

          scMaxEachPostBytes: int/string

          The maximum size of upload chunks, in bytes. Defaults to 1MB.

          The size set by the client must be lower than this value, otherwise when the POST request is sent larger than the value set by the server, the request will be rejected.

          This value should be smaller than the maximum request body allowed by the CDN or other HTTP reverse proxy, otherwise an HTTP 413 error will be thrown.

          It can also be in the form of a string "1000000-2000000". The core will randomly select a value within the range each time to reduce fingerprints.

          scMaxConcurrentPosts: int/string

          The number of concurrent uploads to run. Defaults to 100 on the client, and 200 on the server.

          The value on the client must not be higher than on the server. Otherwise, connectivity issues will occur. In practice, the upload concurrency is also limited by minUploadIntervalMs, so the actual concurrency on the client side will be much lower.

          It can also be in the form of a string "100-200", and the core will randomly select a value within the range each time to reduce fingerprints.

          scMinPostsIntervalMs: int/string

          (Client-only) How much time to pass between upload requests at a minimum. Defaults to 30 (milliseconds).

          It can also be in the form of a string "10-50", and the core will randomly select a value within the range each time to reduce fingerprints.

          noSSEHeader

          (Server-only) Do not send the Content-Type: text/event-stream response header. Defaults to false (the header will be sent)

          xPaddingBytes

          Added in 1.8.24

          Control the padding of requests and responses. Defaults to "100-1000", meaning that each GET and POST will be padded with a random amount of bytes in that range.

          A value of -1 disables padding entirely.

          You can lower this to save bandwidth or increase it to improve censorship resistance. Too much padding may cause the CDN to reject traffic.

          xmux

          Added in 24.9.16

          Control the way that SplitHTTP distributes sub-connections (H2 stream or QUIC stream) on "physical" TCP/QUIC connections. The default behavior is to put all sub-connections of an outbound onto a single physical connection, which is basically equal to using mux.cool with concurrency=999999999.

          It is recommended to tweak this transport-specific xmux instead of the global mux key (mux.cool) for better performance, especially on QUIC/H3 connections. That said, either one may be useful to work around certain connectivity issues (and bugs in xray or other software).

          • maxConcurrency: Default 0 = infinite. The maximum number of sub-connections to put onto a physical connection. New physical connections will be opened to stay under this limit overall. Mutually exclusive with maxConnections. Equivalent to mux.cool's concurrency.

          • maxConnections: Default 0 = infinite. The number of physical connections to open. Every sub-connection will open a new connection until this value is reached, only then connections will be reused. Mutually exclusive with maxConcurrency.

          • cMaxReuseTimes: Default 0 = infinite. Stop re-using a physical connection after it has been used for this many sub-connections.

          • cMaxLifetimeMs: Default 0 = infinite. Stop re-using a physical connection after it has been open for this many milliseconds.

          HTTP versions

          Added in 1.8.21: HTTP/3 support

          SplitHTTP supports http/1.1, h2 and h3 ALPN values. If the value is not set, h2 (prior-knowledge) is assumed when TLS is enabled, and http/1.1 without TLS. If the value is set to h3, the client will attempt to connect as HTTP/3, so UDP instead of TCP.

          The server listens to HTTP/1.1 and h2 by default, but if h3 ALPN is set on the server, it will listen as HTTP/3.

          Please note that nginx, Caddy and all CDN will almost certainly translate client requests to a different HTTP version for forwarding, and so the server may have to be configured with a different ALPN value than the client. If you use a CDN, it is very unlikely that h3 is a correct value for the server, even if the client speaks h3.

          Troubleshooting

          • If a connection hangs, the CDN may not support streaming downloads. You can use curl -Nv https://example.com/abcdef to initiate a download and see for yourself (see protocol details).

            If you do not see 200 OK and a response body of ok, then the CDN is buffering the response body. Please ensure that all HTTP middleboxes along the path between client and server observe X-Accel-Buffering: no from their origin server. If your chain is xray -> nginx -> CDN -> xray, nginx may strip this response header and you have to re-add it.

          Browser Dialer

          v1.8.17+

          If uTLS is not enough, SplitHTTP's TLS can be handled by a browser using Browser Dialer

          Protocol details

          See #3412open in new tag and #3462open in new tag for extensive discussion and revision of the protocol. Here is a summary, and the minimum needed to be compatible:

          1. GET /<UUID> opens the download. The server immediately responds with 200 OK, and immediately sends the string ok (arbitrary length, such as ooook) to force HTTP middleboxes into flushing headers.

            The server will send these headers:

            • X-Accel-Buffering: no to prevent response buffering in nginx and CDN
            • Content-Type: text/event-stream to prevent response buffering in some CDN, can be disabled with noSSEHeader
            • Transfer-Encoding: chunked in HTTP/1.1 only
            • Cache-Control: no-store to disable any potential response caching.
          2. Client uploads using POST /<UUID>/<seq>. seq starts at 0 and can be used like TCP seq number, and multiple "packets" may be sent concurrently. The server has to reassemble the "packets" live. The sequence number never resets for simplicity reasons.

            The client may open upload and download in any order, either one starts a session. However, eventually GET needs to be opened (current deadline is hardcoded to 30 seconds) If not, the session will be terminated.

          3. The GET request is kept open until the tunneled connection has to be terminated. Either server or client can close.

            How this actually works depends on the HTTP version. For example, in HTTP/1.1 it is only possible to disrupt chunked-transfer by closing the TCP connection, in other versions the stream is closed or aborted.

          Recommendations:

          • Do not assume any custom headers are transferred correctly by the CDN. This transport is built for CDN who do not support WebSocket, these CDN tend to not be very modern (or good).

          • It should be assumed there is no streaming upload within a HTTP request, so the size of a packet should be chosen to optimize between latency, throughput, and any size limits imposed by the CDN (just like TCP, nagle's algorithm and MTU...)

          • HTTP/1.1 and h2 should be supported by server and client, and it should be expected that the CDN will translate arbitrarily between versions. A HTTP/1.1 server may indirectly end up talking to a h2 client, and vice versa.

          + diff --git a/en/config/transports/tcp.html b/en/config/transports/tcp.html index 5060b15777..0d7d3e2f61 100644 --- a/en/config/transports/tcp.html +++ b/en/config/transports/tcp.html @@ -24,8 +24,8 @@ TCP | Project X - - + +

          TCP

          TCP (Transmission Control Protocol) is currently one of the recommended transport protocols

          It can be combined with various protocols in multiple ways.

          TcpObject

          TcpObject corresponds to the tcpSettings item in the Transport Protocol.

          {
          @@ -69,6 +69,6 @@
             }
           }
           

          version: string

          HTTP version, default is "1.1"

          status: string

          HTTP status, default is "200"

          reason: string

          HTTP status description, default value is "OK"

          headers: map {string, [ string ]}

          HTTP header, a key-value pair, each key represents the name of an HTTP header, and the corresponding value is an array.

          Each request will include all the keys and randomly select a corresponding value. Please refer to the default values shown in the example above.

          - + diff --git a/en/config/transports/websocket.html b/en/config/transports/websocket.html index c34e183abe..7231af5276 100644 --- a/en/config/transports/websocket.html +++ b/en/config/transports/websocket.html @@ -24,8 +24,8 @@ WebSocket | Project X - - + +

          Warning

          This translation was modified on 30 March 2024 and an updated version (29 July 2024) is available on the source page. View the original page

          WebSocket

          Uses standard WebSocket for data transmission.

          WebSocket connections can be proxied by other web servers (like NGINX) or by VLESS fallback paths.

          Tip

          WebSocket inbounds will parse the X-Forwarded-For header received, overriding the source address with a higher priority than the source address got from PROXY protocol.

          WebSocketObject

          WebSocketObject corresponds to the wsSettings property of the transport configs.

          {
          @@ -37,6 +37,6 @@
             }
           }
           

          acceptProxyProtocol: true | false

          Only used by inbounds. Indicates whether to accept the PROXY protocol.

          The PROXY protocolopen in new tag is used to transmit the real source IP and port of connections. If you are not familiar with this, leave it alone.

          Commonplace reverse proxy software solutions (like HAProxy and NGINX) can be configured to have source IPs and ports sent with PROXY protocol. Same goes to VLESS fallbacks xver.

          When true, after the underlying TCP connection is established, the downstream must first send the source IPs and ports in PROXY protocol v1 or v2, or the connection will be terminated.

          path: string

          The HTTP path used by the WebSocket connection. Defaults to "/".

          If path contains the ed query parameter, early data will be activated for latency reduction, and its value will be the length threshold of the first packet. If the length of the first packet exceeds this value, early data won't be activated. The recommended value is 2560, with a maximum of 8192. Compatibility problems can occur when the value is set too high. Try lowering the threshold when encountering such problems.

          host: string

          The Host header sent in HTTP requests. Defaults to an empty string. Servers will not validate the Host header sent by clients when left blank.

          If the Host header has been defined on the server in any way, the server will validate if the Host header matches.

          The current priority of the Host header sent by clients: host > headers > address

          headers: map {string: string}

          Customized HTTP headers defined in key-value pairs. Defaults to empty.

          Browser Dialer

          Use the browser to handle TLS, see Browser Dialer

          - + diff --git a/en/development/index.html b/en/development/index.html index 90b1d829c7..11d512c279 100644 --- a/en/development/index.html +++ b/en/development/index.html @@ -24,11 +24,11 @@ Development Guide | Project X - - + +

          Development Guide

          Compile Documentation

          Xray supports multiple platforms, and you can perform cross-compilation on various platforms by yourself.

          Please click Compile Documentation to view specific compile-related content.

          Design Concept

          Xray kernel provides a platform for secondary development.

          This section explains the design goals and architecture of Xray.

          Please click Design Principles to learn about the design goals and architecture of Xray.

          Development Standards

          This section outlines the guidelines to follow when obtaining code, developing, submitting PRs, as well as the relevant coding standards.

          Please click Development Specification to view the guidelines that should be followed during Xray development.

          Protocol Details

          Xray uses many protocols, and you can obtain a detailed description of each protocol through various means.

          VLESS Protocol

          VLESS is a stateless lightweight transport protocol that can serve as a bridge between Xray clients and servers.

          VMess Protocol

          VMess is an encrypted transport protocol that can act as a bridge between Xray clients and servers.

          Mux.Cool Protocol

          Mux.Cool protocol is a multiplexing transport protocol used to transmit multiple independent data streams within an established data stream.

          mKCP Protocol

          mKCP is a stream transmission protocol modified from the KCP protocolopen in new tag that can transmit arbitrary data streams in order.

          - + diff --git a/en/development/intro/compile.html b/en/development/intro/compile.html index 7198196fb3..804ae45cd6 100644 --- a/en/development/intro/compile.html +++ b/en/development/intro/compile.html @@ -24,8 +24,8 @@ Compile the document | Project X - - + +

          Compile the document

          Preparatory Work

          Xray uses Golangopen in new tag as its programming language, so you need to install the latest version of Golang first in order to compile.

          If you happen to use Windows, please make sure to use Powershell.

          Pull Xray source code

          git clone https://github.com/XTLS/Xray-core.git
          @@ -38,6 +38,6 @@
           $env:GOOS="linux"
           $env:GOARCH="amd64"
           

          go build -o xray -trimpath -ldflags "-s -w -buildid=" ./main```

          After uploading to the server, remember to execute chmod +x xray in the server terminal.

          Tip

          Execute go tool dist list to view all supported systems and architectures.

          Reproducible Build:

          Following the above steps, it is possible to compile and release an identical binary file as the one in Release.

          Warning

          Please confirm that you are using the same Golang version as the one used to compile the release.

          - + diff --git a/en/development/intro/design.html b/en/development/intro/design.html index 50eb692bbd..d26e4bd382 100644 --- a/en/development/intro/design.html +++ b/en/development/intro/design.html @@ -24,11 +24,11 @@ Design Objectives | Project X - - + +

          Design Objectives

          • Xray Kernel provides a platform that supports essential network proxy functions and can be developed upon to provide a better user experience.
          • Cross-platform is the primary principle to reduce the cost of secondary development.

          Architecture

          Architecture

          The kernel is divided into three layers: the application layer, the proxy layer, and the transport layer.

          Each layer contains several modules, which are independent of each other. Modules of the same type can be seamlessly replaced.

          Application Layer

          The application layer contains some commonly used functions in proxy layers, which are abstracted for reuse in different proxy modules.

          The modules at the application layer should be implemented purely in software and should not be dependent on hardware or platform-related technologies.

          List of Important Modules:

          • Dispatcher: Used to transfer data received by the inbound agent to the outbound agent;
          • Router: Routing module, see Routing Configuration for details;
          • DNS: Built-in DNS server module;
          • Proxy Manager: Proxy manager;

          Proxy Layer

          The proxy layer is divided into two parts: Inbound Proxy and Outbound Proxy.

          The two parts are independent of each other, where the inbound proxy does not rely on a specific outbound proxy, and vice versa.

          Inbound Proxy

          Outbound Proxy

          Transport Layer

          The transport layer provides a set of tools and modules related to network data transmission.

          - + diff --git a/en/development/intro/guide.html b/en/development/intro/guide.html index 11bf626bfc..d38537e427 100644 --- a/en/development/intro/guide.html +++ b/en/development/intro/guide.html @@ -24,8 +24,8 @@ Development Standards | Project X - - + +

          Warning

          This translation was modified on 19 May 2023 and an updated version (13 February 2024) is available on the source page. View the original page

          Development Standards

          Basic

          Version Control

          Project X's code is hosted on GitHub:

          You can use Gitopen in new tag to get the code.

          Branch

          • The main branch is the backbone of this project.
          • The main branch is also the release branch of this project.
          • It is necessary to ensure that main can be compiled and used normally at any time.
          • If you need to develop new features, please create a new branch for development. After development and sufficient testing, merge it back to the main branch.
          • Please delete branches that have been merged into the main branch and are no longer necessary.

          Release

          WIP (Note: this is not translatable as it is a technical tag)
          • Create two release channels: one for the beta version and another for the stable version.
            • The beta version, also known as the daily build, is mainly used for specific testing, experimentation, and instant feedback and improvement.
            • The stable version, updated regularly (e.g. monthly), merges stable modifications and releases them.

          Citing other projects

          • Golang
            • It is recommended to use the Golang standard library and libraries under golang.org/x/open in new tag for product code;
            • If you need to reference other projects, please create an issue for discussion beforehand;
          • Other
            • Tools that do not violate the agreement of both parties and are helpful to the project can be used.

          Development Process

          Before Writing Code

          If you encounter any issues or have any ideas for the project, please create an issueopen in new tag for discussion to reduce redundant work and save time spent on coding.

          Modify the code

          • Golang
            • Please refer to Effective Goopen in new tag;
            • Run go generate core/format.go before each push;
            • If you need to modify protobuf, such as adding new configuration items, please run: go generate core/proto.go;
            • It is recommended to pass the test before submitting a pull request: go test ./...;
            • It is recommended to have more than 70% code coverage for newly added code before submitting pull requests.
          • Other
            • Please pay attention to the readability of the code.

          Pull Request

          • Before submitting a PR, please run git pull https://github.com/xray/xray-core.git to ensure that the merge can proceed smoothly;
          • One PR only does one thing. If there are fixes for multiple bugs, please submit a PR for each bug;
          • Due to Golang's special requirements (Package path), the PR process for Go projects is different from other projects. The recommended process is as follows:
            1. Fork this project first and create your own github.com/<your_name>/Xray-core.git repository;
            2. Clone your own Xray repository to your local machine: git clone https://github.com/<your_name>/Xray-core.git;
            3. Create a new branch based on the main branch, for example git branch issue24 main;
            4. Make changes on the new branch and commit the changes;
            5. Before pushing the modified branch to your own repository, switch to the main branch, and run git pull https://github.com/xray/xray-core.git to pull the latest remote code;
            6. If new remote code is obtained in the previous step, switch to the branch you created earlier and run git rebase main to perform branch merging. If there is a file conflict, you need to resolve the conflict;
            7. After the previous step is completed, you can push the branch you created to your own repository: git push -u origin your-branch
            8. Finally, send a PR from your new pushed branch in your own repository to the main branch of xtls/Xray-core;
            9. Please fully describe the purpose of this PR, including the problem solved, the new feature added, or the modifications made in the title and body of the PR;
            10. Please be patient and wait for the developer's response.

          Modifying Code

          Functional issue

          Please submit at least one test case to verify changes to existing functionality.

          Please provide the necessary test data to demonstrate performance issues in existing code or performance improvements in new code.

          New Feature

          • If the new feature does not affect the existing functionality, please provide a toggle (such as a flag) that can be turned on/off, and keep the new feature disabled by default.
          • For major new features (such as adding a new protocol), please submit an issue for discussion before development.

          Other

          It depends on the specific situation.

          Xray Coding Guidelines

          The following content is applicable to Golang code in Xray.

          Code Structure

          Xray-core
          @@ -40,6 +40,6 @@
           │   ├── vmess
           ├── transport  // Transport module
           

          Coding Standards

          Basic practices are consistent with the recommendations of the official Golang, with a few exceptions. Written here to help everyone familiarize themselves with Golang.

          Naming

          • Use a single English word for file and directory names, such as hello.go;
            • If not possible, use a hyphen for directories / underscore for files to connect two (or more) words, such as hello-world/hello_again.go;
            • Use _test.go to name test code files;
          • Use PascalCase for types, such as ConnectionHandler;
            • Do not force lowercase for abbreviations, i.e. HTML does not need to be written as Html;
          • Use PascalCase for public member variables;
          • Use camelCase for private member variables, such as privateAttribute;
          • For easy refactoring, it is recommended to use PascalCase for all methods;
            • Place completely private types in internal.

          Content Organization

          • A file contains a main type and its related private functions;
          • Testing-related files, such as Mock tools, should be placed in the testing subdirectory.
          - + diff --git a/en/development/protocols/mkcp.html b/en/development/protocols/mkcp.html index d35f0a5136..d65a2045aa 100644 --- a/en/development/protocols/mkcp.html +++ b/en/development/protocols/mkcp.html @@ -24,11 +24,11 @@ mKCP Protocol | Project X - - + +

          mKCP Protocol

          mKCP is a stream transfer protocol, modified from the KCP protocolopen in new tag, which can transmit any data stream in order.

          Version

          mKCP has no version number and does not guarantee compatibility between versions.

          Dependencies

          Underlying Protocol

          mKCP is a protocol based on UDP, and all communication uses UDP transmission.

          Functions

          • fnv: FNV-1aopen in new tag hash function
            • Takes a string of arbitrary length as input parameter;
            • Outputs a 32-bit unsigned integer.

          Communication Process

          1. mKCP splits data streams into several data packets for transmission. Each data stream has a unique identifier to distinguish it from other data streams. Each data packet in the data stream carries the same identifier.
          2. mKCP does not have a handshake process. When receiving a data packet, it determines whether it is a new call or an ongoing call based on the identifier of the data stream it carries.
          3. Each data packet contains several segments (Segment), which are divided into three types: data (Data), acknowledgment (ACK), and heartbeat (Ping). Each segment needs to be processed separately.

          Data Format

          Data Packet

          4 Bytes2 BytesL Bytes
          Auth AData Len LFragment

          as which:

          • Authentication information A = fnv(fragment), big endian;
          • The fragment may contain multiple sections.

          Data snippet

          2 bytes1 byte1 byte4 bytes4 bytes4 bytes2 bytesLen bytes
          Conv flagCmd flagOpt flagTimestampSequenceUnacknowledgedLen flagData

          as which:

          • Identifier Conv: Identifier for mKCP data stream
          • Command Cmd: Constant 0x01
          • Option Opt: Optional values include:
            • 0x00: Empty option
            • 0x01: Opposite party has sent all data
          • Timestamp Ts: Time when the current segment was sent from the remote end, big endian
          • Sequence Number Sn: The position of the data segment in the data stream, the sequence number of the starting segment is 0, and each new segment is sequentially added by 1
          • Unacknowledged Sequence Number Una: The minimum Sn that the remote host is sending and has not yet received confirmation.

          Confirmation snippet

          2 bytes1 byte1 byte4 bytes4 bytes4 bytes2 bytesLen * 4 bytes
          Conv IDCmdOptWndNext Seq NumberTimestampLengthReceived Seq Number

          as which:

          • Identifier Conv: Identifier of the mKCP data stream
          • Command Cmd: Constant 0x00
          • Option Opt: Same as above
          • Window Wnd: The maximum sequence number that the remote host can receive
          • Next receive sequence number Sn: The smallest sequence number of the data segment that the remote host has not received
          • Timestamp Ts: The timestamp of the latest received data segment by the remote host, which can be used to calculate the delay
          • Received sequence numbers: Each 4 bytes, indicating that the data of this sequence number has been confirmed received.

          as which:

          • The remote host expects to receive data within the serial number [Sn, Wnd) range.

          Heartbeat Fragments

          2 Bytes1 Byte1 Byte4 Bytes4 Bytes4 Bytes
          Conv IDCmdOptUnacknowledged Seq NoNext Receive Seq NoRto

          as which:

          • Identifier Conv: Identifier for the mKCP data stream
          • Command Cmd: Optional values include:
            • 0x02: Remote host forcibly terminates the session
            • 0x03: Normal heartbeat
          • Option Opt: Same as above
          • Unacknowledged sequence number Una: Same as the Una of the data fragment
          • Next receive sequence number Sn: Same as the Sn of the acknowledgement fragment
          • Delay Rto: Delay calculated by the remote host itself
          - + diff --git a/en/development/protocols/muxcool.html b/en/development/protocols/muxcool.html index 3c232c378f..dc81ff2971 100644 --- a/en/development/protocols/muxcool.html +++ b/en/development/protocols/muxcool.html @@ -24,11 +24,11 @@ Mux.Cool Protocol | Project X - - + +

          Mux.Cool Protocol

          Mux.Cool protocol is a multiplexing transport protocol that is used to transmit multiple independent data streams within an established data stream.

          Version

          The current version is 1 Beta.

          Dependencies

          Underlying Protocol

          Mux.Cool must run on top of a reliable established data stream.

          Communication Process

          Within a Mux.Cool connection, multiple sub-connections can be transmitted, each with a unique ID and status. The transmission process consists of frames, with each frame used to transmit data for a specific sub-connection.

          Client behavior

          When there is a need for a connection and there are no existing available connections, the client initiates a new connection to the server, referred to as the "main connection".

          1. One main connection can be used to send several sub-connections. The client can decide independently how many sub-connections the main connection can handle.
          2. For a new sub-connection, the client must send the New status to notify the server to establish the sub-connection, and then use the Keep status to transmit data.
          3. When the sub-connection ends, the client sends the End status to notify the server to close the sub-connection.
          4. The client can decide when to close the main connection, but must ensure that the server also maintains the connection.
          5. The client can use the KeepAlive status to prevent the server from closing the main connection.

          Server-side behavior

          When a new sub-connection is received on the server side, the server should handle it as a normal connection.

          1. When the status "End" is received, the server can close the upstream connection to the target address.
          2. The same ID used in the request must be used to transfer sub-connection data in the server response.
          3. The server cannot use the "New" status.
          4. The server can use the KeepAlive status to avoid the client closing the main connection.

          Data Format

          Mux.Cool uses symmetric transmission format, where the client and server send and receive data in the same format.

          Frame Format

          2 BytesL BytesX Bytes
          Metadata Length LMetadataAdditional Data

          Metadata

          There are several types of metadata. All types of metadata contain two items, ID and Opt, with the following meanings:

          • ID: Unique identifier of the sub-connection
            • For general MUX sub-connections, the ID is accumulated starting from 1
            • For XUDP, the ID is always 0
          • Opt:
            • D(0x01): Additional data is available

          When option Opt(D) is enabled, the additional data format is as follows:

          2 BytesX-2 Bytes
          Length X-2Data
          2 Bytes1 Byte1 Byte1 Byte2 Bytes1 ByteA Bytes
          ID0x01OptionNetwork NPortType TAddress

          where:

          • Network type N:
            • 0x01: TCP, indicating that the traffic of the current sub-connection should be sent to the destination in the way of TCP.
            • 0x02: UDP, indicating that the traffic of the current sub-connection should be sent to the destination in the way of UDP.
          • Address type T:
            • 0x01: IPv4
            • 0x02: Domain name
            • 0x03: IPv6
          • Address A:
            • When T = 0x01, A is a 4-byte IPv4 address;
            • When T = 0x02, A is a 1-byte length (L) + L-byte domain name;
            • When T = 0x03, A is a 16-byte IPv6 address;

          If Opt(D) is enabled when creating a sub-connection, the data carried by this frame needs to be sent to the target host.

          Keep sub-connections

          2 Bytes1 Byte1 Byte
          ID0x02Option

          If Opt(D) is enabled while maintaining sub-connections, the data carried by this frame needs to be sent to the target host. XUDP adds the UDP address after Opt(D), and the format is the same as creating a new sub-connection.

          End

          2 Bytes1 Byte1 Byte
          ID0x03Option

          If Opt(D) is enabled while maintaining sub-connections, the data carried by this frame needs to be sent to the target host.

          KeepAlive

          2 Bytes1 Byte1 Byte
          ID0x04Option Opt

          While staying connected:

          • If Opt(D) is enabled, the data carried by this frame must be discarded.
          • ID can be a random value.

          Application

          The Mux.Cool protocol is agnostic to the underlying protocol and can theoretically use any reliable streaming connection to transmit Mux.Cool protocol data.

          In target-oriented protocols such as Shadowsocks and VMess, a specified address must be included when establishing a connection. To maintain compatibility, the Mux.Cool protocol specifies the address as "v1.mux.cool". When the target address of the main connection matches this address, the Mux.Cool forwarding method is used. Otherwise, forwarding is done in the traditional way. (Note: This is an internal tag in the program, and VMess and VLESS do not send the "v1.mux.cool" address in data packets.)

          - + diff --git a/en/development/protocols/vless.html b/en/development/protocols/vless.html index 1b2fd6e4aa..8c21bcd894 100644 --- a/en/development/protocols/vless.html +++ b/en/development/protocols/vless.html @@ -24,11 +24,11 @@ VLESS Protocol | Project X - - + +

          VLESS Protocol

          VLESS is a stateless lightweight transmission protocol that can be used as a bridge between Xray clients and servers.

          Request & Response

          1 byte16 bytes1 byteM bytes1 byte2 bytes1 byteS bytesX bytes
          Protocol VersionEquivalent UUIDAdditional Information Length MAdditional Information ProtoBufInstructionPortAddress TypeAddressRequest Data
          1 Byte1 ByteN BytesY Bytes
          Protocol Version, consistent with the requestLength of additional information NAdditional information in ProtoBufResponse data

          VLESS had the aforementioned structure as early as the second alpha test version (ALPHA 2), with BETA being the fifth test version.

          "Response authentication" has been replaced with "Protocol version" and moved to the front, allowing VLESS to upgrade and eliminate the overhead of generating pseudo-random numbers. The obfuscation-related structure has been replaced with "Additional information" (ProtoBuf) and moved forward, giving the protocol itself scalability, with minimal overhead (gogo/protobufopen in new tag). If there is no additional information, there is no relevant overhead.

          I always thought that "response authentication" was not necessary, and ALPHA replaced crypto/rand with math/rand in order to improve the performance of random number generation, which is no longer needed.

          The "Protocol Version" not only serves as "Response Authentication", but also gives VLESS the ability to upgrade the protocol structure seamlessly, bringing infinite possibilities. The "Protocol Version" is 0 in the test version and 1 in the official version. If there are any incompatible protocol structural changes in the future, the version should be upgraded.

          The design of VLESS server is switch version, which supports all VLESS versions at the same time. If you need to upgrade the protocol version (which may not happen), it is recommended that the server support it one month in advance, and then change the client after one month. VMess requests also have protocol versions, but their authentication information is outside, and the instruction part is highly coupled and has fixed encryption, which makes the protocol version meaningless inside. The server does not judge it, and the response does not have a protocol version. Trojan's protocol structure does not have a protocol version.

          The following is a UUID. I used to think that 16 bytes were a bit long and considered shortening it. However, I later saw that Trojan used 56 printable characters (56 bytes), which completely dispelled this idea. The server needs to verify the UUID every time, so performance is also very important: VLESS's Validator has undergone multiple refactoring/upgrades. Compared with VMess, it is very concise and consumes very few resources. It can support a large number of users at the same time, and its performance is also very strong. The verification speed is extremely fast (sync.Map). API dynamically adds and deletes users, making it more efficient and smooth. https://github.com/XTLS/Xray-core/issues/158

          Introducing ProtoBuf is an innovation, which will be explained in detail later. The structure from "instruction" to "address" is currently identical to VMess and also supports Mux.

          Overall, ALPHA 2 to BETA mainly includes: structural evolution, cleaning and integration, performance improvement, and more completeness. All of these are incremental improvements, please refer to VLESS Changesopen in new tag for details.

          ProtoBuf

          It seems that only VLESS supports embedding ProtoBuf, which is a data exchange format that encodes information tightly into binary TLV (Tag Length Value) structures.

          The reason is that I saw an article that said that SS has some drawbacks, such as the lack of a design error reporting mechanism, and the client cannot take further action based on different errors. (But I don't agree that all errors should be reported, otherwise it can't prevent active probing. In the next beta version, the server can return a custom string of information.) So I think a scalable structure is important, and in the future, it can also carry dynamic port instructions. Not only the response, but the request also needs a similar structure. I originally planned to design TLV by myself, but then I found that ProtoBuf is the structure, ready-made, and it is completely suitable for this purpose, and the support for various languages is also good.

          Currently, "Additional Information" only has Scheduler and SchedulerV, which are substitutes for MessName and MessSeed. When you don't need them, the "Additional Information Length" is 0, so there is no ProtoBuf serialization/deserialization overhead. Actually, I prefer to call this process "concatenation" because that's all pb does in principle, and the related overhead is minimal. The concatenated bytes are very compact, similar to ALPHA's solution, and those who are interested can output and compare them separately.

          To indicate different levels of support for additional information (Addons, which can be understood as plugins and can have many plugins in the future), the next beta version will add "Addon Version" before "Addon Length". 256-1 = 255 bytes is enough and reasonable (65535 is too much and there may be malicious padding), and only one-tenth of the existing space is used. In the future, there will not be so many addons at the same time, and most of the time there will be no addons at all. If it is not enough, you can upgrade to a newer version of VLESS.

          To reduce logical judgment and other expenses, it is temporarily decided that Addons will not use a multi-level structure. A month ago, there was an idea of "variable protocol format". PB can shuffle the order, but it is not necessary because the design of modern encryption will not allow bystanders to see that the headers of the two transmissions are the same.

          Below is an introduction to the concepts of Schedulers and Encryption, both of which are optional. One is designed to address issues related to traffic timing, while the other is designed to address cryptographic issues.

          Flow

          Flow Control (Formerly Traffic Scheduler)

          The Flow Control command is carried by ProtoBuf and manages the data section.

          I previously discovered that VMess's original "metadata obfuscation" feature didn't provide any meaningful changes in TLS but only decreased performance. Consequently, VLESS has abandoned this feature. Moreover, the term "obfuscation" is often misinterpreted as camouflage, so it has been discarded.

          As for camouflage, if it can't be an exact match, wouldn't it be a noticeable characteristic? If it could be an exact match, why not use the intended target for camouflage directly? Initially, I used SSR but found it only provided superficial disguises, fooling operators. Thus, I stopped using it.

          Purpose of Flow Control

          Flow Control influences macro traffic temporal characteristics rather than micro characteristics addressed by encryption. Traffic temporal characteristics can be:

          1. Protocol-based, e.g., Socks5 handshake when using Socks5 over TLS. Different traits on TLS are considered different protocols for monitors. Infinite schedulers equate to infinite protocols (reallocating data sent each time).
          2. Behavior-based, e.g., loading files, their order, and size when accessing Google's homepage. Adding another encryption layer cannot effectively conceal this information.

          Schedulers don't require wrapping like encryption since the header data's tiny amount is negligible compared to the remaining data.

          BETA 2 is anticipated to introduce two basic schedulers: Zstd compression and dynamic data expansion. Advanced operations will control and distribute at a macro level, but for now, these remain under development.

          Encryption

          Unlike VMess, which is highly coupled, VLESS allows the server and client to pre-agree on an encryption method, which is only encrypted with an outer layer. This is somewhat similar to using TLS, which does not affect any of the data carried, and can be understood as replacing TLS with pre-agreed encryption at the bottom. Compared with high coupling, this approach is more reasonable and flexible: if there is a security issue with one encryption method, it can be discarded and another one can be used directly, which is very convenient. The VLESS server also allows for different encryption methods to coexist.

          Compared with VMess, VLESS replaces security with encryption and disableInsecureEncryption with decryption, which solves all the problems. Currently, encryption and decryption only accept "none" and cannot be left blank (even if there are connection security checks in the future), as detailed in the VLESS configuration document. Encryption does not need to be moved out one level, firstly because it cannot reuse a lot of code, and secondly because it will affect the control granularity, which will be understood by looking at future applications.

          Encryption supports two types of forms. One type is completely independent and requires an additional password, suitable for private use. The other type combines with the existing UUID for encryption, which is suitable for public use.

          (If the first type of encryption is used and the password is publicly available in some form, such as multiple people sharing it, then a man-in-the-middle attack is not far away.)

          A redesigned dynamic port may be released simultaneously with encryption, and the command is carried by ProtoBuf. The specific implementation and the dynamic port of VMess will also have many differences.

          It is very easy to cash out encrypted currency, which adds an extra layer of writer & reader. BETA 3 is expected to support SS's aes-128-gcm and chacha20-ietf-poly1305:

          The encryption on the client-side can be filled with "auto: ss_aes-128-gcm_0_123456, ss_chacha20-ietf-poly1305_0_987654". Auto will choose the most suitable one for the current machine, 0 represents the beta version, and the last one is the password. The decryption on the server-side is also filled in a similar way, and each decryption attempt will be made when the request is received.

          Not all combinations need to be tried one by one: VMess encryption is divided into three parts. The first part is the authentication information, which combines UUID, alterId, and time factors. The second part is the instruction part, which is encrypted using a fixed algorithm. The instruction contains the encryption algorithm used in the data part. The third part is the important data part. It can be seen that the VMess encryption and decryption method is actually many-to-one (adapted by the server), not just combining UUID. However, it is also a relatively difficult thing to encrypt only by combining UUID. It will not be available in a short time. Considering that we now have VMessAEAD available, there is no need to rush. If VLESS introduces an encryption method that combines UUID, it is equivalent to reconstructing the entire VMess.

          UDP issues

          XUDP: VLESS & VMess & Mux UDP FullCone NATopen in new tag

          Client Development Guide

          1. The VLESS protocol itself may have incompatible upgrades, but the parameters in the client configuration file are basically only increased and not decreased. The protocol implementation of the iOS client needs to keep up with the upgrade.
          2. Visual standard: Please use VLESS as the UI identifier uniformly, instead of VLess / Vless / vless. The configuration file is not affected, and the code should follow naturally.
          3. Encryption should be made into an input box instead of a selection box. The default value of the new configuration should be none, and if the user leaves it blank, it should be filled in with none.

          Thank you to @DuckSoftopen in new tag for the proposal!

          Please see VMessAEAD/VLESS Sharing Link Standard Proposalopen in new tag for more details.

          - + diff --git a/en/development/protocols/vmess.html b/en/development/protocols/vmess.html index e387319872..d271524c89 100644 --- a/en/development/protocols/vmess.html +++ b/en/development/protocols/vmess.html @@ -24,11 +24,11 @@ VMess Protocol | Project X - - + +

          VMess Protocol

          VMess is an encrypted transmission protocol that can serve as a bridge between the Xray client and server.

          Version

          The current version number is 1.

          Dependencies

          Underlying Protocol

          VMess is a TCP-based protocol where all data is transmitted over TCP.

          User ID

          An ID is equivalent to a UUIDopen in new tag, which is a 16-byte long random number. Its function is similar to a token. An ID looks like: de305d54-75b4-431b-adb2-eb6b9e546014, it is almost entirely random and can be generated using any UUID generator, such as this oneopen in new tag.

          User ID can be specified in the configuration file.

          Functions

          Communication Process

          VMess is a stateless protocol, which means that data can be transmitted directly between the client and the server without the need for a handshake. Each data transmission has no impact on other data transmissions before or after it.

          When a VMess client initiates a request, the server checks whether the request comes from a legitimate client. If the validation passes, the server forwards the request and sends the obtained response back to the client.

          VMess uses an asymmetric format, meaning that the requests sent by the client and the responses from the server use different formats.

          Client Request

          16 BytesX BytesRemaining
          Authentication InformationInstruction PartData Part

          Authentication Information

          The authentication information is a 16-byte hash (hash) value, which is calculated as follows:

          • H = MD5
          • K = User ID (16 bytes)
          • M = UTC time accurate to seconds, with a random value of ±30 seconds from the current time (8 bytes, Big Endian)
          • Hash = HMAC(H, K, M)

          Command Section

          The instruction part is encrypted using AES-128-CFB.

          • Key: MD5(user ID + []byte('c48619fe-8f02-49e0-b9e9-edf763e17e21'))
          • IV: MD5(X + X + X + X), X = []byte(time generated by authentication information) (8 bytes, Big Endian)
          1 Byte16 Bytes16 Bytes1 Byte1 Byte4 bits4 bits1 Byte1 Byte2 Bytes1 ByteN BytesP Bytes4 Bytes
          VersionData Encryption IVData Encryption KeyResponse Authentication ValueOptionsReservedEncryption MethodReservedCommandPortAddress TypeAddressRandom ValueChecksum

          Options Opt Details: (When a bit is 1, it means the option is enabled)

          01234567
          XXXXXMRS

          of which:

          • Version Number Ver: Always 1;
          • Data Encryption IV: Random value;
          • Data Encryption Key: Random value;
          • Response Authentication V: Random value;
          • Option Opt:
            • S (0x01): Standard format data stream (recommended);
            • R (0x02): Client expects to reuse TCP connection (deprecated in Xray 2.23+);
              • This item only takes effect when S is enabled;
            • M (0x04): Enable metadata obfuscation (recommended);
              • This item only takes effect when S is enabled;
              • When this item is enabled, the client and server need to construct two Shake instances respectively, RequestMask = Shake (request data IV), ResponseMask = Shake (response data IV).
            • X: Reserved
          • Redundancy P: Random value added before checksum value;
          • Encryption Method: Specify the encryption method for the data part, and the optional values are:
            • 0x00: AES-128-CFB;
            • 0x01: No encryption;
            • 0x02: AES-128-GCM;
            • 0x03: ChaCha20-Poly1305;
          • Instruction Cmd:
            • 0x01: TCP data;
            • 0x02: UDP data;
          • Port Port: Integer port number in Big Endian format;
          • Address Type T:
            • 0x01: IPv4
            • 0x02: Domain name
            • 0x03: IPv6
          • Address A:
            • When T = 0x01, A is a 4-byte IPv4 address;
            • When T = 0x02, A is a 1-byte length (L) + L-byte domain name;
            • When T = 0x03, A is a 16-byte IPv6 address;
          • Check F: FNV1a hash of all content in the instruction except F.

          Data Section

          When Opt(S) is enabled, this format is used for the data section. The actual request data is divided into several small chunks, and each chunk has the following format. After the server verifies all the small chunks, it will be forwarded in the basic format.

          2 BytesL Bytes
          Length LData Packet

          in which:

          • Length L: A big-endian integer with a maximum value of 2^14.
            • When Opt(M) is enabled, the value of L is equal to the true value xor Mask. Mask = (RequestMask.NextByte() << 8) + RequestMask.NextByte();
          • Packet: A data packet encrypted by the specified encryption method.

          Before the transmission is completed, the data packet must contain actual data, in addition to the length and authentication data. When the transmission is complete, the client must send an empty data packet, that is, L = 0 (unencrypted) or the length of the authentication data (encrypted), to indicate the end of the transmission.

          The packets are formatted as follows, depending on the encryption method:

          • Unencrypted:   - L bytes: actual data;
          • AES-128-CFB: The entire data section is encrypted using AES-128-CFB.   - 4 bytes: FNV1a hash of actual data;   - L - 4 bytes: actual data;
          • AES-128-GCM: Key is the Key of the instruction section, IV = count (2 bytes) + IV (10 bytes). count starts at 0 and increases by 1 for each packet; IV is the 3rd to 12th byte of the instruction section IV.   - L - 16 bytes: actual data;   - 16 bytes: GCM authentication information
          • ChaCha20-Poly1305: Key = MD5 (instruction part Key) + MD5 (MD5 (instruction part Key)), IV = count (2 bytes) + IV (10 bytes). count starts at 0 and increases by 1 for each packet; IV is the 3rd to 12th byte of the instruction section IV.   - L - 16 bytes: actual data;   - 16 bytes: Poly1305 authentication information

          Server Response

          The header data is encrypted using AES-128-CFB encryption. The IV is MD5 of the data encryption IV, and the Key is MD5 of the data encryption Key. The actual response data varies depending on the encryption settings.

          1 Byte1 Byte1 Byte1 ByteM BytesRemaining Part
          Response Authentication VOption OptCommand CmdCommand Length MCommand ContentActual Response Data

          in which:

          • Response Authentication V: must match the response authentication V in the client request.
          • Option Opt:
            • 0x01: server prepares to reuse TCP connections (deprecated in Xray 2.23+).
          • Command Cmd:
            • 0x01: dynamic port command.
          • Actual response data:
            • If Opt(S) in the request is enabled, the standard format is used. Otherwise, the basic format is used.
            • Both formats are identical to the request data.
              • When Opt(M) is enabled, the value of length L is equal to the true value XOR Mask. Mask = (ResponseMask.NextByte() << 8) + ResponseMask.NextByte().

          Dynamic Port Instructions

          1 Byte2 Bytes16 Bytes2 Bytes1 Byte1 Byte
          ReservedPortUser IDAlterIDUser levelValidity period T

          in which:

          • Port: Integer port number in Big Endian format
          • T: Number of minutes as integer value.

          When the client receives a dynamic port command, the server opens a new port for communication. The client can then send data to the new port. After T minutes, the port will expire, and the client must use the main port to communicate again.

          Comment

          • To ensure forward compatibility, the values of all reserved fields must be 0.
          - + diff --git a/en/document/command.html b/en/document/command.html index 24f8a020f4..487acc5284 100644 --- a/en/document/command.html +++ b/en/document/command.html @@ -24,8 +24,8 @@ Command Parameters | Project X - - + +

          Command Parameters

          Tip

          Xray uses Go-style commands and parameters

          Get Basic Commands

          You can run xray helpto get the most basic usage of all xray, as well as available commands and instructions.

          Xray is a platform for building proxies.
          @@ -115,6 +115,6 @@
           

          xray x25519

          Generate x25519 key pair。

          Usage:

          xray x25519 [-i "(base64.RawURLEncoding)" --std-encoding]
           

          xray wg

          Generate wireguard curve25519 key pair。

          Usage:

          xray wg [-i "(base64.StdEncoding)"]
           

          Tip

          When -config is not specified, Xray will try to load config.json from the following paths:

          - + diff --git a/en/document/config.html b/en/document/config.html index 2d2d224556..1742b3be2d 100644 --- a/en/document/config.html +++ b/en/document/config.html @@ -24,8 +24,8 @@ Configure and Run | Project X - - + +

          Warning

          This translation was modified on 14 May 2023 and an updated version (26 December 2023) is available on the source page. View the original page

          Configure and Run

          After downloading and installing Xray, you need to configure it.

          For demonstration purposes, only a simple configuration method is introduced here. For more templates, please refer to Xray-examplesopen in new tag.

          If you need to set up more advanced features, please refer to the relevant instructions in the more detailed configuration file.

          Server Configuration

          You need a server outside the firewall to run server-side Xray. The configuration is as follows:

          {
          @@ -93,6 +93,6 @@
             }
           }
           

          The only thing you need to modify in the above configuration is your server's IP address, which is indicated in the configuration. This configuration will redirect all traffic to your server, except for traffic on the local area network (such as the access router).

          Run

          • On Windows and macOS, the configuration files are usually named config.json.
            • To start Xray, simply run Xray or Xray.exe.
          • On Linux, the configuration files are usually located in /etc/xray/ or /usr/local/etc/xray/.
            • To start Xray, run the command xray run -c /etc/xray/config.json.
            • Alternatively, you can use a tool like systemd to run Xray as a background service.

          For more detailed instructions, please refer to the Configuration Document and Layman's Terms.

          - + diff --git a/en/document/document.html b/en/document/document.html index 8f036b4b66..e5c86a67f7 100644 --- a/en/document/document.html +++ b/en/document/document.html @@ -24,14 +24,14 @@ Contribute to Project X's Document | Project X - - + +

          Warning

          This translation was modified on 4 March 2023 and an updated version (13 February 2024) is available on the source page. View the original page

          Contribute to Project X's Document

          Contributions to Project X's Document are welcome, and we appreciate every Contributor's contribution! You guys make Xray stronger!

          Improve Document

          Document for Project X is hosted on GitHubopen in new tag.

          You can submit your changes to the Document by following these steps:

          1. Open the repository from Project X Documentopen in new tag, click fork in the upper right corner, fork a mirror image of the document repository to your own GitHub repository.

          2. Get a clone of the docs from the repository you cloned using whatever tool you like, like:

          git clone https://github.com/XTLS/Xray-docs-next.git
           
          1. Create a new branch based on the main branch, such as:
          git checkout -b your-branch
           
          1. Make changes on the new branch.

          2. After modification, please use Prettieropen in new tagFormat your changes.

            Note: Pull requests with formatting issues may be rejected.

          3. Submit the changes and push them to your repository

          git push -u origin your-branch
           
          1. Open GitHub, click 'Pull request' to submit a pull request to Project X Documentopen in new tag.

          2. Please outline the new/modified content of this pull request in the title and body of the pull request;

          3. Waiting for a response, if the pull request is merged, your changes will be directly displayed on Project X Document Websiteopen in new tag.

          Found Problems?

          If you find an error in the document, you can improve the documentation or submit an issue.

          - + diff --git a/en/document/index.html b/en/document/index.html index 4d482afdff..f12b737b12 100644 --- a/en/document/index.html +++ b/en/document/index.html @@ -24,11 +24,11 @@ Quick Start | Project X - - + +

          Quick Start

          This chapter will tell you how to get Xray in the easiest way and start using Xray.

          Download and Install

          Xray supports various platforms, and you can get various versions of Xray from various sources and methods.

          Please click How to Download and Install Xray to get Xray.

          Configure and Run

          After downloading and installing Xray, you need to configure it.

          Please click How to Configure and Run Xray to learn the easiest way to configure Xray.

          Command Parameters

          Xray has a variety of commands and parameters available, making it flexible and powerful.

          Please click Command Parameters for Xray to view more commands and parameters usages.

          Improve Documents

          If you're interested, please click Documents to help us improve the documents, or click the Help us improve this page!

          We are very grateful to every Contributor for their contribution! You guys make Project X even stronger!

          Beginner Tutorial

          An easy tutorial for beginner.

          Please click Beginner Tutorial to view it.

          Getting Started Tips

          After you have the basics, you can explore more ways to use them through Getting Started Tips.

          Advanced Documentation

          Tips for advanced user guidance

          Click on Advanced Documentation to view it

          Appreciations

          Thank you very much for your selfless sharing of usage skills and experience, which makes Xray more and more powerful.

          - + diff --git a/en/document/install.html b/en/document/install.html index 765366a4c9..a919b39606 100644 --- a/en/document/install.html +++ b/en/document/install.html @@ -24,11 +24,11 @@ Download and Install | Project X - - + +

          Download and Install

          Platform Support

          • Xray is available on the following platforms:
            • Windows 7 and later (x86 / amd64 / arm32 / arm64);
              • If you need to use these version (1.8.18 and later marked with win7, 1.8.6, 1.8.4) in Windows 7, operating system update KB4474419 is required. For better Internet security, it is recommended to install KB4490628 to acquire later operating system updates from Windows Update.
            • macOS 10.10 Yosemite and later (amd64 / arm64);
            • Linux 2.6.23 and later (x86 / amd64 / arm / arm64 / mips64 / mips / ppc64 / s390x / riscv64);
              • Including but not limited to Debian 7 / 8, Ubuntu 12.04 / 14.04 and subsequent versions, CentOS 7 / 8, Arch Linux, etc.;
            • FreeBSD (x86 / amd64);
            • OpenBSD (x86 / amd64);

          Download Xray

          Precompiled binaries in ZIP format are available at GitHub Releasesopen in new tag found in.

          Download the compressed package of the corresponding platform, and use it after decompression.

          Verify the Installation Package

          Xray provides two verification methods:

          • SHA1/SHA256 digest of the ZIP archive
          • Reproducible build: Please refer to Compile Xray

          Install on Windows

          Install on macOS

          Install on Linux

          Install Script

          Arch Linux

          Arch User Repository

          Need to use AUR helpersopen in new tag, yayopen in new tag as an example, it can be installed via yay -S xray.

          Arch Linux CN

          First add Arch Linux CNopen in new tag repository, and then use the root user pacman -S xrayto install.

          Linuxbrew

          The Linuxbrew package manager is used in the same way as Homebrew: brew install xray

          Debian WIP

          Install via Docker

          The File Structure of the Docker Image

          • /etc/xray/config.json: configuration file
          • /usr/bin/xray: Xray main program
          • /usr/local/share/xray/geoip.dat: IP data file
          • /usr/local/share/xray/geosite.dat: domain name data file

          GUI Client

          UUID Generator

          Third-party UUID generator uuidgenerator.netopen in new tag

          - + diff --git a/en/document/level-0/ch01-preface.html b/en/document/level-0/ch01-preface.html index b241361f1a..788d8c751d 100644 --- a/en/document/level-0/ch01-preface.html +++ b/en/document/level-0/ch01-preface.html @@ -24,11 +24,11 @@ [Chapter 1] Simple and Plain Language | Project X - - + +

          [Chapter 1] Simple and Plain Language

          1.1 Who is this document written for?

          One sentence: Written for newbies who are (1) absolute beginners and (2) interested in learning how to build their own VPS.

          1.2 Who is this document not written for?

          Including but not limited to: experts and professionals, beginners who are too lazy to tinker on their own, advanced users who already know how to tinker, wealthy users who insist on using airport services, and those who prefer using one-click scripts. In short, if you have a technical background or don't want to build it yourself, you can close this article directly, because this article may not be suitable for you and may even make you upset.

          1.3 Declaration and Other Statements

          Declaration:

          My technical skills are extremely limited, so this article is inevitably full of errors and flaws. If you find any problems, please kindly point them out and don't be too harsh on me.

          Disclaimer:

          Please judge the reliability and usability of the content of this article by yourself. If you encounter any problems or negative results when establishing and using a VPS server based on the content of this article, I am not responsible for it.

          Verbose statement:

          Considering the target audience of this article, which is "users with zero experience", many details will be explained in great detail, so the language may be verbose. Please be mentally prepared for this.

          1.4 Why is self-hosting a challenge?

          To answer this question, we need to provide a little more background information.

          1. On the matter of accessing the internet through scientific means

          The act of accessing the internet using scientific methods has been around for almost 20 years (shocking!!!.jpg). Initially, one could do it with a little effort (changing the host file, using SSH), then one had to find a web proxy, and later, one had to develop a private protocol (such as Shadowsocks) and so on.

          With the continuous iteration and upgrade of GFW technology over the past decade, to achieve the goal of [building your own scientific Internet access], the things that need to be done include but are not limited to:

          • Understand basic Linux commands
          • Understand network transmission protocols
          • Have the technical and financial ability to purchase and manage a VPS
          • Have the technical and financial ability to purchase and manage a domain name
          • Have the technical ability to apply for a TLS certificate, and so on.

          This has turned the once simple act of [setting up a self-built VPS for accessing the internet in a secure and unrestricted manner] into a daunting challenge that intimidates newcomers.

          1. Helplessness of Zero-based Users

          For non-technical users with zero foundation, if they complete the above series of operations, they will inevitably need to learn a lot of knowledge. However, after a little searching, newbies are likely to become even more confused: a large amount of information is scattered in various corners of the Internet: blogs, Q&A sites, groups, forums, GitHub, Telegram, YouTube, and so on. These pieces of information are chaotic and complex, with varying levels of quality, and may even contradict each other. Basically, they won't stop until they completely confuse the newcomer.

          Faced with such chaotic information, newcomers suddenly shift from [information scarcity] to [information overload]. If they fail after several attempts of groping and guessing (which is highly probable), their enthusiasm is bound to be greatly frustrated. In this process, if they happen to seek help in some unfriendly places, they may be ridiculed even more: "You're so inexperienced, just use the airport, why bother messing around!" "Go learn Linux first before coming back to ask."

          At this moment, probably only an "hehe" can express the mood.

          1.5 "Why not just use the airport?"

          First of all, I would like to respond to those who ridicule and criticize by asking a question: Is using the airport really a panacea?

          Secondly, I believe that there is a fundamental difference between "not understanding" and "not wanting to understand". The bad attitude of some people who just want handouts is naturally annoying, but those who sincerely want to learn but don't know how should not be subject to unjustified contempt and discrimination. It is precisely this kind of bad community atmosphere that does not distinguish between newcomers that prompted me to write this article. So without further ado, let's take a look at the advantages and disadvantages of the airport:

          1. 稳定性高:机场节点数量多,分布广泛,避免了单点故障的风险,保证了整个网络的稳定性。
          2. 速度快:机场的节点通常采用高速服务器和优化的网络架构,网络速度较快,能够满足用户的高速上网需求。
          3. 安全性高:机场通常会采用严格的安全措施,如流量加密、防火墙等,保护用户数据的安全性。
          4. 稳定性高:机场通常采用专业的运维团队进行管理和维护,保证了服务的稳定性和可靠性。
          5. 服务质量高:机场通常会提供完善的客户服务,及时解决用户的问题和反馈,提升用户的满意度。

          The so-called "airport" refers to the "line provider". They are responsible for completing the technical operations and management mentioned in section 1.4, while users pay for the right to use the service. Therefore, its advantages include at least:

          1. Simple User Operation: Scan code operation, one-click rule addition, etc.
          2. Multiple Line Options: Can unlock network services in different countries and regions, such as iplc dedicated line services, game acceleration services, etc.
          3. Multiple Access Nodes: Therefore, it has a stronger ability to resist node blocking, if one is blocked, just switch to another one.
          • Risks of "Airport"

          "The other side of the coin of 'convenience' is 'risk'. Based on the technical characteristics and market conditions of the 'airport', its risks include at least:"

          1. "Airport" can fully obtain user information: All the traces left by users online will inevitably and very likely be stored on their servers for a long time. These records cannot be restricted by any legally binding user privacy agreement. ("Snooping and recording your every move")
          2. "Airport" lacks market management: There are inevitably malicious merchants who target fraud. ("Actively run away")
          3. "Airport" faces regulatory pressure: While large airports are relatively secure, they cannot avoid attracting attention. In 2020, several large airports experienced shutdowns and runaways, seriously disrupting users' normal usage. ("Passively run away")
          4. "Airport" technical level is difficult to determine: The quality of the line varies greatly, and the phenomenon of falsely advertising quality services is common. ("Slow speed, frequent disconnections, unable to connect")

          1.6 So should you build your own website?

          Now that you have seen the advantages and risks of the airport, please think carefully and make your own decision on what to use. After all, the best plan is the one that suits you best.

          It's Your Choice!

          1. If you decide to use the airport, you can close this article now.

          2. If you decide to build it yourself, please continue reading the following chapters!

          In short, the goal of this article is to serve as a starting point for users with zero experience, providing thorough explanations and demonstrations for each step, even if it may seem overly detailed or repetitive. The aim is to assist beginners in completing the entire process of deploying a VPS server from the first command input to successfully accessing the internet via the client, and gradually introducing them to basic Linux operations, laying a foundation for further self-learning.

          1.7 Some digressions

          1. There is a wealth of information outside of the wall, so please learn to think rationally and independently. Don't take sides easily and don't believe in sensational information.

          2. We sincerely hope that with a smoother internet, everyone can access fresher knowledge, richer entertainment, experience a better world, and make more like-minded friends, but do not become a scapegoat for anyone with ulterior motives.

          3. Your internet identity is still your identity, and achieving absolute anonymity is extremely difficult. Therefore, please be sure to comply with the relevant laws and regulations in your personal location and the location of your IP address. Self-protection is always the most basic bottom line.

          1.8 Your Progress

          ⬛⬜⬜⬜⬜⬜⬜⬜ 12.5%

          - + diff --git a/en/document/level-0/ch02-preparation.html b/en/document/level-0/ch02-preparation.html index 450d3d3178..1c42c5676f 100644 --- a/en/document/level-0/ch02-preparation.html +++ b/en/document/level-0/ch02-preparation.html @@ -24,11 +24,11 @@ [Chapter 2] Preparation of Raw Materials | Project X - - + +

          [Chapter 2] Preparation of Raw Materials

          This chapter is rather special because it involves monetary transactions. This article takes a neutral stance on the project and does not make specific recommendations. What I can do is to tell you what you need to prepare.

          2.1 Acquiring a VPS

          You need to obtain a healthy VPS with an unblocked IP, and perform the following basic preparations in the management console:

          1. Install Debian 10 64-bit system in the backend of VPS.
          2. Write down the IP address of VPS in a notebook (this article will use "100.200.300.400" as an example, which is an intentionally incorrect and illegal IP address. Please replace it with your real IP address).
          3. Write down the SSH remote login port of VPS in a notebook.
          4. Write down the username and password for SSH remote login in a notebook.

          Buying a VPS is a relatively complex matter. It is recommended to first learn the relevant knowledge and choose one that suits your own economic ability and line requirements. In addition, you can choose to take advantage of some benefits offered by international giants (such as permanent free or limited-time free packages offered by Oracle and Google). In any case, you must act within your means.

          Explanation

          Regarding the choice of Debian 10 as the operating system, let me elaborate a bit: No matter what you have heard online, no matter which guru has told you that XXX version of Linux is better or XXX version of Linux is more powerful, these sectarian disputes have nothing to do with you right now! Using Debian 10 is enough to optimize your VPS server for security, stability, and performance (such as using cloud-optimized kernel, timely support of BBR, etc.). After you become familiar with Linux, you can try other Linux distributions.

          2.2 Obtaining a Desired Domain Name

          You need to obtain a domain name and add an A record in the DNS settings, pointing to the IP address of your VPS.

          1. Please choose a reliable international domain name service provider. Choose some common domain name suffixes, and make sure not to use the .cn suffix.
          2. In the DNS settings, add an A record pointing to the IP address of your VPS (the name of the A record can be anything, and in this article, it will be represented by "a-name"). The complete domain name will be represented by "subdomain.yourdomain.com" or "a-name.yourdomain.com". The effect is as shown in the picture below:

          Add A Record

          Tip

          This is not a real usable website. Please replace it with your real website URL.

          2.3 Software you need to install on your local computer

          1. SSH remote login tool
          1. Remote file copying tool
          1. Reliable text editor

          2.4 Your Progress

          If you have all the raw materials ready as mentioned above, you have already obtained the key to unlocking the door to a new world. So, what are you waiting for? Let's quickly move on to the next chapter and step through this door!

          ⬛⬛⬜⬜⬜⬜⬜⬜ 25%

          - + diff --git a/en/document/level-0/ch03-ssh.html b/en/document/level-0/ch03-ssh.html index edcc3be6d4..abed3071f5 100644 --- a/en/document/level-0/ch03-ssh.html +++ b/en/document/level-0/ch03-ssh.html @@ -24,13 +24,13 @@ [Chapter 3] Remote Login | Project X - - + +

          [Chapter 3] Remote Login

          3.1 Remote Login to VPS (PuTTY)

          First of all, considering that the user base of Windows is the largest among the zero-based population, this article uses Windows as an example for demonstration.

          Secondly, although PowerShell and WSL after Windows 10 can also achieve a good SSH operation experience, not all versions of Windows have the latest components. Therefore, this article uses the classic PuTTY as an example to provide a detailed explanation of SSH remote login operation. (If you use other tools, the operations after the SSH login are the same.)

          Follow me step by step and let's start the operation.

          1. Go to the official websiteopen in new tag of PuTTY and download the version that suits your operating system (this article uses the 64-bit version as an example).

          Download PuTTY

          1. After installation and running, you will see the main interface of PuTTY. Now please take out your notebook from the previous chapter where you wrote down the IP address (VPS IP) and port (VPS PORT) of your VPS in the corresponding positions of the following figure. In order to save time and avoid repeatedly entering these details in the future, we can save the session (Saved Sessions), and simply load it in the future with one click.

          PuTTY Settings

          1. I suggest setting keepalive to 60 seconds in the Connection to prevent SSH from automatically disconnecting after a period of inactivity. Be sure to save the settings again.

          Prevent frequent disconnection

          Attention

          Any update to the PuTTY configuration needs to be manually saved to the session again. Otherwise, it will be lost after closing.

          1. Click on Open to enter the SSH connection window, then enter the username and password corresponding to the following figure to establish a connection with your VPS remote host. (This article assumes that the default username is root. Also, when entering a password in the Linux system, there will be no prompt like ******, which can avoid password length leakage. It's not that your keyboard is broken!)

          SSH Remote Login

          3.2 Successfully Logging in SSH! Introduction to Command Line Interface!

          1. If you have filled in your information correctly, you will see a similar interface as the picture below, indicating that you have successfully logged in:

          Logging in to VPS for the first time

          This interface is equivalent to the "desktop" of a remote server, but it does not have familiar icons and a mouse, nor does it have colorful graphics. Instead, all you see is simple text. This is the "Command Line Interface" - shortened as CLI.

          All the following operations require you to act like a hacker in a movie and complete them in this command-line interface. Maybe you will feel unfamiliar, but please believe me, using the command-line interface is neither scary nor mysterious. In the end, it just turns your familiar mouse operations into textual commands, you say it, it does it.

          1. Now, you can observe and familiarize yourself with the command line environment a little bit. This interface has actually provided you with some useful information, such as the system kernel version (e.g. 4.19.37-5 in the picture), last login time and IP address. Of course, depending on the VPS, the interface you see may be slightly different.

          2. Please pay attention to the line at the bottom of the command line, to the left of the flashing cursor, there is a string of characters. The one shown in the figure is root@vps-server:~#. How to understand this string? It's very simple:

          • The current user is root
          • The server where root is located is vps-server
          • The current directory where root is located is ~
          • After # is the place where you can input commands.

          The first two are pretty straightforward, no need to explain further. The third one is about the folder system in Linux. You don't need to go too deep into it for now. Just know that "~" represents the home directory of the current user. As for the fourth one, the prompt symbol "#", you don't need to worry about it either. Just know that in future articles, there will be some commands that you need to input, and they will be preceded by "#" or "$" to indicate where you should input the command. (So when you copy the command, just copy the content after the prompt symbol and don't copy the prompt symbol itself.)

          3.3 Updating software on Linux for the first time!

          1. Just like your phone, whether it's Android or iPhone, in order to keep your apps up-to-date (to get security patches and new features), you will occasionally receive update notifications from the app store, telling you how many apps need to be updated. Linux systems also have a similar update mechanism that works logically. So as long as you know how to update phone apps, you can learn how to update Linux software!

          2. In Linux, each application is called a "package". The program that manages the applications is naturally called a "package manager". You can use it to install, update, and uninstall various software, and even update the Linux system itself. Package managers in Linux are very powerful, but we won't go into details here. For now, you only need to know that the package manager for the Debian system is called apt. Next, we will first use apt to do a comprehensive update of the software to familiarize you with its basic operations.

          3. Tiny White Linux Basic Commands:

          NumberCommand NameCommand Description
          cmd-01apt updateQuery software updates
          cmd-02apt upgradePerform software updates
          1. Now, please enter the first command to get update information.
          apt update
           

          This is a command used in a Linux terminal to update the package list from the repositories configured on the system.

          1. Then enter the second command, and when asked if you want to continue installing (Y/n), type y and press enter to confirm and start the installation.
          apt upgrade
           

          This is a command in the shell terminal to upgrade the installed packages on a Debian or Ubuntu Linux system.

          1. The complete demonstration of the process is as follows:

          Demonstration of the software update process for the first time

          3.4 Your Progress

          Congratulations on taking another solid step! Now, you can log in to your remote server via SSH! After logging in, besides upgrading the software, what else should you do? Please enter the next chapter to find out!

          ⬛⬛⬛⬜⬜⬜⬜⬜ 37.5%

          - + diff --git a/en/document/level-0/ch04-security.html b/en/document/level-0/ch04-security.html index 088124bd02..8a128bd172 100644 --- a/en/document/level-0/ch04-security.html +++ b/en/document/level-0/ch04-security.html @@ -24,8 +24,8 @@ [Chapter 4] Security and Protection | Project X - - + +

          [Chapter 4] Security and Protection

          4.1 Why Do We Need Security Protection?

          Security protection for Linux servers is a complex and huge subject. Countless websites, apps, services, and even offline infrastructure are built on the foundation of Linux, which involves huge economic benefits and commercial value. This also means that there is a huge motivation for black and gray industries to launch attacks. However, these services are so important that major security vulnerabilities are not allowed. Therefore, countless operation and maintenance professionals are working hard on the battlefield of security attacks and defense, which enables us to enjoy a basic stable modern digital life.

          Now, you have a VPS and will open its data access channel to achieve the goal of traffic forwarding, which means you are now on the front line of the security battle and face all risks. However, at the same time, newcomers tend to have a polarized view of security issues due to lack of knowledge and information: either they feel it is as light as a feather and has nothing to do with them, or they feel it is as heavy as Mount Tai and feel anxious all day long.

          • For the former, my suggestion is: safety is of utmost importance. Try to gather more information on safety issues to avoid regretting after experiencing losses.

          • For the latter, my suggestion is: don't worry too much, our servers still don't have too much value and generally won't attract high-level attacks. The basic threats we need to face are mostly malicious scans and login attempts from some automated scripts. Just follow this article to do some basic protection.

          4.2 What are the specific risks

          Just like the configuration we did in the "Remote Login" section, anyone who knows the four elements of [IP address] + [port] + [username] + [password] can log in to your VPS server. So obviously, the security of these four elements is the bottom line that we need to protect. Let's analyze them one by one:

          1. [IP Address]: Malicious scripts randomly attempt to scan IP ranges, which can be regarded as public information and cannot be hidden.

          2. [Port]: If you are using the default port, then [Port = 22].

          3. [Username]: If using the default user, then [Username = root]

          4. [Password]: There is no default value for the password. It must be randomly generated by the VPS backend or set by you. In other words, if all the settings of your server are default, then three of the four elements are already known. Therefore, the security of your entire server relies on a small password. In this case, there are several situations:

          • If you use a VPS management background to generate passwords randomly, it usually contains random uppercase and lowercase letters, symbols, and is relatively secure.

          • If you changed your password to something super weak like 123456 just for the sake of easy memorization, hacking into your VPS server would be a piece of cake.

          • If you change your password to a more complex one that you have used elsewhere just for the sake of easy memory, it is not really safe. You should understand that hackers have cheats in their hands, such as password tables, which contain tens of thousands, hundreds of thousands, millions, or even more real leaked passwords.

          1. But you should understand that no hacker really sits in front of a computer and tries your password repeatedly. All attack attempts are carried out automatically by malicious scripts, which work tirelessly for 24 hours. Perhaps while you are sleeping soundly every night, your server is enduring round after round of attacks.

          Once the password is successfully cracked, it means that all four of your elements have been mastered by the attacker. The malicious script will quickly log in to the server, obtain the highest root control of the server, install and deploy its malicious services, and then use your server to do all kinds of bad things 24 hours a day (such as mining, spreading viruses, sending spam emails, fraudulent emails, acting as a BT relay, and even dark web public nodes, and so on). If the malicious script is relatively restrained, it can actually achieve considerable concealment. Generally, newcomers will not observe and pay attention to indicators such as login records, process changes, CPU usage changes, and traffic changes of the VPS, so it is difficult for you to discover that you have been hacked. Until your VPS service provider blocks your account or you receive a lawyer's letter.

          1. Don't forget that when you obtain a VPS, you probably need to use your real payment information, and when you log in to various websites and social platforms, your IP address will also be recorded, which has a direct or indirect relationship with your identity. Therefore, once these bad things happen, they will inevitably be associated with you.

          4.3 What security measures do we need to take

          Based on the above analysis, what we need to do is to strengthen the three elements of [port], [username], and [password] to reduce the risk of being hacked.

          1. [Port]: Modify the SSH remote login port to a [non-22 port] (4.4).
          2. [Username]: Create a [non-root] new user and disable root user SSH remote login (4.5, 4.6).
          3. [Password]: Enable RSA key verification for SSH login and disable password verification login (4.7).

          Remember to follow the order and don't lock yourself out.

          4.4 Change the SSH Remote Login Port to a Non-22 Port

          Now, let's solve the problem of "port = 22". (Note: some VPS service providers have non-22 ports set as default, so you can ignore this step if that's the case. Of course, you can also follow this article to change it to another port.)

          1. Basic commands of Little White Linux:
          IDCommand NameDescription
          cmd-03nanoText editor
          cmd-04systemctl restartRestart a service
          1. Basic Configuration Files of Little White Linux
          NumberConfiguration File LocationFile Description
          conf-01/etc/ssh/sshd_configSSH Remote Login Program Settings
          1. The first thing we need to do, of course, is to [open the SSH remote login program settings with the text editor nano]. In Windows, you will [find the file and double-click] it. What should you do in Linux? Take a close look at the command instructions above, isn't it simple? Yes, it is:
          nano /etc/ssh/sshd_config
          @@ -40,6 +40,6 @@
           

          This is a command in shell script to change the permissions of the authorized_keys file to 600 for the current user's SSH directory (~/.ssh/).

          1. Modify SSH configuration. We have used this many times, but now that we have changed from the almighty root to the ordinary user vpsadmin, we do not have the permission to edit SSH configuration directly. At this time, we need to use the sudo command:
          sudo nano /etc/ssh/sshd_config
           

          (This is a command in the shell/terminal to open the sshd_config file located in the /etc/ssh/ directory with the sudo privilege using the nano text editor.)

          1. Find (ctrl+w) PasswordAuthentication and change it to no.

          2. Find (ctrl+w) PubkeyAuthentication, change it to yes, then save (ctrl+o) and exit (ctrl+x).

          3. Restart the SSH service. (Note: Don't forget to use sudo to gain permission.)

          sudo systemctl restart ssh
           

          This is a command in the shell terminal to restart the SSH service with root privileges using the systemctl command.

          1. The complete process is as follows:

          Enable SSH key verification and disable password verification

          1. The public key has been set up on the VPS end. Now we need to specify the private key location for PuTTY to use when logging in. (Reminder: Don't forget to save the session.)

          Specify private key location in PuTTY

          1. Now, the [Key-based login] has been successfully enabled, [Password authentication] has been successfully disabled, and the default login username and private key have been saved for PuTTY. In the future, when using PuTTY to log in, simply load the VPS-SERVER configuration, click Open, and you can log in with just one click.

          If you have set a password for your private key, you need to enter this password to use the key when logging in, as shown in the following figure:

          Enter Private Key Password

          1. Don't forget to set the corresponding key for WinSCP, otherwise you won't be able to log in when you want to transfer files later.

          WinSCP Specify Private Key Location

          Warning

          Any software that requires SSH login needs key verification. As there are too many software, it is impossible to show them one by one. Please set it up according to your needs.

          4.8 Your Progress

          Up to this point, your VPS has completed the basic security measures of [port], [username], and [password]. Although it is not completely impregnable, most malicious scripts should no longer be able to harm you.

          Now that we finally have a secure system foundation, in the next chapter, we can start step by step to install and configure the infrastructure that Xray needs! (What infrastructure? A web page, a certificate)

          ⬛⬛⬛⬛⬜⬜⬜⬜ 50%

          - + diff --git a/en/document/level-0/ch05-webpage.html b/en/document/level-0/ch05-webpage.html index f51a90bd99..613a9cab81 100644 --- a/en/document/level-0/ch05-webpage.html +++ b/en/document/level-0/ch05-webpage.html @@ -24,8 +24,8 @@ Chapter 5: Website Building | Project X - - + +

          Warning

          This translation was modified on 19 May 2023 and an updated version (17 March 2024) is available on the source page. View the original page

          Chapter 5: Website Building

          5.1 Why should you create a website?

          Some newcomers may be confused: why do I need to build a website for securing an open digital environment? I don't know how to code! Isn't it very complicated?

          First, let's answer the first question. The reasons for building a website are:

          1. Apply for a legitimate TLS certificate (very important)
          2. Provide reasonable fallback to prevent active probing attacks and improve security
          3. Set up a camouflage site (such as a blog, private cloud storage, multimedia site, game site, etc.) with a reasonable frontend when directly accessed, making traffic usage look more legitimate.

          Now let's answer the second question:

          1. As a demonstration, this article uses only the simplest "single-file HTML page + Nginx" setup to achieve the above objectives, so it is very easy.
          2. This website can not only be used for camouflage but also for real development and growth. The complexity depends entirely on you.
          3. For the goals of "camouflage" and "website operation", uniqueness and personalization are needed. Students who need this can search and learn by themselves. This content has completely deviated from scientific online access, so this article will not go into depth.

          5.2 Log in to VPS, install and run Nginx

          1. Here we use commands that have been explained in detail before, so they won't be repeated. If you don't understand, please refer to the previous chapters.

            sudo apt update && sudo apt install nginx
            @@ -75,6 +75,6 @@
                     }
             

            Be extra careful!

            As mentioned in Step 3 of section 5.3, make sure to change /home/vpsadmin/www/webpage to your actual file path.

          2. Make nginx reload the configuration to take effect.

            sudo systemctl reload nginx
             
          3. The complete setup process is as follows:

            Web page settings demonstration

          4. Now, if you visit http://subdomain.your_domain.com, you should see this page, indicating success:

            http web page success

        5.4 Common error explanations

        First of all, if you follow the instructions in the article step by step and are careful enough, you will definitely not encounter any errors. So, I don't intend to change how this article is written.

        Then why do some students still get stuck at this step, and the web page just won't open? There are basically two words: carelessness. Because there are only two possible issues with the configuration here, and there are only two reasons for them.

        I. Two types of issues:

        • In nginx.conf, the /home/vpsadmin/www/webpage does not match the actual file path; nginx cannot find the file
        • The path is correct, but nginx doesn't have permission to access it

        II. Two reasons:

        • Use a non-root user but still directly copy the commands in the text without modification. (This is basically like copying the name of another student when copying answers)
        • Insist on using a root user

        If you encounter any errors, please carefully review the explanations in Steps 3 and 5-2 of Section 5.3.

        Warning

        In the early stages of this article, a lot of space has been devoted to explaining the importance of using a non-root user for security, and the entire article is written based on this premise. So, issues caused by using a root user are not within the scope of this article.

        But I believe that students who persist in using the root user should have their own opinions, strong hands-on ability, or have a certain foundation in Linux. I have already explained the crux of the problem, and I believe you can solve it on your own.

        5.5 Your Progress

        So far, Xray's first infrastructure [webpage] has been established. Let's now move on to the second infrastructure [certificate]!

        ⬛⬛⬛⬛⬛⬜⬜⬜ 62.5%

    - + diff --git a/en/document/level-0/ch06-certificates.html b/en/document/level-0/ch06-certificates.html index 29e76a475a..2f50c8a332 100644 --- a/en/document/level-0/ch06-certificates.html +++ b/en/document/level-0/ch06-certificates.html @@ -24,8 +24,8 @@ [Chapter 6] Certificate Management | Project X - - + +

    [Chapter 6] Certificate Management

    6.1 Applying for a TLS Certificate

    Next, we need to apply for a real TLS certificate for our domain name, so that the website has the ability to encrypt with standard TLS and the ability to access via HTTPS. This is the most important tool for Xray and other current security proxy tools to ensure fully encrypted traffic.

    Warning

    Please do not use self-signed certificates lightly. It does not make the operation much simpler, but adds unnecessary risks (such as man-in-the-middle attacks).

    Here, I will use a certificate management tool called acme.shopen in new tag, which is simple, lightweight, efficient, and capable of automatically updating certificates.

    In addition, I believe that you have gradually become familiar with the basic operations of Linux. Therefore, from this chapter on, commands that have appeared multiple times will no longer have screenshots and will only be briefly described. If you really can't remember how to use them, just review the previous chapters.

    6.2 Install acme.sh

    1. Basic Linux commands for beginners:

      NumberCommandDescription
      cmd-12wgetRetrieve (or download) a webpage file
      cmd-13acme.shCommands related to acme.sh certificate management
    2. Run the installation script.

    wget -O - https://get.acme.sh | sh
    @@ -139,6 +139,6 @@
     [Mon 14 Feb 2022 03:00:25 PM CST] Installing key to: /etc/xray/cert/cert.key
     [Mon 14 Feb 2022 03:00:25 PM CST] Installing full chain to: /etc/xray/cert/fullchain.crt
     

    (Note: This is a shell command for installing a SSL certificate using acme.sh. The command is specifying the domain, file paths for the certificate, private key, and full chain, as well as indicating that an ECC certificate should be used.)

    6.6 Your Progress

    At this point, the two basic infrastructures required by Xray are finally in place! Xray, which has been eagerly awaited, is about to be revealed, and we are finally about to enter the most exciting chapter!

    ⬛⬛⬛⬛⬛⬛⬜⬜ 75%

    - + diff --git a/en/document/level-0/ch07-xray-server.html b/en/document/level-0/ch07-xray-server.html index 38297afba5..9433f45766 100644 --- a/en/document/level-0/ch07-xray-server.html +++ b/en/document/level-0/ch07-xray-server.html @@ -24,8 +24,8 @@ [Chapter 7]Xray Server | Project X - - + +

    [Chapter 7]Xray Server

    7.1 Study broadly, Act decisively.

    During the writing of this article, the boss joked: Your tutorial has been serialized for 6 chapters and has not yet reached Xray. People who don’t know would think that you are a "hand-in-hand teaching you to build a website" tutorial. (I can't refute it.jpg!)

    In fact, this structure is my decision after much thinking. After all, only by laying a solid foundation can you quickly surpass others with half the effort. I saw many newcomers in the group who can't even use nano correctly, nor can they use WinSCP. The config.json edited by remote handwriting is naturally full of errors, and even error checking becomes difficult.

    Warning

    After the preparation of the first 6 chapters, you have already climbed over several mountains with me, such as basic Linux operations, VPS remote management, web page construction, domain name management, certificate application, etc. Do you think it is actually very simple when you look back? Now that we have such solid preparations, we will have a light feeling of [smooth success] when installing and configuring Xray.

    The things to do next are very simple:

    1. Installation
    2. Configuration (such as installing TLS certificates, config.json)
    3. Run
    4. Optimization (such as updating the kernel, enabling bbr, automatically redirecting http visits to https, etc.)

    7.2 Install Xray

    First of all, the official carrier of Xray is the binary program generated by the open source project xray-coreopen in new tag (Open sourced with License MPL 2.0 ). If you put this binary on the server and run it, it is the server side; if you download it to the local computer and run it, it is the client side. The main difference comes from [configuration].

    When installing, it is very simple and direct to use the official installation script directly. It provides a variety of installation options. If you are interested, you can go to the official installation script repositoryopen in new tag to see the script instructions. This article uses the [non-root user] installation mode.

    When writing this article, the installation script had some minor bugs when using a non-root account, so I decided to separate these steps and explain the deletion command under Linux.

    1. Basic Linux commands for beginners:

      NumberCommand nameCommand description
      cmd-14rmdelete
    2. Download the installation script:

    wget https://github.com/XTLS/Xray-install/raw/main/install-release.sh
    @@ -176,6 +176,6 @@
     
    1. Modify the fallback settings of Xray, changing the fallback from 80 port to 8080 port. (Find "dest": 80, and change it to "dest": 8080)
    sudo nano /usr/local/etc/xray/config.json
     
    1. Restart the Xray service to complete the configuration
    sudo systemctl restart xray
     
    1. The complete process is demonstrated as follows:

    http automatically jumps to https

    1. When you enter http://a-name.yourdomain.com, it should automatically jump to https

    http automatically jumps to https

    7.9 Server Optimization 3: More Fallbacks

    If you need more fallback functions, please refer to 《Fallbacks (fallbacks) Functional Analysis》

    7.10 Your progress

    Congratulations!! At this point, you already have a server that can access the Internet normally and scientifically, and also have a disguised website that can prevent active detection attacks. Next, just install the appropriate software on your client and you can enjoy a smooth network!

    ⬛⬛⬛⬛⬛⬛⬛⬜ 87.5%

    7.11 Important errata

    1. The folder location of the Xray configuration file config.json in the first version is wrong. If you have already operated according to the previous location, Xray will not start correctly. Therefore, the errata is explained here, please check it yourself, and I am very sorry for the inconvenience!
    • Correct location: /usr/local/etc/xray/config.json
    • Wrong location: /usr/local/etc/config.json

    Affected sections:

    • 7.4 Configure Xray - 3. Use nano to create Xray configuration file
    • 7.8 Server Optimization 2 - 6. Modify Xray fallback settings
    1. In the first version, the content of the Nginx configuration file nginx.conf was modified incorrectly (the webpage folder location was incorrect). If you have already performed the operation according to the previous location, Nginx will not be able to find the correct website. Please check it yourself. Sorry for the inconvenience!
    • Correct folder location: root /home/vpsadmin/www/webpage;
    • Wrong folder location: root /var/www/website/html

    Affected sections:

    • 7.8 Server Optimization 2 - 4. Add a local port listener at the same level as the 80 port to provide web page display
    - + diff --git a/en/document/level-0/ch08-xray-clients.html b/en/document/level-0/ch08-xray-clients.html index 1817df242c..b559ae673d 100644 --- a/en/document/level-0/ch08-xray-clients.html +++ b/en/document/level-0/ch08-xray-clients.html @@ -24,8 +24,8 @@ 【第 8 章】Xray 客户端篇 | Project X - - + +

    【第 8 章】Xray 客户端篇

    8.1 Xray 的工作原理简述

    要正确的配置和使用Xray,就需要正确的理解其工作原理,对于新人,可以先看看下面简化的示意图(省略了许多复杂的设置):

    Xray数据流向

    这其中的关键点是:

    1. APP 要主动或借助转发工具,将数据【流入(inbounds)】Xray 客户端

    2. 流量进入客户端后,会被【客户端路由(routing)】按规则处理后,向不同方向【流出(outbounds)Xray 客户端。比如:

      1. 国内流量直连(direct
      2. 国外流量转发 VPS(proxy
      3. 广告流量屏蔽(block
    3. 向 VPS 转发的国外流量,会跨过防火墙,【流入(inbounds)】 Xray 服务器端

    4. 流量进入服务器端后,与客户端一样,会被【服务器端路由(routing)】按规则处理后,向不同方向【流出(outbounds)】:

      1. 因为已经在防火墙之外,所以流量默认直连,你就可以访问到不存在网站们了(direct
      2. 如果需要在不同的 VPS 之间做链式转发,就可以继续配置转发规则(proxy
      3. 你可以在服务器端继续禁用各种你想禁用的流量,如广告、BT 下载等(block

    注意

    请务必记得,Xray 的路由配置非常灵活,上面的说明只是无限可能性中的一种。

    借助 geosite.datgeoip.dat 这两个文件,可以很灵活的从【域名】和【IP】这两个角度、不留死角的控制流量流出的方向。这比曾经单一笼统的 GFWList 强大很多很多,可以做到非常细致的微调:比如可以指定 Apple 域名直连或转发、指定亚马逊域名代理或转发,百度的域名屏蔽等等。。。)

    现在,《路由 (routing) 功能简析》 已经上线,我建议对路由功能有兴趣的同学,先继续跟着本文完成客户端的基础配置,之后再去这里详细学习。

    8.2 客户端与服务器端正确连接

    现在你已经理解了 Xray 的工作原理,那么接下来的配置,其实就是【告诉你的客户端如何连接 VPS 服务器】。这和你已经很熟悉的、告诉PuTTY如何远程连接服务器是一样的。只不过 Xray 连接时的要素不止是【IP 地址】+【端口】+【用户名】+【密码】这四要素了。

    实际上,Xray的连接要素是由不同的协议决定的。本文在第 7 章的配置文件 config.json 里,我们使用 Xray 下独特而强大的 VLESS 协议 + XTLS 流控。所以看看那个配置文件的内容就能知道,这个协议组合的连接要素有:

    • 服务器【地址】: a-name.yourdomain.com
    • 服务器【端口】: 443
    • 连接的【协议】: vless
    • 连接的【流控】: xtls-rprx-vision (vision 模式适合全平台)
    • 连接的【验证】: uuiduuid-uuid-uuid-uuiduuiduuid
    • 连接的【安全】: "allowInsecure": false

    鉴于新人一般都会使用手机 APP 或者电脑的 GUI 客户端,我就把常用的客户端罗列在下面。每个客户端都有自己独特的配置界面,逐一截图展示并不现实,所以请你务必仔细阅读这些客户端的说明、然后把上述要素填入合适的地方即可。

    注意

    许多工具其实是同时支持 xray-corev2fly-core 的,但默认内置的不一定是哪个,所以别忘记检查一下是否是你想要的那个在工作哦!

    到这一步,你的全套配置就已经可以正常使用啦!

    8.3 附加题 1:在 PC 端手工配置 xray-core

    虽然到上面一步已经可以结束了,但是如果你是个好奇心强、记忆力好的的同学,一定会想起来我在上一章说过,你把xray-core 的二进制文件“放在服务器运行,它就是服务器端;你把它下载到本地电脑运行,它就是客户端。” 那究竟要怎样直接使用 xray-core 做客户端呢?

    为了回答这个问题,我加入了附加题章节,有一点点超纲,有一点点麻烦,但费这个笔墨是因为这个方式有它的优势:

    • 第一时间获得最新版而无需等待 APP 升级适配

    • 灵活自由的路由配置能力(当然 GUI 客户端中 Qv2ray 的高级路由编辑器非常强大,也可以完整实现 xray-core 的路由配置功能)

    • 节约系统资源 (GUI 界面一定会有资源消耗,消耗的多少则取决于客户端的实现)

    它的劣势应该就是【需要手写配置文件】有点麻烦了。但其实,你想想,服务器上你已经成功的写过一次了,现在又有什么区别呢?接下来,还是老样子,我们分解一下步骤:

    1. 首先请从 Xray 官方的 GitHub 仓库 Release 页面open in new tag 获取对应平台的版本,并解压缩到合适的文件夹

    2. 在合适的文件夹建立空白配置文件:config.json (自己常用平台下新建文件大家肯定都会,这就真不用啰嗦了)

    3. 至于什么是“合适的文件夹”?这就取决于具体的平台了~

    4. 填写客户端配置

      • 我就以 8.1 原理说明里展示的基本三类分流(国内流量直连、国际流量转发 VPS、广告流量屏蔽),结合 8.2 的连接要素,写成一个配置文件
      • 请将 uuid 替换成与你服务器一致的 uuid
      • 请将 address 替换成你的真实域名
      • 请将 serverName 替换成你的真实域名
      • 各个配置模块的说明我都已经(很啰嗦的)放在对应的配置点上了
      // REFERENCE:
      @@ -181,6 +181,6 @@
       

    8.4 附加题 2:在 PC 端手工运行 xray-core

    写好了配置文件该,要怎么让 xray-core 运行起来呢?双击好像并没有反应啊?

    首先,你要找到电脑上的【命令行界面】。

    1. Linux 桌面、macOS 系统的同学肯定已经比较熟悉了,搜索 Console 或者 Terminal 就可以
    2. Windows 就可以搜索使用 Cmd 或者 Powershell 等程序(WSL 的同学你坐下,你的 Console 当然也可以)

    其次,我们要做的事情是【让 xray 找到并读取配置文件 config.json,然后运行】,所以:

    1. 在 Windows 下,假设你的 Xray 程序位置是 C:\Xray-windows-64\xray.exe,配置文件位置是C:\Xray-windows-64\config.json,那么正确的启动命令就是:

      C:\Xray-windows-64\xray.exe -c C:\Xray-windows-64\config.json
       

      说明

      这里的 -c 就是指定配置文件路径的参数,告诉 xray 去后面的位置找配置文件

    2. 相似的,在 Linux 和 macOS 下,假设你的 Xray 程序位置是 /usr/local/bin/xray,配置文件位置是/usr/local/etc/xray/config.json,那么正确的启动命令就是

      /usr/local/bin/xray -c /usr/local/etc/xray/config.json
       

      说明

      每个系统都有系统路径变量,所以写 Xray 程序时不一定要写绝对路径。但是写了肯定没错,所以我就如此演示了。

    8.5 附加题 3:在 PC 端开机自动运行 xray-core

    如果你真的尝试了手动运行 xray-core,你一定会发现这个方式还有点小问题:

    1. 每次运行 Xray 都要出现一个黑乎乎的窗口,很丑
    2. 不能开机自动运行,每次都要手工输入,十分不方便

    我可以肯定的告诉你:完全可以解决。但是具体的解决方式,就当作课外作业留给大家吧!(友情提示,文档站的问答区有线索哦)

    8.6 圆满完成!

    我相信,有耐心看到这里的同学,都是兼具好奇心和行动力的学习派!我现在要郑重的恭喜你,因为到了这里,你已经完完整整的【从第一条命令开始,完成了 VPS 服务器部署,并成功的在客户端配置使用 Xray】了!这毫无疑问是一个巨大的胜利!

    我相信,你现在一定对Linux不再恐惧,对Xray不再陌生了吧!

    至此,小小白白话文圆满结束!

    ⬛⬛⬛⬛⬛⬛⬛⬛ 100%

    8.7 TO INFINITY AND BEYOND!

    但现在你看到的,远远不是 Xray 的全貌。

    Xray是一个强大而丰富的网络工具集合,平台化的提供了众多模块,可以像瑞士军刀一样,通过灵活的配置组合解决各种不同的问题。而本文,仅仅蜻蜓点水的用了最简单最直观的配置来做基础演示

    如果你觉得现在已经完全够用了,那就好好的享受它给你带来的信息自由。但如果你的好奇心依然不能停歇,那就去继续挖掘它无限的可能性吧!

    需要更多信息,可以到这里寻找:

    1. xtls.github.ioopen in new tag - 官方文档站
    2. 官方 Telegram 群组open in new tag - 活跃而友善的官方讨论社区

    TO INFINITY AND BEYOND!

    不算后记的后记

    希望我陪你走过的这一段小小的旅程,可以成为你网络生活中的一份小小助力。

    这篇文章里的工具和信息难免会一点点的陈旧过时,但你一定会逐渐成长为大佬。未来的某个时间,若你能偶尔想起这篇教程、想起我写下本文的初衷,那我衷心希望你能够薪火相传、把最新的知识分享给后来人,让这一份小小的助力在社区里坚定的传递下去。

    这是个大雪封山乌云密布的世界,人们孤独的走在各自的路上试图寻找阳光,如果大家偶尔交汇时不能守望相助互相鼓励,那最终剩下的,恐怕只有【千山鸟飞绝 万径人踪灭】的凄凉了吧。

    - + diff --git a/en/document/level-0/ch09-appendix.html b/en/document/level-0/ch09-appendix.html index 1df4f102e3..a0a8fe6f9c 100644 --- a/en/document/level-0/ch09-appendix.html +++ b/en/document/level-0/ch09-appendix.html @@ -24,11 +24,11 @@ 【第 9 章】附录 | Project X - - + +

    【第 9 章】附录

    1. 小小白白 Linux 基础命令索引

    编号命令名称命令说明出现篇章
    cmd-01apt update查询软件更新《远程登录篇》
    cmd-02apt upgrade执行软件更新《远程登录篇》
    cmd-03nano文本编辑器《安全防护篇》
    cmd-04systemctl restart重启某个服务《安全防护篇》
    cmd-05adduser给系统新增用户《安全防护篇》
    cmd-06apt install安装某个软件《安全防护篇》
    cmd-07visudo修改 sudo 权限设置专用编辑器《安全防护篇》
    cmd-08sudoroot权限运行某个命令《安全防护篇》
    cmd-09chmod修改目标文件/文件夹的权限《安全防护篇》
    cmd-10mkdir新建文件夹《网站建设篇》
    cmd-11systemctl reload重新加载某个服务《网站建设篇》
    cmd-12wget访问(或下载)某个网页文件《证书管理篇》
    cmd-13acme.shacme.sh 证书管理相关的命令《证书管理篇》
    cmd-14rm删除命令《Xray 服务器篇》
    cmd-15crontab -e编辑当前用户的定时任务《Xray 服务器篇》
    cmd-16touch建立空白文件《Xray 服务器篇》
    cmd-17systemctlsystemd基本服务管理命令《Xray 服务器篇》
    cmd-18reboot重启 Linux 系统《Xray 服务器篇》

    2. 小小白白 Linux 重要配置文件索引

    编号配置文件位置文件说明出现篇章
    conf-01/etc/ssh/sshd_configSSH 远程登录程序设置《远程登录篇》
    conf-02/etc/nginx/nginx.confNginx 程序设置《网站建设篇》
    conf-03/etc/apt/sources.listapt 软件源列表《Xray 服务器篇》
    conf-04/etc/apt/sources.list.d/vpsadmin.list用户自定义软件源列表列表《Xray 服务器篇》
    conf-05crontab -e当前用户的定时任务《Xray 服务器篇》
    conf-06/etc/sysctl.conf手动设置 kernel 参数《Xray 服务器篇》
    conf-07/etc/sysctl.d/vpsadmin.conf用户自定义 kernel 参数配置文件《Xray 服务器篇》

    3. 小小白白 Xray 重要文件索引

    编号配置文件位置文件说明出现篇章
    xray-01/usr/local/etc/xray/config.jsonXray 程序设置《Xray 服务器篇》
    xray-02/home/vpsadmin/xray_cert/xray.certTLS 证书《Xray 服务器篇》
    xray-03/home/vpsadmin/xray_cert/xray.keyTLS 私钥《Xray 服务器篇》
    xray-04/home/vpsadmin/xray_log/access.logXray 访问日志《Xray 服务器篇》
    xray-05/home/vpsadmin/xray_log/error.logXray 错误日志《Xray 服务器篇》
    - + diff --git a/en/document/level-0/index.html b/en/document/level-0/index.html index 99a5ec50c3..16395de029 100644 --- a/en/document/level-0/index.html +++ b/en/document/level-0/index.html @@ -24,11 +24,11 @@ Plain and Simple Language | Project X - - + +

    Plain and Simple Language

    This chapter is a basic lesson of [Starting from Scratch]. New students, please watch and learn carefully.

    Tip

    Made with ❤️ by @ricuhkaenopen in new tag

    【Chapter 1】 Preface: Rambling - Airport or Self-built? That is the question.

    Chapter 2: Preparation of Raw Materials - Tools must be sharpened before they can be used proficiently.

    Chapter 3: Remote Login - A bridge connecting the north and south, turning a natural obstacle into a thoroughfare.

    【Chapter 4】Security Protection - If you don't pay attention to security, you will shed tears for your loved ones.

    [【Chapter 5】Website Construction] - Show Your Beauty (Link to webpage.md file)

    Chapter 6: Certificate Management - Only those who obtain certificates are considered legitimate.

    Chapter 7: Xray Server - Finally, waited for you.

    Chapter 8: Xray Client - A New Beginning.

    [Chapter 9] Appendix - All the exam points are here.

    - + diff --git a/en/document/level-1/fallbacks-lv1.html b/en/document/level-1/fallbacks-lv1.html index 7b3472d04d..580cee8405 100644 --- a/en/document/level-1/fallbacks-lv1.html +++ b/en/document/level-1/fallbacks-lv1.html @@ -24,8 +24,8 @@ 回落 (fallbacks) 功能简析 | Project X - - + +

    Warning

    This translation was modified on 4 March 2023 and an updated version (8 April 2024) is available on the source page. View the original page

    回落 (fallbacks) 功能简析

    在使用 Xray 的过程中,你一定无数次的听说了【回落】这个功能。本文就稍微说明一下这个功能的逻辑以及使用方式。

    1. 回顾《小小白白话文》中的回落

    如果你用了《小小白白话文》中的Xray 配置,并完成了HTTP 自动跳转 HTTPS 优化,那么你已经有了基于 VLESS 协议的简易回落:

    {
    @@ -200,6 +200,6 @@
       }
     }
     
  5. 至此,我们就能够完整的画出模板的回落路线了:

6. 结语

至此,Xray 的【回落】功能就介绍完了。希望本文能够对你理解 Xray 的强大有所帮助。

7. 附加题

我再无耻的留一个附加题:本文详解的 VLESS-TCP-XTLS-WHATEVERopen in new tag 模板?是否有可以优化的地方?

提示:HTTP 自动跳转 HTTPS

- + diff --git a/en/document/level-1/fallbacks-with-sni.html b/en/document/level-1/fallbacks-with-sni.html index f99b0841f9..d2a62b92c8 100644 --- a/en/document/level-1/fallbacks-with-sni.html +++ b/en/document/level-1/fallbacks-with-sni.html @@ -24,8 +24,8 @@ SNI fallback | Project X - - + +

Implementing camouflage and domain-based routing through SNI fallback function

VLESS is a lightweight protocol that, like Trojan, does not perform complex encryption and obfuscation on traffic. Instead, it is encrypted through the TLS protocol and mixed in with other HTTPS traffic, making it difficult to detect. In order to better disguise itself and respond to active probing, the fallback function appeared with VLESS at the same time. This tutorial will demonstrate how to use the fallback function of VLESS inbound protocol in Xray, combined with Nginx or Caddy, to achieve domain name-based traffic routing while ensuring complete disguise.

Application Scenarios

Due to XTLS, Xray needs to listen on port 443, which means that if there is a website running on the server, it cannot run or needs to run on another port, which is obviously unreasonable. There are three solutions to this problem:

  • Xray monitors other commonly used ports (such as 22, 3389, 8443).

This plan is the simplest, but not perfect enough.

  • Nginx or HAProxy listens on port 443, uses SNI for L4 load balancing, and achieves port multiplexing through reverse proxy.

This plan is relatively complicated and requires some understanding of using Nginx or HAProxy. We will not explain it in too much detail here.

  • Xray listens on port 443, and uses Fallbacks feature to split website traffic based on SNI and fallbacks it to Nginx or Caddy.

This plan has a moderate level of difficulty and is the scheme that this tutorial will demonstrate next.

Introduction to SNI

Server Name Indication (SNI) is an extension protocol of TLS. Friends who are familiar with reverse proxies know that the following configuration is required if you want to proxy traffic to the correct content through a domain name:

proxy_set_header Host hostname;
@@ -211,6 +211,6 @@
     redir https://{host}{uri} permanent
 }
 

Reference

  1. Server Name Indication - Wikipedia, the free encyclopediaopen in new tag
  2. Home · acmesh-official/acme.sh Wikiopen in new tag
  3. HTTP/2 - Wikipedia, the free encyclopediaopen in new tag

Quotation


  1. Proxy Protocol - HAProxy Technologiesopen in new tag ↩︎

  2. Introduction to Proxy Protocol and Nginx Configuration - Jianshuopen in new tag ↩︎

  3. v2fly-github-io/vless.md at master · rprx/v2fly-github-ioopen in new tag ↩︎

- + diff --git a/en/document/level-1/index.html b/en/document/level-1/index.html index 8768419df7..30061d3545 100644 --- a/en/document/level-1/index.html +++ b/en/document/level-1/index.html @@ -24,11 +24,11 @@ Beginner's Tips | Project X - - + +
- + diff --git a/en/document/level-1/routing-lv1-part1.html b/en/document/level-1/routing-lv1-part1.html index 1d18068369..a59ef1c6cf 100644 --- a/en/document/level-1/routing-lv1-part1.html +++ b/en/document/level-1/routing-lv1-part1.html @@ -24,8 +24,8 @@ 路由 (routing) 功能简析(上) | Project X - - + +

路由 (routing) 功能简析(上)

如果说 Xray 的【强大】主要体现在它极致的速度和广泛的兼容性。那么 Xray 的【灵活】,则主要应该归功于它巧妙的【路由】功能。本文就稍微说明一下这个功能的逻辑以及使用方式。

1. 初识【路由】三兄弟

要理解路由,就要理解完整的路由功能需要有三兄弟来合力完成:1. 入站;2. 路由;3. 出站

路由三兄弟

三兄弟桃园结义,不求同年同月同日生,但求同年同月同日死。

所以谨记:任何一个元素错误,就可能导致路由功能无法正常工作。

因为路由的灵活性非常高,只看技术文档很容易把自己绕晕,所以本文我们用几个具体的示例来逐层讲解。

啰嗦君

路由功能实在过于灵活,所以本文的示例,都是为了讲解对应的概念,实际使用时请根据自己的需求进行调整。

2. 基本功: “兄弟一条心”

下图的示例,就是在客户端的 Xray 入站接收 APP 数据、在路由 100%转发给出站,并从出站流向 VPS。

下面我们来逐个分析:

2.1 入站

Tip

入站: 就是流量如何流入 Xray

下面的入站配置示例,用大白话说就是:数据按照 socks 协议,通过 10808 端口,从本机 127.0.0.1 流入Xray。同时,Xray 将这个入站用 [tag] 命名为 inbound-10808

{
@@ -141,6 +141,6 @@
   ]
 }
 

此时,路由规则其实变成了:

这就是路由功能的灵活之处了,你可以自由的改变它的顺序来实现不同的设计。

至此,我们已经解释完了 【如何利用 geosite.dat 文件,通过路由规则,根据【域名】来分流网络流量】。

5. 攻城略池 - 多种路由匹配条件

请确保你已经读懂了上面的内容,因为这样,你就已经理解了【路由】功能的工作逻辑。有了这个基础,我们就可以继续分析【路由】功能更多更详细的配置方式和匹配条件了。

等你看完后面的内容,就完全可以自由的定制属于自己的路由规则啦!还等什么,让我们一起进入 《路由 (routing) 功能简析(下)》 吧!

- + diff --git a/en/document/level-1/routing-lv1-part2.html b/en/document/level-1/routing-lv1-part2.html index 8bd737fba8..e94bc4cda6 100644 --- a/en/document/level-1/routing-lv1-part2.html +++ b/en/document/level-1/routing-lv1-part2.html @@ -24,8 +24,8 @@ 路由 (routing) 功能简析(下) | Project X - - + +

路由 (routing) 功能简析(下)

欢迎继续学习 Xray 的【路由】功能!

《路由 (routing) 功能简析(上)》 中,我们已经对【路由】功能的工作逻辑有了清晰的理解,也基于 geosite.dat 文件做了简单的域名分流配置。

如前面所说,域名分流仅仅是【路由】功能的牛刀小试而已。下面就让我们来看看除了域名之外,还什么可以用做分流依据的东西吧!

5. 攻城略池 - 多种路由匹配条件

[域名], [IP], [协议], etc.

基于域名的分流,已经可以让我们对网络流量进行基本合理的分流。为什么说【基本合理】呢?

因为【三分天下】虽然是正确的战略方向,但如果只用【域名】来实现这个战略,其实漏洞百出,比如:

  1. 我读了《小小白白话文》后,给 VPS 新申请了一个 proxy.yourdomain.com 的域名, 我希望它无论如何都代理,geosite.dat 里面有吗?
  2. 如果我还有个 direct.yourdomain.com 的域名,我希望它无论如何都直连, geosite.dat 里面有吗?
  3. 本机 127.0.0.1 的内部流量,是否正确直连了?(比如 docker 等)
  4. 路由器、本地局域网 192.168.*.* 的流量,是否正确直连了?(比如路由器、群晖等)
  5. 我的国内 DNS 查询(如 223.5.5.5)是否正确直连了?
  6. 我的国外 DNS 查询(如 1.1.1.1)是否正确代理了?
  7. 其他类似国内公共 DNS 一样没有域名、只有 IP 地址的国内网站,是否正确直连了?
  8. 其他类似国外公共 DNS 一样没有域名、只有 IP 地址的国外网站,是否正确代理了?
  9. BT 下载的流量,虽然来源是国外,但如果通过 VPS 下载很可能导致违规使用被封,这该如何强制直连?
  10. ......

我之所以说只用【域名分流】会漏洞百出,是因为 geosite.dat 文件内只包含了一部分常用的域名。换言之,仅仅依赖它,则会:

  • 无法匹配文件里没有的新域名
  • 无法匹配基于 IP 地址的规则
  • 无法匹配基于网络协议的规则

啰嗦君

那我们来复习一下,当上面这些情况无法匹配时,会发生什么?对了,会触发隐藏路由规则,即【转发给第一个出站 】。这其实就是说:

  • 当你的第一个出站是 [direct-out] 时:需要直连的都正确了,但需要代理的则都错误
  • 当你的第一个出站是 [proxy-out-vless] 时:需要代理的都正确了,但需要直连的则都错误

所以,我们需要一个办法,让我们鱼与熊掌兼得。这样的办法是否存在呢?当然存在! 我们需要的只是【域名】之外更多的【分流判断依据】而已。

5.1 基于指定域名分流:[domain], [full]

  1. 如果需要匹配某个子域名,如 a-name.yourdomain.com,我们使用 full: "a-name.yourdomain.com"
  2. 前面的 问题1问题2,就可以通过给 proxy.yourdomain.com 指定 [proxy-out-vless] 出站,给 direct.yourdomain.com 指定 [direct-out] 出站来解决
  3. 如果需要匹配 yourdomain.com 的所有子域名,我们使用 domain: "yourdomain.com" 实现
  4. 上述两个可以成为两个独立的路由规则,达到某些子域名直连,其他子域名代理的配置
  5. 另外,[domain] 还支持正则表达式等匹配方式。详情请参考 《基础配置模块 - 路由》文档

上述配置如下:

{
@@ -187,6 +187,6 @@
   }
 }
 

其实,第 6 点已经是我整理过的规则了,原则就是【相同的匹配依据可以合并,不同的匹配依据保持独立】。

8. 明修栈道、暗渡陈仓

[domain] 转化 [ip] 的密道:domainStrategy

我们在 5.4 中提交了多种流量判断的【依据】,其中一种是域名 [domain]、一种是 [IP]

如果你初步了解过 DNS 的运作过程,就会知道,我们对一个域名 [domain] 发起访问请求时,其实需要先向 DNS 发起请求来解析域名 [domain] 对应的 [IP],在得到 [IP] 后再向它发起实际请求。

所以,面对入站的一次域名请求,Xray 其实有两次机会去判断它的类型。那么,究竟是否要用这两次机会呢?这就是由 domainStrategy 这个配置来决定的。它有三个选项:

  • AsIs
  • IPIfNonMatch
  • IPOnDemand

按么我们逐个来解释一下:

8.1 域名策略: "AsIs"

就是 "As Domain Is",也就是说 【域名什么样,就什么样,不多折腾】。

简单粗暴理解就是说【仅用 [domain] 来匹配】。

Tip

AsIs 的实际意义为 【如原先所示,不加修改】,🍉 老师这里描述的不是很恰当。

这个方式的处理都在 Xray 内部完成,没有与外界的数据往来,所以速度最快。它的兜底策略也很清晰:即前面所说的、无法匹配的域名自动转入第一条出站处理。所以,对于常规使用路由功能这最推荐的策略。

8.2 域名策略: "IPIfNonMatch"

就是 "lookup IP if (there's) no matching rule",也就是说【如果其他所有规则都匹配不上,那就转化成 IP 去匹配 IP 规则】。

简单粗暴理解就是说【先把访问目标和其他所有类型规则匹配,如果匹配不上,那就通过 DNS 查询转化成 IP,再从头和所有规则匹配一次】。

该策略下没有命中任何规则的这一部分域名,会需要再经历 DNS 查询过程、以及第二轮规则匹配的过程,其耗时会多于 AsIs 策略,所以并不是首选推荐的策略。

8.3 域名策略: "IPOnDemand"

这里其实说 Demand IP 更准确些,也就是说【当匹配时碰到任何基于 IP 的规则,将域名立即解析为 IP 进行匹配】。

简单粗暴理解就是说【只要路由规则中有 IP 类规则,那么所有基于域名 [domain] 的请求都要解析成 [IP] 然后去匹配 [IP] 类规则】。

它要对所有首次域名访问进行 DNS 解析,所以首次查询比较耗时。虽然由于 XrayDNS 缓存机制的存在,后续对相同域名的访问速度会重回巅峰,但总体来说也不是首选推荐的策略。

啰嗦君

domainStrategy 仅对域名生效,不要搞混了哦~

9. 思考题

迄今为止,我们都是在【单入站】和【单出站】的基础上,讲解【路由】内部的各种配置逻辑。

但是,如你所知,Xray 本身是支持多端口,多协议的。那么,如果我问你:

  1. 我希望 VLESS 协议将我日常的网页浏览和 APP 流量转发给美国的大流量服务器
  2. 我希望 trojan 协议将我的所有 Netflix 流量转发给日本的服务器解锁各种二次元
  3. 我希望 shadowsocks 协议将我所有的游戏流量转发给香港的服务器达到最低的延迟
  4. 我希望有一个独立的端口,能够把 telegram 的流量全都转发给 VPS
  5. 我希望有一个独立的端口,能够把 bittorrent 下载流量全都转发给欧洲大盘鸡
  6. 我希望......

这些想法,是否能通过【路由】功能配置实现呢?

答案当然是 【完全可以】 啦! 但是这些对于 level-1 来说已经超纲了,就留给各位自由的探索吧!

10. 结语

至此,Xray 的【路由】功能就介绍完了。希望本文能够对你理解 Xray 的灵活有所帮助。

11. 尾注

  • 现在你可以重新阅读一遍 路由,看看是否有更加深刻的理解。
  • 🍉🍉🍉🍉🍉 😄
- + diff --git a/en/document/level-1/work.html b/en/document/level-1/work.html index a1108d069e..7c7e904314 100644 --- a/en/document/level-1/work.html +++ b/en/document/level-1/work.html @@ -24,11 +24,11 @@ Xray 的工作模式 | Project X - - + +

Xray 的工作模式

单服务器模式

与其它的网络代理工具一样,你需要一台配置了 Xray 的服务器,然后在自己的设备上安装并配置 Xray 客户端,然后即可流畅地访问互联网。

一个 Xray 服务器可同时支持多台设备使用不同的代理协议访问。同时,经过合理的配置,Xray 可以识别并区分需要代理以及不需要代理的流量,直连的流量不需要绕路。

桥接模式

如果你不想在每一台设备上都配置路由,你也可以设置一台中转服务器,用于接收客户端发来的所有流量,然后在服务器中进行转发判断。

工作原理

在配置 Xray 之前,不妨先来看一下 Xray 的工作原理,以下是单个 Xray 进程的内部结构示意图。多个 Xray 之间相互独立,互不影响。

  • 需要配置至少一个入站连接(Inbound)和一个出站连接(Outbound)才可以正常工作。
    • 入站连接负责与客户端(如浏览器)通信:
      • 入站连接通常可以配置用户认证,如 ID 和密码等;
      • 入站连接收到数据之后,会交给分发器(Dispatcher)进行分发;
    • 出站连接负责将数据发给服务器,如另一台主机上的 Xray。
  • 当有多个出站连接时,可以配置路由(Routing)来指定某一类流量由某一个出站连接发出。
    • 路由会在必要时查询 DNS 以获取更多信息来进行判断。
- + diff --git a/en/document/level-2/index.html b/en/document/level-2/index.html index e82538e760..c3d60d51c8 100644 --- a/en/document/level-2/index.html +++ b/en/document/level-2/index.html @@ -24,11 +24,11 @@ Advanced Documentation | Project X - - + +

Advanced Documentation

This chapter contains experience sharing of using Xray at an advanced level. If you are already familiar with Xray, the experience shared here can help you unleash the full power of Xray.

Beginner's Guide to Transparent Proxies by a @kirinopen in new tag

An Introduction to Transparent Proxies.

TProxy Configuration Tutorial by a @BioniCosmosopen in new tag

Complete tutorial on configuring transparent proxy (TProxy) based on Xray.

TProxy Transparent Proxy (IPv4 and IPv6) Configuration Tutorial by a @SQLimitopen in new tag

Xray-based TProxy Transparent Proxy (IPv4 and IPv6) Configuration Tutorial

Nginx_TLS Tunnel Hidden Fingerprint by a @SQLimitopen in new tag

Use Nginx_TLS tunnel on both ends to hide the fingerprint.

[Transparent Proxy] Avoiding Xray Traffic Through gid by a @kirinopen in new tag

A new way of bypassing Xray traffic in transparent proxy implemented by iptables/nftables.

Redirect Specific Traffic to Specific Gateway using Xray to Achieve Global Routing "Load Balancing" by a @Zzz3mopen in new tag

Play Xray to the fullest: Implement "load balancing" based on fwmark or sendThrough.

Enhancing Proxy Security with Cloudflare Warp by a @yuhan6665open in new tag

Introduction to using WireGuard for outbound traffic added in Xray v1.6.5.

Xray Traffic Statistics by a @yuhan6665open in new tag

Adapt traffic statistics and scripts compatible with Xray.

- + diff --git a/en/document/level-2/iptables_gid.html b/en/document/level-2/iptables_gid.html index 2efec8e62b..ece639b4f3 100644 --- a/en/document/level-2/iptables_gid.html +++ b/en/document/level-2/iptables_gid.html @@ -24,8 +24,8 @@ Transparent proxy via GID | Project X - - + +

Transparent proxy to circumvent Xray traffic via GID

Warning

This translation was modified on 26 May 2021 and an updated version (14 October 2021) is available on the source page. View the original page

In the existing transparent proxy configuration(New V2Ray vernacular tutorial on transparent proxyopen in new tagNew V2Ray vernacular tutorial on transparent proxy (TProxy)open in new tagTransparent proxy(TProxy)configuration tutorial)tutorials, the circumvention of Xray traffic is achieved by using mark. That is, mark outbound traffics and set up iptables rules which directly connect traffics corresponding to the mark, to circumvent the Xray traffic and prevent loop back.

There are several problems with this method:

  1. Inexplicable traffic into PREROUTING chainopen in new tag

  2. Android has its own mark mechanism and this solution is not available on Android

The solution in this tutorial does not require a mark setting and has a higher theoretical performance, as well as not having the problems mentioned above.

Ideas

TProxy traffic can only be received by users with root privileges (uid==0) or other users with CAP_NET_ADMIN privileges.

The iptables rules can separate network traffic by uid (user id) and gid (user group id). Let Xray run on a user with uid==0 but gid!=0. Set the iptables rule to not proxy traffic for that gid to circumvent Xray traffic.

Configuration Procedure

1. Preliminary preparation

Android

  1. System has root privilege.

  2. Install busyboxopen in new tag

  3. There is a terminal that can execute commands, you can use adb shell, termux etc.

Other Linux system

Need sudo, iptables-tproxy module and iptables-extra module。

Usually the system comes with these functions. If you are using openwrt, you will need to run the following command:

opkg install sudo iptables-mod-tproxy iptables-mod-extra
@@ -113,6 +113,6 @@
 ip6tables -t mangle -A XRAY6_MASK -j MARK --set-mark 1
 ip6tables -t mangle -A OUTPUT -m owner ! --gid-owner 23333 ! -p icmp -j XRAY6_MASK
 
- + diff --git a/en/document/level-2/nginx_or_haproxy_tls_tunnel.html b/en/document/level-2/nginx_or_haproxy_tls_tunnel.html index 65c8280f95..cb477175da 100644 --- a/en/document/level-2/nginx_or_haproxy_tls_tunnel.html +++ b/en/document/level-2/nginx_or_haproxy_tls_tunnel.html @@ -24,8 +24,8 @@ Nginx 或 Haproxy 搭建 TLS 隧道隐藏指纹 | Project X - - + +

Nginx 或 Haproxy 实现的 HTTPS 隧道、HTTP/2 over HTTPS 隧道、WebSocket over HTTP/2 over HTTPS 隧道、gRPC over HTTP/2 over HTTPS 隧道以及自签证书双端认证的 gRPC over HTTP/2 over HTTPS 隧道

客户端服务端 Nginx 构建 HTTPS 隧道隐藏指纹

网路结构:

xray_client ---tcp--- nginx_client ---HTTPS--- nginx_sever ---tcp--- xray_server

编译 nginx --with-stream

在客户端及服务端均编译

curl -O -L http://nginx.org/download/nginx-1.22.1.tar.gz

tar -zxvf nginx-1.22.1.tar.gz

cd nginx-1.22.1

apt install gcc make //编译依赖 gcc 以及 make

./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_v2_module --with-stream --with-stream_ssl_module //此步需要依赖一些库,根据报错安装相应 lib

make && make install

编译之后 nginx 文件夹位于 /usr/local/nginx

配置 nginx

编辑 nginx 配置文件 nginx.conf

vim /usr/local/nginx/conf/nginx.conf

服务端加入如下配置

服务器申请证书不再赘述,参考白话文

stream {
@@ -548,6 +548,6 @@
 backend web
     server web /dev/shm/h1h2c.sock
 

xray 配置

简单的 gRPC 配置,无需 TLS,配置见文档,配置的 serviceName 可用于分流。

- + diff --git a/en/document/level-2/redirect.html b/en/document/level-2/redirect.html index be82143a48..d07ba8d9b8 100644 --- a/en/document/level-2/redirect.html +++ b/en/document/level-2/redirect.html @@ -24,8 +24,8 @@ 出站流量重定向 | Project X - - + +

基于 fwmark 或 sendThrough 的流量重定向

Warning

This translation was modified on 26 May 2021 and an updated version (24 December 2023) is available on the source page. View the original page

通过 Xray 将特定的流量指向特定出口,实现全局路由“分流”

前言

之前在网络上看到许多代理或者 VPN 会接管全局路由,如果与 Xray 同时安装,会导致 Xray 失效。参考了网络上许多教程,及时分流,也是通过维护一张或者多张 CIDR 路由表来实现的。这种情况下并不优雅,如果我想可以任意替换,实现按需分流,那有没有更好的办法呢?有!

通过 fwmark 或 Xray 的 sendThrough,再简单配合路由表功能即可实现:

  1. Xray 可设置指定的 Tag、域名等走指定接口。如果您的接口是双栈的,可以指定 IPV4 或者 IPV6
  2. 其余用户则走原 IPV4 或者 IPV6

具体设置如下(以 Debian10 为例):

1、安装代理或者 VPN 软件(例如 Wireguard、IPsec 等)

根据不同系统和不同软件,请参考官方安装方法

2、编辑 VPN 配置文件(以 WireGuard 为例)

原始文件:

[Interface]
@@ -240,6 +240,6 @@
 

开机自启

systemctl enable wg-quick@wg0
 systemctl start wg-quick@wg0
 

验证 IPv4/IPv6

自行验证 Google 搜索 myip

后记

本文本意是可以避免的多余的流量浪费,将路由和分流的功能交给 Xray 处理。避免了维护路由表的繁琐工作。顺便技术提升 UP。

感谢

@Xray-core @V2ray-core @WireGuard @p3terx @w @Hiram @Luminous @Ln @JackChou

- + diff --git a/en/document/level-2/tproxy.html b/en/document/level-2/tproxy.html index 39d62680ee..c64aec2f2b 100644 --- a/en/document/level-2/tproxy.html +++ b/en/document/level-2/tproxy.html @@ -24,8 +24,8 @@ TProxy 透明代理 | Project X - - + +

透明代理(TProxy)配置教程

本配置基于TProxy 透明代理的新 V2Ray 白话文教程open in new tag,加入了 Xray 的新特性,使用 VLESS + XTLS Vision 方案,并将旧教程中默认出站代理的分流方式改为默认出站直连,使用者请按照实际情况进行修改。

本文中所有配置已在 Raspberry Pi 2B、Ubuntu 20.04 环境下测试成功,如在其它环境中使用请自行调整配置。

开始之前

请检查您的设备是否有可用的网络连接,且服务端已经配置成功,客户端已经安装完毕。

需注意的是,目前很多透明代理教程都会将 Linux 系统的 IP 转发打开,但这样会导致 Splice 性能下降。详情请参考大案牍术破案纪实第三篇--我们是如何破解 Splice 性能下降甚至低于 Direct 之谜的open in new tag

这里我想要补充的是,很多透明代理教程会使用 Netfilter 进行分流,使直连流量直接发出而不经过 Xray,这时必须开启 IP 转发;也有的教程,如本文,会将所有流量导入 Xray 之中,由 Xray 的路由模块进行分流,这时无需开启 IP 转发。

Xray 配置

为了更好的分流体验,请替换默认路由规则文件为 Loyalsoldier/v2ray-rules-datopen in new tag,否则 Xray-core 将无法加载本配置。

sudo curl -oL /usr/local/share/xray/geoip.dat https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat
@@ -281,6 +281,6 @@
 [Install]
 WantedBy=multi-user.target
 
- + diff --git a/en/document/level-2/tproxy_ipv4_and_ipv6.html b/en/document/level-2/tproxy_ipv4_and_ipv6.html index a7cd1122ee..e81582e2a3 100644 --- a/en/document/level-2/tproxy_ipv4_and_ipv6.html +++ b/en/document/level-2/tproxy_ipv4_and_ipv6.html @@ -24,8 +24,8 @@ TProxy 透明代理 (ipv4 and ipv6) | Project X - - + +

TProxy 透明代理(ipv4 and ipv6)配置教程

Warning

This translation was modified on 4 March 2023 and an updated version (12 March 2023) is available on the source page. View the original page

本配置参考了TProxy 透明代理的新 V2Ray 白话文教程open in new tag透明代理(TProxy)配置教程open in new tag以及透明代理通过 gid 规避 Xray 流量open in new tag,加入了透明代理对 ipv6 的支持,并且使用 VLESS-TCP-XTLS-RPRX-Vision 方案对抗封锁 (推荐使用 1.7.2 及之后版本)。

关于 Xray 的配置并不是本文重点,使用者可依实际情况进行修改,具体可以参考官方文档示例open in new tag或其他优秀示例 比如@chika0801open in new tag 又如@lxhao61open in new tag

注意

若使用其他配置,你需要着重注意客户端配置中 outboundtagproxy 的部分,其他部分不变

服务端配置也要同时改变

此配置意在解决例如 Netflix 等默认使用 ipv6 连接的网站无法通过旁路由进行代理的问题,或对 ipv6 代理有需要。

本文网络结构为单臂旁路由

本文中所有配置已在 Arch Linux (Kernel: 6.0.10) 环境下测试成功,如在其它环境中同理

注意安装相应程序 # sudo apt install iptables ip6tables# sudo apt install nftables

若旁路由未安装 xray 程序,可以手动下载相应 xray 程序如 Xray-linux-64.zipopen in new tag ,然后复制 install-release.shopen in new tag 文件到旁路由,赋予可执行权限 # chmod 700 install-release.sh,然后使用 # ./install-release.sh --local Xray-linux-64.zip 根据提示进行本地安装。

Xray 配置

客户端配置

{
@@ -430,6 +430,6 @@
 [Install]
 WantedBy=multi-user.target
 
  1. 最后执行 systemctl enable tproxyrules 命令。

tproxyrules.service

注意其中主路由器 IP 地址,根据实际修改

ExecStartPre=/bin/sh -c 'until ping -c1 192.168.31.1; do sleep 1; done;' 命令为确保获得 IP 地址后再执行命令,否则会诡异报错,其中 IP 地址为主路由器地址,根据实际修改。

注意

如果通过 dhcpcd 等设置了静态 IP 及网关,则上述相关 ip route add/del 设置需删除

局域网设备上网设置

此处假定旁路由 ipv4, ipv6 地址分别为192.168.31.100, fd00:6868:6868::8866, 旁路由的 ipv4, ipv6 地址可由命令ip add获得。

方法一

局域网设备上网有两种方式,第一种就是在使用设备上进行静态 IP 的配置,将网关指向旁路由 IP。注意绝大部分手机仅支持手动配置 ipv4 网关,不支持手动配置 ipv6 网关,除非 root 后进行相关设置。

以 windows 设备为例,可以先开启 DHCP 记录自动分配的 IP 以参考,然后手写静态配置。

DNS 设置

此配置劫持 DNS 流量,DNS 可以随便写

image image

方法二

局域网设备上网的第二种方式,是在路由器上进行网关设置,这种方法对于连接到此路由器的设备无需做任何设置即可科学上网,但注意有些路由器不支持 ipv6 的网关设置,有 ipv6 需求的设备仍需在所需设备上单独手动配置 ipv6 相关设置参考方法一。

image

Finally

按照以上方法设置后设备即可双栈访问,进入测试网站比如 https://ipv6-test.com/ 可以看到如下结果 (需要代理此网站才能看到如下结果)

image

写在最后

如今 ipv6 并未完全普及,我们日常访问的流量 99%仍为 ipv4 流量;很多 VPS 商家虽然提供 ipv6 地址,但线路优化非常垃圾,甚至处于不可用状态,为何要加入 ipV6 的设置?

可以看到目前 ipv6 处于很尴尬的境地,各种设备对于 ipv6 的支持很烂,但是都在逐步完善,同时 Windows 系统对于 ipv6 的优先级也在提高,很多浏览器也会优先进行 ipv6 的解析以及访问,很多网站也开始默认使用 ipv6 进行访问(比如 Netflix, 如果没有配置 ipv6, 浏览器打开 Netflix 会显示 Not Available 是因为没有代理 Netflix 的 ipv6 请求,当然可以选择禁用 Windows 的 ipv6,但支持 ipv6 的 pt 站就无法使用)

这种情况下 ipv4 无法完全胜任网络冲浪的需求,即使是那 1%的流量,遇到了也会让人头疼不已。

而可以预见 ipv6 也会逐步与 ipv4 分庭抗礼,所以有必要加入 ipv6 的设置。

- + diff --git a/en/document/level-2/traffic_stats.html b/en/document/level-2/traffic_stats.html index 0b0cebc2c6..243c8473d6 100644 --- a/en/document/level-2/traffic_stats.html +++ b/en/document/level-2/traffic_stats.html @@ -24,8 +24,8 @@ 流量统计 | Project X - - + +

流量统计配置教程

请熟悉流量统计 白话文教程open in new tag,本文在其基础上适配了 Xray(1.5.9+)。

查看流量信息

配置方法与 v2fly 一致。 查看流量信息是 xray 命令行的其中一个功能。配置内设置的 api dokodemo-door 端口,即为 --server 参数的端口。

xray api statsquery --server=127.0.0.1:10085 #查看所有流量
@@ -120,6 +120,6 @@
 print_sum "$DATA" "user"
 echo "-----------------------------"
 
- + diff --git a/en/document/level-2/transparent_proxy/transparent_proxy.html b/en/document/level-2/transparent_proxy/transparent_proxy.html index c02f03d58b..47d2844a0e 100644 --- a/en/document/level-2/transparent_proxy/transparent_proxy.html +++ b/en/document/level-2/transparent_proxy/transparent_proxy.html @@ -24,8 +24,8 @@ 透明代理入门 | Project X - - + +

Warning

This translation was modified on 26 May 2021 and an updated version (26 December 2023) is available on the source page. View the original page

透明代理入门

什么是透明代理

透明代理简单地说就是不让被代理的设备感觉到自己被代理了。简单地说就是,被代理的设备上不需要运行任何代理软件(比如 Xray、V2RayNG 等),当你连接上网络时,你的设备已经被代理了。

这也意味着,代理的软件运行在别的地方,比如运行在路由器中,通过路由器上网的设备就自动被代理了。

透明代理的实现

透明代理的实现目前主要有两种方式:

tun2socks

可用 Windows/Linux(包括安卓)实现。因为实现过程比较简单,很少有教程,我这里简单描述一下。

Windows

  1. 安装 Netchopen in new tag ,使用模式[3] [TUN/TAP] 绕过局域网启动。

  2. 开启热点

  3. 打开控制面板->网络和 Internet->网络和共享中心->更改适配器设置,找到TAP-Windows AdapterMicrosoft Wi-Fi Direct Virtual Adapter

  4. 鼠标右键点击TAP-Windows Adapter属性->共享,勾选允许其他网络用户通过此计算机的 Internet 连接来连接,在家庭网络连接中选择Microsoft Wi-Fi Direct Virtual Adapter的那个网络连接,点击确定。

Android

  1. 配置连接 V2RayNG

  2. 开启热点

  3. 热点设置 -> 允许热点使用 VPN(部分安卓系统可能没有这个选项)

iptables/nftables

iptables 与 nftables 实现透明代理的原理相同,下文统一使用 iptables。

基于 iptables 的透明代理实现只能用于 Linux 系统(包括 openwrt/安卓)。由于其比 tun2socks 更高效率以及适合在路由器中配置而广泛使用。

现存的三篇白话文透明代理教程其实讲的都是基于这种方案的透明代理实现,它们是: 新 V2Ray 白话文指南-透明代理open in new tag新 V2Ray 白话文指南-透明代理(TPROXY)open in new tag透明代理(TProxy)配置教程 。其中第一篇是基于 iptables-redirect 模式,已经过时了,不建议使用,仅供参考。第二篇和第三篇讲的都是基于 iptables-tproxy 模式的透明代理实现。

iptables 实现透明代理原理

Linux 使用Netfilter来管理网络,Netfilter模型如下:

Netfilter

假设使用路由器作为网关(即我们平时的上网方式),那么:

局域网设备通过路由器访问互联网的流量方向:

PREROUTING链->FORWARD链->POSTINGROUTING链

局域网设备访问路由器的流量(如登陆路由器 web 管理界面/ssh 连接路由器/访问路由器的 dns 服务器等)方向:

PREROUTING链->INPUT链->网关本机

路由器访问互联网的流量方向:

网关本机->OUTPUT链->POSTINGROUTING链

通过使用 iptables 操控PREROUTING链OUTPUT链的流量走向,转发到 Xray,就可以代理局域网设备和网关本机。

透明代理难在哪里

透明代理的难点就在于路由,所谓路由,就是区分哪些流量是直连的,哪些该被代理,所以我个人认为叫做分流更加合适。

我们可以把路由由易到难分为以下几个阶段:

  1. 代理全部请求

  2. 本地局域网 IP/组播 IP 请求直连,其它请求代理

  3. 在 2 的基础上直连 Xray 发起的连接请求

  4. 在 3 的基础上直连指向中国大陆 IP 的连接请求,并对国内外域名选择国内外 DNS 服务器解析。

上面说的三篇教程,都是在第四阶段。所以新手直接阅读可能显得有点难懂。

从零开始一步步实现基于 iptables-tproxy 的透明代理

在开始之前,你需要有一定的基础知识:

  1. 大概知道什么是 TCP/IP 协议、域名和 DNS 服务器

  2. 知道什么是 WAN 口,LAN 口,LAN_IP,WAN_IP 以及 DHCP 服务器。对于旁路由,只有一个网口,这里称其为 LAN 口

  3. 对 Linux 系统有最基础的了解(知道怎么运行命令)

  4. 能够手写客户端 json 文件配置,至少要能看懂

前期准备工作

1. 准备一个运行 Linux 系统的网关

比如,刷了 OpenWRT 的路由器

2. 在网关(路由器)准备好 Xray 可执行文件以及配置文件

配置文件监听 12345 端口,开启 tproxy:

{
@@ -107,6 +107,6 @@
 iptables -t mangle -A OUTPUT -p tcp -j XRAY_MASK
 iptables -t mangle -A OUTPUT -p udp -j XRAY_MASK
 

但是这么配置有个缺点,如果使用 CDN 或者 VPS 很多的话,就不好写规则了。

  1. 通过 mark 规避

三个白话文教程都是使用这种方法规避,自行参考,这里不再赘述。

  1. 通过 gid 规避(推荐)

参考 [透明代理]通过 gid 规避 Xray 流量

这样就完成了第三阶段的代理,也就是平时说的全局代理。但是记得把网关的 DNS 服务器设置为国外的 DNS 服务器,否则可能依然返回被污染的结果。

第四阶段

其实,并不是所有人都需要实现第四阶段。全局代理对于大部分情况已经适用。

特别是对于旁路由而言。需要代理时,将网关调成旁路由的 IP,不需要代理时,将网关换回主路由 IP。

至于第四阶段的具体实现,那三篇白话文教程讲的都是。在理解了上面的内容后,再去看那三篇白话文教程,就比较容易理解了。

代理 ipv6

上面的规则只对 ipv4 生效,如果还想要代理 ipv6 请求,则使用 ip6tables 命令,用法与 iptables 基本相同。参考 [透明代理]通过 gid 规避 Xray 流量#4-设置 iptables 规则

iptables 透明代理的其它注意事项

  1. 如果作为代理的网关作为主路由,要在PREROUTING链规则中加一条iptables -t mangle -A XRAY ! -s 网关LAN_IP地址段 -j RETURN,即在第一阶段使用、第二阶段被删除的指令。如果不写,WAN 口中同网段的其它人可以将网关填写成你的 WAN_IP,从而蹭你的透明代理用,还可能带来一定的危险性。

  2. 新 V2Ray 白话文指南-透明代理(TPROXY)#设置网关open in new tag 中的第三条说:手动配置 PC 的网络,将默认网关指向树莓派的地址即 192.168.1.22。此时 PC 应当能正常上网(由于还没设置代理,“正常”是指可以上国内的网站)。实际上,Ubuntu、CentOS、debian 等系统就算开启了 IP 转发,PC 也不能正常上网,这是正常的。事实上只有 OpenWRT 能做到文中所描述的那样,据 @BioniCosmosopen in new tag 点拨,这是由于一般的 Linux 系统没有 Masquery 规则。

  3. too many open files 问题open in new tag ,解决方法见 [透明代理]通过 gid 规避 Xray 流量-配置最大文件大开数&运行 Xray 客户端

  4. 关于开启 ip_forward,待补充...

  5. 避免已有连接的包二次通过 TPROXY ,待补充...

  6. 主路由、单臂路由与旁路由,待补充...

- + diff --git a/en/document/level-2/warp.html b/en/document/level-2/warp.html index de21524398..24e0893657 100644 --- a/en/document/level-2/warp.html +++ b/en/document/level-2/warp.html @@ -24,8 +24,8 @@ Enhancing Proxy Security with Cloudflare Warp | Project X - - + +

Enhancing Proxy Security with Cloudflare Warp

Warning

This translation was modified on 19 May 2023 and an updated version (6 April 2024) is available on the source page. View the original page

Xray (1.6.5+) has added outbound WireGuard support. Although the added code and dependencies will increase the core size, we believe that this is a necessary new feature for three reasons:

  1. Through recent discussions and experimentsopen in new tag, we know that proxying the traffic back to China is not safe. One way to deal with this is to route the back-to-China traffic to a black hole, but the downside is that due to the delay in geosite and geoip updates or the lack of knowledge on how to properly split the traffic on the client side, the traffic ends up going to the black hole, affecting the user experience. In this case, we only need to import the back-to-China traffic into Cloudflare Warp, which can achieve the same level of security without affecting the user experience.
  2. As we all know, most airports will log the domain names visited by users, and some airports will even audit and block some user traffic. One way to protect user privacy is to use chain proxies on the client side. The WireGuard lightweight VPN protocol used by Warp adds an extra layer of encryption within the proxy layer. For airports, the target of all user traffic is Warp, thereby maximizing privacy protection.
  3. It is easy to use, and only one core is needed to complete the split, Wireguard Tun, and chain proxy settings.

Applying for a Warp Account

  1. Thank you Cloudflare for promoting a free internet. Now you can use the Warp service for free, and the nearest server will be automatically selected based on the exit.
  2. Use a VPS and download wgcfopen in new tag.
  3. Run wgcf register to generate wgcf-account.toml.
  4. Run wgcf generate to generate wgcf-profile.conf. Copy the following content:
[Interface]
@@ -111,6 +111,6 @@
    ]
 }
 
- + diff --git a/en/index.html b/en/index.html index dab3a19a92..a6a7cf1fd4 100644 --- a/en/index.html +++ b/en/index.html @@ -24,8 +24,8 @@ Project X - - + +
Project X

Project X

Fear not the clouds that obscure the view, golden eyes like a torch brighten the sky

Start here → Configuration guide →

High-speed protocol

Original VLESS and XTLS protocols, free from redundant encryption, release CPU power

Free combination

Perfect fallback mechanism, effectively prevent active detection, multi-service sharing ports @@ -34,6 +34,6 @@

Full compatibility

Fully compatible with v2ray-core configuration files and API calls

Affinity

Active community discussions and contributions, MPL 2.0 open source license

XTLS? Xray? V2Ray?

XTLS are brilliant ideas for TLS we study, while Xray is the best practice we maintain.

  • Xray-core is a superset of v2ray-core, with better overall performance and enhancements such as XTLS, and it'scompletelycompatible with v2ray-core functionality and configuration.
    • Only one executable file, including ctl functionality, run is the default command
    • Configuration iscompletelycompatible, environment variables and API calls need to be changed to start with XRAY_
    • Exposed raw protocol's ReadV on all platforms
    • Provides complete VLESS & Trojan XTLS support, both with ReadV
    • Provides multiple XTLS flow control modes, unrivaled performance!

"Configuration compatible, overall better"

Who are we?

It doesn't matter who we are. What matters is that we will keep riding and never look back.

Help Xray become stronger

Welcome to help Xray become stronger!

Telegram

Thanks

  • Thanks to everyone for their support!
  • Thanks to all kinds of scripts, Docker images, client support... Thanks to all the big guys who helped improve the ecosystem!
  • Thanks to friends who have contributed to the Xray website and documentation.
  • Thanks to friends who have made meaningful suggestions and comments.
  • Thanks to every friend in the Telegram group who helps others.

More about project X

  • If you would like to learn more about project X's history and growth, please click here
  • Now Project X releases NFTs! If you would like to have one Project X NFT, or want to donate to or sponsoring Project X, please click hereopen in new tag

License

Mozilla Public License Version 2.0open in new tag

Stargazers over time

Stargazers over timeopen in new tag

- + diff --git a/index.html b/index.html index d8baaadf41..db350793fc 100644 --- a/index.html +++ b/index.html @@ -24,8 +24,8 @@ Project X - - + +
Project X

Project X

不畏浮云遮望眼 · 金睛如炬耀苍穹

由此开始 → 配置指南 →

极速协议

原创 VLESS 与 XTLS 协议,摆脱冗余加密,释放CPU算力

自由组合

完善的回落机制,有效防止主动探测,多服务共享端口 @@ -34,6 +34,6 @@

完整兼容

完整兼容 v2ray-core 配置文件与 API 调用

亲和力

活跃的社区讨论及贡献,MPL 2.0 开源许可协议

XTLS ? Xray ? V2Ray ?

XTLS are brilliant ideas for TLS we study, while Xray is the best practice we maintain.

  • Xray-core 是 v2ray-core 的超集,含更好的整体性能和 XTLS 等一系列增强,且完全兼容 v2ray-core 的功能及配置。
    • 只有一个可执行文件,含 ctl 的功能,run 为默认指令
    • 配置上完全兼容,环境变量和 API 对应要改为以 XRAY_ 开头
    • 全平台开放了裸协议的 ReadV
    • 提供完整的 VLESS & Trojan XTLS 支持,均有 ReadV
    • 提供了 XTLS 多种流控模式, 性能一骑绝尘!

“配置兼容,整体更好”

我们是谁?

It doesn't matter who we are. What matters is that we will keep riding and never look back.

帮助 Xray 变得更强

欢迎帮助 Xray 变得更强!

Telegram

致谢

  • 感谢所有人的支持!
  • 感谢各类脚本、Docker 镜像、客户端支持...感谢所有帮忙完善生态的大佬们!
  • 感谢为 Xray 网站和文档添砖加瓦的朋友们.
  • 感谢提出有意义的建议和意见的朋友们.
  • 感谢 Telegram 群每一位帮助群友的朋友.

更多关于 Project X

  • 如果你想知道更多关于 Project X 的足迹与成长, 请点击这里
  • 现在 Project X 也发行 NFT 了!如果想拥有一枚 Project X NFT 或者想捐赠或者赞助 Project X,请点击这里open in new tag

License

Mozilla Public License Version 2.0open in new tag

Stargazers over time

Stargazers over timeopen in new tag

- + diff --git a/ru/about/news.html b/ru/about/news.html index 6442714469..4d83c34d67 100644 --- a/ru/about/news.html +++ b/ru/about/news.html @@ -24,11 +24,11 @@ 大史记 | Project X - - + +

大史记

2024.9.12

大史记重出江湖?!

2024.9.7 v24.9.7Открыть в новой вкладке

更改版本号之后的首次发版。

  • 这次移除了 QUIC 以及 DomainSocket 传输,移除了两处远古配置遗留代码。
    • 二进制大小比 v1.8.24 减小了 1MB。
  • 依然有每次必备的 bug 修复。

2024.8.30 v1.8.24Открыть в новой вкладке

在等待 SplitHTTP multiplex controller 期间,main 分支已经积累了大量重要更新,所以我们决定先发一个版本。

  • Socks 入站现在默认兼容 HTTP 代理请求。
  • UDP noise (preview)
  • 还有一些改进。

由于传统版本号的存在,为每个版本规划功能、进行排期已经严重阻碍了新功能的开发、合并、发布。所以我们决定从下个版本开始弃用传统的版本号,改用发版日期作为版本号,如 v24.8.30,并取消版本规划,全面采用流式更新,写好的功能直接合并,不再等待,预计每月月底发一个版本。

毕竟对于反审查软件来说,相较于传统的版本号,新功能的及时性、每月更新更为重要,而不是发一个功能确定的版本并长期维护。

下个版本会移除一些历史久远的代码,以后日常积累新代码、提醒迁移,跨年新版删代码、breaking。

我们相信有了各位的捐款以及对发版形式的革新,Xray-core 这个项目会发展得更好。

2024.8.26

Project VLESS 群组创立。

We have created Project VLESSОткрыть в новой вкладке for non-Chinese users (mainly Russian).

2024.8.3

第一个 Project X NFTОткрыть в новой вкладке 正式发行!

就像 Xray 开创过很多历史一样,发行 NFT 也是这个领域前无古人的操作。这些 NFT 非常有纪念意义,甚至可以说是有历史意义,远大于现在的初始价格,假以时日它们必将价值连城。最后再次感谢大家对 Project X 的支持。

2024.7.29 v1.8.23Открыть в новой вкладке

2024.7.22 v1.8.21Открыть в новой вкладке

中间似乎回到了最初的腹泻式发版状态……

正如 v1.8.16 所预告的,SplitHTTP 现已初步支持 HTTP/3(QUIC)。毫无疑问,SplitHTTP H3 已经开启了一个崭新的时代。

  • SplitHTTP H3 是第一个完全基于标准 H3、支持套 CDN 的 QUIC 类代理,亦可用反代、Browser Dialer 来隐蔽自身。

2024.7.16

Project X 文档迎来了俄语版!感谢 @iambabyninjaОткрыть в новой вкладке 的翻译!

Привет, друзья из России!

2024.7.15

通过已知信息以及努力,Xray-core 现在重新支持 Windows 7!在后续的发版中,Windows 7 用户下载名为 Xray-win7-32.zip 或 Xray-win7-64.zip 的压缩包解压即可享受,感谢大家的支持!具体使用方式请点这里

虽然日后随着各方面升级 Windows 7 最终会离开,但是现在还是可以让这个时间来得稍微晚一些。

2024.6.18 v1.8.16Открыть в новой вкладке

新传输来了,它目前叫 SplitHTTP。

  • 实现进一步的流量混淆有两种刚好相反的方式:多路复用与拆分连接。
  • 可以通过不支持 WebSocket、gRPC 的 CDN,实现与 Meek 相同的目标,且 SplitHTTP 比 Meek 更简单、效率更高。
  • SplitHTTP 没有 WebSocket 的 ALPN 问题,这是一大优势,未来还会支持 HTTP/3(QUIC)。
  • 另外 SplitHTTP 也已经加入分享链接套餐~

2024.6.2

一个新的传输方式正在被打造……

2024.4.26 v1.8.11Открыть в новой вкладке

  • 现在有了生成 ECH 密钥的工具。
  • 增强、修复,并移除了一点不再使用的代码。

2024.4.20

我们现在有了 issues 模板,感谢 @FanglidingОткрыть в новой вкладке

2024.4.13

VLESS Seed 整备完毕,待势而发。

2024.3.18 v1.8.10Открыть в новой вкладке

和 WebSocket 一样,HTTPUpgrade 也有 0-RTT 了。

2024.3.11 v1.8.9Открыть в новой вкладке

新增 HTTPUpgrade 传输,听说比 WebSocket 要轻。

  • 已加入分享链接套餐~

2024.2.29

gRPC 传输现在也有 Host 一样的配置字段了!它叫 authority。这下 gRPC 也能“域前置”了,没有 ALPN 问题。

2024.2.25 v1.8.8Открыть в новой вкладке

  • 现在 XUDP 流量统一使用 Vision 填充了,速来体验。
  • 新增了 leastLoad balancer。
  • 修复错误、优化性能……

2024.1.9

惊闻 Win7 无法运行新版 Xray-core?探索之下竟发现 Go 放弃了对 Win7 的支持。有什么办法能继续支持这个有些古老但是依然优雅的操作系统吗?

2023.11.21

发表在 USENIX 顶会的论文Открыть в новой вкладке证实,XTLS Vision 已经达到它的设计目标。

而 XTLS 也不会止步于此,如 X 射线一般穿破高耸的围墙。

2023.11.18 v1.8.6Открыть в новой вкладке

  • WireGuard 现在也有了对应的入站。Freedom 出站也终于有了 splice。
  • 现在出站的 domainStrategy 也得到了统一。
  • 更多的美味小点心。
  • 因为 不可抗力 功能变更,Dragonfly BSD 支持黯然离场。
  • 我们真的要对一代经典 Windows 7 说再见了吗?

2023.9.30

为 v2rayNG 设计了全新的配色,安装最新的 Pre-release 版本即可体验。

2023.8.29 v1.8.4Открыть в новой вкладке

1.8.x 在经过半年的打磨后终于来到了第一个认可的正式版了。

同样地,这次集成的改进也不少,速来品尝!

2023.7.22

又修好了一个 HTTP/2 传输的历史遗留断流问题。

2023.7.7

即将给 Vision 添加 Seed 支持。

2023.6.30

下一个 XTLS 流控:xtls-rprx-switch 🍪

  • XTLS 的 0-RTT 已经预告几个月了,本来也是想保留神秘感。
  • 对比现有的 XTLS Vision 和 Mux 有着更加不错的优势。

2023.6.27

如何选取 REALITY 目标域名?来看这里助你事半功倍!Открыть в новой вкладке

2023.6.19 v1.8.3Открыть в новой вкладке

  • 精简代码计划后的第一个版本,VMess (MD5)、MTProto 以及 Starlark 相关代码已被卸下。轻装上阵。
  • 对代码进重构也是轻装上阵的一部分。
  • 同时我们也没有忘记增添一些增强功能,还有修复漏洞。
  • v1.8.3 为今年的最后一个版本。

2023.6.6

好消息:下一个 XTLS 流控不叫 Vision。 🍪

2023.4.21

也许我们可以借助一下 RealiTLScannerОткрыть в новой вкладке……

2023.4.20

经过长年累月的开发,累积代码不计其数…… 精简代码计划Открыть в новой вкладке 被提出了!

2023.4.19

xtls-0rtt-vision(-udp443) 🍪

2023.4.18 v1.8.1Открыть в новой вкладке

升级后的 XUDP 也来了!

  • 现在 XUDP 也带有连接迁移、端口复用的特性,并且带有全局 Session ID ,麻麻再也不用担心意外断线的时候怎么办了
  • 同时我们也添加了 XUDP 的控制配置,让你能更好掌控它~
  • 新的 XUDP 配合 XTLS Vision 食用风味更好喔~
  • 惯例还有小甜点,欢迎品尝~

2023.4.6

XUDP 也在悄然升级……

2023.3.29

PLUX protocol 🍪

2023.3.19

对 REALITY 的分享链接标准也已经出现了。

2023.3.9 v1.8.0Открыть в новой вкладке

THE NEXT FUTURE, REALITY is NOW release on Xray-core

REALITY 已经实装发版!欢迎体验! XTLS Vision 也已经完善,请两端升级至最新版食用。

  • 因为这次 Vision 填充算法改变,XTLS Vision 旧版和新版之间会存在兼容性问题。
  • HTTP/2 传输也已经做了改善,现在使用新版即可纵享丝滑~
  • 还有大量小改进欢迎体验~

2023.3.4

Legends never die, they become a part of you VLESS.

They simply fade away.

2023.3.2

HTTP/2 传输的一些遗留问题已经被改善,欢迎搭配 REALITY 测试纵享丝滑~

2023.2.16

THE NEXT FUTURE becomes THE REALITY NOW!

2023.2.9

REALITY is reality now!

2023.2.8 v1.7.5Открыть в новой вкладке

Keep riding and never look back.

  • 恭喜 @yuhan6665Открыть в новой вкладке 贡献了 Xray-core 的第 500 个 commit!
  • XTLS Vision 流控已经接近完善,即将实用。
  • 现在对 uTLS 指纹模拟添加了更多可选项,有哪一款适合你?
  • 分享链接也支持同时分享 uTLS 指纹配置了。
  • 还有更多的功能增强和修复。
  • 这一版也是能最后一次看到 XTLS Origin、Direct 和 Splice 流控的一版了。 有点伤感不是吗?

2023.1.29

Winter cannot cover the NEXT FUTURE...

2022.12.26 v1.7.0Открыть в новой вкладке

因为手滑,这次的版本号直接大升,感谢大家支持!

  • 以后将会严格执行 Semantic Versioning。

2022.11.28 v1.6.5Открыть в новой вкладке

这次我们有了 WireGuard 出站。

  • 使用 WireGuard 搭配 CF WARP 使用可以解锁有趣的新玩法呢。
  • 同样安全更新和修复也不会少。

2022.11.7 v1.6.3Открыть в новой вкладке

现在 Vision 流控也能使用 uTLS 指纹模拟了,这就是使用 tlsSettings 带来的好处吗!

2022.10.29 v1.6.2Открыть в новой вкладке

第一个包含 Vision 流控的发行版已经放出!欢迎试用并提交反馈!

2022.10.22 v1.6.1Открыть в новой вкладке

  • 为 WebSocket、HTTP/2 以及 gRPC 传输带来了 uTLS 指纹支持!
    • 之前只有普通 TLS 下 TCP 传输能用的选项现在更好用了。
  • Linux 下可以单独为出入口设置 TCP 拥塞控制了。

2022.10.3

天气渐凉,但是并没有凉下开发的脚步。封锁天降,但无法阻止前行……

  • 新的 XTLS 流控酝酿中……
    • 解决之前流控已有的问题;
    • 对 TLS 1.3 直接启用 splice;
    • 增加 TLS 握手长度混淆;
    • 简化代码,使用 tlsSettings 而不是 xtlsSettings……

2022.8.28 v1.5.10Открыть в новой вкладке

底层传输支持更合理的 TCP Keepalive 配置了。

2022.6.20 v1.5.8Открыть в новой вкладке

现在 Shadowsocks-2022 的 relay 中转也受支持了。

2022.5.29 v1.5.6Открыть в новой вкладке

Shadowsocks-2022 协议来到了 Xray-core!

Shadowsocks-2022 是重新设计的全新协议:

  • 在保留 Shadowsocks 原生 udp 的基础上解决了重放攻击等安全问题(与 vmess 一样使用时间戳,因此客户端与服务端需要时间一致)。
  • 支持单端口多用户,并且参考 quic、wireguard 等协议设计与实现使用了 session 机制,减低加密负担,保证网络变动时的无缝迁移。

2022.4.24 v1.5.5Открыть в новой вкладке

这次带来了方便可视化的检测数据接口!快来体验!

  • 顺便修复了一些影响使用体验的问题。

2022.3.13 v1.5.4Открыть в новой вкладке

给 Windows 平台加上了没有黑窗冒出的 wxray.exe 文件,并带来了对 UDS 监听的增强。

2022.1.29 v1.5.3Открыть в новой вкладке

牛辞胜岁,虎跃新程。🧨

  • 这次带来了对 QUIC 传输的流分配改进,使用 QUIC 传输现在更丝滑了。

2021.12.24 v1.5.2Открыть в новой вкладке

为 gRPC 添加了一个新的选项,在通过 CDN 时变得更好用了。

2021.12.15 v1.5.1Открыть в новой вкладке

“过渡时期的阶段性的维护版本”

  • 新功能、增强还有大量修复陆续有来。
  • 记得将 VMess 配置中的 alterID 去掉!

2021.10.20 v1.5.0Открыть в новой вкладке

真的是巨大的改动!

  • 重构了 DNS 组件,支持的协议和细化配置更多了。
  • 增强了 gRPC 传输以及 FakeDNS。
  • 现在终于支持 Windows ARM64 了。
  • 更多新功能和改进等待体验。

2021.9.23 v1.4.5Открыть в новой вкладке

中秋快乐,阖家团圆。

  • 修正了版本号过低,版本号不吉利的 bug。
  • 这次移除了 Shadowsocks 里面已经不安全的加密方式。要尽快迁移到 AEAD 加密上面喔。
  • 这次修复了远古时期开始就存在的历史问题:开启流量统计功能可能会使性能下降。简单来说,不论什么配置现在打开统计都不会对性能有任何影响了。
  • 还有对 XTLS 的安全性更新以及大量修复。
  • 对了,因为 TLS 库的更新,cipherSuites 不能再指定加密套件顺序了,而 preferServerCipherSuites 已经被彻底弃用。事实上这些变化在 Xray-core v1.4.3 中已经产生了。

2021.9.16

2021.9.8 v1.4.3Открыть в новой вкладке

这是一个阶段性维护版本。开发仍在继续……

  • 在此期间累积了大量改进和新功能。
  • 加入新的 DomainMatcher,现在域名规则匹配性能更好了。
  • 加入对 HTTP/2 和 gRPC 传输的健康检查、对未知 SNI 的处理改进,以及修复了一大堆 bug。

Helden sterben nicht!

2021.7.14

  • AnXray 重金设计 的新图标已经上线!
    • 现在图标的辨识度更高了。
  • 过去三个星期,AnXray 共积累了 600 stars、2K+ 频道订阅数和 11K+ GitHub 下载量,感谢大家的支持。
  • AX 为 AnXray 的缩写,推荐用 AX 指代 AnXray,简短方便

2021.6.21

现在一个以 Xray-core 为核心的开源、自由的 Android 客户端已经出现——AnXrayОткрыть в новой вкладке!由 @nekohasekaiОткрыть в новой вкладке 维护。

前两天从早到晚反复打磨细节,希望大家多多 Star、关注。

2021.5.1

对 tun2socks 的改进出现在 v2rayNG 上面了。

2021.4.26

给 tun2socks 带来了一个改进。后续有可能能吃到它~

2021.4.12

现在带来了 X-flutter 前瞻,可以期待一下会是什么样子呢~ 🍪

2021.4.6

  • VuePress Next.
  • With Dark Mode.

2021.4.4

  • 本文档迎来的新的首页。
  • 本文档迎来了暗黑模式。
  • 当然,暗黑模式还有各种各样的问题。具体的内容还需要慢慢调整。
  • 另:Telegram 群聊突破了 5000 人!还加入了 Anti-Spam 机器人!
  • 🎉🎉🎉

2021.4.1 v1.4.2Открыть в новой вкладке

  • 不是愚人节玩笑,今天更新。
  • 加入 Browser Dialer,用与改变 TLS 指纹与行为。
  • 加入 uTLS,用与改变 TLS Client Hello 的指纹。
  • 顺便修复了一大堆奇妙的问题,具体的内容见更新日志。

2021.3.25

没错还在变。 -_-

2021.3.15

文档网站正在悄悄的进行着某些神秘的变化。。。,🙊🙊🙊

2021.3.14 v1.4.0Открыть в новой вкладке

  • Happy Pi-Day!
  • 这次是个大更新:
    • 为链式代理引入了传输层支持。
    • 为 Dialer 引入了 Domain Strategy,解决奇妙的 DNS 问题。
    • 添加了 gRPC 传输方式,与更快一点的 Multi Mode。
    • 添加了 WebSocket Early-Data 功能,减少了 WebSocket 的延迟。
    • 添加了 FakeDNS。
    • 还修复了系列的问题,添加了各类功能,详情请见更新日志。
  • 还是 VuePress 比较爽啊(

2021.3.3 1.3.1Открыть в новой вкладке

  • 这个版本使用了 Golang 1.16,正式原生支持 Apple Silicon。
  • 同时修复了一个会导致 Panic 的 bug。Holmium_认为这是在骗、在偷袭。
  • 修复了几个遗留问题。

2021.2.14 1.3.0Открыть в новой вкладке

  • Happy 🐮 Year 🎉!
  • v1.3.0 通过非常巧妙的机制实现了 V 系协议全部 FullCone,同时保证了一定的兼容性。
  • OHHHHHHHHHHHH!

2021.01.31 1.2.4Открыть в новой вкладке

  • 解决两个“连接至标准 Socks 服务端时可能出错”的历史遗留问题。
  • 似乎这个版本没有什么改变,但这只是暴风雨前的宁静。
  • (没错我就是先知)

    你个傻子,你拿的是 UNO 牌。

2021.01.25

  • 全互联网最好最详细的秘籍入门篇同学们练熟了吗? 🍉 老师开始连载秘籍第一层咯...
  • 英文版文档网站逐渐增加内容 ing, 感谢各位大佬的辛苦付出~!

2021.01.22 1.2.3Открыть в новой вкладке

  • 对 SS 协议的支持变强了, 支持单端口多用户!
  • 对 trojan 协议的支持也变强了, trojan 的回落也解锁 SNI 分流的新姿势啦~!
  • (VLESS: 嘤嘤嘤)
  • UDP 奇奇怪怪的 BUG 被干掉了, 一个字, "稳定".
  • 嗅探可以排除你不想嗅探的域名, 可以开启一些新玩法.
  • 向发现问题->开 issue->自行测试->自行分析->自行找到问题->自行解决->然后给上下游提交 PR 的大佬 @Bohan YangОткрыть в новой вкладке 致敬!
  • 其他美味小樱桃, 惯例更新品尝就对啦.

2021.01.19

  • 一些数字
    • 版本发布了 10   个 tag
    • 解决掉了 100  个 issue
    • 复刻了 300  个 fork
    • 点了 2000 个 star
    • 群 3000 个 人

2021.01.17

2021.01.15 1.2.2Открыть в новой вкладке

  • 回落分流又解锁了奇怪的新姿势! 回落中可以根据 SNI 分流啦~!
  • 之前预告的 UUID 修改正式上线.(往下看往下看)
  • 日志现在看起来比上一次顺眼又更顺眼了一丢丢.
  • 远程 DOH 和其他的 DNS 模式一样学会了走路由分流.
  • 当然还有其他各种小糖果.(更新品尝就对了)
  • 啊, 还有, 世界上第一個 M1 上跑起 Xray 的男人是 Anthony TSE

2021.01.12

  • 将要到来的 UUID 修改, 支持自定义字符串和 UUID 之间的映射. 这意味着你将可以这样在配置文件中写 id 来对应用户.
    • 客户端写 "id": "我爱 🍉 老师 1314",
    • 服务端写 "id": "5783a3e7-e373-51cd-8642-c83782b807c5" (此 UUID 是 我爱🍉老师1314 的 UUID 映射)
  • 🍉 老师的小小白白话文大结局, 撒花.

2021.01.10 1.2.1Открыть в новой вкладке

  • 大量的 UDP 相关修复, 甚至可以在育碧的土豆服务器上玩彩虹六号!
  • Google Voice 应该也可以正常使用 v2rayNG 拨打了.
  • 日志现在看起来更顺眼.

2021.01.07

  • 礼貌和尊重本应是社区不需要明说的准则之一。

2021.01.05

  • 文档网站正在悄悄的进行着某些神秘的变化。。。,🙊🙊🙊

2021.01.03

2021.01.01

【祝大家新年快乐,嗨皮牛耶!】🎆🎇🎆 1.2.0Открыть в новой вкладке

🎁 在元旦的最后几分钟,v1.2.0 它来了,带着周五必更的惯例,带着各位贡献大佬的心血以及 @rprxx 的黑眼圈,不负众望的来了!

  • 圣诞礼物v1.1.5后的元旦礼物 🎁,游戏玩家大福利,全面 FullCone。
  • (UDP 还会继续增强!)
  • 如果你已经拆过圣诞礼物,这次还有比圣诞礼物更精美的包装和小糖果哦。(同样不用问,更新品尝就对了)
  • (不,下面不是广告,是里程碑。)
  • Xray 是有史以来第一个不受限制的多协议平台:只需 Xray 即可解决问题,无需借力其它实现。
    • 一人扛起了所有!支持各大主流协议!
    • 一骑绝尘的性能!
    • 日趋完善的功能!
    • 可怕的生命力与社区亲和力!
  • Xray 将继续保持前行! 因此 Xray 需要更多的英雄!!Открыть в новой вкладке
  • PS:请品,请细品release notesОткрыть в новой вкладке每一句。似乎有一个小秘密小彩蛋 (啊,有人敲门...我一会和你们说)

2020.12.29

透明代理的游戏玩家利好! Xray-core tproxy 入站, socks 出站 UDP FullCone 测试版, TG 群Открыть в новой вкладке火热测试中

2020.12.25 1.1.5Открыть в новой вкладке

圣诞节快乐!

  • 游戏玩家的圣诞礼物!你可以用 xray 爽快的打游戏啦!因为有了 SS/trojan UDP fullcone
  • 你可以用你喜欢的格式写配置文件了,比如 yaml,比如 toml...
  • (VLESS 的 UDP fullcone 和更多增强很快就到!)
  • 无须再担心证书验证被墙,OCSP stapling 已经上线!
  • kirin 带来了一大波 脚本更新.脚本在此Открыть в новой вкладке
  • 还有更多美味小樱桃!(不用问,更新品尝就对了)

2020.12.24

因为某些不可描述的原因,Xray 的文档网站已在发布日前偷跑上线。 网址为:没错你正在看的就是Открыть в новой вкладке

大家可以查阅各种内容也欢迎纠错/提出建议(可发往文档 github 仓库的 issue 区)

文档网站需要不断完善和增加内容,以及完善设计。 因此更欢迎大家一起为文档建设添砖加瓦。 文档的仓库Открыть в новой вкладке

仓库的 readme 中有简略教程说明如何帮助 xray 改进文档网站. 欢迎大家查看,纠错,修改,增加心得。

2020.12.23

Xray-core Shadowsocks UDP FullCone 测试版, TG 群Открыть в новой вкладке火热测试中

2020.12.21

  • Project X 群人数 2000+
  • 群消息(含游戏群) 日均破万

2020.12.18 1.1.4Открыть в новой вкладке

  • 更低的启动内占用和内存使用优化
  • 随意定制的 TLS 提高你的 SSL 评级
  • 支持 XTLS 入站的 Splice 以及支持 trojan 的 XTLS
  • 还有在您路由器上使用的 Splice 最佳使用模式建议

2020.12.17

鉴于日益增长群人数和游戏需求, 开启了TG 游戏群Открыть в новой вкладке

2020.12.15

安装脚本 dev 分支Открыть в новой вкладке开启, 持续更新功能中.

2020.12.11 1.1.3Открыть в новой вкладке

  • 完整版本的 REDIRECT 透明代理模式.
  • 软路由 splice 流控模式的优化建议.

2020.12.06 1.1.2Открыть в новой вкладке

  • 流控增加 splice 模式, Linux 限定, 性能一骑绝尘.
  • 增强了 API 兼容

2020.12.04

增加 splice 模式

2020.11.27

  • Project X 的 GitHub 主仓库 Xray-core 已获 500+ stars
  • 登上了 GitHub Trending
  • Project X 群人数破千,频道订阅数 500+

2020.11.25 1.0.0Открыть в новой вкладке

Xray 的第一个版本.

  • 基于 v2ray-core 修改而来,改动较大
  • 全面增强, 性能卓越, 完全兼容

2020.11.23

project X start

梦开始的时候

- + diff --git a/ru/config/api.html b/ru/config/api.html index e7f33475d7..95dd77420e 100644 --- a/ru/config/api.html +++ b/ru/config/api.html @@ -24,8 +24,8 @@ API | Project X - - + +

API

Настройка API предоставляет API-интерфейсы на основе gRPCОткрыть в новой вкладке для удаленного вызова.

Интерфейсы можно включить с помощью модуля конфигурации api. Когда API включен, Xray создает исходящее подключение с тем же тегом, что и тег API.
Необходимо вручную направить все входящие API-подключения на это исходящее подключение с помощью правил маршрутизации.
См. раздел Связанные настройки в этом документе.

Начиная с версии v1.8.12Открыть в новой вкладке поддерживается упрощенный режим настройки, в котором достаточно указать только ApiObject, без необходимости настройки inbounds и routing.
Однако при использовании упрощенной настройки статистика трафика не учитывает трафик входящих API-подключений.

Внимание

Большинству пользователей не нужен этот API, новички могут просто пропустить этот раздел.

ApiObject

ApiObject соответствует полю api в конфигурационном файле.

{
@@ -70,6 +70,6 @@
 xray.app.proxyman.command.HandlerService
 xray.app.stats.command.StatsService
 

Примеры вызова API

Xray-API-documentsОткрыть в новой вкладке @crossfw

- + diff --git a/ru/config/dns.html b/ru/config/dns.html index 871d79bfd8..b4b2a28976 100644 --- a/ru/config/dns.html +++ b/ru/config/dns.html @@ -24,8 +24,8 @@ Встроенный DNS-сервер | Project X - - + +

Встроенный DNS-сервер

DNS-сервер

Встроенный DNS-модуль Xray имеет два основных назначения:

  • Разрешение доменных имен в IP-адреса на этапе маршрутизации и сопоставление правил с полученными IP-адресами для разделения трафика.
    Разрешение доменных имен и разделение трафика зависят от значения параметра domainStrategy в модуле конфигурации маршрутизации.
    Встроенный DNS-сервер будет использоваться для DNS-запросов только при следующих значениях:

    • "IPIfNonMatch": при запросе доменного имени Xray сопоставляет его с доменами, указанными в правилах маршрутизации.
      Если совпадение не найдено, встроенный DNS-сервер используется для разрешения доменного имени, а затем полученный IP-адрес снова сопоставляется с правилами маршрутизации на основе IP-адресов.
    • "IPOnDemand": при сопоставлении правил, основанных на IP-адресах, доменное имя немедленно разрешается в IP-адрес для сопоставления.
  • Разрешение целевого адреса для подключения.

    • Например, в исходящем подключении freedom, если параметр domainStrategy установлен в UseIP, исходящие запросы будут сначала разрешать доменное имя в IP-адрес с помощью встроенного DNS-сервера, а затем устанавливать соединение.
    • Например, в sockopt, если параметр domainStrategy установлен в UseIP, системные соединения, инициированные этим исходящим подключением, будут сначала разрешать доменное имя в IP-адрес с помощью встроенного DNS-сервера, а затем устанавливать соединение.

Совет 1

DNS-запросы, отправляемые встроенным DNS-сервером, автоматически перенаправляются в соответствии с конфигурацией маршрутизации.

Совет 2

Поддерживаются только базовые запросы IP-адресов (записи A и AAAA). Записи CNAME будут запрашиваться повторно до тех пор, пока не будет возвращена запись A/AAAA. Другие запросы не обрабатываются встроенным DNS-сервером.

Процесс обработки DNS-запросов

Если запрашиваемое доменное имя:

  • Соответствует сопоставлению "домен - IP" или "домен - массив IP" в hosts, то этот IP-адрес или массив IP-адресов возвращается в качестве результата DNS-разрешения.
  • Соответствует сопоставлению "домен - домен" в hosts, то значение этого сопоставления (другой домен) используется в качестве текущего запрашиваемого доменного имени, и процесс обработки DNS-запросов продолжается до тех пор, пока не будет разрешен IP-адрес или не будет возвращен пустой результат.
  • Не соответствует hosts, но соответствует списку доменов domains одного (или нескольких) DNS-серверов, то запросы отправляются на соответствующие DNS-серверы в порядке приоритета.
    Если запрос к DNS-серверу завершается неудачей или expectIPs не совпадает, используется следующий подходящий DNS-сервер.
    В противном случае возвращается полученный IP-адрес.
    Если запросы ко всем подходящим DNS-серверам завершаются неудачей или expectIPs не совпадает, компонент DNS:
    • По умолчанию выполняет "резервный (fallback) запрос DNS": запросы отправляются на "DNS-серверы, которые не использовались в предыдущем раунде неудачных запросов и для которых skipFallback имеет значение по умолчанию false".
      Если запрос завершается неудачей или expectIPs не совпадает, возвращается пустой результат.
      В противном случае возвращается полученный IP-адрес.
    • Если disableFallback установлен в true, "резервный (fallback) запрос DNS" не выполняется.
  • Не соответствует hosts и не соответствует списку доменов domains ни одного DNS-сервера, то:
    • По умолчанию запросы отправляются на "DNS-серверы, для которых skipFallback имеет значение по умолчанию false".
      Если запрос к первому выбранному DNS-серверу завершается неудачей или expectIPs не совпадает, используется следующий выбранный DNS-сервер.
      В противном случае возвращается полученный IP-адрес.
      Если запросы ко всем выбранным DNS-серверам завершаются неудачей или expectIPs не совпадает, возвращается пустой результат.
    • Если количество "DNS-серверов, для которых skipFallback имеет значение по умолчанию false", равно 0 или disableFallback установлен в true, используется первый DNS-сервер в конфигурации DNS.
      Если запрос завершается неудачей или expectIPs не совпадает, возвращается пустой результат.
      В противном случае возвращается полученный IP-адрес.

DnsObject

DnsObject соответствует полю dns в конфигурационном файле.

{
@@ -116,6 +116,6 @@
   "clientIP": "1.2.3.4"
 }
 

address: address

Адрес DNS-сервера.
Поддерживаются два типа: адрес DNS (в виде строки) и ServerObject.

Значение "localhost" означает использование локальных настроек DNS.

Если значение - это адрес DNS "IP", например "8.8.8.8", Xray будет использовать указанный UDP-порт этого адреса для DNS-запросов.
Запрос будет следовать правилам маршрутизации.
По умолчанию используется порт 53.

Если значение имеет вид "tcp://host", например "tcp://8.8.8.8", Xray будет использовать DNS over TCP для запросов.
Запрос будет следовать правилам маршрутизации.
По умолчанию используется порт 53.

Если значение имеет вид "tcp+local://host", например "tcp+local://8.8.8.8", Xray будет использовать локальный режим TCP (TCPL) для запросов.
Это означает, что DNS-запросы не будут проходить через компонент маршрутизации, а будут отправляться непосредственно через исходящее подключение Freedom для сокращения времени ожидания.
Если порт не указан, по умолчанию используется порт 53.

Если значение имеет вид "https://host:port/dns-query", например "https://dns.google/dns-query", Xray будет использовать DNS over HTTPS (RFC8484, сокращенно DOH) для запросов.
Некоторые провайдеры имеют сертификаты с IP-псевдонимами, поэтому можно использовать IP-адрес напрямую, например https://1.1.1.1/dns-query.
Также можно использовать нестандартные порты и пути, например "https://a.b.c.d:8443/my-dns-query".

Если значение имеет вид "https+local://host:port/dns-query", например "https+local://dns.google/dns-query", Xray будет использовать локальный режим DOH (DOHL) для запросов.
Это означает, что DOH-запросы не будут проходить через компонент маршрутизации, а будут отправляться непосредственно через исходящее подключение Freedom для сокращения времени ожидания.
Обычно этот режим подходит для использования на сервере.
Также можно использовать нестандартные порты и пути.

Если значение имеет вид "quic+local://host:port", например "quic+local://dns.adguard.com", Xray будет использовать локальный режим DOQ (DOQL) для запросов.
Это означает, что DNS-запросы не будут проходить через компонент маршрутизации, а будут отправляться непосредственно через исходящее подключение Freedom.
Этот режим требует, чтобы DNS-сервер поддерживал DNS over QUIC.
По умолчанию для запросов используется порт 853, можно использовать нестандартный порт.

Если значение равно fakedns, для запросов будет использоваться FakeDNS.

port: number

Порт DNS-сервера, например 53.
По умолчанию используется порт 53.
Этот параметр не используется в режимах DOH, DOHL, DOQL.
Нестандартный порт должен быть указан в URL.

domains: [string]

Список доменов, для которых в первую очередь будет использоваться этот сервер.
Формат доменных имен такой же, как и в конфигурации маршрутизации.

expectIPs: [string]

Список диапазонов IP-адресов, формат такой же, как и в конфигурации маршрутизации.

Если этот параметр настроен, DNS Xray будет проверять возвращаемые IP-адреса и возвращать только те, которые входят в список expectIPs.

Если этот параметр не настроен, IP-адреса возвращаются без изменений.

skipFallback: true | false

true - пропустить этот сервер при выполнении резервных (fallback) DNS-запросов, по умолчанию false (не пропускать).

- + diff --git a/ru/config/fakedns.html b/ru/config/fakedns.html index dc46c145ec..a6c28f3686 100644 --- a/ru/config/fakedns.html +++ b/ru/config/fakedns.html @@ -24,8 +24,8 @@ FakeDNS | Project X - - + +

FakeDNS

FakeDNS подменяет DNS-записи, чтобы получить целевое доменное имя, что позволяет сократить время DNS-запросов и получить целевое доменное имя при использовании прозрачного проксирования.

Внимание

FakeDNS может загрязнить локальный DNS-кэш, что может привести к "недоступности сети" после отключения Xray.

FakeDNSObject

FakeDNSObject соответствует полю fakedns в конфигурационном файле.

{
@@ -130,6 +130,6 @@
   ]
 }
 
- + diff --git a/ru/config/features/browser_dialer.html b/ru/config/features/browser_dialer.html index cdc902dcd5..b1e2eb4544 100644 --- a/ru/config/features/browser_dialer.html +++ b/ru/config/features/browser_dialer.html @@ -24,11 +24,11 @@ Browser Dialer | Project X - - + +

Warning

This translation was modified on 18 July 2024 and an updated version (20 July 2024) is available on the source page. View the original page

Browser Dialer

БЕТА v1.4.1+

Предыстория

Xray обычно использует uTLS для имитации поведения популярных браузеров, и им можно управлять с помощью настройки fingerprint. Однако отпечатки, создаваемые uTLS, являются несовершенной копией реальных, и поскольку uTLS является популярной библиотекой, они сами могут стать целью.

Итак, идея Browser DialerОткрыть в новой вкладке заключается в том, что Xray использует настоящий браузер для установления TLS-соединений. Это работает так: Xray запускает небольшой веб-сайт на localhost:8080, пользователь открывает этот веб-сайт в выбранном им браузере, а JavaScript на этой странице будет действовать как сетевой стек Xray (HTTP-клиент, TLS-клиент).

Таким образом, поведение снятия отпечатков TLS является идеальным, и поэтому может быть возможно оживить серверы, которые отлично открываются как веб-сайты в браузере, но не подключаются с использованием какого-либо программного обеспечения для проксирования.

Однако есть много недостатков:

  • Пользователь должен запускать браузер рядом с клиентом Xray только для открытия прокси-соединения.
  • Browser Dialer не должен быть туннелирован через сам прокси, иначе возникнет петля. Пользователи TUN должны быть осторожны.
  • Браузер может работать только со стандартным HTTP, что означает, что поддерживаются только WebSocket и SplitHTTP.
  • CORSОткрыть в новой вкладке необходимо учитывать при выполнении запросов с одного веб-сайта (localhost:8080) на другой (proxy.example.com:443).
  • Браузер туннелирует ваш трафик с помощью JavaScript, поэтому наблюдается значительное снижение производительности (или разрядка аккумулятора).
  • Конфигурация, используемая с Browser Dialer, не может использовать собственные заголовки SNI или хоста. SNI == host == address. Пользовательские заголовки HTTP и tlsSettings игнорируются полностью.

Конфигурация

  1. Подготовьте рабочую конфигурацию WebSocket или SplitHTTP. Помните о вышеуказанных ограничениях.
  2. Запустите Xray с помощью XRAY_BROWSER_DIALER=127.0.0.1:8080. В Windows это можно сделать как set XRAY_BROWSER_DIALER=..., а затем запустить ядро из консоли, в Linux ядро можно запустить как XRAY_BROWSER_DIALER=127.0.0.1:8080 ./xray -c config.json.
  3. Откройте браузер, который не туннелирован через прокси, или измените маршрутизацию конфигурации таким образом, чтобы домен сервера Xray переходил к freedom непосредственно с клиента. Перейдите по адресу localhost:8080 и откройте консоль разработчика с помощью F12, чтобы отслеживать ошибки.
  4. Для повышения производительности и обхода произвольных ограничений на подключение, применяемых браузером, рекомендуется включить Mux.Cool.

Внутренняя работа

  • Xray прослушивает http://127.0.0.1:8080, а браузер обращается к http://127.0.0.1:8080, чтобы загрузить JS на веб-страницу.
  • JS активно устанавливает соединение WebSocket с http://127.0.0.1:8080. Xray будет использовать это соединение для отправки инструкций, но пока оно попадает в пул соединений (реализованный как канал Go).
  • Когда необходимо установить соединение, Xray получает доступное соединение из пула и отправляет имя протокола, целевой URL-адрес и необязательные ранние данные.
  • Как только JS успешно подключается к цели, он сообщает об этом Xray и продолжает использовать это соединение для двунаправленной пересылки данных.
  • После закрытия соединения с сервером соединение с localhost также закрывается, но JS гарантирует, что всегда доступно как минимум одно незанятое соединение.

WebSocket

v1.4.1+

В соответствии с потребностями браузера механизм ранних данных был скорректирован следующим образом:

  • Заголовок ответа сервера будет содержать запрошенный Sec-WebSocket-Protocol, который также изначально obfuscates the length characteristic of the WSS handshake response.
  • Кодировка, используемая для ранних данных для браузеров, - это base64.RawURLEncoding вместо StdEncoding, и сервер сделал ее совместимой.
  • Кроме того, в связи с Xray-core#375Открыть в новой вкладке рекомендациями по ?ed=2048 этот PR также увеличил сервер MaxHeaderBytes на 4096. (Хотя, похоже, это будет работать и без модификации.)

SplitHTTP

v1.8.19+

SplitHTTP поддерживает QUIC, но также может использоваться собственный стек QUIC браузера. В Chrome это можно сделать через chrome://flags, в других браузерах он может быть уже включен или для него может потребоваться другой флаг.

В общем, tlsSettings полностью игнорируются при использовании Browser Dialer. Xray никак не контролирует, какую версию HTTP выбирает браузер.

- + diff --git a/ru/config/features/env.html b/ru/config/features/env.html index 319425655f..373e33a5c0 100644 --- a/ru/config/features/env.html +++ b/ru/config/features/env.html @@ -24,14 +24,14 @@ Переменные среды | Project X - - + +

Переменные среды

Xray предоставляет следующие переменные среды для изменения некоторых базовых настроек Xray.

Путь к файлам ресурсов

  • Название: xray.location.asset или XRAY_LOCATION_ASSET.
  • Значение по умолчанию: Определенный каталог FHSОткрыть в новой вкладке или тот же каталог, что и файл Xray.

Эта переменная среды указывает расположение папки, которая должна содержать файлы geoip.dat и geosite.dat. Если значение переменной не указано, программа будет искать файлы ресурсов в следующем порядке:

./
 /usr/local/share/xray
 /usr/share/xray
 

Расположение файла конфигурации

  • Название: xray.location.config или XRAY_LOCATION_CONFIG.
  • Значение по умолчанию: Тот же каталог, что и файл Xray.

Эта переменная среды указывает расположение папки, которая должна содержать файл config.json.

Каталог с несколькими конфигурациями

  • Название: xray.location.confdir или XRAY_LOCATION_CONFDIR.
  • Значение по умолчанию: "".

Файлы .json в этом каталоге будут читаться в порядке имен файлов как параметры конфигурации.

- + diff --git a/ru/config/features/fallback.html b/ru/config/features/fallback.html index 3a29b98e2a..249f771251 100644 --- a/ru/config/features/fallback.html +++ b/ru/config/features/fallback.html @@ -24,8 +24,8 @@ Fallback | Project X - - + +

Fallback

Fallback - одна из самых мощных функций Xray, эффективно предотвращающая активное зондирование и позволяющая свободно настраивать совместное использование нескольких служб на часто используемых портах.

Fallback обеспечивает Xray высокой степенью защиты от активного зондирования и имеет уникальный механизм резервирования первого пакета.

Fallback также может разделять трафик различных типов по пути, что позволяет совместно использовать один порт для нескольких служб.

В настоящее время вы можете использовать функцию fallback при использовании протоколов VLESS или Trojan, настроив fallbacks, и создавать очень разнообразные комбинации.

Настройка fallbacks

  "fallbacks": [
@@ -41,6 +41,6 @@
   "xver": 0
 }
 

fallbacks - это массив, здесь приведено описание конфигурации одного из его элементов.

Элемент fallbacks является необязательным и может использоваться только для комбинации транспорта TCP+TLS.

  • Если этот элемент имеет дочерние элементы, в Inbound TLS необходимо установить "alpn":["http/1.1"].

Обычно сначала нужно настроить набор резервных путей по умолчанию с опущенными или пустыми alpn и path, а затем настроить другие разделения по мере необходимости.

VLESS будет перенаправлять трафик с длиной первого пакета после дешифрования TLS менее 18 байт, неверной версией протокола или неудачной аутентификацией на адрес, указанный в dest.

Для других комбинаций транспорта необходимо удалить элемент fallbacks или все его дочерние элементы. В этом случае Fallback не будет включен, VLESS будет ждать считывания необходимой длины, а в случае неверной версии протокола или сбоя аутентификации соединение будет немедленно разорвано.

name: string

Попытка сопоставить TLS SNI (указание имени сервера), любое значение или пустая строка, по умолчанию "".

alpn: string

Попытка сопоставить результат согласования TLS ALPN, любое значение или пустая строка, по умолчанию "".

При необходимости VLESS попытается прочитать результат согласования TLS ALPN, и в случае успеха выведет в лог realAlpn =. Назначение: решает проблему несовместимости службы h2c Nginx с http/1.1, для которой в Nginx требуется написать две строки listen, по одной для 1.1 и h2c. Примечание: если в fallbacks alpn присутствует "h2", в Inbound TLS необходимо установить "alpn":["h2","http/1.1"] для поддержки доступа h2.

Подсказка

alpn, установленный в Fallback, соответствует фактически согласованному ALPN, а alpn, установленный в Inbound TLS, - это список дополнительных ALPN во время рукопожатия. Это разные вещи.

path: string

Попытка сопоставить HTTP-путь первого пакета, любое значение или пустая строка, по умолчанию пустая строка, если не пустая, то должна начинаться с /, h2c не поддерживается.

Интеллектуальность: при необходимости VLESS попытается просмотреть PATH (не более 55 байт; самый быстрый алгоритм, не выполняет полный разбор HTTP) и в случае успеха выведет в INFO-лог realPath =. Назначение: разделение трафика WebSocket или HTTP-маскировки для других входящих соединений, без лишней обработки, чистая переадресация трафика, теоретически более высокая производительность, чем у Nginx.

Примечание: входящее соединение, в котором находится fallbacks, должно быть TCP+TLS, это необходимо для разделения трафика на другие входящие соединения WS, входящие соединения, на которые разделяется трафик, не нуждаются в настройке TLS.

dest: string | number

Определяет, куда перенаправляется TCP-трафик после дешифрования TLS, в настоящее время поддерживаются два типа адресов (это поле является обязательным, иначе запуск невозможен):

  1. TCP, формат "addr:port", где addr поддерживает IPv4, доменное имя, IPv6, если указано доменное имя, TCP-соединение будет установлено напрямую (без использования встроенного DNS).
  2. Unix domain socket, формат - абсолютный путь, например, "/dev/shm/domain.socket", в начале можно добавить @ для обозначения abstractОткрыть в новой вкладке, @@ - для обозначения abstract с заполнением.

Если указан только порт, можно использовать число или строку, например, 80, "80", обычно указывает на службу http в открытом виде (addr будет дополнен до "127.0.0.1").

xver: number

Отправка PROXY protocolОткрыть в новой вкладке, специально для передачи реального исходного IP-адреса и порта запроса, заполняется версией 1 или 2, по умолчанию 0, то есть не отправляется. При необходимости рекомендуется указать 1.

В настоящее время при указании 1 или 2 функциональность полностью идентична, отличается только структура, причем первая может быть распечатана, а вторая - двоичная. Входящие TCP- и WS-соединения Xray уже поддерживают прием PROXY protocol.

Внимание

Если вы настраиваете Nginx на прием PROXY protocolОткрыть в новой вкладке, помимо установки proxy_protocol, необходимо также установить set_real_ip_from, иначе могут возникнуть проблемы.

Дополнительные замечания

  • Будет выполнено сопоставление с наиболее точным дочерним элементом, порядок дочерних элементов не имеет значения. Если настроено несколько дочерних элементов с одинаковыми alpn и path, будет использоваться последний.
  • Резервирование и разделение трафика - это переадресация на уровне TCP после дешифрования, а не на уровне HTTP, проверка PATH первого пакета выполняется только при необходимости.
  • Вы можете просмотреть больше советов и рекомендаций по использованию Fallbacks:

Теория Fallbacks В разработке

- + diff --git a/ru/config/features/multiple.html b/ru/config/features/multiple.html index e2f46b21ef..eab710d918 100644 --- a/ru/config/features/multiple.html +++ b/ru/config/features/multiple.html @@ -24,8 +24,8 @@ Настройка с помощью нескольких файлов | Project X - - + +

Настройка с помощью нескольких файлов

Программа Xray поддерживает использование нескольких файлов конфигурации.

Основная цель использования нескольких файлов конфигурации — разделение настроек модулей с разными функциями для удобства управления и обслуживания.

Эта функция в основном предназначена для обогащения экосистемы Xray. Например, для клиентских GUI обычно реализуются только фиксированные функции, такие как выбор узла, и слишком сложные конфигурации трудно реализовать графически. Можно оставить только один пользовательский каталог конфигурации confdir для настройки сложных функций. Для сценариев развертывания сервера достаточно добавить файлы в confdir для настройки различных протоколов.

Запуск с несколькими файлами

Подсказка

В информации о запуске будет указан каждый считываемый файл конфигурации. Убедитесь, что порядок считывания соответствует ожидаемому. Вы можете контролировать порядок, добавляя префиксы с номерами к именам файлов. Например, 01_имя_файла, 02_имя_файла, чем больше число, тем позже файл будет обработан.

$ xray run -confdir /etc/xray/confs
@@ -103,6 +103,6 @@
   ]
 }
 

Подсказка

Вы можете использовать команду xray run -confdir=./confs -dump для просмотра объединенной конфигурации. Однако, поскольку ядро использует формат данных protobuf, формат вывода конфигурации для параметра -dump будет отличаться.

- + diff --git a/ru/config/features/xtls.html b/ru/config/features/xtls.html index ee735fdec4..424bcb4f30 100644 --- a/ru/config/features/xtls.html +++ b/ru/config/features/xtls.html @@ -24,11 +24,11 @@ Глубокое погружение в XTLS | Project X - - + +

Глубокое погружение в XTLS

XTLS - это оригинальная технология Xray, которая является ключевым фактором высокой производительности Xray.

WIP
- + diff --git a/ru/config/inbound.html b/ru/config/inbound.html index e035b78a08..79a92b2453 100644 --- a/ru/config/inbound.html +++ b/ru/config/inbound.html @@ -24,8 +24,8 @@ Входящие подключения | Project X - - + +

Warning

This translation was modified on 16 July 2024 and an updated version (11 September 2024) is available on the source page. View the original page

Входящие подключения

Входящие подключения используются для приема данных. Доступные протоколы см. в разделе Входящие протоколы.

InboundObject

InboundObject соответствует дочернему элементу поля inbounds в конфигурационном файле.

{
@@ -68,6 +68,6 @@
   "concurrency": 3
 }
 

strategy: "always" | "random"

Стратегия выделения портов.

  • "always" - всегда выделять все указанные порты.
    Xray будет прослушивать все порты, указанные в port.
  • "random" - случайным образом открывать порты.
    Каждые refresh минут Xray будет случайным образом выбирать concurrency портов из диапазона, указанного в port, и прослушивать их.

refresh: number

Интервал обновления случайных портов в минутах.
Минимальное значение - 2, рекомендуемое значение - 5.
Этот параметр действителен только при strategy = "random".

concurrency: number

Количество случайных портов.
Минимальное значение - 1, максимальное значение - треть от диапазона портов, указанного в port.
Рекомендуемое значение - 3.

- + diff --git a/ru/config/inbounds/dokodemo.html b/ru/config/inbounds/dokodemo.html index c40b6720b0..a353d57a01 100644 --- a/ru/config/inbounds/dokodemo.html +++ b/ru/config/inbounds/dokodemo.html @@ -24,8 +24,8 @@ Dokodemo-Door | Project X - - + +

Dokodemo-Door

Dokodemo door может прослушивать локальный порт и отправлять все данные, поступающие на этот порт, на порт указанного сервера, тем самым реализуя перенаправление портов.

InboundConfigurationObject

{
@@ -49,6 +49,6 @@
   "tag": "mc"
 }
 

В этом случае ядро будет прослушивать 127.0.0.1:25565 и перенаправлять трафик через исходящее соединение по умолчанию на mc.hypixel.net:25565 (сервер MC). При подключении клиента Minecraft к 127.0.0.1:25565 будет осуществлено подключение к серверу Hypixel через прокси.

Пример настройки прозрачного прокси

Эту часть см. в разделе Руководство по настройке прозрачного прокси (TProxy).

- + diff --git a/ru/config/inbounds/http.html b/ru/config/inbounds/http.html index 4aa20a8dd8..1f635f7bbe 100644 --- a/ru/config/inbounds/http.html +++ b/ru/config/inbounds/http.html @@ -24,8 +24,8 @@ HTTP | Project X - - + +

HTTP

Протокол HTTP.

Предупреждение

Протокол HTTP не обеспечивает шифрования передачи данных, поэтому он не подходит для передачи данных через общедоступные сети и более уязвим для использования в качестве ботнета.

Использование входящих соединений http более целесообразно в локальной сети или локальной среде, где он может быть использован для прослушивания входящих подключений и предоставления локальных сервисов другим программам.

СОВЕТ 1

http proxy может проксировать только протокол tcp, протоколы семейства udp не поддерживаются.

СОВЕТ 2

Используйте следующие переменные среды в Linux, чтобы использовать глобальный HTTP-прокси в текущем сеансе (эта настройка поддерживается многими программами, но не всеми).

  • export http_proxy=http://127.0.0.1:8080/ (замените адрес на адрес вашего настроенного входящего HTTP-прокси)
  • export https_proxy=$http_proxy

InboundConfigurationObject

{
@@ -43,6 +43,6 @@
   "pass": "my-password"
 }
 

user: string

Имя пользователя, тип данных: строка. Обязательный параметр.

pass: string

Пароль, тип данных: строка. Обязательный параметр.

- + diff --git a/ru/config/inbounds/shadowsocks.html b/ru/config/inbounds/shadowsocks.html index 954b7f4514..2d84de850d 100644 --- a/ru/config/inbounds/shadowsocks.html +++ b/ru/config/inbounds/shadowsocks.html @@ -24,8 +24,8 @@ Shadowsocks | Project X - - + +

Shadowsocks

Протокол ShadowsocksОткрыть в новой вкладке, совместимый с большинством других реализаций.

Текущая совместимость:

  • Поддерживает пересылку пакетов TCP и UDP, при этом UDP можно выборочно отключить;
  • Рекомендуемые методы шифрования:
    • 2022-blake3-aes-128-gcm
    • 2022-blake3-aes-256-gcm
    • 2022-blake3-chacha20-poly1305
  • Другие методы шифрования:
    • aes-256-gcm
    • aes-128-gcm
    • chacha20-poly1305 или chacha20-ietf-poly1305
    • xchacha20-poly1305 или xchacha20-ietf-poly1305
    • none или plain

Новый формат протокола Shadowsocks 2022 повышает производительность и обеспечивает полную защиту от повторов, решая следующие проблемы безопасности старого протокола:

Предупреждение

При использовании метода шифрования "none" трафик передается в открытом виде. В целях безопасности не используйте этот метод в общедоступных сетях.

InboundConfigurationObject

{
@@ -50,6 +50,6 @@
   "email": "love@xray.com"
 }
 

Наличие этой опции означает включение многопользовательского режима.

Если method в InboundConfigurationObject не является опцией SS2022, можно указать "method" для каждого пользователя. ("method" также поддерживает только опции, не относящиеся к SS2022) и "password" (при этом "password", установленный в InboundConfigurationObject, будет игнорироваться).

Если method в InboundConfigurationObject является опцией SS2022, то из соображений безопасности больше не поддерживается установка "method" для отдельных пользователей, используется единый "method", указанный в InboundConfigurationObject.

Обратите внимание, что SS2022, в отличие от старого SS, не игнорирует "password" верхнего уровня, правильный способ записи пароля клиента: ServerPassword:UserPassword. Например: "password": "114514:1919810"

Остальные опции имеют то же значение, что и в InboundConfigurationObject.

- + diff --git a/ru/config/inbounds/socks.html b/ru/config/inbounds/socks.html index 7767b965c6..c777e551e1 100644 --- a/ru/config/inbounds/socks.html +++ b/ru/config/inbounds/socks.html @@ -24,8 +24,8 @@ Socks | Project X - - + +

Warning

This translation was modified on 16 July 2024 and an updated version (15 August 2024) is available on the source page. View the original page

Socks

Стандартная реализация протокола Socks, совместимая с Socks 4Открыть в новой вкладке, Socks 4aОткрыть в новой вкладке и Socks 5.

Предупреждение

Протокол Socks не обеспечивает шифрование передачи данных, поэтому он не подходит для передачи данных через общедоступные сети.

Использование входящих соединений SOCKS более целесообразно в локальной сети или локальной среде, где он может быть использован для прослушивания входящих подключений и предоставления локальных сервисов другим программам.

InboundConfigurationObject

{
@@ -45,6 +45,6 @@
   "pass": "my-password"
 }
 

user: string

Имя пользователя, тип данных: строка. Обязательный параметр.

pass: string

Пароль, тип данных: строка. Обязательный параметр.

- + diff --git a/ru/config/inbounds/trojan.html b/ru/config/inbounds/trojan.html index 3d1f265957..2dd388d0a6 100644 --- a/ru/config/inbounds/trojan.html +++ b/ru/config/inbounds/trojan.html @@ -24,8 +24,8 @@ Trojan | Project X - - + +

Trojan

Протокол TrojanОткрыть в новой вкладке.

Предупреждение

Trojan предназначен для работы в правильно настроенном зашифрованном TLS-туннеле.

InboundConfigurationObject

{
@@ -48,6 +48,6 @@
   "level": 0
 }
 

password: string

Обязательный параметр, любая строка.

email: string

Адрес электронной почты, необязательный параметр, используется для идентификации пользователя.

Предупреждение

Если существует несколько объектов ClientObject, убедитесь, что адреса электронной почты не дублируются.

level: number

Уровень пользователя, для соединения будет использоваться локальная политика, соответствующая этому уровню пользователя.

Значение userLevel соответствует значению level в разделе policy. Если не указано, используется значение по умолчанию - 0.

- + diff --git a/ru/config/inbounds/vless.html b/ru/config/inbounds/vless.html index dc22b4098b..7206119fae 100644 --- a/ru/config/inbounds/vless.html +++ b/ru/config/inbounds/vless.html @@ -24,8 +24,8 @@ VLESS | Project X - - + +

Warning

This translation was modified on 27 July 2024 and an updated version (7 August 2024) is available on the source page. View the original page

VLESS

Предупреждение

VLESS не предусматривает встроенного шифрования, поэтому обязательным условием для его использования является наличие надежного канала, такого как TLS или REALITY.

VLESS - это легкий транспортный протокол без сохранения состояния, который разделен на входящую и исходящую части и может служить мостом между клиентом и сервером Xray.

В отличие от VMess, VLESS не зависит от системного времени, аутентификация также осуществляется с помощью UUID.

InboundConfigurationObject

{
@@ -51,6 +51,6 @@
   "flow": "xtls-rprx-vision"
 }
 

id: string

Идентификатор пользователя VLESS, может быть любой строкой длиной менее 30 байт или допустимым UUID. Пользовательская строка и ее UUID-отображение эквивалентны, это означает, что вы можете использовать следующие способы записи id в файле конфигурации для идентификации одного и того же пользователя:

  • Напишите "id": "Я люблю арбуз учителя 1314",
  • Или напишите "id": "5783a3e7-e373-51cd-8642-c83782b807c5" (этот UUID является UUID-отображением строки "Я люблю арбуз учителя 1314")

Стандарт сопоставления описан в VLESS UUID Mapping Standard: Mapping Custom Strings to a UUIDv5Открыть в новой вкладке.

Вы можете использовать команду xray uuid -i "Пользовательская строка" для генерации UUID, соответствующего пользовательской строке.

Вы также можете использовать команду xray uuid для генерации случайного UUID.

level: number

Уровень пользователя, для подключения будет использоваться локальная политика, соответствующая этому уровню пользователя.

Значение level соответствует значению level в разделе policy. Если не указано, используется значение по умолчанию - 0.

email: string

Адрес электронной почты пользователя, используется для разделения трафика разных пользователей (отображается в журналах, статистике).

flow: string

Режим управления потоком, используется для выбора алгоритма XTLS.

В настоящее время для входящего протокола доступны следующие режимы управления потоком:

  • Отсутствует flow или пустая строка: используется обычный TLS-прокси
  • xtls-rprx-vision: используется новый режим XTLS, включает случайное заполнение внутреннего рукопожатия

Кроме того, в настоящее время XTLS поддерживает только TCP+TLS/Reality.

- + diff --git a/ru/config/inbounds/vmess.html b/ru/config/inbounds/vmess.html index 748c36811f..c158094aac 100644 --- a/ru/config/inbounds/vmess.html +++ b/ru/config/inbounds/vmess.html @@ -24,8 +24,8 @@ VMess | Project X - - + +

VMess

VMess - это зашифрованный транспортный протокол, который обычно используется в качестве моста между клиентами и серверами Xray.

Предупреждение

VMess полагается на системное время. Убедитесь, что системное время UTC, используемое Xray, находится в пределах 120 секунд от фактического времени, независимо от часового пояса. В системах Linux вы можете установить службу ntp для автоматической синхронизации системного времени.

InboundConfigurationObject

{
@@ -55,6 +55,6 @@
   "level": 0
 }
 

level: number

Уровень пользователя, который будет использоваться соединением для определения соответствующей локальной политики.

Значение level соответствует значению level в policy. Если не указано, используется значение по умолчанию - 0.

- + diff --git a/ru/config/inbounds/wireguard.html b/ru/config/inbounds/wireguard.html index eedfc0ce84..92a462516a 100644 --- a/ru/config/inbounds/wireguard.html +++ b/ru/config/inbounds/wireguard.html @@ -24,8 +24,8 @@ Wireguard | Project X - - + +

Wireguard

User-space implementation of the Wireguard protocol.

Предупреждение

The Wireguard protocol is not specifically designed for circumvention purposes. If used as the outer layer for circumvention, its characteristics may lead to server blocking.

InboundConfigurationObject

{
@@ -51,6 +51,6 @@
   "allowedIPs": ["0.0.0.0/0"] // optional, default ["0.0.0.0/0", "::/0"]
 }
 

publicKey: string

Public key, used for verification.

allowedIPs: string array

Allowed source IPs.

- + diff --git a/ru/config/index.html b/ru/config/index.html index dfe65292cb..e5f7bb5ce5 100644 --- a/ru/config/index.html +++ b/ru/config/index.html @@ -24,8 +24,8 @@ Конфигурационный файл | Project X - - + +

В этом разделе вы узнаете все детали настройки Xray. Овладев этими знаниями, вы сможете раскрыть весь потенциал Xray.

Обзор

Конфигурационный файл Xray имеет формат JSON. Формат конфигурации одинаков для клиента и сервера, но фактическое содержимое отличается.
Он выглядит следующим образом:

{
@@ -45,6 +45,6 @@
   "burstObservatory": {}
 }
 

Внимание

Если вы новичок в Xray, вы можете сначала прочитать раздел Настройка и запуск в кратком руководстве, чтобы узнать об основных способах настройки, а затем прочитать этот раздел, чтобы узнать обо всех способах настройки Xray.

Основные модули конфигурации

log: LogObject

Настройка журнала, управляющая способом вывода журналов Xray.

api: ApiObject

Предоставляет API-интерфейсы для удаленного вызова.

dns: DnsObject

Встроенный DNS-сервер. Если этот параметр не настроен, используются системные настройки DNS.

routing: RoutingObject

Функция маршрутизации. Позволяет настроить правила для разделения трафика и отправки его через разные исходящие подключения.

policy: PolicyObject

Локальная политика, позволяющая настроить разные уровни пользователей и соответствующие им политики.

inbounds: [ InboundObject ]

Массив, каждый элемент которого представляет собой конфигурацию входящего подключения.

outbounds: [ OutboundObject ]

Массив, каждый элемент которого представляет собой конфигурацию исходящего подключения.

transport: TransportObject

Используется для настройки способа, которым Xray устанавливает и использует сетевые подключения к другим серверам.

stats: StatsObject

Используется для настройки сбора статистики трафика.

reverse: ReverseObject

Обратный прокси. Позволяет перенаправлять трафик с сервера на клиент, т.е. перенаправлять трафик в обратном направлении.

fakedns: FakeDnsObject

Настройка FakeDNS. Может использоваться совместно с прозрачным проксированием для получения фактических доменных имен.

metrics: metricsObject

Настройка метрик. Более прямой (и, надеемся, лучший) способ экспорта статистики.

observatory: ObservatoryObject

Мониторинг фоновых подключений. Обнаружение состояния подключения исходящего прокси.

burstObservatory: BurstObservatoryObject

Мониторинг параллельных подключений. Обнаружение состояния подключения исходящего прокси.

- + diff --git a/ru/config/log.html b/ru/config/log.html index 62b407a410..e489e06156 100644 --- a/ru/config/log.html +++ b/ru/config/log.html @@ -24,8 +24,8 @@ Настройка журнала | Project X - - + +

Warning

This translation was modified on 16 July 2024 and an updated version (11 September 2024) is available on the source page. View the original page

Настройка журнала

Настройка журнала управляет тем, как Xray выводит журналы.

Xray имеет два типа журналов: журнал доступа и журнал ошибок.
Вы можете настроить способ вывода каждого типа журнала отдельно.

LogObject

LogObject соответствует полю log в конфигурационном файле.

{
@@ -37,6 +37,6 @@
   }
 }
 

access: string

Путь к файлу журнала доступа.
Значение должно быть допустимым путем к файлу, например "/var/log/Xray/access.log" (Linux) или "C:\\Temp\\Xray\\_access.log" (Windows).
Если этот параметр не указан или имеет пустое значение, журнал выводится в stdout.

  • Специальное значение none отключает журнал доступа.

error: string

Путь к файлу журнала ошибок.
Значение должно быть допустимым путем к файлу, например "/var/log/Xray/error.log" (Linux) или "C:\\Temp\\Xray\\_error.log" (Windows).
Если этот параметр не указан или имеет пустое значение, журнал выводится в stdout.

  • Специальное значение none отключает журнал ошибок.

loglevel: "debug" | "info" | "warning" | "error" | "none"

Уровень журнала ошибок, указывающий, какую информацию следует записывать в журнал ошибок.
Значение по умолчанию - "warning".

  • "debug": информация, используемая при отладке программы.
    Включает всю информацию уровня "info".
  • "info": информация о состоянии во время выполнения и т.д., не влияющая на нормальную работу.
    Включает всю информацию уровня "warning".
  • "warning": информация, выводимая при возникновении проблем, не влияющих на нормальную работу, но которые могут повлиять на работу пользователя.
    Включает всю информацию уровня "error".
  • "error": Xray столкнулся с проблемой, которая не позволяет ему работать нормально, и ее необходимо немедленно решить.
  • "none": не записывать ничего.

dnsLog: bool

Включить ведение журнала DNS-запросов, например: DOH//doh.server got answer: domain.com -> [ip1, ip2] 2.333ms.

- + diff --git a/ru/config/metrics.html b/ru/config/metrics.html index 81d569733f..3d6030db7a 100644 --- a/ru/config/metrics.html +++ b/ru/config/metrics.html @@ -24,8 +24,8 @@ Метрики | Project X - - + +

Метрики

Более простой (и, надеюсь, лучший) способ экспорта статистики.

Связанные настройки

Можно добавить входящее подключение metrics в раздел inbounds:

    "inbounds": [
@@ -242,6 +242,6 @@
            id: udp
            expvar_type: int
 

И вы получите красивый график, подобный этому:

160428235-2988bf69-5d6c-41ec-8267-1bd512508aa8

Дополнительно

Возможно, лучше использовать пустой объект stats в конфигурационном файле, чем добавлять metrics?

Изменение: удалены настройки, связанные с Prometheus, и добавлено использование expvars.

- + diff --git a/ru/config/observatory.html b/ru/config/observatory.html index a40065e570..ec719c9320 100644 --- a/ru/config/observatory.html +++ b/ru/config/observatory.html @@ -24,8 +24,8 @@ Мониторинг подключений | Project X - - + +

Мониторинг подключений

Компонент мониторинга подключений использует HTTP-пинги для проверки состояния подключения исходящих прокси. Результаты мониторинга могут использоваться другими компонентами, например, балансировщиком нагрузки.
В настоящее время доступны два режима: observatory (фоновый мониторинг подключений) и burstObservatory (мониторинг параллельных подключений).
Выберите один из них в соответствии с вашими потребностями.

ObservatoryObject

{
@@ -50,6 +50,6 @@
   "timeout": "30s"
 }
 

destination: string

URL-адрес, используемый для проверки состояния подключения исходящего прокси.
Этот URL-адрес должен возвращать код состояния HTTP 204.

connectivity: string

URL-адрес, используемый для проверки подключения к локальной сети.
Пустая строка означает, что проверка подключения к локальной сети не выполняется.

interval: string

Проверить все соответствующие исходящие прокси в течение указанного времени, отправляя sampling + 1 запросов на каждый прокси.
Формат времени: число + единица измерения, например "10s", "2h45m".
Поддерживаемые единицы измерения: ns, us, ms, s, m, h (наносекунды, микросекунды, миллисекунды, секунды, минуты, часы).

sampling: number

Количество последних результатов проверок, которые нужно сохранить.

timeout: string

Время ожидания ответа при проверке.
Формат такой же, как и у interval.

- + diff --git a/ru/config/outbound.html b/ru/config/outbound.html index c2f7eec072..9a08207491 100644 --- a/ru/config/outbound.html +++ b/ru/config/outbound.html @@ -24,8 +24,8 @@ Исходящие подключения | Project X - - + +

Исходящие подключения

Исходящие подключения используются для отправки данных. Доступные протоколы см. в разделе Исходящие протоколы.

OutboundObject

OutboundObject соответствует дочернему элементу поля outbounds в конфигурационном файле.

Подсказка

Первый элемент в списке используется как основной исходящий узел.
Если совпадений с правилами маршрутизации нет или ни одно правило не сработало, трафик отправляется через основной исходящий узел.

{
@@ -53,6 +53,6 @@
   "xudpProxyUDP443": "reject"
 }
 

enabled: true | false

Включить пересылку запросов через Mux.
Значение по умолчанию - false.

concurrency: number

Максимальное количество одновременных подключений.
Минимальное значение - 1, максимальное значение - 1024.
Если этот параметр опущен или равен 0, используется значение 8.

Это значение определяет максимальное количество дочерних соединений, которые могут быть мультиплексированы по одному TCP-соединению.
Например, если concurrency равен 8, то при отправке 8 TCP-запросов клиентом Xray создаст только одно фактическое TCP-соединение, и все 8 запросов клиента будут передаваться по этому соединению.

Подсказка

Если указать отрицательное значение, например -1, трафик TCP не будет проходить через Mux.

xudpConcurrency: number

Использовать новый агрегированный туннель XUDP (т.е. другое Mux-соединение) для проксирования UDP-трафика.
Укажите максимальное количество одновременных дочерних UoT-подключений.
Минимальное значение - 1, максимальное значение - 1024.
Если этот параметр опущен или равен 0, UDP-трафик будет использовать тот же путь, что и TCP-трафик (традиционное поведение).

Подсказка

Если указать отрицательное значение, например -1, трафик UDP не будет проходить через Mux.
Будет использоваться исходный способ передачи UDP-трафика для данного протокола прокси.
Например, Shadowsocks будет использовать нативный UDP, а VLESS будет использовать UoT.

xudpProxyUDP443: string

Управление обработкой проксируемого трафика UDP/443 (QUIC) в Mux:

  • По умолчанию reject - отклонять трафик (обычно браузеры автоматически переключаются на TCP HTTP/2).
  • allow - разрешить трафик через Mux.
  • skip - не использовать Mux для трафика UDP/443.
    Будет использоваться исходный способ передачи UDP-трафика для данного протокола прокси.
    Например, Shadowsocks будет использовать нативный UDP, а VLESS будет использовать UoT.
- + diff --git a/ru/config/outbounds/blackhole.html b/ru/config/outbounds/blackhole.html index 1c83065b6f..e37f511b5d 100644 --- a/ru/config/outbounds/blackhole.html +++ b/ru/config/outbounds/blackhole.html @@ -24,8 +24,8 @@ Blackhole | Project X - - + +

Blackhole

Blackhole - это протокол исходящих данных, который блокирует все исходящие данные. В сочетании с конфигурацией маршрутизации он может быть использован для запрета доступа к определенным сайтам.

OutboundConfigurationObject

{
@@ -37,6 +37,6 @@
   "type": "none"
 }
 

type: "http" | "none"

Если type равен "none" (значение по умолчанию), Blackhole просто закроет соединение.

Если type равен "http", Blackhole вернет простой пакет HTTP 403, а затем закроет соединение.

- + diff --git a/ru/config/outbounds/dns.html b/ru/config/outbounds/dns.html index 917e5adc4a..0e0e721bcc 100644 --- a/ru/config/outbounds/dns.html +++ b/ru/config/outbounds/dns.html @@ -24,8 +24,8 @@ DNS | Project X - - + +

Warning

This translation was modified on 16 July 2024 and an updated version (15 September 2024) is available on the source page. View the original page

DNS

DNS — это исходящий протокол, который в основном используется для перехвата и пересылки DNS-запросов.

Этот исходящий протокол может принимать только DNS-трафик (включая запросы по протоколам UDP и TCP), другие типы трафика будут вызывать ошибки.

При обработке DNS-запросов этот исходящий протокол перенаправляет IP-запросы (то есть A и AAAA) на встроенный DNS-сервер. Другие типы запросов будут перенаправлены на их исходные адреса назначения.

OutboundConfigurationObject

{
@@ -35,6 +35,6 @@
   "nonIPQuery": "drop"
 }
 

network: "tcp" | "udp"

Изменяет транспортный протокол DNS-трафика, возможные значения: "tcp" и "udp". Если не указан, сохраняется исходный транспортный протокол.

address: address

Изменяет адрес DNS-сервера. Если не указан, сохраняется адрес, указанный в источнике.

port: number

Изменяет порт DNS-сервера. Если не указан, сохраняется порт, указанный в источнике.

nonIPQuery: string

Управляет не IP-запросами (не A и AAAA), "drop" - отбрасывать или "skip" - не обрабатывать встроенным DNS-сервером, а пересылать на целевой сервер. Значение по умолчанию: "drop".

Пример настройки DNS WIP

- + diff --git a/ru/config/outbounds/freedom.html b/ru/config/outbounds/freedom.html index 835bb8a53f..2ce1526d11 100644 --- a/ru/config/outbounds/freedom.html +++ b/ru/config/outbounds/freedom.html @@ -24,8 +24,8 @@ Freedom | Project X - - + +

Warning

This translation was modified on 16 July 2024 and an updated version (17 September 2024) is available on the source page. View the original page

Freedom

Freedom - это исходящий протокол, который можно использовать для отправки (обычных) данных TCP или UDP в любую сеть.

OutboundConfigurationObject

{
@@ -40,6 +40,6 @@
   "proxyProtocol": 0
 }
 

domainStrategy: "AsIs"
"UseIP" | "UseIPv6v4" | "UseIPv6" | "UseIPv4v6" | "UseIPv4"
"ForceIP" | "ForceIPv6v4" | "ForceIPv6" | "ForceIPv4v6" | "ForceIPv4"

Значение по умолчанию: "AsIs".

Если целевой адрес является доменным именем, настройте соответствующее значение для режима работы Freedom:

  • При использовании "AsIs" Xray будет напрямую использовать системный стек для установления соединения, приоритет и выбор IP будут зависеть от системных настроек. По некоторым причинам UDP-соединения, использующие доменные имена, будут игнорировать системные настройки и отдавать приоритет IPv4.
  • При указании других значений для разрешения будет использоваться встроенный DNS-сервер Xray-core. Если DNSObject отсутствует, будет использоваться системный DNS. Если существует несколько подходящих IP-адресов, ядро случайным образом выберет один IP-адрес в качестве целевого.
  • "IPv4" означает попытку подключения только с использованием IPv4, "IPv4v6" - попытку подключения с использованием IPv4 или IPv6, но с предпочтением IPv4 для доменных имен с поддержкой обоих протоколов. (То же самое относится и к v4v6, но в обратном порядке, поэтому здесь не приводится).
  • Если в настройках встроенного DNS указан параметр "queryStrategy", фактическое поведение будет объединено с этой опцией, и будут разрешаться только те типы IP, которые включены в обе опции. Например, "queryStrategy": "UseIPv4" и "domainStrategy": "UseIP" фактически эквивалентны "domainStrategy": "UseIPv4".
  • При использовании опций, начинающихся с "Use", если результаты разрешения не соответствуют требованиям (например, доменное имя имеет только результат разрешения IPv4, но используется UseIPv6), будет выполнен откат к AsIs.
  • При использовании опций, начинающихся с "Force", если результаты разрешения не соответствуют требованиям, соединение не будет установлено.

СОВЕТ 1

При использовании режимов "UseIP" или "ForceIP" и указании sendThrough в конфигурации исходящего соединения Freedom будет автоматически определять необходимый тип IP (IPv4 или IPv6) на основе значения sendThrough. Если вручную указать один тип IP (например, UseIPv4), но он не совпадает с локальным адресом, указанным в sendThrough, соединение не будет установлено.

redirect: адрес_порт

Freedom будет принудительно отправлять все данные на указанный адрес (а не на адрес, указанный во входящем соединении).

Его значение представляет собой строку, например: "127.0.0.1:80", ":1234".

Если адрес не указан, например, ":443", Freedom не будет изменять исходный целевой адрес. Если порт равен 0, например, "xray.com: 0", Freedom не будет изменять исходный порт.

userLevel: number

Уровень пользователя, для соединения будет использоваться локальная политика, соответствующая этому уровню пользователя.

Значение userLevel соответствует значению level в разделе policy. Если не указано, используется значение по умолчанию - 0.

fragment: map

Некоторые пары "ключ-значение" для управления исходящей TCP-фрагментацией, которые в некоторых случаях могут обмануть систему цензуры, например, обойти черный список SNI.

"packets": поддерживаются два режима фрагментации: "1-3" - это фрагментация потока TCP, применяемая к первым трем операциям записи данных на стороне клиента. "tlshello" - это фрагментация пакета TLS-рукопожатия.

"length": длина фрагмента пакета (в байтах).

"interval": интервал фрагментации (в миллисекундах).

proxyProtocol: number

Протокол PROXY обычно используется в сочетании с redirect для перенаправления на Nginx или другой сервер, на котором включен протокол PROXY. Если сервер не поддерживает протокол PROXY, соединение будет разорвано.

Значение proxyProtocol - это номер версии протокола PROXY, возможные значения: 1 или 2. Если не указано, используется значение по умолчанию - 0 (протокол не используется).

- + diff --git a/ru/config/outbounds/http.html b/ru/config/outbounds/http.html index d2d00af760..9224f1efaa 100644 --- a/ru/config/outbounds/http.html +++ b/ru/config/outbounds/http.html @@ -24,8 +24,8 @@ HTTP | Project X - - + +

HTTP

Протокол HTTP.

Предупреждение

Протокол HTTP не обеспечивает шифрования передачи, что делает его непригодным для передачи по общедоступным сетям и более уязвимым для использования в качестве скомпрометированного хоста для атак.

Подсказка

HTTP может проксировать только протоколы TCP и не может обрабатывать протоколы на основе UDP.

OutboundConfigurationObject

{
@@ -61,6 +61,6 @@
   "pass": "my-password"
 }
 

user: string

Имя пользователя, тип данных: строка. Обязательный параметр.

pass: string

Пароль, тип данных: строка. Обязательный параметр.

- + diff --git a/ru/config/outbounds/loopback.html b/ru/config/outbounds/loopback.html index 4c443678b4..95d9062737 100644 --- a/ru/config/outbounds/loopback.html +++ b/ru/config/outbounds/loopback.html @@ -24,8 +24,8 @@ Loopback | Project X - - + +

Loopback

Loopback - это исходящий протокол данных, который перенаправляет данные, прошедшие через это исходящее соединение, обратно на вход маршрутизатора, что позволяет повторно обработать данные по правилам маршрутизации, не покидая Xray-core.

OutboundConfigurationObject

{
@@ -65,6 +65,6 @@
   }
 }
 
- + diff --git a/ru/config/outbounds/shadowsocks.html b/ru/config/outbounds/shadowsocks.html index 0174a1895f..f56d618f93 100644 --- a/ru/config/outbounds/shadowsocks.html +++ b/ru/config/outbounds/shadowsocks.html @@ -24,8 +24,8 @@ Shadowsocks | Project X - - + +

Shadowsocks

Протокол ShadowsocksОткрыть в новой вкладке, совместимый с большинством других реализаций.

Текущая совместимость:

  • Поддерживает пересылку пакетов TCP и UDP, при этом UDP можно выборочно отключить;
  • Рекомендуемые методы шифрования:
    • 2022-blake3-aes-128-gcm
    • 2022-blake3-aes-256-gcm
    • 2022-blake3-chacha20-poly1305
  • Другие методы шифрования:
    • aes-256-gcm
    • aes-128-gcm
    • chacha20-poly1305 или chacha20-ietf-poly1305
    • xchacha20-poly1305 или xchacha20-ietf-poly1305
    • none или plain

Новый формат протокола Shadowsocks 2022 повышает производительность и обеспечивает полную защиту от повторов, решая следующие проблемы безопасности старого протокола:

Предупреждение

При использовании метода шифрования "none" трафик передается в открытом виде. В целях безопасности не используйте этот метод в общедоступных сетях.

OutboundConfigurationObject

{
@@ -53,6 +53,6 @@
   "level": 0
 }
 

email: string

Адрес электронной почты, необязательный параметр, используется для идентификации пользователя.

address: address

Адрес сервера Shadowsocks, поддерживаются IPv4, IPv6 и доменные имена. Обязательный параметр.

port: number

Порт сервера Shadowsocks. Обязательный параметр.

method: string

Обязательный параметр.

password: string

Обязательный параметр.

uot: bool

Включить udp over tcp.

UoTVersion: number

Версия реализации UDP over TCP.

Допустимые значения: 1, 2.

  • Shadowsocks 2022

В качестве пароля используется предварительный общий ключ, аналогичный ключам WireGuard.

Используйте openssl rand -base64 <длина>, чтобы сгенерировать ключ, совместимый с shadowsocks-rust, длина зависит от используемого метода шифрования.

Метод шифрованияДлина ключа
2022-blake3-aes-128-gcm16
2022-blake3-aes-256-gcm32
2022-blake3-chacha20-poly130532

В реализации Go всегда работают 32-битные ключи.

  • Другие методы шифрования

Любая строка. Длина пароля не ограничена, но короткие пароли более уязвимы для взлома, рекомендуется использовать пароли длиной 16 символов или более.

level: number

Уровень пользователя, для соединения будет использоваться локальная политика, соответствующая этому уровню пользователя.

Значение level соответствует значению level в разделе policy. Если не указано, используется значение по умолчанию - 0.

- + diff --git a/ru/config/outbounds/socks.html b/ru/config/outbounds/socks.html index 83c71e6b37..3d5500fc73 100644 --- a/ru/config/outbounds/socks.html +++ b/ru/config/outbounds/socks.html @@ -24,8 +24,8 @@ Socks | Project X - - + +

Socks

Стандартная реализация протокола Socks, совместимая с Socks 4Открыть в новой вкладке, Socks 4aОткрыть в новой вкладке и Socks 5.

Предупреждение

Протокол Socks не обеспечивает шифрования передачи, поэтому он не подходит для передачи данных через общедоступные сети.

OutboundConfigurationObject

{
@@ -60,6 +60,6 @@
   "level": 0
 }
 

user: string

Имя пользователя, тип данных: строка. Обязательный параметр.

pass: string

Пароль, тип данных: строка. Обязательный параметр.

level: number

Уровень пользователя, для соединения будет использоваться локальная политика, соответствующая этому уровню пользователя.

Значение userLevel соответствует значению level в разделе policy. Если не указано, используется значение по умолчанию - 0.

- + diff --git a/ru/config/outbounds/trojan.html b/ru/config/outbounds/trojan.html index 653b9ac29e..b51be871e4 100644 --- a/ru/config/outbounds/trojan.html +++ b/ru/config/outbounds/trojan.html @@ -24,8 +24,8 @@ Trojan | Project X - - + +

Trojan

Протокол TrojanОткрыть в новой вкладке.

Предупреждение

Trojan предназначен для работы в правильно настроенном зашифрованном TLS-туннеле.

OutboundConfigurationObject

{
@@ -47,6 +47,6 @@
   "level": 0
 }
 

address: address

Адрес сервера, поддерживаются IPv4, IPv6 и доменные имена. Обязательный параметр.

port: number

Порт сервера, обычно тот же, что и порт, прослушиваемый сервером.

password: string

Пароль. Обязательный параметр, любая строка.

email: string

Адрес электронной почты, необязательный параметр, используется для идентификации пользователя.

level: number

Уровень пользователя, для соединения будет использоваться локальная политика, соответствующая этому уровню пользователя.

Значение level соответствует значению level в разделе policy. Если не указано, используется значение по умолчанию - 0.

- + diff --git a/ru/config/outbounds/vless.html b/ru/config/outbounds/vless.html index eea3a6ed5f..07bc8c8ac9 100644 --- a/ru/config/outbounds/vless.html +++ b/ru/config/outbounds/vless.html @@ -24,8 +24,8 @@ VLESS | Project X - - + +

Warning

This translation was modified on 27 July 2024 and an updated version (7 August 2024) is available on the source page. View the original page

VLESS

Предупреждение

VLESS не предусматривает встроенного шифрования, поэтому обязательным условием для его использования является наличие надежного канала, такого как TLS или REALITY.

VLESS - это легкий транспортный протокол без сохранения состояния, который разделен на входящую и исходящую части и может служить мостом между клиентом и сервером Xray.

В отличие от VMess, VLESS не зависит от системного времени, аутентификация также осуществляется с помощью UUID.

OutboundConfigurationObject

{
@@ -63,6 +63,6 @@
   "level": 0
 }
 

id: string

Идентификатор пользователя VLESS, может быть любой строкой длиной менее 30 байт или допустимым UUID. Пользовательская строка и ее UUID-отображение эквивалентны, это означает, что вы можете использовать следующие способы записи id в файле конфигурации для идентификации одного и того же пользователя:

  • Напишите "id": "Я люблю арбуз учителя 1314",
  • Или напишите "id": "5783a3e7-e373-51cd-8642-c83782b807c5" (этот UUID является UUID-отображением строки "Я люблю арбуз учителя 1314")

Стандарт сопоставления описан в VLESS UUID Mapping Standard: Mapping Custom Strings to a UUIDv5Открыть в новой вкладке.

Вы можете использовать команду xray uuid -i "Пользовательская строка" для генерации UUID, соответствующего пользовательской строке. Вы также можете использовать команду xray uuid для генерации случайного UUID.

encryption: "none"

Необходимо указать "none", значение не может быть пустым.

Это требование призвано напомнить пользователю об отсутствии шифрования, а также предотвратить ошибки пользователей при вводе имени атрибута или его расположения в будущем, когда будут доступны методы шифрования.

Если значение encryption установлено неверно, при использовании Xray или -test будет выдано сообщение об ошибке.

flow: string

Режим управления потоком, используется для выбора алгоритма XTLS.

В настоящее время для исходящего протокола доступны следующие режимы управления потоком:

  • Отсутствует flow или пустая строка: используется обычный TLS-прокси.
  • xtls-rprx-vision: используется новый режим XTLS, включает случайное заполнение внутреннего рукопожатия, поддерживает uTLS для имитации отпечатка клиента.
  • xtls-rprx-vision-udp443: аналогично xtls-rprx-vision, но разрешает UDP-трафик, направленный на порт 443.

Кроме того, в настоящее время XTLS поддерживает только TCP+TLS/Reality.

О режимах управления потоком xtls-rprx-*-udp443

Когда XTLS в Xray-core включен, трафик, направленный на UDP-порт 443 (обычно QUIC), по умолчанию блокируется, чтобы приложение не использовало QUIC, а использовало TLS, чтобы XTLS действительно вступил в силу. Фактически, QUIC сам по себе не подходит для проксирования, поскольку QUIC имеет встроенные функции TCP, и когда он передается по протоколу VLESS как UDP-трафик, базовый протокол - TCP, что эквивалентно двум уровням TCP.

Если блокировка не требуется, укажите xtls-rprx-*-udp443 на стороне клиента, на стороне сервера оставляйте без изменений.

О режиме Splice

Splice - это функция, предоставляемая ядром Linux, где ядро системы напрямую пересылает TCP, минуя память Xray, что значительно сокращает количество операций копирования данных и переключения контекста процессора.

Ограничения использования режима Splice:

  • Среда Linux.
  • Входящий протокол: Dokodemo door, Socks, HTTP и другие чистые TCP-соединения или другие входящие протоколы, использующие XTLS.
  • Исходящий протокол: VLESS + XTLS.
  • Обратите внимание, что при использовании протокола mKCP Splice не будет использоваться (да, хотя ошибки и нет, на самом деле он не используется).

Кроме того, при использовании Splice отображение скорости сети будет запаздывать, это особенность, а не ошибка.

При использовании режима Vision Splice будет включен автоматически, если выполнены вышеуказанные условия.

level: number

Уровень пользователя, для соединения будет использоваться локальная политика, соответствующая этому уровню пользователя.

Значение level соответствует значению level в разделе policy. Если не указано, используется значение по умолчанию - 0.

- + diff --git a/ru/config/outbounds/vmess.html b/ru/config/outbounds/vmess.html index 0a8570b0c8..fb498501aa 100644 --- a/ru/config/outbounds/vmess.html +++ b/ru/config/outbounds/vmess.html @@ -24,8 +24,8 @@ VMess | Project X - - + +

VMess

VMess - это зашифрованный транспортный протокол, который обычно используется в качестве моста между клиентами и серверами Xray.

Предупреждение

VMess полагается на системное время. Убедитесь, что системное время UTC, используемое Xray, находится в пределах 120 секунд от фактического времени, независимо от часового пояса. В системах Linux вы можете установить службу ntp для автоматической синхронизации системного времени.

OutboundConfigurationObject

{
@@ -56,6 +56,6 @@
   "experiments": ""
 }
 

id: string

Идентификатор пользователя VMess, может быть любой строкой длиной менее 30 байт или допустимым UUID.

Пользовательская строка и соответствующий ей UUID эквивалентны, что означает, что вы можете использовать любой из следующих вариантов в файле конфигурации для идентификации одного и того же пользователя:

  • Напишите "id": "Я люблю арбуз учителя 1314",
  • Или напишите "id": "5783a3e7-e373-51cd-8642-c83782b807c5" (этот UUID является сопоставлением строки "Я люблю арбуз учителя 1314")

Стандарт сопоставления описан в VLESS UUID Mapping Standard: Mapping Custom Strings to a UUIDv5Открыть в новой вкладке.

Вы можете использовать команду xray uuid -i "пользовательская строка" для создания UUID, соответствующего пользовательской строке. Вы также можете использовать команду xray uuid для создания случайного UUID.

level: number

Уровень пользователя, для соединения будет использоваться локальная политика, соответствующая этому уровню пользователя.

Значение level соответствует значению level в разделе policy. Если не указано, используется значение по умолчанию - 0.

security: "aes-128-gcm" | "chacha20-poly1305" | "auto" | "none" | "zero"

Метод шифрования. Клиент будет отправлять данные с использованием настроенного метода шифрования, сервер автоматически распознает его, настройка на сервере не требуется.

  • "aes-128-gcm": рекомендуется для использования на ПК.
  • "chacha20-poly1305": рекомендуется для использования на мобильных устройствах.
  • "auto": значение по умолчанию, автоматический выбор (метод шифрования aes-128-gcm, если платформа выполнения - AMD64, ARM64 или s390x, в противном случае - Chacha20-Poly1305).
  • "none": без шифрования.
  • "zero": без шифрования и проверки подлинности сообщений (v1.4.0+).

Подсказка

Рекомендуется использовать метод шифрования "auto", чтобы обеспечить безопасность и совместимость в долгосрочной перспективе.

Метод псевдошифрования "none" будет вычислять и проверять контрольные суммы пакетов данных, но поскольку алгоритм аутентификации не имеет аппаратной поддержки, на некоторых платформах он может быть медленнее, чем "aes-128-gcm" с аппаратным ускорением.

Метод псевдошифрования "zero" не шифрует сообщения и не вычисляет контрольные суммы данных, поэтому теоретически он должен быть быстрее любого другого метода шифрования. Фактическая скорость может зависеть от других факторов.

Не рекомендуется использовать методы псевдошифрования "none" и "zero" без включенного TLS-шифрования и обязательной проверки сертификатов. Если для установления соединения используется CDN или другая промежуточная платформа, расшифровывающая TLS, или сетевая среда, не рекомендуется использовать методы псевдошифрования "none" и "zero".

Независимо от используемого метода шифрования, заголовок пакета VMess защищен шифрованием и аутентификацией.

experiments: string

Включенные экспериментальные функции протокола VMess. (Функции здесь нестабильны и могут быть удалены в любое время). Несколько включенных экспериментов можно разделить символом |, например, "AuthenticatedLength|NoTerminationSignal".

"AuthenticatedLength" включает эксперимент с аутентифицированной длиной пакета. Этот эксперимент необходимо включить одновременно на клиенте и сервере, а также запустить одну и ту же версию программы.

"NoTerminationSignal" включает эксперимент с отключением сигнала завершения соединения. Этот эксперимент может повлиять на стабильность проксируемого соединения.

- + diff --git a/ru/config/outbounds/wireguard.html b/ru/config/outbounds/wireguard.html index e624c9d3ab..9c783a1c6b 100644 --- a/ru/config/outbounds/wireguard.html +++ b/ru/config/outbounds/wireguard.html @@ -24,8 +24,8 @@ WireGuard | Project X - - + +

WireGuard

Стандартная реализация протокола WireGuard.

Предупреждение

Протокол WireGuard не предназначен для обхода блокировок, и его использование может привести к блокировке сервера из-за наличия характерных признаков.

OutboundConfigurationObject

{
@@ -77,6 +77,6 @@
   "allowedIPs": ["0.0.0.0/0"] // необязательно, по умолчанию ["0.0.0.0/0", "::/0"]
 }
 

endpoint: address

Адрес сервера, обязательный параметр.

Формат URL:порт, например, engage.cloudflareclient.com:2408
Формат IP:порт, например, 162.159.192.1:2408 или [2606:4700:d0::a29f:c001]:2408.

Подсказка

Если целевой адрес имеет тип URL, для получения IP-адреса будет использоваться встроенный DNS-сервер Xray-core, приоритет IPv4 или IPv6 определяется значением domainStrategy.
Если конфигурация "dns" не указана, для получения IP-адреса будет использоваться системный DNS, а приоритет IPv4 или IPv6 будет определяться системой.

publicKey: string

Публичный ключ сервера, используемый для аутентификации, обязательный параметр.

preSharedKey: string

Дополнительный ключ симметричного шифрования.

keepAlive: int

Интервал отправки keep-alive пакетов в секундах, значение по умолчанию - 0, что означает отсутствие keep-alive.

allowedIPs: string array

WireGuard разрешает трафик только от определенных исходных IP-адресов.

- + diff --git a/ru/config/policy.html b/ru/config/policy.html index 19f8e4a3fe..e30f1041a6 100644 --- a/ru/config/policy.html +++ b/ru/config/policy.html @@ -24,8 +24,8 @@ Локальные политики | Project X - - + +

Локальные политики

Локальные политики позволяют настраивать различные уровни пользователей и соответствующие им политики, например, настройки тайм-аута подключения.
Каждое соединение, обрабатываемое Xray, соответствует определенному пользователю, и к нему применяются политики в соответствии с уровнем пользователя (level).

PolicyObject

PolicyObject соответствует полю policy в конфигурационном файле.

{
@@ -65,6 +65,6 @@
   "statsOutboundDownlink": false
 }
 

statsInboundUplink: true | false

Если значение равно true, включить учет исходящего трафика для всех входящих подключений.

statsInboundDownlink: true | false

Если значение равно true, включить учет входящего трафика для всех входящих подключений.

statsOutboundUplink: true | false

Если значение равно true, включить учет исходящего трафика для всех исходящих подключений.

statsOutboundDownlink: true | false

Если значение равно true, включить учет входящего трафика для всех исходящих подключений.

- + diff --git a/ru/config/reverse.html b/ru/config/reverse.html index ee7ec40f9b..26747557fc 100644 --- a/ru/config/reverse.html +++ b/ru/config/reverse.html @@ -24,8 +24,8 @@ Обратный прокси | Project X - - + +

Обратный прокси

Обратный прокси позволяет перенаправлять трафик с сервера на клиент, то есть перенаправлять трафик в обратном направлении.

Принцип работы обратного прокси:

  • Предположим, что на хосте A запущен веб-сервер, но у этого хоста нет публичного IP-адреса, и к нему нельзя получить доступ из Интернета.
    У нас есть другой хост B с публичным IP-адресом.
    Мы хотим использовать хост B в качестве шлюза и перенаправлять трафик с B на A.
  • На хосте A настроен Xray, называемый bridge, и на хосте B также настроен Xray, называемый portal.
  • bridge устанавливает соединение с portal.
    Целевой адрес этого соединения можно настроить произвольно.
    portal получает два типа соединений: соединения от bridge и соединения от пользователей из Интернета.
    portal автоматически объединяет эти два типа соединений.
    Таким образом, bridge может получать трафик из Интернета.
  • После получения трафика из Интернета bridge перенаправляет его на веб-сервер на хосте A без изменений.
    Конечно, для этого требуется настроить маршрутизацию.
  • bridge выполняет динамическую балансировку нагрузки в зависимости от объема трафика.

Подсказка

Обратный прокси по умолчанию использует Mux.
Не включайте Mux для исходящих подключений, используемых обратным прокси.

Внимание

Функция обратного прокси находится в стадии тестирования и может работать некорректно.

ReverseObject

ReverseObject соответствует полю reverse в конфигурационном файле.

{
@@ -144,6 +144,6 @@
   ]
 }
 
- + diff --git a/ru/config/routing.html b/ru/config/routing.html index a46f973c3f..e8407b78f9 100644 --- a/ru/config/routing.html +++ b/ru/config/routing.html @@ -24,8 +24,8 @@ Маршрутизация | Project X - - + +

Warning

This translation was modified on 4 September 2024 and an updated version (13 September 2024) is available on the source page. View the original page

Маршрутизация

Модуль маршрутизации позволяет направлять входящие данные через разные исходящие подключения в соответствии с различными правилами, что позволяет реализовать проксирование по требованию.

Например, распространенным сценарием использования является разделение трафика на внутренний и внешний.
Xray может определять трафик из разных регионов с помощью внутренних механизмов и отправлять его через разные исходящие подключения.

Более подробное описание функции маршрутизации: Введение в маршрутизацию (routing).

RoutingObject

RoutingObject соответствует полю routing в конфигурационном файле.

{
@@ -102,6 +102,6 @@
         }
     ]
 

Предопределенные списки доменов

Этот список включен в каждый установочный пакет Xray и называется geosite.dat.
Этот файл содержит некоторые распространенные доменные имена.
Формат использования: geosite:filename, например geosite:google означает сопоставление с доменными именами, указанными в файле в разделе google, для маршрутизации или фильтрации DNS.

Распространенные доменные имена:

  • category-ads: содержит доменные имена распространенных рекламных сервисов.
  • category-ads-all: содержит доменные имена распространенных рекламных сервисов, а также доменные имена поставщиков рекламы.
  • cn: эквивалентно объединению geolocation-cn и tld-cn.
  • apple: содержит большинство доменных имен Apple.
  • google: содержит большинство доменных имен Google.
  • microsoft: содержит большинство доменных имен Microsoft.
  • facebook: содержит большинство доменных имен Facebook.
  • twitter: содержит большинство доменных имен Twitter.
  • telegram: содержит большинство доменных имен Telegram.
  • geolocation-cn: содержит доменные имена распространенных сайтов, расположенных в Китае.
  • geolocation-!cn: содержит доменные имена распространенных сайтов, расположенных за пределами Китая.
  • tld-cn: содержит доменные имена верхнего уровня, управляемые CNNIC и используемые в Китае, например, домены, оканчивающиеся на .cn, .中国.
  • tld-!cn: содержит доменные имена верхнего уровня, не используемые в Китае, например, домены, оканчивающиеся на .tw (Тайвань), .jp (Япония), .sg (Сингапур), .us (США), .ca (Канада) и т.д.

Вы также можете просмотреть полный список доменов здесь: Domain list communityОткрыть в новой вкладке.

- + diff --git a/ru/config/stats.html b/ru/config/stats.html index a8b206b62f..a0d30ac2fa 100644 --- a/ru/config/stats.html +++ b/ru/config/stats.html @@ -24,14 +24,14 @@ Статистика | Project X - - + +

Статистика

Используется для настройки сбора статистики трафика Xray.

StatsObject

StatsObject соответствует полю stats в конфигурационном файле.

{
   "stats": {}
 }
 

В настоящее время для статистики не требуется никаких параметров.
Если поле StatsObject присутствует, внутренняя статистика включается.

После включения статистики вам нужно только включить соответствующие параметры в разделе Политики, чтобы начать сбор статистики.

Получение статистики

Вы можете получить статистику с помощью соответствующих команд xray api.

В настоящее время доступна следующая статистика:

  • Данные пользователя

    • user>>>[email]>>>traffic>>>uplink

      Исходящий трафик для определенного пользователя в байтах.

    • user>>>[email]>>>traffic>>>downlink

      Входящий трафик для определенного пользователя в байтах.

Подсказка

Если для пользователя не указан email, статистика для него не будет собираться.

  • Глобальные данные

    • inbound>>>[tag]>>>traffic>>>uplink

      Исходящий трафик для определенного входящего подключения в байтах.

    • inbound>>>[tag]>>>traffic>>>downlink

      Входящий трафик для определенного входящего подключения в байтах.

    • outbound>>>[tag]>>>traffic>>>uplink

      Исходящий трафик для определенного исходящего подключения в байтах.

    • outbound>>>[tag]>>>traffic>>>downlink

      Входящий трафик для определенного исходящего подключения в байтах.

- + diff --git a/ru/config/transport.html b/ru/config/transport.html index 07ae20b854..6d321cc47e 100644 --- a/ru/config/transport.html +++ b/ru/config/transport.html @@ -24,8 +24,8 @@ Транспорт | Project X - - + +

Warning

This translation was modified on 3 September 2024 and an updated version (8 September 2024) is available on the source page. View the original page

Транспорт

Транспорт (transport) - это способ, которым текущий узел Xray взаимодействует с другими узлами.

Транспорт определяет способ передачи данных. Обычно оба конца сетевого подключения должны использовать одинаковый транспорт.
Например, если один конец использует WebSocket, то другой конец также должен использовать WebSocket, иначе соединение не будет установлено.

StreamSettingsObject

StreamSettingsObject соответствует полю streamSettings во входящем или исходящем подключении.
Каждое входящее или исходящее подключение может иметь свои собственные настройки транспорта.

{
@@ -173,6 +173,6 @@
   }
 ]
 

type: ""

Обязательный параметр, тип настройки, в настоящее время доступны int и str.

level: ""

Необязательный параметр, уровень протокола, используемый для указания области действия.
Значение по умолчанию - 6 (TCP).

opt: ""

Название настраиваемого параметра в десятичном формате (в этом примере используется значение TCP_CONGESTION, которое равно 0xd в шестнадцатеричном формате и 13 в десятичном формате).

value: ""

Значение, которое нужно установить.
В этом примере используется значение bbr.

Если type равен int, значение должно быть десятичным числом.

- + diff --git a/ru/config/transports/grpc.html b/ru/config/transports/grpc.html index a6fbfea2fe..5a6c373b10 100644 --- a/ru/config/transports/grpc.html +++ b/ru/config/transports/grpc.html @@ -24,8 +24,8 @@ gRPC | Project X - - + +

gRPC

Режим передачи данных, основанный на HTTP/2, полностью соответствует стандарту HTTP/2 и может быть ретранслирован другими HTTP-серверами (такими как Nginx).

gRPC (HTTP/2) имеет встроенное мультиплексирование, не рекомендуется включать mux.cool при использовании gRPC и HTTP/2.

⚠⚠⚠

  • gRPC не поддерживает указание Host. Пожалуйста, укажите правильное доменное имя в адресе исходящего прокси или укажите ServerName в (x)tlsSettings, иначе подключение не будет установлено.
  • gRPC не поддерживает fallback на другие сервисы.
  • Существует риск активного сканирования сервисов gRPC. Рекомендуется использовать обратный прокси-сервер, такой как Caddy или Nginx, для предварительного разделения трафика по пути.

Подсказка

Если вы используете обратный прокси-сервер, такой как Caddy или Nginx, обратите внимание на следующие моменты:

  • Убедитесь, что на обратном прокси-сервере включен HTTP/2.
  • Используйте HTTP/2 или h2c (Caddy), grpc_pass (Nginx) для подключения к Xray.
  • Путь в обычном режиме: /${serviceName}/Tun, в режиме Multi: /${serviceName}/TunMulti.
  • Если необходимо получать IP-адрес клиента, его можно передать через заголовок X-Real-IP, отправленный Caddy / Nginx.

Подсказка

Если вы используете fallback, обратите внимание на следующие моменты:

  • Не рекомендуется использовать fallback на gRPC, так как существует риск активного сканирования.
  • Убедитесь, что h2 находится на первом месте в (x)tlsSettings.alpn, иначе gRPC (HTTP/2) может не завершить TLS-рукопожатие.
  • gRPC не поддерживает маршрутизацию на основе path с помощью Xray.

GRPCObject

GRPCObject соответствует элементу grpcSettings конфигурации передачи.

{
@@ -39,6 +39,6 @@
   "initial_windows_size": 0
 }
 

authority: string

Строка, которая может использоваться как Host для реализации некоторых других целей.

serviceName: string

Строка, указывающая имя сервиса, аналогично пути в HTTP/2. Клиент будет использовать это имя для связи, а сервер будет проверять, совпадает ли имя сервиса.

Подсказка

Когда serviceName начинается с косой черты, можно настроить собственный путь, используя как минимум две косые черты.
Например, если на сервере указано "serviceName": "/my/sample/path1|path2", то на клиенте можно указать "serviceName": "/my/sample/path1" или "/my/sample/path2".

user_agent: string

Подсказка

Необходимо настроить только в outbound (клиент).

Установка пользовательского агента gRPC, может предотвратить блокировку трафика gRPC некоторыми CDN.

multiMode: true | false BETA

true включает multiMode, значение по умолчанию: false.

Это экспериментальная опция, которая может быть удалена в будущем, и ее совместимость между версиями не гарантируется. Этот режим может обеспечить прирост производительности примерно на 20% в тестовой среде, фактическая производительность зависит от скорости передачи.

Подсказка

Необходимо настроить только в outbound (клиент).

idle_timeout: number

Проверка работоспособности выполняется, если в течение определенного периода времени, измеряемого в секундах, не происходит передача данных. Если это значение меньше 10, то в качестве минимального значения будет использоваться 10.

Подсказка

Если не используется обратный прокси-сервер, такой как Caddy или Nginx (обычно не используется), и это значение установлено меньше 60, сервер может отправить непредвиденный кадр h2 GOAWAY, чтобы закрыть существующее соединение.

По умолчанию проверка работоспособности отключена.

Подсказка

Необходимо настроить только в outbound (клиент).

Подсказка

Может решить некоторые проблемы с "обрывом" соединения.

health_check_timeout: number

Время ожидания ответа проверки работоспособности в секундах. Если в течение этого времени проверка работоспособности не будет завершена и по-прежнему не будет передачи данных, проверка работоспособности будет считаться неудачной. Значение по умолчанию: 20.

Подсказка

Настройка требуется только на стороне исходящего соединения (клиента).

permit_without_stream: true | false

true разрешает проверку работоспособности, если нет дочерних подключений. Значение по умолчанию: false.

Подсказка

Необходимо настроить только в outbound (клиент).

initial_windows_size: number

Начальный размер окна h2 Stream. Если значение меньше или равно 0, эта функция не действует. Если значение больше 65535, механизм динамического окна будет отключен. Значение по умолчанию: 0, то есть не действует.

Подсказка

Необходимо настроить только в outbound (клиент).

Подсказка

При использовании CDN Cloudflare можно установить значение 65536 или выше, чтобы отключить механизм динамического окна, что предотвратит отправку непредвиденных кадров h2 GOAWAY CDN Cloudflare для закрытия существующего соединения.

- + diff --git a/ru/config/transports/h2.html b/ru/config/transports/h2.html index 48f4de782c..3ba54a21a8 100644 --- a/ru/config/transports/h2.html +++ b/ru/config/transports/h2.html @@ -24,8 +24,8 @@ HTTP/2 | Project X - - + +

Warning

This translation was modified on 16 July 2024 and an updated version (29 July 2024) is available on the source page. View the original page

HTTP/2

Способ передачи данных на основе HTTP/2.

Он полностью реализован в соответствии со стандартом HTTP/2 и может быть перенаправлен через другие HTTP-серверы (например, Nginx).

В соответствии с рекомендациями HTTP/2, клиент и сервер должны одновременно включать TLS для нормальной работы этого способа передачи.

HTTP/2 имеет встроенное мультиплексирование, не рекомендуется включать mux.cool при использовании HTTP/2.

Подсказка

Текущая версия способа передачи HTTP/2 не требует, чтобы входящее соединение (сервер) имело конфигурацию TLS. Это позволяет в среде развертывания с разделением трафика для специальных целей использовать внешний шлюз для обработки TLS-соединения, в то время как Xray будет использоваться в качестве серверного приложения, а связь между шлюзом и Xray будет осуществляться по незашифрованному протоколу http/2, который называется h2c.

Внимание

⚠️ Если вы используете fallback, обратите внимание на следующие моменты:

  • Убедитесь, что (x)tlsSettings.alpn содержит h2, иначе HTTP/2 не сможет завершить TLS-рукопожатие.
  • HTTP/2 не может быть разделен по пути, рекомендуется использовать SNI-разделение.

HttpObject

HttpObject соответствует элементу httpSettings конфигурации передачи.

{
@@ -39,6 +39,6 @@
   }
 }
 

host: [string]

Массив строк, каждый элемент которого является доменным именем.

Клиент будет случайным образом выбирать доменное имя из списка для связи, а сервер будет проверять, находится ли доменное имя в списке.

Подсказка

Если не указать "httpSettings" или оставить значение "host": [] пустым, то будет использоваться значение по умолчанию "www.example.com". Для успешного подключения значение "host" должно быть одинаковым на обеих сторонах. "host": [""] не является пустым значением.

path: string

HTTP-путь, начинающийся с /, должен быть одинаковым у клиента и сервера.

Значение по умолчанию: "/".

read_idle_timeout: number

Время в секундах, по истечении которого, если данные не были получены, будет выполнена проверка работоспособности.

По умолчанию проверка работоспособности не включена.

Подсказка

Настройка требуется только на стороне исходящего соединения (клиента).

Подсказка

Может решить некоторые проблемы с "обрывом" соединения.

health_check_timeout: number

Время ожидания ответа проверки работоспособности в секундах. Если в течение этого времени проверка работоспособности не будет завершена, она будет считаться неудачной. Значение по умолчанию: 15.

Подсказка

Настройка требуется только на стороне исходящего соединения (клиента).

method: string

HTTP-метод. Значение по умолчанию: "PUT".

При настройке следует использовать значения, перечисленные здесьОткрыть в новой вкладке.

headers: map{ string: [string] }

Пользовательские HTTP-заголовки, пара ключ-значение, где каждый ключ представляет собой имя HTTP-заголовка, а значение представляет собой массив.

- + diff --git a/ru/config/transports/httpupgrade.html b/ru/config/transports/httpupgrade.html index d1dfabaf39..cb33bea5ed 100644 --- a/ru/config/transports/httpupgrade.html +++ b/ru/config/transports/httpupgrade.html @@ -24,8 +24,8 @@ HTTPUpgrade | Project X - - + +

Warning

This translation was modified on 16 July 2024 and an updated version (29 July 2024) is available on the source page. View the original page

HTTPUpgrade

Это протокол, реализующий запросы и ответы на обновление HTTP 1.1, подобно WebSocket. Это позволяет ему, как и WebSocket, быть проксируемым CDN или Nginx, но без необходимости реализации других частей протокола WebSocket, что делает его более эффективным.

Его дизайн не рекомендуется для самостоятельного использования, а лучше всего работает в сочетании с TLS.

HttpUpgradeObject

HttpUpgradeObject соответствует пункту httpupgradeSettings в настройках передачи.

{
@@ -37,6 +37,6 @@
   }
 }
 

acceptProxyProtocol: true | false

Используется только для входящих соединений и указывает, принимать ли протокол PROXY.

PROXY protocolОткрыть в новой вкладке предназначен для передачи реального IP-адреса и порта запроса. Если вы не знакомы с ним, проигнорируйте этот пункт.

Распространенные программы для reverse прокси (например, HAProxy, Nginx) и VLESS fallbacks xver могут быть настроены для его включения.

При установке значения true, после установления TCP-соединения на самом нижнем уровне, запрашивающая сторона должна сначала отправить PROXY protocol v1 или v2, в противном случае соединение будет закрыто.

path: string

HTTP-путь, используемый HTTPUpgrade, по умолчанию "/".

Если в пути клиента содержится параметр ed (например, /mypath?ed=2560), будет активирована функция Early Data для уменьшения задержки, ее значение - порог длины первого пакета. Если длина первого пакета превышает это значение, Early Data не будет активирована. Рекомендуемое значение - 2560.

host: string

Хост, отправляемый в HTTP-запросе HTTPUpgrade, по умолчанию пустой. Если значение на стороне сервера пустое, значение хоста, отправляемое клиентом, не проверяется.

Когда на стороне сервера указано это значение или в headers указан хост, будет проверено соответствие хоста запроса клиента.

Приоритет выбора хоста, отправляемого клиентом: host > headers > address

headers: map {string: string}

Пользовательские HTTP-заголовки, пара ключ-значение, где каждый ключ представляет имя HTTP-заголовка, а соответствующее значение - строка.

По умолчанию пустое.

- + diff --git a/ru/config/transports/mkcp.html b/ru/config/transports/mkcp.html index c2badb939c..047e7dc0c5 100644 --- a/ru/config/transports/mkcp.html +++ b/ru/config/transports/mkcp.html @@ -24,8 +24,8 @@ mKCP | Project X - - + +

mKCP

mKCP использует UDP для имитации TCP-соединения.

mKCP жертвует пропускной способностью ради уменьшения задержки. При передаче одного и того же контента mKCP, как правило, потребляет больше трафика, чем TCP.

Подсказка

Убедитесь, что на хосте правильно настроена конфигурация брандмауэра.

KcpObject

KcpObject соответствует параметрам передачи kcpSettings.

{
@@ -47,6 +47,6 @@
   "domain": "example.com"
 }
 

type: string

Тип маскировки, доступные значения:

  • "none": значение по умолчанию, не применяется маскировка, отправляемые данные не имеют никаких отличительных признаков.
  • "srtp": маскировка под SRTP-пакеты, будет идентифицироваться как данные видеозвонка (например, FaceTime).
  • "utp": маскировка под uTP-пакеты, будет идентифицироваться как данные загрузки BT.
  • "wechat-video": маскировка под пакеты видеозвонка WeChat.
  • "dtls": маскировка под DTLS 1.2-пакеты.
  • "wireguard": маскировка под WireGuard-пакеты. (Это не настоящий протокол WireGuard).
  • "dns": некоторые корпоративные сети разрешают DNS-запросы без авторизации, добавление DNS-заголовка к KCP-пакетам позволяет обойти некоторые корпоративные сети.

domain: string

Используется совместно с типом маскировки "dns", можно указать произвольный домен.

Благодарности

Улучшения протокола KCP

Более компактный заголовок протокола

Протокол KCP использует заголовок размером 24 байта, а mKCP уменьшил его до 18 байт для пакета данных и 16 байт для пакета подтверждения. Более компактный заголовок помогает избежать обнаружения по признакам и ускоряет передачу данных.

Кроме того, в оригинальном KCP каждый пакет подтверждения может подтвердить только один пакет данных, то есть, если KCP нужно подтвердить получение 100 пакетов данных, он отправит 24 * 100 = 2400 байт данных. В этом случае многократно повторяются заголовки, что приводит к ненужному расходу полосы пропускания. mKCP сжимает несколько пакетов подтверждения, 100 пакетов подтверждения занимают всего 16 + 2 + 100 * 4 = 418 байт, что в шесть раз меньше, чем в оригинальном KCP.

Передача пакетов подтверждения

В оригинальном KCP пакет подтверждения отправляется только один раз, если пакет подтверждения потерян, то обязательно произойдет повторная передача данных, что приводит к ненужному расходу полосы пропускания. mKCP будет повторно отправлять пакеты подтверждения с определенной частотой, пока отправитель не получит подтверждение. Размер одного пакета подтверждения составляет 22 байта, что значительно меньше, чем размер пакета данных, который составляет более 1000 байт, поэтому повторная передача пакета подтверждения имеет гораздо меньшую цену.

Управление состоянием соединения

mKCP может эффективно управлять состоянием соединения. Когда удаленный хост инициализирует закрытие соединения, соединение будет закрыто в течение двух секунд; когда удаленный хост теряет соединение, соединение будет закрыто в течение максимум 30 секунд.

Оригинальный KCP не поддерживает этот сценарий.

- + diff --git a/ru/config/transports/splithttp.html b/ru/config/transports/splithttp.html index a2f772cec0..da57590146 100644 --- a/ru/config/transports/splithttp.html +++ b/ru/config/transports/splithttp.html @@ -24,8 +24,8 @@ SplitHTTP | Project X - - + +

Warning

This translation was modified on 18 July 2024 and an updated version (18 September 2024) is available on the source page. View the original page

SplitHTTP

v1.8.16+

Используется для загрузки с помощью HTTP-фрагментированной передачи, загрузка осуществляется с помощью нескольких HTTP POST-запросов.

Может использоваться через CDN, не поддерживающие WebSocket, но есть несколько требований:

  • CDN должен поддерживать HTTP-фрагментированную передачу и потоковые ответы без буферизации. Ядро будет отправлять X-Accel-Buffering: no и Content-Type: text/event-stream, чтобы сообщить CDN об этом, но CDN должен соблюдать этот заголовок. Если промежуточный сервер не поддерживает потоковые ответы и зависает, передача, скорее всего, не будет работать.

Цель та же, что и у V2fly Meek, но благодаря использованию фрагментированной загрузки скорость загрузки выше, а скорость отдачи оптимизирована, но все еще очень ограничена, поэтому к HTTP-прокси предъявляются более высокие требования (см. выше).

SplitHTTP также принимает заголовок X-Forwarded-For.

SplitHttpObject

SplitHttpObject соответствует элементу splithttpSettings в конфигурации транспорта.

{
@@ -38,6 +38,6 @@
   "maxConcurrentUploads": 10 
 }
 

path: string

Путь HTTP-протокола, используемый SplitHTTP, значение по умолчанию — "/".

host: string

Хост, отправляемый в HTTP-запросе SplitHTTP, по умолчанию пуст. Если значение на стороне сервера пустое, значение хоста, отправленное клиентом, не проверяется.

Если это значение указано на стороне сервера или host указан в headers, то проверяется соответствие хоста запроса клиента.

Приоритет выбора хоста для отправки клиентом: host > headers > address.

headers: map {string: string}

Пользовательские HTTP-заголовки, пары ключ-значение, где каждый ключ представляет имя HTTP-заголовка, а соответствующее значение является строкой.

maxUploadSize: int

Максимальный размер фрагмента загрузки в байтах, по умолчанию 1 МБ.

Это значение должно быть меньше максимального размера тела запроса, разрешенного CDN или другим обратным HTTP-прокси, иначе будет выдаваться ошибка HTTP 413.

Увеличение этого значения может увеличить скорость загрузки.

maxConcurrentUploads: int

Максимальное количество одновременных загрузок, по умолчанию 10, соединения будут использоваться повторно, насколько это возможно.

Если соединение нестабильно или потребление памяти на сервере слишком велико, попробуйте уменьшить это значение.

Значение, установленное клиентом, должно быть меньше, чем на сервере, иначе это может привести к проблемам с подключением.

Детали протокола

Подробное обсуждение см. #3412Открыть в новой вкладке и #3462Открыть в новой вкладке. Ниже приведено краткое описание и требования к совместимой реализации:

  1. Загрузка начинается с GET /<UUID>. Сервер немедленно отвечает 200 OK и Transfer Encoding:chunked и немедленно отправляет двухбайтовую полезную нагрузку, чтобы принудительно обновить заголовки HTTP-прокси.

  2. Отправка данных начинается с POST /<UUID>/<seq>. seq действует как порядковый номер TCP, начиная с 0, пакеты данных могут отправляться одновременно, сервер должен пересобрать данные по порядковому номеру. Порядковый номер не следует сбрасывать.

    Клиент может свободно выбирать порядок открытия исходящих и нисходящих запросов, любой из них может инициировать сеанс, но соединение GET должно быть открыто в течение 30 секунд, иначе сеанс будет разорван.

  3. Запрос GET будет оставаться открытым до тех пор, пока соединение не будет разорвано, и сервер, и клиент могут закрыть соединение. Конкретное поведение зависит от версии HTTP.

Рекомендации:

  • Не ожидайте, что CDN будет правильно передавать все заголовки, цель этого протокола — обойти CDN, не поддерживающие WS, а поведение этих CDN обычно не очень дружелюбное.

  • Следует предполагать, что все HTTP-соединения не поддерживают потоковые запросы, поэтому размер каждого пакета, отправляемого исходящим соединением, должен определяться с учетом задержки, пропускной способности и ограничений самого промежуточного сервера (аналогично MTU TCP и алгоритму Нейгла).

  • Что касается версий HTTP, ядро временно не поддерживает h2c, поэтому при отсутствии HTTPS Xray отправляет только запросы http/1.1.

Во избежание дополнительных сложностей, связанных с согласованием ALPN, клиент Xray использует h2 при использовании HTTPS. Вы также можете вручную указать alpn как http/1.1 или h3 в настройках TLS клиента, чтобы использовать соответствующую версию HTTP для отправки запросов. Сервер Xray, с другой стороны, совместим со всеми типами входящих соединений, включая h2c (h3 пока не поддерживается), поскольку входящие соединения могут использовать различные типы запросов из-за перенаправления через промежуточные узлы.

BrowserDialer

При использовании HTTPS этот транспорт также поддерживает BrowserDialer.

- + diff --git a/ru/config/transports/tcp.html b/ru/config/transports/tcp.html index d2c6a62fe8..7d7721db9a 100644 --- a/ru/config/transports/tcp.html +++ b/ru/config/transports/tcp.html @@ -24,8 +24,8 @@ TCP | Project X - - + +

TCP

Режим транспорта TCP — один из рекомендуемых в настоящее время режимов транспорта.

Может использоваться в различных комбинациях с различными протоколами.

TcpObject

TcpObject соответствует элементу tcpSettings в конфигурации транспорта.

{
@@ -69,6 +69,6 @@
   }
 }
 

version: string

Версия HTTP, значение по умолчанию — "1.1".

status: string

Состояние HTTP, значение по умолчанию — "200".

reason: string

Описание состояния HTTP, значение по умолчанию — "OK".

headers: map {string, [ string ]}

HTTP-заголовки, пары ключ-значение, где каждый ключ представляет имя HTTP-заголовка, а соответствующее значение является массивом.

Каждый запрос будет содержать все ключи и случайно выбранное соответствующее значение. Значение по умолчанию см. в примере выше.

- + diff --git a/ru/config/transports/websocket.html b/ru/config/transports/websocket.html index d82493a396..8204c4f0af 100644 --- a/ru/config/transports/websocket.html +++ b/ru/config/transports/websocket.html @@ -24,8 +24,8 @@ WebSocket | Project X - - + +

Warning

This translation was modified on 16 July 2024 and an updated version (29 July 2024) is available on the source page. View the original page

WebSocket

Использует стандартный WebSocket для передачи данных.

Подключение WebSocket может быть проксировано другими HTTP-серверами (например, Nginx) и VLESS fallbacks path.

Подсказка

WebSocket распознает заголовок X-Forwarded-For в HTTP-запросе для перезаписи исходного адреса трафика, приоритет выше, чем у PROXY protocol.

WebSocketObject

WebSocketObject соответствует элементу wsSettings в конфигурации транспорта.

{
@@ -37,6 +37,6 @@
   }
 }
 

acceptProxyProtocol: true | false

Только для входящих подключений, указывает, следует ли принимать PROXY protocol.

PROXY protocolОткрыть в новой вкладке используется для передачи реального исходного IP-адреса и порта запроса, если вы не знаете, что это такое, проигнорируйте этот параметр.

Распространенные программы-обработчики обратного прокси (например, HAProxy, Nginx) можно настроить на его отправку, VLESS fallbacks xver также может его отправлять.

Если установлено значение true, то после установления TCP-соединения на самом нижнем уровне запрашивающая сторона должна сначала отправить PROXY protocol v1 или v2, иначе соединение будет закрыто.

path: string

Путь, используемый WebSocket в HTTP-протоколе, значение по умолчанию — "/".

Если в пути клиента есть параметр ed (например, /mypath?ed=2560), будет активирован Early Data для уменьшения задержки.

host: string

Хост, отправляемый в HTTP-запросе WebSocket, значение по умолчанию — пустое. Если значение на стороне сервера пустое, значение хоста, отправленное клиентом, не проверяется.

Если это значение указано на стороне сервера или host указан в headers, то проверяется соответствие хоста запроса клиента.

Приоритет выбора хоста для отправки клиентом: host > headers > address.

headers: map {string: string}

Пользовательские HTTP-заголовки, пары ключ-значение, где каждый ключ представляет имя HTTP-заголовка, а соответствующее значение является строкой.

Значение по умолчанию: пустое.

Browser Dialer

Использует браузер для обработки TLS, подробнее см. в Browser Dialer.

- + diff --git a/ru/development/index.html b/ru/development/index.html index 49c0de0061..017c1a5bab 100644 --- a/ru/development/index.html +++ b/ru/development/index.html @@ -24,11 +24,11 @@ 开发指南 | Project X - - + +

开发指南

编译文档

Xray 支持各种平台, 您可以在多种平台上自行进行交叉编译。

请点击编译文档以查看具体编译相关内容。

设计思路

Xray 内核提供了一个平台,在其之上可以进二次开发。

这个章节阐述了 Xray 的设计目标和架构。

请点击设计思路以了解 Xray 的设计目标和架构。

开发规范

这个章节阐述了获取代码,进行开发,提交 PR 的流程中需要遵循的准则, 以及相关的编码规范。

请点击开发规范查看 Xray 开发中应遵循的准则。

协议详解

Xray 用到了很多种协议, 您可以通过各种途径获得协议的详细描述。

VLESS 协议

VLESS 是一个无状态的轻量传输协议,可以作为 Xray 客户端和服务器之间的桥梁。

VMess 协议

VMess 是一个加密传输协议,可以作为 Xray 客户端和服务器之间的桥梁。

Mux.Cool 协议

Mux.Cool 协议是一个多路复用传输协议,用于在一条已建立的数据流中传输多个各自独立的数据流。

mKCP 协议

mKCP 是流式传输协议,由 KCP 协议Открыть в новой вкладке修改而来,可以按顺序传输任意的数据流。

- + diff --git a/ru/development/intro/compile.html b/ru/development/intro/compile.html index fd8cc8da99..4827a7fd38 100644 --- a/ru/development/intro/compile.html +++ b/ru/development/intro/compile.html @@ -24,8 +24,8 @@ 编译文档 | Project X - - + +

编译文档

前序工作

Xray 使用 GolangОткрыть в новой вкладке 作为编程语言,你需要先安装最新版本 Golang 才能够编译。

如果你不幸使用 Windows, 请 务必 使用 Powershell

拉取 Xray 源代码

git clone https://github.com/XTLS/Xray-core.git
@@ -40,6 +40,6 @@
 
 go build -o xray -trimpath -ldflags "-s -w -buildid=" ./main
 

上传到服务器后,记得在服务器终端内执行 chmod +x xray

Подсказка

执行 go tool dist list 查看所有支持的系统与架构。

可复现构建:

按照上述步骤,能够编译与 Release 中完全相同的二进制文件。

Внимание

请先确认您使用的 Golang 版本与编译 Release 的一致。

- + diff --git a/ru/development/intro/design.html b/ru/development/intro/design.html index 02e9754d3f..a2a5ce0c00 100644 --- a/ru/development/intro/design.html +++ b/ru/development/intro/design.html @@ -24,11 +24,11 @@ 设计目标 | Project X - - + +

设计目标

  • Xray 内核提供了一个平台,支持必要的网络代理功能,在其之上可以进二次开发,以提供更好的用户体验;
  • 以跨平台为首要原则,以减少二次开发的成本;

架构

Architecture

内核分为三层:应用层、代理层和传输层。

每一层内包含数个模块,模块间互相独立,同类型的模块可无缝替换。

应用层

应用层包含一些代理层中常用的功能,这些功能被抽象出来,以便在不同的代理模块中复用。

应用层的模块应为纯软件实现,与硬件或平台相关的技术无关。

重要模块列表:

  • Dispatcher: 用于把入站代理所接收到的数据,传送给出站代理;
  • Router: 路由模块,详见 路由配置
  • DNS: 内置的 DNS 服务器模块;
  • Proxy Manager: 代理管理器;

代理层

代理层分为两部分:入站代理(Inbound Proxy)和出站代理(Outbound Proxy)。

两部分相互独立,入站代理不依赖于某个特定的出站代理,反之亦然。

入站代理

出站代理

传输层

传输层提供一些网络数据传输相关的工具模块。

- + diff --git a/ru/development/intro/guide.html b/ru/development/intro/guide.html index 2bf1841e31..4a1f3fa011 100644 --- a/ru/development/intro/guide.html +++ b/ru/development/intro/guide.html @@ -24,8 +24,8 @@ 开发规范 | Project X - - + +

开发规范

基本

版本控制

Project X 的代码被托管在 github 上:

您可以使用 GitОткрыть в новой вкладке 来获取代码。

分支(Branch)

  • 本项目的主干分支为 main,
  • 本项目的发布主分支同为 main,
  • 需要确保 main 在任一时刻都是可编译,且可正常使用的。
  • 如果需要开发新的功能,请新建分支进行开发,在开发完成并且经过充分测试后,合并回主干分支。
  • 已经合并入主干且没有必要存在的分支,请删除。

发布(Release)

WIP
  • 建立尝鲜版本和稳定版本两个发布通道
    • 尝鲜版本,可以为 daily build,主要用于特定情况的测试,尝鲜和获得即时反馈和再改进。
    • 稳定版本,为定时更新(比如月更),合并稳定的修改并发布。

引用其它项目

开发流程

写代码之前

发现任何问题,或对项目有任何想法,请创建 issueОткрыть в новой вкладке 讨论以减少重复劳动和消耗在代码上的时间。

修改代码

  • Golang
    • 请参考 Effective GoОткрыть в новой вкладке
    • 每一次 push 之前,请运行:go generate core/format.go
    • 如果需要修改 protobuf,例如增加新配置项,请运行:go generate core/proto.go
    • 提交 pull request 之前,建议测试通过:go test ./...
    • 提交 pull request 之前,建议新增代码有超过 70% 的代码覆盖率(code coverage);
  • 其它
    • 请注意代码的可读性。

Pull Request

  • 提交 PR 之前,请先运行 git pull https://github.com/XTLS/Xray-core.git 以确保 merge 可顺利进行;
  • 一个 PR 只做一件事,如有对多个 bug 的修复,请对每一个 bug 提交一个 PR;
  • 由于 Golang 的特殊需求(Package path),Go 项目的 PR 流程和其它项目有所不同,建议流程如下:
    1. 先 Fork 本项目,创建你自己的 github.com/<your_name>/Xray-core.git 仓库;
    2. 克隆你自己的 Xray 仓库到本地:git clone https://github.com/<your_name>/Xray-core.git
    3. 基于 main 分支创建新的分支,例如 git branch issue24 main
    4. 在新创建的分支上作修改并提交修改(commit);
    5. 在推送(push)修改完成的分支到自己的仓库前,先切换到 main 分支,运行 git pull https://github.com/XTLS/Xray-core.git 拉取最新的远端代码;
    6. 如果上一步拉取得到了新的远端代码,则切换到之前自己创建的分支,运行 git rebase main 执行分支合并操作。如遇到文件冲突,则需要解决冲突;
    7. 上一步处理完毕后,就可以把自己创建的分支推送到自己的仓库:git push -u origin your-branch
    8. 最后,把自己仓库的新推送的分支往 XTLS/Xray-coremain 分支发 PR 即可;
    9. 请在 PR 的标题和正文中,完整表述此次 PR 解决的问题 / 新增的功能 / 代码所做的修改的用意等;
    10. 耐心等待开发者的回应。

对代码的修改

功能性问题

请提交至少一个测试用例(Test Case)来验证对现有功能的改动。

性能相关

请提交必要的测试数据来证明现有代码的性能缺陷,或是新增代码的性能提升。

新功能

  • 如果新增功能对已有功能不影响,请提供可以开启/关闭的开关(如 flag),并使新功能保持默认关闭的状态;
  • 大型新功能(比如增加一个新的协议)开发之前,请先提交一个 issue,讨论完毕之后再进行开发。

其它

视具体情况而定。

Xray 编码规范

以下内容适用于 Xray 中的 Golang 代码。

代码结构

Xray-core
@@ -40,6 +40,6 @@
 │   ├── vmess
 ├── transport  // 传输模块
 

编码规范

基本与 Golang 官方所推荐做法一致,有一些例外。写在这里以方便大家熟悉 Golang。

命名

  • 文件和目录名尽量使用单个英文单词,比如 hello.go;
    • 如果实在没办法,则目录使用连接线/文件名使用下划线连接两个(或多个单词),比如 hello-world/hello_again.go;
    • 测试代码使用 _test.go 结尾;
  • 类型使用 Pascal 命名法,比如 ConnectionHandler;
    • 对缩写不强制小写,即 HTML 不必写成 Html;
  • 公开成员变量也使用 Pascal 命名法;
  • 私有成员变量使用 小驼峰式命名法Открыть в новой вкладке ,如 privateAttribute
  • 为了方便重构,方法建议全部使用 Pascal 命名法;
    • 完全私有的类型放入 internal

内容组织

  • 一个文件包含一个主要类型,及其相关的私有函数等;
  • 测试相关的文件,如 Mock 等工具类,放入 testing 子目录。
- + diff --git a/ru/development/protocols/mkcp.html b/ru/development/protocols/mkcp.html index caa2e89c14..40ba7c6357 100644 --- a/ru/development/protocols/mkcp.html +++ b/ru/development/protocols/mkcp.html @@ -24,11 +24,11 @@ mKCP 协议 | Project X - - + +

mKCP 协议

mKCP 是流式传输协议,由 KCP 协议Открыть в новой вкладке 修改而来,可以按顺序传输任意的数据流。

版本

mKCP 没有版本号,不保证版本之间兼容性。

依赖

底层协议

mKCP 是一个基于 UDP 的协议,所有通讯使用 UDP 传输。

函数

通讯过程

  1. mKCP 将数据流拆成若干个数据包进行发送。一个数据流有一个唯一标识,用以区分不同的数据流。数据流中的每一个数据包都携带了同样的标识。
  2. mKCP 没有握手过程,当收到一个数据包时,根据其携带的数据流的标识来判断是否为新的通话,或是正在进行中的通话。
  3. 每一个数据包中包含若干个片段(Segment),片段分为三类:数据(Data)、确认(ACK)、心跳(Ping)。每个片段需要单独处理。

数据格式

数据包

4 字节2 字节L 字节
认证信息 A数据长度 L片段部分

其中:

  • 认证信息 A = fnv(片段部分),big endian;
  • 片段部分可能包含多个片段;

数据片段

2 字节1 字节1 字节4 字节4 字节4 字节2 字节Len 字节
标识 Conv指令 Cmd选项 Opt时间戳 Ts序列号 Sn未确认序列号 Una长度 Len数据

其中:

  • 标识 Conv: mKCP 数据流的标识
  • 指令 Cmd: 常量 0x01
  • 选项 Opt: 可选的值有:
    • 0x00: 空选项
    • 0x01: 对方已发出所有数据
  • 时间戳 Ts: 当前片段从远端发送出来时的时间,big endian
  • 序列号 Sn: 该数据片段时数据流中的位置,起始片段的序列号为 0,之后每个新片段按顺序加 1
  • 未确认序列号 Una: 远端主机正在发送的,且尚未收到确认的最小的 Sn

确认片段

2 字节1 字节1 字节4 字节4 字节4 字节2 字节Len * 4 字节
标识 Conv指令 Cmd选项 Opt窗口 Wnd下一接收序列号 Sn时间戳 Ts长度 Len已收到的序列号

其中:

  • 标识 Conv: mKCP 数据流的标识
  • 指令 Cmd: 常量 0x00
  • 选项 Opt: 同上
  • 窗口 Wnd: 远端主机可以接收的最大序列号
  • 下一接收序列号 Sn: 远端主机未收到的数据片段中的最小序列号
  • 时间戳 Ts: 远端主机最新收到的数据片段的时间戳,可用于计算延迟
  • 已收到的序列号: 每个 4 字节,表示此序列号的数据已经确认收到

注释:

  • 远程主机期待收到序列号 [Sn, Wnd) 范围内的数据

心跳片段

2 字节1 字节1 字节4 字节4 字节4 字节
标识 Conv指令 Cmd选项 Opt未确认序列号 Una下一接收序列号 Sn延迟 Rto

其中:

  • 标识 Conv: mKCP 数据流的标识
  • 指令 Cmd: 可选的值有
    • 0x02: 远端主机强行终止会话
    • 0x03: 正常心跳
  • 选项 Opt: 同上
  • 未确认序列号 Una: 同数据片段的 Una
  • 下一接收序列号 Sn: 同确认片段的 Sn
  • 延迟 Rto: 远端主机自己计算出的延迟
- + diff --git a/ru/development/protocols/muxcool.html b/ru/development/protocols/muxcool.html index 905be793cb..1906987b89 100644 --- a/ru/development/protocols/muxcool.html +++ b/ru/development/protocols/muxcool.html @@ -24,11 +24,11 @@ Mux.Cool 协议 | Project X - - + +

Mux.Cool 协议

Mux.Cool 协议是一个多路复用传输协议,用于在一条已建立的数据流中传输多个各自独立的数据流。

版本

当前版本是 1 Beta。

依赖

底层协议

Mux.Cool 必须运行在一个已建立的可靠数据流之上。

通讯过程

一个 Mux.Cool 连接中可传输若干个子连接,每个子连接有一个独立的 ID 和状态。传输过程由帧(Frame)组成,每一帧用于传输一个特定的子连接的数据。

客户端行为

当有连接需求时并且没有现有可用的连接时,客户端向服务器发起一个新连接,以下称为“主连接”。

  1. 一个主连接可用于发送若干个子连接。客户端可自主决定主连接可承载的子连接数量。
  2. 对于一个新的子连接,客户端必须发送状态New以通知服务器建立子连接,然后使用状态Keep来传送数据。
  3. 当子连接结束时,客户端发送End状态来通知服务器关闭子连接。
  4. 客户端可自行决定何时关闭主连接,但必须确定服务器也同时保持连接。
  5. 客户端可使用 KeepAlive 状态来避免服务器关闭主连接。

服务器端行为

当服务器端接收到新的子连接时,服务器应当按正常的连接来处理。

  1. 当收到状态End时,服务器端可以关闭对目标地址的上行连接。
  2. 在服务器的响应中,必须使用与请求相同的 ID 来传输子连接的数据。
  3. 服务器不能使用New状态。
  4. 服务器可使用 KeepAlive 状态来避免客户端关闭主连接。

传输格式

Mux.Cool 使用对称传输格式,即客户端和服务器发送和接收相同格式的数据。

帧格式

2 字节L 字节X 字节
元数据长度 L元数据额外数据

元数据

元数据有若干种类型。所有类型的元数据都包含 ID 和 Opt 两项,其含义为:

当选项 Opt(D) 开启时,额外数据格式如下:

2 字节X-2 字节
长度 X-2数据

新建子连接 (New)

2 字节1 字节1 字节1 字节2 字节1 字节A 字节8 字节
ID0x01选项 Opt网络类型 N端口地址类型 T地址 AGlobal ID (XUDP)

其中:

  • 网络类型 N:
    • 0x01:TCP,表示当前子连接的流量应当以 TCP 的方式发送至目标。
    • 0x02:UDP,表示当前子连接的流量应当以 UDP 的方式发送至目标。
  • 地址类型 T:
    • 0x01:IPv4
    • 0x02:域名
    • 0x03:IPv6
  • 地址 A:
    • 当 T = 0x01 时,A 为 4 字节 IPv4 地址;
    • 当 T = 0x02 时,A 为 1 字节长度(L) + L 字节域名;
    • 当 T = 0x03 时,A 为 16 字节 IPv6 地址;
  • Global ID (XUDP):
    • 客户端计算出 UDP 来源二元组的全局独特 ID,服务端用以确保当 XUDP 断线重连时,仍使用同一个端口与目标通信。

在新建子连接时,若 Opt(D) 开启,则这一帧所带的数据需要被发往目标主机。

保持子连接 (Keep)

TCP

2 字节1 字节1 字节
ID0x02选项 Opt

UDP

2 字节1 字节1 字节1 字节2 字节1 字节A 字节
ID0x02选项 Opt网络类型 N端口地址类型 T地址 A

在保持子连接时,若 Opt(D) 开启,则这一帧所带的数据需要被发往目标主机。 XUDP 在 Opt(D) 之后加 UDP 地址,格式同新建子连接,但没有 Global ID。

关闭子连接 (End)

2 字节1 字节1 字节
ID0x03选项 Opt

在保持子连接时,若 Opt(D) 开启,则这一帧所带的数据需要被发往目标主机。

保持连接 (KeepAlive)

2 字节1 字节1 字节
ID0x04选项 Opt

在保持连接时:

  • 若 Opt(D) 开启,则这一帧所带的数据必须被丢弃。
  • ID 可为随机值。

应用

Mux.Cool 协议与底层协议无关,理论上可以使用任何可靠的流式连接来传输 Mux.Cool 的协议数据。

在目标导向的协议如 Shadowsocks 和 VMess 协议中,连接建立时必须包含一个指定的地址。 为了保持兼容性,Mux.Cool 协议指定地址为“v1.mux.cool”。即当主连接的目标地址与之匹配时,则进行 Mux.Cool 方式的转发,否则按传统方式进行转发。(注:这是一个程序内的标记,VMess 和 VLESS 并不会在数据包中发送“v1.mux.cool”地址)

- + diff --git a/ru/development/protocols/vless.html b/ru/development/protocols/vless.html index 9ae9547530..8511e51a35 100644 --- a/ru/development/protocols/vless.html +++ b/ru/development/protocols/vless.html @@ -24,11 +24,11 @@ VLESS 协议 | Project X - - + +

VLESS 协议

VLESS 是一个无状态的轻量传输协议,可以作为 Xray 客户端和服务器之间的桥梁。

Request & Response

1 字节16 字节1 字节M 字节1 字节2 字节1 字节S 字节X 字节
协议版本等价 UUID附加信息长度 M附加信息 ProtoBuf指令端口地址类型地址请求数据
1 字节1 字节N 字节Y 字节
协议版本,与请求的一致附加信息长度 N附加信息 ProtoBuf响应数据

VLESS 早在第二个测试版 ALPHA 2 时就已经是上述结构了(BETA 是第五个测试版):

“响应认证”被替换为“协议版本”并移至最前,使 VLESS 可以升级换代,同时消除了生成伪随机数的开销。混淆相关结构被替换为附加信息(ProtoBuf)并前移,赋予协议本身可扩展性,相关开销也极小(gogo/protobufОткрыть в новой вкладке),若无附加信息则无相关开销。

我一直觉得“响应认证”不是必要的,ALPHA 时为了提升生成随机数的性能,还用 math/rand 替换 crypto/rand,而现在都不需要了。

“协议版本”不仅能起到“响应认证”的作用,还赋予了 VLESS 无痛升级协议结构的能力,带来无限的可能性。 “协议版本”在测试版本中均为 0,正式版本中为 1,以后若有不兼容的协议结构变更则应升级版本。

VLESS 服务端的设计是 switch version,即同时支持所有 VLESS 版本。若需要升级协议版本(可能到不了这一步),推荐的做法是服务端提前一个月支持,一个月后再改客户端。VMess 请求也有协议版本,但它的认证信息在外面,指令部分则高度耦合且有固定加密,导致里面的协议版本毫无意义,服务端也没有进行判断,响应则没有协议版本。Trojan 的协议结构中没有协议版本。

接下来是 UUID,我本来觉得 16 字节有点长,曾经考虑过缩短它,但后来看到 Trojan 用了 56 个可打印字符(56 字节),就彻底打消了这个念头。服务端每次都要验证 UUID,所以性能也很重要:VLESS 的 Validator 经历了多次重构/升级,相较于 VMess,它十分简洁且耗资源很少,可以同时支持非常多的用户,性能也十分强悍,验证速度极快(sync.Map)。API 动态增删用户则更高效顺滑。 https://github.com/XTLS/Xray-core/issues/158

引入 ProtoBuf 是一个创举,等下会详细讲解。“指令”到“地址”的结构目前与 VMess 完全相同,同样支持 Mux。

总体上,ALPHA 2 到 BETA 主要是:结构进化、清理整合、性能提升、更加完善。这些都是一点一滴的,详见 VLESS ChangesОткрыть в новой вкладке

ProtoBuf

似乎只有 VLESS 可选内嵌 ProtoBuf,它是一种数据交换格式,信息被紧密编码成二进制,TLV 结构(Tag Length Value)。

起因是我看到一篇文章称 SS 有一些缺点,如没有设计错误回报机制,客户端没办法根据不同的错误采取进一步的动作。 (但我并不认同所有错误都要回报,不然防不了主动探测。下一个测试版中,服务器可以返回一串自定义信息。) 于是想到一个可扩展的结构是很重要的,未来它也可以承载如动态端口指令。不止响应,请求也需要类似的结构。 本来打算自己设计 TLV,接着发觉 ProtoBuf 就是此结构、现成的轮子,完全适合用来做这件事,各语言支持等也不错。

目前“附加信息”只有 Scheduler 和 SchedulerV,它们是 MessName 和 MessSeed 的替代者,当你不需要它们时,“附加信息长度”为 0,也就不会有 ProtoBuf 序列化/反序列化的开销。其实我更愿意称这个过程为“拼接”,因为 pb 实际原理上也只是这么做而已,相关开销极小。拼接后的 bytes 十分紧凑,和 ALPHA 的方案相差无几,有兴趣的可以分别输出并对比。

为了指示对附加信息(Addons,也可以理解成插件,以后可以有很多个插件)的不同支持程度,下个测试版会在“附加信息长度”前新增“附加信息版本”。256 - 1 = 255 字节是够用且合理的(65535 就太多了,还可能有人恶意填充),现有的只用了十分之一,以后也不会同时有那么多附加信息,且大多数情况下是完全没有附加信息的。真不够用的话,可以升级 VLESS 版本。

为了减少逻辑判断等开销,暂定 Addons 不使用多级结构。一个月前出现过“可变协议格式”的想法,pb 是可以做到打乱顺序,但没必要,因为现代加密的设计不会让旁观者看出两次传输的头部相同。

下面介绍 Schedulers 和 Encryption 的构想,它们都是可选的,一个应对流量时序特征问题,一个应对密码学上的问题。

Schedulers Flow

中文名暂称:流量调度器(2020-09-03 更新:中文名确定为“流控”),指令由 ProtoBuf 承载,控制的是数据部分。

我之前发现,VMess 原有的 shake “元数据混淆”在 TLS 上完全不会带来有意义的改变,只会降低性能,所以 VLESS 弃用了它。并且,“混淆”这个表述容易被误解成伪装,也弃用了。顺便一提,我一直是不看好伪装的:做不到完全一样,那不就是强特征吗?做得到完全一样,那为什么不直接用伪装目标?我一开始用的是 SSR,后来发现它只是表面伪装骗运营商,就再也没用过了。

那么,“流量调度器”要解决什么问题?它影响的是宏观流量时序特征,而不是微观特征,后者是加密要解决的事情。流量时序特征可以是协议带来的,比如 Socks5 over TLS 时的 Socks5 握手 ,TLS 上不同的这种特征对于监测者来说就是不同的协议,此时无限 Schedulers 就相当于无限协议(重新分配每次发送的数据量大小等)。流量时序特征也可以是行为带来的,比如访问 Google 首页时加载了多少文件、顺序、每个文件的大小,多套一层加密并不能有效掩盖这些信息。

Schedulers 没必要像下面的 Encryption 一样整个套在外面,因为头部的一丁点数据相对于后面的数据量来说太微不足道了。

BETA 2 预计推出两个初级的 Scheduler:Zstd 压缩、数据量动态扩充。进阶操作才是从宏观层面来控制、分配,暂时咕咕。

Encryption

与 VMess 的高度耦合不同,VLESS 的服务端、客户端不久后可以提前约定好加密方式,仅在外面套一层加密。这有点类似于使用 TLS,不影响承载的任何数据,也可以理解成底层就是从 TLS 换成预设约定加密。相对于高度耦合,这种方式更合理且灵活:一种加密方式出了安全性问题,直接扔掉并换用其它的就行了,十分方便。VLESS 服务端还会允许不同的加密方式共存。

对比 VMess,VLESS 相当于把 security 换成 encryption,把 disableInsecureEncryption 换成 decryption,就解决了所有问题。目前 encryption 和 decryption 只接受 "none" 且不能留空(即使以后有连接安全性检查),详见 VLESS 配置文档Открыть в новой вкладке。encryption 并不需要往外移一级,一是因为无法复用很多代码,二是因为会影响控制粒度,看未来的应用就明白了。

加密支持两类形式,一类是加密完全独立,需要额外密码,适合私用,另一类是结合已有的 UUID 来加密,适合公用。 (若用第一类加密形式,且密码是以某种形式公开的,比如多人共用,那么中间人攻击就不远了) 重新设计的动态端口可能会随加密同时推出,指令由 ProtoBuf 承载,具体实现和 VMess 的动态端口也会有很多不同。

套现成加密是件很简单的事情,也就多一层 writer & reader。BETA 3 预计支持 SS 的 aes-128-gcm 和 chacha20-ietf-poly1305: 客户端的 encryption 可以填 “auto: ss_aes-128-gcm_0_123456, ss_chacha20-ietf-poly1305_0_987654”,auto 会选择最适合当前机器的,0 代表测试版,最后的是密码。服务端的 decryption 也是类似填法,收到请求时会逐一尝试解密。

并不是所有组合都需逐一尝试:VMess 的加密分为三段,第一段是认证信息,结合了 UUID、alterId、时间因素,第二段是指令部分,以固定算法加密,指令中含有数据部分使用的加密算法,第三段才是重要的数据部分。可以看出,VMess 的加解密方式实际上是多对一(服务端适配),而不仅是结合 UUID。但仅是结合 UUID 来加密也是件相对麻烦的事情,短时间内不会出,鉴于我们现在有 VMessAEAD 可用,也并不着急。若 VLESS 推出了结合 UUID 的加密方式,相当于重构了整个 VMess。

UDP issues

XUDP:VLESS & VMess & Mux UDP FullCone NATОткрыть в новой вкладке

客户端开发指引

  1. VLESS 协议本身还会有不兼容升级,但客户端配置文件参数基本上是只增不减的。iOS 客户端的协议实现则需紧跟升级。
  2. 视觉标准:UI 标识请统一用 VLESS,而不是 VLess / Vless / vless,配置文件不受影响,代码内则顺其自然。
  3. encryption 应做成输入框而不是选择框,新配置的默认值应为 none,若用户置空则应代填 none

VLESS 分享链接标准

感谢 a @DuckSoftОткрыть в новой вкладке 的提案!

详情请见 VMessAEAD / VLESS 分享链接标准提案Открыть в новой вкладке

- + diff --git a/ru/development/protocols/vmess.html b/ru/development/protocols/vmess.html index e9affb0b89..ec4d628445 100644 --- a/ru/development/protocols/vmess.html +++ b/ru/development/protocols/vmess.html @@ -24,11 +24,11 @@ VMess 协议 | Project X - - + +

VMess 协议

VMess 是一个加密传输协议,可以作为 Xray 客户端和服务器之间的桥梁。

版本

当前版本号为 1。

依赖

底层协议

VMess 是一个基于 TCP 的协议,所有数据使用 TCP 传输。

用户 ID

ID 等价于 UUIDОткрыть в новой вкладке,是一个 16 字节长的随机数,它的作用相当于一个令牌(Token)。 一个 ID 形如:de305d54-75b4-431b-adb2-eb6b9e546014,几乎完全随机,可以使用任何的 UUID 生成器来生成,比如这个Открыть в новой вкладке

用户 ID 可在配置文件中指定。

函数

通讯过程

VMess 是一个无状态协议,即客户端和服务器之间不需要握手即可直接传输数据,每一次数据传输对之前和之后的其它数据传输没有影响。

VMess 的客户端发起一次请求,服务器判断该请求是否来自一个合法的客户端。如验证通过,则转发该请求,并把获得的响应发回给客户端。

VMess 使用非对称格式,即客户端发出的请求和服务器端的响应使用了不同的格式。

客户端请求

16 字节X 字节余下部分
认证信息指令部分数据部分

认证信息

认证信息是一个 16 字节的哈希(hash)值,它的计算方式如下:

  • H = MD5
  • K = 用户 ID (16 字节)
  • M = UTC 时间,精确到秒,取值为当前时间的前后 30 秒随机值(8 字节, Big Endian)
  • Hash = HMAC(H, K, M)

指令部分

指令部分经过 AES-128-CFB 加密:

  • Key:MD5(用户 ID + []byte('c48619fe-8f02-49e0-b9e9-edf763e17e21'))
  • IV:MD5(X + X + X + X),X = []byte(认证信息生成的时间) (8 字节, Big Endian)
1 字节16 字节16 字节1 字节1 字节4 位4 位1 字节1 字节2 字节1 字节N 字节P 字节4 字节
版本号 Ver数据加密 IV数据加密 Key响应认证 V选项 Opt余量 P加密方式 Sec保留指令 Cmd端口 Port地址类型 T地址 A随机值校验 F

选项 Opt 细节:(当某一位为 1 时,表示该选项启用)

01234567
XXXXXMRS

其中:

  • 版本号 Ver:始终为 1;
  • 数据加密 IV:随机值;
  • 数据加密 Key:随机值;
  • 响应认证 V:随机值;
  • 选项 Opt:
    • S (0x01):标准格式的数据流(建议开启);
    • R (0x02):客户端期待重用 TCP 连接(Xray 2.23+ 弃用);
      • 只有当 S 开启时,这一项才有效;
    • M (0x04):开启元数据混淆(建议开启);
      • 只有当 S 开启时,这一项才有效;
      • 当其项开启时,客户端和服务器端需要分别构造两个 Shake 实例,分别为 RequestMask = Shake(请求数据 IV), ResponseMask = Shake(响应数据 IV)。
    • X:保留
  • 余量 P:在校验值之前加入 P 字节的随机值;
  • 加密方式:指定数据部分的加密方式,可选的值有:
    • 0x00:AES-128-CFB;
    • 0x01:不加密;
    • 0x02:AES-128-GCM;
    • 0x03:ChaCha20-Poly1305;
  • 指令 Cmd:
    • 0x01:TCP 数据;
    • 0x02:UDP 数据;
  • 端口 Port:Big Endian 格式的整型端口号;
  • 地址类型 T:
    • 0x01:IPv4
    • 0x02:域名
    • 0x03:IPv6
  • 地址 A:
    • 当 T = 0x01 时,A 为 4 字节 IPv4 地址;
    • 当 T = 0x02 时,A 为 1 字节长度(L) + L 字节域名;
    • 当 T = 0x03 时,A 为 16 字节 IPv6 地址;
  • 校验 F:指令部分除 F 外所有内容的 FNV1a hash;

数据部分

当 Opt(S) 开启时,数据部分使用此格式。实际的请求数据被分割为若干个小块,每个小块的格式如下。服务器校验完所有的小块之后,再按基本格式的方式进行转发。

2 字节L 字节
长度 L数据包

其中:

  • 长度 L:Big Endian 格式的整型,最大值为 2^14;
    • 当 Opt(M) 开启时,L 的值 = 真实值 xor Mask。Mask = (RequestMask.NextByte() << 8) + RequestMask.NextByte();
  • 数据包:由指定的加密方式加密过的数据包;

在传输结束之前,数据包中必须有实际数据,即除了长度和认证数据之外的数据。当传输结束时,客户端必须发送一个空的数据包,即 L = 0(不加密) 或认证数据长度(有加密),来表示传输结束。

按加密方式不同,数据包的格式如下:

  • 不加密:
    • L 字节:实际数据;
  • AES-128-CFB:整个数据部分使用 AES-128-CFB 加密
    • 4 字节:实际数据的 FNV1a hash;
    • L - 4 字节:实际数据;
  • AES-128-GCM:Key 为指令部分的 Key,IV = count (2 字节) + IV (10 字节)。count 从 0 开始递增,每个数据包加 1;IV 为 指令部分 IV 的第 3 至第 12 字节。
    • L - 16 字节:实际数据;
    • 16 字节:GCM 认证信息
  • ChaCha20-Poly1305:Key = MD5(指令部分 Key) + MD5(MD5(指令部分 Key)),IV = count (2 字节) + IV (10 字节)。count 从 0 开始递增,每个数据包加 1;IV 为 指令部分 IV 的第 3 至第 12 字节。
    • L - 16 字节:实际数据;
    • 16 字节:Poly1305 认证信息

服务器应答

应答头部数据使用 AES-128-CFB 加密,IV 为 MD5(数据加密 IV),Key 为 MD5(数据加密 Key)。实际应答数据视加密设置不同而不同。

1 字节1 字节1 字节1 字节M 字节余下部分
响应认证 V选项 Opt指令 Cmd指令长度 M指令内容实际应答数据

其中:

  • 响应认证 V:必须和客户端请求中的响应认证 V 一致;
  • 选项 Opt:
    • 0x01:服务器端准备重用 TCP 连接(Xray 2.23+ 弃用);
  • 指令 Cmd:
    • 0x01:动态端口指令
  • 实际应答数据:
    • 如果请求中的 Opt(S) 开启,则使用标准格式,否则使用基本格式。
    • 格式均和请求数据相同。
      • 当 Opt(M) 开启时,长度 L 的值 = 真实值 xor Mask。Mask = (ResponseMask.NextByte() << 8) + ResponseMask.NextByte();

动态端口指令

1 字节2 字节16 字节2 字节1 字节1 字节
保留端口 Port用户 IDAlterID用户等级有效时间 T

其中:

  • 端口 Port:Big Endian 格式的整型端口号;
  • 有效时间 T:分钟数;

客户端在收到动态端口指令时,服务器已开放新的端口用于通信,这时客户端可以将数据发往新的端口。在 T 分钟之后,这个端口将失效,客户端必须重新使用主端口进行通信。

注释

  • 为确保向前兼容性,所有保留字段的值必须为 0。
- + diff --git a/ru/document/command.html b/ru/document/command.html index e4d713a8e5..85b275df5e 100644 --- a/ru/document/command.html +++ b/ru/document/command.html @@ -24,8 +24,8 @@ Командные аргументы | Project X - - + +

Командные аргументы

Подсказка

Xray использует команды и аргументы в стиле Go.

Базовые команды

Вы можете запустить xray help, чтобы получить список всех базовых команд Xray, а также их описание и примеры использования.

Xray is a platform for building proxies.
@@ -116,6 +116,6 @@
 

xray x25519

Генерация пары ключей x25519.

Использование:

xray x25519 [-i "(base64.RawURLEncoding)" --std-encoding ]
 

xray wg

Генерация пары ключей curve25519 для WireGuard.

Использование:

xray wg [-i "(base64.StdEncoding)"]
 

Подсказка

Если -config не указан, Xray попытается загрузить config.json из следующих мест:

- + diff --git a/ru/document/config.html b/ru/document/config.html index 0b528fa02e..0104ad0912 100644 --- a/ru/document/config.html +++ b/ru/document/config.html @@ -24,8 +24,8 @@ Настройка и запуск | Project X - - + +

Настройка и запуск

После того, как вы скачали и установили Xray, вам потребуется его настроить.

В данном руководстве мы рассмотрим только простой способ настройки. Дополнительные шаблоны: Xray-examplesОткрыть в новой вкладке

Для настройки более сложных функций обратитесь к подробным инструкциям в разделе Файл конфигурации.

Предупреждение

Во избежание расшифровки вашего трафика
следует сгенерировать уникальный UUID с помощью команды xray uuid или uuidgen,
который затем нужно вставить на стороне сервера в поле inbounds[0].settings.clients[0].id,
а на стороне клиента - в поле outbounds[0].settings.vnext[0].users[0].id.

Настройка сервера

Вам понадобится сервер с публичным IP-адресом (не за NAT), на котором будет запущен Xray. Конфигурация сервера:

{
@@ -93,6 +93,6 @@
   }
 }
 

Единственное, что вам нужно изменить в приведенной выше конфигурации, - это IP-адрес вашего сервера и UUID пользователя, как указано в комментариях. Эта конфигурация будет перенаправлять весь трафик на ваш сервер, за исключением локальной сети (например, доступ к маршрутизатору) и диапазонов IP-адресов Китая (например, доступ к bilibili, acfun).

Запуск

  • В Windows и macOS файл конфигурации обычно находится в том же каталоге, что и Xray, и называется config.json.
    • Просто запустите Xray или Xray.exe.
  • В Linux файл конфигурации обычно находится в каталоге /etc/xray/ или /usr/local/etc/xray/.
    • Запустите команду xray run -c /etc/xray/config.json.
    • Или используйте systemd или другой инструмент для запуска Xray как службы в фоновом режиме.

Более подробную информацию можно найти в документации по конфигурации и в разделе Простыми словами.

- + diff --git a/ru/document/document.html b/ru/document/document.html index 6cb99da8fe..22486f4cd3 100644 --- a/ru/document/document.html +++ b/ru/document/document.html @@ -24,14 +24,14 @@ Вклад в документацию Project X | Project X - - + +

Вклад в документацию Project X

Мы приветствуем ваш вклад в документацию Project X и благодарим каждого контрибьютора за помощь! Вы делаете Xray лучше!

Улучшение документации

Документация Project X размещена на GitHubОткрыть в новой вкладке.

Вы можете внести изменения в документацию, выполнив следующие действия:

  1. Откройте репозиторий документации Project XОткрыть в новой вкладке, нажмите кнопку "Fork" в правом верхнем углу, чтобы создать копию репозитория документации в вашей учетной записи GitHub.

  2. Используйте любой удобный инструмент для клонирования документации из вашего репозитория, например:

git clone https://github.com/XTLS/Xray-docs-next.git
 
  1. Создайте новую ветку на основе ветки main, например:
git checkout -b your-branch
 
  1. Внесите изменения в новую ветку.

    Примечание: рекомендуем придерживаться Руководства по оформлению текстов на китайском языкеОткрыть в новой вкладке (на китайском).

  2. После внесения изменений отформатируйте их с помощью PrettierОткрыть в новой вкладке.

    Примечание: запросы на включение (PR) с ошибками форматирования могут быть отклонены.

  3. Зафиксируйте изменения и отправьте их в ваш репозиторий:

git push -u origin your-branch
 
  1. Откройте GitHub, перейдите в раздел "Pull requests" и создайте новый запрос на включение (PR) в репозиторий документации Project XОткрыть в новой вкладке.

  2. В заголовке и описании PR кратко опишите внесенные изменения.

  3. Дождитесь ответа. Если ваш PR будет принят, изменения появятся на сайте документации Project XОткрыть в новой вкладке.

Нашли ошибку?

Если вы обнаружили ошибку в документации, вы можете внести исправления или создать задачу (Issue).

- + diff --git a/ru/document/index.html b/ru/document/index.html index 63433382aa..cd90a55eb9 100644 --- a/ru/document/index.html +++ b/ru/document/index.html @@ -24,11 +24,11 @@ Быстрый старт | Project X - - + +

Быстрый старт

В этой главе вы узнаете, как максимально просто получить Xray и начать его использовать.

Загрузка и установка

Xray поддерживает разнообразные платформы, и вы можете получить разные версии Xray из множества источников и различными способами.

Перейдите в раздел Загрузка и установка, чтобы загрузить Xray.

Настройка и запуск

После загрузки и установки Xray вам нужно всего лишь настроить его, чтобы начать использование.

Перейдите в раздел Настройка и запуск, чтобы изучить самый простой способ настройки.

Команды и аргументы

Xray обладает множеством команд и аргументов, что делает его гибким и мощным.

Перейдите в раздел Команды и аргументы, чтобы узнать больше о командах и аргументах Xray.

Улучшение документации

Если вы заинтересованы, перейдите в раздел Использование документации, чтобы помочь нам улучшить документацию, или нажмите кнопку Помогите нам улучшить эту страницу! внизу страницы.

Мы очень благодарны каждому участнику за вклад! Вы делаете Project X сильнее!

Простыми словами

Практические советы для новичков.

Перейдите в раздел Простыми словами для просмотра.

Базовые навыки

Освоив основы, вы можете перейти к разделу Базовые навыки, чтобы узнать о других способах использования.

Продвинутая документация

Практические советы для опытных пользователей.

Перейдите в раздел Продвинутая документация для просмотра.

Благодарность

Огромное спасибо всем за то, что делитесь своими навыками и опытом, которые делают Xray с каждым днем ​​лучше.

- + diff --git a/ru/document/install.html b/ru/document/install.html index c895d9772b..2aa0bf2c07 100644 --- a/ru/document/install.html +++ b/ru/document/install.html @@ -24,11 +24,11 @@ Загрузка и установка | Project X - - + +

Загрузка и установка

Поддерживаемые платформы

Xray доступен на следующих платформах:

  • Windows 7 и выше (x86 / amd64 / arm32 / arm64);
    • If you need to use these version (1.8.18 and later marked with win7, 1.8.6, 1.8.4) in Windows 7, operating system update KB4474419 is required. For better Internet security, it is recommended to install KB4490628 to acquire later operating system updates from Windows Update.
  • macOS 10.10 Yosemite и выше (amd64 / arm64);
  • Linux 2.6.23 и выше (x86 / amd64 / arm / arm64 / mips64 / mips / ppc64 / s390x / riscv64);
    • Включая, но не ограничиваясь: Debian 7 / 8, Ubuntu 12.04 / 14.04 и выше, CentOS 7 / 8, Arch Linux и др.;
  • FreeBSD (x86 / amd64);
  • OpenBSD (x86 / amd64);

Загрузка Xray

Предварительно скомпилированные ZIP-архивы с двоичными файлами можно найти в Github ReleasesОткрыть в новой вкладке.

Скачайте архив для своей платформы, распакуйте его и можете использовать.

Проверка установочного пакета

Xray предлагает два способа проверки:

  • SHA1 / SHA256 хэш-сумма ZIP-архива;
  • Воспроизводимая сборка: см. Сборка Xray.

Установка на Windows

Установка на macOS

Установка на Linux

Установочные скрипты

Arch Linux

Arch User Repository

Требуется помощник AURОткрыть в новой вкладке, например, yayОткрыть в новой вкладке, установка с помощью команды yay -S xray.

Arch Linux CN

Сначала добавьте репозиторий Arch Linux CNОткрыть в новой вкладке, затем установите от имени пользователя root с помощью команды pacman -S xray.

Linuxbrew

Использование менеджера пакетов Linuxbrew аналогично Homebrew: brew install xray.

Debian WIP

Gentoo

В настоящее время существует три оверлея сторонних разработчиков, которые предоставляют сценарии установки Portage:

Добавьте оверлей в локальную систему с помощью layman или eselect-repository, а затем выполните установку.

Установка с помощью Docker

Файловая структура образа Docker

  • /etc/xray/config.json: файл конфигурации;
  • /usr/bin/xray: основная программа Xray;
  • /usr/share/xray/geoip.dat: файл данных IP;
  • /usr/share/xray/geosite.dat: файл данных доменных имен.

Графические клиенты

Генератор UUID

Генератор UUID от сторонних разработчиков: uuidgenerator.netОткрыть в новой вкладке

- + diff --git a/ru/document/level-0/ch01-preface.html b/ru/document/level-0/ch01-preface.html index b0280a89a8..039944c9f3 100644 --- a/ru/document/level-0/ch01-preface.html +++ b/ru/document/level-0/ch01-preface.html @@ -24,11 +24,11 @@ 【Глава 1】 Простыми словами | Project X - - + +

【Глава 1】 Простыми словами

1.1 Для кого эта документация?

В двух словах: для ① новичков без опыта ② желающих научиться настраивать свой собственный VPS.

1.2 Для кого эта документация не предназначена?

В том числе, но не ограничиваясь: для всевозможных гуру и экспертов, для тех, кто слишком ленив, чтобы во всём разбираться самостоятельно, для тех, кто уже умеет настраивать VPS, для тех, кто точно решил пользоваться платными VPN-сервисами, для тех, кто предпочитает использовать готовые скрипты... Короче говоря, если у вас есть технические знания или вы не хотите настраивать всё сами, можете смело закрывать эту статью. Скорее всего, она покажется вам бесполезной и даже может вызвать раздражение, а оно вам надо?

1.3 Важное замечание и другие примечания

Важное замечание:

Я не являюсь техническим экспертом, поэтому в этой статье неизбежны пробелы и неточности. Если вы обнаружите какие-либо ошибки, пожалуйста, дайте мне знать об этом деликатно, без лишних эмоций.

Отказ от ответственности:

Пожалуйста, относитесь к информации, представленной в этой статье, критически и проверяйте её самостоятельно. Я не несу никакой ответственности за любые проблемы или негативные последствия, возникшие в результате использования информации из этой статьи.

Предупреждение о многословности:

Поскольку эта статья предназначена для новичков без опыта, многие вещи будут объяснены максимально подробно. Поэтому будьте готовы к тому, что текст будет довольно многословным.

1.4 Почему самостоятельная настройка — это сложно?

Чтобы ответить на этот вопрос, нужно немного углубиться в историю вопроса.

Во-первых, обход блокировок существует уже почти двадцать лет (Шок! Ужас!). Сначала для этого достаточно было пары манипуляций (поправить файл hosts, подключиться по SSH), потом понадобились веб-прокси, затем — собственные протоколы (например, Shadowsocks) и так далее.

По мере того, как технологии блокировок совершенствовались на протяжении последних десятилетий, для самостоятельного обхода блокировок теперь нужно уметь:

  • Разбираться в основных командах Linux.
  • Понимать принципы работы сетевых протоколов.
  • Иметь технические навыки и средства для покупки и управления VPS.
  • Иметь технические навыки и средства для покупки и управления доменными именами.
  • Уметь получать TLS-сертификаты.
  • И многое другое.

Всё это превратило некогда простую задачу в пугающее испытание для новичков.

Во-вторых, о проблемах новичков.

Начинающим пользователям без технического бэкграунда, чтобы разобраться во всех этих премудростях, приходится изучать огромные массивы информации, разбросанной по всему интернету: блогам, форумам, группам в мессенджерах, репозиториям на GitHub, видео на YouTube и так далее.

Вся эта информация часто оказывается противоречивой, неполной или попросту неверной. Новичкам остаётся только гадать, кому верить и как всё это работает на самом деле.

В итоге вместо нехватки информации новички сталкиваются с её избытком. После нескольких (скорее всего, неудачных) попыток разобраться во всём этом, их энтузиазм угасает. А если по пути им ещё и «посчастливится» обратиться за помощью не в то место, их могут ещё и высмеять: «Ну ты и нуб, проще уж платным VPN пользоваться, зачем изобретать велосипед?» или «Сначала Linux изучи, потом приходи».

В такие моменты остаётся только горько усмехнуться.

1.5 «Почему бы просто не пользоваться платным VPN?»

Во-первых, я хотел бы спросить у любителей подобных советов: разве платные VPN — это панацея?

Во-вторых, я считаю, что «не знать» и «не хотеть знать» — это две большие разницы. Конечно, инфантилы, которые хотят всё и сразу, не прилагая никаких усилий, вызывают только раздражение. Но люди, которые искренне хотят разобраться во всём сами, не заслуживают презрения и издёвок. Именно эта нетерпимость к новичкам и побудила меня написать эту статью.

Давайте разберёмся, в чём плюсы и минусы платных VPN-сервисов.

Плюсы:

  1. Простота использования: сканирование QR-кода, добавление правил в один клик и т.д.
  2. Большой выбор серверов: доступ к ресурсам разных стран и регионов; например, выделенные серверы с низкой задержкой (iplc), серверы для онлайн-игр и т.д.
  3. Множество точек подключения: выше устойчивость к блокировкам, если один сервер заблокируют, можно подключиться к другому.

Риски:

За удобство приходится платить, и в случае с платными VPN-сервисами риски следующие:

  1. VPN-провайдер имеет полный доступ к вашим данным: всё, что вы делаете в интернете, обязательно проходит и с большой вероятностью хранится на серверах провайдера. Эти данные никак не защищены пользовательским соглашением или законом о защите персональных данных (вас могут отслеживать и записывать всё, что вы делаете).
  2. Отсутствие регулирования рынка: высока вероятность нарваться на мошенников (провайдер может в любой момент исчезнуть с вашими деньгами).
  3. Давление со стороны регулирующих органов: крупные VPN-провайдеры, с одной стороны, кажутся более надёжными, но, с другой стороны, чаще привлекают к себе внимание властей. В 2020 году было несколько случаев закрытия и прекращения работы крупных VPN-провайдеров, что привело к серьёзным неудобствам для пользователей (провайдер может быть вынужден прекратить работу).
  4. Непрозрачность технических решений: качество предоставляемых услуг может сильно варьироваться, не редки случаи обмана (низкая скорость, частые обрывы связи, невозможность подключения).

1.6 Так стоит ли настраивать VPN самостоятельно?

Теперь, когда вы знаете о плюсах и минусах платных VPN, решать вам. В конце концов, лучший вариант — тот, который подходит именно вам.

Выбор за вами!

  1. Если вы решили воспользоваться платным VPN, можете закрыть эту статью.

  2. Если же вы решили настроить всё самостоятельно, продолжайте чтение!

Цель этой статьи — стать отправной точкой для новичков, предоставить подробное пошаговое руководство по настройке VPN-сервера на VPS, начиная с ввода первой команды и заканчивая успешным подключением к заблокированным ресурсам.

В процессе настройки вы познакомитесь с основными командами Linux, что станет хорошей базой для дальнейшего изучения этой операционной системы.

1.7 Немного лирики

  1. В интернете много дезинформации, поэтому важно научиться критически мыслить, не поддаваться на провокации и не верить всему, что пишут.
  2. Искренне надеюсь, что, получив доступ к свободному интернету, вы сможете узнавать больше нового, наслаждаться разнообразным контентом, знакомиться с интересными людьми и находить единомышленников.
  3. Ваша личность в интернете — это всё ещё вы. Добиться полной анонимности крайне сложно, поэтому не забывайте о законах вашей страны и стран, IP-адреса которых вы используете. Всегда помните о собственной безопасности.

1.8 Ваш прогресс

⬛⬜⬜⬜⬜⬜⬜⬜ 12.5%

- + diff --git a/ru/document/level-0/ch02-preparation.html b/ru/document/level-0/ch02-preparation.html index 9e6eeb435b..89a86cf784 100644 --- a/ru/document/level-0/ch02-preparation.html +++ b/ru/document/level-0/ch02-preparation.html @@ -24,11 +24,11 @@ 【Глава 2】 Подготовка | Project X - - + +

【Глава 2】 Подготовка

Эта глава особенная, поскольку затрагивает финансовые операции. В соответствии с нейтральной позицией проекта, здесь не будет конкретных рекомендаций. Всё, что я могу сделать, — это рассказать, что вам понадобится.

2.1 Приобретение VPS

Вам нужно получить работающий VPS с не заблокированным IP-адресом и выполнить следующие базовые действия в панели управления:

  1. Установить на VPS операционную систему Debian 10 64-bit.
  2. Записать IP-адрес VPS (в этой статье он будет обозначаться как "100.200.300.400").

    Подсказка

    Это неверный IP-адрес, используемый только в качестве примера. Не забудьте заменить его на свой реальный IP-адрес.

  3. Записать порт (Port) SSH для удалённого подключения к VPS.
  4. Записать имя пользователя и пароль для удалённого подключения по SSH.

Выбор и покупка VPS — дело непростое. Рекомендуем сначала изучить этот вопрос и выбрать тариф, который соответствует вашим финансовым возможностям и требованиям к скорости и качеству связи. Также можно воспользоваться бесплатными (постоянными или временными) предложениями от крупных облачных провайдеров, таких как Oracle Cloud и Google Cloud. Главное — не влезайте в долги.

Пояснение

Несколько слов о выборе Debian 10 в качестве операционной системы. Что бы вы ни слышали в интернете, какой бы дистрибутив Linux ни советовали вам гуру, все эти споры о том, какой Linux лучше, не имеют к вам никакого отношения! Debian 10 — это надёжная и стабильная операционная система, которая отлично подходит для работы VPN-сервера и достаточно оптимизирована (например, имеет специальное ядро для облачных сред и своевременную поддержку BBR). Когда вы освоитесь с Linux, можете попробовать и другие дистрибутивы.

2.2 Выбор доменного имени

Вам нужно получить доменное имя и добавить A-запись, указывающую на IP-адрес вашего VPS, в настройках DNS.

  1. Выберите надёжного международного регистратора доменных имён. Доменная зона (расширение домена) может быть любой, главное — не используйте .cn.
  2. В настройках DNS добавьте A-запись, указывающую на IP-адрес вашего VPS (имя A-записи может быть любым, в этой статье оно будет обозначаться как "a-name". Полное доменное имя будет выглядеть как "a-name.yourdomain.com"). Должно получиться примерно так:

Добавление A-записи

Подсказка

Это не настоящий URL-адрес. Не забудьте заменить его на свой реальный адрес.

2.3 Необходимое программное обеспечение

  1. SSH-клиент для удалённого подключения:

  2. Программа для передачи файлов:

  3. Хороший текстовый редактор:

2.4 Ваш прогресс

Если вы выполнили все пункты из этого раздела, у вас уже есть всё необходимое, чтобы открыть для себя новый мир. Так чего же мы ждём? Давайте перейдём к следующей главе и сделаем это!

⬛⬛⬜⬜⬜⬜⬜⬜ 25%

- + diff --git a/ru/document/level-0/ch03-ssh.html b/ru/document/level-0/ch03-ssh.html index cc29a027ac..686b26e646 100644 --- a/ru/document/level-0/ch03-ssh.html +++ b/ru/document/level-0/ch03-ssh.html @@ -24,13 +24,13 @@ 【Глава 3】 Удалённое подключение | Project X - - + +

【Глава 3】 Удалённое подключение

3.1 Удалённое подключение к VPS (PuTTY)

Во-первых, поскольку Windows является самой распространённой операционной системой среди новичков, в этой статье мы будем использовать её в качестве примера.

Во-вторых, хотя PowerShell и WSL в Windows 10 и выше также предоставляют удобные инструменты для работы по SSH, не все версии Windows имеют эти компоненты. Поэтому в этой статье мы рассмотрим подключение по SSH с помощью старого доброго PuTTY. (После подключения по SSH действия во всех программах будут одинаковыми.)

Итак, давайте начнём.

  1. Перейдите на официальный сайтОткрыть в новой вкладке PuTTY и скачайте версию, подходящую для вашей операционной системы (в этой статье мы будем использовать 64-битную версию).

    Скачать PuTTY

  2. Запустите PuTTY. Откроется главное окно программы. Теперь возьмите блокнот, в который вы записывали информацию в предыдущей главе, и введите IP-адрес и порт вашего VPS в соответствующие поля (на скриншоте ниже). Чтобы не вводить эти данные каждый раз, можно сохранить сеанс (Saved Sessions). В дальнейшем вы сможете загрузить сохранённые настройки одним кликом.

    Настройка PuTTY

  3. Рекомендуем установить значение keepalive в разделе Connection равным 60 секундам, чтобы предотвратить разрыв SSH-соединения, если вы долгое время не будете выполнять никаких действий. Не забудьте снова сохранить настройки.

    Предотвращение разрывов соединения

Внимание

После любых изменений настроек PuTTY необходимо сохранить сеанс, иначе они будут потеряны при закрытии программы.

  1. Нажмите кнопку "Open", чтобы открыть окно SSH-подключения. Введите имя пользователя и пароль для подключения к вашему VPS (в этой статье предполагается, что имя пользователя по умолчанию — root. Обратите внимание, что при вводе пароля в Linux не отображаются символы ******. Это сделано для того, чтобы скрыть длину пароля. Не пугайтесь, ваша клавиатура в порядке!).

    Подключение по SSH

3.2 Успешное подключение по SSH! Знакомство с командной строкой!

  1. Если вы всё сделали правильно, вы увидите примерно такой экран, как на рисунке ниже. Это означает, что вы успешно подключились к серверу:

    Первое подключение к VPS

    Этот экран — аналог «рабочего стола» на удалённом сервере, но здесь нет привычных значков, курсора мыши и ярких цветов. Только текст. Это и есть командная строкаCommand Line Interface или сокращённо CLI.

    Все дальнейшие действия вам придётся выполнять в командной строке, как хакер в кино. Возможно, поначалу это покажется вам непривычным, но поверьте, в использовании командной строки нет ничего страшного или сложного. По сути, это всего лишь способ взаимодействия с компьютером с помощью текстовых команд вместо графического интерфейса. Вы пишете команду, а компьютер её выполняет.

  2. Теперь можете немного осмотреться и познакомиться с командной строкой. На этом экране уже есть полезная информация, например, версия ядра системы (в данном случае 4.19.37-5), время последнего входа в систему, IP-адрес и т.д. Конечно, в зависимости от VPS, ваш экран может выглядеть немного иначе.

  3. Обратите внимание на последнюю строку командной строки. Слева от мигающего курсора находится набор символов. В данном случае это root@vps-server:~#. Что это значит? Всё просто:

    • Текущий пользователь: root.
    • Имя сервера, на котором работает пользователь root: vps-server.
    • Текущий каталог, в котором находится пользователь root: ~.
    • Символ # указывает на то, что после него можно вводить команды.

    Первые два пункта интуитивно понятны и не требуют пояснений. Третий пункт относится к файловой системе Linux. Сейчас вам не нужно вдаваться в подробности, достаточно знать, что ~ — это «домашний каталог» текущего пользователя. Четвёртый пункт, символ #, также не требует особого внимания. Просто знайте, что в дальнейшем все команды, которые вам нужно будет вводить, будут начинаться с # или $. Это будет означать, что после этого символа нужно ввести команду (поэтому при копировании команд копируйте только текст после, без символа # или $).

3.3 Первое обновление программного обеспечения Linux!

  1. Так же, как и ваш телефон, будь то Android или iPhone, Linux нуждается в регулярном обновлении программного обеспечения для получения исправлений безопасности и новых функций. В Linux каждое приложение называется «пакетом» (package). А программа, которая управляет пакетами, называется «менеджером пакетов» (Package Manager). С помощью менеджера пакетов можно устанавливать, обновлять и удалять программы, а также обновлять саму систему Linux. Менеджеры пакетов Linux очень мощные, но сейчас вам достаточно знать, что в Debian используется менеджер пакетов apt. Давайте обновим систему с помощью apt, чтобы вы познакомились с его основными функциями.

  2. Базовые команды Linux:

    НомерКомандаОписание
    cmd-01apt updateПроверить обновления
    cmd-02apt upgradeУстановить обновления
  3. Введите первую команду, чтобы получить информацию об обновлениях:

    apt update
     
  4. Затем введите вторую команду. При появлении запроса на подтверждение установки (Y/n) введите y и нажмите Enter, чтобы начать установку.

    apt upgrade
     
  5. Весь процесс показан на гифке ниже:

    Демонстрация процесса обновления

3.4 Ваш прогресс

Поздравляем, вы сделали ещё один важный шаг! Теперь вы умеете подключаться к своему серверу по SSH! Но что делать после подключения, кроме обновления системы? Узнаем в следующей главе!

⬛⬛⬛⬜⬜⬜⬜⬜ 37.5%

- + diff --git a/ru/document/level-0/ch04-security.html b/ru/document/level-0/ch04-security.html index 77bd19f68d..b37f09bb66 100644 --- a/ru/document/level-0/ch04-security.html +++ b/ru/document/level-0/ch04-security.html @@ -24,8 +24,8 @@ 【Глава 4】 Обеспечение безопасности | Project X - - + +

【Глава 4】 Обеспечение безопасности

4.1 Зачем нужна безопасность?

Безопасность Linux-серверов — это обширная и сложная тема. Бесчисленные веб-сайты, приложения, сервисы и даже критически важная инфраструктура построены на базе Linux. За всем этим стоят огромные деньги и коммерческие интересы, что, естественно, привлекает злоумышленников. В то же время надёжная работа этих сервисов крайне важна, поэтому любые серьёзные уязвимости недопустимы. Именно поэтому множество специалистов по безопасности изо дня в день ведут борьбу на передовой, обеспечивая стабильную работу цифрового мира, к которому мы все привыкли.

Теперь, когда у вас есть собственный VPS-сервер, и вы собираетесь открыть на нём порты для перенаправления трафика, вы фактически оказываетесь на передовой этой борьбы и подвергаетесь тем же рискам. В то же время, новички, не обладающие достаточными знаниями и информацией, склонны впадать в крайности: либо они считают, что им ничего не угрожает, либо же, наоборот, впадают в паранойю.

  • Первым я бы посоветовал не относиться к безопасности легкомысленно и изучить этот вопрос более подробно, чтобы потом не пришлось кусать локти.

  • Вторым я бы посоветовал не паниковать. Ваш сервер вряд ли представляет собой лакомую цель для серьёзных злоумышленников, поэтому вам достаточно базовых мер защиты от автоматических сканеров и ботов, о которых мы и поговорим в этой главе.

4.2 Какие именно риски существуют?

Как мы уже говорили в главе про удалённое подключение, для доступа к вашему VPS достаточно знать четыре вещи: IP-адрес, порт, имя пользователя и пароль. Очевидно, что эти четыре элемента нужно защищать в первую очередь. Давайте разберём каждый из них:

  1. IP-адрес: злоумышленники могут сканировать целые диапазоны IP-адресов в поисках уязвимых серверов. Ваш IP-адрес — это публичная информация, которую невозможно скрыть.

  2. Порт: если вы используете настройки по умолчанию, то порт SSH равен 22.

  3. Имя пользователя: если вы используете настройки по умолчанию, то имя пользователя — root.

  4. Пароль: пароль не имеет значения по умолчанию. Он либо генерируется автоматически при создании VPS, либо задаётся вами. Таким образом, если вы не меняли настройки сервера, то три из четырёх элементов уже известны злоумышленникам, и вся безопасность вашего сервера держится на одном только пароле. Возможны следующие варианты:

    • Вы используете автоматически сгенерированный пароль из панели управления VPS. Такие пароли обычно состоят из случайного набора символов (букв в разных регистрах, цифр и спецсимволов) и достаточно надёжны.

    • Вы установили простой пароль, например, 123456. Взломать такой сервер не составит труда.

    • Вы установили сложный пароль, который используете где-то ещё. Это тоже небезопасно. Злоумышленники используют специальные программы, которые перебирают миллионы ранее скомпрометированных паролей из утечек данных.

  5. Важно понимать, что никакой хакер не будет лично подбирать ваш пароль. Все атаки выполняются автоматически с помощью специальных скриптов, которые работают круглосуточно. Пока вы спите, ваш сервер может подвергаться атакам.

    Если пароль будет подобран, злоумышленники получат полный доступ к вашему серверу (права пользователя root), смогут установить на него вредоносное ПО и использовать его в своих целях (например, для майнинга криптовалюты, рассылки спама, фишинговых атак, организации торрент-трекера, размещения публичных узлов для доступа к даркнету и т.д.). При этом злоумышленники могут действовать очень скрытно, и вы даже не заметите, что ваш сервер взломан, пока не получите уведомление от хостинг-провайдера о блокировке вашего аккаунта или, что ещё хуже, повестку в суд.

  6. Не забывайте, что при покупке VPS вы, скорее всего, указывали свои реальные платёжные данные. А при посещении сайтов и использовании социальных сетей ваш IP-адрес также сохраняется. Всё это может быть использовано против вас. Поэтому, если на вашем сервере произойдёт что-то противозаконное, отвечать за это придётся вам.

4.3 Какие меры безопасности нужно предпринять?

Исходя из всего вышесказанного, нам нужно защитить порт, имя пользователя и пароль, чтобы снизить риск взлома. Для этого необходимо:

  1. Изменить порт SSH на нестандартный (отличный от 22) (см. раздел 4.4).
  2. Создать нового пользователя (не root) и запретить удалённое подключение по SSH для пользователя root (см. разделы 4.5 и 4.6).
  3. Настроить аутентификацию по SSH-ключам и запретить аутентификацию по паролю (см. раздел 4.7).

Выполняйте эти действия по порядку, чтобы не оказаться случайно заблокированным на своём же сервере.

4.4 Изменение порта SSH

Давайте решим проблему с портом SSH, который по умолчанию равен 22 (обратите внимание: у некоторых хостинг-провайдеров порт SSH по умолчанию уже отличается от 22. В этом случае вы можете пропустить этот шаг, но можете и изменить порт ещё раз, следуя инструкциям ниже).

  1. Базовые команды Linux:

    НомерКомандаОписание
    cmd-03nanoТекстовый редактор
    cmd-04systemctl restartПерезапуск службы
  2. Важные файлы конфигурации Linux:

    НомерПуть к файлуОписание
    conf-01/etc/ssh/sshd_configНастройки SSH-сервера
  3. Первое, что нужно сделать, — это открыть файл настроек SSH-сервера (/etc/ssh/sshd_config) в текстовом редакторе nano. В Windows вы бы просто нашли этот файл и дважды кликнули по нему. А как это сделать в Linux? Если вы внимательно читали предыдущие разделы, то наверняка уже догадались! Правильно, нужно выполнить команду:

    nano /etc/ssh/sshd_config
    @@ -40,6 +40,6 @@
     
  4. Откройте файл настроек SSH. Мы уже делали это раньше, но теперь мы работаем не под пользователем root, а под пользователем vpsadmin. У этого пользователя нет прав на редактирование системных файлов, поэтому нужно использовать команду sudo:

    sudo nano /etc/ssh/sshd_config
     
  5. Найдите (Ctrl+W) строку PasswordAuthentication и измените значение на no.

  6. Найдите (Ctrl+W) строку PubkeyAuthentication и измените значение на yes. Сохраните изменения (Ctrl+O) и выйдите из редактора (Ctrl+X).

  7. Перезапустите SSH-сервер (не забудьте, что теперь вам нужно использовать команду sudo):

    sudo systemctl restart ssh
     
  8. Весь процесс показан на гифке ниже:

    Включение аутентификации по ключам и отключение аутентификации по паролю

  • Теперь, когда на сервере настроен публичный ключ, нужно указать PuTTY путь к приватному ключу (не забудьте сохранить сеанс!).

    Путь к приватному ключу в PuTTY

  • Готово! Теперь у вас настроена аутентификация по SSH-ключам, а аутентификация по паролю отключена. Кроме того, вы сохранили имя пользователя и путь к приватному ключу в сеансе PuTTY. Теперь для подключения к VPS достаточно будет выбрать сохранённый сеанс VPS-SERVER и нажать кнопку «Open».

    Если вы установили пароль для защиты приватного ключа, вам нужно будет ввести его при подключении, как показано на скриншоте ниже:

    Парольная фраза для приватного ключа

  • Не забудьте настроить аутентификацию по ключам и в WinSCP. В противном случае вы не сможете подключаться к серверу для передачи файлов:

    Путь к приватному ключу в WinSCP

  • Внимание

    Теперь для подключения к вашему серверу по SSH требуется авторизация по ключам. Мы рассмотрели настройку PuTTY и WinSCP, но существует множество других программ, которые также используют SSH. Настройте их самостоятельно при необходимости.

    4.8 Ваш прогресс

    На этом этапе ваш VPS защищён базовыми мерами безопасности. Конечно, это не панацея, но большинство автоматизированных атак вам уже не страшны!

    Теперь у нас есть надёжный фундамент, и в следующей главе мы можем приступить к установке и настройке необходимых компонентов Xray (а именно, веб-сервера и SSL-сертификата).

    ⬛⬛⬛⬛⬜⬜⬜⬜ 50%

    - + diff --git a/ru/document/level-0/ch05-webpage.html b/ru/document/level-0/ch05-webpage.html index ba908d12df..4bb2fcb951 100644 --- a/ru/document/level-0/ch05-webpage.html +++ b/ru/document/level-0/ch05-webpage.html @@ -24,8 +24,8 @@ 【Глава 5】 Создание веб-сайта | Project X - - + +

    【Глава 5】 Создание веб-сайта

    5.1 Зачем нужен веб-сайт?

    Начинающие пользователи могут задаться вопросом: зачем создавать веб-сайт для обхода блокировок? Я не программист, это же сложно?

    Начнём с первого вопроса. Веб-сайт нужен для того, чтобы:

    1. Получить действующий SSL-сертификат (это очень важно).
    2. Обеспечить маскировку трафика (fallback) и защититься от атак, направленных на выявление VPN-серверов.
    3. Создать сайт-прикрытие (например, блог, облачное хранилище, медиа-портал, игровой сайт), который будет отображаться при прямом доступе к серверу, делая использование VPN менее заметным.

    Теперь ответим на второй вопрос:

    1. В этой статье мы создадим максимально простой веб-сайт, состоящий из одного HTML-файла и работающий на веб-сервере Nginx, чтобы решить поставленные выше задачи. Это очень просто.
    2. Этот веб-сайт не обязательно должен быть просто прикрытием. Вы можете развивать его и превратить в полноценный проект. Всё зависит от ваших желаний и возможностей.
    3. Создание сайта-прикрытия и его продвижение — это отдельная большая тема, которая выходит за рамки этой статьи. Если вам интересно, вы можете найти информацию об этом в интернете.

    5.2 Подключение к VPS и установка Nginx

    1. В этом разделе мы будем использовать команды, которые уже были подробно рассмотрены ранее. Если вы что-то не понимаете, вернитесь и перечитайте предыдущие главы.

      sudo apt update && sudo apt install nginx
      @@ -90,6 +90,6 @@
               }
       

      Важно!

      Как уже говорилось в 3-м шаге, убедитесь, что путь /home/vpsadmin/www/webpage соответствует реальному пути к вашему файлу.

    2. Перезагрузите Nginx, чтобы применить изменения.

      sudo systemctl reload nginx
       
    3. Весь процесс настройки показан на гифке ниже:

      Настройка веб-сайта

    4. Теперь, если вы откроете в браузере адрес http://поддомен.ваш_домен.com, вы должны увидеть созданную нами страницу:

      Веб-сайт работает

    5.4 Распространённые ошибки

    Вообще, если вы внимательно следовали инструкциям, ошибок быть не должно. Однако на этом этапе многие пользователи сталкиваются с проблемами. В чём же дело? Ответ прост: невнимательность. Здесь возможны только две ошибки, и обе они связаны с невнимательностью.

    Ошибки:

    • Путь /home/vpsadmin/www/webpage в файле nginx.conf не соответствует реальному пути к файлу index.html. Nginx не может найти файл.
    • Путь указан верно, но у Nginx нет прав на чтение файла.

    Причины:

    • Вы работаете не под пользователем root, но скопировали команды из статьи без изменений (как будто списали домашнее задание вместе с именем одноклассника).
    • Вы работаете под пользователем root.

    Если у вас возникли проблемы, вернитесь к разделу 5.3 и внимательно перечитайте пункты 3 и 6.2.

    Внимание

    В предыдущих главах мы много говорили о важности использования пользователя, отличного от root, и вся статья написана с учётом этого. Поэтому проблемы, связанные с использованием root, не рассматриваются в рамках этой статьи.

    Однако я уверен, что те, кто всё-таки работает под root, достаточно опытны и смогут решить эти проблемы самостоятельно.

    5.5 Ваш прогресс

    Первый компонент Xray — веб-сайт — готов. Давайте перейдём ко второму компоненту — SSL-сертификату!

    ⬛⬛⬛⬛⬛⬜⬜⬜ 62.5%

    - + diff --git a/ru/document/level-0/ch06-certificates.html b/ru/document/level-0/ch06-certificates.html index 5e0592c0f9..835127a30a 100644 --- a/ru/document/level-0/ch06-certificates.html +++ b/ru/document/level-0/ch06-certificates.html @@ -24,8 +24,8 @@ 【Глава 6】 Управление сертификатами | Project X - - + +

    【Глава 6】 Управление сертификатами

    6.1 Получение SSL-сертификата

    Теперь нам нужно получить действующий SSL-сертификат для нашего доменного имени, чтобы веб-сайт работал по протоколу HTTPS. Это важнейший инструмент для обеспечения безопасности трафика при использовании современных VPN-сервисов, таких как Xray.

    Внимание

    Не используйте самоподписанные сертификаты. Это ненамного упростит задачу, но создаст дополнительные риски (например, возможность атак типа «человек посередине»).

    Мы будем использовать инструмент для управления сертификатами acme.shОткрыть в новой вкладке. Он простой, лёгкий, эффективный и умеет автоматически обновлять сертификаты.

    Я уверен, что вы уже освоились с базовыми командами Linux, поэтому скриншоты с выводом команд, которые мы уже использовали ранее, будут опущены. Если вы забыли, как выполнять ту или иную команду, вернитесь и перечитайте предыдущие главы.

    6.2 Установка acme.sh

    1. Базовые команды Linux:

      НомерКомандаОписание
      cmd-12wgetЗагрузка файла из интернета
      cmd-13acme.shУправление сертификатами
    2. Запустите скрипт установки:

      wget -O -  https://get.acme.sh | sh
      @@ -136,6 +136,6 @@
       [Mon 14 Feb 2022 03:00:25 PM CST] Installing key to: /etc/xray/cert/cert.key
       [Mon 14 Feb 2022 03:00:25 PM CST] Installing full chain to: /etc/xray/cert/fullchain.crt
       

    6.6 Ваш прогресс

    Наконец-то все необходимые компоненты Xray готовы! Мы подошли к самому интересному — установке и настройке самого Xray!

    ⬛⬛⬛⬛⬛⬛⬜⬜ 75%

    - + diff --git a/ru/document/level-0/ch07-xray-server.html b/ru/document/level-0/ch07-xray-server.html index c276dae396..60becb2fb7 100644 --- a/ru/document/level-0/ch07-xray-server.html +++ b/ru/document/level-0/ch07-xray-server.html @@ -24,8 +24,8 @@ 【Глава 7】Настройка Xray на сервере | Project X - - + +

    【Глава 7】Настройка Xray на сервере

    7.1 Познать многое, усвоить нужное; копить постепенно, тратить осмотрительно

    Во время написания этого руководства один знакомый в шутку заметил: "Твое руководство уже 6 глав публикуется, а до Xray всё никак не дойдёт. Кто не знает, подумает, что это руководство "Создание сайта с нуля". (И ведь не поспоришь! 😂)

    На самом деле такая структура — результат моего осознанного решения. Ведь только заложив прочный фундамент, можно в дальнейшем двигаться вперёд семимильными шагами. Я видел в чатах много новичков, которые не могут правильно использовать даже nano, не говоря уже о WinSCP. Из-за этого их config.json, написанные вручную на удалённом сервере, пестрят ошибками, а поиск и исправление этих ошибок превращается в мучение.

    Внимание

    Пройдя первые 6 глав, мы вместе с вами преодолели несколько важных этапов: освоили базовые операции Linux, научились удалённо управлять VPS, разобрались с установкой веб-сервера, управлением доменными именами, получением SSL-сертификатов. Оглядываясь назад, разве всё это кажется таким уж сложным? Теперь, имея такой солидный багаж знаний, мы подойдём к установке и настройке Xray с чувством лёгкости и уверенности, ведь всё уже готово!

    Дальнейшие шаги предельно просты:

    1. Установка
    2. Настройка (например, установка TLS-сертификата, настройка config.json)
    3. Запуск
    4. Оптимизация (например, обновление ядра, включение bbr, автоматическое перенаправление http-запросов на https и т. д.)

    7.2 Установка Xray

    Xray основан на проекте с открытым исходным кодом xray-coreОткрыть в новой вкладке (лицензия MPL 2.0). Запущенный на сервере, скомпилированный бинарный файл этого проекта, работает как серверная часть Xray; запущенный на локальном компьютере, он становится клиентской частью. Основное различие заключается в конфигурации.

    Для установки воспользуемся официальным скриптом. Он предлагает несколько вариантов установки. Вы можете ознакомиться с ними в репозитории скриптовОткрыть в новой вкладке. В данном руководстве мы будем использовать установку от имени непривилегированного пользователя.

    На момент написания руководства в скрипте есть небольшая ошибка при установке от имени непривилегированного пользователя, поэтому мы выполним эти шаги вручную. Заодно рассмотрим команду удаления файлов в Linux.

    1. Базовые команды Linux:

      НомерКомандаОписание
      cmd-14rmУдаление файлов
    2. Скачиваем установочный скрипт:

      wget https://github.com/XTLS/Xray-install/raw/main/install-release.sh
      @@ -187,6 +187,6 @@
       
    3. Изменяем настройки перенаправления в файле конфигурации Xray, заменив порт 80 на 8080 (находим "dest": 80 и меняем на "dest": 8080):

      sudo nano /usr/local/etc/xray/config.json
       
    4. Перезапускаем Xray:

      sudo systemctl restart xray
       
    5. Весь процесс показан на гифке:

      Автоматическое перенаправление HTTP на HTTPS

    6. Теперь, если вы попытаетесь открыть сайт по адресу http://sub.yourdomain.com, он должен автоматически перенаправиться на HTTPS:

      Проверка автоматического перенаправления HTTP на HTTPS

    7.9 Оптимизация сервера: более гибкая настройка перенаправления

    Если вам нужны более гибкие настройки перенаправления, обратитесь к статье «Разбор функции Fallback».

    7.10 Ваши успехи

    Поздравляю! На этом этапе у вас есть работающий сервер с обходом блокировок и сайт-приманка, который защитит вас от сканирования. Теперь достаточно установить клиентское приложение на ваше устройство — и можно наслаждаться свободным интернетом!

    ⬛⬛⬛⬛⬛⬛⬛⬜ 87.5%

    7.11 Важные исправления

    1. В первоначальной версии руководства был указан неверный путь к файлу конфигурации Xray (config.json). Если вы настроили Xray по старой инструкции, то он не запустится. Приносим извинения за неудобства!

      • Верный путь: /usr/local/etc/xray/config.json
      • Неверный путь: /usr/local/etc/config.json

      Затронутые разделы:

      • 7.4 Настройка Xray - 3. Создание файла конфигурации Xray с помощью nano
      • 7.8 Оптимизация сервера: автоматическое перенаправление HTTP на HTTPS - 6. Изменяем настройки перенаправления в файле конфигурации Xray
    2. В первоначальной версии руководства была ошибка в настройках Nginx (неверный путь к папке с файлами сайта). Если вы настроили Nginx по старой инструкции, то сайт не будет работать. Приносим извинения за неудобства!

      • Верный путь: root /home/vpsadmin/www/webpage;
      • Неверный путь: root /var/www/website/html

      Затронутые разделы:

      • 7.8 Оптимизация сервера: автоматическое перенаправление HTTP на HTTPS - 4. Добавляем новый сервер, который будет прослушивать локальный порт и отдавать файлы сайта.
    - + diff --git a/ru/document/level-0/ch08-xray-clients.html b/ru/document/level-0/ch08-xray-clients.html index 6f093ab06c..a40de53a9a 100644 --- a/ru/document/level-0/ch08-xray-clients.html +++ b/ru/document/level-0/ch08-xray-clients.html @@ -24,8 +24,8 @@ 【Глава 8】Настройка Xray на клиенте | Project X - - + +

    【Глава 8】Настройка Xray на клиенте

    8.1 Как работает Xray: краткое описание

    Чтобы правильно настраивать и использовать Xray, важно понимать принципы его работы. Новичкам поможет упрощённая схема, на которой не показаны некоторые сложные моменты:

    Поток данных в Xray

    Ключевые моменты:

    1. Приложение должно самостоятельно или с помощью стороннего инструмента перенаправить трафик на входящее подключение (inbounds) клиента Xray.

    2. Поступивший на клиент трафик обрабатывается модулем маршрутизации (routing) в соответствии с заданными правилами и перенаправляется на разные исходящие подключения (outbounds) клиента Xray, например:

      • Трафик на китайские ресурсы — напрямую (direct)
      • Трафик на зарубежные ресурсы — через VPS (proxy)
      • Рекламный трафик — блокируется (block)
    3. Трафик на зарубежные ресурсы, перенаправленный на VPS, проходит через Великий Китайский Файрвол и попадает на входящее подключение (inbounds) сервера Xray.

    4. Как и на клиенте, трафик, поступивший на сервер, обрабатывается модулем маршрутизации (routing) в соответствии с заданными правилами и перенаправляется на разные исходящие подключения (outbounds):

      • Поскольку сервер находится за пределами Китая, трафик по умолчанию идёт напрямую, что позволяет получить доступ к заблокированным ресурсам (direct).
      • При необходимости можно настроить перенаправление трафика на другие VPS (proxy).
      • На сервере также можно блокировать нежелательный трафик, например, рекламу или торренты (block).

    Внимание!

    Важно помнить, что маршрутизация в Xray очень гибкая, и описанный выше сценарий — лишь один из множества возможных.

    Используя файлы geosite.dat и geoip.dat, можно очень гибко управлять маршрутизацией трафика по доменным именам и IP-адресам. Это гораздо удобнее, чем устаревший GFWList, поскольку позволяет очень точно настроить правила: например, можно разрешить прямое подключение к доменам Apple, перенаправить трафик на домены Amazon через прокси-сервер, блокировать доступ к доменам Baidu и т. д.

    Более подробно о маршрутизации в Xray читайте в статье «Разбор функции маршрутизации (routing)». Советую сначала дочитать эту главу и настроить базовый клиент, а потом уже углубляться в тонкости маршрутизации.

    8.2 Подключение клиента к серверу

    Теперь, когда вы понимаете принципы работы Xray, настройка клиента сводится к тому, чтобы сообщить ему, как подключиться к вашему VPS. Это как настроить PuTTY для подключения к серверу, только в случае с Xray параметров подключения больше, чем IP-адрес, порт, имя пользователя и пароль.

    Набор параметров подключения в Xray зависит от используемого протокола. В главе 7 мы настроили сервер на использование протокола VLESS с шифрованием XTLS. Посмотрим на файл конфигурации сервера, чтобы узнать, какие параметры нужны для подключения:

    • Адрес сервера: sub.yourdomain.com
    • Порт сервера: 443
    • Протокол: vless
    • Поток: xtls-rprx-vision (режим vision подходит для всех платформ)
    • Идентификатор: uuiduuid-uuid-uuid-uuid-uuiduuiduuid
    • Безопасность: "allowInsecure": false

    Ниже приведен список популярных клиентов Xray для мобильных и настольных устройств. Каждый клиент имеет свой собственный интерфейс, поэтому я не буду делать скриншоты для каждого из них. Внимательно изучите документацию к выбранному клиенту и укажите нужные параметры подключения.

    Внимание!

    Многие клиенты поддерживают как xray-core, так и v2fly-core. Но по умолчанию может использоваться не тот, который вам нужен. Убедитесь, что вы выбрали нужный инструмент!

    На этом этапе ваша система готова к работе!

    8.3 Дополнительное задание 1: настройка xray-core на ПК вручную

    Хотя на предыдущем шаге мы уже всё настроили, любознательным и обладающим хорошей памятью читателям наверняка вспомнятся мои слова из предыдущей главы о том, что xray-core можно запускать как на сервере, так и на клиенте. Так как же использовать xray-core в качестве клиента?

    Чтобы ответить на этот вопрос, я добавил этот раздел с дополнительным заданием. Оно немного выходит за рамки основного материала и может показаться сложным, но у него есть свои преимущества:

    • Вы всегда будете использовать самую последнюю версию xray-core, не дожидаясь, пока разработчики клиентов выпустят обновления.
    • Вы получите максимальную гибкость в настройке маршрутизации (хотя стоит отметить, что Qv2ray имеет мощный редактор маршрутизации, который позволяет настраивать все функции xray-core).
    • Вы сэкономите системные ресурсы (графические клиенты всегда потребляют больше ресурсов, чем консольные).

    Недостаток этого способа заключается в том, что вам придётся настраивать клиент вручную, редактируя файл конфигурации. Но ведь на сервере вы уже делали это, так что ничего сложного здесь нет. Давайте разберёмся по шагам:

    1. Скачайте последнюю версию xray-core для вашей платформы из репозитория на GitHubОткрыть в новой вкладке и распакуйте архив в удобное место.

    2. Создайте пустой файл конфигурации config.json в той же папке (думаю, с этим проблем не возникнет).

    3. Что значит "удобное место"? Это зависит от платформы.

    4. Заполните файл конфигурации.

      • Я написал пример конфигурации, основанный на схеме из раздела 8.1 (прямое подключение к китайским ресурсам, проксирование трафика на зарубежные ресурсы через VPS, блокировка рекламы) и параметрах подключения из раздела 8.2.
      • Замените uuid на идентификатор из вашей конфигурации сервера.
      • Замените address на доменное имя вашего сервера.
      • Замените serverName на доменное имя вашего сервера.
      • Я добавил подробные комментарии к каждому разделу конфигурации.
      // ССЫЛКИ:
      @@ -183,6 +183,6 @@
       

    8.4 Дополнительное задание 2: запуск xray-core на ПК

    Итак, мы создали файл конфигурации. Как теперь запустить xray-core? Двойной клик по файлу не работает!

    Во-первых, вам нужно открыть командную строку.

    1. Пользователи Linux и macOS наверняка знают, как это сделать. Просто найдите приложение «Терминал».
    2. В Windows используйте «Командную строку» или PowerShell (пользователи WSL, можете использовать привычный вам «Терминал»).

    Во-вторых, нам нужно указать xray путь к файлу конфигурации config.json и запустить его.

    1. В Windows, если файл xray.exe находится в папке C:\Xray-windows-64\, а файл config.json — в той же папке, то команда запуска будет выглядеть так:

      C:\Xray-windows-64\xray.exe -c C:\Xray-windows-64\config.json
       

      Подсказка

      Параметр -c указывает путь к файлу конфигурации.

    2. Аналогично, в Linux и macOS, если файл xray находится в папке /usr/local/bin/, а файл config.json — в папке /usr/local/etc/xray/, то команда запуска будет выглядеть так:

      /usr/local/bin/xray -c /usr/local/etc/xray/config.json
       

      Подсказка

      В каждой системе есть переменные окружения, которые хранят пути к часто используемым папкам. Указывать полный путь к файлу xray не обязательно, при его расположении в таких директориях. Но я всё же указал его для надёжности.

    8.5 Дополнительное задание 3: автозапуск xray-core на ПК

    Если вы попробовали запускать xray-core вручную, то наверняка заметили следующие недостатки:

    1. При каждом запуске Xray открывается чёрное окно консоли, что не очень красиво.
    2. Xray не запускается автоматически при загрузке системы, поэтому его приходится запускать вручную каждый раз.

    Спешу вас обрадовать: эти проблемы решаемы! Но как именно их решить, я оставлю вам в качестве домашнего задания (подсказка: загляните в раздел FAQ на сайте документации).

    8.6 Финишная прямая!

    Уверен, что те, кто дочитал до этого места, — это любознательные и целеустремлённые люди, которые готовы учиться новому! Я от всей души поздравляю вас, ведь вы самостоятельно, начиная с самых азов, настроили сервер VPS и клиент Xray! Это огромная победа!

    Надеюсь, теперь вы больше не боитесь Linux и разобрались с тем, как работает Xray.

    На этом наше повествование завершается!

    ⬛⬛⬛⬛⬛⬛⬛⬛ 100%

    8.7 В бесконечность и далее!

    Но это ещё не всё, что может Xray.

    Xray — это мощный и многофункциональный инструмент, который можно использовать для решения самых разных задач. В этом руководстве мы лишь поверхностно рассмотрели самые простые и наглядные варианты его настройки.

    Если вам достаточно и этого, то наслаждайтесь свободой в интернете! Но если ваш пытливый ум жаждет новых знаний, то продолжайте изучать безграничные возможности Xray!

    Дополнительную информацию можно найти здесь:

    1. xtls.github.ioОткрыть в новой вкладке — официальная документация
    2. Официальная группа в TelegramОткрыть в новой вкладке — активное и дружелюбное сообщество

    В бесконечность и далее!

    Вместо послесловия

    Надеюсь, это небольшое путешествие, в которое я вас отправил, поможет вам сделать интернет лучше.

    Конечно, со временем информация из этого руководства устареет. Но вы будете расти и развиваться, и, возможно, когда-нибудь, вспоминая это руководство и те цели, которые я ставил перед собой, создавая его, вы передадите свои знания другим, чтобы эта эстафета помощи новичкам не прекращалась.

    Мы живём в мире, где царят тьма и цензура. Люди бродят в одиночестве в поисках лучика света. И если мы не будем помогать друг другу и поддерживать друг друга на этом пути, то в конце концов нас ждёт лишь печальная картина запустения.

    - + diff --git a/ru/document/level-0/ch09-appendix.html b/ru/document/level-0/ch09-appendix.html index e8e219a787..8f23fbd967 100644 --- a/ru/document/level-0/ch09-appendix.html +++ b/ru/document/level-0/ch09-appendix.html @@ -24,11 +24,11 @@ [Глава 9] Приложение | Project X - - + +

    [Глава 9] Приложение

    1. Индекс основных команд Linux для начинающих

    НомерНазвание командыОписание командыГлава
    cmd-01apt updateОбновление списка пакетовГлава о удаленном подключении
    cmd-02apt upgradeОбновление пакетов системыГлава о удаленном подключении
    cmd-03nanoТекстовый редакторГлава о безопасности
    cmd-04systemctl restartПерезапуск сервисаГлава о безопасности
    cmd-05adduserДобавление пользователяГлава о безопасности
    cmd-06apt installУстановка пакетаГлава о безопасности
    cmd-07visudoРедактор для настройки sudoГлава о безопасности
    cmd-08sudoВыполнение команды от имени rootГлава о безопасности
    cmd-09chmodИзменение прав доступа к файлу/папкеГлава о безопасности
    cmd-10mkdirСоздание папкиГлава о создании сайта
    cmd-11systemctl reloadПерезагрузка конфигурации сервисаГлава о создании сайта
    cmd-12wgetЗагрузка файла/страницы из сетиГлава об управлении сертификатами
    cmd-13acme.shУправление сертификатами с помощью acme.shГлава об управлении сертификатами
    cmd-14rmУдаление файлов/папокГлава о Xray сервере
    cmd-15crontab -eРедактирование crontab текущего пользователяГлава о Xray сервере
    cmd-16touchСоздание пустого файлаГлава о Xray сервере
    cmd-17systemctlБазовые команды управления сервисами systemdГлава о Xray сервере
    cmd-18rebootПерезагрузка LinuxГлава о Xray сервере

    2. Индекс важных конфигурационных файлов Linux

    НомерРасположение файлаОписание файлаГлава
    conf-01/etc/ssh/sshd_configКонфигурация SSH сервераГлава о удаленном подключении
    conf-02/etc/nginx/nginx.confКонфигурация NginxГлава о создании сайта
    conf-03/etc/apt/sources.listСписок репозиториев APTГлава о Xray сервере
    conf-04/etc/apt/sources.list.d/vpsadmin.listСписок пользовательских репозиториев APTГлава о Xray сервере
    conf-05crontab -eCrontab текущего пользователяГлава о Xray сервере
    conf-06/etc/sysctl.confНастройки ядра LinuxГлава о Xray сервере
    conf-07/etc/sysctl.d/vpsadmin.confПользовательские настройки ядра LinuxГлава о Xray сервере

    3. Индекс важных файлов Xray

    НомерРасположение файлаОписание файлаГлава
    xray-01/usr/local/etc/xray/config.jsonКонфигурация XrayГлава о Xray сервере
    xray-02/home/vpsadmin/xray_cert/xray.certTLS сертификатГлава о Xray сервере
    xray-03/home/vpsadmin/xray_cert/xray.keyTLS ключГлава о Xray сервере
    xray-04/home/vpsadmin/xray_log/access.logЛог доступа XrayГлава о Xray сервере
    xray-05/home/vpsadmin/xray_log/error.logЛог ошибок XrayГлава о Xray сервере
    - + diff --git a/ru/document/level-0/index.html b/ru/document/level-0/index.html index e92634f4ab..1bb8eb1032 100644 --- a/ru/document/level-0/index.html +++ b/ru/document/level-0/index.html @@ -24,11 +24,11 @@ Простые разговоры о сложном | Project X - - + +

    Простые разговоры о сложном

    Эта глава - базовый курс «С нуля», новичкам читать и учить обязательно

    Подсказка

    Сделано с ❤️ @ricuhkaenОткрыть в новой вкладке

    【Глава 1】 Введение - Чужой или свой сервер? Вот в чём вопрос

    【Глава 2】 Подготовка - Прежде чем браться за дело, заготовь средства

    【Глава 3】 Удалённое подключение - Мост между севером и югом, пропасть превращается в путь

    【Глава 4】 Безопасность - Небрежность в безопасности, и родные будут лить слёзы

    【Глава 5】 Создание сайта - Покажи свою красоту

    【Глава 6】 Управление сертификатами - Законно то, что с лицензией

    【Глава 7】 Xray сервер - Наконец-то дождались

    【Глава 8】 Xray клиенты - Новое начало

    【Глава 9】 Приложение - Все контрольные точки здесь

    - + diff --git a/ru/document/level-1/fallbacks-lv1.html b/ru/document/level-1/fallbacks-lv1.html index bc10ae64be..bb7c40c84a 100644 --- a/ru/document/level-1/fallbacks-lv1.html +++ b/ru/document/level-1/fallbacks-lv1.html @@ -24,8 +24,8 @@ Обзор функции Fallback | Project X - - + +

    Обзор функции Fallback

    При использовании Xray вы наверняка много раз слышали о функции "fallback". В этой статье мы кратко рассмотрим логику этой функции и способы ее применения.

    1. Что такое Fallback в простых словах

    Если вы использовали конфигурацию Xray из нашего руководства и настроили автоматическое перенаправление HTTP на HTTPS, то у вас уже есть простой fallback на основе протокола VLESS:

    {
    @@ -200,6 +200,6 @@
       }
     }
     
  • Теперь мы можем нарисовать полную схему fallback:

  • 6. Заключение

    На этом обзор функции "fallback" в Xray завершен. Надеемся, что эта статья поможет вам лучше понять возможности Xray.

    7. Дополнительное задание

    Позвольте мне нагло оставить вам дополнительное задание: есть ли что-то, что можно оптимизировать в шаблоне VLESS-TCP-XTLS-WHATEVERОткрыть в новой вкладке, описанном в этой статье?

    Подсказка: автоматическое перенаправление HTTP на HTTPS.

    - + diff --git a/ru/document/level-1/fallbacks-with-sni.html b/ru/document/level-1/fallbacks-with-sni.html index 7396917485..50ff950cdf 100644 --- a/ru/document/level-1/fallbacks-with-sni.html +++ b/ru/document/level-1/fallbacks-with-sni.html @@ -24,8 +24,8 @@ SNI Fallback | Project X - - + +

    Маскировка и разделение трафика по доменам с помощью функции SNI Fallback

    VLESS - это очень легкий протокол, который, как и Trojan, не использует сложного шифрования и обфускации трафика. Вместо этого он, подобно тому, как искусный мастер кунг-фу скрывает свою силу, шифрует трафик с помощью протокола TLS, маскируя его под обычный HTTPS-трафик и позволяя ему беспрепятственно проходить через Великий китайский файрвол. Для лучшей маскировки от активного зондирования вместе с VLESS была представлена функция Fallbacks (резервирование). В этой статье мы рассмотрим, как использовать функцию Fallbacks входящего протокола VLESS в Xray совместно с Nginx или Caddy для реализации разделения трафика по доменам при обеспечении полной маскировки.

    Сценарии использования

    Из-за XTLS Xray необходимо прослушивать порт 443, что создает проблему, если на сервере уже запущен веб-сайт - сайт либо не сможет работать, либо его придется запускать на другом порту, что нежелательно. Есть три способа решить эту проблему:

    • Xray прослушивает другие часто используемые порты (например, 22, 3389, 8443).

      Это самое простое решение, но оно не идеально.

    • Nginx или HAProxy прослушивает порт 443 и выполняет обратное проксирование на уровне L4 с разделением трафика по SNI, что позволяет использовать один порт для нескольких сервисов.

      Этот вариант более сложный и требует определенных знаний Nginx или HAProxy, поэтому мы не будем его здесь подробно рассматривать.

    • Xray прослушивает порт 443 и использует функцию Fallbacks для перенаправления трафика веб-сайта на Nginx или Caddy на основе SNI.

      Этот вариант имеет среднюю сложность и является тем, который мы рассмотрим в этом руководстве.

    Что такое SNI

    SNI (Server Name Indication) - это расширение протокола TLS. Те, кто знаком с обратным проксированием, знают, что для правильной маршрутизации трафика по доменному имени необходимо следующее правило:

    proxy_set_header Host имя_хоста;
    @@ -210,6 +210,6 @@
         redir https://{host}{uri} permanent
     }
     

    Ссылки

    1. Указание имени сервера - ВикипедияОткрыть в новой вкладке
    2. Home · acmesh-official/acme.sh WikiОткрыть в новой вкладке
    3. HTTP/2 - ВикипедияОткрыть в новой вкладке

    Примечания


    1. Часто задаваемые вопросы - Let's Encrypt - бесплатные SSL/TLS сертификатыОткрыть в новой вкладке ↩︎

    2. Proxy Protocol - HAProxy TechnologiesОткрыть в новой вкладке ↩︎

    3. proxy protocol 介绍及 nginx 配置 - 简书Открыть в новой вкладке ↩︎

    4. v2fly-github-io/vless.md at master · rprx/v2fly-github-ioОткрыть в новой вкладке ↩︎

    - + diff --git a/ru/document/level-1/index.html b/ru/document/level-1/index.html index f8b089686b..ccc30691c3 100644 --- a/ru/document/level-1/index.html +++ b/ru/document/level-1/index.html @@ -24,11 +24,11 @@ Советы для начинающих | Project X - - + +
    - + diff --git a/ru/document/level-1/routing-lv1-part1.html b/ru/document/level-1/routing-lv1-part1.html index 4b7aa2b899..10670b7d05 100644 --- a/ru/document/level-1/routing-lv1-part1.html +++ b/ru/document/level-1/routing-lv1-part1.html @@ -24,8 +24,8 @@ Краткий обзор функции маршрутизации (routing) (часть 1) | Project X - - + +

    Краткий обзор функции маршрутизации (routing) (часть 1)

    Если "мощность" Xray в основном заключается в его высокой скорости и широкой совместимости, то его "гибкость" в первую очередь связана с продуманной функцией "routing" (маршрутизация). В этой статье мы кратко рассмотрим логику этой функции и способы ее применения.

    1. Знакомство с тремя братьями-маршрутизаторами

    Чтобы понять маршрутизацию, нужно понимать, что для ее полноценной работы нужны три компонента: 1. входящий трафик (inbound); 2. маршрутизация (routing); 3. исходящий трафик (outbound).

    Три брата-маршрутизатора

    Три брата, поклявшиеся в верности, не обязательно родились в один день, но должны быть готовы умереть в один день.

    Поэтому запомните: если один из элементов работает неправильно, функция маршрутизации может не работать.

    Поскольку маршрутизация очень гибкая, чтение только технической документации может вас запутать, поэтому в этой статье мы будем использовать конкретные примеры, чтобы объяснить все пошагово.

    Внимание

    Функция маршрутизации настолько гибкая, что примеры в этой статье приведены только для объяснения соответствующих концепций. На практике, пожалуйста, корректируйте их в соответствии с вашими потребностями.

    2. Основы: "Братья едины"

    На рисунке ниже показан пример, когда входящий трафик от приложения поступает на Xray на клиенте, маршрутизируется на исходящий трафик и отправляется на VPS.

    Давайте проанализируем каждый шаг:

    2.1 Входящий трафик

    Подсказка

    Входящий трафик (inbound): это то, как трафик попадает в Xray.

    Пример конфигурации входящего трафика ниже означает, что данные поступают в Xray по протоколу socks через порт 10808 с локального адреса 127.0.0.1. Xray присваивает этому входящему трафику имя inbound-10808 с помощью [tag].

    {
    @@ -141,6 +141,6 @@
       ]
     }
     

    Теперь правила маршрутизации выглядят так:

    В этом и заключается гибкость функции маршрутизации - вы можете свободно менять порядок правил для достижения различных результатов.

    На этом мы закончили объяснение того, как использовать файл geosite.dat для разделения сетевого трафика по доменному имени с помощью правил маршрутизации.

    5. Покорение новых высот - Различные условия сопоставления маршрутов

    Пожалуйста, убедитесь, что вы хорошо усвоили материал, изложенный выше, поскольку это основа для понимания принципов работы функции маршрутизации. Имея эту базу, мы можем двигаться дальше и рассмотреть более подробные параметры конфигурации и условия сопоставления.

    После того, как вы прочитаете следующий раздел, вы сможете свободно настраивать свои собственные правила маршрутизации! Так чего же мы ждем? Давайте перейдем к части 2!

    - + diff --git a/ru/document/level-1/routing-lv1-part2.html b/ru/document/level-1/routing-lv1-part2.html index 7f57033e6a..354b0bf36b 100644 --- a/ru/document/level-1/routing-lv1-part2.html +++ b/ru/document/level-1/routing-lv1-part2.html @@ -24,8 +24,8 @@ Краткий обзор функции маршрутизации (routing) (часть 2) | Project X - - + +

    Краткий обзор функции маршрутизации (routing) (часть 2)

    Добро пожаловать на продолжение изучения функции маршрутизации в Xray!

    В части 1 мы разобрались с логикой работы функции маршрутизации и настроили простое разделение трафика по домену на основе файла geosite.dat.

    Как уже было сказано, разделение по домену — это лишь верхушка айсберга возможностей функции маршрутизации. Давайте посмотрим, что еще, кроме домена, можно использовать в качестве критерия для разделения трафика!

    5. Покорение новых высот - Различные условия сопоставления маршрутов

    [домен], [IP], [протокол], etc.

    Разделение по домену уже позволяет нам в общих чертах разделить сетевой трафик. Почему в общих чертах?

    Потому что, хотя "разделение мира на три части" — это правильная стратегия, ее реализация только с помощью доменов имеет множество недостатков, например:

    1. После прочтения нашего руководства я зарегистрировал новый домен proxy.yourdomain.com для своего VPS и хочу, чтобы трафик на него всегда проксировался. Есть ли он в geosite.dat?
    2. У меня есть еще один домен direct.yourdomain.com, и я хочу, чтобы трафик на него всегда шел напрямую. Есть ли он в geosite.dat?
    3. Правильно ли настроен прямой доступ для локального трафика на 127.0.0.1 (например, docker)?
    4. Правильно ли настроен прямой доступ для трафика в моей локальной сети 192.168.*.* (например, роутер, NAS)?
    5. Правильно ли настроен прямой доступ для моих DNS-запросов к внутренним DNS-серверам (например, 223.5.5.5)?
    6. Правильно ли настроен прокси для моих DNS-запросов к внешним DNS-серверам (например, 1.1.1.1)?
    7. Правильно ли настроен прямой доступ для других внутренних сайтов, у которых нет доменного имени, а только IP-адрес, как у внутренних DNS-серверов?
    8. Правильно ли настроен прокси для других внешних сайтов, у которых нет доменного имени, а только IP-адрес, как у внешних DNS-серверов?
    9. Как настроить принудительное прямое подключение для торрент-трафика, который, хотя и поступает извне, может привести к блокировке VPS при проксировании?
    10. ......

    Я говорю, что разделение по домену имеет много недостатков, потому что файл geosite.dat содержит только ограниченный набор часто используемых доменов. Другими словами, полагаясь только на него, мы:

    • не сможем сопоставить новые домены, которых нет в файле;
    • не сможем сопоставить правила на основе IP-адресов;
    • не сможем сопоставить правила на основе сетевых протоколов.

    Внимание

    Давайте вспомним, что происходит, когда эти условия не выполняются? Верно, срабатывает скрытое правило маршрутизации: трафик перенаправляется на первый исходящий трафик. Это означает, что:

    • если вашим первым исходящим трафиком является [direct-out]: все, что должно идти напрямую, будет работать правильно, а все, что должно проксироваться, будет работать неправильно;
    • если вашим первым исходящим трафиком является [proxy-out-vless]: все, что должно проксироваться, будет работать правильно, а все, что должно идти напрямую, будет работать неправильно.

    Поэтому нам нужен способ, который позволит нам получить и то, и другое. Существует ли такой способ? Конечно, существует! Нам просто нужны дополнительные критерии сопоставления помимо домена.

    5.1 Разделение по определенному домену: [domain], [full] и т. д.

    1. Для сопоставления поддомена, например a-name.yourdomain.com, мы используем full: "a-name.yourdomain.com".
    2. Проблемы 1 и 2, описанные выше, можно решить, указав исходящий трафик [proxy-out-vless] для proxy.yourdomain.com и исходящий трафик [direct-out] для direct.yourdomain.com.
    3. Для сопоставления всех поддоменов yourdomain.com мы используем domain: "yourdomain.com".
    4. Эти два правила могут быть независимыми, чтобы настроить прямое подключение для одних поддоменов и проксирование для других.
    5. Кроме того, [domain] поддерживает сопоставление с помощью регулярных выражений. Подробнее см. документацию по модулю маршрутизации.

    Конфигурация выглядит следующим образом:

    {
    @@ -187,6 +187,6 @@
       }
     }
     

    На самом деле, в пункте 6 я уже привел упорядоченные правила, принцип которых заключается в том, что одинаковые критерии сопоставления можно объединять, а разные критерии сопоставления должны быть разделены.

    8. Скрытые пути

    Секретный проход для преобразования [domain] в [ip]: domainStrategy

    В пункте 5.4 мы рассмотрели различные критерии для сопоставления трафика, среди которых были домен [domain] и IP-адрес [IP].

    Если вы знакомы с принципами работы DNS, то знаете, что при обращении к домену [domain] сначала нужно отправить запрос на DNS-сервер, чтобы получить IP-адрес [IP], соответствующий домену, а затем отправить фактический запрос на этот IP-адрес.

    Поэтому у Xray есть два шанса определить тип входящего запроса к домену. Использовать ли эти два шанса, решает параметр domainStrategy. Он имеет три значения:

    • AsIs
    • IPIfNonMatch
    • IPOnDemand

    Давайте рассмотрим каждое из них:

    8.1 Стратегия домена: "AsIs"

    "As Domain Is" означает "как есть, без лишних действий".

    Проще говоря, "сопоставлять только по домену".

    Подсказка

    AsIs на самом деле означает "как есть, без изменений". Описание 🍉-sensei не совсем точное.

    В этом режиме вся обработка выполняется внутри Xray без обмена данными с внешним миром, поэтому скорость максимальна. Стратегия обработки несопоставимых доменов также ясна: как уже говорилось ранее, они автоматически перенаправляются на первый исходящий трафик. Поэтому это наиболее рекомендуемая стратегия для обычного использования функции маршрутизации.

    8.2 Стратегия домена: "IPIfNonMatch"

    "lookup IP if (there's) no matching rule" означает "искать IP-адрес, если не найдено совпадений по другим правилам".

    Проще говоря, "сначала сопоставить целевой адрес со всеми правилами, а если совпадений не найдено, то получить IP-адрес через DNS и снова сопоставить его со всеми правилами".

    В этом режиме домены, не сопоставленные ни с одним правилом, будут проходить через DNS-запрос и второй этап сопоставления правил, что займет больше времени, чем в режиме AsIs. Поэтому это не самая рекомендуемая стратегия.

    8.3 Стратегия домена: "IPOnDemand"

    "Demand IP" означает "запрашивать IP-адрес".

    Проще говоря, "если в правилах маршрутизации есть правила на основе IP-адреса, то все запросы на основе домена [domain] будут преобразованы в IP-адреса [IP] и сопоставлены с правилами на основе IP-адреса".

    В этом режиме все запросы к доменам будут проходить через DNS-запрос, поэтому первый запрос будет медленным. Хотя благодаря механизму кэширования DNS в Xray последующие запросы к тому же домену будут быстрыми, в целом это не самая рекомендуемая стратегия.

    Внимание

    domainStrategy действует только для доменов, не путайте!

    9. Задание для размышления

    До сих пор мы рассматривали логику конфигурации маршрутизации на основе одного входящего и одного исходящего трафика.

    Но, как вы знаете, Xray поддерживает несколько портов и протоколов. Что, если я спрошу вас:

    1. Я хочу, чтобы протокол VLESS перенаправлял мой обычный веб-трафик и трафик приложений на высокоскоростной сервер в США.
    2. Я хочу, чтобы протокол trojan перенаправлял весь мой трафик Netflix на сервер в Японии, чтобы разблокировать все аниме.
    3. Я хочу, чтобы протокол shadowsocks перенаправлял весь мой игровой трафик на сервер в Гонконге для минимальной задержки.
    4. Я хочу, чтобы был отдельный порт, который перенаправлял бы весь трафик telegram на VPS.
    5. Я хочу, чтобы был отдельный порт, который перенаправлял бы весь торрент-трафик на мощный сервер в Европе.
    6. Я хочу......

    Можно ли реализовать эти сценарии с помощью функции маршрутизации?

    Ответ, конечно же, да! Однако, это выходит за рамки уровня 1, поэтому я оставлю это вам для самостоятельного изучения!

    10. Заключение

    На этом обзор функции маршрутизации в Xray завершен. Надеюсь, эта статья помогла вам лучше понять гибкость Xray.

    11. Примечания

    • Теперь вы можете перечитать раздел Маршрутизация и посмотреть, стало ли вам что-то понятнее.
    • 🍉🍉🍉🍉🍉 😄
    - + diff --git a/ru/document/level-1/work.html b/ru/document/level-1/work.html index cfd60e6ae2..80d2bdb484 100644 --- a/ru/document/level-1/work.html +++ b/ru/document/level-1/work.html @@ -24,11 +24,11 @@ Режимы работы Xray | Project X - - + +

    Режимы работы Xray

    Режим одного сервера

    Как и в случае с другими прокси-инструментами, вам понадобится сервер с настроенным Xray, а затем установить и настроить клиент Xray на вашем устройстве, после чего вы сможете свободно пользоваться Интернетом.

    Один сервер Xray может одновременно обслуживать несколько устройств, использующих разные протоколы проксирования. При правильной настройке Xray может распознавать и различать трафик, который нужно проксировать, и трафик, который можно отправлять напрямую, без проксирования.

    Режим моста

    Если вы не хотите настраивать маршрутизацию на каждом устройстве, вы можете настроить промежуточный сервер, который будет принимать весь трафик от клиентов и перенаправлять его в зависимости от настроек.

    Принцип работы

    Перед настройкой Xray давайте рассмотрим, как он работает. Ниже представлена схема внутреннего устройства одного процесса Xray. Несколько процессов Xray работают независимо друг от друга.

    • Для нормальной работы необходимо настроить как минимум одно входящее соединение (Inbound) и одно исходящее соединение (Outbound).
      • Входящее соединение отвечает за связь с клиентом (например, браузером):
        • Входящее соединение обычно можно настроить с аутентификацией пользователя, например, с использованием ID и пароля;
        • После получения данных входящее соединение передает их диспетчеру (Dispatcher) для распределения.
      • Исходящее соединение отвечает за отправку данных на сервер, например, на другой Xray, работающий на другом хосте.
    • При наличии нескольких исходящих соединений можно настроить маршрутизацию (Routing) для указания, какое исходящее соединение должно использоваться для определенного типа трафика.
      • При необходимости маршрутизатор обращается к DNS для получения дополнительной информации для принятия решения.
    - + diff --git a/ru/document/level-2/index.html b/ru/document/level-2/index.html index 56f79e2263..dbc67a18b8 100644 --- a/ru/document/level-2/index.html +++ b/ru/document/level-2/index.html @@ -24,11 +24,11 @@ Продвинутая документация | Project X - - + +

    Продвинутая документация

    В этом разделе представлены советы и рекомендации по использованию Xray для продвинутых пользователей. Если вы уже знакомы с Xray, то информация, представленная здесь, поможет вам использовать Xray по максимуму.

    Введение в прозрачное проксирование от a @kirinОткрыть в новой вкладке

    Вводная статья о прозрачном проксировании.

    Руководство по настройке прозрачного проксирования (TProxy) от a @BioniCosmosОткрыть в новой вкладке

    Полное руководство по настройке прозрачного проксирования (TProxy) на основе Xray.

    Руководство по настройке прозрачного проксирования TProxy (ipv4 и ipv6) от a @SQLimitОткрыть в новой вкладке

    Руководство по настройке прозрачного проксирования TProxy (ipv4 и ipv6) на основе Xray.

    Создание TLS-туннеля с помощью Nginx или Haproxy для скрытия отпечатков от a @SQLimitОткрыть в новой вкладке

    Создание TLS-туннеля с помощью Nginx или Haproxy на стороне клиента и сервера для скрытия отпечатков.

    [Прозрачное проксирование] Исключение трафика Xray с помощью GID от a @kirinОткрыть в новой вкладке

    Новый способ исключения трафика Xray при реализации прозрачного проксирования с помощью iptables/nftables.

    Направление определенного трафика через определенный выходной узел с помощью Xray для реализации "разделения" глобальной маршрутизации от a @Zzz3mОткрыть в новой вкладке

    Использование Xray по максимуму: реализация "разделения" трафика на основе fwmark, sendThrough или sockopt.interface.

    Повышение безопасности проксирования с помощью Cloudflare Warp от a @yuhan6665Открыть в новой вкладке

    Введение в использование исходящего подключения WireGuard, добавленного в Xray v1.6.5.

    Статистика трафика Xray от a @yuhan6665Открыть в новой вкладке

    Статистика трафика и скрипты для Xray.

    - + diff --git a/ru/document/level-2/iptables_gid.html b/ru/document/level-2/iptables_gid.html index efafdd944e..88a5059f35 100644 --- a/ru/document/level-2/iptables_gid.html +++ b/ru/document/level-2/iptables_gid.html @@ -24,8 +24,8 @@ GID Прозрачное проксирование | Project X - - + +

    Прозрачное проксирование: Исключение трафика Xray с помощью GID

    В существующих русскоязычных руководствах по прозрачному проксированию с использованием iptables (Новое руководство по V2Ray на русском языке - Прозрачное проксированиеОткрыть в новой вкладке, Новое руководство по V2Ray на русском языке - Прозрачное проксирование (TPROXY)Открыть в новой вкладке, Руководство по настройке прозрачного проксирования (TProxy)) исключение трафика Xray осуществляется с помощью меток. Исходящий трафик Xray помечается, а затем с помощью правил iptables трафик с соответствующей меткой направляется напрямую, минуя Xray и предотвращая зацикливание.

    У такого подхода есть несколько недостатков:

    1. Необъяснимый трафик попадает в цепочку PREROUTINGОткрыть в новой вкладке

    2. Android использует собственный механизм меток, поэтому данный метод не применим к Android

    Предлагаемый в данном руководстве подход не требует использования меток, теоретически обеспечивая более высокую производительность и избегая описанных выше проблем.

    Идея

    Tproxy трафик может приниматься только пользователями с правами root (uid==0) или CAP_NET_ADMIN.

    Правила iptables позволяют разделять трафик на основе UID (идентификатор пользователя) и GID (идентификатор группы).

    Запустим Xray от имени пользователя с uid==0 и gid!=0 и настроим правила iptables, чтобы исключить трафик с этим GID, избегая проксирования трафика Xray.

    Настройка

    1. Предварительная подготовка

    Android

    1. На устройстве должны быть получены root-права.
    2. Установите busyboxОткрыть в новой вкладке.
    3. Наличие терминала для выполнения команд, например, adb shell, Termux и т.д.

    Другие Linux системы

    Необходимо наличие sudo, модуля tproxy для iptables и модуля extra.

    Обычно все это уже установлено в системе, для OpenWRT выполните:

    opkg install sudo iptables-mod-tproxy iptables-mod-extra
    @@ -125,6 +125,6 @@
     ip6tables -t mangle -A OUTPUT -p tcp -j XRAY6_MASK
     ip6tables -t mangle -A OUTPUT -p udp -j XRAY6_MASK
     
    - + diff --git a/ru/document/level-2/nginx_or_haproxy_tls_tunnel.html b/ru/document/level-2/nginx_or_haproxy_tls_tunnel.html index de235844b2..8ac1cbd652 100644 --- a/ru/document/level-2/nginx_or_haproxy_tls_tunnel.html +++ b/ru/document/level-2/nginx_or_haproxy_tls_tunnel.html @@ -24,8 +24,8 @@ Создание TLS-туннеля с помощью Nginx или Haproxy для скрытия отпечатков | Project X - - + +

    Nginx или Haproxy реализуют HTTPS-туннели, туннели HTTP/2 over HTTPS, туннели WebSocket over HTTP/2 over HTTPS, туннели gRPC over HTTP/2 over HTTPS, а также туннели gRPC over HTTP/2 over HTTPS с двусторонней аутентификацией по самозаверяющему сертификату.

    Создание HTTPS-туннеля с помощью Nginx на стороне клиента и сервера для скрытия отпечатков

    Сетевая структура:

    xray_client ---tcp--- nginx_client ---HTTPS--- nginx_sever ---tcp--- xray_server

    Компиляция nginx с поддержкой --with-stream

    Выполните компиляцию как на клиенте, так и на сервере.

    curl -O -L http://nginx.org/download/nginx-1.22.1.tar.gz

    tar -zxvf nginx-1.22.1.tar.gz

    cd nginx-1.22.1

    apt install gcc make // Для компиляции требуются gcc и make

    ./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_v2_module --with-stream --with-stream_ssl_module // На этом шаге могут потребоваться дополнительные библиотеки, установите их в соответствии с сообщениями об ошибках.

    make && make install

    После компиляции папка nginx будет находиться в /usr/local/nginx.

    Настройка nginx

    Отредактируйте конфигурационный файл nginx.conf.

    vim /usr/local/nginx/conf/nginx.conf

    Добавьте следующую конфигурацию на стороне сервера.

    Получение сертификата для сервера не рассматривается в данном руководстве. Обратитесь к документации.

    stream {
    @@ -557,6 +557,6 @@
     backend web
         server web /dev/shm/h1h2c.sock
     

    Настройка Xray

    Простая конфигурация gRPC, TLS не требуется. Конфигурация см. в документации. Параметр serviceName можно использовать для разделения трафика.

    - + diff --git a/ru/document/level-2/redirect.html b/ru/document/level-2/redirect.html index 06c3149158..0091105ec2 100644 --- a/ru/document/level-2/redirect.html +++ b/ru/document/level-2/redirect.html @@ -24,8 +24,8 @@ Перенаправление исходящего трафика | Project X - - + +

    Перенаправление трафика на основе fwmark или sendThrough

    Направление определенного трафика через определенный выходной узел с помощью Xray для реализации "разделения" глобальной маршрутизации

    Введение

    Я видел много прокси-серверов или VPN, которые перехватывают весь трафик, что приводит к неработоспособности Xray, если он установлен одновременно с ними. Многие руководства, которые я находил, предлагали решать эту проблему путем разделения трафика на основе таблиц маршрутизации CIDR. Это не очень элегантно, и если я хочу иметь возможность гибко переключаться между маршрутами и реализовывать разделение трафика по требованию, то есть ли лучший способ? Да, есть!

    С помощью fwmark или sendThrough/sockopt.interface в Xray и простой настройки таблицы маршрутизации можно добиться следующего:

    1. Xray может направлять трафик с определенным тегом, доменным именем и т.д. через определенный интерфейс. Если ваш интерфейс поддерживает dual-stack, вы можете указать IPv4 или IPv6.
    2. Остальной трафик будет идти через исходный интерфейс IPv4 или IPv6.

    Вот как это настроить (на примере Debian 10):

    1. Установите прокси-сервер или VPN-клиент (например, Wireguard, IPsec и т.д.)

    Обратитесь к официальной документации для получения инструкций по установке для вашей системы и программного обеспечения.

    2. Отредактируйте конфигурационный файл VPN (на примере WireGuard)

    Исходный файл:

    [Interface]
    @@ -169,6 +169,6 @@
     

    Настройте автоматический запуск:

    systemctl enable wg-quick@wg0
     systemctl start wg-quick@wg0
     

    Проверьте IPv4/IPv6:

    На прокси-сервере выполните команду curl ip-api.com -4/-6 / откройте в браузере сайт ip-api.com

    Послесловие

    Цель этой статьи - показать, как избежать ненужных затрат трафика, переложив функции маршрутизации и разделения трафика на Xray. Это позволяет избежать утомительной работы по обслуживанию таблиц маршрутизации и повышает технический уровень.

    Благодарности

    XTLS/Xray-coreОткрыть в новой вкладке; v2fly/v2ray-coreОткрыть в новой вкладке; WireGuardОткрыть в новой вкладке; @p3terxОткрыть в новой вкладке; @w; @Hiram; @Luminous; @Ln; @JackChou;

    - + diff --git a/ru/document/level-2/tproxy.html b/ru/document/level-2/tproxy.html index 951a4e89a4..6e0025a12e 100644 --- a/ru/document/level-2/tproxy.html +++ b/ru/document/level-2/tproxy.html @@ -24,8 +24,8 @@ Прозрачное проксирование TProxy | Project X - - + +

    Руководство по настройке прозрачного проксирования (TProxy)

    Эта конфигурация основана на Новом руководстве по V2Ray на русском языке - Прозрачное проксирование (TPROXY)Открыть в новой вкладке с добавлением новых функций Xray, использованием схемы VLESS + XTLS Vision и изменением режима разделения трафика с проксирования по умолчанию на прямое подключение по умолчанию. Пользователи должны настроить конфигурацию в соответствии со своими потребностями.

    Все конфигурации, представленные в этой статье, были успешно протестированы в средах Raspberry Pi 2B и Ubuntu 20.04. При использовании в других средах вам может потребоваться изменить конфигурацию.

    Перед началом работы

    Убедитесь, что на вашем устройстве есть доступное сетевое подключение, сервер настроен, а клиент установлен.

    Обратите внимание, что многие руководства по настройке прозрачного проксирования предлагают включить переадресацию IP в системе Linux, но это может привести к снижению производительности Splice. Дополнительную информацию см. в статье Расследование снижения производительности Splice до уровня ниже, чем DirectОткрыть в новой вкладке.

    Хочу добавить, что многие руководства по настройке прозрачного проксирования используют Netfilter для разделения трафика, отправляя прямой трафик напрямую, минуя Xray. В этом случае необходимо включить переадресацию IP.
    Другие руководства, например это, направляют весь трафик через Xray, где он разделяется модулем маршрутизации Xray. В этом случае переадресацию IP включать не нужно.

    Настройка Xray

    Для лучшего разделения трафика замените файл правил маршрутизации по умолчанию на Loyalsoldier/v2ray-rules-datОткрыть в новой вкладке, иначе Xray-core не сможет загрузить эту конфигурацию.

    sudo curl -oL /usr/local/share/xray/geoip.dat https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat
    @@ -281,6 +281,6 @@
     [Install]
     WantedBy=multi-user.target
     
    - + diff --git a/ru/document/level-2/tproxy_ipv4_and_ipv6.html b/ru/document/level-2/tproxy_ipv4_and_ipv6.html index 61d75132be..ccb43c38b4 100644 --- a/ru/document/level-2/tproxy_ipv4_and_ipv6.html +++ b/ru/document/level-2/tproxy_ipv4_and_ipv6.html @@ -24,8 +24,8 @@ Прозрачное проксирование TProxy (ipv4 и ipv6) | Project X - - + +

    Руководство по настройке прозрачного проксирования TProxy (ipv4 и ipv6)

    Эта конфигурация основана на Новом руководстве по V2Ray на русском языке - Прозрачное проксирование (TPROXY)Открыть в новой вкладке, Руководстве по настройке прозрачного проксирования (TProxy)Открыть в новой вкладке и Прозрачное проксирование: Исключение трафика Xray с помощью GIDОткрыть в новой вкладке. Она включает поддержку IPv6 для прозрачного проксирования и использует схему VLESS-TCP-XTLS-RPRX-Vision для обхода блокировок (рекомендуется использовать версии 1.7.2 и выше).

    Настройка Xray не является основной темой данной статьи. Пользователи могут изменять ее в соответствии со своими потребностями. Подробную информацию можно найти в примерах официальной документацииОткрыть в новой вкладке или в других отличных примерах, таких как @chika0801Открыть в новой вкладке и @lxhao61Открыть в новой вкладке.

    Внимание

    При использовании других конфигураций обратите особое внимание на часть outbound с тегом proxy в конфигурации клиента. Остальные части остаются неизменными.

    Конфигурация сервера также должна быть изменена соответственно.

    Эта конфигурация предназначена для решения проблемы, когда такие сайты, как Netflix, которые по умолчанию используют IPv6, не могут быть проксированы через пограничный маршрутизатор, или когда требуется проксирование IPv6.

    В данной статье используется сетевая структура с пограничным маршрутизатором с одним интерфейсом.

    Все конфигурации, представленные в этой статье, были успешно протестированы в среде Arch Linux (Kernel: 6.0.10). В других средах настройка аналогична.

    Убедитесь, что установлены необходимые программы: # sudo apt install iptables ip6tables или # sudo apt install nftables.

    Если на пограничном маршрутизаторе не установлена программа Xray, можно вручную скачать соответствующую версию Xray, например Xray-linux-64.zipОткрыть в новой вкладке, а затем скопировать файл install-release.shОткрыть в новой вкладке на пограничный маршрутизатор. Предоставьте файлу права на выполнение # chmod 700 install-release.sh и запустите его с помощью команды # ./install-release.sh --local Xray-linux-64.zip. Следуйте инструкциям для локальной установки.

    Настройка Xray

    Конфигурация клиента

    {
    @@ -437,6 +437,6 @@
     [Install]
     WantedBy=multi-user.target
     
    1. Выполните команду systemctl enable tproxyrules.

    tproxyrules.service

    Обратите внимание на IP-адрес основного маршрутизатора и измените его в соответствии с вашей конфигурацией.

    Команда ExecStartPre=/bin/sh -c 'until ping -c1 192.168.31.1; do sleep 1; done;' гарантирует, что команды будут выполнены только после получения IP-адреса, иначе могут возникнуть странные ошибки. IP-адрес - это адрес основного маршрутизатора, измените его в соответствии с вашей конфигурацией.

    Внимание

    Если вы настроили статический IP-адрес и шлюз с помощью dhcpcd и т.д., удалите соответствующие строки ip route add/del из приведенных выше конфигураций.

    Настройка доступа к интернету на устройствах локальной сети

    Предположим, что IPv4- и IPv6-адреса пограничного маршрутизатора - 192.168.31.100 и fd00:6868:6868::8866 соответственно. IP-адреса пограничного маршрутизатора можно узнать с помощью команды ip add.

    Метод 1

    Есть два способа настроить доступ к интернету на устройствах локальной сети.
    Первый способ - настроить статический IP-адрес на каждом устройстве и указать IP-адрес пограничного маршрутизатора в качестве шлюза.
    Обратите внимание, что большинство мобильных устройств поддерживают только ручную настройку IPv4-шлюза и не поддерживают ручную настройку IPv6-шлюза, если не получены root-права и не выполнены соответствующие настройки.

    В качестве примера рассмотрим устройство Windows.
    Можно сначала включить DHCP и записать автоматически назначенный IP-адрес для справки, а затем вручную настроить статический IP-адрес.

    Настройка DNS

    В этой конфигурации перехватывается DNS-трафик, поэтому DNS можно указать произвольно.

    Рекомендуется указать IP-адрес пограничного маршрутизатора, чтобы избежать утечки DNS.

    image image

    Метод 2

    Второй способ настроить доступ к интернету на устройствах локальной сети - указать пограничный маршрутизатор в качестве шлюза в настройках маршрутизатора.
    Этот метод не требует настройки на каждом устройстве, подключенном к маршрутизатору, но обратите внимание, что некоторые маршрутизаторы не поддерживают настройку IPv6-шлюза, поэтому устройствам, которым требуется IPv6, необходимо вручную настроить IPv6 в соответствии с методом 1.

    image

    Результаты

    После настройки в соответствии с вышеуказанными инструкциями устройства смогут получать доступ к интернету по IPv4 и IPv6.
    На тестовом сайте, например https://ipv6-test.com/, вы увидите следующие результаты (сайт должен быть проксирован, чтобы увидеть эти результаты):

    image

    Заключение

    В настоящее время IPv6 еще не получил широкого распространения, и 99% трафика, к которому мы обращаемся, по-прежнему приходится на IPv4.
    Многие провайдеры VPS

    - + diff --git a/ru/document/level-2/traffic_stats.html b/ru/document/level-2/traffic_stats.html index 508a65fbb1..626ea9e40f 100644 --- a/ru/document/level-2/traffic_stats.html +++ b/ru/document/level-2/traffic_stats.html @@ -24,8 +24,8 @@ Статистика трафика | Project X - - + +

    Руководство по настройке статистики трафика

    Ознакомьтесь с руководством по статистике трафикаОткрыть в новой вкладке.
    Эта статья адаптирует его для Xray (1.5.9+).

    Просмотр статистики трафика

    Способ настройки такой же, как и для v2fly. Просмотр статистики трафика - одна из функций командной строки Xray. Порт api dokodemo-door, указанный в конфигурации, - это порт, используемый в параметре --server.

    xray api statsquery --server=127.0.0.1:10085 # Просмотр всей статистики трафика
    @@ -120,6 +120,6 @@
     print_sum "$DATA" "user"
     echo "-----------------------------"
     
    - + diff --git a/ru/document/level-2/transparent_proxy/transparent_proxy.html b/ru/document/level-2/transparent_proxy/transparent_proxy.html index 465e2488f6..7945517c98 100644 --- a/ru/document/level-2/transparent_proxy/transparent_proxy.html +++ b/ru/document/level-2/transparent_proxy/transparent_proxy.html @@ -24,8 +24,8 @@ Другие замечания по прозрачному проксированию с помощью iptables | Project X - - + +

    Погружение в прозрачное проксирование

    Что такое прозрачное проксирование?

    Проще говоря, прозрачное проксирование не позволяет проксируемому устройству понять, что оно проксируется. Это означает, что на проксируемом устройстве не нужно запускать какое-либо программное обеспечение для проксирования (например, Xray, V2RayNG и т. д.). Когда вы подключаетесь к сети, ваше устройство уже проксируется.

    Это также означает, что программное обеспечение прокси работает в другом месте, например, на маршрутизаторе, и устройства, подключенные к Интернету через маршрутизатор, автоматически проксируются.

    Реализация прозрачного проксирования

    В настоящее время существует два основных способа реализации прозрачного проксирования:

    tun2socks

    Доступно для Windows/Linux (включая Android). Поскольку процесс реализации относительно прост, существует не так много руководств, поэтому я кратко опишу его здесь.

    Windows

    1. Установите NetchОткрыть в новой вкладке, используя режим [3] [TUN/TAP] Обход локальной сети для запуска.

    2. Включите точку доступа.

    3. Откройте Панель управления -> Сеть и Интернет -> Центр управления сетями и общим доступом -> Изменение параметров адаптера, найдите TAP-Windows Adapter и Microsoft Wi-Fi Direct Virtual Adapter.

    4. Щелкните правой кнопкой мыши TAP-Windows Adapter, Свойства -> Доступ, установите флажок Разрешить другим пользователям сети подключаться к Интернету через это подключение к Интернету, в Домашнее сетевое подключение выберите сетевое подключение Microsoft Wi-Fi Direct Virtual Adapter, нажмите ОК.

    Android

    1. Настройте подключение V2RayNG.

    2. Включите точку доступа.

    3. Настройки точки доступа -> Разрешить использование VPN для точки доступа (эта опция может отсутствовать в некоторых системах Android).

    iptables/nftables

    iptables и nftables реализуют прозрачное проксирование по одному и тому же принципу, в дальнейшем мы будем использовать iptables.

    Реализация прозрачного проксирования на основе iptables применима только к системам Linux (включая openwrt/Android). Благодаря своей эффективности по сравнению с tun2socks и возможности настройки на маршрутизаторах, она получила широкое распространение.

    Существующие три русскоязычных руководства по прозрачному проксированию на самом деле описывают реализацию прозрачного проксирования на основе этого решения: Новое руководство по V2Ray на русском языке - Прозрачное проксированиеОткрыть в новой вкладке, Новое руководство по V2Ray на русском языке - Прозрачное проксирование (TPROXY)Открыть в новой вкладке, Руководство по настройке прозрачного проксирования (TProxy). Первое основано на устаревшем режиме iptables-redirect, который не рекомендуется использовать и приводится только для справки. Второе и третье описывают реализацию прозрачного проксирования на основе режима iptables-tproxy.

    Принцип реализации прозрачного проксирования с помощью iptables

    Linux использует Netfilter для управления сетью, модель Netfilter выглядит следующим образом:

    Netfilter

    Предположим, что в качестве шлюза используется маршрутизатор (т. е. наш обычный способ подключения к Интернету), тогда:

    Направление трафика от устройств локальной сети к Интернету через маршрутизатор:

    Цепочка PREROUTING -> Цепочка FORWARD -> Цепочка POSTINGROUTING

    Направление трафика от устройств локальной сети к маршрутизатору (например, вход в веб-интерфейс маршрутизатора/подключение к маршрутизатору по ssh/доступ к DNS-серверу маршрутизатора и т. д.):

    Цепочка PREROUTING -> Цепочка INPUT -> Хост шлюза

    Направление трафика от маршрутизатора к Интернету:

    Хост шлюза -> Цепочка OUTPUT -> Цепочка POSTINGROUTING

    Управляя направлением трафика цепочек PREROUTING и OUTPUT с помощью iptables и перенаправляя его на Xray, мы можем проксировать устройства локальной сети и хост шлюза.

    В чем сложность прозрачного проксирования?

    Сложность прозрачного проксирования заключается в маршрутизации, то есть в различении того, какой трафик должен быть прямым, а какой должен проксироваться, поэтому я лично считаю, что термин разделение трафика более уместен.

    Мы можем разделить маршрутизацию на следующие этапы по возрастанию сложности:

    1. Проксирование всех запросов.
    2. Прямое подключение для локальных IP-адресов/многоадресных IP-адресов, проксирование для остальных запросов.
    3. На основе пункта 2, прямое подключение для исходящих запросов, инициированных Xray.
    4. На основе пункта 3, прямое подключение для запросов, адресованных китайским IP-адресам, и выбор внутренних и внешних DNS-серверов для разрешения внутренних и внешних доменных имен.

    Три вышеупомянутых руководства описывают четвертый этап. Поэтому новичкам может быть сложно понять их, читая напрямую.

    Пошаговая реализация прозрачного проксирования на основе iptables-tproxy с нуля

    Прежде чем начать, вам необходимо иметь базовые знания:

    1. Примерное представление о протоколах TCP/IP, доменных именах и DNS-серверах.
    2. Знание того, что такое WAN-порт, LAN-порт, LAN_IP, WAN_IP и DHCP-сервер. Для пограничных маршрутизаторов есть только один сетевой порт, который мы будем называть LAN-портом.
    3. Базовое понимание системы Linux (знание того, как запускать команды).
    4. Умение писать конфигурационные файлы клиента в формате json или, по крайней мере, понимать их.

    Предварительная подготовка

    Внимание

    Перед началом работы не забудьте включить пересылку пакетов ipv4 в Linux с помощью команды sysctl -w net.ipv4.ip_forward=1

    1. Подготовьте шлюз под управлением Linux

    Например, маршрутизатор с прошивкой OpenWRT.

    2. Подготовьте исполняемый файл Xray и конфигурационный файл на шлюзе (маршрутизаторе)

    Конфигурационный файл прослушивает порт 12345 и включает tproxy:

    {
    @@ -111,6 +111,6 @@
     iptables -t mangle -A OUTPUT -p tcp -j XRAY_MASK
     iptables -t mangle -A OUTPUT -p udp -j XRAY_MASK
     

    Однако у этого метода есть недостаток: если используется CDN или много VPS, то написание правил становится неудобным.

    1. Исключение с помощью меток

    Три вышеупомянутых русскоязычных руководства используют этот метод исключения, обратитесь к ним, мы не будем повторяться здесь.

    1. Исключение с помощью gid (рекомендуется)

    См. [Прозрачное проксирование] Исключение трафика Xray с помощью gid

    На этом третий этап проксирования, также известный как глобальное проксирование, завершен. Но не забудьте установить DNS-сервер шлюза на зарубежный DNS-сервер, иначе вы все равно можете получить загрязненные результаты.

    Четвертый этап

    На самом деле, не всем нужно реализовывать четвертый этап. Глобальное проксирование подходит для большинства случаев.

    Особенно для пограничных маршрутизаторов. При необходимости проксирования установите шлюз на IP-адрес пограничного маршрутизатора, при отсутствии необходимости проксирования - на IP-адрес основного маршрутизатора.

    Что касается конкретной реализации четвертого этапа, то об этом подробно рассказывается в трех вышеупомянутых русскоязычных руководствах. После того, как вы поймете вышеизложенное, вам будет легче понять эти руководства.

    Проксирование IPv6

    Вышеуказанные правила действительны только для IPv4, если вы хотите проксировать запросы IPv6, используйте команду ip6tables, ее использование в основном такое же, как и у iptables. См. [[Прозрачное проксирование] Исключение трафика Xray с помощью gid # 4-Настройка правил iptables](../iptables_gid # 4-Настройка правил iptables.md)

    Другие замечания по прозрачному проксированию с помощью iptables

    1. Если шлюз, выступающий в качестве прокси, также является основным маршрутизатором, необходимо добавить правило iptables -t mangle -A XRAY ! -s Диапазон LAN-адресов шлюза -j RETURN в цепочку PREROUTING, то есть команду, использованную на первом этапе и удаленную на втором этапе. Если этого не сделать, другие люди в той же подсети, что и WAN-порт, смогут использовать ваш WAN_IP в качестве шлюза, чтобы злоупотреблять вашим прозрачным прокси, что может быть небезопасно.

    2. В [Новое руководство по V2Ray на русском языке - Прозрачное проксирование (TPROXY) # Настройка шлюза](https://guide.v2fly.org/app/tproxy.html # Настройка шлюза) третий пункт гласит: Настройте сеть ПК вручную, указав в качестве шлюза по умолчанию адрес Raspberry Pi, то есть 192.168.1.22. Теперь ПК должен иметь доступ к Интернету (поскольку проксирование еще не настроено, “доступ” означает возможность доступа к внутренним веб-сайтам). На самом деле, даже если включена переадресация IP, ПК под управлением Ubuntu, CentOS, Debian и других систем не смогут получить доступ к Интернету, это нормально. Фактически, только OpenWRT может сделать то, что описано в статье, как указал @BioniCosmosОткрыть в новой вкладке, это связано с тем, что в обычных системах Linux нет правил Masquerade.

    3. Проблема too many open filesОткрыть в новой вкладке, см. решение в [Прозрачное проксирование] Исключение трафика Xray с помощью gid - Настройка максимального количества открытых файлов и запуск клиента Xray

    4. Избегайте повторного прохождения пакетов с существующими подключениями через TPROXY, будет дополнено...

    5. Основной маршрутизатор, однорукий маршрутизатор и пограничный маршрутизатор, будет дополнено...

    - + diff --git a/ru/document/level-2/warp.html b/ru/document/level-2/warp.html index 6439ca1973..1f267eacb5 100644 --- a/ru/document/level-2/warp.html +++ b/ru/document/level-2/warp.html @@ -24,8 +24,8 @@ Повышение безопасности проксирования с помощью Cloudflare Warp | Project X - - + +

    Повышение безопасности проксирования с помощью Cloudflare Warp

    В Xray (1.6.5+) добавлен исходящий WireGuard. Хотя это увеличивает размер ядра из-за дополнительных кода и зависимостей, мы считаем, что это важная новая функция по трем причинам:

    1. Из недавних обсуждений и экспериментовОткрыть в новой вкладке мы знаем, что проксирование трафика в Китай небезопасно.
      Одним из способов решения этой проблемы является перенаправление трафика в Китай в черный дыры.
      Недостаток этого метода заключается в том, что geosite и geoip обновляются нерегулярно, и новички могут не знать, как правильно настроить разделение трафика на клиенте, в результате чего трафик попадает в черный дыры, что снижает удобство использования.
      В этом случае мы можем просто перенаправить трафик в Китай через Cloudflare Warp, что обеспечит такую же безопасность без ущерба для удобства использования.
    2. Как известно, большинство VPN-провайдеров ведут журналы посещенных пользователями доменов, а некоторые даже проверяют и блокируют определенный трафик.
      Один из способов защиты конфиденциальности пользователей - использовать цепочку прокси-серверов на клиенте.
      Warp использует легкий VPN-протокол WireGuard, который добавляет дополнительный уровень шифрования.
      Для VPN-провайдера весь трафик пользователя будет направляться на Warp, что обеспечивает максимальную защиту конфиденциальности.
    3. Простота использования.
      Для настройки разделения трафика, WireGuard-туннеля и цепочки прокси-серверов достаточно одного ядра.

    Создание аккаунта Warp

    Спасибо Cloudflare за содействие свободному интернету! Теперь вы можете бесплатно пользоваться услугами Warp. При подключении автоматически выбирается ближайший сервер.

    Метод 1:

    1. Используйте VPS и загрузите wgcfОткрыть в новой вкладке.
    2. Запустите wgcf register, чтобы создать файл wgcf-account.toml.
    3. Запустите wgcf generate, чтобы создать файл wgcf-profile.conf. Скопируйте его содержимое:
    [Interface]
    @@ -187,6 +187,6 @@
        ]
     }
     
    - + diff --git a/ru/index.html b/ru/index.html index 8adb4e460f..4027e5a41a 100644 --- a/ru/index.html +++ b/ru/index.html @@ -24,8 +24,8 @@ Project X - - + +
    Project X

    Project X

    Не бойтесь облаков, застилающих вид – золотые глаза, словно факел, озаряют небо.

    Начать здесь → Руководство по конфигурации →

    Высокоскоростной протокол

    Оригинальные протоколы VLESS и XTLS, свободные от избыточного шифрования, высвобождают вычислительную мощность процессора.

    Свободная комбинация

    Безупречный механизм fallback, эффективно предотвращающий активное зондирование, совместное использование портов несколькими сервисами @@ -34,6 +34,6 @@

    Полная совместимость

    Полная совместимость с конфигурационными файлами и вызовами API v2ray-core.

    Сообщество

    Активные обсуждения и вклад сообщества, лицензия с открытым исходным кодом MPL 2.0.

    XTLS? Xray? V2Ray?

    XTLS — это блестящая идея для TLS, которую мы изучаем, в то время как Xray — это лучшая практика, которую мы поддерживаем.

    • Xray-core - это расширенная версия v2ray-core с улучшенной общей производительностью, включающая XTLS и другие улучшения. Xray-core полностью совместим с функциональностью и конфигурацией v2ray-core.
      • Только один исполняемый файл, включающий функциональность ctl, команда run используется по умолчанию.
      • Конфигурация полностью совместима, переменные среды и вызовы API должны начинаться с XRAY_
      • Открытый raw протокол ReadV на всех платформах.
      • Обеспечивает полную поддержку VLESS и Trojan XTLS, обе с ReadV.
      • Предоставляет несколько режимов управления потоком XTLS, непревзойденная производительность!

    Конфигурация без изменений, результат — значительно лучше.

    Кто мы?

    Неважно, кто мы. Важно то, что мы будем продолжать двигаться вперед и никогда не оглядываться назад.

    Помогите Xray стать сильнее

    Мы будем рады вашей помощи в развитии Xray!

    Telegram

    Благодарности

    • Спасибо всем за вашу поддержку!
    • Спасибо создателям всевозможных скриптов, образов Docker, клиентам... Спасибо всем, кто помогает улучшать экосистему!
    • Спасибо всем, кто вносит свой вклад в веб-сайт и документацию Xray.
    • Спасибо всем, кто высказывает ценные предложения и замечания.
    • Спасибо каждому участнику группы Telegram, который помогает другим.

    Подробнее о Project X

    • Если вы хотите узнать больше об истории и развитии Project X, нажмите здесь
    • Now Project X releases NFTs! If you would like to have one Project X NFT, or want to donate to or sponsoring Project X, please click hereОткрыть в новой вкладке

    Лицензия

    Mozilla Public License Version 2.0Открыть в новой вкладке

    Динамика звезд на GitHub

    Stargazers over timeОткрыть в новой вкладке

    - +