diff --git a/404.html b/404.html index 3e542064b..58fcbd5be 100644 --- a/404.html +++ b/404.html @@ -24,11 +24,11 @@ Project X - - + + -

404

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

404

Looks like we've got some broken links.
+ diff --git a/about/news.html b/about/news.html index f5b82b615..431cfa701 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-BfiHFBjP.js b/assets/404.html-CIRXttqd.js similarity index 63% rename from assets/404.html-BfiHFBjP.js rename to assets/404.html-CIRXttqd.js index b0ecbf0ce..ed58b938c 100644 --- a/assets/404.html-BfiHFBjP.js +++ b/assets/404.html-CIRXttqd.js @@ -1 +1 @@ -import{_ as e,o as c,c as t}from"./app-BClOOpdM.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-Dp4t6tDQ.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-DzkBFzwq.js b/assets/Mermaid-CldRIkxW.js similarity index 89% rename from assets/Mermaid-DzkBFzwq.js rename to assets/Mermaid-CldRIkxW.js index b1184887d..e327d636b 100644 --- a/assets/Mermaid-DzkBFzwq.js +++ b/assets/Mermaid-CldRIkxW.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-BClOOpdM.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,C=x?window:void 0;function I(e){var t;const o=w(e);return(t=o==null?void 0:o.$el)!=null?t:o}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 z(e,t,o={}){const{window:i=C,...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(I).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"},B=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-IUatkdtb.js").then(a=>a.bz),__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"&&z(document.documentElement,()=>{r.value=p()},{attributeFilter:["class","data-theme"],attributes:!0}),v(r,()=>n()),{tag:o,payload:t}}}),G=["innerHTML"];function F(e,t,o,i,r,n){return R(),T("div",{innerHTML:e.payload.innerHtml},null,8,G)}const V=L(B,[["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-Dp4t6tDQ.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,C=x?window:void 0;function I(e){var t;const o=w(e);return(t=o==null?void 0:o.$el)!=null?t:o}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 z(e,t,o={}){const{window:i=C,...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(I).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"},B=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-VsNG6kTl.js").then(a=>a.bz),__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"&&z(document.documentElement,()=>{r.value=p()},{attributeFilter:["class","data-theme"],attributes:!0}),v(r,()=>n()),{tag:o,payload:t}}}),G=["innerHTML"];function F(e,t,o,i,r,n){return R(),T("div",{innerHTML:e.payload.innerHtml},null,8,G)}const V=L(B,[["render",F],["__file","Mermaid.vue"]]);export{V as default}; function __vite__mapDeps(indexes) { if (!__vite__mapDeps.viteFileDeps) { - __vite__mapDeps.viteFileDeps = ["assets/mermaid.core-IUatkdtb.js","assets/app-BClOOpdM.js"] + __vite__mapDeps.viteFileDeps = ["assets/mermaid.core-VsNG6kTl.js","assets/app-Dp4t6tDQ.js"] } return indexes.map((i) => __vite__mapDeps.viteFileDeps[i]) } diff --git a/assets/Tab-DrybaNdq.js b/assets/Tab-DHpoGKXO.js similarity index 89% rename from assets/Tab-DrybaNdq.js rename to assets/Tab-DHpoGKXO.js index 08e8db75b..01c44539c 100644 --- a/assets/Tab-DrybaNdq.js +++ b/assets/Tab-DHpoGKXO.js @@ -1 +1 @@ -import{f as e,_ as a,o as s,c as l,g as r}from"./app-BClOOpdM.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-Dp4t6tDQ.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-BwcLe76G.js b/assets/Tabs-CPdZ5LMC.js similarity index 95% rename from assets/Tabs-BwcLe76G.js rename to assets/Tabs-CPdZ5LMC.js index f0d076c70..0f9ea46f9 100644 --- a/assets/Tabs-BwcLe76G.js +++ b/assets/Tabs-CPdZ5LMC.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-BClOOpdM.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-Dp4t6tDQ.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-Cp-LFo2x.js b/assets/api.html-B9L82kBF.js similarity index 99% rename from assets/api.html-Cp-LFo2x.js rename to assets/api.html-B9L82kBF.js index 9b11d515d..fe5a6fad1 100644 --- a/assets/api.html-Cp-LFo2x.js +++ b/assets/api.html-B9L82kBF.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-BClOOpdM.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-Dp4t6tDQ.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/api.html-BxmRsqEt.js b/assets/api.html-BckqTxy3.js
similarity index 99%
rename from assets/api.html-BxmRsqEt.js
rename to assets/api.html-BckqTxy3.js
index 3cabd339b..714dca73b 100644
--- a/assets/api.html-BxmRsqEt.js
+++ b/assets/api.html-BckqTxy3.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-BClOOpdM.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-Dp4t6tDQ.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-Dk9f65gx.js b/assets/api.html-BwBfpocK.js
similarity index 99%
rename from assets/api.html-Dk9f65gx.js
rename to assets/api.html-BwBfpocK.js
index 46b2c6e55..cd21d67e1 100644
--- a/assets/api.html-Dk9f65gx.js
+++ b/assets/api.html-BwBfpocK.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-BClOOpdM.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-Dp4t6tDQ.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/app-BClOOpdM.js b/assets/app-Dp4t6tDQ.js
similarity index 88%
rename from assets/app-BClOOpdM.js
rename to assets/app-Dp4t6tDQ.js
index 2f52b5a45..a6cd99ff0 100644
--- a/assets/app-BClOOpdM.js
+++ b/assets/app-Dp4t6tDQ.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,Qt=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,pc=({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){pl();const i=ve(this)[t].apply(this,l);return gl(),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(!pi(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 Jl(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),pt(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)&&pt(l,"set",e,t):pt(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&&pt(t,"delete",e,void 0),r}function cr(){const e=ve(this),t=e.size!==0,l=e.clear();return t&&pt(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 Jl(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 Jl(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 Jl(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 Jl(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 pi(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 pe(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||pi(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):pe(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(g)?g.trim():g)),v&&(n=l.map(rc))}let c,a=i[c=Mi(t)]||i[c=Mi(dt(t))];!a&&r&&(a=i[c=Mi(Qt(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,Qt(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:g,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,g,_,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:Qc(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=Jc(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 Qc=e=>{let t;for(const l in e)(l==="class"||l==="style"||Bl(l))&&((t||(t={}))[l]=e[l]);return t},Jc=(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=pi(e)):rl(e)?(u=()=>e,i=!0):te(e)?(v=!0,d=e.some(y=>rl(y)||pi(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,[g])}:u=ut,t&&i){const y=u;u=()=>zt(y())}let _,g=y=>{_=O.onStop=()=>{Dt(y,a,4),_=O.onStop=void 0}},m;if(dl)if(g=ut,t?l&&Ze(t,a,3,[u(),v?[]:void 0,g]):u(),n==="sync"){const y=Ja();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,g]),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 Qe=[Function,Array],Go={mode:String,appear:Boolean,persisted:Boolean,onBeforeEnter:Qe,onEnter:Qe,onAfterEnter:Qe,onEnterCancelled:Qe,onBeforeLeave:Qe,onLeave:Qe,onAfterLeave:Qe,onLeaveCancelled:Qe,onBeforeAppear:Qe,onAppear:Qe,onAfterAppear:Qe,onAppearCancelled:Qe},ca={name:"BaseTransition",props:Go,setup(e,{slots:t}){const l=Vn(),i=sa();let n;return()=>{const r=t.default&&Qo(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 g=!1;const{getTransitionKey:m}=u.type;if(m){const x=m();n===void 0?n=x:x!==n&&(n=x,g=!0)}if(_&&_.type!==Ye&&(!Bt(u,_)||g)){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:g,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(g,[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 Qo(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 g;return a||(g=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=>g!==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 g=Re;if(u)return()=>Ui(u,g);const m=O=>{a=null,Ul(O,g,13,!i)};if(o&&g.suspense||dl)return _().then(O=>()=>Ui(O,g)).catch(O=>(m(O),()=>i?ne(i,{error:O}):null));const x=pe(!1),A=pe(),D=pe(!!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,g.parent&&Kl(g.parent.vnode)&&Di(g.parent.update)}).catch(O=>{m(O),A.value=O}),()=>{if(x.value&&u)return Ui(u,g);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){Jo(e,"a",t)}function da(e,t){Jo(e,"da",t)}function Jo(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;pl(),ul(l);const c=Ze(t,l,e,o);return qt(),gl(),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"),pa=kt("sp"),ga=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 g=o[t];if(g!==void 0)switch(g){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:g,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 Q in o){const X=o[Q];oe(X)&&(i[Q]=X.bind(l))}if(n){const Q=n.call(l,l);Ee(Q)&&(e.data=zl(Q))}if(dn=!0,r)for(const Q in r){const X=r[Q],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,Q,{enumerable:!0,configurable:!0,get:()=>ze.value,set:He=>ze.value=He})}if(c)for(const Q in c)es(c[Q],i,l,Q);if(a){const Q=oe(a)?a.call(l):a;Reflect.ownKeys(Q).forEach(X=>{Kt(X,Q[X])})}d&&_r(d,e,"c");function S(Q,X){te(X)?X.forEach(De=>Q(De.bind(l))):X&&Q(X.bind(l))}if(S(va,v),S(We,_),S(_a,g),S(fa,m),S(ua,x),S(da,A),S(ba,E),S(ma,G),S(ga,N),S(ql,O),S(Ci,y),S(pa,K),te(w))if(w.length){const Q=e.exposed||(e.exposed={});w.forEach(X=>{Object.defineProperty(Q,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:pr,emits:pr,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[_,g]=is(v,t,!0);Ie(o,_),g&&c.push(...g)};!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,g[1]=x<0||m-1||de(g,"default"))&&c.push(v)}}}const u=[o,c];return Ee(e)&&i.set(e,u),u}function gr(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((_,g)=>yi(_,t&&(te(t)?t[g]: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),g=Ne(a);if(_||g){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)):g&&(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),gi(),y._vnode=b;return}Tt=!1,v(y.firstChild,b,null,null,null),gi(),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 Q=!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 Q;if((Q=w&&w.onVnodeBeforeMount)&&Je(Q,H,y),V&&ct(y,null,H,"beforeMount"),((Q=w&&w.onVnodeMounted)||V||S)&&Ko(()=>{Q&&Je(Q,H,y),S&&le.enter(b),V&&ct(y,null,H,"mounted")},G),L&16&&!(w&&(w.innerHTML||w.textContent))){let X=g(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},g=(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=g(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:g=ut,insertStaticContent:m}=e,x=(f,p,k,T=null,R=null,I=null,B=!1,F=null,$=!!p.dynamicChildren)=>{if(f===p)return;f&&!Bt(f,p)&&(T=P(f),He(f,R,I,!0),f=null),p.patchFlag===-2&&($=!1,p.dynamicChildren=null);const{type:j,ref:J,shapeFlag:q}=p;switch(j){case al:A(f,p,k,T);break;case Ye:D(f,p,k,T);break;case Rl:f==null&&O(p,k,T,B);break;case ke:L(f,p,k,T,R,I,B,F,$);break;default:q&1?H(f,p,k,T,R,I,B,F,$):q&6?V(f,p,k,T,R,I,B,F,$):(q&64||q&128)&&j.process(f,p,k,T,R,I,B,F,$,M)}J!=null&&R&&yi(J,f&&f.ref,I,p||f,!p)},A=(f,p,k,T)=>{if(f==null)i(p.el=c(p.children),k,T);else{const R=p.el=f.el;p.children!==f.children&&u(R,p.children)}},D=(f,p,k,T)=>{f==null?i(p.el=a(p.children||""),k,T):p.el=f.el},O=(f,p,k,T)=>{[f.el,f.anchor]=m(f.children,p,k,T,f.el,f.anchor)},b=({el:f,anchor:p},k,T)=>{let R;for(;f&&f!==p;)R=_(f),i(f,k,T),f=R;i(p,k,T)},y=({el:f,anchor:p})=>{let k;for(;f&&f!==p;)k=_(f),n(f),f=k;n(p)},H=(f,p,k,T,R,I,B,F,$)=>{B=B||p.type==="svg",f==null?G(p,k,T,R,I,B,F,$):K(f,p,R,I,B,F,$)},G=(f,p,k,T,R,I,B,F)=>{let $,j;const{type:J,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&&J!=="foreignObject",B,F),se&&ct(f,null,T,"created"),N($,f,f.scopeId,B,T),q){for(const ge in q)ge!=="value"&&!Al(ge)&&r($,ge,null,q[ge],I,f.children,T,R,je);"value"in q&&r($,"value",null,q.value),(j=q.onVnodeBeforeMount)&&Je(j,T,f)}se&&ct(f,null,T,"beforeMount");const me=ss(R,re);me&&re.beforeEnter($),i($,p,k),((j=q&&q.onVnodeMounted)||me||se)&&Ue(()=>{j&&Je(j,T,f),me&&re.enter($),se&&ct(f,null,T,"mounted")},R)},N=(f,p,k,T,R)=>{if(k&&g(f,k),T)for(let I=0;I{for(let j=$;j{const F=p.el=f.el;let{patchFlag:$,dynamicChildren:j,dirs:J}=p;$|=f.patchFlag&16;const q=f.props||ye,Z=p.props||ye;let re;k&&Ft(k,!1),(re=Z.onVnodeBeforeUpdate)&&Je(re,k,p,f),J&&ct(p,f,k,"beforeUpdate"),k&&Ft(k,!0);const se=R&&p.type!=="foreignObject";if(j?w(f.dynamicChildren,j,F,k,T,se,I):B||X(f,p,F,null,k,T,se,I,!1),$>0){if($&16)U(F,p,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=p.dynamicProps;for(let ge=0;ge{re&&Je(re,k,p,f),J&&ct(p,f,k,"updated")},T)},w=(f,p,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,p.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,p.children,R,I,je)}"value"in T&&r(f,"value",k.value,T.value)}},L=(f,p,k,T,R,I,B,F,$)=>{const j=p.el=f?f.el:c(""),J=p.anchor=f?f.anchor:c("");let{patchFlag:q,dynamicChildren:Z,slotScopeIds:re}=p;re&&(F=F?F.concat(re):re),f==null?(i(j,k,T),i(J,k,T),E(p.children,k,J,R,I,B,F,$)):q>0&&q&64&&Z&&f.dynamicChildren?(w(f.dynamicChildren,Z,k,R,I,B,F),(p.key!=null||R&&p===R.subTree)&&cs(f,p,!0)):X(f,p,k,J,R,I,B,F,$)},V=(f,p,k,T,R,I,B,F,$)=>{p.slotScopeIds=F,f==null?p.shapeFlag&512?R.ctx.activate(p,k,T,B,$):le(p,k,T,R,I,B,$):ie(f,p,$)},le=(f,p,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,$,p,k)}return}S(F,f,p,k,R,I,B)},ie=(f,p,k)=>{const T=p.component=f.component;if(Zc(f,p,k))if(T.asyncDep&&!T.asyncResolved){Q(T,p,k);return}else T.next=p,Kc(T.update),T.update();else p.el=f.el,T.vnode=p},S=(f,p,k,T,R,I,B)=>{const F=()=>{if(f.isMounted){let{next:J,bu:q,u:Z,parent:re,vnode:se}=f,me=J,ge;Ft(f,!1),J?(J.el=se.el,Q(f,J,B)):J=se,q&&$i(q),(ge=J.props&&J.props.onVnodeBeforeUpdate)&&Je(ge,re,J,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),J.el=Oe.el,me===null&&ea(f,Oe.el),Z&&Ue(Z,R),(ge=J.props&&J.props.onVnodeUpdated)&&Ue(()=>Je(ge,re,J,se),R)}else{let J;const{el:q,props:Z}=p,{bm:re,m:se,parent:me}=f,ge=sl(p);if(Ft(f,!1),re&&$i(re),!ge&&(J=Z&&Z.onVnodeBeforeMount)&&Je(J,me,p),Ft(f,!0),q&&ae){const Oe=()=>{f.subTree=Wi(f),ae(q,f.subTree,f,R,null)};ge?p.type.__asyncLoader().then(()=>!f.isUnmounted&&Oe()):Oe()}else{const Oe=f.subTree=Wi(f);x(null,Oe,k,T,f,R,I),p.el=Oe.el}if(se&&Ue(se,R),!ge&&(J=Z&&Z.onVnodeMounted)){const Oe=p;Ue(()=>Je(J,me,Oe),R)}(p.shapeFlag&256||me&&sl(me.vnode)&&me.vnode.shapeFlag&256)&&f.a&&Ue(f.a,R),f.isMounted=!0,p=k=T=null}},$=f.effect=new Ln(F,()=>Di(j),f.scope),j=f.update=()=>$.run();j.id=f.uid,Ft(f,!0),j()},Q=(f,p,k)=>{p.component=f;const T=f.vnode.props;f.vnode=p,f.next=null,wa(f,p.props,T,k),Da(f,p.children,k),pl(),ar(f),gl()},X=(f,p,k,T,R,I,B,F,$=!1)=>{const j=f&&f.children,J=f?f.shapeFlag:0,q=p.children,{patchFlag:Z,shapeFlag:re}=p;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?(J&16&&je(j,R,I),q!==j&&d(k,q)):J&16?re&16?Se(j,q,k,T,R,I,B,F,$):je(j,R,I,!0):(J&8&&d(k,""),re&16&&E(q,k,T,R,I,B,F,$))},De=(f,p,k,T,R,I,B,F,$)=>{f=f||il,p=p||il;const j=f.length,J=p.length,q=Math.min(j,J);let Z;for(Z=0;ZJ?je(f,R,I,!0,!1,q):E(p,k,T,R,I,B,F,$,q)},Se=(f,p,k,T,R,I,B,F,$)=>{let j=0;const J=p.length;let q=f.length-1,Z=J-1;for(;j<=q&&j<=Z;){const re=f[j],se=p[j]=$?wt(p[j]):tt(p[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=p[Z]=$?wt(p[Z]):tt(p[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=p[j]=$?wt(p[j]):tt(p[j]);Ke.key!=null&&me.set(Ke.key,j)}let ge,Oe=0;const et=Z-se+1;let Jt=!1,Jn=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(ge=se;ge<=Z;ge++)if(kl[ge-se]===0&&Bt(Ke,p[ge])){st=ge;break}st===void 0?He(Ke,R,I,!0):(kl[st-se]=j+1,st>=Jn?Jn=st:Jt=!0,x(Ke,p[st],k,null,R,I,B,F,$),Oe++)}const Zn=Jt?Va(kl):il;for(ge=Zn.length-1,j=et-1;j>=0;j--){const Ke=se+j,st=p[Ke],er=Ke+1{const{el:I,type:B,transition:F,children:$,shapeFlag:j}=f;if(j&6){ze(f.component.subTree,p,k,T);return}if(j&128){f.suspense.move(p,k,T);return}if(j&64){B.move(f,p,k,M);return}if(B===ke){i(I,p,k);for(let q=0;q<$.length;q++)ze($[q],p,k,T);i(f.anchor,p,k);return}if(B===Rl){b(f,p,k);return}if(T!==2&&j&1&&F)if(T===0)F.beforeEnter(I),i(I,p,k),Ue(()=>F.enter(I),R);else{const{leave:q,delayLeave:Z,afterLeave:re}=F,se=()=>i(I,p,k),me=()=>{q(I,()=>{se(),re&&re()})};Z?Z(I,se,me):me()}else i(I,p,k)},He=(f,p,k,T=!1,R=!1)=>{const{type:I,props:B,ref:F,children:$,dynamicChildren:j,shapeFlag:J,patchFlag:q,dirs:Z}=f;if(F!=null&&yi(F,null,k,f,!0),J&256){p.ctx.deactivate(f);return}const re=J&1&&Z,se=!sl(f);let me;if(se&&(me=B&&B.onVnodeBeforeUnmount)&&Je(me,p,f),J&6)ot(f.component,k,T);else{if(J&128){f.suspense.unmount(k,T);return}re&&ct(f,null,p,"beforeUnmount"),J&64?f.type.remove(f,p,k,R,M,T):j&&(I!==ke||q>0&&q&64)?je(j,p,k,!1,!0):(I===ke&&q&384||!R&&J&16)&&je($,p,k),T&&yt(f)}(se&&(me=B&&B.onVnodeUnmounted)||re)&&Ue(()=>{me&&Je(me,p,f),re&&ct(f,null,p,"unmounted")},k)},yt=f=>{const{type:p,el:k,anchor:T,transition:R}=f;if(p===ke){xt(k,T);return}if(p===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,p)=>{let k;for(;f!==p;)k=_(f),n(f),f=k;n(p)},ot=(f,p,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,p,k)),F&&Ue(F,p),Ue(()=>{f.isUnmounted=!0},p),p&&p.pendingBranch&&!p.isUnmounted&&f.asyncDep&&!f.asyncResolved&&f.suspenseId===p.pendingId&&(p.deps--,p.deps===0&&p.resolve())},je=(f,p,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,p,k)=>{f==null?p._vnode&&He(p._vnode,null,null,!0):x(p._vnode||null,f,p,null,null,null,k),ar(),gi(),p._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),pl();const r=Dt(i,e,0,[e.props,n]);if(gl(),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),pl();try{Ea(e)}finally{gl(),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 Qa=Symbol.for("v-scx"),Ja=()=>Te(Qa),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:g=`${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,g),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,g),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()},_=g=>{g.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 g=d===Ot&&/\b(transform|all)(,|$)/.test(i(`${Ot}Property`).toString());return{type:d,timeout:v,propCount:_,hasTransform:g}}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(Qt(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||(gu.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=Qt(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--E11Bnfl.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-RxvsCsGa.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-1d860c29":()=>s(()=>import("./log.html-CGZK1GQx.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-CcUIcEMa.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-ZMnQxtAD.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-Beki-8Ir.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-hSwIpJ1e.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-76460a00":()=>s(()=>import("./http.html-Bd8eE7sZ.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-0614d322":()=>s(()=>import("./raw.html-Dq-5Ka_e.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-eeea2fb0":()=>s(()=>import("./splithttp.html-LJ7zPnkk.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-33b1b709":()=>s(()=>import("./tcp.html-C7gwATZ1.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-BDf29_N4.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-BRoSCILt.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-CcQo-ZLW.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-DpRhKwiH.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-f91d64d6":()=>s(()=>import("./log.html-D45GuajB.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-BamFBjc9.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-BxZHVhF5.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-CAFb2hD9.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-BS64uoiA.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-990249a2":()=>s(()=>import("./log.html-CzhOF4Kn.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-59o86u4a.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-ByjruzeN.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-40ee4e87":()=>s(()=>import("./index.html-K7jpM5hZ.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-LSm1KTPV.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-C7BRucCz.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-DeeVesel.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-BOBwhNJh.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-5254cbc6":()=>s(()=>import("./tcp.html-Ddhaj7-G.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-D3njg8AT.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-CYYO7zib.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-SaUw7tAi.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-Bgp2ZT6j.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-BElssFCl.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-4360702e":()=>s(()=>import("./freedom.html-CrDIedPH.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-DxlumNKD.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-61928006":()=>s(()=>import("./http.html-B48Vd-PN.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-57fe845c":()=>s(()=>import("./raw.html-DuNVSVgJ.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-32d545e2":()=>s(()=>import("./splithttp.html-lyS93xvr.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--bDd7Pwh.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-01d5d1de":()=>s(()=>import("./design.html-Btn4Kben.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-4d4e5367":()=>s(()=>import("./guide.html-CsHVnUvI.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-a58031da":()=>s(()=>import("./mkcp.html-CiCy0zuJ.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-5440615b":()=>s(()=>import("./muxcool.html-0vAkP06p.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-069325e5":()=>s(()=>import("./vless.html-B1AEvEQ5.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-ca50d634":()=>s(()=>import("./vmess.html-MjTCQevM.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-DtsVy-Ya.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),"v-379e896c":()=>s(()=>import("./http.html-RpxJy5zC.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-ad8e9394":()=>s(()=>import("./raw.html-Bhb5iOzr.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-f4c92f7a":()=>s(()=>import("./tcp.html-2dkeqgjG.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,ps=(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 gs={"v-8daa1a0e":h(()=>s(()=>import("./index.html-Dd_tdi9r.js"),__vite__mapDeps([]))),"v-aad48c6a":h(()=>s(()=>import("./news.html-CYdBxwmd.js"),__vite__mapDeps([]))),"v-ba934fd8":h(()=>s(()=>import("./index.html-a34UBYSn.js"),__vite__mapDeps([]))),"v-41ade9da":h(()=>s(()=>import("./api.html-Dk9f65gx.js"),__vite__mapDeps([]))),"v-83dedd38":h(()=>s(()=>import("./dns.html-CKM_Wq5k.js"),__vite__mapDeps([]))),"v-192a19b9":h(()=>s(()=>import("./fakedns.html-BgcTIXgw.js"),__vite__mapDeps([]))),"v-7f6279d8":h(()=>s(()=>import("./inbound.html-Bn25952w.js"),__vite__mapDeps([]))),"v-1d860c29":h(()=>s(()=>import("./log.html-DoZScHqi.js"),__vite__mapDeps([]))),"v-fbaf47ec":h(()=>s(()=>import("./metrics.html-CLlGz2fL.js"),__vite__mapDeps([]))),"v-24956213":h(()=>s(()=>import("./observatory.html-Dr5cLNKE.js"),__vite__mapDeps([]))),"v-2367d756":h(()=>s(()=>import("./outbound.html-BnJWujx3.js"),__vite__mapDeps([]))),"v-4ebec35a":h(()=>s(()=>import("./policy.html-Ac1N2_ym.js"),__vite__mapDeps([]))),"v-31b7756a":h(()=>s(()=>import("./reverse.html-9kvYp4Kb.js"),__vite__mapDeps([]))),"v-70677432":h(()=>s(()=>import("./routing.html-B5ZjveLm.js"),__vite__mapDeps([]))),"v-7e21d6ae":h(()=>s(()=>import("./stats.html-BCwtJiO-.js"),__vite__mapDeps([]))),"v-e3dfff38":h(()=>s(()=>import("./transport.html-D2kyr6E5.js"),__vite__mapDeps([]))),"v-f7496066":h(()=>s(()=>import("./index.html-jM25DbUH.js"),__vite__mapDeps([]))),"v-36b1a79b":h(()=>s(()=>import("./index.html-ISZNMRDN.js"),__vite__mapDeps([]))),"v-09a64f89":h(()=>s(()=>import("./command.html-BF0VD3ix.js"),__vite__mapDeps([]))),"v-2b1adf48":h(()=>s(()=>import("./config.html-BT24bI8Z.js"),__vite__mapDeps([]))),"v-86ee963a":h(()=>s(()=>import("./document.html-D33r7piT.js"),__vite__mapDeps([]))),"v-0e5d7b39":h(()=>s(()=>import("./install.html-CzbCyu0D.js"),__vite__mapDeps([]))),"v-2d0a870d":h(()=>s(()=>import("./index.html-DTyCliON.js"),__vite__mapDeps([]))),"v-2d0ab8b3":h(()=>s(()=>import("./index.html-CC-ntY8u.js"),__vite__mapDeps([]))),"v-0d714d87":h(()=>s(()=>import("./browser_dialer.html-Kq-_Dh1k.js"),__vite__mapDeps([]))),"v-0da7880a":h(()=>s(()=>import("./env.html-BgPWlS3M.js"),__vite__mapDeps([]))),"v-2aeb21f9":h(()=>s(()=>import("./fallback.html-Dorx_zZZ.js"),__vite__mapDeps([]))),"v-3acf20ea":h(()=>s(()=>import("./multiple.html-Cbuk3VNw.js"),__vite__mapDeps([]))),"v-792e28f8":h(()=>s(()=>import("./xtls.html-BjuGNIe7.js"),__vite__mapDeps([]))),"v-b50d2334":h(()=>s(()=>import("./dokodemo.html-bRch7wZq.js"),__vite__mapDeps([]))),"v-593408b0":h(()=>s(()=>import("./http.html-CdlAqNdU.js"),__vite__mapDeps([]))),"v-802a842a":h(()=>s(()=>import("./shadowsocks.html-B6IK2Bt5.js"),__vite__mapDeps([]))),"v-29995cea":h(()=>s(()=>import("./socks.html-6GLe0ev0.js"),__vite__mapDeps([]))),"v-2a1b3d72":h(()=>s(()=>import("./trojan.html-BuDWDr3U.js"),__vite__mapDeps([]))),"v-fb92e8aa":h(()=>s(()=>import("./vless.html-DMOzaFBW.js"),__vite__mapDeps([]))),"v-167afaac":h(()=>s(()=>import("./vmess.html-BGyxKyme.js"),__vite__mapDeps([]))),"v-5588d0cc":h(()=>s(()=>import("./wireguard.html-X7XXtZyr.js"),__vite__mapDeps([]))),"v-749ad71a":h(()=>s(()=>import("./blackhole.html-BFJc9_Nr.js"),__vite__mapDeps([]))),"v-6d39b970":h(()=>s(()=>import("./dns.html-DHy15IYN.js"),__vite__mapDeps([]))),"v-d76e893a":h(()=>s(()=>import("./freedom.html-CsYhhuOD.js"),__vite__mapDeps([]))),"v-c6b4b59e":h(()=>s(()=>import("./http.html-EVA_u-iB.js"),__vite__mapDeps([]))),"v-41ec0e0e":h(()=>s(()=>import("./loopback.html-HZZKgpGg.js"),__vite__mapDeps([]))),"v-7b293e4a":h(()=>s(()=>import("./shadowsocks.html-DlgWnNHl.js"),__vite__mapDeps([]))),"v-15f5452a":h(()=>s(()=>import("./socks.html-DLLiJu-R.js"),__vite__mapDeps([]))),"v-5797bdb3":h(()=>s(()=>import("./trojan.html-DM5uyqdN.js"),__vite__mapDeps([]))),"v-a60f016c":h(()=>s(()=>import("./vless.html-XxiZb3rA.js"),__vite__mapDeps([]))),"v-413cee4b":h(()=>s(()=>import("./vmess.html-Ds0K_f_h.js"),__vite__mapDeps([]))),"v-208ca3b9":h(()=>s(()=>import("./wireguard.html-BJuFKWp0.js"),__vite__mapDeps([]))),"v-2877542a":h(()=>s(()=>import("./grpc.html-CKj98XZP.js"),__vite__mapDeps([]))),"v-76460a00":h(()=>s(()=>import("./http.html-CS41BEAS.js"),__vite__mapDeps([]))),"v-04158536":h(()=>s(()=>import("./httpupgrade.html-DUTYtYRX.js"),__vite__mapDeps([]))),"v-3167b1dd":h(()=>s(()=>import("./mkcp.html-DRciitZ8.js"),__vite__mapDeps([]))),"v-0614d322":h(()=>s(()=>import("./raw.html-pQj0GMkg.js"),__vite__mapDeps([]))),"v-eeea2fb0":h(()=>s(()=>import("./splithttp.html-C61Iuay7.js"),__vite__mapDeps([]))),"v-33b1b709":h(()=>s(()=>import("./tcp.html-C1uis9Br.js"),__vite__mapDeps([]))),"v-1ff57bba":h(()=>s(()=>import("./websocket.html-D8U-ZWQv.js"),__vite__mapDeps([]))),"v-6a9e8054":h(()=>s(()=>import("./compile.html-ByJLQtO8.js"),__vite__mapDeps([]))),"v-95e3eaea":h(()=>s(()=>import("./design.html-CZzHKdu0.js"),__vite__mapDeps([]))),"v-61e7eea6":h(()=>s(()=>import("./guide.html-B9jnIFkQ.js"),__vite__mapDeps([]))),"v-6e6c37e6":h(()=>s(()=>import("./mkcp.html-CJbrAZRy.js"),__vite__mapDeps([]))),"v-13168a21":h(()=>s(()=>import("./muxcool.html-CGZu6T_9.js"),__vite__mapDeps([]))),"v-5c48c82b":h(()=>s(()=>import("./vless.html-BT7cc7Rr.js"),__vite__mapDeps([]))),"v-1ee591a8":h(()=>s(()=>import("./vmess.html-Dnj-lkRC.js"),__vite__mapDeps([]))),"v-3f09dcfa":h(()=>s(()=>import("./index.html-ynExHE2C.js"),__vite__mapDeps([]))),"v-fb444906":h(()=>s(()=>import("./ch01-preface.html-Cb_Ov8Tj.js"),__vite__mapDeps([]))),"v-075f3ae5":h(()=>s(()=>import("./ch02-preparation.html-Cf5azvGS.js"),__vite__mapDeps([]))),"v-726d0633":h(()=>s(()=>import("./ch03-ssh.html-DTz6D2Rh.js"),__vite__mapDeps([]))),"v-430c6ab8":h(()=>s(()=>import("./ch04-security.html-_r_wrIQN.js"),__vite__mapDeps([]))),"v-717c6376":h(()=>s(()=>import("./ch05-webpage.html-BFDR3pBN.js"),__vite__mapDeps([]))),"v-278039be":h(()=>s(()=>import("./ch06-certificates.html-BmShiB5T.js"),__vite__mapDeps([]))),"v-a0c7f88e":h(()=>s(()=>import("./ch07-xray-server.html-grk6pMf0.js"),__vite__mapDeps([]))),"v-86586ca2":h(()=>s(()=>import("./ch08-xray-clients.html-BGGs_7Co.js"),__vite__mapDeps([]))),"v-3eb62514":h(()=>s(()=>import("./ch09-appendix.html-Ct0MNjdR.js"),__vite__mapDeps([]))),"v-3f09dcbc":h(()=>s(()=>import("./index.html-CJ7rc5gT.js"),__vite__mapDeps([]))),"v-b21a2a20":h(()=>s(()=>import("./fallbacks-lv1.html-DPcjjXwW.js"),__vite__mapDeps([]))),"v-da623318":h(()=>s(()=>import("./fallbacks-with-sni.html-DuBUlL52.js"),__vite__mapDeps([]))),"v-fdd722ac":h(()=>s(()=>import("./routing-lv1-part1.html-BeZz17nL.js"),__vite__mapDeps([]))),"v-fa6d716e":h(()=>s(()=>import("./routing-lv1-part2.html-ByjqcoL7.js"),__vite__mapDeps([]))),"v-2f29e106":h(()=>s(()=>import("./work.html-0lRGF5LV.js"),__vite__mapDeps([]))),"v-3f09dc7e":h(()=>s(()=>import("./index.html-CVR1ZGSF.js"),__vite__mapDeps([]))),"v-1c17916e":h(()=>s(()=>import("./iptables_gid.html-C0pRP5Rs.js"),__vite__mapDeps([]))),"v-a001cfa6":h(()=>s(()=>import("./nginx_or_haproxy_tls_tunnel.html-Cnf3cJ6J.js"),__vite__mapDeps([]))),"v-46333b48":h(()=>s(()=>import("./redirect.html-IndA836H.js"),__vite__mapDeps([]))),"v-338bc63e":h(()=>s(()=>import("./tproxy.html-BW7ZdTB0.js"),__vite__mapDeps([]))),"v-d68f7d58":h(()=>s(()=>import("./tproxy_ipv4_and_ipv6.html-Cpbn1IZo.js"),__vite__mapDeps([]))),"v-e533e2c6":h(()=>s(()=>import("./traffic_stats.html-BlmP7gwP.js"),__vite__mapDeps([]))),"v-1e465ab0":h(()=>s(()=>import("./warp.html-DJ9-KANE.js"),__vite__mapDeps([]))),"v-1080fb37":h(()=>s(()=>import("./news.html-CcRjgoWH.js"),__vite__mapDeps([]))),"v-317fc580":h(()=>s(()=>import("./index.html-C8eaj_Mf.js"),__vite__mapDeps([]))),"v-45144c7f":h(()=>s(()=>import("./api.html-Cp-LFo2x.js"),__vite__mapDeps([]))),"v-23fbd2d0":h(()=>s(()=>import("./dns.html-BqTOgtqG.js"),__vite__mapDeps([]))),"v-2b7ec525":h(()=>s(()=>import("./fakedns.html-zTVe-lF4.js"),__vite__mapDeps([]))),"v-5ab92300":h(()=>s(()=>import("./inbound.html-BnCvi1ip.js"),__vite__mapDeps([]))),"v-f91d64d6":h(()=>s(()=>import("./log.html-B-5T4nul.js"),__vite__mapDeps([]))),"v-d705f114":h(()=>s(()=>import("./metrics.html-CrYEopPV.js"),__vite__mapDeps([]))),"v-5c8e777f":h(()=>s(()=>import("./observatory.html-BIHhBKex.js"),__vite__mapDeps([]))),"v-268cd669":h(()=>s(()=>import("./outbound.html-zKdIM7bT.js"),__vite__mapDeps([]))),"v-4492d567":h(()=>s(()=>import("./policy.html-C4brVis9.js"),__vite__mapDeps([]))),"v-0d0e1e92":h(()=>s(()=>import("./reverse.html-CaSrdJAD.js"),__vite__mapDeps([]))),"v-4bbe1d5a":h(()=>s(()=>import("./routing.html-Dr5dN-4f.js"),__vite__mapDeps([]))),"v-16426d1a":h(()=>s(()=>import("./stats.html-Bgjxt7xr.js"),__vite__mapDeps([]))),"v-5de780d0":h(()=>s(()=>import("./transport.html-DhvzqRzp.js"),__vite__mapDeps([]))),"v-f88d343e":h(()=>s(()=>import("./index.html-CCiP37z4.js"),__vite__mapDeps([]))),"v-38d56a07":h(()=>s(()=>import("./index.html-CZ9m8Lcw.js"),__vite__mapDeps([]))),"v-4d046016":h(()=>s(()=>import("./command.html-uXs_G-wM.js"),__vite__mapDeps([]))),"v-22b35270":h(()=>s(()=>import("./config.html-CLIWPOuR.js"),__vite__mapDeps([]))),"v-30bd7c12":h(()=>s(()=>import("./document.html-BfgqK0AW.js"),__vite__mapDeps([]))),"v-439608b6":h(()=>s(()=>import("./install.html-Bw8Wfs-_.js"),__vite__mapDeps([]))),"v-408e88d1":h(()=>s(()=>import("./news.html-BbFI_I_S.js"),__vite__mapDeps([]))),"v-b1cce5cc":h(()=>s(()=>import("./index.html-CWk5bGVN.js"),__vite__mapDeps([]))),"v-7521da19":h(()=>s(()=>import("./api.html-BxmRsqEt.js"),__vite__mapDeps([]))),"v-5409606a":h(()=>s(()=>import("./dns.html-U3P3hT9J.js"),__vite__mapDeps([]))),"v-5877f5bf":h(()=>s(()=>import("./fakedns.html-w8mpOaBa.js"),__vite__mapDeps([]))),"v-00c6c1cc":h(()=>s(()=>import("./inbound.html-Df7BiaXd.js"),__vite__mapDeps([]))),"v-990249a2":h(()=>s(()=>import("./log.html-D7gRP2SF.js"),__vite__mapDeps([]))),"v-7d138fe0":h(()=>s(()=>import("./metrics.html-CVc9hI8H.js"),__vite__mapDeps([]))),"v-11e9cb19":h(()=>s(()=>import("./observatory.html-DVMvM0rf.js"),__vite__mapDeps([]))),"v-ce8c8de2":h(()=>s(()=>import("./outbound.html-DzO6kzAh.js"),__vite__mapDeps([]))),"v-3dc4298d":h(()=>s(()=>import("./policy.html-DbjgMwZW.js"),__vite__mapDeps([]))),"v-26722151":h(()=>s(()=>import("./reverse.html-CNiVmXjg.js"),__vite__mapDeps([]))),"v-071a21ed":h(()=>s(()=>import("./routing.html-C0ZSU5uF.js"),__vite__mapDeps([]))),"v-7922fc34":h(()=>s(()=>import("./stats.html-Dx9fcabd.js"),__vite__mapDeps([]))),"v-3156f2ea":h(()=>s(()=>import("./transport.html-_5N6k7Mk.js"),__vite__mapDeps([]))),"v-40ee4e87":h(()=>s(()=>import("./index.html-CUdXYj6p.js"),__vite__mapDeps([]))),"v-a1c899be":h(()=>s(()=>import("./index.html-WChIF31z.js"),__vite__mapDeps([]))),"v-a6257be2":h(()=>s(()=>import("./command.html-Blm6CTPO.js"),__vite__mapDeps([]))),"v-d63f95d4":h(()=>s(()=>import("./config.html-DsMaT424.js"),__vite__mapDeps([]))),"v-fbbfd9c6":h(()=>s(()=>import("./document.html-nQC-96qj.js"),__vite__mapDeps([]))),"v-9cb72482":h(()=>s(()=>import("./install.html-uqLzyLFC.js"),__vite__mapDeps([]))),"v-51a51d87":h(()=>s(()=>import("./transparent_proxy.html-CB7ITqDt.js"),__vite__mapDeps([]))),"v-76b9a0f3":h(()=>s(()=>import("./browser_dialer.html-CB_B_9rS.js"),__vite__mapDeps([]))),"v-565dbfc4":h(()=>s(()=>import("./env.html-DU1GD2FF.js"),__vite__mapDeps([]))),"v-0fbd1336":h(()=>s(()=>import("./fallback.html-BrN0kAZC.js"),__vite__mapDeps([]))),"v-a0627812":h(()=>s(()=>import("./multiple.html-ZrBBPvoT.js"),__vite__mapDeps([]))),"v-d190d938":h(()=>s(()=>import("./xtls.html-DkBmDiCN.js"),__vite__mapDeps([]))),"v-72afc2d2":h(()=>s(()=>import("./dokodemo.html-DOvjc4cT.js"),__vite__mapDeps([]))),"v-773d731c":h(()=>s(()=>import("./http.html-C5N79PRn.js"),__vite__mapDeps([]))),"v-f555fc02":h(()=>s(()=>import("./shadowsocks.html-D1Blunoy.js"),__vite__mapDeps([]))),"v-e35196c2":h(()=>s(()=>import("./socks.html-DagNy3gy.js"),__vite__mapDeps([]))),"v-29188644":h(()=>s(()=>import("./trojan.html-DzAn779h.js"),__vite__mapDeps([]))),"v-255a6ebf":h(()=>s(()=>import("./vless.html-BIa__9by.js"),__vite__mapDeps([]))),"v-8cc24480":h(()=>s(()=>import("./vmess.html-tXOkY5oD.js"),__vite__mapDeps([]))),"v-a2605ea4":h(()=>s(()=>import("./wireguard.html-DfdLmO6b.js"),__vite__mapDeps([]))),"v-64e47ef4":h(()=>s(()=>import("./blackhole.html-q3xeL8OX.js"),__vite__mapDeps([]))),"v-e979b848":h(()=>s(()=>import("./dns.html-fEPhd3oF.js"),__vite__mapDeps([]))),"v-617f0fcf":h(()=>s(()=>import("./freedom.html-DBKermX9.js"),__vite__mapDeps([]))),"v-3fc98845":h(()=>s(()=>import("./http.html-DDZB0k1M.js"),__vite__mapDeps([]))),"v-1b804722":h(()=>s(()=>import("./loopback.html-4t4spiuV.js"),__vite__mapDeps([]))),"v-63077cb6":h(()=>s(()=>import("./shadowsocks.html-DWMjTHBI.js"),__vite__mapDeps([]))),"v-516476d4":h(()=>s(()=>import("./socks.html-BvIE__Bw.js"),__vite__mapDeps([]))),"v-7d61a872":h(()=>s(()=>import("./trojan.html-DEzWkEyk.js"),__vite__mapDeps([]))),"v-6e50feb6":h(()=>s(()=>import("./vless.html-BOKM9gNU.js"),__vite__mapDeps([]))),"v-02956db7":h(()=>s(()=>import("./vmess.html-CFNH9JT0.js"),__vite__mapDeps([]))),"v-797f8d25":h(()=>s(()=>import("./wireguard.html-m61ylbO3.js"),__vite__mapDeps([]))),"v-2c6058d4":h(()=>s(()=>import("./grpc.html-BBtDCpfw.js"),__vite__mapDeps([]))),"v-1c38292a":h(()=>s(()=>import("./h2.html-RTLybXpz.js"),__vite__mapDeps([]))),"v-17ff144a":h(()=>s(()=>import("./httpupgrade.html-DlzaZq--.js"),__vite__mapDeps([]))),"v-1a7f9d6e":h(()=>s(()=>import("./mkcp.html-CtmErV5x.js"),__vite__mapDeps([]))),"v-4df52c3c":h(()=>s(()=>import("./splithttp.html-CiF71Wo2.js"),__vite__mapDeps([]))),"v-5254cbc6":h(()=>s(()=>import("./tcp.html-sVHKrGaV.js"),__vite__mapDeps([]))),"v-9520f392":h(()=>s(()=>import("./websocket.html-gylvmC0D.js"),__vite__mapDeps([]))),"v-b7760e2c":h(()=>s(()=>import("./compile.html-CjZXx27q.js"),__vite__mapDeps([]))),"v-fb774212":h(()=>s(()=>import("./design.html-hf-r5dmK.js"),__vite__mapDeps([]))),"v-38c376c1":h(()=>s(()=>import("./guide.html-DarpIlI5.js"),__vite__mapDeps([]))),"v-21bccd79":h(()=>s(()=>import("./mkcp.html-BAnAQ47o.js"),__vite__mapDeps([]))),"v-27001935":h(()=>s(()=>import("./muxcool.html-DPVwc3va.js"),__vite__mapDeps([]))),"v-21b30c3f":h(()=>s(()=>import("./vless.html-HGlcHtRy.js"),__vite__mapDeps([]))),"v-94110980":h(()=>s(()=>import("./vmess.html-1xnKx21Y.js"),__vite__mapDeps([]))),"v-789ba7ef":h(()=>s(()=>import("./index.html-CrBamsFA.js"),__vite__mapDeps([]))),"v-d3712ade":h(()=>s(()=>import("./ch01-preface.html-N4amw0Ox.js"),__vite__mapDeps([]))),"v-41f9c00e":h(()=>s(()=>import("./ch02-preparation.html-_Og0J-0X.js"),__vite__mapDeps([]))),"v-4c013f47":h(()=>s(()=>import("./ch03-ssh.html-B2d2lltd.js"),__vite__mapDeps([]))),"v-a75683b8":h(()=>s(()=>import("./ch04-security.html-C0QRw92W.js"),__vite__mapDeps([]))),"v-f5341aec":h(()=>s(()=>import("./ch05-webpage.html-Dt_H9ckT.js"),__vite__mapDeps([]))),"v-4458f72a":h(()=>s(()=>import("./ch06-certificates.html-hZw22qFC.js"),__vite__mapDeps([]))),"v-f1802e66":h(()=>s(()=>import("./ch07-xray-server.html-C8PxlQdU.js"),__vite__mapDeps([]))),"v-4ca6f1ca":h(()=>s(()=>import("./ch08-xray-clients.html-C8H6XK9U.js"),__vite__mapDeps([]))),"v-b0030f00":h(()=>s(()=>import("./ch09-appendix.html-Df8p5LWP.js"),__vite__mapDeps([]))),"v-789ba80e":h(()=>s(()=>import("./index.html-BBBxkEh9.js"),__vite__mapDeps([]))),"v-103b3e5c":h(()=>s(()=>import("./fallbacks-lv1.html-tiE_cj9R.js"),__vite__mapDeps([]))),"v-110dd688":h(()=>s(()=>import("./fallbacks-with-sni.html-CeYEzXyB.js"),__vite__mapDeps([]))),"v-c425a7d4":h(()=>s(()=>import("./routing-lv1-part1.html-Wi4pzvd6.js"),__vite__mapDeps([]))),"v-c0bbf696":h(()=>s(()=>import("./routing-lv1-part2.html-C8-_AlZd.js"),__vite__mapDeps([]))),"v-5b6477cc":h(()=>s(()=>import("./work.html-LiUJgLuE.js"),__vite__mapDeps([]))),"v-789ba82d":h(()=>s(()=>import("./index.html-q7kj9qZg.js"),__vite__mapDeps([]))),"v-05ddc65d":h(()=>s(()=>import("./iptables_gid.html-B7BAabEG.js"),__vite__mapDeps([]))),"v-474afe99":h(()=>s(()=>import("./nginx_or_haproxy_tls_tunnel.html-DR5-FE6s.js"),__vite__mapDeps([]))),"v-930ac920":h(()=>s(()=>import("./redirect.html-DYni_bis.js"),__vite__mapDeps([]))),"v-c579975c":h(()=>s(()=>import("./tproxy.html-C4Wak-Ch.js"),__vite__mapDeps([]))),"v-7efb7c68":h(()=>s(()=>import("./tproxy_ipv4_and_ipv6.html-BNsWytYC.js"),__vite__mapDeps([]))),"v-12a33bee":h(()=>s(()=>import("./traffic_stats.html-Bmki1ou2.js"),__vite__mapDeps([]))),"v-7d2b8478":h(()=>s(()=>import("./warp.html-DgEMK8FR.js"),__vite__mapDeps([]))),"v-1cfb44e6":h(()=>s(()=>import("./browser_dialer.html-BHxcHS_p.js"),__vite__mapDeps([]))),"v-6a3f8078":h(()=>s(()=>import("./env.html-RA7PrAQR.js"),__vite__mapDeps([]))),"v-74f22e7f":h(()=>s(()=>import("./fallback.html-BRqaP6rq.js"),__vite__mapDeps([]))),"v-2c9f7c11":h(()=>s(()=>import("./multiple.html-4yXCI2Ca.js"),__vite__mapDeps([]))),"v-630c687e":h(()=>s(()=>import("./xtls.html-hZzXSvQP.js"),__vite__mapDeps([]))),"v-20ff0a28":h(()=>s(()=>import("./dokodemo.html-DZ-7Us1_.js"),__vite__mapDeps([]))),"v-43124836":h(()=>s(()=>import("./http.html-CrilsEvo.js"),__vite__mapDeps([]))),"v-6a351ba5":h(()=>s(()=>import("./shadowsocks.html-D70GzRWG.js"),__vite__mapDeps([]))),"v-3d1d02c5":h(()=>s(()=>import("./socks.html-Dq9DrPIe.js"),__vite__mapDeps([]))),"v-1567b378":h(()=>s(()=>import("./trojan.html-DWkiD9C-.js"),__vite__mapDeps([]))),"v-57bf8636":h(()=>s(()=>import("./vless.html-CAkNmt00.js"),__vite__mapDeps([]))),"v-6864abe6":h(()=>s(()=>import("./vmess.html-CSZyIFqN.js"),__vite__mapDeps([]))),"v-67d3c858":h(()=>s(()=>import("./wireguard.html-B6x6u49u.js"),__vite__mapDeps([]))),"v-5910da20":h(()=>s(()=>import("./blackhole.html-XOKhneJi.js"),__vite__mapDeps([]))),"v-5717f8f6":h(()=>s(()=>import("./dns.html-Bho_gUMA.js"),__vite__mapDeps([]))),"v-4360702e":h(()=>s(()=>import("./freedom.html-BaZQj-Ms.js"),__vite__mapDeps([]))),"v-22e1532a":h(()=>s(()=>import("./http.html-BYmjDBWA.js"),__vite__mapDeps([]))),"v-38c69248":h(()=>s(()=>import("./loopback.html-Ni1oAZCT.js"),__vite__mapDeps([]))),"v-1a2a97d0":h(()=>s(()=>import("./shadowsocks.html-CnY4fOzh.js"),__vite__mapDeps([]))),"v-0141bb30":h(()=>s(()=>import("./socks.html-C0gkY3rI.js"),__vite__mapDeps([]))),"v-544bef26":h(()=>s(()=>import("./trojan.html-DTx446Hu.js"),__vite__mapDeps([]))),"v-cf761560":h(()=>s(()=>import("./vless.html-bxJgGdM4.js"),__vite__mapDeps([]))),"v-2c896451":h(()=>s(()=>import("./vmess.html-B0GECYM-.js"),__vite__mapDeps([]))),"v-0502a6bf":h(()=>s(()=>import("./wireguard.html-C7d91cx3.js"),__vite__mapDeps([]))),"v-13c3ca30":h(()=>s(()=>import("./grpc.html-CuUtjqB-.js"),__vite__mapDeps([]))),"v-61928006":h(()=>s(()=>import("./http.html-CshzrTyQ.js"),__vite__mapDeps([]))),"v-453f5c70":h(()=>s(()=>import("./httpupgrade.html-DyeHB5qe.js"),__vite__mapDeps([]))),"v-1cb427e3":h(()=>s(()=>import("./mkcp.html-A6Lhrl8v.js"),__vite__mapDeps([]))),"v-57fe845c":h(()=>s(()=>import("./raw.html-C0l7UYo_.js"),__vite__mapDeps([]))),"v-32d545e2":h(()=>s(()=>import("./splithttp.html-BYEq0RDl.js"),__vite__mapDeps([]))),"v-cb60c046":h(()=>s(()=>import("./websocket.html-DUOE6Z_k.js"),__vite__mapDeps([]))),"v-7ce977e0":h(()=>s(()=>import("./compile.html-DuAS5vnR.js"),__vite__mapDeps([]))),"v-01d5d1de":h(()=>s(()=>import("./design.html-XfD5aROW.js"),__vite__mapDeps([]))),"v-4d4e5367":h(()=>s(()=>import("./guide.html-Dwzng_V-.js"),__vite__mapDeps([]))),"v-a58031da":h(()=>s(()=>import("./mkcp.html-BwaiJk20.js"),__vite__mapDeps([]))),"v-5440615b":h(()=>s(()=>import("./muxcool.html-D0kuQV6X.js"),__vite__mapDeps([]))),"v-069325e5":h(()=>s(()=>import("./vless.html-B_Oy3zb3.js"),__vite__mapDeps([]))),"v-ca50d634":h(()=>s(()=>import("./vmess.html-D1_Hwxuj.js"),__vite__mapDeps([]))),"v-490791ee":h(()=>s(()=>import("./index.html-DJZ8xXVB.js"),__vite__mapDeps([]))),"v-78f09a92":h(()=>s(()=>import("./ch01-preface.html-DQT8PYpt.js"),__vite__mapDeps([]))),"v-64f6e51f":h(()=>s(()=>import("./ch02-preparation.html-BNLBNj5J.js"),__vite__mapDeps([]))),"v-69478a6d":h(()=>s(()=>import("./ch03-ssh.html-BBlWjSPH.js"),__vite__mapDeps([]))),"v-271d7abe":h(()=>s(()=>import("./ch04-security.html-DtoTR_GG.js"),__vite__mapDeps([]))),"v-9ab38aa0":h(()=>s(()=>import("./ch05-webpage.html-BP0EdKmB.js"),__vite__mapDeps([]))),"v-7cddd6c4":h(()=>s(()=>import("./ch06-certificates.html-D-kQ9qhu.js"),__vite__mapDeps([]))),"v-0d33adf3":h(()=>s(()=>import("./ch07-xray-server.html-Jl0JVjmz.js"),__vite__mapDeps([]))),"v-123166b5":h(()=>s(()=>import("./ch08-xray-clients.html-CmT1Ytes.js"),__vite__mapDeps([]))),"v-22c7351a":h(()=>s(()=>import("./ch09-appendix.html-lyRlTtzf.js"),__vite__mapDeps([]))),"v-490791b0":h(()=>s(()=>import("./index.html-d88pFbkg.js"),__vite__mapDeps([]))),"v-e9f80a14":h(()=>s(()=>import("./fallbacks-lv1.html-Ckp_6TD3.js"),__vite__mapDeps([]))),"v-2db62ba4":h(()=>s(()=>import("./fallbacks-with-sni.html-BM_lo7LS.js"),__vite__mapDeps([]))),"v-531be8a0":h(()=>s(()=>import("./routing-lv1-part1.html-XgFNj8rA.js"),__vite__mapDeps([]))),"v-4fb23762":h(()=>s(()=>import("./routing-lv1-part2.html-CAznfBeq.js"),__vite__mapDeps([]))),"v-fdd8db80":h(()=>s(()=>import("./work.html-CLfkotRL.js"),__vite__mapDeps([]))),"v-49079172":h(()=>s(()=>import("./index.html-CBYNGVas.js"),__vite__mapDeps([]))),"v-331e0e83":h(()=>s(()=>import("./iptables_gid.html-DiTyvfAc.js"),__vite__mapDeps([]))),"v-7418a5b3":h(()=>s(()=>import("./nginx_or_haproxy_tls_tunnel.html-Dcb_ekpN.js"),__vite__mapDeps([]))),"v-587e32d4":h(()=>s(()=>import("./redirect.html-BP4j1duL.js"),__vite__mapDeps([]))),"v-9c63de10":h(()=>s(()=>import("./tproxy.html-zMvXk72O.js"),__vite__mapDeps([]))),"v-a4c782e4":h(()=>s(()=>import("./tproxy_ipv4_and_ipv6.html-OETh4Y-h.js"),__vite__mapDeps([]))),"v-71771ea3":h(()=>s(()=>import("./traffic_stats.html-tywRIfWl.js"),__vite__mapDeps([]))),"v-70300bea":h(()=>s(()=>import("./warp.html-l5rz1Xgi.js"),__vite__mapDeps([]))),"v-7689d7f3":h(()=>s(()=>import("./transparent_proxy.html-DDpbn2RR.js"),__vite__mapDeps([]))),"v-39b3c50d":h(()=>s(()=>import("./transparent_proxy.html-Dfb29zhW.js"),__vite__mapDeps([]))),"v-3706649a":h(()=>s(()=>import("./404.html-BfiHFBjP.js"),__vite__mapDeps([]))),"v-379e896c":h(()=>s(()=>import("./http.html-BeOSDU9A.js"),__vite__mapDeps([]))),"v-ad8e9394":h(()=>s(()=>import("./raw.html-BZcvQwi4.js"),__vite__mapDeps([]))),"v-f4c92f7a":h(()=>s(()=>import("./tcp.html-B1TpuKMg.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(""),gt=()=>{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=pe(Iu),Mn=Symbol(""),Ql=()=>{const e=Te(Mn);if(!e)throw new Error("useRouteLocale() is called without provider.");return e},ll=pe(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)=>ps(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=pe(!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(()=>gs[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 g=Date.now()-u;if(g+t>=a)return a-g}return t}var _=function(){var g=[].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,g);c&&c(b),d.forEach(function(y){return(0,y.resolve)(b)}),d=[]}},v()),D){var O=e.apply(m,g);return c&&c(O),x(O)}d.push({resolve:x,reject:A})})};return _.cancel=function(g){r!==void 0&&clearTimeout(r),d.forEach(function(m){return(0,m.reject)(g)}),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,Qt=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,pc=({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){pl();const i=ve(this)[t].apply(this,l);return gl(),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(!pi(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 Jl(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),pt(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)&&pt(l,"set",e,t):pt(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&&pt(t,"delete",e,void 0),r}function cr(){const e=ve(this),t=e.size!==0,l=e.clear();return t&&pt(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 Jl(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 Jl(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 Jl(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 Jl(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 pi(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 pe(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||pi(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):pe(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(g)?g.trim():g)),v&&(n=l.map(rc))}let c,a=i[c=Mi(t)]||i[c=Mi(dt(t))];!a&&r&&(a=i[c=Mi(Qt(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,Qt(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:g,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,g,_,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:Qc(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=Jc(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 Qc=e=>{let t;for(const l in e)(l==="class"||l==="style"||Bl(l))&&((t||(t={}))[l]=e[l]);return t},Jc=(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=pi(e)):rl(e)?(u=()=>e,i=!0):te(e)?(v=!0,d=e.some(y=>rl(y)||pi(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,[g])}:u=ut,t&&i){const y=u;u=()=>zt(y())}let _,g=y=>{_=O.onStop=()=>{Dt(y,a,4),_=O.onStop=void 0}},m;if(dl)if(g=ut,t?l&&Ze(t,a,3,[u(),v?[]:void 0,g]):u(),n==="sync"){const y=Ja();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,g]),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 Qe=[Function,Array],Go={mode:String,appear:Boolean,persisted:Boolean,onBeforeEnter:Qe,onEnter:Qe,onAfterEnter:Qe,onEnterCancelled:Qe,onBeforeLeave:Qe,onLeave:Qe,onAfterLeave:Qe,onLeaveCancelled:Qe,onBeforeAppear:Qe,onAppear:Qe,onAfterAppear:Qe,onAppearCancelled:Qe},ca={name:"BaseTransition",props:Go,setup(e,{slots:t}){const l=Vn(),i=sa();let n;return()=>{const r=t.default&&Qo(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 g=!1;const{getTransitionKey:m}=u.type;if(m){const x=m();n===void 0?n=x:x!==n&&(n=x,g=!0)}if(_&&_.type!==Ye&&(!Bt(u,_)||g)){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:g,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(g,[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 Qo(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 g;return a||(g=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=>g!==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 g=Re;if(u)return()=>Ui(u,g);const m=O=>{a=null,Ul(O,g,13,!i)};if(o&&g.suspense||dl)return _().then(O=>()=>Ui(O,g)).catch(O=>(m(O),()=>i?ne(i,{error:O}):null));const x=pe(!1),A=pe(),D=pe(!!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,g.parent&&Kl(g.parent.vnode)&&Di(g.parent.update)}).catch(O=>{m(O),A.value=O}),()=>{if(x.value&&u)return Ui(u,g);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){Jo(e,"a",t)}function da(e,t){Jo(e,"da",t)}function Jo(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;pl(),ul(l);const c=Ze(t,l,e,o);return qt(),gl(),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"),pa=kt("sp"),ga=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 g=o[t];if(g!==void 0)switch(g){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:g,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 Q in o){const X=o[Q];oe(X)&&(i[Q]=X.bind(l))}if(n){const Q=n.call(l,l);Ee(Q)&&(e.data=zl(Q))}if(dn=!0,r)for(const Q in r){const X=r[Q],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,Q,{enumerable:!0,configurable:!0,get:()=>ze.value,set:He=>ze.value=He})}if(c)for(const Q in c)es(c[Q],i,l,Q);if(a){const Q=oe(a)?a.call(l):a;Reflect.ownKeys(Q).forEach(X=>{Kt(X,Q[X])})}d&&_r(d,e,"c");function S(Q,X){te(X)?X.forEach(De=>Q(De.bind(l))):X&&Q(X.bind(l))}if(S(va,v),S(We,_),S(_a,g),S(fa,m),S(ua,x),S(da,A),S(ba,E),S(ma,G),S(ga,N),S(ql,O),S(Ci,y),S(pa,K),te(w))if(w.length){const Q=e.exposed||(e.exposed={});w.forEach(X=>{Object.defineProperty(Q,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:pr,emits:pr,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[_,g]=is(v,t,!0);Ie(o,_),g&&c.push(...g)};!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,g[1]=x<0||m-1||de(g,"default"))&&c.push(v)}}}const u=[o,c];return Ee(e)&&i.set(e,u),u}function gr(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((_,g)=>yi(_,t&&(te(t)?t[g]: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),g=Ne(a);if(_||g){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)):g&&(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),gi(),y._vnode=b;return}Tt=!1,v(y.firstChild,b,null,null,null),gi(),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 Q=!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 Q;if((Q=w&&w.onVnodeBeforeMount)&&Je(Q,H,y),V&&ct(y,null,H,"beforeMount"),((Q=w&&w.onVnodeMounted)||V||S)&&Ko(()=>{Q&&Je(Q,H,y),S&&le.enter(b),V&&ct(y,null,H,"mounted")},G),L&16&&!(w&&(w.innerHTML||w.textContent))){let X=g(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},g=(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=g(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:g=ut,insertStaticContent:m}=e,x=(f,p,k,T=null,R=null,I=null,B=!1,F=null,$=!!p.dynamicChildren)=>{if(f===p)return;f&&!Bt(f,p)&&(T=P(f),He(f,R,I,!0),f=null),p.patchFlag===-2&&($=!1,p.dynamicChildren=null);const{type:j,ref:J,shapeFlag:q}=p;switch(j){case al:A(f,p,k,T);break;case Ye:D(f,p,k,T);break;case Rl:f==null&&O(p,k,T,B);break;case ke:L(f,p,k,T,R,I,B,F,$);break;default:q&1?H(f,p,k,T,R,I,B,F,$):q&6?V(f,p,k,T,R,I,B,F,$):(q&64||q&128)&&j.process(f,p,k,T,R,I,B,F,$,M)}J!=null&&R&&yi(J,f&&f.ref,I,p||f,!p)},A=(f,p,k,T)=>{if(f==null)i(p.el=c(p.children),k,T);else{const R=p.el=f.el;p.children!==f.children&&u(R,p.children)}},D=(f,p,k,T)=>{f==null?i(p.el=a(p.children||""),k,T):p.el=f.el},O=(f,p,k,T)=>{[f.el,f.anchor]=m(f.children,p,k,T,f.el,f.anchor)},b=({el:f,anchor:p},k,T)=>{let R;for(;f&&f!==p;)R=_(f),i(f,k,T),f=R;i(p,k,T)},y=({el:f,anchor:p})=>{let k;for(;f&&f!==p;)k=_(f),n(f),f=k;n(p)},H=(f,p,k,T,R,I,B,F,$)=>{B=B||p.type==="svg",f==null?G(p,k,T,R,I,B,F,$):K(f,p,R,I,B,F,$)},G=(f,p,k,T,R,I,B,F)=>{let $,j;const{type:J,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&&J!=="foreignObject",B,F),se&&ct(f,null,T,"created"),N($,f,f.scopeId,B,T),q){for(const ge in q)ge!=="value"&&!Al(ge)&&r($,ge,null,q[ge],I,f.children,T,R,je);"value"in q&&r($,"value",null,q.value),(j=q.onVnodeBeforeMount)&&Je(j,T,f)}se&&ct(f,null,T,"beforeMount");const me=ss(R,re);me&&re.beforeEnter($),i($,p,k),((j=q&&q.onVnodeMounted)||me||se)&&Ue(()=>{j&&Je(j,T,f),me&&re.enter($),se&&ct(f,null,T,"mounted")},R)},N=(f,p,k,T,R)=>{if(k&&g(f,k),T)for(let I=0;I{for(let j=$;j{const F=p.el=f.el;let{patchFlag:$,dynamicChildren:j,dirs:J}=p;$|=f.patchFlag&16;const q=f.props||ye,Z=p.props||ye;let re;k&&Ft(k,!1),(re=Z.onVnodeBeforeUpdate)&&Je(re,k,p,f),J&&ct(p,f,k,"beforeUpdate"),k&&Ft(k,!0);const se=R&&p.type!=="foreignObject";if(j?w(f.dynamicChildren,j,F,k,T,se,I):B||X(f,p,F,null,k,T,se,I,!1),$>0){if($&16)U(F,p,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=p.dynamicProps;for(let ge=0;ge{re&&Je(re,k,p,f),J&&ct(p,f,k,"updated")},T)},w=(f,p,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,p.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,p.children,R,I,je)}"value"in T&&r(f,"value",k.value,T.value)}},L=(f,p,k,T,R,I,B,F,$)=>{const j=p.el=f?f.el:c(""),J=p.anchor=f?f.anchor:c("");let{patchFlag:q,dynamicChildren:Z,slotScopeIds:re}=p;re&&(F=F?F.concat(re):re),f==null?(i(j,k,T),i(J,k,T),E(p.children,k,J,R,I,B,F,$)):q>0&&q&64&&Z&&f.dynamicChildren?(w(f.dynamicChildren,Z,k,R,I,B,F),(p.key!=null||R&&p===R.subTree)&&cs(f,p,!0)):X(f,p,k,J,R,I,B,F,$)},V=(f,p,k,T,R,I,B,F,$)=>{p.slotScopeIds=F,f==null?p.shapeFlag&512?R.ctx.activate(p,k,T,B,$):le(p,k,T,R,I,B,$):ie(f,p,$)},le=(f,p,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,$,p,k)}return}S(F,f,p,k,R,I,B)},ie=(f,p,k)=>{const T=p.component=f.component;if(Zc(f,p,k))if(T.asyncDep&&!T.asyncResolved){Q(T,p,k);return}else T.next=p,Kc(T.update),T.update();else p.el=f.el,T.vnode=p},S=(f,p,k,T,R,I,B)=>{const F=()=>{if(f.isMounted){let{next:J,bu:q,u:Z,parent:re,vnode:se}=f,me=J,ge;Ft(f,!1),J?(J.el=se.el,Q(f,J,B)):J=se,q&&$i(q),(ge=J.props&&J.props.onVnodeBeforeUpdate)&&Je(ge,re,J,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),J.el=Oe.el,me===null&&ea(f,Oe.el),Z&&Ue(Z,R),(ge=J.props&&J.props.onVnodeUpdated)&&Ue(()=>Je(ge,re,J,se),R)}else{let J;const{el:q,props:Z}=p,{bm:re,m:se,parent:me}=f,ge=sl(p);if(Ft(f,!1),re&&$i(re),!ge&&(J=Z&&Z.onVnodeBeforeMount)&&Je(J,me,p),Ft(f,!0),q&&ae){const Oe=()=>{f.subTree=Wi(f),ae(q,f.subTree,f,R,null)};ge?p.type.__asyncLoader().then(()=>!f.isUnmounted&&Oe()):Oe()}else{const Oe=f.subTree=Wi(f);x(null,Oe,k,T,f,R,I),p.el=Oe.el}if(se&&Ue(se,R),!ge&&(J=Z&&Z.onVnodeMounted)){const Oe=p;Ue(()=>Je(J,me,Oe),R)}(p.shapeFlag&256||me&&sl(me.vnode)&&me.vnode.shapeFlag&256)&&f.a&&Ue(f.a,R),f.isMounted=!0,p=k=T=null}},$=f.effect=new Ln(F,()=>Di(j),f.scope),j=f.update=()=>$.run();j.id=f.uid,Ft(f,!0),j()},Q=(f,p,k)=>{p.component=f;const T=f.vnode.props;f.vnode=p,f.next=null,wa(f,p.props,T,k),Da(f,p.children,k),pl(),ar(f),gl()},X=(f,p,k,T,R,I,B,F,$=!1)=>{const j=f&&f.children,J=f?f.shapeFlag:0,q=p.children,{patchFlag:Z,shapeFlag:re}=p;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?(J&16&&je(j,R,I),q!==j&&d(k,q)):J&16?re&16?Se(j,q,k,T,R,I,B,F,$):je(j,R,I,!0):(J&8&&d(k,""),re&16&&E(q,k,T,R,I,B,F,$))},De=(f,p,k,T,R,I,B,F,$)=>{f=f||il,p=p||il;const j=f.length,J=p.length,q=Math.min(j,J);let Z;for(Z=0;ZJ?je(f,R,I,!0,!1,q):E(p,k,T,R,I,B,F,$,q)},Se=(f,p,k,T,R,I,B,F,$)=>{let j=0;const J=p.length;let q=f.length-1,Z=J-1;for(;j<=q&&j<=Z;){const re=f[j],se=p[j]=$?wt(p[j]):tt(p[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=p[Z]=$?wt(p[Z]):tt(p[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=p[j]=$?wt(p[j]):tt(p[j]);Ke.key!=null&&me.set(Ke.key,j)}let ge,Oe=0;const et=Z-se+1;let Jt=!1,Jn=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(ge=se;ge<=Z;ge++)if(kl[ge-se]===0&&Bt(Ke,p[ge])){st=ge;break}st===void 0?He(Ke,R,I,!0):(kl[st-se]=j+1,st>=Jn?Jn=st:Jt=!0,x(Ke,p[st],k,null,R,I,B,F,$),Oe++)}const Zn=Jt?Va(kl):il;for(ge=Zn.length-1,j=et-1;j>=0;j--){const Ke=se+j,st=p[Ke],er=Ke+1{const{el:I,type:B,transition:F,children:$,shapeFlag:j}=f;if(j&6){ze(f.component.subTree,p,k,T);return}if(j&128){f.suspense.move(p,k,T);return}if(j&64){B.move(f,p,k,M);return}if(B===ke){i(I,p,k);for(let q=0;q<$.length;q++)ze($[q],p,k,T);i(f.anchor,p,k);return}if(B===Rl){b(f,p,k);return}if(T!==2&&j&1&&F)if(T===0)F.beforeEnter(I),i(I,p,k),Ue(()=>F.enter(I),R);else{const{leave:q,delayLeave:Z,afterLeave:re}=F,se=()=>i(I,p,k),me=()=>{q(I,()=>{se(),re&&re()})};Z?Z(I,se,me):me()}else i(I,p,k)},He=(f,p,k,T=!1,R=!1)=>{const{type:I,props:B,ref:F,children:$,dynamicChildren:j,shapeFlag:J,patchFlag:q,dirs:Z}=f;if(F!=null&&yi(F,null,k,f,!0),J&256){p.ctx.deactivate(f);return}const re=J&1&&Z,se=!sl(f);let me;if(se&&(me=B&&B.onVnodeBeforeUnmount)&&Je(me,p,f),J&6)ot(f.component,k,T);else{if(J&128){f.suspense.unmount(k,T);return}re&&ct(f,null,p,"beforeUnmount"),J&64?f.type.remove(f,p,k,R,M,T):j&&(I!==ke||q>0&&q&64)?je(j,p,k,!1,!0):(I===ke&&q&384||!R&&J&16)&&je($,p,k),T&&yt(f)}(se&&(me=B&&B.onVnodeUnmounted)||re)&&Ue(()=>{me&&Je(me,p,f),re&&ct(f,null,p,"unmounted")},k)},yt=f=>{const{type:p,el:k,anchor:T,transition:R}=f;if(p===ke){xt(k,T);return}if(p===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,p)=>{let k;for(;f!==p;)k=_(f),n(f),f=k;n(p)},ot=(f,p,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,p,k)),F&&Ue(F,p),Ue(()=>{f.isUnmounted=!0},p),p&&p.pendingBranch&&!p.isUnmounted&&f.asyncDep&&!f.asyncResolved&&f.suspenseId===p.pendingId&&(p.deps--,p.deps===0&&p.resolve())},je=(f,p,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,p,k)=>{f==null?p._vnode&&He(p._vnode,null,null,!0):x(p._vnode||null,f,p,null,null,null,k),ar(),gi(),p._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),pl();const r=Dt(i,e,0,[e.props,n]);if(gl(),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),pl();try{Ea(e)}finally{gl(),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 Qa=Symbol.for("v-scx"),Ja=()=>Te(Qa),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:g=`${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,g),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,g),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()},_=g=>{g.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 g=d===Ot&&/\b(transform|all)(,|$)/.test(i(`${Ot}Property`).toString());return{type:d,timeout:v,propCount:_,hasTransform:g}}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(Qt(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||(gu.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=Qt(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--E11Bnfl.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-RxvsCsGa.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-1d860c29":()=>s(()=>import("./log.html-CGZK1GQx.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-CcUIcEMa.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-ZMnQxtAD.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-Beki-8Ir.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-BDf29_N4.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-hSwIpJ1e.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-76460a00":()=>s(()=>import("./http.html-Bd8eE7sZ.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-0614d322":()=>s(()=>import("./raw.html-Dq-5Ka_e.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-eeea2fb0":()=>s(()=>import("./splithttp.html-Bx6q0Pwz.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-33b1b709":()=>s(()=>import("./tcp.html-C7gwATZ1.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-BRoSCILt.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-CcQo-ZLW.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-DpRhKwiH.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-f91d64d6":()=>s(()=>import("./log.html-D45GuajB.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-BamFBjc9.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-BxZHVhF5.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-CAFb2hD9.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-BS64uoiA.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-990249a2":()=>s(()=>import("./log.html-CzhOF4Kn.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-59o86u4a.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-ByjruzeN.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-40ee4e87":()=>s(()=>import("./index.html-K7jpM5hZ.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-LSm1KTPV.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-C7BRucCz.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-DeeVesel.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-BSp-VUbt.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-5254cbc6":()=>s(()=>import("./tcp.html-Ddhaj7-G.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-D3njg8AT.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-CYYO7zib.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-SaUw7tAi.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-Bgp2ZT6j.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-BElssFCl.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-4360702e":()=>s(()=>import("./freedom.html-CrDIedPH.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-DxlumNKD.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-61928006":()=>s(()=>import("./http.html-B48Vd-PN.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-57fe845c":()=>s(()=>import("./raw.html-DuNVSVgJ.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-32d545e2":()=>s(()=>import("./splithttp.html-DyKm1XN4.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--bDd7Pwh.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-01d5d1de":()=>s(()=>import("./design.html-Btn4Kben.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-4d4e5367":()=>s(()=>import("./guide.html-CsHVnUvI.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-a58031da":()=>s(()=>import("./mkcp.html-CiCy0zuJ.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-5440615b":()=>s(()=>import("./muxcool.html-0vAkP06p.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-069325e5":()=>s(()=>import("./vless.html-B1AEvEQ5.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-ca50d634":()=>s(()=>import("./vmess.html-MjTCQevM.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-DtsVy-Ya.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),"v-379e896c":()=>s(()=>import("./http.html-RpxJy5zC.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-ad8e9394":()=>s(()=>import("./raw.html-Bhb5iOzr.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-f4c92f7a":()=>s(()=>import("./tcp.html-2dkeqgjG.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,ps=(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 gs={"v-8daa1a0e":h(()=>s(()=>import("./index.html-BHnedDAt.js"),__vite__mapDeps([]))),"v-aad48c6a":h(()=>s(()=>import("./news.html-B91dhz1J.js"),__vite__mapDeps([]))),"v-f7496066":h(()=>s(()=>import("./index.html-CccDmH3c.js"),__vite__mapDeps([]))),"v-ba934fd8":h(()=>s(()=>import("./index.html-gKYIFezi.js"),__vite__mapDeps([]))),"v-41ade9da":h(()=>s(()=>import("./api.html-BwBfpocK.js"),__vite__mapDeps([]))),"v-83dedd38":h(()=>s(()=>import("./dns.html-8KXbkngf.js"),__vite__mapDeps([]))),"v-192a19b9":h(()=>s(()=>import("./fakedns.html-CXq9EuY-.js"),__vite__mapDeps([]))),"v-7f6279d8":h(()=>s(()=>import("./inbound.html-BItHMh7T.js"),__vite__mapDeps([]))),"v-1d860c29":h(()=>s(()=>import("./log.html-Bo--iN1M.js"),__vite__mapDeps([]))),"v-fbaf47ec":h(()=>s(()=>import("./metrics.html-B3-FRGDI.js"),__vite__mapDeps([]))),"v-24956213":h(()=>s(()=>import("./observatory.html-BlplEISQ.js"),__vite__mapDeps([]))),"v-2367d756":h(()=>s(()=>import("./outbound.html-Iw8X2g5l.js"),__vite__mapDeps([]))),"v-4ebec35a":h(()=>s(()=>import("./policy.html-BRsJy0BP.js"),__vite__mapDeps([]))),"v-31b7756a":h(()=>s(()=>import("./reverse.html-OgoGtCv-.js"),__vite__mapDeps([]))),"v-70677432":h(()=>s(()=>import("./routing.html-DtA5ezO_.js"),__vite__mapDeps([]))),"v-7e21d6ae":h(()=>s(()=>import("./stats.html-CfiWDV46.js"),__vite__mapDeps([]))),"v-e3dfff38":h(()=>s(()=>import("./transport.html-Dv127mMA.js"),__vite__mapDeps([]))),"v-36b1a79b":h(()=>s(()=>import("./index.html-BCkfQtsq.js"),__vite__mapDeps([]))),"v-09a64f89":h(()=>s(()=>import("./command.html-C74Zzwa_.js"),__vite__mapDeps([]))),"v-2b1adf48":h(()=>s(()=>import("./config.html-CaEweKA5.js"),__vite__mapDeps([]))),"v-86ee963a":h(()=>s(()=>import("./document.html-CQH_IQX-.js"),__vite__mapDeps([]))),"v-0e5d7b39":h(()=>s(()=>import("./install.html-BqABFEgq.js"),__vite__mapDeps([]))),"v-2d0a870d":h(()=>s(()=>import("./index.html-BJJLWPxO.js"),__vite__mapDeps([]))),"v-2d0ab8b3":h(()=>s(()=>import("./index.html-B2bo5ZOO.js"),__vite__mapDeps([]))),"v-6a9e8054":h(()=>s(()=>import("./compile.html-gJ9_uLGu.js"),__vite__mapDeps([]))),"v-95e3eaea":h(()=>s(()=>import("./design.html-9xtXJBKw.js"),__vite__mapDeps([]))),"v-61e7eea6":h(()=>s(()=>import("./guide.html-UAu-Y-4H.js"),__vite__mapDeps([]))),"v-6e6c37e6":h(()=>s(()=>import("./mkcp.html-Cq8mAMHo.js"),__vite__mapDeps([]))),"v-13168a21":h(()=>s(()=>import("./muxcool.html-CUo0YI7_.js"),__vite__mapDeps([]))),"v-5c48c82b":h(()=>s(()=>import("./vless.html-CFcJw_nL.js"),__vite__mapDeps([]))),"v-1ee591a8":h(()=>s(()=>import("./vmess.html-DShhxEZz.js"),__vite__mapDeps([]))),"v-0d714d87":h(()=>s(()=>import("./browser_dialer.html-DPoLLonb.js"),__vite__mapDeps([]))),"v-0da7880a":h(()=>s(()=>import("./env.html-0m4UBMJO.js"),__vite__mapDeps([]))),"v-2aeb21f9":h(()=>s(()=>import("./fallback.html-uhRPRVcx.js"),__vite__mapDeps([]))),"v-3acf20ea":h(()=>s(()=>import("./multiple.html-CAuTO5xa.js"),__vite__mapDeps([]))),"v-792e28f8":h(()=>s(()=>import("./xtls.html-NZ56bZ_i.js"),__vite__mapDeps([]))),"v-b50d2334":h(()=>s(()=>import("./dokodemo.html-VXFl6Ejr.js"),__vite__mapDeps([]))),"v-593408b0":h(()=>s(()=>import("./http.html-B-9rXNoS.js"),__vite__mapDeps([]))),"v-802a842a":h(()=>s(()=>import("./shadowsocks.html-BoBE3TUs.js"),__vite__mapDeps([]))),"v-29995cea":h(()=>s(()=>import("./socks.html--OGyrplG.js"),__vite__mapDeps([]))),"v-2a1b3d72":h(()=>s(()=>import("./trojan.html-DGG1rBaz.js"),__vite__mapDeps([]))),"v-fb92e8aa":h(()=>s(()=>import("./vless.html-a9Jkze9g.js"),__vite__mapDeps([]))),"v-167afaac":h(()=>s(()=>import("./vmess.html-CM0l5E2w.js"),__vite__mapDeps([]))),"v-5588d0cc":h(()=>s(()=>import("./wireguard.html-DzgB3EwV.js"),__vite__mapDeps([]))),"v-749ad71a":h(()=>s(()=>import("./blackhole.html-DfpkkgPY.js"),__vite__mapDeps([]))),"v-6d39b970":h(()=>s(()=>import("./dns.html-DLTBofHa.js"),__vite__mapDeps([]))),"v-d76e893a":h(()=>s(()=>import("./freedom.html-ByGWvIrV.js"),__vite__mapDeps([]))),"v-c6b4b59e":h(()=>s(()=>import("./http.html-DOvT0y9w.js"),__vite__mapDeps([]))),"v-41ec0e0e":h(()=>s(()=>import("./loopback.html-DNsapIsk.js"),__vite__mapDeps([]))),"v-7b293e4a":h(()=>s(()=>import("./shadowsocks.html-Dp7Rjs0q.js"),__vite__mapDeps([]))),"v-15f5452a":h(()=>s(()=>import("./socks.html-0_G5pJuv.js"),__vite__mapDeps([]))),"v-5797bdb3":h(()=>s(()=>import("./trojan.html-CsEcJ5iO.js"),__vite__mapDeps([]))),"v-a60f016c":h(()=>s(()=>import("./vless.html-Cn6zw_0I.js"),__vite__mapDeps([]))),"v-413cee4b":h(()=>s(()=>import("./vmess.html-CZoqmIbf.js"),__vite__mapDeps([]))),"v-208ca3b9":h(()=>s(()=>import("./wireguard.html-UyKFaqMG.js"),__vite__mapDeps([]))),"v-2877542a":h(()=>s(()=>import("./grpc.html-2RCEkU0J.js"),__vite__mapDeps([]))),"v-76460a00":h(()=>s(()=>import("./http.html-BoEkf3hc.js"),__vite__mapDeps([]))),"v-04158536":h(()=>s(()=>import("./httpupgrade.html-B2K1tBnW.js"),__vite__mapDeps([]))),"v-3167b1dd":h(()=>s(()=>import("./mkcp.html-RYDvu18q.js"),__vite__mapDeps([]))),"v-0614d322":h(()=>s(()=>import("./raw.html-moyWEHbs.js"),__vite__mapDeps([]))),"v-eeea2fb0":h(()=>s(()=>import("./splithttp.html-C59rxUsD.js"),__vite__mapDeps([]))),"v-33b1b709":h(()=>s(()=>import("./tcp.html-hSF8trgX.js"),__vite__mapDeps([]))),"v-1ff57bba":h(()=>s(()=>import("./websocket.html-CER5FpY3.js"),__vite__mapDeps([]))),"v-3f09dcfa":h(()=>s(()=>import("./index.html-BVGw8-M8.js"),__vite__mapDeps([]))),"v-fb444906":h(()=>s(()=>import("./ch01-preface.html-D77cA9Yz.js"),__vite__mapDeps([]))),"v-075f3ae5":h(()=>s(()=>import("./ch02-preparation.html-COiMyrPE.js"),__vite__mapDeps([]))),"v-726d0633":h(()=>s(()=>import("./ch03-ssh.html-BOqQ3pux.js"),__vite__mapDeps([]))),"v-430c6ab8":h(()=>s(()=>import("./ch04-security.html-CKLdMMrq.js"),__vite__mapDeps([]))),"v-717c6376":h(()=>s(()=>import("./ch05-webpage.html-BFGvmjSO.js"),__vite__mapDeps([]))),"v-278039be":h(()=>s(()=>import("./ch06-certificates.html-GiWXSBdk.js"),__vite__mapDeps([]))),"v-a0c7f88e":h(()=>s(()=>import("./ch07-xray-server.html-CDn-775a.js"),__vite__mapDeps([]))),"v-86586ca2":h(()=>s(()=>import("./ch08-xray-clients.html-CEOoUra3.js"),__vite__mapDeps([]))),"v-3eb62514":h(()=>s(()=>import("./ch09-appendix.html-CozFZEJT.js"),__vite__mapDeps([]))),"v-3f09dcbc":h(()=>s(()=>import("./index.html-DbxdBC_G.js"),__vite__mapDeps([]))),"v-b21a2a20":h(()=>s(()=>import("./fallbacks-lv1.html-Bg8dj7Kh.js"),__vite__mapDeps([]))),"v-da623318":h(()=>s(()=>import("./fallbacks-with-sni.html-eKJVkRJ1.js"),__vite__mapDeps([]))),"v-fdd722ac":h(()=>s(()=>import("./routing-lv1-part1.html-BFenFNvP.js"),__vite__mapDeps([]))),"v-fa6d716e":h(()=>s(()=>import("./routing-lv1-part2.html-BqDKZVNr.js"),__vite__mapDeps([]))),"v-2f29e106":h(()=>s(()=>import("./work.html-ClRD37Fr.js"),__vite__mapDeps([]))),"v-3f09dc7e":h(()=>s(()=>import("./index.html-gmKSBbSu.js"),__vite__mapDeps([]))),"v-1c17916e":h(()=>s(()=>import("./iptables_gid.html-DNk5paAn.js"),__vite__mapDeps([]))),"v-a001cfa6":h(()=>s(()=>import("./nginx_or_haproxy_tls_tunnel.html-D0KkG3pU.js"),__vite__mapDeps([]))),"v-46333b48":h(()=>s(()=>import("./redirect.html-DOiNg0s_.js"),__vite__mapDeps([]))),"v-338bc63e":h(()=>s(()=>import("./tproxy.html-DBGuths-.js"),__vite__mapDeps([]))),"v-d68f7d58":h(()=>s(()=>import("./tproxy_ipv4_and_ipv6.html-DZorz4ml.js"),__vite__mapDeps([]))),"v-e533e2c6":h(()=>s(()=>import("./traffic_stats.html-CJPd3Vx1.js"),__vite__mapDeps([]))),"v-1e465ab0":h(()=>s(()=>import("./warp.html-D7q1TYSF.js"),__vite__mapDeps([]))),"v-1080fb37":h(()=>s(()=>import("./news.html-D6AEFpyV.js"),__vite__mapDeps([]))),"v-317fc580":h(()=>s(()=>import("./index.html-DENfAWCd.js"),__vite__mapDeps([]))),"v-45144c7f":h(()=>s(()=>import("./api.html-B9L82kBF.js"),__vite__mapDeps([]))),"v-23fbd2d0":h(()=>s(()=>import("./dns.html-Rqqe7q81.js"),__vite__mapDeps([]))),"v-2b7ec525":h(()=>s(()=>import("./fakedns.html-t4xl7UEa.js"),__vite__mapDeps([]))),"v-5ab92300":h(()=>s(()=>import("./inbound.html-BiWuRsHt.js"),__vite__mapDeps([]))),"v-f91d64d6":h(()=>s(()=>import("./log.html-B5OAPKR7.js"),__vite__mapDeps([]))),"v-d705f114":h(()=>s(()=>import("./metrics.html-BLVGjqEG.js"),__vite__mapDeps([]))),"v-5c8e777f":h(()=>s(()=>import("./observatory.html-CTtdzf4U.js"),__vite__mapDeps([]))),"v-268cd669":h(()=>s(()=>import("./outbound.html-DIhD1gph.js"),__vite__mapDeps([]))),"v-4492d567":h(()=>s(()=>import("./policy.html-LeuD8U7Z.js"),__vite__mapDeps([]))),"v-0d0e1e92":h(()=>s(()=>import("./reverse.html-DgBDzGdK.js"),__vite__mapDeps([]))),"v-4bbe1d5a":h(()=>s(()=>import("./routing.html-C9IlburL.js"),__vite__mapDeps([]))),"v-16426d1a":h(()=>s(()=>import("./stats.html-Bbi2nVPE.js"),__vite__mapDeps([]))),"v-5de780d0":h(()=>s(()=>import("./transport.html-8GeYnnYT.js"),__vite__mapDeps([]))),"v-f88d343e":h(()=>s(()=>import("./index.html-_0Ezskfc.js"),__vite__mapDeps([]))),"v-38d56a07":h(()=>s(()=>import("./index.html-CvwzfGmP.js"),__vite__mapDeps([]))),"v-4d046016":h(()=>s(()=>import("./command.html-EcRoAGlR.js"),__vite__mapDeps([]))),"v-22b35270":h(()=>s(()=>import("./config.html-BzsuZqqV.js"),__vite__mapDeps([]))),"v-30bd7c12":h(()=>s(()=>import("./document.html-BZ1SIqVg.js"),__vite__mapDeps([]))),"v-439608b6":h(()=>s(()=>import("./install.html-DzAGXbV7.js"),__vite__mapDeps([]))),"v-408e88d1":h(()=>s(()=>import("./news.html-DCjYRQYz.js"),__vite__mapDeps([]))),"v-b1cce5cc":h(()=>s(()=>import("./index.html-B15e5H01.js"),__vite__mapDeps([]))),"v-7521da19":h(()=>s(()=>import("./api.html-BckqTxy3.js"),__vite__mapDeps([]))),"v-5409606a":h(()=>s(()=>import("./dns.html-DR4B6jjx.js"),__vite__mapDeps([]))),"v-5877f5bf":h(()=>s(()=>import("./fakedns.html-CpDHPnS9.js"),__vite__mapDeps([]))),"v-00c6c1cc":h(()=>s(()=>import("./inbound.html-L9a0cvjw.js"),__vite__mapDeps([]))),"v-990249a2":h(()=>s(()=>import("./log.html-BXL_0fB7.js"),__vite__mapDeps([]))),"v-7d138fe0":h(()=>s(()=>import("./metrics.html-Dkomm98b.js"),__vite__mapDeps([]))),"v-11e9cb19":h(()=>s(()=>import("./observatory.html-Bx2LCBH2.js"),__vite__mapDeps([]))),"v-ce8c8de2":h(()=>s(()=>import("./outbound.html-S2rhwo1W.js"),__vite__mapDeps([]))),"v-3dc4298d":h(()=>s(()=>import("./policy.html-DYGaWyLN.js"),__vite__mapDeps([]))),"v-26722151":h(()=>s(()=>import("./reverse.html-DWsup7hU.js"),__vite__mapDeps([]))),"v-071a21ed":h(()=>s(()=>import("./routing.html-Bteon3s5.js"),__vite__mapDeps([]))),"v-7922fc34":h(()=>s(()=>import("./stats.html-DscjAxzk.js"),__vite__mapDeps([]))),"v-3156f2ea":h(()=>s(()=>import("./transport.html-5mGZ7PS0.js"),__vite__mapDeps([]))),"v-40ee4e87":h(()=>s(()=>import("./index.html-DiLddjw-.js"),__vite__mapDeps([]))),"v-a1c899be":h(()=>s(()=>import("./index.html-mwD5RiEN.js"),__vite__mapDeps([]))),"v-a6257be2":h(()=>s(()=>import("./command.html-B6aFEOgE.js"),__vite__mapDeps([]))),"v-d63f95d4":h(()=>s(()=>import("./config.html-vruIm5ed.js"),__vite__mapDeps([]))),"v-fbbfd9c6":h(()=>s(()=>import("./document.html-Dc52ImNq.js"),__vite__mapDeps([]))),"v-9cb72482":h(()=>s(()=>import("./install.html-EtxbwpEb.js"),__vite__mapDeps([]))),"v-51a51d87":h(()=>s(()=>import("./transparent_proxy.html-B1GAn8Vo.js"),__vite__mapDeps([]))),"v-76b9a0f3":h(()=>s(()=>import("./browser_dialer.html-9mg-S3B0.js"),__vite__mapDeps([]))),"v-565dbfc4":h(()=>s(()=>import("./env.html-CxuA45IG.js"),__vite__mapDeps([]))),"v-0fbd1336":h(()=>s(()=>import("./fallback.html-E73rITGw.js"),__vite__mapDeps([]))),"v-a0627812":h(()=>s(()=>import("./multiple.html-BybJ5crB.js"),__vite__mapDeps([]))),"v-d190d938":h(()=>s(()=>import("./xtls.html-DG8Gu1K9.js"),__vite__mapDeps([]))),"v-72afc2d2":h(()=>s(()=>import("./dokodemo.html-BBd3QiE-.js"),__vite__mapDeps([]))),"v-773d731c":h(()=>s(()=>import("./http.html-DxP83VAp.js"),__vite__mapDeps([]))),"v-f555fc02":h(()=>s(()=>import("./shadowsocks.html-CeqH0S6O.js"),__vite__mapDeps([]))),"v-e35196c2":h(()=>s(()=>import("./socks.html-CrKlUUFh.js"),__vite__mapDeps([]))),"v-29188644":h(()=>s(()=>import("./trojan.html-C9BfolYY.js"),__vite__mapDeps([]))),"v-255a6ebf":h(()=>s(()=>import("./vless.html-CtLVfJjP.js"),__vite__mapDeps([]))),"v-8cc24480":h(()=>s(()=>import("./vmess.html-CH8R4M0b.js"),__vite__mapDeps([]))),"v-a2605ea4":h(()=>s(()=>import("./wireguard.html-DsutH5Up.js"),__vite__mapDeps([]))),"v-64e47ef4":h(()=>s(()=>import("./blackhole.html-CD0iddvc.js"),__vite__mapDeps([]))),"v-e979b848":h(()=>s(()=>import("./dns.html-DteCkEye.js"),__vite__mapDeps([]))),"v-617f0fcf":h(()=>s(()=>import("./freedom.html-CMut6erm.js"),__vite__mapDeps([]))),"v-3fc98845":h(()=>s(()=>import("./http.html-BK7TKRvo.js"),__vite__mapDeps([]))),"v-1b804722":h(()=>s(()=>import("./loopback.html-lkkEOlDw.js"),__vite__mapDeps([]))),"v-63077cb6":h(()=>s(()=>import("./shadowsocks.html-CfyZl4UT.js"),__vite__mapDeps([]))),"v-516476d4":h(()=>s(()=>import("./socks.html-ynBvKVZW.js"),__vite__mapDeps([]))),"v-7d61a872":h(()=>s(()=>import("./trojan.html-US2vPEfy.js"),__vite__mapDeps([]))),"v-6e50feb6":h(()=>s(()=>import("./vless.html-CR2GlAuv.js"),__vite__mapDeps([]))),"v-02956db7":h(()=>s(()=>import("./vmess.html-D6aAfTYm.js"),__vite__mapDeps([]))),"v-797f8d25":h(()=>s(()=>import("./wireguard.html-Bh9HPmRj.js"),__vite__mapDeps([]))),"v-2c6058d4":h(()=>s(()=>import("./grpc.html-CbqWvXkn.js"),__vite__mapDeps([]))),"v-1c38292a":h(()=>s(()=>import("./h2.html-ChGHILPS.js"),__vite__mapDeps([]))),"v-17ff144a":h(()=>s(()=>import("./httpupgrade.html-CIAeTyxj.js"),__vite__mapDeps([]))),"v-1a7f9d6e":h(()=>s(()=>import("./mkcp.html-Cc1dhAxF.js"),__vite__mapDeps([]))),"v-4df52c3c":h(()=>s(()=>import("./splithttp.html-DpYV3dkE.js"),__vite__mapDeps([]))),"v-5254cbc6":h(()=>s(()=>import("./tcp.html-C8W2HTBr.js"),__vite__mapDeps([]))),"v-9520f392":h(()=>s(()=>import("./websocket.html-CIfvjdmu.js"),__vite__mapDeps([]))),"v-b7760e2c":h(()=>s(()=>import("./compile.html-BrZYwGdl.js"),__vite__mapDeps([]))),"v-fb774212":h(()=>s(()=>import("./design.html-CD_tRvvq.js"),__vite__mapDeps([]))),"v-38c376c1":h(()=>s(()=>import("./guide.html-B-RTAIpY.js"),__vite__mapDeps([]))),"v-21bccd79":h(()=>s(()=>import("./mkcp.html-I65vHqSR.js"),__vite__mapDeps([]))),"v-27001935":h(()=>s(()=>import("./muxcool.html-BrGombeu.js"),__vite__mapDeps([]))),"v-21b30c3f":h(()=>s(()=>import("./vless.html-DDvmOZHh.js"),__vite__mapDeps([]))),"v-94110980":h(()=>s(()=>import("./vmess.html-CX4bhZ0G.js"),__vite__mapDeps([]))),"v-789ba7ef":h(()=>s(()=>import("./index.html-DaEmYnBK.js"),__vite__mapDeps([]))),"v-d3712ade":h(()=>s(()=>import("./ch01-preface.html-DlvnkN2h.js"),__vite__mapDeps([]))),"v-41f9c00e":h(()=>s(()=>import("./ch02-preparation.html-B8tpsGb2.js"),__vite__mapDeps([]))),"v-4c013f47":h(()=>s(()=>import("./ch03-ssh.html-CBC8l8gj.js"),__vite__mapDeps([]))),"v-a75683b8":h(()=>s(()=>import("./ch04-security.html-CSWtjUmG.js"),__vite__mapDeps([]))),"v-f5341aec":h(()=>s(()=>import("./ch05-webpage.html-C9hDniXJ.js"),__vite__mapDeps([]))),"v-4458f72a":h(()=>s(()=>import("./ch06-certificates.html-R61iRZQr.js"),__vite__mapDeps([]))),"v-f1802e66":h(()=>s(()=>import("./ch07-xray-server.html-9lLGK84R.js"),__vite__mapDeps([]))),"v-4ca6f1ca":h(()=>s(()=>import("./ch08-xray-clients.html-DLNDZslA.js"),__vite__mapDeps([]))),"v-b0030f00":h(()=>s(()=>import("./ch09-appendix.html-Bfj0ily0.js"),__vite__mapDeps([]))),"v-789ba80e":h(()=>s(()=>import("./index.html-BEqfzz3v.js"),__vite__mapDeps([]))),"v-103b3e5c":h(()=>s(()=>import("./fallbacks-lv1.html-BTlqatoV.js"),__vite__mapDeps([]))),"v-110dd688":h(()=>s(()=>import("./fallbacks-with-sni.html-Do5jNPZL.js"),__vite__mapDeps([]))),"v-c425a7d4":h(()=>s(()=>import("./routing-lv1-part1.html-CjfPl-AJ.js"),__vite__mapDeps([]))),"v-c0bbf696":h(()=>s(()=>import("./routing-lv1-part2.html-AY0RcavA.js"),__vite__mapDeps([]))),"v-5b6477cc":h(()=>s(()=>import("./work.html-C0sVGft-.js"),__vite__mapDeps([]))),"v-789ba82d":h(()=>s(()=>import("./index.html-BA6EnvF3.js"),__vite__mapDeps([]))),"v-05ddc65d":h(()=>s(()=>import("./iptables_gid.html-8qdut9aE.js"),__vite__mapDeps([]))),"v-474afe99":h(()=>s(()=>import("./nginx_or_haproxy_tls_tunnel.html-BBscUhBq.js"),__vite__mapDeps([]))),"v-930ac920":h(()=>s(()=>import("./redirect.html-B-G6C8Kz.js"),__vite__mapDeps([]))),"v-c579975c":h(()=>s(()=>import("./tproxy.html-Dulb6WIx.js"),__vite__mapDeps([]))),"v-7efb7c68":h(()=>s(()=>import("./tproxy_ipv4_and_ipv6.html-CmyteKZw.js"),__vite__mapDeps([]))),"v-12a33bee":h(()=>s(()=>import("./traffic_stats.html-BFwn7sHB.js"),__vite__mapDeps([]))),"v-7d2b8478":h(()=>s(()=>import("./warp.html-B7-UX_pL.js"),__vite__mapDeps([]))),"v-1cfb44e6":h(()=>s(()=>import("./browser_dialer.html-TLjtzU25.js"),__vite__mapDeps([]))),"v-6a3f8078":h(()=>s(()=>import("./env.html-Oz3j8oFe.js"),__vite__mapDeps([]))),"v-74f22e7f":h(()=>s(()=>import("./fallback.html-DdkmPffb.js"),__vite__mapDeps([]))),"v-2c9f7c11":h(()=>s(()=>import("./multiple.html-BSBGs6J2.js"),__vite__mapDeps([]))),"v-630c687e":h(()=>s(()=>import("./xtls.html-DW7qpfS8.js"),__vite__mapDeps([]))),"v-20ff0a28":h(()=>s(()=>import("./dokodemo.html-BRscbUqJ.js"),__vite__mapDeps([]))),"v-43124836":h(()=>s(()=>import("./http.html-Cokq0RDI.js"),__vite__mapDeps([]))),"v-6a351ba5":h(()=>s(()=>import("./shadowsocks.html-B66sBlmf.js"),__vite__mapDeps([]))),"v-3d1d02c5":h(()=>s(()=>import("./socks.html-qPyShTyR.js"),__vite__mapDeps([]))),"v-1567b378":h(()=>s(()=>import("./trojan.html-jDz_xw6S.js"),__vite__mapDeps([]))),"v-57bf8636":h(()=>s(()=>import("./vless.html-CzthPHZp.js"),__vite__mapDeps([]))),"v-6864abe6":h(()=>s(()=>import("./vmess.html-hbK08lZx.js"),__vite__mapDeps([]))),"v-67d3c858":h(()=>s(()=>import("./wireguard.html-B0ggG9X9.js"),__vite__mapDeps([]))),"v-5910da20":h(()=>s(()=>import("./blackhole.html-Dm6vb_2V.js"),__vite__mapDeps([]))),"v-5717f8f6":h(()=>s(()=>import("./dns.html-D7WmQBVs.js"),__vite__mapDeps([]))),"v-4360702e":h(()=>s(()=>import("./freedom.html-BpiDXzpq.js"),__vite__mapDeps([]))),"v-22e1532a":h(()=>s(()=>import("./http.html-B-jc76lJ.js"),__vite__mapDeps([]))),"v-38c69248":h(()=>s(()=>import("./loopback.html-f6MTGwlS.js"),__vite__mapDeps([]))),"v-1a2a97d0":h(()=>s(()=>import("./shadowsocks.html-DKR8aoD9.js"),__vite__mapDeps([]))),"v-0141bb30":h(()=>s(()=>import("./socks.html-DsSoQ2EE.js"),__vite__mapDeps([]))),"v-544bef26":h(()=>s(()=>import("./trojan.html-DGRy70K7.js"),__vite__mapDeps([]))),"v-cf761560":h(()=>s(()=>import("./vless.html-DTd56s9M.js"),__vite__mapDeps([]))),"v-2c896451":h(()=>s(()=>import("./vmess.html-BcLHSwPd.js"),__vite__mapDeps([]))),"v-0502a6bf":h(()=>s(()=>import("./wireguard.html-Z-rjO2wB.js"),__vite__mapDeps([]))),"v-13c3ca30":h(()=>s(()=>import("./grpc.html-C8FaUDz7.js"),__vite__mapDeps([]))),"v-61928006":h(()=>s(()=>import("./http.html-BNAuY1-K.js"),__vite__mapDeps([]))),"v-453f5c70":h(()=>s(()=>import("./httpupgrade.html-D0PJ7P8D.js"),__vite__mapDeps([]))),"v-1cb427e3":h(()=>s(()=>import("./mkcp.html-BKGtAD67.js"),__vite__mapDeps([]))),"v-57fe845c":h(()=>s(()=>import("./raw.html-D1leTOpm.js"),__vite__mapDeps([]))),"v-32d545e2":h(()=>s(()=>import("./splithttp.html-BYFFTbwo.js"),__vite__mapDeps([]))),"v-cb60c046":h(()=>s(()=>import("./websocket.html-tuR9jVHl.js"),__vite__mapDeps([]))),"v-7ce977e0":h(()=>s(()=>import("./compile.html-CB5wbp39.js"),__vite__mapDeps([]))),"v-01d5d1de":h(()=>s(()=>import("./design.html-TCBoryCh.js"),__vite__mapDeps([]))),"v-4d4e5367":h(()=>s(()=>import("./guide.html-BaiH9eLl.js"),__vite__mapDeps([]))),"v-a58031da":h(()=>s(()=>import("./mkcp.html-B_VgiCh2.js"),__vite__mapDeps([]))),"v-5440615b":h(()=>s(()=>import("./muxcool.html-B1gy8ouX.js"),__vite__mapDeps([]))),"v-069325e5":h(()=>s(()=>import("./vless.html-CRUfBMsw.js"),__vite__mapDeps([]))),"v-ca50d634":h(()=>s(()=>import("./vmess.html-iOLQROgD.js"),__vite__mapDeps([]))),"v-490791ee":h(()=>s(()=>import("./index.html-Di_c7H8I.js"),__vite__mapDeps([]))),"v-78f09a92":h(()=>s(()=>import("./ch01-preface.html-C0a0dqvP.js"),__vite__mapDeps([]))),"v-64f6e51f":h(()=>s(()=>import("./ch02-preparation.html-BTFVBYnb.js"),__vite__mapDeps([]))),"v-69478a6d":h(()=>s(()=>import("./ch03-ssh.html-DMelmJ53.js"),__vite__mapDeps([]))),"v-271d7abe":h(()=>s(()=>import("./ch04-security.html-lWMkPygX.js"),__vite__mapDeps([]))),"v-9ab38aa0":h(()=>s(()=>import("./ch05-webpage.html-Ttc51XZa.js"),__vite__mapDeps([]))),"v-7cddd6c4":h(()=>s(()=>import("./ch06-certificates.html-DTfFRe9A.js"),__vite__mapDeps([]))),"v-0d33adf3":h(()=>s(()=>import("./ch07-xray-server.html-CeBPCvns.js"),__vite__mapDeps([]))),"v-123166b5":h(()=>s(()=>import("./ch08-xray-clients.html-4HRoOenM.js"),__vite__mapDeps([]))),"v-22c7351a":h(()=>s(()=>import("./ch09-appendix.html-Dxssa-41.js"),__vite__mapDeps([]))),"v-490791b0":h(()=>s(()=>import("./index.html-Dw33NxP-.js"),__vite__mapDeps([]))),"v-e9f80a14":h(()=>s(()=>import("./fallbacks-lv1.html-DYR8pz2w.js"),__vite__mapDeps([]))),"v-2db62ba4":h(()=>s(()=>import("./fallbacks-with-sni.html-B9Z6PoAs.js"),__vite__mapDeps([]))),"v-531be8a0":h(()=>s(()=>import("./routing-lv1-part1.html-DgnRljgC.js"),__vite__mapDeps([]))),"v-4fb23762":h(()=>s(()=>import("./routing-lv1-part2.html-DRTLdiGd.js"),__vite__mapDeps([]))),"v-fdd8db80":h(()=>s(()=>import("./work.html-CWo8pB56.js"),__vite__mapDeps([]))),"v-49079172":h(()=>s(()=>import("./index.html-DdX7oNPd.js"),__vite__mapDeps([]))),"v-331e0e83":h(()=>s(()=>import("./iptables_gid.html-BioBNJrh.js"),__vite__mapDeps([]))),"v-7418a5b3":h(()=>s(()=>import("./nginx_or_haproxy_tls_tunnel.html-4XVDz6M7.js"),__vite__mapDeps([]))),"v-587e32d4":h(()=>s(()=>import("./redirect.html-7Cirz0bl.js"),__vite__mapDeps([]))),"v-9c63de10":h(()=>s(()=>import("./tproxy.html-B25CC21-.js"),__vite__mapDeps([]))),"v-a4c782e4":h(()=>s(()=>import("./tproxy_ipv4_and_ipv6.html-CoLDDyIl.js"),__vite__mapDeps([]))),"v-71771ea3":h(()=>s(()=>import("./traffic_stats.html-F4ztFfj9.js"),__vite__mapDeps([]))),"v-70300bea":h(()=>s(()=>import("./warp.html-BjjHsRAC.js"),__vite__mapDeps([]))),"v-7689d7f3":h(()=>s(()=>import("./transparent_proxy.html-DCVZLq4e.js"),__vite__mapDeps([]))),"v-39b3c50d":h(()=>s(()=>import("./transparent_proxy.html-DLTkeZqq.js"),__vite__mapDeps([]))),"v-3706649a":h(()=>s(()=>import("./404.html-CIRXttqd.js"),__vite__mapDeps([]))),"v-379e896c":h(()=>s(()=>import("./http.html-BvJL3-d2.js"),__vite__mapDeps([]))),"v-ad8e9394":h(()=>s(()=>import("./raw.html-2_ieGPf7.js"),__vite__mapDeps([]))),"v-f4c92f7a":h(()=>s(()=>import("./tcp.html-Dvpc5dBq.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(""),gt=()=>{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=pe(Iu),Mn=Symbol(""),Ql=()=>{const e=Te(Mn);if(!e)throw new Error("useRouteLocale() is called without provider.");return e},ll=pe(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)=>ps(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=pe(!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(()=>gs[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 g=Date.now()-u;if(g+t>=a)return a-g}return t}var _=function(){var g=[].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,g);c&&c(b),d.forEach(function(y){return(0,y.resolve)(b)}),d=[]}},v()),D){var O=e.apply(m,g);return c&&c(O),x(O)}d.push({resolve:x,reject:A})})};return _.cancel=function(g){r!==void 0&&clearTimeout(r),d.forEach(function(m){return(0,m.reject)(g)}),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,Q){return[].concat(S,no(Q))},[]):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},g=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},Q=void 0,X=void 0;if(N.container)if(N.container instanceof Object)S=Mt({},S,N.container),Q=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})}Q=Q||S.width-N.margin*2,X=X||S.height-N.margin*2;var ot=E.zoomedHd||E.original,je=io(ot)?Q:ot.naturalWidth||Q,P=io(ot)?X:ot.naturalHeight||X,z=ot.getBoundingClientRect(),M=z.top,Y=z.left,ae=z.width,f=z.height,p=Math.min(Math.max(ae,je),Q)/ae,k=Math.min(Math.max(f,P),X)/f,T=Math.min(p,k),R=(-Y+(Q-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 Q=b;E.original=Q[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():g({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:g,close:m,toggle:x,update:c,clone:a,attach:u,detach:d,on:v,off:_,getOptions:A,getImages:D,getZoomedImage:O};return w};function ph(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 gh=".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}";ph(gh);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/http.md","/config/transports/mkcp.md","/config/transports/raw.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/http.md","/ru/config/transports/mkcp.md","/ru/config/transports/raw.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=pe(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=pe(!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=pe(!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=pe(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,_,g)=>(d.addEventListener(v,_,g),()=>d.removeEventListener(v,_,g)),a=Ge(()=>[qh(t),_l(n)],([d,v])=>{if(o(),!d)return;const _=Hh(v)?{...v}:v;r.push(...l.flatMap(g=>i.map(m=>c(d,g,m,_))))},{immediate:!0,flush:"post"}),u=()=>{a(),o()};return Ms(u),u}function Gh(){const e=pe(!1),t=Vn();return t&&We(()=>{e.value=!0},t),e}function Yh(e){const t=Gh();return C(()=>(t.value,!!e()))}function Qh(e,t={}){const{window:l=Ti}=t,i=Yh(()=>l&&"matchMedia"in l&&typeof l.matchMedia=="function");let n;const r=pe(!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__",Jh=Zh();function Zh(){return ui in ai||(ai[ui]=ai[ui]||{}),ai[ui]}function ev(e,t){return Jh[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:g=w=>{console.error(w)},initOnMounted:m}=i,x=(d?No:pe)(typeof t=="function"?t():t);if(!l)try{l=ev("getDefaultStorage",()=>{var w;return(w=Ti)==null?void 0:w.localStorage})()}catch(w){g(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){g(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){g(U)}finally{w?Xl(y):y()}}}}function K(w){E(w.detail)}return x}function iv(e){return Qh("(prefers-color-scheme: dark)",e)}const nv=_e({name:"CodeGroup",slots:Object,setup(e,{slots:t}){const l=pe([]),i=pe(-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 g=_===i.value;return he("button",{ref:m=>{m&&(l.value[_]=m)},class:{"code-group__nav-tab":!0,"code-group__nav-tab-active":g},role:"tab",ariaSelected:g,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},pv=()=>{const e=Fe(),t=gt(),l=Gt(),i=ml(),n=bt(),r=C(()=>gv(t.value,e.value,l.value,n,i.path));Kt(qs,r)},gv=(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=ps(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 go;const yv={[$l.MOBILE]:Number.parseInt((go=Ev.mobile)==null?void 0:go.replace("px",""),10)},Qs=(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=gt(),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=gt(),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),g=C(()=>{const D=Object.keys(n.value.locales);return D.length?!D.some(O=>O===r.value.link):r.value.link!=="/"}),m=C(()=>g.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:g,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=gt(),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:g,link:m,type:x="primary"})=>({text:g,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 g=he("img",{src:Wn(r.value),alt:o.value,height:c.value});return l.value.heroImageDark===void 0?g:he(Bn,()=>g)},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=Ql(),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 g=he("img",{class:"logo",src:Wn(a.value),alt:u.value});return n.value.logoDark===void 0?g:he(Bn,()=>g)}};return Object.defineProperty(_,"__isScriptSetup",{enumerable:!1,value:!0}),_}}),Qv=["aria-hidden"];function Jv(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,Qv)):Le("",!0)]),_:1},8,["to"])}const Zv=xe(Yv,[["render",Jv],["__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 Js=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=pe(!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:Js};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 g=bt(),m=Ql(),x=xs(),A=$n(),D=cv(),O=Fe();return C(()=>{const b=Object.keys(x.value.locales);if(b.length<2)return[];const y=g.currentRoute.value.path,H=g.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);g.getRoutes().some(S=>S.path===ie)?L=H.replace(y,ie):L=K.home??N}return{text:U,link:L}})}]})},i=()=>{const g=Fe(),m=C(()=>g.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?g.value.repoLabel?g.value.repoLabel:x.value===null?"Source":x.value:null);return C(()=>!A.value||!D.value?[]:[{text:D.value,link:A.value}])},n=(g,m)=>nt(m)?qn(g,m):m.children?{...m,children:m.children.map(x=>n(g,x))}:m,r=()=>{const g=bt(),m=Fe();return C(()=>(m.value.navbar||[]).map(x=>n(g,x)))},o=pe(!1),c=r(),a=l(),u=i(),d=C(()=>[...c.value,...a.value,...u.value]);Qs($l.MOBILE,g=>{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 p_(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",p_],["__file","NavbarItems.vue"]]),g_=_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(g_,[["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=pe(null),n=pe(null),r=pe(0),o=C(()=>r.value?{maxWidth:r.value+"px"}:{});Qs($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(),_=gt();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(),_=gt();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(),_=gt();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=(_,g)=>g===!1?null:nt(g)?qn(_,g):Hn(g)?g:!1,i=(_,g,m)=>{const x=_.findIndex(A=>A.link===g);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,g,m);if(D)return D}return null},n=gt(),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}}),Q_=["aria-label"],J_={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",J_,[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,Q_)):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())},g=o.afterEach(x=>{Xl(()=>{d.value=u.value})});ql(()=>{g()});const m={props:l,item:i,depth:n,route:r,router:o,isActive:c,itemClass:a,isOpenDefault:u,isOpen:d,toggleIsOpen:v,onClick:_,unregisterRouterHook:g,AutoLink:bl,DropdownTransition:Js};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"]]),p2=_e({__name:"Sidebar",setup(e,{expose:t}){t();const l={NavbarItems:Zs,SidebarItems:f2};return Object.defineProperty(l,"__isScriptSetup",{enumerable:!1,value:!0}),l}}),g2={class:"sidebar"};function m2(e,t,l,i,n,r){return W(),ee("aside",g2,[ne(i.NavbarItems),be(e.$slots,"top"),ne(i.SidebarItems),be(e.$slots,"bottom")])}const b2=xe(p2,[["render",m2],["__file","Sidebar.vue"]]),k2=_e({__name:"Layout",setup(e,{expose:t}){t();const l=Gt(),i=gt(),n=Fe(),r=C(()=>i.value.navbar!==!1&&n.value.navbar!==!1),o=Gn(),c=pe(!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 g;We(()=>{g=bt().afterEach(()=>{a(!1)})}),Ci(()=>{g()});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 g},set unregisterRouterHook(O){g=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=Ql(),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(),pv()},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}}),Qn=_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),g={linkRenderer:l,getContent:i,i18nData:n,containerClass:r,titleClass:o,locale:c,showTips:a,tipType:u,containerType:d,containerTitle:v,containerContent:_};return Object.defineProperty(g,"__isScriptSetup",{enumerable:!1,value:!0}),g}}),$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)}Qn.render=B2;Qn.__file="src/client/components/I18nTip.vue";var W2=Qn,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:"DnsServerObject",slug:"dnsserverobject",link:"#dnsserverobject",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",headers:[{level:2,title:"HttpObject",slug:"httpobject",link:"#httpobject",children:[]}],path:"/config/transports/http.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:"RAW",headers:[{level:2,title:"RawObject",slug:"rawobject",link:"#rawobject",children:[{level:3,title:"NoneHeaderObject",slug:"noneheaderobject",link:"#noneheaderobject",children:[]},{level:3,title:"HttpHeaderObject",slug:"httpheaderobject",link:"#httpheaderobject",children:[]}]}],path:"/config/transports/raw.html",pathLocale:"/",extraFields:[]},{title:"SplitHTTP(H2、QUIC H3)",headers:[{level:2,title:"SplitHttpObject",slug:"splithttpobject",link:"#splithttpobject",children:[]},{level:2,title:"XmuxObject",slug:"xmuxobject",link:"#xmuxobject",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:[],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:"DnsServerObject",slug:"dnsserverobject",link:"#dnsserverobject",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:"DnsServerObject",slug:"dnsserverobject",link:"#dnsserverobject",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:"Способы передачи (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:"/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:"XmuxObject",slug:"xmuxobject",link:"#xmuxobject",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(XTLS Vision Seed)",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 (fragment, noises)",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(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:"/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",headers:[{level:2,title:"HttpObject",slug:"httpobject",link:"#httpobject",children:[]}],path:"/ru/config/transports/http.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:"RAW",headers:[{level:2,title:"RawObject",slug:"rawobject",link:"#rawobject",children:[{level:3,title:"NoneHeaderObject",slug:"noneheaderobject",link:"#noneheaderobject",children:[]},{level:3,title:"HttpHeaderObject",slug:"httpheaderobject",link:"#httpheaderobject",children:[]}]}],path:"/ru/config/transports/raw.html",pathLocale:"/ru/",extraFields:[]},{title:"SplitHTTP (H2, QUIC H3)",headers:[{level:2,title:"SplitHttpObject",slug:"splithttpobject",link:"#splithttpobject",children:[]},{level:2,title:"XmuxObject",slug:"xmuxobject",link:"#xmuxobject",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:"/ru/config/transports/splithttp.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:"Запрос и ответ",slug:"запрос-и-ответ",link:"#запрос-и-ответ",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",slug:"проблемы-с-udp",link:"#проблемы-с-udp",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:"Идентификатор пользователя",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: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:[]},{title:"HTTP",headers:[{level:2,title:"HttpObject",slug:"httpobject",link:"#httpobject",children:[]}],path:"/en/config/transports/http.html",pathLocale:"/en/",extraFields:[]},{title:"RAW",headers:[{level:2,title:"RawObject",slug:"rawobject",link:"#rawobject",children:[{level:3,title:"NoneHeaderObject",slug:"noneheaderobject",link:"#noneheaderobject",children:[]},{level:3,title:"HttpHeaderObject",slug:"httpheaderobject",link:"#httpheaderobject",children:[]}]}],path:"/en/config/transports/raw.html",pathLocale:"/en/",extraFields:[]},{title:"TCP",headers:[],path:"/ru/config/transports/tcp.html",pathLocale:"/ru/",extraFields:[]}],Q2=pe(Y2),J2=()=>Q2,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=pe(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=Ql(),o=J2(),c=pe(null),a=pe(!1),u=pe(""),d=C(()=>t.value[r.value]??{}),v=Z2({searchIndex:o,routeLocale:r,query:u,maxSuggestions:i}),{focusIndex:_,focusNext:g,focusPrev:m}=ef(v);G2({input:c,hotKeys:l});const x=C(()=>a.value&&!!v.value.length),A=()=>{x.value&&m()},D=()=>{x.value&&g()},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-DzkBFzwq.js"),__vite__mapDeps([])))),e.component("Tab",h(()=>s(()=>import("./Tab-DrybaNdq.js"),__vite__mapDeps([])))),e.component("Tabs",h(()=>s(()=>import("./Tabs-BwcLe76G.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-76460a00","/config/transports/http.html",{title:"HTTP"},[":md"]],["v-04158536","/config/transports/httpupgrade.html",{title:"HTTPUpgrade"},[":md"]],["v-3167b1dd","/config/transports/mkcp.html",{title:"mKCP"},[":md"]],["v-0614d322","/config/transports/raw.html",{title:"RAW"},[":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:"Способы передачи (uTLS, REALITY)"},[":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(XTLS Vision Seed)"},[":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 (fragment, noises)"},[":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(XTLS Vision Seed)"},[":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-61928006","/ru/config/transports/http.html",{title:"HTTP"},[":md"]],["v-453f5c70","/ru/config/transports/httpupgrade.html",{title:"HTTPUpgrade"},[":md"]],["v-1cb427e3","/ru/config/transports/mkcp.html",{title:"mKCP"},[":md"]],["v-57fe845c","/ru/config/transports/raw.html",{title:"RAW"},[":md"]],["v-32d545e2","/ru/config/transports/splithttp.html",{title:"SplitHTTP (H2, QUIC H3)"},[":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:""},[]],["v-379e896c","/en/config/transports/http.html",{title:"HTTP"},[":md"]],["v-ad8e9394","/en/config/transports/raw.html",{title:"RAW"},[":md"]],["v-f4c92f7a","/ru/config/transports/tcp.html",{title:"TCP"},[":md"]]];var po=_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:po,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:po}]),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=gs[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}},pf=()=>{const e=$u(),t=Wu();let l=[];const i=()=>{e.value.forEach(o=>{const c=gf(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})})},gf=([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;pf();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,pe 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/http.md","/config/transports/mkcp.md","/config/transports/raw.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/http.md","/ru/config/transports/mkcp.md","/ru/config/transports/raw.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=pe(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=pe(!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=pe(!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=pe(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,_,g)=>(d.addEventListener(v,_,g),()=>d.removeEventListener(v,_,g)),a=Ge(()=>[qh(t),_l(n)],([d,v])=>{if(o(),!d)return;const _=Hh(v)?{...v}:v;r.push(...l.flatMap(g=>i.map(m=>c(d,g,m,_))))},{immediate:!0,flush:"post"}),u=()=>{a(),o()};return Ms(u),u}function Gh(){const e=pe(!1),t=Vn();return t&&We(()=>{e.value=!0},t),e}function Yh(e){const t=Gh();return C(()=>(t.value,!!e()))}function Qh(e,t={}){const{window:l=Ti}=t,i=Yh(()=>l&&"matchMedia"in l&&typeof l.matchMedia=="function");let n;const r=pe(!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__",Jh=Zh();function Zh(){return ui in ai||(ai[ui]=ai[ui]||{}),ai[ui]}function ev(e,t){return Jh[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:g=w=>{console.error(w)},initOnMounted:m}=i,x=(d?No:pe)(typeof t=="function"?t():t);if(!l)try{l=ev("getDefaultStorage",()=>{var w;return(w=Ti)==null?void 0:w.localStorage})()}catch(w){g(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){g(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){g(U)}finally{w?Xl(y):y()}}}}function K(w){E(w.detail)}return x}function iv(e){return Qh("(prefers-color-scheme: dark)",e)}const nv=_e({name:"CodeGroup",slots:Object,setup(e,{slots:t}){const l=pe([]),i=pe(-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 g=_===i.value;return he("button",{ref:m=>{m&&(l.value[_]=m)},class:{"code-group__nav-tab":!0,"code-group__nav-tab-active":g},role:"tab",ariaSelected:g,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},pv=()=>{const e=Fe(),t=gt(),l=Gt(),i=ml(),n=bt(),r=C(()=>gv(t.value,e.value,l.value,n,i.path));Kt(qs,r)},gv=(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=ps(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 go;const yv={[$l.MOBILE]:Number.parseInt((go=Ev.mobile)==null?void 0:go.replace("px",""),10)},Qs=(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=gt(),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=gt(),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),g=C(()=>{const D=Object.keys(n.value.locales);return D.length?!D.some(O=>O===r.value.link):r.value.link!=="/"}),m=C(()=>g.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:g,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=gt(),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:g,link:m,type:x="primary"})=>({text:g,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 g=he("img",{src:Wn(r.value),alt:o.value,height:c.value});return l.value.heroImageDark===void 0?g:he(Bn,()=>g)},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=Ql(),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 g=he("img",{class:"logo",src:Wn(a.value),alt:u.value});return n.value.logoDark===void 0?g:he(Bn,()=>g)}};return Object.defineProperty(_,"__isScriptSetup",{enumerable:!1,value:!0}),_}}),Qv=["aria-hidden"];function Jv(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,Qv)):Le("",!0)]),_:1},8,["to"])}const Zv=xe(Yv,[["render",Jv],["__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 Js=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=pe(!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:Js};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 g=bt(),m=Ql(),x=xs(),A=$n(),D=cv(),O=Fe();return C(()=>{const b=Object.keys(x.value.locales);if(b.length<2)return[];const y=g.currentRoute.value.path,H=g.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);g.getRoutes().some(S=>S.path===ie)?L=H.replace(y,ie):L=K.home??N}return{text:U,link:L}})}]})},i=()=>{const g=Fe(),m=C(()=>g.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?g.value.repoLabel?g.value.repoLabel:x.value===null?"Source":x.value:null);return C(()=>!A.value||!D.value?[]:[{text:D.value,link:A.value}])},n=(g,m)=>nt(m)?qn(g,m):m.children?{...m,children:m.children.map(x=>n(g,x))}:m,r=()=>{const g=bt(),m=Fe();return C(()=>(m.value.navbar||[]).map(x=>n(g,x)))},o=pe(!1),c=r(),a=l(),u=i(),d=C(()=>[...c.value,...a.value,...u.value]);Qs($l.MOBILE,g=>{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 p_(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",p_],["__file","NavbarItems.vue"]]),g_=_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(g_,[["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=pe(null),n=pe(null),r=pe(0),o=C(()=>r.value?{maxWidth:r.value+"px"}:{});Qs($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(),_=gt();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(),_=gt();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(),_=gt();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=(_,g)=>g===!1?null:nt(g)?qn(_,g):Hn(g)?g:!1,i=(_,g,m)=>{const x=_.findIndex(A=>A.link===g);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,g,m);if(D)return D}return null},n=gt(),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}}),Q_=["aria-label"],J_={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",J_,[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,Q_)):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())},g=o.afterEach(x=>{Xl(()=>{d.value=u.value})});ql(()=>{g()});const m={props:l,item:i,depth:n,route:r,router:o,isActive:c,itemClass:a,isOpenDefault:u,isOpen:d,toggleIsOpen:v,onClick:_,unregisterRouterHook:g,AutoLink:bl,DropdownTransition:Js};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"]]),p2=_e({__name:"Sidebar",setup(e,{expose:t}){t();const l={NavbarItems:Zs,SidebarItems:f2};return Object.defineProperty(l,"__isScriptSetup",{enumerable:!1,value:!0}),l}}),g2={class:"sidebar"};function m2(e,t,l,i,n,r){return W(),ee("aside",g2,[ne(i.NavbarItems),be(e.$slots,"top"),ne(i.SidebarItems),be(e.$slots,"bottom")])}const b2=xe(p2,[["render",m2],["__file","Sidebar.vue"]]),k2=_e({__name:"Layout",setup(e,{expose:t}){t();const l=Gt(),i=gt(),n=Fe(),r=C(()=>i.value.navbar!==!1&&n.value.navbar!==!1),o=Gn(),c=pe(!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 g;We(()=>{g=bt().afterEach(()=>{a(!1)})}),Ci(()=>{g()});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 g},set unregisterRouterHook(O){g=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=Ql(),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(),pv()},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}}),Qn=_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),g={linkRenderer:l,getContent:i,i18nData:n,containerClass:r,titleClass:o,locale:c,showTips:a,tipType:u,containerType:d,containerTitle:v,containerContent:_};return Object.defineProperty(g,"__isScriptSetup",{enumerable:!1,value:!0}),g}}),$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)}Qn.render=B2;Qn.__file="src/client/components/I18nTip.vue";var W2=Qn,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:"DnsServerObject",slug:"dnsserverobject",link:"#dnsserverobject",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",headers:[{level:2,title:"HttpObject",slug:"httpobject",link:"#httpobject",children:[]}],path:"/config/transports/http.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:"RAW",headers:[{level:2,title:"RawObject",slug:"rawobject",link:"#rawobject",children:[{level:3,title:"NoneHeaderObject",slug:"noneheaderobject",link:"#noneheaderobject",children:[]},{level:3,title:"HttpHeaderObject",slug:"httpheaderobject",link:"#httpheaderobject",children:[]}]}],path:"/config/transports/raw.html",pathLocale:"/",extraFields:[]},{title:"SplitHTTP(H2、QUIC H3)",headers:[{level:2,title:"SplitHttpObject",slug:"splithttpobject",link:"#splithttpobject",children:[]},{level:2,title:"XmuxObject",slug:"xmuxobject",link:"#xmuxobject",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:[],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:"DnsServerObject",slug:"dnsserverobject",link:"#dnsserverobject",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:"DnsServerObject",slug:"dnsserverobject",link:"#dnsserverobject",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:"Способы передачи (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:"/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:"XmuxObject",slug:"xmuxobject",link:"#xmuxobject",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(XTLS Vision Seed)",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 (fragment, noises)",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(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:"/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",headers:[{level:2,title:"HttpObject",slug:"httpobject",link:"#httpobject",children:[]}],path:"/ru/config/transports/http.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:"RAW",headers:[{level:2,title:"RawObject",slug:"rawobject",link:"#rawobject",children:[{level:3,title:"NoneHeaderObject",slug:"noneheaderobject",link:"#noneheaderobject",children:[]},{level:3,title:"HttpHeaderObject",slug:"httpheaderobject",link:"#httpheaderobject",children:[]}]}],path:"/ru/config/transports/raw.html",pathLocale:"/ru/",extraFields:[]},{title:"SplitHTTP (H2, QUIC H3)",headers:[{level:2,title:"SplitHttpObject",slug:"splithttpobject",link:"#splithttpobject",children:[]},{level:2,title:"XmuxObject",slug:"xmuxobject",link:"#xmuxobject",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:"/ru/config/transports/splithttp.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:"Запрос и ответ",slug:"запрос-и-ответ",link:"#запрос-и-ответ",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",slug:"проблемы-с-udp",link:"#проблемы-с-udp",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:"Идентификатор пользователя",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: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:[]},{title:"HTTP",headers:[{level:2,title:"HttpObject",slug:"httpobject",link:"#httpobject",children:[]}],path:"/en/config/transports/http.html",pathLocale:"/en/",extraFields:[]},{title:"RAW",headers:[{level:2,title:"RawObject",slug:"rawobject",link:"#rawobject",children:[{level:3,title:"NoneHeaderObject",slug:"noneheaderobject",link:"#noneheaderobject",children:[]},{level:3,title:"HttpHeaderObject",slug:"httpheaderobject",link:"#httpheaderobject",children:[]}]}],path:"/en/config/transports/raw.html",pathLocale:"/en/",extraFields:[]},{title:"TCP",headers:[],path:"/ru/config/transports/tcp.html",pathLocale:"/ru/",extraFields:[]}],Q2=pe(Y2),J2=()=>Q2,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=pe(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=Ql(),o=J2(),c=pe(null),a=pe(!1),u=pe(""),d=C(()=>t.value[r.value]??{}),v=Z2({searchIndex:o,routeLocale:r,query:u,maxSuggestions:i}),{focusIndex:_,focusNext:g,focusPrev:m}=ef(v);G2({input:c,hotKeys:l});const x=C(()=>a.value&&!!v.value.length),A=()=>{x.value&&m()},D=()=>{x.value&&g()},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-CldRIkxW.js"),__vite__mapDeps([])))),e.component("Tab",h(()=>s(()=>import("./Tab-DHpoGKXO.js"),__vite__mapDeps([])))),e.component("Tabs",h(()=>s(()=>import("./Tabs-CPdZ5LMC.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-76460a00","/config/transports/http.html",{title:"HTTP"},[":md"]],["v-04158536","/config/transports/httpupgrade.html",{title:"HTTPUpgrade"},[":md"]],["v-3167b1dd","/config/transports/mkcp.html",{title:"mKCP"},[":md"]],["v-0614d322","/config/transports/raw.html",{title:"RAW"},[":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:"Способы передачи (uTLS, REALITY)"},[":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(XTLS Vision Seed)"},[":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 (fragment, noises)"},[":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(XTLS Vision Seed)"},[":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-61928006","/ru/config/transports/http.html",{title:"HTTP"},[":md"]],["v-453f5c70","/ru/config/transports/httpupgrade.html",{title:"HTTPUpgrade"},[":md"]],["v-1cb427e3","/ru/config/transports/mkcp.html",{title:"mKCP"},[":md"]],["v-57fe845c","/ru/config/transports/raw.html",{title:"RAW"},[":md"]],["v-32d545e2","/ru/config/transports/splithttp.html",{title:"SplitHTTP (H2, QUIC H3)"},[":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:""},[]],["v-379e896c","/en/config/transports/http.html",{title:"HTTP"},[":md"]],["v-ad8e9394","/en/config/transports/raw.html",{title:"RAW"},[":md"]],["v-f4c92f7a","/ru/config/transports/tcp.html",{title:"TCP"},[":md"]]];var po=_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:po,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:po}]),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=gs[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}},pf=()=>{const e=$u(),t=Wu();let l=[];const i=()=>{e.value.forEach(o=>{const c=gf(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})})},gf=([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;pf();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,pe 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-BJstDFsX.js b/assets/arc-TolVAfGG.js similarity index 98% rename from assets/arc-BJstDFsX.js rename to assets/arc-TolVAfGG.js index 6f3a5e4fa..f560113da 100644 --- a/assets/arc-BJstDFsX.js +++ b/assets/arc-TolVAfGG.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-IUatkdtb.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),ph?(this.rect.x-=(this.labelWidth-h)/2,this.setWidth(this.labelWidth)):this.labelPosHorizontal=="right"&&this.setWidth(h+this.labelWidth)),this.labelHeight&&(this.labelPosVertical=="top"?(this.rect.y-=this.labelHeight,this.setHeight(o+this.labelHeight)):this.labelPosVertical=="center"&&this.labelHeight>o?(this.rect.y-=(this.labelHeight-o)/2,this.setHeight(this.labelHeight)):this.labelPosVertical=="bottom"&&this.setHeight(o+this.labelHeight))}}},a.prototype.getInclusionTreeDepth=function(){if(this.inclusionTreeDepth==s.MAX_VALUE)throw"assert failed";return this.inclusionTreeDepth},a.prototype.transform=function(t){var h=this.rect.x;h>r.WORLD_BOUNDARY?h=r.WORLD_BOUNDARY:h<-r.WORLD_BOUNDARY&&(h=-r.WORLD_BOUNDARY);var o=this.rect.y;o>r.WORLD_BOUNDARY?o=r.WORLD_BOUNDARY:o<-r.WORLD_BOUNDARY&&(o=-r.WORLD_BOUNDARY);var c=new f(h,o),l=t.inverseTransformPoint(c);this.setLocation(l.x,l.y)},a.prototype.getLeft=function(){return this.rect.x},a.prototype.getRight=function(){return this.rect.x+this.rect.width},a.prototype.getTop=function(){return this.rect.y},a.prototype.getBottom=function(){return this.rect.y+this.rect.height},a.prototype.getParent=function(){return this.owner==null?null:this.owner.getParent()},A.exports=a},function(A,G,N){var g=N(0);function s(){}for(var i in g)s[i]=g[i];s.MAX_ITERATIONS=2500,s.DEFAULT_EDGE_LENGTH=50,s.DEFAULT_SPRING_STRENGTH=.45,s.DEFAULT_REPULSION_STRENGTH=4500,s.DEFAULT_GRAVITY_STRENGTH=.4,s.DEFAULT_COMPOUND_GRAVITY_STRENGTH=1,s.DEFAULT_GRAVITY_RANGE_FACTOR=3.8,s.DEFAULT_COMPOUND_GRAVITY_RANGE_FACTOR=1.5,s.DEFAULT_USE_SMART_IDEAL_EDGE_LENGTH_CALCULATION=!0,s.DEFAULT_USE_SMART_REPULSION_RANGE_CALCULATION=!0,s.DEFAULT_COOLING_FACTOR_INCREMENTAL=.3,s.COOLING_ADAPTATION_FACTOR=.33,s.ADAPTATION_LOWER_NODE_LIMIT=1e3,s.ADAPTATION_UPPER_NODE_LIMIT=5e3,s.MAX_NODE_DISPLACEMENT_INCREMENTAL=100,s.MAX_NODE_DISPLACEMENT=s.MAX_NODE_DISPLACEMENT_INCREMENTAL*3,s.MIN_REPULSION_DIST=s.DEFAULT_EDGE_LENGTH/10,s.CONVERGENCE_CHECK_PERIOD=100,s.PER_LEVEL_IDEAL_EDGE_LENGTH_FACTOR=.1,s.MIN_EDGE_LENGTH=1,s.GRID_CALCULATION_CHECK_PERIOD=10,A.exports=s},function(A,G,N){function g(s,i){s==null&&i==null?(this.x=0,this.y=0):(this.x=s,this.y=i)}g.prototype.getX=function(){return this.x},g.prototype.getY=function(){return this.y},g.prototype.setX=function(s){this.x=s},g.prototype.setY=function(s){this.y=s},g.prototype.getDifference=function(s){return new DimensionD(this.x-s.x,this.y-s.y)},g.prototype.getCopy=function(){return new g(this.x,this.y)},g.prototype.translate=function(s){return this.x+=s.width,this.y+=s.height,this},A.exports=g},function(A,G,N){var g=N(2),s=N(10),i=N(0),r=N(7),e=N(3),f=N(1),a=N(13),y=N(12),t=N(11);function h(c,l,T){g.call(this,T),this.estimatedSize=s.MIN_VALUE,this.margin=i.DEFAULT_GRAPH_MARGIN,this.edges=[],this.nodes=[],this.isConnected=!1,this.parent=c,l!=null&&l instanceof r?this.graphManager=l:l!=null&&l instanceof Layout&&(this.graphManager=l.graphManager)}h.prototype=Object.create(g.prototype);for(var o in g)h[o]=g[o];h.prototype.getNodes=function(){return this.nodes},h.prototype.getEdges=function(){return this.edges},h.prototype.getGraphManager=function(){return this.graphManager},h.prototype.getParent=function(){return this.parent},h.prototype.getLeft=function(){return this.left},h.prototype.getRight=function(){return this.right},h.prototype.getTop=function(){return this.top},h.prototype.getBottom=function(){return this.bottom},h.prototype.isConnected=function(){return this.isConnected},h.prototype.add=function(c,l,T){if(l==null&&T==null){var u=c;if(this.graphManager==null)throw"Graph has no graph mgr!";if(this.getNodes().indexOf(u)>-1)throw"Node already in graph!";return u.owner=this,this.getNodes().push(u),u}else{var d=c;if(!(this.getNodes().indexOf(l)>-1&&this.getNodes().indexOf(T)>-1))throw"Source or target not in graph!";if(!(l.owner==T.owner&&l.owner==this))throw"Both owners must be this graph!";return l.owner!=T.owner?null:(d.source=l,d.target=T,d.isInterGraph=!1,this.getEdges().push(d),l.edges.push(d),T!=l&&T.edges.push(d),d)}},h.prototype.remove=function(c){var l=c;if(c instanceof e){if(l==null)throw"Node is null!";if(!(l.owner!=null&&l.owner==this))throw"Owner graph is invalid!";if(this.graphManager==null)throw"Owner graph manager is invalid!";for(var T=l.edges.slice(),u,d=T.length,L=0;L-1&&P>-1))throw"Source and/or target doesn't know this edge!";u.source.edges.splice(M,1),u.target!=u.source&&u.target.edges.splice(P,1);var F=u.source.owner.getEdges().indexOf(u);if(F==-1)throw"Not in owner's edge list!";u.source.owner.getEdges().splice(F,1)}},h.prototype.updateLeftTop=function(){for(var c=s.MAX_VALUE,l=s.MAX_VALUE,T,u,d,L=this.getNodes(),F=L.length,M=0;MT&&(c=T),l>u&&(l=u)}return c==s.MAX_VALUE?null:(L[0].getParent().paddingLeft!=null?d=L[0].getParent().paddingLeft:d=this.margin,this.left=l-d,this.top=c-d,new y(this.left,this.top))},h.prototype.updateBounds=function(c){for(var l=s.MAX_VALUE,T=-s.MAX_VALUE,u=s.MAX_VALUE,d=-s.MAX_VALUE,L,F,M,P,J,V=this.nodes,Q=V.length,D=0;DL&&(l=L),TM&&(u=M),dL&&(l=L),TM&&(u=M),d=this.nodes.length){var Q=0;T.forEach(function(D){D.owner==c&&Q++}),Q==this.nodes.length&&(this.isConnected=!0)}},A.exports=h},function(A,G,N){var g,s=N(1);function i(r){g=N(6),this.layout=r,this.graphs=[],this.edges=[]}i.prototype.addRoot=function(){var r=this.layout.newGraph(),e=this.layout.newNode(null),f=this.add(r,e);return this.setRootGraph(f),this.rootGraph},i.prototype.add=function(r,e,f,a,y){if(f==null&&a==null&&y==null){if(r==null)throw"Graph is null!";if(e==null)throw"Parent node is null!";if(this.graphs.indexOf(r)>-1)throw"Graph already in this graph mgr!";if(this.graphs.push(r),r.parent!=null)throw"Already has a parent!";if(e.child!=null)throw"Already has a child!";return r.parent=e,e.child=r,r}else{y=f,a=e,f=r;var t=a.getOwner(),h=y.getOwner();if(!(t!=null&&t.getGraphManager()==this))throw"Source not in this graph mgr!";if(!(h!=null&&h.getGraphManager()==this))throw"Target not in this graph mgr!";if(t==h)return f.isInterGraph=!1,t.add(f,a,y);if(f.isInterGraph=!0,f.source=a,f.target=y,this.edges.indexOf(f)>-1)throw"Edge already in inter-graph edge list!";if(this.edges.push(f),!(f.source!=null&&f.target!=null))throw"Edge source and/or target is null!";if(!(f.source.edges.indexOf(f)==-1&&f.target.edges.indexOf(f)==-1))throw"Edge already in source and/or target incidency list!";return f.source.edges.push(f),f.target.edges.push(f),f}},i.prototype.remove=function(r){if(r instanceof g){var e=r;if(e.getGraphManager()!=this)throw"Graph not in this graph mgr";if(!(e==this.rootGraph||e.parent!=null&&e.parent.graphManager==this))throw"Invalid parent node!";var f=[];f=f.concat(e.getEdges());for(var a,y=f.length,t=0;t=r.getRight()?e[0]+=Math.min(r.getX()-i.getX(),i.getRight()-r.getRight()):r.getX()<=i.getX()&&r.getRight()>=i.getRight()&&(e[0]+=Math.min(i.getX()-r.getX(),r.getRight()-i.getRight())),i.getY()<=r.getY()&&i.getBottom()>=r.getBottom()?e[1]+=Math.min(r.getY()-i.getY(),i.getBottom()-r.getBottom()):r.getY()<=i.getY()&&r.getBottom()>=i.getBottom()&&(e[1]+=Math.min(i.getY()-r.getY(),r.getBottom()-i.getBottom()));var y=Math.abs((r.getCenterY()-i.getCenterY())/(r.getCenterX()-i.getCenterX()));r.getCenterY()===i.getCenterY()&&r.getCenterX()===i.getCenterX()&&(y=1);var t=y*e[0],h=e[1]/y;e[0]t)return e[0]=f,e[1]=o,e[2]=y,e[3]=V,!1;if(ay)return e[0]=h,e[1]=a,e[2]=P,e[3]=t,!1;if(fy?(e[0]=l,e[1]=T,n=!0):(e[0]=c,e[1]=o,n=!0):v===p&&(f>y?(e[0]=h,e[1]=o,n=!0):(e[0]=u,e[1]=T,n=!0)),-E===p?y>f?(e[2]=J,e[3]=V,m=!0):(e[2]=P,e[3]=M,m=!0):E===p&&(y>f?(e[2]=F,e[3]=M,m=!0):(e[2]=Q,e[3]=V,m=!0)),n&&m)return!1;if(f>y?a>t?(I=this.getCardinalDirection(v,p,4),w=this.getCardinalDirection(E,p,2)):(I=this.getCardinalDirection(-v,p,3),w=this.getCardinalDirection(-E,p,1)):a>t?(I=this.getCardinalDirection(-v,p,1),w=this.getCardinalDirection(-E,p,3)):(I=this.getCardinalDirection(v,p,2),w=this.getCardinalDirection(E,p,4)),!n)switch(I){case 1:H=o,R=f+-L/p,e[0]=R,e[1]=H;break;case 2:R=u,H=a+d*p,e[0]=R,e[1]=H;break;case 3:H=T,R=f+L/p,e[0]=R,e[1]=H;break;case 4:R=l,H=a+-d*p,e[0]=R,e[1]=H;break}if(!m)switch(w){case 1:k=M,x=y+-rt/p,e[2]=x,e[3]=k;break;case 2:x=Q,k=t+D*p,e[2]=x,e[3]=k;break;case 3:k=V,x=y+rt/p,e[2]=x,e[3]=k;break;case 4:x=J,k=t+-D*p,e[2]=x,e[3]=k;break}}return!1},s.getCardinalDirection=function(i,r,e){return i>r?e:1+e%4},s.getIntersection=function(i,r,e,f){if(f==null)return this.getIntersection2(i,r,e);var a=i.x,y=i.y,t=r.x,h=r.y,o=e.x,c=e.y,l=f.x,T=f.y,u=void 0,d=void 0,L=void 0,F=void 0,M=void 0,P=void 0,J=void 0,V=void 0,Q=void 0;return L=h-y,M=a-t,J=t*y-a*h,F=T-c,P=o-l,V=l*c-o*T,Q=L*P-F*M,Q===0?null:(u=(M*V-P*J)/Q,d=(F*J-L*V)/Q,new g(u,d))},s.angleOfVector=function(i,r,e,f){var a=void 0;return i!==e?(a=Math.atan((f-r)/(e-i)),e=0){var T=(-o+Math.sqrt(o*o-4*h*c))/(2*h),u=(-o-Math.sqrt(o*o-4*h*c))/(2*h),d=null;return T>=0&&T<=1?[T]:u>=0&&u<=1?[u]:d}else return null},s.HALF_PI=.5*Math.PI,s.ONE_AND_HALF_PI=1.5*Math.PI,s.TWO_PI=2*Math.PI,s.THREE_PI=3*Math.PI,A.exports=s},function(A,G,N){function g(){}g.sign=function(s){return s>0?1:s<0?-1:0},g.floor=function(s){return s<0?Math.ceil(s):Math.floor(s)},g.ceil=function(s){return s<0?Math.floor(s):Math.ceil(s)},A.exports=g},function(A,G,N){function g(){}g.MAX_VALUE=2147483647,g.MIN_VALUE=-2147483648,A.exports=g},function(A,G,N){var g=function(){function a(y,t){for(var h=0;h"u"?"undefined":g(i);return i==null||r!="object"&&r!="function"},A.exports=s},function(A,G,N){function g(o){if(Array.isArray(o)){for(var c=0,l=Array(o.length);c0&&c;){for(L.push(M[0]);L.length>0&&c;){var P=L[0];L.splice(0,1),d.add(P);for(var J=P.getEdges(),u=0;u-1&&M.splice(rt,1)}d=new Set,F=new Map}}return o},h.prototype.createDummyNodesForBendpoints=function(o){for(var c=[],l=o.source,T=this.graphManager.calcLowestCommonAncestor(o.source,o.target),u=0;u0){for(var T=this.edgeToDummyNodes.get(l),u=0;u=0&&c.splice(V,1);var Q=F.getNeighborsList();Q.forEach(function(n){if(l.indexOf(n)<0){var m=T.get(n),v=m-1;v==1&&P.push(n),T.set(n,v)}})}l=l.concat(P),(c.length==1||c.length==2)&&(u=!0,d=c[0])}return d},h.prototype.setGraphManager=function(o){this.graphManager=o},A.exports=h},function(A,G,N){function g(){}g.seed=1,g.x=0,g.nextDouble=function(){return g.x=Math.sin(g.seed++)*1e4,g.x-Math.floor(g.x)},A.exports=g},function(A,G,N){var g=N(5);function s(i,r){this.lworldOrgX=0,this.lworldOrgY=0,this.ldeviceOrgX=0,this.ldeviceOrgY=0,this.lworldExtX=1,this.lworldExtY=1,this.ldeviceExtX=1,this.ldeviceExtY=1}s.prototype.getWorldOrgX=function(){return this.lworldOrgX},s.prototype.setWorldOrgX=function(i){this.lworldOrgX=i},s.prototype.getWorldOrgY=function(){return this.lworldOrgY},s.prototype.setWorldOrgY=function(i){this.lworldOrgY=i},s.prototype.getWorldExtX=function(){return this.lworldExtX},s.prototype.setWorldExtX=function(i){this.lworldExtX=i},s.prototype.getWorldExtY=function(){return this.lworldExtY},s.prototype.setWorldExtY=function(i){this.lworldExtY=i},s.prototype.getDeviceOrgX=function(){return this.ldeviceOrgX},s.prototype.setDeviceOrgX=function(i){this.ldeviceOrgX=i},s.prototype.getDeviceOrgY=function(){return this.ldeviceOrgY},s.prototype.setDeviceOrgY=function(i){this.ldeviceOrgY=i},s.prototype.getDeviceExtX=function(){return this.ldeviceExtX},s.prototype.setDeviceExtX=function(i){this.ldeviceExtX=i},s.prototype.getDeviceExtY=function(){return this.ldeviceExtY},s.prototype.setDeviceExtY=function(i){this.ldeviceExtY=i},s.prototype.transformX=function(i){var r=0,e=this.lworldExtX;return e!=0&&(r=this.ldeviceOrgX+(i-this.lworldOrgX)*this.ldeviceExtX/e),r},s.prototype.transformY=function(i){var r=0,e=this.lworldExtY;return e!=0&&(r=this.ldeviceOrgY+(i-this.lworldOrgY)*this.ldeviceExtY/e),r},s.prototype.inverseTransformX=function(i){var r=0,e=this.ldeviceExtX;return e!=0&&(r=this.lworldOrgX+(i-this.ldeviceOrgX)*this.lworldExtX/e),r},s.prototype.inverseTransformY=function(i){var r=0,e=this.ldeviceExtY;return e!=0&&(r=this.lworldOrgY+(i-this.ldeviceOrgY)*this.lworldExtY/e),r},s.prototype.inverseTransformPoint=function(i){var r=new g(this.inverseTransformX(i.x),this.inverseTransformY(i.y));return r},A.exports=s},function(A,G,N){function g(t){if(Array.isArray(t)){for(var h=0,o=Array(t.length);hi.ADAPTATION_LOWER_NODE_LIMIT&&(this.coolingFactor=Math.max(this.coolingFactor*i.COOLING_ADAPTATION_FACTOR,this.coolingFactor-(t-i.ADAPTATION_LOWER_NODE_LIMIT)/(i.ADAPTATION_UPPER_NODE_LIMIT-i.ADAPTATION_LOWER_NODE_LIMIT)*this.coolingFactor*(1-i.COOLING_ADAPTATION_FACTOR))),this.maxNodeDisplacement=i.MAX_NODE_DISPLACEMENT_INCREMENTAL):(t>i.ADAPTATION_LOWER_NODE_LIMIT?this.coolingFactor=Math.max(i.COOLING_ADAPTATION_FACTOR,1-(t-i.ADAPTATION_LOWER_NODE_LIMIT)/(i.ADAPTATION_UPPER_NODE_LIMIT-i.ADAPTATION_LOWER_NODE_LIMIT)*(1-i.COOLING_ADAPTATION_FACTOR)):this.coolingFactor=1,this.initialCoolingFactor=this.coolingFactor,this.maxNodeDisplacement=i.MAX_NODE_DISPLACEMENT),this.maxIterations=Math.max(this.getAllNodes().length*5,this.maxIterations),this.displacementThresholdPerNode=3*i.DEFAULT_EDGE_LENGTH/100,this.totalDisplacementThreshold=this.displacementThresholdPerNode*this.getAllNodes().length,this.repulsionRange=this.calcRepulsionRange()},a.prototype.calcSpringForces=function(){for(var t=this.getAllEdges(),h,o=0;o0&&arguments[0]!==void 0?arguments[0]:!0,h=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!1,o,c,l,T,u=this.getAllNodes(),d;if(this.useFRGridVariant)for(this.totalIterations%i.GRID_CALCULATION_CHECK_PERIOD==1&&t&&this.updateGrid(),d=new Set,o=0;oL||d>L)&&(t.gravitationForceX=-this.gravityConstant*l,t.gravitationForceY=-this.gravityConstant*T)):(L=h.getEstimatedSize()*this.compoundGravityRangeFactor,(u>L||d>L)&&(t.gravitationForceX=-this.gravityConstant*l*this.compoundGravityConstant,t.gravitationForceY=-this.gravityConstant*T*this.compoundGravityConstant))},a.prototype.isConverged=function(){var t,h=!1;return this.totalIterations>this.maxIterations/3&&(h=Math.abs(this.totalDisplacement-this.oldTotalDisplacement)<2),t=this.totalDisplacement=u.length||L>=u[0].length)){for(var F=0;Fa}}]),e}();A.exports=r},function(A,G,N){function g(){}g.svd=function(s){this.U=null,this.V=null,this.s=null,this.m=0,this.n=0,this.m=s.length,this.n=s[0].length;var i=Math.min(this.m,this.n);this.s=function(Nt){for(var Mt=[];Nt-- >0;)Mt.push(0);return Mt}(Math.min(this.m+1,this.n)),this.U=function(Nt){var Mt=function Zt(Gt){if(Gt.length==0)return 0;for(var $t=[],Ft=0;Ft0;)Mt.push(0);return Mt}(this.n),e=function(Nt){for(var Mt=[];Nt-- >0;)Mt.push(0);return Mt}(this.m),f=!0,a=Math.min(this.m-1,this.n),y=Math.max(0,Math.min(this.n-2,this.m)),t=0;t=0;E--)if(this.s[E]!==0){for(var p=E+1;p=0;W--){if(function(Nt,Mt){return Nt&&Mt}(W0;){var q=void 0,Rt=void 0;for(q=n-2;q>=-1&&q!==-1;q--)if(Math.abs(r[q])<=lt+_*(Math.abs(this.s[q])+Math.abs(this.s[q+1]))){r[q]=0;break}if(q===n-2)Rt=4;else{var Lt=void 0;for(Lt=n-1;Lt>=q&&Lt!==q;Lt--){var vt=(Lt!==n?Math.abs(r[Lt]):0)+(Lt!==q+1?Math.abs(r[Lt-1]):0);if(Math.abs(this.s[Lt])<=lt+_*vt){this.s[Lt]=0;break}}Lt===q?Rt=3:Lt===n-1?Rt=1:(Rt=2,q=Lt)}switch(q++,Rt){case 1:{var it=r[n-2];r[n-2]=0;for(var ut=n-2;ut>=q;ut--){var Tt=g.hypot(this.s[ut],it),At=this.s[ut]/Tt,Dt=it/Tt;this.s[ut]=Tt,ut!==q&&(it=-Dt*r[ut-1],r[ut-1]=At*r[ut-1]);for(var mt=0;mt=this.s[q+1]);){var Ct=this.s[q];if(this.s[q]=this.s[q+1],this.s[q+1]=Ct,qMath.abs(i)?(r=i/s,r=Math.abs(s)*Math.sqrt(1+r*r)):i!=0?(r=s/i,r=Math.abs(i)*Math.sqrt(1+r*r)):r=0,r},A.exports=g},function(A,G,N){var g=function(){function r(e,f){for(var a=0;a2&&arguments[2]!==void 0?arguments[2]:1,y=arguments.length>3&&arguments[3]!==void 0?arguments[3]:-1,t=arguments.length>4&&arguments[4]!==void 0?arguments[4]:-1;s(this,r),this.sequence1=e,this.sequence2=f,this.match_score=a,this.mismatch_penalty=y,this.gap_penalty=t,this.iMax=e.length+1,this.jMax=f.length+1,this.grid=new Array(this.iMax);for(var h=0;h=0;e--){var f=this.listeners[e];f.event===i&&f.callback===r&&this.listeners.splice(e,1)}},s.emit=function(i,r){for(var e=0;e{var G={45:(i,r,e)=>{var f={};f.layoutBase=e(551),f.CoSEConstants=e(806),f.CoSEEdge=e(767),f.CoSEGraph=e(880),f.CoSEGraphManager=e(578),f.CoSELayout=e(765),f.CoSENode=e(991),f.ConstraintHandler=e(902),i.exports=f},806:(i,r,e)=>{var f=e(551).FDLayoutConstants;function a(){}for(var y in f)a[y]=f[y];a.DEFAULT_USE_MULTI_LEVEL_SCALING=!1,a.DEFAULT_RADIAL_SEPARATION=f.DEFAULT_EDGE_LENGTH,a.DEFAULT_COMPONENT_SEPERATION=60,a.TILE=!0,a.TILING_PADDING_VERTICAL=10,a.TILING_PADDING_HORIZONTAL=10,a.TRANSFORM_ON_CONSTRAINT_HANDLING=!0,a.ENFORCE_CONSTRAINTS=!0,a.APPLY_LAYOUT=!0,a.RELAX_MOVEMENT_ON_CONSTRAINTS=!0,a.TREE_REDUCTION_ON_INCREMENTAL=!0,a.PURE_INCREMENTAL=a.DEFAULT_INCREMENTAL,i.exports=a},767:(i,r,e)=>{var f=e(551).FDLayoutEdge;function a(t,h,o){f.call(this,t,h,o)}a.prototype=Object.create(f.prototype);for(var y in f)a[y]=f[y];i.exports=a},880:(i,r,e)=>{var f=e(551).LGraph;function a(t,h,o){f.call(this,t,h,o)}a.prototype=Object.create(f.prototype);for(var y in f)a[y]=f[y];i.exports=a},578:(i,r,e)=>{var f=e(551).LGraphManager;function a(t){f.call(this,t)}a.prototype=Object.create(f.prototype);for(var y in f)a[y]=f[y];i.exports=a},765:(i,r,e)=>{var f=e(551).FDLayout,a=e(578),y=e(880),t=e(991),h=e(767),o=e(806),c=e(902),l=e(551).FDLayoutConstants,T=e(551).LayoutConstants,u=e(551).Point,d=e(551).PointD,L=e(551).DimensionD,F=e(551).Layout,M=e(551).Integer,P=e(551).IGeometry,J=e(551).LGraph,V=e(551).Transform,Q=e(551).LinkedList;function D(){f.call(this),this.toBeTiled={},this.constraints={}}D.prototype=Object.create(f.prototype);for(var rt in f)D[rt]=f[rt];D.prototype.newGraphManager=function(){var n=new a(this);return this.graphManager=n,n},D.prototype.newGraph=function(n){return new y(null,this.graphManager,n)},D.prototype.newNode=function(n){return new t(this.graphManager,n)},D.prototype.newEdge=function(n){return new h(null,null,n)},D.prototype.initParameters=function(){f.prototype.initParameters.call(this,arguments),this.isSubLayout||(o.DEFAULT_EDGE_LENGTH<10?this.idealEdgeLength=10:this.idealEdgeLength=o.DEFAULT_EDGE_LENGTH,this.useSmartIdealEdgeLengthCalculation=o.DEFAULT_USE_SMART_IDEAL_EDGE_LENGTH_CALCULATION,this.gravityConstant=l.DEFAULT_GRAVITY_STRENGTH,this.compoundGravityConstant=l.DEFAULT_COMPOUND_GRAVITY_STRENGTH,this.gravityRangeFactor=l.DEFAULT_GRAVITY_RANGE_FACTOR,this.compoundGravityRangeFactor=l.DEFAULT_COMPOUND_GRAVITY_RANGE_FACTOR,this.prunedNodesAll=[],this.growTreeIterations=0,this.afterGrowthIterations=0,this.isTreeGrowing=!1,this.isGrowthFinished=!1)},D.prototype.initSpringEmbedder=function(){f.prototype.initSpringEmbedder.call(this),this.coolingCycle=0,this.maxCoolingCycle=this.maxIterations/l.CONVERGENCE_CHECK_PERIOD,this.finalTemperature=.04,this.coolingAdjuster=1},D.prototype.layout=function(){var n=T.DEFAULT_CREATE_BENDS_AS_NEEDED;return n&&(this.createBendpoints(),this.graphManager.resetAllEdges()),this.level=0,this.classicLayout()},D.prototype.classicLayout=function(){if(this.nodesWithGravity=this.calculateNodesToApplyGravitationTo(),this.graphManager.setAllNodesToApplyGravitation(this.nodesWithGravity),this.calcNoOfChildrenForAllNodes(),this.graphManager.calcLowestCommonAncestors(),this.graphManager.calcInclusionTreeDepths(),this.graphManager.getRoot().calcEstimatedSize(),this.calcIdealEdgeLengths(),this.incremental){if(o.TREE_REDUCTION_ON_INCREMENTAL){this.reduceTrees(),this.graphManager.resetAllNodesToApplyGravitation();var m=new Set(this.getAllNodes()),v=this.nodesWithGravity.filter(function(I){return m.has(I)});this.graphManager.setAllNodesToApplyGravitation(v)}}else{var n=this.getFlatForest();if(n.length>0)this.positionNodesRadially(n);else{this.reduceTrees(),this.graphManager.resetAllNodesToApplyGravitation();var m=new Set(this.getAllNodes()),v=this.nodesWithGravity.filter(function(E){return m.has(E)});this.graphManager.setAllNodesToApplyGravitation(v),this.positionNodesRandomly()}}return Object.keys(this.constraints).length>0&&(c.handleConstraints(this),this.initConstraintVariables()),this.initSpringEmbedder(),o.APPLY_LAYOUT&&this.runSpringEmbedder(),!0},D.prototype.tick=function(){if(this.totalIterations++,this.totalIterations===this.maxIterations&&!this.isTreeGrowing&&!this.isGrowthFinished)if(this.prunedNodesAll.length>0)this.isTreeGrowing=!0;else return!0;if(this.totalIterations%l.CONVERGENCE_CHECK_PERIOD==0&&!this.isTreeGrowing&&!this.isGrowthFinished){if(this.isConverged())if(this.prunedNodesAll.length>0)this.isTreeGrowing=!0;else return!0;this.coolingCycle++,this.layoutQuality==0?this.coolingAdjuster=this.coolingCycle:this.layoutQuality==1&&(this.coolingAdjuster=this.coolingCycle/3),this.coolingFactor=Math.max(this.initialCoolingFactor-Math.pow(this.coolingCycle,Math.log(100*(this.initialCoolingFactor-this.finalTemperature))/Math.log(this.maxCoolingCycle))/100*this.coolingAdjuster,this.finalTemperature),this.animationPeriod=Math.ceil(this.initialAnimationPeriod*Math.sqrt(this.coolingFactor))}if(this.isTreeGrowing){if(this.growTreeIterations%10==0)if(this.prunedNodesAll.length>0){this.graphManager.updateBounds(),this.updateGrid(),this.growTree(this.prunedNodesAll),this.graphManager.resetAllNodesToApplyGravitation();var n=new Set(this.getAllNodes()),m=this.nodesWithGravity.filter(function(p){return n.has(p)});this.graphManager.setAllNodesToApplyGravitation(m),this.graphManager.updateBounds(),this.updateGrid(),o.PURE_INCREMENTAL?this.coolingFactor=l.DEFAULT_COOLING_FACTOR_INCREMENTAL/2:this.coolingFactor=l.DEFAULT_COOLING_FACTOR_INCREMENTAL}else this.isTreeGrowing=!1,this.isGrowthFinished=!0;this.growTreeIterations++}if(this.isGrowthFinished){if(this.isConverged())return!0;this.afterGrowthIterations%10==0&&(this.graphManager.updateBounds(),this.updateGrid()),o.PURE_INCREMENTAL?this.coolingFactor=l.DEFAULT_COOLING_FACTOR_INCREMENTAL/2*((100-this.afterGrowthIterations)/100):this.coolingFactor=l.DEFAULT_COOLING_FACTOR_INCREMENTAL*((100-this.afterGrowthIterations)/100),this.afterGrowthIterations++}var v=!this.isTreeGrowing&&!this.isGrowthFinished,E=this.growTreeIterations%10==1&&this.isTreeGrowing||this.afterGrowthIterations%10==1&&this.isGrowthFinished;return this.totalDisplacement=0,this.graphManager.updateBounds(),this.calcSpringForces(),this.calcRepulsionForces(v,E),this.calcGravitationalForces(),this.moveNodes(),this.animate(),!1},D.prototype.getPositionsData=function(){for(var n=this.graphManager.getAllNodes(),m={},v=0;v0&&this.updateDisplacements();for(var v=0;v0&&(E.fixedNodeWeight=I)}}if(this.constraints.relativePlacementConstraint){var w=new Map,R=new Map;if(this.dummyToNodeForVerticalAlignment=new Map,this.dummyToNodeForHorizontalAlignment=new Map,this.fixedNodesOnHorizontal=new Set,this.fixedNodesOnVertical=new Set,this.fixedNodeSet.forEach(function(O){n.fixedNodesOnHorizontal.add(O),n.fixedNodesOnVertical.add(O)}),this.constraints.alignmentConstraint){if(this.constraints.alignmentConstraint.vertical)for(var H=this.constraints.alignmentConstraint.vertical,v=0;v=2*O.length/3;_--)X=Math.floor(Math.random()*(_+1)),B=O[_],O[_]=O[X],O[X]=B;return O},this.nodesInRelativeHorizontal=[],this.nodesInRelativeVertical=[],this.nodeToRelativeConstraintMapHorizontal=new Map,this.nodeToRelativeConstraintMapVertical=new Map,this.nodeToTempPositionMapHorizontal=new Map,this.nodeToTempPositionMapVertical=new Map,this.constraints.relativePlacementConstraint.forEach(function(O){if(O.left){var X=w.has(O.left)?w.get(O.left):O.left,B=w.has(O.right)?w.get(O.right):O.right;n.nodesInRelativeHorizontal.includes(X)||(n.nodesInRelativeHorizontal.push(X),n.nodeToRelativeConstraintMapHorizontal.set(X,[]),n.dummyToNodeForVerticalAlignment.has(X)?n.nodeToTempPositionMapHorizontal.set(X,n.idToNodeMap.get(n.dummyToNodeForVerticalAlignment.get(X)[0]).getCenterX()):n.nodeToTempPositionMapHorizontal.set(X,n.idToNodeMap.get(X).getCenterX())),n.nodesInRelativeHorizontal.includes(B)||(n.nodesInRelativeHorizontal.push(B),n.nodeToRelativeConstraintMapHorizontal.set(B,[]),n.dummyToNodeForVerticalAlignment.has(B)?n.nodeToTempPositionMapHorizontal.set(B,n.idToNodeMap.get(n.dummyToNodeForVerticalAlignment.get(B)[0]).getCenterX()):n.nodeToTempPositionMapHorizontal.set(B,n.idToNodeMap.get(B).getCenterX())),n.nodeToRelativeConstraintMapHorizontal.get(X).push({right:B,gap:O.gap}),n.nodeToRelativeConstraintMapHorizontal.get(B).push({left:X,gap:O.gap})}else{var _=R.has(O.top)?R.get(O.top):O.top,lt=R.has(O.bottom)?R.get(O.bottom):O.bottom;n.nodesInRelativeVertical.includes(_)||(n.nodesInRelativeVertical.push(_),n.nodeToRelativeConstraintMapVertical.set(_,[]),n.dummyToNodeForHorizontalAlignment.has(_)?n.nodeToTempPositionMapVertical.set(_,n.idToNodeMap.get(n.dummyToNodeForHorizontalAlignment.get(_)[0]).getCenterY()):n.nodeToTempPositionMapVertical.set(_,n.idToNodeMap.get(_).getCenterY())),n.nodesInRelativeVertical.includes(lt)||(n.nodesInRelativeVertical.push(lt),n.nodeToRelativeConstraintMapVertical.set(lt,[]),n.dummyToNodeForHorizontalAlignment.has(lt)?n.nodeToTempPositionMapVertical.set(lt,n.idToNodeMap.get(n.dummyToNodeForHorizontalAlignment.get(lt)[0]).getCenterY()):n.nodeToTempPositionMapVertical.set(lt,n.idToNodeMap.get(lt).getCenterY())),n.nodeToRelativeConstraintMapVertical.get(_).push({bottom:lt,gap:O.gap}),n.nodeToRelativeConstraintMapVertical.get(lt).push({top:_,gap:O.gap})}});else{var k=new Map,W=new Map;this.constraints.relativePlacementConstraint.forEach(function(O){if(O.left){var X=w.has(O.left)?w.get(O.left):O.left,B=w.has(O.right)?w.get(O.right):O.right;k.has(X)?k.get(X).push(B):k.set(X,[B]),k.has(B)?k.get(B).push(X):k.set(B,[X])}else{var _=R.has(O.top)?R.get(O.top):O.top,lt=R.has(O.bottom)?R.get(O.bottom):O.bottom;W.has(_)?W.get(_).push(lt):W.set(_,[lt]),W.has(lt)?W.get(lt).push(_):W.set(lt,[_])}});var U=function(X,B){var _=[],lt=[],q=new Q,Rt=new Set,Lt=0;return X.forEach(function(vt,it){if(!Rt.has(it)){_[Lt]=[],lt[Lt]=!1;var ut=it;for(q.push(ut),Rt.add(ut),_[Lt].push(ut);q.length!=0;){ut=q.shift(),B.has(ut)&&(lt[Lt]=!0);var Tt=X.get(ut);Tt.forEach(function(At){Rt.has(At)||(q.push(At),Rt.add(At),_[Lt].push(At))})}Lt++}}),{components:_,isFixed:lt}},et=U(k,n.fixedNodesOnHorizontal);this.componentsOnHorizontal=et.components,this.fixedComponentsOnHorizontal=et.isFixed;var z=U(W,n.fixedNodesOnVertical);this.componentsOnVertical=z.components,this.fixedComponentsOnVertical=z.isFixed}}},D.prototype.updateDisplacements=function(){var n=this;if(this.constraints.fixedNodeConstraint&&this.constraints.fixedNodeConstraint.forEach(function(z){var O=n.idToNodeMap.get(z.nodeId);O.displacementX=0,O.displacementY=0}),this.constraints.alignmentConstraint){if(this.constraints.alignmentConstraint.vertical)for(var m=this.constraints.alignmentConstraint.vertical,v=0;v1){var R;for(R=0;RE&&(E=Math.floor(w.y)),I=Math.floor(w.x+o.DEFAULT_COMPONENT_SEPERATION)}this.transform(new d(T.WORLD_CENTER_X-w.x/2,T.WORLD_CENTER_Y-w.y/2))},D.radialLayout=function(n,m,v){var E=Math.max(this.maxDiagonalInTree(n),o.DEFAULT_RADIAL_SEPARATION);D.branchRadialLayout(m,null,0,359,0,E);var p=J.calculateBounds(n),I=new V;I.setDeviceOrgX(p.getMinX()),I.setDeviceOrgY(p.getMinY()),I.setWorldOrgX(v.x),I.setWorldOrgY(v.y);for(var w=0;w1;){var B=X[0];X.splice(0,1);var _=W.indexOf(B);_>=0&&W.splice(_,1),z--,U--}m!=null?O=(W.indexOf(X[0])+1)%z:O=0;for(var lt=Math.abs(E-v)/U,q=O;et!=U;q=++q%z){var Rt=W[q].getOtherEnd(n);if(Rt!=m){var Lt=(v+et*lt)%360,vt=(Lt+lt)%360;D.branchRadialLayout(Rt,n,Lt,vt,p+I,I),et++}}},D.maxDiagonalInTree=function(n){for(var m=M.MIN_VALUE,v=0;vm&&(m=p)}return m},D.prototype.calcRepulsionRange=function(){return 2*(this.level+1)*this.idealEdgeLength},D.prototype.groupZeroDegreeMembers=function(){var n=this,m={};this.memberGroups={},this.idToDummyNode={};for(var v=[],E=this.graphManager.getAllNodes(),p=0;p"u"&&(m[R]=[]),m[R]=m[R].concat(I)}Object.keys(m).forEach(function(H){if(m[H].length>1){var x="DummyCompound_"+H;n.memberGroups[x]=m[H];var k=m[H][0].getParent(),W=new t(n.graphManager);W.id=x,W.paddingLeft=k.paddingLeft||0,W.paddingRight=k.paddingRight||0,W.paddingBottom=k.paddingBottom||0,W.paddingTop=k.paddingTop||0,n.idToDummyNode[x]=W;var U=n.getGraphManager().add(n.newGraph(),W),et=k.getChild();et.add(W);for(var z=0;zp?(E.rect.x-=(E.labelWidth-p)/2,E.setWidth(E.labelWidth),E.labelMarginLeft=(E.labelWidth-p)/2):E.labelPosHorizontal=="right"&&E.setWidth(p+E.labelWidth)),E.labelHeight&&(E.labelPosVertical=="top"?(E.rect.y-=E.labelHeight,E.setHeight(I+E.labelHeight),E.labelMarginTop=E.labelHeight):E.labelPosVertical=="center"&&E.labelHeight>I?(E.rect.y-=(E.labelHeight-I)/2,E.setHeight(E.labelHeight),E.labelMarginTop=(E.labelHeight-I)/2):E.labelPosVertical=="bottom"&&E.setHeight(I+E.labelHeight))}})},D.prototype.repopulateCompounds=function(){for(var n=this.compoundOrder.length-1;n>=0;n--){var m=this.compoundOrder[n],v=m.id,E=m.paddingLeft,p=m.paddingTop,I=m.labelMarginLeft,w=m.labelMarginTop;this.adjustLocations(this.tiledMemberPack[v],m.rect.x,m.rect.y,E,p,I,w)}},D.prototype.repopulateZeroDegreeMembers=function(){var n=this,m=this.tiledZeroDegreePack;Object.keys(m).forEach(function(v){var E=n.idToDummyNode[v],p=E.paddingLeft,I=E.paddingTop,w=E.labelMarginLeft,R=E.labelMarginTop;n.adjustLocations(m[v],E.rect.x,E.rect.y,p,I,w,R)})},D.prototype.getToBeTiled=function(n){var m=n.id;if(this.toBeTiled[m]!=null)return this.toBeTiled[m];var v=n.getChild();if(v==null)return this.toBeTiled[m]=!1,!1;for(var E=v.getNodes(),p=0;p0)return this.toBeTiled[m]=!1,!1;if(I.getChild()==null){this.toBeTiled[I.id]=!1;continue}if(!this.getToBeTiled(I))return this.toBeTiled[m]=!1,!1}return this.toBeTiled[m]=!0,!0},D.prototype.getNodeDegree=function(n){n.id;for(var m=n.getEdges(),v=0,E=0;Ek&&(k=U.rect.height)}v+=k+n.verticalPadding}},D.prototype.tileCompoundMembers=function(n,m){var v=this;this.tiledMemberPack=[],Object.keys(n).forEach(function(E){var p=m[E];if(v.tiledMemberPack[E]=v.tileNodes(n[E],p.paddingLeft+p.paddingRight),p.rect.width=v.tiledMemberPack[E].width,p.rect.height=v.tiledMemberPack[E].height,p.setCenter(v.tiledMemberPack[E].centerX,v.tiledMemberPack[E].centerY),p.labelMarginLeft=0,p.labelMarginTop=0,o.NODE_DIMENSIONS_INCLUDE_LABELS){var I=p.rect.width,w=p.rect.height;p.labelWidth&&(p.labelPosHorizontal=="left"?(p.rect.x-=p.labelWidth,p.setWidth(I+p.labelWidth),p.labelMarginLeft=p.labelWidth):p.labelPosHorizontal=="center"&&p.labelWidth>I?(p.rect.x-=(p.labelWidth-I)/2,p.setWidth(p.labelWidth),p.labelMarginLeft=(p.labelWidth-I)/2):p.labelPosHorizontal=="right"&&p.setWidth(I+p.labelWidth)),p.labelHeight&&(p.labelPosVertical=="top"?(p.rect.y-=p.labelHeight,p.setHeight(w+p.labelHeight),p.labelMarginTop=p.labelHeight):p.labelPosVertical=="center"&&p.labelHeight>w?(p.rect.y-=(p.labelHeight-w)/2,p.setHeight(p.labelHeight),p.labelMarginTop=(p.labelHeight-w)/2):p.labelPosVertical=="bottom"&&p.setHeight(w+p.labelHeight))}})},D.prototype.tileNodes=function(n,m){var v=this.tileNodesByFavoringDim(n,m,!0),E=this.tileNodesByFavoringDim(n,m,!1),p=this.getOrgRatio(v),I=this.getOrgRatio(E),w;return IR&&(R=z.getWidth())});var H=I/p,x=w/p,k=Math.pow(v-E,2)+4*(H+E)*(x+v)*p,W=(E-v+Math.sqrt(k))/(2*(H+E)),U;m?(U=Math.ceil(W),U==W&&U++):U=Math.floor(W);var et=U*(H+E)-E;return R>et&&(et=R),et+=E*2,et},D.prototype.tileNodesByFavoringDim=function(n,m,v){var E=o.TILING_PADDING_VERTICAL,p=o.TILING_PADDING_HORIZONTAL,I=o.TILING_COMPARE_BY,w={rows:[],rowWidth:[],rowHeight:[],width:0,height:m,verticalPadding:E,horizontalPadding:p,centerX:0,centerY:0};I&&(w.idealRowWidth=this.calcIdealRowWidth(n,v));var R=function(O){return O.rect.width*O.rect.height},H=function(O,X){return R(X)-R(O)};n.sort(function(z,O){var X=H;return w.idealRowWidth?(X=I,X(z.id,O.id)):X(z,O)});for(var x=0,k=0,W=0;W0&&(w+=n.horizontalPadding),n.rowWidth[v]=w,n.width0&&(R+=n.verticalPadding);var H=0;R>n.rowHeight[v]&&(H=n.rowHeight[v],n.rowHeight[v]=R,H=n.rowHeight[v]-H),n.height+=H,n.rows[v].push(m)},D.prototype.getShortestRowIndex=function(n){for(var m=-1,v=Number.MAX_VALUE,E=0;Ev&&(m=E,v=n.rowWidth[E]);return m},D.prototype.canAddHorizontal=function(n,m,v){if(n.idealRowWidth){var E=n.rows.length-1,p=n.rowWidth[E];return p+m+n.horizontalPadding<=n.idealRowWidth}var I=this.getShortestRowIndex(n);if(I<0)return!0;var w=n.rowWidth[I];if(w+n.horizontalPadding+m<=n.width)return!0;var R=0;n.rowHeight[I]0&&(R=v+n.verticalPadding-n.rowHeight[I]);var H;n.width-w>=m+n.horizontalPadding?H=(n.height+R)/(w+m+n.horizontalPadding):H=(n.height+R)/n.width,R=v+n.verticalPadding;var x;return n.widthI&&m!=v){E.splice(-1,1),n.rows[v].push(p),n.rowWidth[m]=n.rowWidth[m]-I,n.rowWidth[v]=n.rowWidth[v]+I,n.width=n.rowWidth[instance.getLongestRowIndex(n)];for(var w=Number.MIN_VALUE,R=0;Rw&&(w=E[R].height);m>0&&(w+=n.verticalPadding);var H=n.rowHeight[m]+n.rowHeight[v];n.rowHeight[m]=w,n.rowHeight[v]0)for(var et=p;et<=I;et++)U[0]+=this.grid[et][w-1].length+this.grid[et][w].length-1;if(I0)for(var et=w;et<=R;et++)U[3]+=this.grid[p-1][et].length+this.grid[p][et].length-1;for(var z=M.MAX_VALUE,O,X,B=0;B{var f=e(551).FDLayoutNode,a=e(551).IMath;function y(h,o,c,l){f.call(this,h,o,c,l)}y.prototype=Object.create(f.prototype);for(var t in f)y[t]=f[t];y.prototype.calculateDisplacement=function(){var h=this.graphManager.getLayout();this.getChild()!=null&&this.fixedNodeWeight?(this.displacementX+=h.coolingFactor*(this.springForceX+this.repulsionForceX+this.gravitationForceX)/this.fixedNodeWeight,this.displacementY+=h.coolingFactor*(this.springForceY+this.repulsionForceY+this.gravitationForceY)/this.fixedNodeWeight):(this.displacementX+=h.coolingFactor*(this.springForceX+this.repulsionForceX+this.gravitationForceX)/this.noOfChildren,this.displacementY+=h.coolingFactor*(this.springForceY+this.repulsionForceY+this.gravitationForceY)/this.noOfChildren),Math.abs(this.displacementX)>h.coolingFactor*h.maxNodeDisplacement&&(this.displacementX=h.coolingFactor*h.maxNodeDisplacement*a.sign(this.displacementX)),Math.abs(this.displacementY)>h.coolingFactor*h.maxNodeDisplacement&&(this.displacementY=h.coolingFactor*h.maxNodeDisplacement*a.sign(this.displacementY)),this.child&&this.child.getNodes().length>0&&this.propogateDisplacementToChildren(this.displacementX,this.displacementY)},y.prototype.propogateDisplacementToChildren=function(h,o){for(var c=this.getChild().getNodes(),l,T=0;T{function f(c){if(Array.isArray(c)){for(var l=0,T=Array(c.length);l0){var Ct=0;st.forEach(function(ht){$=="horizontal"?(tt.set(ht,u.has(ht)?d[u.get(ht)]:Z.get(ht)),Ct+=tt.get(ht)):(tt.set(ht,u.has(ht)?L[u.get(ht)]:Z.get(ht)),Ct+=tt.get(ht))}),Ct=Ct/st.length,ft.forEach(function(ht){K.has(ht)||tt.set(ht,Ct)})}else{var ct=0;ft.forEach(function(ht){$=="horizontal"?ct+=u.has(ht)?d[u.get(ht)]:Z.get(ht):ct+=u.has(ht)?L[u.get(ht)]:Z.get(ht)}),ct=ct/ft.length,ft.forEach(function(ht){tt.set(ht,ct)})}});for(var wt=function(){var st=dt.shift(),Ct=b.get(st);Ct.forEach(function(ct){if(tt.get(ct.id)ht&&(ht=qt),_tWt&&(Wt=_t)}}catch(ie){Mt=!0,Zt=ie}finally{try{!Nt&&Gt.return&&Gt.return()}finally{if(Mt)throw Zt}}var ce=(Ct+ht)/2-(ct+Wt)/2,Kt=!0,te=!1,ee=void 0;try{for(var jt=ft[Symbol.iterator](),se;!(Kt=(se=jt.next()).done);Kt=!0){var re=se.value;tt.set(re,tt.get(re)+ce)}}catch(ie){te=!0,ee=ie}finally{try{!Kt&&jt.return&&jt.return()}finally{if(te)throw ee}}})}return tt},rt=function(b){var $=0,K=0,Z=0,at=0;if(b.forEach(function(j){j.left?d[u.get(j.left)]-d[u.get(j.right)]>=0?$++:K++:L[u.get(j.top)]-L[u.get(j.bottom)]>=0?Z++:at++}),$>K&&Z>at)for(var gt=0;gtK)for(var ot=0;otat)for(var tt=0;tt1)l.fixedNodeConstraint.forEach(function(S,b){E[b]=[S.position.x,S.position.y],p[b]=[d[u.get(S.nodeId)],L[u.get(S.nodeId)]]}),I=!0;else if(l.alignmentConstraint)(function(){var S=0;if(l.alignmentConstraint.vertical){for(var b=l.alignmentConstraint.vertical,$=function(tt){var j=new Set;b[tt].forEach(function(yt){j.add(yt)});var dt=new Set([].concat(f(j)).filter(function(yt){return R.has(yt)})),wt=void 0;dt.size>0?wt=d[u.get(dt.values().next().value)]:wt=Q(j).x,b[tt].forEach(function(yt){E[S]=[wt,L[u.get(yt)]],p[S]=[d[u.get(yt)],L[u.get(yt)]],S++})},K=0;K0?wt=d[u.get(dt.values().next().value)]:wt=Q(j).y,Z[tt].forEach(function(yt){E[S]=[d[u.get(yt)],wt],p[S]=[d[u.get(yt)],L[u.get(yt)]],S++})},gt=0;gtW&&(W=k[et].length,U=et);if(W0){var mt={x:0,y:0};l.fixedNodeConstraint.forEach(function(S,b){var $={x:d[u.get(S.nodeId)],y:L[u.get(S.nodeId)]},K=S.position,Z=V(K,$);mt.x+=Z.x,mt.y+=Z.y}),mt.x/=l.fixedNodeConstraint.length,mt.y/=l.fixedNodeConstraint.length,d.forEach(function(S,b){d[b]+=mt.x}),L.forEach(function(S,b){L[b]+=mt.y}),l.fixedNodeConstraint.forEach(function(S){d[u.get(S.nodeId)]=S.position.x,L[u.get(S.nodeId)]=S.position.y})}if(l.alignmentConstraint){if(l.alignmentConstraint.vertical)for(var xt=l.alignmentConstraint.vertical,St=function(b){var $=new Set;xt[b].forEach(function(at){$.add(at)});var K=new Set([].concat(f($)).filter(function(at){return R.has(at)})),Z=void 0;K.size>0?Z=d[u.get(K.values().next().value)]:Z=Q($).x,$.forEach(function(at){R.has(at)||(d[u.get(at)]=Z)})},Vt=0;Vt0?Z=L[u.get(K.values().next().value)]:Z=Q($).y,$.forEach(function(at){R.has(at)||(L[u.get(at)]=Z)})},bt=0;bt{i.exports=A}},N={};function g(i){var r=N[i];if(r!==void 0)return r.exports;var e=N[i]={exports:{}};return G[i](e,e.exports,g),e.exports}var s=g(45);return s})()})}(pe)),pe.exports}(function(C,Y){(function(G,N){C.exports=N(cr())})(Te,function(A){return(()=>{var G={658:i=>{i.exports=Object.assign!=null?Object.assign.bind(Object):function(r){for(var e=arguments.length,f=Array(e>1?e-1:0),a=1;a{var f=function(){function t(h,o){var c=[],l=!0,T=!1,u=void 0;try{for(var d=h[Symbol.iterator](),L;!(l=(L=d.next()).done)&&(c.push(L.value),!(o&&c.length===o));l=!0);}catch(F){T=!0,u=F}finally{try{!l&&d.return&&d.return()}finally{if(T)throw u}}return c}return function(h,o){if(Array.isArray(h))return h;if(Symbol.iterator in Object(h))return t(h,o);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),a=e(140).layoutBase.LinkedList,y={};y.getTopMostNodes=function(t){for(var h={},o=0;o0&&I.merge(x)});for(var w=0;w1){L=u[0],F=L.connectedEdges().length,u.forEach(function(p){p.connectedEdges().length0&&c.set("dummy"+(c.size+1),J),V},y.relocateComponent=function(t,h,o){if(!o.fixedNodeConstraint){var c=Number.POSITIVE_INFINITY,l=Number.NEGATIVE_INFINITY,T=Number.POSITIVE_INFINITY,u=Number.NEGATIVE_INFINITY;if(o.quality=="draft"){var d=!0,L=!1,F=void 0;try{for(var M=h.nodeIndexes[Symbol.iterator](),P;!(d=(P=M.next()).done);d=!0){var J=P.value,V=f(J,2),Q=V[0],D=V[1],rt=o.cy.getElementById(Q);if(rt){var n=rt.boundingBox(),m=h.xCoords[D]-n.w/2,v=h.xCoords[D]+n.w/2,E=h.yCoords[D]-n.h/2,p=h.yCoords[D]+n.h/2;ml&&(l=v),Eu&&(u=p)}}}catch(x){L=!0,F=x}finally{try{!d&&M.return&&M.return()}finally{if(L)throw F}}var I=t.x-(l+c)/2,w=t.y-(u+T)/2;h.xCoords=h.xCoords.map(function(x){return x+I}),h.yCoords=h.yCoords.map(function(x){return x+w})}else{Object.keys(h).forEach(function(x){var k=h[x],W=k.getRect().x,U=k.getRect().x+k.getRect().width,et=k.getRect().y,z=k.getRect().y+k.getRect().height;Wl&&(l=U),etu&&(u=z)});var R=t.x-(l+c)/2,H=t.y-(u+T)/2;Object.keys(h).forEach(function(x){var k=h[x];k.setCenter(k.getCenterX()+R,k.getCenterY()+H)})}}},y.calcBoundingBox=function(t,h,o,c){for(var l=Number.MAX_SAFE_INTEGER,T=Number.MIN_SAFE_INTEGER,u=Number.MAX_SAFE_INTEGER,d=Number.MIN_SAFE_INTEGER,L=void 0,F=void 0,M=void 0,P=void 0,J=t.descendants().not(":parent"),V=J.length,Q=0;QL&&(l=L),TM&&(u=M),d{var f=e(548),a=e(140).CoSELayout,y=e(140).CoSENode,t=e(140).layoutBase.PointD,h=e(140).layoutBase.DimensionD,o=e(140).layoutBase.LayoutConstants,c=e(140).layoutBase.FDLayoutConstants,l=e(140).CoSEConstants,T=function(d,L){var F=d.cy,M=d.eles,P=M.nodes(),J=M.edges(),V=void 0,Q=void 0,D=void 0,rt={};d.randomize&&(V=L.nodeIndexes,Q=L.xCoords,D=L.yCoords);var n=function(x){return typeof x=="function"},m=function(x,k){return n(x)?x(k):x},v=f.calcParentsWithoutChildren(F,M),E=function H(x,k,W,U){for(var et=k.length,z=0;z0){var q=void 0;q=W.getGraphManager().add(W.newGraph(),B),H(q,X,W,U)}}},p=function(x,k,W){for(var U=0,et=0,z=0;z0?l.DEFAULT_EDGE_LENGTH=c.DEFAULT_EDGE_LENGTH=U/et:n(d.idealEdgeLength)?l.DEFAULT_EDGE_LENGTH=c.DEFAULT_EDGE_LENGTH=50:l.DEFAULT_EDGE_LENGTH=c.DEFAULT_EDGE_LENGTH=d.idealEdgeLength,l.MIN_REPULSION_DIST=c.MIN_REPULSION_DIST=c.DEFAULT_EDGE_LENGTH/10,l.DEFAULT_RADIAL_SEPARATION=c.DEFAULT_EDGE_LENGTH)},I=function(x,k){k.fixedNodeConstraint&&(x.constraints.fixedNodeConstraint=k.fixedNodeConstraint),k.alignmentConstraint&&(x.constraints.alignmentConstraint=k.alignmentConstraint),k.relativePlacementConstraint&&(x.constraints.relativePlacementConstraint=k.relativePlacementConstraint)};d.nestingFactor!=null&&(l.PER_LEVEL_IDEAL_EDGE_LENGTH_FACTOR=c.PER_LEVEL_IDEAL_EDGE_LENGTH_FACTOR=d.nestingFactor),d.gravity!=null&&(l.DEFAULT_GRAVITY_STRENGTH=c.DEFAULT_GRAVITY_STRENGTH=d.gravity),d.numIter!=null&&(l.MAX_ITERATIONS=c.MAX_ITERATIONS=d.numIter),d.gravityRange!=null&&(l.DEFAULT_GRAVITY_RANGE_FACTOR=c.DEFAULT_GRAVITY_RANGE_FACTOR=d.gravityRange),d.gravityCompound!=null&&(l.DEFAULT_COMPOUND_GRAVITY_STRENGTH=c.DEFAULT_COMPOUND_GRAVITY_STRENGTH=d.gravityCompound),d.gravityRangeCompound!=null&&(l.DEFAULT_COMPOUND_GRAVITY_RANGE_FACTOR=c.DEFAULT_COMPOUND_GRAVITY_RANGE_FACTOR=d.gravityRangeCompound),d.initialEnergyOnIncremental!=null&&(l.DEFAULT_COOLING_FACTOR_INCREMENTAL=c.DEFAULT_COOLING_FACTOR_INCREMENTAL=d.initialEnergyOnIncremental),d.tilingCompareBy!=null&&(l.TILING_COMPARE_BY=d.tilingCompareBy),d.quality=="proof"?o.QUALITY=2:o.QUALITY=0,l.NODE_DIMENSIONS_INCLUDE_LABELS=c.NODE_DIMENSIONS_INCLUDE_LABELS=o.NODE_DIMENSIONS_INCLUDE_LABELS=d.nodeDimensionsIncludeLabels,l.DEFAULT_INCREMENTAL=c.DEFAULT_INCREMENTAL=o.DEFAULT_INCREMENTAL=!d.randomize,l.ANIMATE=c.ANIMATE=o.ANIMATE=d.animate,l.TILE=d.tile,l.TILING_PADDING_VERTICAL=typeof d.tilingPaddingVertical=="function"?d.tilingPaddingVertical.call():d.tilingPaddingVertical,l.TILING_PADDING_HORIZONTAL=typeof d.tilingPaddingHorizontal=="function"?d.tilingPaddingHorizontal.call():d.tilingPaddingHorizontal,l.DEFAULT_INCREMENTAL=c.DEFAULT_INCREMENTAL=o.DEFAULT_INCREMENTAL=!0,l.PURE_INCREMENTAL=!d.randomize,o.DEFAULT_UNIFORM_LEAF_NODE_SIZES=d.uniformNodeDimensions,d.step=="transformed"&&(l.TRANSFORM_ON_CONSTRAINT_HANDLING=!0,l.ENFORCE_CONSTRAINTS=!1,l.APPLY_LAYOUT=!1),d.step=="enforced"&&(l.TRANSFORM_ON_CONSTRAINT_HANDLING=!1,l.ENFORCE_CONSTRAINTS=!0,l.APPLY_LAYOUT=!1),d.step=="cose"&&(l.TRANSFORM_ON_CONSTRAINT_HANDLING=!1,l.ENFORCE_CONSTRAINTS=!1,l.APPLY_LAYOUT=!0),d.step=="all"&&(d.randomize?l.TRANSFORM_ON_CONSTRAINT_HANDLING=!0:l.TRANSFORM_ON_CONSTRAINT_HANDLING=!1,l.ENFORCE_CONSTRAINTS=!0,l.APPLY_LAYOUT=!0),d.fixedNodeConstraint||d.alignmentConstraint||d.relativePlacementConstraint?l.TREE_REDUCTION_ON_INCREMENTAL=!1:l.TREE_REDUCTION_ON_INCREMENTAL=!0;var w=new a,R=w.newGraphManager();return E(R.addRoot(),f.getTopMostNodes(P),w,d),p(w,R,J),I(w,d),w.runLayout(),rt};i.exports={coseLayout:T}},212:(i,r,e)=>{var f=function(){function d(L,F){for(var M=0;M0)if(v){var I=t.getTopMostNodes(M.eles.nodes());if(D=t.connectComponents(P,M.eles,I),D.forEach(function(vt){var it=vt.boundingBox();rt.push({x:it.x1+it.w/2,y:it.y1+it.h/2})}),M.randomize&&D.forEach(function(vt){M.eles=vt,V.push(o(M))}),M.quality=="default"||M.quality=="proof"){var w=P.collection();if(M.tile){var R=new Map,H=[],x=[],k=0,W={nodeIndexes:R,xCoords:H,yCoords:x},U=[];if(D.forEach(function(vt,it){vt.edges().length==0&&(vt.nodes().forEach(function(ut,Tt){w.merge(vt.nodes()[Tt]),ut.isParent()||(W.nodeIndexes.set(vt.nodes()[Tt].id(),k++),W.xCoords.push(vt.nodes()[0].position().x),W.yCoords.push(vt.nodes()[0].position().y))}),U.push(it))}),w.length>1){var et=w.boundingBox();rt.push({x:et.x1+et.w/2,y:et.y1+et.h/2}),D.push(w),V.push(W);for(var z=U.length-1;z>=0;z--)D.splice(U[z],1),V.splice(U[z],1),rt.splice(U[z],1)}}D.forEach(function(vt,it){M.eles=vt,Q.push(l(M,V[it])),t.relocateComponent(rt[it],Q[it],M)})}else D.forEach(function(vt,it){t.relocateComponent(rt[it],V[it],M)});var O=new Set;if(D.length>1){var X=[],B=J.filter(function(vt){return vt.css("display")=="none"});D.forEach(function(vt,it){var ut=void 0;if(M.quality=="draft"&&(ut=V[it].nodeIndexes),vt.nodes().not(B).length>0){var Tt={};Tt.edges=[],Tt.nodes=[];var At=void 0;vt.nodes().not(B).forEach(function(Dt){if(M.quality=="draft")if(!Dt.isParent())At=ut.get(Dt.id()),Tt.nodes.push({x:V[it].xCoords[At]-Dt.boundingbox().w/2,y:V[it].yCoords[At]-Dt.boundingbox().h/2,width:Dt.boundingbox().w,height:Dt.boundingbox().h});else{var mt=t.calcBoundingBox(Dt,V[it].xCoords,V[it].yCoords,ut);Tt.nodes.push({x:mt.topLeftX,y:mt.topLeftY,width:mt.width,height:mt.height})}else Q[it][Dt.id()]&&Tt.nodes.push({x:Q[it][Dt.id()].getLeft(),y:Q[it][Dt.id()].getTop(),width:Q[it][Dt.id()].getWidth(),height:Q[it][Dt.id()].getHeight()})}),vt.edges().forEach(function(Dt){var mt=Dt.source(),xt=Dt.target();if(mt.css("display")!="none"&&xt.css("display")!="none")if(M.quality=="draft"){var St=ut.get(mt.id()),Vt=ut.get(xt.id()),Xt=[],Ut=[];if(mt.isParent()){var bt=t.calcBoundingBox(mt,V[it].xCoords,V[it].yCoords,ut);Xt.push(bt.topLeftX+bt.width/2),Xt.push(bt.topLeftY+bt.height/2)}else Xt.push(V[it].xCoords[St]),Xt.push(V[it].yCoords[St]);if(xt.isParent()){var Ht=t.calcBoundingBox(xt,V[it].xCoords,V[it].yCoords,ut);Ut.push(Ht.topLeftX+Ht.width/2),Ut.push(Ht.topLeftY+Ht.height/2)}else Ut.push(V[it].xCoords[Vt]),Ut.push(V[it].yCoords[Vt]);Tt.edges.push({startX:Xt[0],startY:Xt[1],endX:Ut[0],endY:Ut[1]})}else Q[it][mt.id()]&&Q[it][xt.id()]&&Tt.edges.push({startX:Q[it][mt.id()].getCenterX(),startY:Q[it][mt.id()].getCenterY(),endX:Q[it][xt.id()].getCenterX(),endY:Q[it][xt.id()].getCenterY()})}),Tt.nodes.length>0&&(X.push(Tt),O.add(it))}});var _=m.packComponents(X,M.randomize).shifts;if(M.quality=="draft")V.forEach(function(vt,it){var ut=vt.xCoords.map(function(At){return At+_[it].dx}),Tt=vt.yCoords.map(function(At){return At+_[it].dy});vt.xCoords=ut,vt.yCoords=Tt});else{var lt=0;O.forEach(function(vt){Object.keys(Q[vt]).forEach(function(it){var ut=Q[vt][it];ut.setCenter(ut.getCenterX()+_[lt].dx,ut.getCenterY()+_[lt].dy)}),lt++})}}}else{var E=M.eles.boundingBox();if(rt.push({x:E.x1+E.w/2,y:E.y1+E.h/2}),M.randomize){var p=o(M);V.push(p)}M.quality=="default"||M.quality=="proof"?(Q.push(l(M,V[0])),t.relocateComponent(rt[0],Q[0],M)):t.relocateComponent(rt[0],V[0],M)}var q=function(it,ut){if(M.quality=="default"||M.quality=="proof"){typeof it=="number"&&(it=ut);var Tt=void 0,At=void 0,Dt=it.data("id");return Q.forEach(function(xt){Dt in xt&&(Tt={x:xt[Dt].getRect().getCenterX(),y:xt[Dt].getRect().getCenterY()},At=xt[Dt])}),M.nodeDimensionsIncludeLabels&&(At.labelWidth&&(At.labelPosHorizontal=="left"?Tt.x+=At.labelWidth/2:At.labelPosHorizontal=="right"&&(Tt.x-=At.labelWidth/2)),At.labelHeight&&(At.labelPosVertical=="top"?Tt.y+=At.labelHeight/2:At.labelPosVertical=="bottom"&&(Tt.y-=At.labelHeight/2))),Tt==null&&(Tt={x:it.position("x"),y:it.position("y")}),{x:Tt.x,y:Tt.y}}else{var mt=void 0;return V.forEach(function(xt){var St=xt.nodeIndexes.get(it.id());St!=null&&(mt={x:xt.xCoords[St],y:xt.yCoords[St]})}),mt==null&&(mt={x:it.position("x"),y:it.position("y")}),{x:mt.x,y:mt.y}}};if(M.quality=="default"||M.quality=="proof"||M.randomize){var Rt=t.calcParentsWithoutChildren(P,J),Lt=J.filter(function(vt){return vt.css("display")=="none"});M.eles=J.not(Lt),J.nodes().not(":parent").not(Lt).layoutPositions(F,M,q),Rt.length>0&&Rt.forEach(function(vt){vt.position(q(vt))})}else console.log("If randomize option is set to false, then quality option must be 'default' or 'proof'.")}}]),d}();i.exports=u},657:(i,r,e)=>{var f=e(548),a=e(140).layoutBase.Matrix,y=e(140).layoutBase.SVD,t=function(o){var c=o.cy,l=o.eles,T=l.nodes(),u=l.nodes(":parent"),d=new Map,L=new Map,F=new Map,M=[],P=[],J=[],V=[],Q=[],D=[],rt=[],n=[],m=void 0,v=1e8,E=1e-9,p=o.piTol,I=o.samplingType,w=o.nodeSeparation,R=void 0,H=function(){for(var b=0,$=0,K=!1;$=at;){ot=Z[at++];for(var It=M[ot],ft=0;ftdt&&(dt=Q[Ct],wt=Ct)}return wt},k=function(b){var $=void 0;if(b){$=Math.floor(Math.random()*m);for(var Z=0;Z=1)break;j=tt}for(var yt=0;yt=1)break;j=tt}for(var ft=0;ft0&&($.isParent()?M[b].push(F.get($.id())):M[b].push($.id()))})});var Lt=function(b){var $=L.get(b),K=void 0;d.get(b).forEach(function(Z){c.getElementById(Z).isParent()?K=F.get(Z):K=Z,M[$].push(K),M[L.get(K)].push(b)})},vt=!0,it=!1,ut=void 0;try{for(var Tt=d.keys()[Symbol.iterator](),At;!(vt=(At=Tt.next()).done);vt=!0){var Dt=At.value;Lt(Dt)}}catch(S){it=!0,ut=S}finally{try{!vt&&Tt.return&&Tt.return()}finally{if(it)throw ut}}m=L.size;var mt=void 0;if(m>2){R=m{var f=e(212),a=function(t){t&&t("layout","fcose",f)};typeof cytoscape<"u"&&a(cytoscape),i.exports=a},140:i=>{i.exports=A}},N={};function g(i){var r=N[i];if(r!==void 0)return r.exports;var e=N[i]={exports:{}};return G[i](e,e.exports,g),e.exports}var s=g(579);return s})()})})(be);var gr=be.exports;const ur=ke(gr);var xe={L:"left",R:"right",T:"top",B:"bottom"},Ie={L:nt(C=>`${C},${C/2} 0,${C} 0,0`,"L"),R:nt(C=>`0,${C/2} ${C},0 ${C},${C}`,"R"),T:nt(C=>`0,0 ${C},0 ${C/2},${C}`,"T"),B:nt(C=>`${C/2},0 ${C},${C} 0,${C}`,"B")},he={L:nt((C,Y)=>C-Y+2,"L"),R:nt((C,Y)=>C-2,"R"),T:nt((C,Y)=>C-Y+2,"T"),B:nt((C,Y)=>C-2,"B")},dr=nt(function(C){return zt(C)?C==="L"?"R":"L":C==="T"?"B":"T"},"getOppositeArchitectureDirection"),Re=nt(function(C){const Y=C;return Y==="L"||Y==="R"||Y==="T"||Y==="B"},"isArchitectureDirection"),zt=nt(function(C){const Y=C;return Y==="L"||Y==="R"},"isArchitectureDirectionX"),Qt=nt(function(C){const Y=C;return Y==="T"||Y==="B"},"isArchitectureDirectionY"),Pe=nt(function(C,Y){const A=zt(C)&&Qt(Y),G=Qt(C)&&zt(Y);return A||G},"isArchitectureDirectionXY"),vr=nt(function(C){const Y=C[0],A=C[1],G=zt(Y)&&Qt(A),N=Qt(Y)&&zt(A);return G||N},"isArchitecturePairXY"),pr=nt(function(C){return C!=="LL"&&C!=="RR"&&C!=="TT"&&C!=="BB"},"isValidArchitectureDirectionPair"),me=nt(function(C,Y){const A=`${C}${Y}`;return pr(A)?A:void 0},"getArchitectureDirectionPair"),yr=nt(function([C,Y],A){const G=A[0],N=A[1];return zt(G)?Qt(N)?[C+(G==="L"?-1:1),Y+(N==="T"?1:-1)]:[C+(G==="L"?-1:1),Y]:zt(N)?[C+(N==="L"?1:-1),Y+(G==="T"?1:-1)]:[C,Y+(G==="T"?1:-1)]},"shiftPositionByArchitectureDirectionPair"),Er=nt(function(C){return C==="LT"||C==="TL"?[1,1]:C==="BL"||C==="LB"?[1,-1]:C==="BR"||C==="RB"?[-1,-1]:[-1,1]},"getArchitectureDirectionXYFactors"),mr=nt(function(C){return C.type==="service"},"isArchitectureService"),Tr=nt(function(C){return C.type==="junction"},"isArchitectureJunction"),Ge=nt(C=>C.data(),"edgeData"),ne=nt(C=>C.data(),"nodeData"),Ue=qe.architecture,pt=new hr(()=>({nodes:{},groups:{},edges:[],registeredIds:{},config:Ue,dataStructures:void 0,elements:{}})),Nr=nt(()=>{pt.reset(),ar()},"clear"),Lr=nt(function({id:C,icon:Y,in:A,title:G,iconText:N}){if(pt.records.registeredIds[C]!==void 0)throw new Error(`The service id [${C}] is already in use by another ${pt.records.registeredIds[C]}`);if(A!==void 0){if(C===A)throw new Error(`The service [${C}] cannot be placed within itself`);if(pt.records.registeredIds[A]===void 0)throw new Error(`The service [${C}]'s parent does not exist. Please make sure the parent is created before this service`);if(pt.records.registeredIds[A]==="node")throw new Error(`The service [${C}]'s parent is not a group`)}pt.records.registeredIds[C]="node",pt.records.nodes[C]={id:C,type:"service",icon:Y,iconText:N,title:G,edges:[],in:A}},"addService"),Cr=nt(()=>Object.values(pt.records.nodes).filter(mr),"getServices"),Mr=nt(function({id:C,in:Y}){pt.records.registeredIds[C]="node",pt.records.nodes[C]={id:C,type:"junction",edges:[],in:Y}},"addJunction"),Ar=nt(()=>Object.values(pt.records.nodes).filter(Tr),"getJunctions"),wr=nt(()=>Object.values(pt.records.nodes),"getNodes"),Or=nt(C=>pt.records.nodes[C],"getNode"),Dr=nt(function({id:C,icon:Y,in:A,title:G}){if(pt.records.registeredIds[C]!==void 0)throw new Error(`The group id [${C}] is already in use by another ${pt.records.registeredIds[C]}`);if(A!==void 0){if(C===A)throw new Error(`The group [${C}] cannot be placed within itself`);if(pt.records.registeredIds[A]===void 0)throw new Error(`The group [${C}]'s parent does not exist. Please make sure the parent is created before this group`);if(pt.records.registeredIds[A]==="node")throw new Error(`The group [${C}]'s parent is not a group`)}pt.records.registeredIds[C]="group",pt.records.groups[C]={id:C,icon:Y,title:G,in:A}},"addGroup"),xr=nt(()=>Object.values(pt.records.groups),"getGroups"),Ir=nt(function({lhsId:C,rhsId:Y,lhsDir:A,rhsDir:G,lhsInto:N,rhsInto:g,lhsGroup:s,rhsGroup:i,title:r}){if(!Re(A))throw new Error(`Invalid direction given for left hand side of edge ${C}--${Y}. Expected (L,R,T,B) got ${A}`);if(!Re(G))throw new Error(`Invalid direction given for right hand side of edge ${C}--${Y}. Expected (L,R,T,B) got ${G}`);if(pt.records.nodes[C]===void 0&&pt.records.groups[C]===void 0)throw new Error(`The left-hand id [${C}] does not yet exist. Please create the service/group before declaring an edge to it.`);if(pt.records.nodes[Y]===void 0&&pt.records.groups[C]===void 0)throw new Error(`The right-hand id [${Y}] does not yet exist. Please create the service/group before declaring an edge to it.`);const e=pt.records.nodes[C].in,f=pt.records.nodes[Y].in;if(s&&e&&f&&e==f)throw new Error(`The left-hand id [${C}] is modified to traverse the group boundary, but the edge does not pass through two groups.`);if(i&&e&&f&&e==f)throw new Error(`The right-hand id [${Y}] is modified to traverse the group boundary, but the edge does not pass through two groups.`);const a={lhsId:C,lhsDir:A,lhsInto:N,lhsGroup:s,rhsId:Y,rhsDir:G,rhsInto:g,rhsGroup:i,title:r};pt.records.edges.push(a),pt.records.nodes[C]&&pt.records.nodes[Y]&&(pt.records.nodes[C].edges.push(pt.records.edges[pt.records.edges.length-1]),pt.records.nodes[Y].edges.push(pt.records.edges[pt.records.edges.length-1]))},"addEdge"),Rr=nt(()=>pt.records.edges,"getEdges"),Sr=nt(()=>{if(pt.records.dataStructures===void 0){const C=Object.entries(pt.records.nodes).reduce((s,[i,r])=>(s[i]=r.edges.reduce((e,f)=>{if(f.lhsId===i){const a=me(f.lhsDir,f.rhsDir);a&&(e[a]=f.rhsId)}else{const a=me(f.rhsDir,f.lhsDir);a&&(e[a]=f.lhsId)}return e},{}),s),{}),Y=Object.keys(C)[0],A={[Y]:1},G=Object.keys(C).reduce((s,i)=>i===Y?s:{...s,[i]:1},{}),N=nt(s=>{const i={[s]:[0,0]},r=[s];for(;r.length>0;){const e=r.shift();if(e){A[e]=1,delete G[e];const f=C[e],[a,y]=i[e];Object.entries(f).forEach(([t,h])=>{A[h]||(i[h]=yr([a,y],t),r.push(h))})}}return i},"BFS"),g=[N(Y)];for(;Object.keys(G).length>0;)g.push(N(Object.keys(G)[0]));pt.records.dataStructures={adjList:C,spatialMaps:g}}return pt.records.dataStructures},"getDataStructures"),Fr=nt((C,Y)=>{pt.records.elements[C]=Y},"setElementForId"),br=nt(C=>pt.records.elements[C],"getElementById"),le={clear:Nr,setDiagramTitle:Ke,getDiagramTitle:je,setAccTitle:_e,getAccTitle:tr,setAccDescription:er,getAccDescription:rr,addService:Lr,getServices:Cr,addJunction:Mr,getJunctions:Ar,getNodes:wr,getNode:Or,addGroup:Dr,getGroups:xr,addEdge:Ir,getEdges:Rr,setElementForId:Fr,getElementById:br,getDataStructures:Sr};function Pt(C){const Y=fe().architecture;return Y!=null&&Y[C]?Y[C]:Ue[C]}nt(Pt,"getConfigField");var Pr=nt((C,Y)=>{sr(C,Y),C.groups.map(Y.addGroup),C.services.map(A=>Y.addService({...A,type:"service"})),C.junctions.map(A=>Y.addJunction({...A,type:"junction"})),C.edges.map(Y.addEdge)},"populateDb"),Gr={parse:nt(async C=>{const Y=await lr("architecture",C);Se.debug(Y),Pr(Y,le)},"parse")},Ur=nt(C=>` +import{aF as Te,aG as ke,F as qe,_ as nt,aH as Je,aI as Qe,q as Ke,r as je,s as _e,g as tr,c as er,b as rr,d as fe,l as Se,j as ir,t as ar,K as nr,aa as or,D as Ne,aJ as Ee}from"./mermaid.core-VsNG6kTl.js";import{p as sr}from"./chunk-OQCM5LHU-Cbp36FHa.js";import{I as hr}from"./chunk-2RYQ3QTB-8PgX7ysJ.js";import{p as lr}from"./gitGraph-YCYPL57B-CW0sFWI7.js";import{c as Fe}from"./cytoscape.esm-DjcA8a8N.js";import"./app-Dp4t6tDQ.js";import"./baseUniq-Bpwj4IW2.js";import"./basePickBy-BMIT5f2S.js";import"./clone-CyxiHGLh.js";var be={exports:{}},pe={exports:{}},ye={exports:{}},Oe;function fr(){return Oe||(Oe=1,function(C,Y){(function(G,N){C.exports=N()})(Te,function(){return function(A){var G={};function N(g){if(G[g])return G[g].exports;var s=G[g]={i:g,l:!1,exports:{}};return A[g].call(s.exports,s,s.exports,N),s.l=!0,s.exports}return N.m=A,N.c=G,N.i=function(g){return g},N.d=function(g,s,i){N.o(g,s)||Object.defineProperty(g,s,{configurable:!1,enumerable:!0,get:i})},N.n=function(g){var s=g&&g.__esModule?function(){return g.default}:function(){return g};return N.d(s,"a",s),s},N.o=function(g,s){return Object.prototype.hasOwnProperty.call(g,s)},N.p="",N(N.s=28)}([function(A,G,N){function g(){}g.QUALITY=1,g.DEFAULT_CREATE_BENDS_AS_NEEDED=!1,g.DEFAULT_INCREMENTAL=!1,g.DEFAULT_ANIMATION_ON_LAYOUT=!0,g.DEFAULT_ANIMATION_DURING_LAYOUT=!1,g.DEFAULT_ANIMATION_PERIOD=50,g.DEFAULT_UNIFORM_LEAF_NODE_SIZES=!1,g.DEFAULT_GRAPH_MARGIN=15,g.NODE_DIMENSIONS_INCLUDE_LABELS=!1,g.SIMPLE_NODE_SIZE=40,g.SIMPLE_NODE_HALF_SIZE=g.SIMPLE_NODE_SIZE/2,g.EMPTY_COMPOUND_NODE_SIZE=40,g.MIN_EDGE_LENGTH=1,g.WORLD_BOUNDARY=1e6,g.INITIAL_WORLD_BOUNDARY=g.WORLD_BOUNDARY/1e3,g.WORLD_CENTER_X=1200,g.WORLD_CENTER_Y=900,A.exports=g},function(A,G,N){var g=N(2),s=N(8),i=N(9);function r(f,a,y){g.call(this,y),this.isOverlapingSourceAndTarget=!1,this.vGraphObject=y,this.bendpoints=[],this.source=f,this.target=a}r.prototype=Object.create(g.prototype);for(var e in g)r[e]=g[e];r.prototype.getSource=function(){return this.source},r.prototype.getTarget=function(){return this.target},r.prototype.isInterGraph=function(){return this.isInterGraph},r.prototype.getLength=function(){return this.length},r.prototype.isOverlapingSourceAndTarget=function(){return this.isOverlapingSourceAndTarget},r.prototype.getBendpoints=function(){return this.bendpoints},r.prototype.getLca=function(){return this.lca},r.prototype.getSourceInLca=function(){return this.sourceInLca},r.prototype.getTargetInLca=function(){return this.targetInLca},r.prototype.getOtherEnd=function(f){if(this.source===f)return this.target;if(this.target===f)return this.source;throw"Node is not incident with this edge"},r.prototype.getOtherEndInGraph=function(f,a){for(var y=this.getOtherEnd(f),t=a.getGraphManager().getRoot();;){if(y.getOwner()==a)return y;if(y.getOwner()==t)break;y=y.getOwner().getParent()}return null},r.prototype.updateLength=function(){var f=new Array(4);this.isOverlapingSourceAndTarget=s.getIntersection(this.target.getRect(),this.source.getRect(),f),this.isOverlapingSourceAndTarget||(this.lengthX=f[0]-f[2],this.lengthY=f[1]-f[3],Math.abs(this.lengthX)<1&&(this.lengthX=i.sign(this.lengthX)),Math.abs(this.lengthY)<1&&(this.lengthY=i.sign(this.lengthY)),this.length=Math.sqrt(this.lengthX*this.lengthX+this.lengthY*this.lengthY))},r.prototype.updateLengthSimple=function(){this.lengthX=this.target.getCenterX()-this.source.getCenterX(),this.lengthY=this.target.getCenterY()-this.source.getCenterY(),Math.abs(this.lengthX)<1&&(this.lengthX=i.sign(this.lengthX)),Math.abs(this.lengthY)<1&&(this.lengthY=i.sign(this.lengthY)),this.length=Math.sqrt(this.lengthX*this.lengthX+this.lengthY*this.lengthY)},A.exports=r},function(A,G,N){function g(s){this.vGraphObject=s}A.exports=g},function(A,G,N){var g=N(2),s=N(10),i=N(13),r=N(0),e=N(16),f=N(5);function a(t,h,o,c){o==null&&c==null&&(c=h),g.call(this,c),t.graphManager!=null&&(t=t.graphManager),this.estimatedSize=s.MIN_VALUE,this.inclusionTreeDepth=s.MAX_VALUE,this.vGraphObject=c,this.edges=[],this.graphManager=t,o!=null&&h!=null?this.rect=new i(h.x,h.y,o.width,o.height):this.rect=new i}a.prototype=Object.create(g.prototype);for(var y in g)a[y]=g[y];a.prototype.getEdges=function(){return this.edges},a.prototype.getChild=function(){return this.child},a.prototype.getOwner=function(){return this.owner},a.prototype.getWidth=function(){return this.rect.width},a.prototype.setWidth=function(t){this.rect.width=t},a.prototype.getHeight=function(){return this.rect.height},a.prototype.setHeight=function(t){this.rect.height=t},a.prototype.getCenterX=function(){return this.rect.x+this.rect.width/2},a.prototype.getCenterY=function(){return this.rect.y+this.rect.height/2},a.prototype.getCenter=function(){return new f(this.rect.x+this.rect.width/2,this.rect.y+this.rect.height/2)},a.prototype.getLocation=function(){return new f(this.rect.x,this.rect.y)},a.prototype.getRect=function(){return this.rect},a.prototype.getDiagonal=function(){return Math.sqrt(this.rect.width*this.rect.width+this.rect.height*this.rect.height)},a.prototype.getHalfTheDiagonal=function(){return Math.sqrt(this.rect.height*this.rect.height+this.rect.width*this.rect.width)/2},a.prototype.setRect=function(t,h){this.rect.x=t.x,this.rect.y=t.y,this.rect.width=h.width,this.rect.height=h.height},a.prototype.setCenter=function(t,h){this.rect.x=t-this.rect.width/2,this.rect.y=h-this.rect.height/2},a.prototype.setLocation=function(t,h){this.rect.x=t,this.rect.y=h},a.prototype.moveBy=function(t,h){this.rect.x+=t,this.rect.y+=h},a.prototype.getEdgeListToNode=function(t){var h=[],o=this;return o.edges.forEach(function(c){if(c.target==t){if(c.source!=o)throw"Incorrect edge source!";h.push(c)}}),h},a.prototype.getEdgesBetween=function(t){var h=[],o=this;return o.edges.forEach(function(c){if(!(c.source==o||c.target==o))throw"Incorrect edge source and/or target";(c.target==t||c.source==t)&&h.push(c)}),h},a.prototype.getNeighborsList=function(){var t=new Set,h=this;return h.edges.forEach(function(o){if(o.source==h)t.add(o.target);else{if(o.target!=h)throw"Incorrect incidency!";t.add(o.source)}}),t},a.prototype.withChildren=function(){var t=new Set,h,o;if(t.add(this),this.child!=null)for(var c=this.child.getNodes(),l=0;lh?(this.rect.x-=(this.labelWidth-h)/2,this.setWidth(this.labelWidth)):this.labelPosHorizontal=="right"&&this.setWidth(h+this.labelWidth)),this.labelHeight&&(this.labelPosVertical=="top"?(this.rect.y-=this.labelHeight,this.setHeight(o+this.labelHeight)):this.labelPosVertical=="center"&&this.labelHeight>o?(this.rect.y-=(this.labelHeight-o)/2,this.setHeight(this.labelHeight)):this.labelPosVertical=="bottom"&&this.setHeight(o+this.labelHeight))}}},a.prototype.getInclusionTreeDepth=function(){if(this.inclusionTreeDepth==s.MAX_VALUE)throw"assert failed";return this.inclusionTreeDepth},a.prototype.transform=function(t){var h=this.rect.x;h>r.WORLD_BOUNDARY?h=r.WORLD_BOUNDARY:h<-r.WORLD_BOUNDARY&&(h=-r.WORLD_BOUNDARY);var o=this.rect.y;o>r.WORLD_BOUNDARY?o=r.WORLD_BOUNDARY:o<-r.WORLD_BOUNDARY&&(o=-r.WORLD_BOUNDARY);var c=new f(h,o),l=t.inverseTransformPoint(c);this.setLocation(l.x,l.y)},a.prototype.getLeft=function(){return this.rect.x},a.prototype.getRight=function(){return this.rect.x+this.rect.width},a.prototype.getTop=function(){return this.rect.y},a.prototype.getBottom=function(){return this.rect.y+this.rect.height},a.prototype.getParent=function(){return this.owner==null?null:this.owner.getParent()},A.exports=a},function(A,G,N){var g=N(0);function s(){}for(var i in g)s[i]=g[i];s.MAX_ITERATIONS=2500,s.DEFAULT_EDGE_LENGTH=50,s.DEFAULT_SPRING_STRENGTH=.45,s.DEFAULT_REPULSION_STRENGTH=4500,s.DEFAULT_GRAVITY_STRENGTH=.4,s.DEFAULT_COMPOUND_GRAVITY_STRENGTH=1,s.DEFAULT_GRAVITY_RANGE_FACTOR=3.8,s.DEFAULT_COMPOUND_GRAVITY_RANGE_FACTOR=1.5,s.DEFAULT_USE_SMART_IDEAL_EDGE_LENGTH_CALCULATION=!0,s.DEFAULT_USE_SMART_REPULSION_RANGE_CALCULATION=!0,s.DEFAULT_COOLING_FACTOR_INCREMENTAL=.3,s.COOLING_ADAPTATION_FACTOR=.33,s.ADAPTATION_LOWER_NODE_LIMIT=1e3,s.ADAPTATION_UPPER_NODE_LIMIT=5e3,s.MAX_NODE_DISPLACEMENT_INCREMENTAL=100,s.MAX_NODE_DISPLACEMENT=s.MAX_NODE_DISPLACEMENT_INCREMENTAL*3,s.MIN_REPULSION_DIST=s.DEFAULT_EDGE_LENGTH/10,s.CONVERGENCE_CHECK_PERIOD=100,s.PER_LEVEL_IDEAL_EDGE_LENGTH_FACTOR=.1,s.MIN_EDGE_LENGTH=1,s.GRID_CALCULATION_CHECK_PERIOD=10,A.exports=s},function(A,G,N){function g(s,i){s==null&&i==null?(this.x=0,this.y=0):(this.x=s,this.y=i)}g.prototype.getX=function(){return this.x},g.prototype.getY=function(){return this.y},g.prototype.setX=function(s){this.x=s},g.prototype.setY=function(s){this.y=s},g.prototype.getDifference=function(s){return new DimensionD(this.x-s.x,this.y-s.y)},g.prototype.getCopy=function(){return new g(this.x,this.y)},g.prototype.translate=function(s){return this.x+=s.width,this.y+=s.height,this},A.exports=g},function(A,G,N){var g=N(2),s=N(10),i=N(0),r=N(7),e=N(3),f=N(1),a=N(13),y=N(12),t=N(11);function h(c,l,T){g.call(this,T),this.estimatedSize=s.MIN_VALUE,this.margin=i.DEFAULT_GRAPH_MARGIN,this.edges=[],this.nodes=[],this.isConnected=!1,this.parent=c,l!=null&&l instanceof r?this.graphManager=l:l!=null&&l instanceof Layout&&(this.graphManager=l.graphManager)}h.prototype=Object.create(g.prototype);for(var o in g)h[o]=g[o];h.prototype.getNodes=function(){return this.nodes},h.prototype.getEdges=function(){return this.edges},h.prototype.getGraphManager=function(){return this.graphManager},h.prototype.getParent=function(){return this.parent},h.prototype.getLeft=function(){return this.left},h.prototype.getRight=function(){return this.right},h.prototype.getTop=function(){return this.top},h.prototype.getBottom=function(){return this.bottom},h.prototype.isConnected=function(){return this.isConnected},h.prototype.add=function(c,l,T){if(l==null&&T==null){var u=c;if(this.graphManager==null)throw"Graph has no graph mgr!";if(this.getNodes().indexOf(u)>-1)throw"Node already in graph!";return u.owner=this,this.getNodes().push(u),u}else{var d=c;if(!(this.getNodes().indexOf(l)>-1&&this.getNodes().indexOf(T)>-1))throw"Source or target not in graph!";if(!(l.owner==T.owner&&l.owner==this))throw"Both owners must be this graph!";return l.owner!=T.owner?null:(d.source=l,d.target=T,d.isInterGraph=!1,this.getEdges().push(d),l.edges.push(d),T!=l&&T.edges.push(d),d)}},h.prototype.remove=function(c){var l=c;if(c instanceof e){if(l==null)throw"Node is null!";if(!(l.owner!=null&&l.owner==this))throw"Owner graph is invalid!";if(this.graphManager==null)throw"Owner graph manager is invalid!";for(var T=l.edges.slice(),u,d=T.length,L=0;L-1&&P>-1))throw"Source and/or target doesn't know this edge!";u.source.edges.splice(M,1),u.target!=u.source&&u.target.edges.splice(P,1);var F=u.source.owner.getEdges().indexOf(u);if(F==-1)throw"Not in owner's edge list!";u.source.owner.getEdges().splice(F,1)}},h.prototype.updateLeftTop=function(){for(var c=s.MAX_VALUE,l=s.MAX_VALUE,T,u,d,L=this.getNodes(),F=L.length,M=0;MT&&(c=T),l>u&&(l=u)}return c==s.MAX_VALUE?null:(L[0].getParent().paddingLeft!=null?d=L[0].getParent().paddingLeft:d=this.margin,this.left=l-d,this.top=c-d,new y(this.left,this.top))},h.prototype.updateBounds=function(c){for(var l=s.MAX_VALUE,T=-s.MAX_VALUE,u=s.MAX_VALUE,d=-s.MAX_VALUE,L,F,M,P,J,V=this.nodes,Q=V.length,D=0;DL&&(l=L),TM&&(u=M),dL&&(l=L),TM&&(u=M),d=this.nodes.length){var Q=0;T.forEach(function(D){D.owner==c&&Q++}),Q==this.nodes.length&&(this.isConnected=!0)}},A.exports=h},function(A,G,N){var g,s=N(1);function i(r){g=N(6),this.layout=r,this.graphs=[],this.edges=[]}i.prototype.addRoot=function(){var r=this.layout.newGraph(),e=this.layout.newNode(null),f=this.add(r,e);return this.setRootGraph(f),this.rootGraph},i.prototype.add=function(r,e,f,a,y){if(f==null&&a==null&&y==null){if(r==null)throw"Graph is null!";if(e==null)throw"Parent node is null!";if(this.graphs.indexOf(r)>-1)throw"Graph already in this graph mgr!";if(this.graphs.push(r),r.parent!=null)throw"Already has a parent!";if(e.child!=null)throw"Already has a child!";return r.parent=e,e.child=r,r}else{y=f,a=e,f=r;var t=a.getOwner(),h=y.getOwner();if(!(t!=null&&t.getGraphManager()==this))throw"Source not in this graph mgr!";if(!(h!=null&&h.getGraphManager()==this))throw"Target not in this graph mgr!";if(t==h)return f.isInterGraph=!1,t.add(f,a,y);if(f.isInterGraph=!0,f.source=a,f.target=y,this.edges.indexOf(f)>-1)throw"Edge already in inter-graph edge list!";if(this.edges.push(f),!(f.source!=null&&f.target!=null))throw"Edge source and/or target is null!";if(!(f.source.edges.indexOf(f)==-1&&f.target.edges.indexOf(f)==-1))throw"Edge already in source and/or target incidency list!";return f.source.edges.push(f),f.target.edges.push(f),f}},i.prototype.remove=function(r){if(r instanceof g){var e=r;if(e.getGraphManager()!=this)throw"Graph not in this graph mgr";if(!(e==this.rootGraph||e.parent!=null&&e.parent.graphManager==this))throw"Invalid parent node!";var f=[];f=f.concat(e.getEdges());for(var a,y=f.length,t=0;t=r.getRight()?e[0]+=Math.min(r.getX()-i.getX(),i.getRight()-r.getRight()):r.getX()<=i.getX()&&r.getRight()>=i.getRight()&&(e[0]+=Math.min(i.getX()-r.getX(),r.getRight()-i.getRight())),i.getY()<=r.getY()&&i.getBottom()>=r.getBottom()?e[1]+=Math.min(r.getY()-i.getY(),i.getBottom()-r.getBottom()):r.getY()<=i.getY()&&r.getBottom()>=i.getBottom()&&(e[1]+=Math.min(i.getY()-r.getY(),r.getBottom()-i.getBottom()));var y=Math.abs((r.getCenterY()-i.getCenterY())/(r.getCenterX()-i.getCenterX()));r.getCenterY()===i.getCenterY()&&r.getCenterX()===i.getCenterX()&&(y=1);var t=y*e[0],h=e[1]/y;e[0]t)return e[0]=f,e[1]=o,e[2]=y,e[3]=V,!1;if(ay)return e[0]=h,e[1]=a,e[2]=P,e[3]=t,!1;if(fy?(e[0]=l,e[1]=T,n=!0):(e[0]=c,e[1]=o,n=!0):v===p&&(f>y?(e[0]=h,e[1]=o,n=!0):(e[0]=u,e[1]=T,n=!0)),-E===p?y>f?(e[2]=J,e[3]=V,m=!0):(e[2]=P,e[3]=M,m=!0):E===p&&(y>f?(e[2]=F,e[3]=M,m=!0):(e[2]=Q,e[3]=V,m=!0)),n&&m)return!1;if(f>y?a>t?(I=this.getCardinalDirection(v,p,4),w=this.getCardinalDirection(E,p,2)):(I=this.getCardinalDirection(-v,p,3),w=this.getCardinalDirection(-E,p,1)):a>t?(I=this.getCardinalDirection(-v,p,1),w=this.getCardinalDirection(-E,p,3)):(I=this.getCardinalDirection(v,p,2),w=this.getCardinalDirection(E,p,4)),!n)switch(I){case 1:H=o,R=f+-L/p,e[0]=R,e[1]=H;break;case 2:R=u,H=a+d*p,e[0]=R,e[1]=H;break;case 3:H=T,R=f+L/p,e[0]=R,e[1]=H;break;case 4:R=l,H=a+-d*p,e[0]=R,e[1]=H;break}if(!m)switch(w){case 1:k=M,x=y+-rt/p,e[2]=x,e[3]=k;break;case 2:x=Q,k=t+D*p,e[2]=x,e[3]=k;break;case 3:k=V,x=y+rt/p,e[2]=x,e[3]=k;break;case 4:x=J,k=t+-D*p,e[2]=x,e[3]=k;break}}return!1},s.getCardinalDirection=function(i,r,e){return i>r?e:1+e%4},s.getIntersection=function(i,r,e,f){if(f==null)return this.getIntersection2(i,r,e);var a=i.x,y=i.y,t=r.x,h=r.y,o=e.x,c=e.y,l=f.x,T=f.y,u=void 0,d=void 0,L=void 0,F=void 0,M=void 0,P=void 0,J=void 0,V=void 0,Q=void 0;return L=h-y,M=a-t,J=t*y-a*h,F=T-c,P=o-l,V=l*c-o*T,Q=L*P-F*M,Q===0?null:(u=(M*V-P*J)/Q,d=(F*J-L*V)/Q,new g(u,d))},s.angleOfVector=function(i,r,e,f){var a=void 0;return i!==e?(a=Math.atan((f-r)/(e-i)),e=0){var T=(-o+Math.sqrt(o*o-4*h*c))/(2*h),u=(-o-Math.sqrt(o*o-4*h*c))/(2*h),d=null;return T>=0&&T<=1?[T]:u>=0&&u<=1?[u]:d}else return null},s.HALF_PI=.5*Math.PI,s.ONE_AND_HALF_PI=1.5*Math.PI,s.TWO_PI=2*Math.PI,s.THREE_PI=3*Math.PI,A.exports=s},function(A,G,N){function g(){}g.sign=function(s){return s>0?1:s<0?-1:0},g.floor=function(s){return s<0?Math.ceil(s):Math.floor(s)},g.ceil=function(s){return s<0?Math.floor(s):Math.ceil(s)},A.exports=g},function(A,G,N){function g(){}g.MAX_VALUE=2147483647,g.MIN_VALUE=-2147483648,A.exports=g},function(A,G,N){var g=function(){function a(y,t){for(var h=0;h"u"?"undefined":g(i);return i==null||r!="object"&&r!="function"},A.exports=s},function(A,G,N){function g(o){if(Array.isArray(o)){for(var c=0,l=Array(o.length);c0&&c;){for(L.push(M[0]);L.length>0&&c;){var P=L[0];L.splice(0,1),d.add(P);for(var J=P.getEdges(),u=0;u-1&&M.splice(rt,1)}d=new Set,F=new Map}}return o},h.prototype.createDummyNodesForBendpoints=function(o){for(var c=[],l=o.source,T=this.graphManager.calcLowestCommonAncestor(o.source,o.target),u=0;u0){for(var T=this.edgeToDummyNodes.get(l),u=0;u=0&&c.splice(V,1);var Q=F.getNeighborsList();Q.forEach(function(n){if(l.indexOf(n)<0){var m=T.get(n),v=m-1;v==1&&P.push(n),T.set(n,v)}})}l=l.concat(P),(c.length==1||c.length==2)&&(u=!0,d=c[0])}return d},h.prototype.setGraphManager=function(o){this.graphManager=o},A.exports=h},function(A,G,N){function g(){}g.seed=1,g.x=0,g.nextDouble=function(){return g.x=Math.sin(g.seed++)*1e4,g.x-Math.floor(g.x)},A.exports=g},function(A,G,N){var g=N(5);function s(i,r){this.lworldOrgX=0,this.lworldOrgY=0,this.ldeviceOrgX=0,this.ldeviceOrgY=0,this.lworldExtX=1,this.lworldExtY=1,this.ldeviceExtX=1,this.ldeviceExtY=1}s.prototype.getWorldOrgX=function(){return this.lworldOrgX},s.prototype.setWorldOrgX=function(i){this.lworldOrgX=i},s.prototype.getWorldOrgY=function(){return this.lworldOrgY},s.prototype.setWorldOrgY=function(i){this.lworldOrgY=i},s.prototype.getWorldExtX=function(){return this.lworldExtX},s.prototype.setWorldExtX=function(i){this.lworldExtX=i},s.prototype.getWorldExtY=function(){return this.lworldExtY},s.prototype.setWorldExtY=function(i){this.lworldExtY=i},s.prototype.getDeviceOrgX=function(){return this.ldeviceOrgX},s.prototype.setDeviceOrgX=function(i){this.ldeviceOrgX=i},s.prototype.getDeviceOrgY=function(){return this.ldeviceOrgY},s.prototype.setDeviceOrgY=function(i){this.ldeviceOrgY=i},s.prototype.getDeviceExtX=function(){return this.ldeviceExtX},s.prototype.setDeviceExtX=function(i){this.ldeviceExtX=i},s.prototype.getDeviceExtY=function(){return this.ldeviceExtY},s.prototype.setDeviceExtY=function(i){this.ldeviceExtY=i},s.prototype.transformX=function(i){var r=0,e=this.lworldExtX;return e!=0&&(r=this.ldeviceOrgX+(i-this.lworldOrgX)*this.ldeviceExtX/e),r},s.prototype.transformY=function(i){var r=0,e=this.lworldExtY;return e!=0&&(r=this.ldeviceOrgY+(i-this.lworldOrgY)*this.ldeviceExtY/e),r},s.prototype.inverseTransformX=function(i){var r=0,e=this.ldeviceExtX;return e!=0&&(r=this.lworldOrgX+(i-this.ldeviceOrgX)*this.lworldExtX/e),r},s.prototype.inverseTransformY=function(i){var r=0,e=this.ldeviceExtY;return e!=0&&(r=this.lworldOrgY+(i-this.ldeviceOrgY)*this.lworldExtY/e),r},s.prototype.inverseTransformPoint=function(i){var r=new g(this.inverseTransformX(i.x),this.inverseTransformY(i.y));return r},A.exports=s},function(A,G,N){function g(t){if(Array.isArray(t)){for(var h=0,o=Array(t.length);hi.ADAPTATION_LOWER_NODE_LIMIT&&(this.coolingFactor=Math.max(this.coolingFactor*i.COOLING_ADAPTATION_FACTOR,this.coolingFactor-(t-i.ADAPTATION_LOWER_NODE_LIMIT)/(i.ADAPTATION_UPPER_NODE_LIMIT-i.ADAPTATION_LOWER_NODE_LIMIT)*this.coolingFactor*(1-i.COOLING_ADAPTATION_FACTOR))),this.maxNodeDisplacement=i.MAX_NODE_DISPLACEMENT_INCREMENTAL):(t>i.ADAPTATION_LOWER_NODE_LIMIT?this.coolingFactor=Math.max(i.COOLING_ADAPTATION_FACTOR,1-(t-i.ADAPTATION_LOWER_NODE_LIMIT)/(i.ADAPTATION_UPPER_NODE_LIMIT-i.ADAPTATION_LOWER_NODE_LIMIT)*(1-i.COOLING_ADAPTATION_FACTOR)):this.coolingFactor=1,this.initialCoolingFactor=this.coolingFactor,this.maxNodeDisplacement=i.MAX_NODE_DISPLACEMENT),this.maxIterations=Math.max(this.getAllNodes().length*5,this.maxIterations),this.displacementThresholdPerNode=3*i.DEFAULT_EDGE_LENGTH/100,this.totalDisplacementThreshold=this.displacementThresholdPerNode*this.getAllNodes().length,this.repulsionRange=this.calcRepulsionRange()},a.prototype.calcSpringForces=function(){for(var t=this.getAllEdges(),h,o=0;o0&&arguments[0]!==void 0?arguments[0]:!0,h=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!1,o,c,l,T,u=this.getAllNodes(),d;if(this.useFRGridVariant)for(this.totalIterations%i.GRID_CALCULATION_CHECK_PERIOD==1&&t&&this.updateGrid(),d=new Set,o=0;oL||d>L)&&(t.gravitationForceX=-this.gravityConstant*l,t.gravitationForceY=-this.gravityConstant*T)):(L=h.getEstimatedSize()*this.compoundGravityRangeFactor,(u>L||d>L)&&(t.gravitationForceX=-this.gravityConstant*l*this.compoundGravityConstant,t.gravitationForceY=-this.gravityConstant*T*this.compoundGravityConstant))},a.prototype.isConverged=function(){var t,h=!1;return this.totalIterations>this.maxIterations/3&&(h=Math.abs(this.totalDisplacement-this.oldTotalDisplacement)<2),t=this.totalDisplacement=u.length||L>=u[0].length)){for(var F=0;Fa}}]),e}();A.exports=r},function(A,G,N){function g(){}g.svd=function(s){this.U=null,this.V=null,this.s=null,this.m=0,this.n=0,this.m=s.length,this.n=s[0].length;var i=Math.min(this.m,this.n);this.s=function(Nt){for(var Mt=[];Nt-- >0;)Mt.push(0);return Mt}(Math.min(this.m+1,this.n)),this.U=function(Nt){var Mt=function Zt(Gt){if(Gt.length==0)return 0;for(var $t=[],Ft=0;Ft0;)Mt.push(0);return Mt}(this.n),e=function(Nt){for(var Mt=[];Nt-- >0;)Mt.push(0);return Mt}(this.m),f=!0,a=Math.min(this.m-1,this.n),y=Math.max(0,Math.min(this.n-2,this.m)),t=0;t=0;E--)if(this.s[E]!==0){for(var p=E+1;p=0;W--){if(function(Nt,Mt){return Nt&&Mt}(W0;){var q=void 0,Rt=void 0;for(q=n-2;q>=-1&&q!==-1;q--)if(Math.abs(r[q])<=lt+_*(Math.abs(this.s[q])+Math.abs(this.s[q+1]))){r[q]=0;break}if(q===n-2)Rt=4;else{var Lt=void 0;for(Lt=n-1;Lt>=q&&Lt!==q;Lt--){var vt=(Lt!==n?Math.abs(r[Lt]):0)+(Lt!==q+1?Math.abs(r[Lt-1]):0);if(Math.abs(this.s[Lt])<=lt+_*vt){this.s[Lt]=0;break}}Lt===q?Rt=3:Lt===n-1?Rt=1:(Rt=2,q=Lt)}switch(q++,Rt){case 1:{var it=r[n-2];r[n-2]=0;for(var ut=n-2;ut>=q;ut--){var Tt=g.hypot(this.s[ut],it),At=this.s[ut]/Tt,Dt=it/Tt;this.s[ut]=Tt,ut!==q&&(it=-Dt*r[ut-1],r[ut-1]=At*r[ut-1]);for(var mt=0;mt=this.s[q+1]);){var Ct=this.s[q];if(this.s[q]=this.s[q+1],this.s[q+1]=Ct,qMath.abs(i)?(r=i/s,r=Math.abs(s)*Math.sqrt(1+r*r)):i!=0?(r=s/i,r=Math.abs(i)*Math.sqrt(1+r*r)):r=0,r},A.exports=g},function(A,G,N){var g=function(){function r(e,f){for(var a=0;a2&&arguments[2]!==void 0?arguments[2]:1,y=arguments.length>3&&arguments[3]!==void 0?arguments[3]:-1,t=arguments.length>4&&arguments[4]!==void 0?arguments[4]:-1;s(this,r),this.sequence1=e,this.sequence2=f,this.match_score=a,this.mismatch_penalty=y,this.gap_penalty=t,this.iMax=e.length+1,this.jMax=f.length+1,this.grid=new Array(this.iMax);for(var h=0;h=0;e--){var f=this.listeners[e];f.event===i&&f.callback===r&&this.listeners.splice(e,1)}},s.emit=function(i,r){for(var e=0;e{var G={45:(i,r,e)=>{var f={};f.layoutBase=e(551),f.CoSEConstants=e(806),f.CoSEEdge=e(767),f.CoSEGraph=e(880),f.CoSEGraphManager=e(578),f.CoSELayout=e(765),f.CoSENode=e(991),f.ConstraintHandler=e(902),i.exports=f},806:(i,r,e)=>{var f=e(551).FDLayoutConstants;function a(){}for(var y in f)a[y]=f[y];a.DEFAULT_USE_MULTI_LEVEL_SCALING=!1,a.DEFAULT_RADIAL_SEPARATION=f.DEFAULT_EDGE_LENGTH,a.DEFAULT_COMPONENT_SEPERATION=60,a.TILE=!0,a.TILING_PADDING_VERTICAL=10,a.TILING_PADDING_HORIZONTAL=10,a.TRANSFORM_ON_CONSTRAINT_HANDLING=!0,a.ENFORCE_CONSTRAINTS=!0,a.APPLY_LAYOUT=!0,a.RELAX_MOVEMENT_ON_CONSTRAINTS=!0,a.TREE_REDUCTION_ON_INCREMENTAL=!0,a.PURE_INCREMENTAL=a.DEFAULT_INCREMENTAL,i.exports=a},767:(i,r,e)=>{var f=e(551).FDLayoutEdge;function a(t,h,o){f.call(this,t,h,o)}a.prototype=Object.create(f.prototype);for(var y in f)a[y]=f[y];i.exports=a},880:(i,r,e)=>{var f=e(551).LGraph;function a(t,h,o){f.call(this,t,h,o)}a.prototype=Object.create(f.prototype);for(var y in f)a[y]=f[y];i.exports=a},578:(i,r,e)=>{var f=e(551).LGraphManager;function a(t){f.call(this,t)}a.prototype=Object.create(f.prototype);for(var y in f)a[y]=f[y];i.exports=a},765:(i,r,e)=>{var f=e(551).FDLayout,a=e(578),y=e(880),t=e(991),h=e(767),o=e(806),c=e(902),l=e(551).FDLayoutConstants,T=e(551).LayoutConstants,u=e(551).Point,d=e(551).PointD,L=e(551).DimensionD,F=e(551).Layout,M=e(551).Integer,P=e(551).IGeometry,J=e(551).LGraph,V=e(551).Transform,Q=e(551).LinkedList;function D(){f.call(this),this.toBeTiled={},this.constraints={}}D.prototype=Object.create(f.prototype);for(var rt in f)D[rt]=f[rt];D.prototype.newGraphManager=function(){var n=new a(this);return this.graphManager=n,n},D.prototype.newGraph=function(n){return new y(null,this.graphManager,n)},D.prototype.newNode=function(n){return new t(this.graphManager,n)},D.prototype.newEdge=function(n){return new h(null,null,n)},D.prototype.initParameters=function(){f.prototype.initParameters.call(this,arguments),this.isSubLayout||(o.DEFAULT_EDGE_LENGTH<10?this.idealEdgeLength=10:this.idealEdgeLength=o.DEFAULT_EDGE_LENGTH,this.useSmartIdealEdgeLengthCalculation=o.DEFAULT_USE_SMART_IDEAL_EDGE_LENGTH_CALCULATION,this.gravityConstant=l.DEFAULT_GRAVITY_STRENGTH,this.compoundGravityConstant=l.DEFAULT_COMPOUND_GRAVITY_STRENGTH,this.gravityRangeFactor=l.DEFAULT_GRAVITY_RANGE_FACTOR,this.compoundGravityRangeFactor=l.DEFAULT_COMPOUND_GRAVITY_RANGE_FACTOR,this.prunedNodesAll=[],this.growTreeIterations=0,this.afterGrowthIterations=0,this.isTreeGrowing=!1,this.isGrowthFinished=!1)},D.prototype.initSpringEmbedder=function(){f.prototype.initSpringEmbedder.call(this),this.coolingCycle=0,this.maxCoolingCycle=this.maxIterations/l.CONVERGENCE_CHECK_PERIOD,this.finalTemperature=.04,this.coolingAdjuster=1},D.prototype.layout=function(){var n=T.DEFAULT_CREATE_BENDS_AS_NEEDED;return n&&(this.createBendpoints(),this.graphManager.resetAllEdges()),this.level=0,this.classicLayout()},D.prototype.classicLayout=function(){if(this.nodesWithGravity=this.calculateNodesToApplyGravitationTo(),this.graphManager.setAllNodesToApplyGravitation(this.nodesWithGravity),this.calcNoOfChildrenForAllNodes(),this.graphManager.calcLowestCommonAncestors(),this.graphManager.calcInclusionTreeDepths(),this.graphManager.getRoot().calcEstimatedSize(),this.calcIdealEdgeLengths(),this.incremental){if(o.TREE_REDUCTION_ON_INCREMENTAL){this.reduceTrees(),this.graphManager.resetAllNodesToApplyGravitation();var m=new Set(this.getAllNodes()),v=this.nodesWithGravity.filter(function(I){return m.has(I)});this.graphManager.setAllNodesToApplyGravitation(v)}}else{var n=this.getFlatForest();if(n.length>0)this.positionNodesRadially(n);else{this.reduceTrees(),this.graphManager.resetAllNodesToApplyGravitation();var m=new Set(this.getAllNodes()),v=this.nodesWithGravity.filter(function(E){return m.has(E)});this.graphManager.setAllNodesToApplyGravitation(v),this.positionNodesRandomly()}}return Object.keys(this.constraints).length>0&&(c.handleConstraints(this),this.initConstraintVariables()),this.initSpringEmbedder(),o.APPLY_LAYOUT&&this.runSpringEmbedder(),!0},D.prototype.tick=function(){if(this.totalIterations++,this.totalIterations===this.maxIterations&&!this.isTreeGrowing&&!this.isGrowthFinished)if(this.prunedNodesAll.length>0)this.isTreeGrowing=!0;else return!0;if(this.totalIterations%l.CONVERGENCE_CHECK_PERIOD==0&&!this.isTreeGrowing&&!this.isGrowthFinished){if(this.isConverged())if(this.prunedNodesAll.length>0)this.isTreeGrowing=!0;else return!0;this.coolingCycle++,this.layoutQuality==0?this.coolingAdjuster=this.coolingCycle:this.layoutQuality==1&&(this.coolingAdjuster=this.coolingCycle/3),this.coolingFactor=Math.max(this.initialCoolingFactor-Math.pow(this.coolingCycle,Math.log(100*(this.initialCoolingFactor-this.finalTemperature))/Math.log(this.maxCoolingCycle))/100*this.coolingAdjuster,this.finalTemperature),this.animationPeriod=Math.ceil(this.initialAnimationPeriod*Math.sqrt(this.coolingFactor))}if(this.isTreeGrowing){if(this.growTreeIterations%10==0)if(this.prunedNodesAll.length>0){this.graphManager.updateBounds(),this.updateGrid(),this.growTree(this.prunedNodesAll),this.graphManager.resetAllNodesToApplyGravitation();var n=new Set(this.getAllNodes()),m=this.nodesWithGravity.filter(function(p){return n.has(p)});this.graphManager.setAllNodesToApplyGravitation(m),this.graphManager.updateBounds(),this.updateGrid(),o.PURE_INCREMENTAL?this.coolingFactor=l.DEFAULT_COOLING_FACTOR_INCREMENTAL/2:this.coolingFactor=l.DEFAULT_COOLING_FACTOR_INCREMENTAL}else this.isTreeGrowing=!1,this.isGrowthFinished=!0;this.growTreeIterations++}if(this.isGrowthFinished){if(this.isConverged())return!0;this.afterGrowthIterations%10==0&&(this.graphManager.updateBounds(),this.updateGrid()),o.PURE_INCREMENTAL?this.coolingFactor=l.DEFAULT_COOLING_FACTOR_INCREMENTAL/2*((100-this.afterGrowthIterations)/100):this.coolingFactor=l.DEFAULT_COOLING_FACTOR_INCREMENTAL*((100-this.afterGrowthIterations)/100),this.afterGrowthIterations++}var v=!this.isTreeGrowing&&!this.isGrowthFinished,E=this.growTreeIterations%10==1&&this.isTreeGrowing||this.afterGrowthIterations%10==1&&this.isGrowthFinished;return this.totalDisplacement=0,this.graphManager.updateBounds(),this.calcSpringForces(),this.calcRepulsionForces(v,E),this.calcGravitationalForces(),this.moveNodes(),this.animate(),!1},D.prototype.getPositionsData=function(){for(var n=this.graphManager.getAllNodes(),m={},v=0;v0&&this.updateDisplacements();for(var v=0;v0&&(E.fixedNodeWeight=I)}}if(this.constraints.relativePlacementConstraint){var w=new Map,R=new Map;if(this.dummyToNodeForVerticalAlignment=new Map,this.dummyToNodeForHorizontalAlignment=new Map,this.fixedNodesOnHorizontal=new Set,this.fixedNodesOnVertical=new Set,this.fixedNodeSet.forEach(function(O){n.fixedNodesOnHorizontal.add(O),n.fixedNodesOnVertical.add(O)}),this.constraints.alignmentConstraint){if(this.constraints.alignmentConstraint.vertical)for(var H=this.constraints.alignmentConstraint.vertical,v=0;v=2*O.length/3;_--)X=Math.floor(Math.random()*(_+1)),B=O[_],O[_]=O[X],O[X]=B;return O},this.nodesInRelativeHorizontal=[],this.nodesInRelativeVertical=[],this.nodeToRelativeConstraintMapHorizontal=new Map,this.nodeToRelativeConstraintMapVertical=new Map,this.nodeToTempPositionMapHorizontal=new Map,this.nodeToTempPositionMapVertical=new Map,this.constraints.relativePlacementConstraint.forEach(function(O){if(O.left){var X=w.has(O.left)?w.get(O.left):O.left,B=w.has(O.right)?w.get(O.right):O.right;n.nodesInRelativeHorizontal.includes(X)||(n.nodesInRelativeHorizontal.push(X),n.nodeToRelativeConstraintMapHorizontal.set(X,[]),n.dummyToNodeForVerticalAlignment.has(X)?n.nodeToTempPositionMapHorizontal.set(X,n.idToNodeMap.get(n.dummyToNodeForVerticalAlignment.get(X)[0]).getCenterX()):n.nodeToTempPositionMapHorizontal.set(X,n.idToNodeMap.get(X).getCenterX())),n.nodesInRelativeHorizontal.includes(B)||(n.nodesInRelativeHorizontal.push(B),n.nodeToRelativeConstraintMapHorizontal.set(B,[]),n.dummyToNodeForVerticalAlignment.has(B)?n.nodeToTempPositionMapHorizontal.set(B,n.idToNodeMap.get(n.dummyToNodeForVerticalAlignment.get(B)[0]).getCenterX()):n.nodeToTempPositionMapHorizontal.set(B,n.idToNodeMap.get(B).getCenterX())),n.nodeToRelativeConstraintMapHorizontal.get(X).push({right:B,gap:O.gap}),n.nodeToRelativeConstraintMapHorizontal.get(B).push({left:X,gap:O.gap})}else{var _=R.has(O.top)?R.get(O.top):O.top,lt=R.has(O.bottom)?R.get(O.bottom):O.bottom;n.nodesInRelativeVertical.includes(_)||(n.nodesInRelativeVertical.push(_),n.nodeToRelativeConstraintMapVertical.set(_,[]),n.dummyToNodeForHorizontalAlignment.has(_)?n.nodeToTempPositionMapVertical.set(_,n.idToNodeMap.get(n.dummyToNodeForHorizontalAlignment.get(_)[0]).getCenterY()):n.nodeToTempPositionMapVertical.set(_,n.idToNodeMap.get(_).getCenterY())),n.nodesInRelativeVertical.includes(lt)||(n.nodesInRelativeVertical.push(lt),n.nodeToRelativeConstraintMapVertical.set(lt,[]),n.dummyToNodeForHorizontalAlignment.has(lt)?n.nodeToTempPositionMapVertical.set(lt,n.idToNodeMap.get(n.dummyToNodeForHorizontalAlignment.get(lt)[0]).getCenterY()):n.nodeToTempPositionMapVertical.set(lt,n.idToNodeMap.get(lt).getCenterY())),n.nodeToRelativeConstraintMapVertical.get(_).push({bottom:lt,gap:O.gap}),n.nodeToRelativeConstraintMapVertical.get(lt).push({top:_,gap:O.gap})}});else{var k=new Map,W=new Map;this.constraints.relativePlacementConstraint.forEach(function(O){if(O.left){var X=w.has(O.left)?w.get(O.left):O.left,B=w.has(O.right)?w.get(O.right):O.right;k.has(X)?k.get(X).push(B):k.set(X,[B]),k.has(B)?k.get(B).push(X):k.set(B,[X])}else{var _=R.has(O.top)?R.get(O.top):O.top,lt=R.has(O.bottom)?R.get(O.bottom):O.bottom;W.has(_)?W.get(_).push(lt):W.set(_,[lt]),W.has(lt)?W.get(lt).push(_):W.set(lt,[_])}});var U=function(X,B){var _=[],lt=[],q=new Q,Rt=new Set,Lt=0;return X.forEach(function(vt,it){if(!Rt.has(it)){_[Lt]=[],lt[Lt]=!1;var ut=it;for(q.push(ut),Rt.add(ut),_[Lt].push(ut);q.length!=0;){ut=q.shift(),B.has(ut)&&(lt[Lt]=!0);var Tt=X.get(ut);Tt.forEach(function(At){Rt.has(At)||(q.push(At),Rt.add(At),_[Lt].push(At))})}Lt++}}),{components:_,isFixed:lt}},et=U(k,n.fixedNodesOnHorizontal);this.componentsOnHorizontal=et.components,this.fixedComponentsOnHorizontal=et.isFixed;var z=U(W,n.fixedNodesOnVertical);this.componentsOnVertical=z.components,this.fixedComponentsOnVertical=z.isFixed}}},D.prototype.updateDisplacements=function(){var n=this;if(this.constraints.fixedNodeConstraint&&this.constraints.fixedNodeConstraint.forEach(function(z){var O=n.idToNodeMap.get(z.nodeId);O.displacementX=0,O.displacementY=0}),this.constraints.alignmentConstraint){if(this.constraints.alignmentConstraint.vertical)for(var m=this.constraints.alignmentConstraint.vertical,v=0;v1){var R;for(R=0;RE&&(E=Math.floor(w.y)),I=Math.floor(w.x+o.DEFAULT_COMPONENT_SEPERATION)}this.transform(new d(T.WORLD_CENTER_X-w.x/2,T.WORLD_CENTER_Y-w.y/2))},D.radialLayout=function(n,m,v){var E=Math.max(this.maxDiagonalInTree(n),o.DEFAULT_RADIAL_SEPARATION);D.branchRadialLayout(m,null,0,359,0,E);var p=J.calculateBounds(n),I=new V;I.setDeviceOrgX(p.getMinX()),I.setDeviceOrgY(p.getMinY()),I.setWorldOrgX(v.x),I.setWorldOrgY(v.y);for(var w=0;w1;){var B=X[0];X.splice(0,1);var _=W.indexOf(B);_>=0&&W.splice(_,1),z--,U--}m!=null?O=(W.indexOf(X[0])+1)%z:O=0;for(var lt=Math.abs(E-v)/U,q=O;et!=U;q=++q%z){var Rt=W[q].getOtherEnd(n);if(Rt!=m){var Lt=(v+et*lt)%360,vt=(Lt+lt)%360;D.branchRadialLayout(Rt,n,Lt,vt,p+I,I),et++}}},D.maxDiagonalInTree=function(n){for(var m=M.MIN_VALUE,v=0;vm&&(m=p)}return m},D.prototype.calcRepulsionRange=function(){return 2*(this.level+1)*this.idealEdgeLength},D.prototype.groupZeroDegreeMembers=function(){var n=this,m={};this.memberGroups={},this.idToDummyNode={};for(var v=[],E=this.graphManager.getAllNodes(),p=0;p"u"&&(m[R]=[]),m[R]=m[R].concat(I)}Object.keys(m).forEach(function(H){if(m[H].length>1){var x="DummyCompound_"+H;n.memberGroups[x]=m[H];var k=m[H][0].getParent(),W=new t(n.graphManager);W.id=x,W.paddingLeft=k.paddingLeft||0,W.paddingRight=k.paddingRight||0,W.paddingBottom=k.paddingBottom||0,W.paddingTop=k.paddingTop||0,n.idToDummyNode[x]=W;var U=n.getGraphManager().add(n.newGraph(),W),et=k.getChild();et.add(W);for(var z=0;zp?(E.rect.x-=(E.labelWidth-p)/2,E.setWidth(E.labelWidth),E.labelMarginLeft=(E.labelWidth-p)/2):E.labelPosHorizontal=="right"&&E.setWidth(p+E.labelWidth)),E.labelHeight&&(E.labelPosVertical=="top"?(E.rect.y-=E.labelHeight,E.setHeight(I+E.labelHeight),E.labelMarginTop=E.labelHeight):E.labelPosVertical=="center"&&E.labelHeight>I?(E.rect.y-=(E.labelHeight-I)/2,E.setHeight(E.labelHeight),E.labelMarginTop=(E.labelHeight-I)/2):E.labelPosVertical=="bottom"&&E.setHeight(I+E.labelHeight))}})},D.prototype.repopulateCompounds=function(){for(var n=this.compoundOrder.length-1;n>=0;n--){var m=this.compoundOrder[n],v=m.id,E=m.paddingLeft,p=m.paddingTop,I=m.labelMarginLeft,w=m.labelMarginTop;this.adjustLocations(this.tiledMemberPack[v],m.rect.x,m.rect.y,E,p,I,w)}},D.prototype.repopulateZeroDegreeMembers=function(){var n=this,m=this.tiledZeroDegreePack;Object.keys(m).forEach(function(v){var E=n.idToDummyNode[v],p=E.paddingLeft,I=E.paddingTop,w=E.labelMarginLeft,R=E.labelMarginTop;n.adjustLocations(m[v],E.rect.x,E.rect.y,p,I,w,R)})},D.prototype.getToBeTiled=function(n){var m=n.id;if(this.toBeTiled[m]!=null)return this.toBeTiled[m];var v=n.getChild();if(v==null)return this.toBeTiled[m]=!1,!1;for(var E=v.getNodes(),p=0;p0)return this.toBeTiled[m]=!1,!1;if(I.getChild()==null){this.toBeTiled[I.id]=!1;continue}if(!this.getToBeTiled(I))return this.toBeTiled[m]=!1,!1}return this.toBeTiled[m]=!0,!0},D.prototype.getNodeDegree=function(n){n.id;for(var m=n.getEdges(),v=0,E=0;Ek&&(k=U.rect.height)}v+=k+n.verticalPadding}},D.prototype.tileCompoundMembers=function(n,m){var v=this;this.tiledMemberPack=[],Object.keys(n).forEach(function(E){var p=m[E];if(v.tiledMemberPack[E]=v.tileNodes(n[E],p.paddingLeft+p.paddingRight),p.rect.width=v.tiledMemberPack[E].width,p.rect.height=v.tiledMemberPack[E].height,p.setCenter(v.tiledMemberPack[E].centerX,v.tiledMemberPack[E].centerY),p.labelMarginLeft=0,p.labelMarginTop=0,o.NODE_DIMENSIONS_INCLUDE_LABELS){var I=p.rect.width,w=p.rect.height;p.labelWidth&&(p.labelPosHorizontal=="left"?(p.rect.x-=p.labelWidth,p.setWidth(I+p.labelWidth),p.labelMarginLeft=p.labelWidth):p.labelPosHorizontal=="center"&&p.labelWidth>I?(p.rect.x-=(p.labelWidth-I)/2,p.setWidth(p.labelWidth),p.labelMarginLeft=(p.labelWidth-I)/2):p.labelPosHorizontal=="right"&&p.setWidth(I+p.labelWidth)),p.labelHeight&&(p.labelPosVertical=="top"?(p.rect.y-=p.labelHeight,p.setHeight(w+p.labelHeight),p.labelMarginTop=p.labelHeight):p.labelPosVertical=="center"&&p.labelHeight>w?(p.rect.y-=(p.labelHeight-w)/2,p.setHeight(p.labelHeight),p.labelMarginTop=(p.labelHeight-w)/2):p.labelPosVertical=="bottom"&&p.setHeight(w+p.labelHeight))}})},D.prototype.tileNodes=function(n,m){var v=this.tileNodesByFavoringDim(n,m,!0),E=this.tileNodesByFavoringDim(n,m,!1),p=this.getOrgRatio(v),I=this.getOrgRatio(E),w;return IR&&(R=z.getWidth())});var H=I/p,x=w/p,k=Math.pow(v-E,2)+4*(H+E)*(x+v)*p,W=(E-v+Math.sqrt(k))/(2*(H+E)),U;m?(U=Math.ceil(W),U==W&&U++):U=Math.floor(W);var et=U*(H+E)-E;return R>et&&(et=R),et+=E*2,et},D.prototype.tileNodesByFavoringDim=function(n,m,v){var E=o.TILING_PADDING_VERTICAL,p=o.TILING_PADDING_HORIZONTAL,I=o.TILING_COMPARE_BY,w={rows:[],rowWidth:[],rowHeight:[],width:0,height:m,verticalPadding:E,horizontalPadding:p,centerX:0,centerY:0};I&&(w.idealRowWidth=this.calcIdealRowWidth(n,v));var R=function(O){return O.rect.width*O.rect.height},H=function(O,X){return R(X)-R(O)};n.sort(function(z,O){var X=H;return w.idealRowWidth?(X=I,X(z.id,O.id)):X(z,O)});for(var x=0,k=0,W=0;W0&&(w+=n.horizontalPadding),n.rowWidth[v]=w,n.width0&&(R+=n.verticalPadding);var H=0;R>n.rowHeight[v]&&(H=n.rowHeight[v],n.rowHeight[v]=R,H=n.rowHeight[v]-H),n.height+=H,n.rows[v].push(m)},D.prototype.getShortestRowIndex=function(n){for(var m=-1,v=Number.MAX_VALUE,E=0;Ev&&(m=E,v=n.rowWidth[E]);return m},D.prototype.canAddHorizontal=function(n,m,v){if(n.idealRowWidth){var E=n.rows.length-1,p=n.rowWidth[E];return p+m+n.horizontalPadding<=n.idealRowWidth}var I=this.getShortestRowIndex(n);if(I<0)return!0;var w=n.rowWidth[I];if(w+n.horizontalPadding+m<=n.width)return!0;var R=0;n.rowHeight[I]0&&(R=v+n.verticalPadding-n.rowHeight[I]);var H;n.width-w>=m+n.horizontalPadding?H=(n.height+R)/(w+m+n.horizontalPadding):H=(n.height+R)/n.width,R=v+n.verticalPadding;var x;return n.widthI&&m!=v){E.splice(-1,1),n.rows[v].push(p),n.rowWidth[m]=n.rowWidth[m]-I,n.rowWidth[v]=n.rowWidth[v]+I,n.width=n.rowWidth[instance.getLongestRowIndex(n)];for(var w=Number.MIN_VALUE,R=0;Rw&&(w=E[R].height);m>0&&(w+=n.verticalPadding);var H=n.rowHeight[m]+n.rowHeight[v];n.rowHeight[m]=w,n.rowHeight[v]0)for(var et=p;et<=I;et++)U[0]+=this.grid[et][w-1].length+this.grid[et][w].length-1;if(I0)for(var et=w;et<=R;et++)U[3]+=this.grid[p-1][et].length+this.grid[p][et].length-1;for(var z=M.MAX_VALUE,O,X,B=0;B{var f=e(551).FDLayoutNode,a=e(551).IMath;function y(h,o,c,l){f.call(this,h,o,c,l)}y.prototype=Object.create(f.prototype);for(var t in f)y[t]=f[t];y.prototype.calculateDisplacement=function(){var h=this.graphManager.getLayout();this.getChild()!=null&&this.fixedNodeWeight?(this.displacementX+=h.coolingFactor*(this.springForceX+this.repulsionForceX+this.gravitationForceX)/this.fixedNodeWeight,this.displacementY+=h.coolingFactor*(this.springForceY+this.repulsionForceY+this.gravitationForceY)/this.fixedNodeWeight):(this.displacementX+=h.coolingFactor*(this.springForceX+this.repulsionForceX+this.gravitationForceX)/this.noOfChildren,this.displacementY+=h.coolingFactor*(this.springForceY+this.repulsionForceY+this.gravitationForceY)/this.noOfChildren),Math.abs(this.displacementX)>h.coolingFactor*h.maxNodeDisplacement&&(this.displacementX=h.coolingFactor*h.maxNodeDisplacement*a.sign(this.displacementX)),Math.abs(this.displacementY)>h.coolingFactor*h.maxNodeDisplacement&&(this.displacementY=h.coolingFactor*h.maxNodeDisplacement*a.sign(this.displacementY)),this.child&&this.child.getNodes().length>0&&this.propogateDisplacementToChildren(this.displacementX,this.displacementY)},y.prototype.propogateDisplacementToChildren=function(h,o){for(var c=this.getChild().getNodes(),l,T=0;T{function f(c){if(Array.isArray(c)){for(var l=0,T=Array(c.length);l0){var Ct=0;st.forEach(function(ht){$=="horizontal"?(tt.set(ht,u.has(ht)?d[u.get(ht)]:Z.get(ht)),Ct+=tt.get(ht)):(tt.set(ht,u.has(ht)?L[u.get(ht)]:Z.get(ht)),Ct+=tt.get(ht))}),Ct=Ct/st.length,ft.forEach(function(ht){K.has(ht)||tt.set(ht,Ct)})}else{var ct=0;ft.forEach(function(ht){$=="horizontal"?ct+=u.has(ht)?d[u.get(ht)]:Z.get(ht):ct+=u.has(ht)?L[u.get(ht)]:Z.get(ht)}),ct=ct/ft.length,ft.forEach(function(ht){tt.set(ht,ct)})}});for(var wt=function(){var st=dt.shift(),Ct=b.get(st);Ct.forEach(function(ct){if(tt.get(ct.id)ht&&(ht=qt),_tWt&&(Wt=_t)}}catch(ie){Mt=!0,Zt=ie}finally{try{!Nt&&Gt.return&&Gt.return()}finally{if(Mt)throw Zt}}var ce=(Ct+ht)/2-(ct+Wt)/2,Kt=!0,te=!1,ee=void 0;try{for(var jt=ft[Symbol.iterator](),se;!(Kt=(se=jt.next()).done);Kt=!0){var re=se.value;tt.set(re,tt.get(re)+ce)}}catch(ie){te=!0,ee=ie}finally{try{!Kt&&jt.return&&jt.return()}finally{if(te)throw ee}}})}return tt},rt=function(b){var $=0,K=0,Z=0,at=0;if(b.forEach(function(j){j.left?d[u.get(j.left)]-d[u.get(j.right)]>=0?$++:K++:L[u.get(j.top)]-L[u.get(j.bottom)]>=0?Z++:at++}),$>K&&Z>at)for(var gt=0;gtK)for(var ot=0;otat)for(var tt=0;tt1)l.fixedNodeConstraint.forEach(function(S,b){E[b]=[S.position.x,S.position.y],p[b]=[d[u.get(S.nodeId)],L[u.get(S.nodeId)]]}),I=!0;else if(l.alignmentConstraint)(function(){var S=0;if(l.alignmentConstraint.vertical){for(var b=l.alignmentConstraint.vertical,$=function(tt){var j=new Set;b[tt].forEach(function(yt){j.add(yt)});var dt=new Set([].concat(f(j)).filter(function(yt){return R.has(yt)})),wt=void 0;dt.size>0?wt=d[u.get(dt.values().next().value)]:wt=Q(j).x,b[tt].forEach(function(yt){E[S]=[wt,L[u.get(yt)]],p[S]=[d[u.get(yt)],L[u.get(yt)]],S++})},K=0;K0?wt=d[u.get(dt.values().next().value)]:wt=Q(j).y,Z[tt].forEach(function(yt){E[S]=[d[u.get(yt)],wt],p[S]=[d[u.get(yt)],L[u.get(yt)]],S++})},gt=0;gtW&&(W=k[et].length,U=et);if(W0){var mt={x:0,y:0};l.fixedNodeConstraint.forEach(function(S,b){var $={x:d[u.get(S.nodeId)],y:L[u.get(S.nodeId)]},K=S.position,Z=V(K,$);mt.x+=Z.x,mt.y+=Z.y}),mt.x/=l.fixedNodeConstraint.length,mt.y/=l.fixedNodeConstraint.length,d.forEach(function(S,b){d[b]+=mt.x}),L.forEach(function(S,b){L[b]+=mt.y}),l.fixedNodeConstraint.forEach(function(S){d[u.get(S.nodeId)]=S.position.x,L[u.get(S.nodeId)]=S.position.y})}if(l.alignmentConstraint){if(l.alignmentConstraint.vertical)for(var xt=l.alignmentConstraint.vertical,St=function(b){var $=new Set;xt[b].forEach(function(at){$.add(at)});var K=new Set([].concat(f($)).filter(function(at){return R.has(at)})),Z=void 0;K.size>0?Z=d[u.get(K.values().next().value)]:Z=Q($).x,$.forEach(function(at){R.has(at)||(d[u.get(at)]=Z)})},Vt=0;Vt0?Z=L[u.get(K.values().next().value)]:Z=Q($).y,$.forEach(function(at){R.has(at)||(L[u.get(at)]=Z)})},bt=0;bt{i.exports=A}},N={};function g(i){var r=N[i];if(r!==void 0)return r.exports;var e=N[i]={exports:{}};return G[i](e,e.exports,g),e.exports}var s=g(45);return s})()})}(pe)),pe.exports}(function(C,Y){(function(G,N){C.exports=N(cr())})(Te,function(A){return(()=>{var G={658:i=>{i.exports=Object.assign!=null?Object.assign.bind(Object):function(r){for(var e=arguments.length,f=Array(e>1?e-1:0),a=1;a{var f=function(){function t(h,o){var c=[],l=!0,T=!1,u=void 0;try{for(var d=h[Symbol.iterator](),L;!(l=(L=d.next()).done)&&(c.push(L.value),!(o&&c.length===o));l=!0);}catch(F){T=!0,u=F}finally{try{!l&&d.return&&d.return()}finally{if(T)throw u}}return c}return function(h,o){if(Array.isArray(h))return h;if(Symbol.iterator in Object(h))return t(h,o);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),a=e(140).layoutBase.LinkedList,y={};y.getTopMostNodes=function(t){for(var h={},o=0;o0&&I.merge(x)});for(var w=0;w1){L=u[0],F=L.connectedEdges().length,u.forEach(function(p){p.connectedEdges().length0&&c.set("dummy"+(c.size+1),J),V},y.relocateComponent=function(t,h,o){if(!o.fixedNodeConstraint){var c=Number.POSITIVE_INFINITY,l=Number.NEGATIVE_INFINITY,T=Number.POSITIVE_INFINITY,u=Number.NEGATIVE_INFINITY;if(o.quality=="draft"){var d=!0,L=!1,F=void 0;try{for(var M=h.nodeIndexes[Symbol.iterator](),P;!(d=(P=M.next()).done);d=!0){var J=P.value,V=f(J,2),Q=V[0],D=V[1],rt=o.cy.getElementById(Q);if(rt){var n=rt.boundingBox(),m=h.xCoords[D]-n.w/2,v=h.xCoords[D]+n.w/2,E=h.yCoords[D]-n.h/2,p=h.yCoords[D]+n.h/2;ml&&(l=v),Eu&&(u=p)}}}catch(x){L=!0,F=x}finally{try{!d&&M.return&&M.return()}finally{if(L)throw F}}var I=t.x-(l+c)/2,w=t.y-(u+T)/2;h.xCoords=h.xCoords.map(function(x){return x+I}),h.yCoords=h.yCoords.map(function(x){return x+w})}else{Object.keys(h).forEach(function(x){var k=h[x],W=k.getRect().x,U=k.getRect().x+k.getRect().width,et=k.getRect().y,z=k.getRect().y+k.getRect().height;Wl&&(l=U),etu&&(u=z)});var R=t.x-(l+c)/2,H=t.y-(u+T)/2;Object.keys(h).forEach(function(x){var k=h[x];k.setCenter(k.getCenterX()+R,k.getCenterY()+H)})}}},y.calcBoundingBox=function(t,h,o,c){for(var l=Number.MAX_SAFE_INTEGER,T=Number.MIN_SAFE_INTEGER,u=Number.MAX_SAFE_INTEGER,d=Number.MIN_SAFE_INTEGER,L=void 0,F=void 0,M=void 0,P=void 0,J=t.descendants().not(":parent"),V=J.length,Q=0;QL&&(l=L),TM&&(u=M),d{var f=e(548),a=e(140).CoSELayout,y=e(140).CoSENode,t=e(140).layoutBase.PointD,h=e(140).layoutBase.DimensionD,o=e(140).layoutBase.LayoutConstants,c=e(140).layoutBase.FDLayoutConstants,l=e(140).CoSEConstants,T=function(d,L){var F=d.cy,M=d.eles,P=M.nodes(),J=M.edges(),V=void 0,Q=void 0,D=void 0,rt={};d.randomize&&(V=L.nodeIndexes,Q=L.xCoords,D=L.yCoords);var n=function(x){return typeof x=="function"},m=function(x,k){return n(x)?x(k):x},v=f.calcParentsWithoutChildren(F,M),E=function H(x,k,W,U){for(var et=k.length,z=0;z0){var q=void 0;q=W.getGraphManager().add(W.newGraph(),B),H(q,X,W,U)}}},p=function(x,k,W){for(var U=0,et=0,z=0;z0?l.DEFAULT_EDGE_LENGTH=c.DEFAULT_EDGE_LENGTH=U/et:n(d.idealEdgeLength)?l.DEFAULT_EDGE_LENGTH=c.DEFAULT_EDGE_LENGTH=50:l.DEFAULT_EDGE_LENGTH=c.DEFAULT_EDGE_LENGTH=d.idealEdgeLength,l.MIN_REPULSION_DIST=c.MIN_REPULSION_DIST=c.DEFAULT_EDGE_LENGTH/10,l.DEFAULT_RADIAL_SEPARATION=c.DEFAULT_EDGE_LENGTH)},I=function(x,k){k.fixedNodeConstraint&&(x.constraints.fixedNodeConstraint=k.fixedNodeConstraint),k.alignmentConstraint&&(x.constraints.alignmentConstraint=k.alignmentConstraint),k.relativePlacementConstraint&&(x.constraints.relativePlacementConstraint=k.relativePlacementConstraint)};d.nestingFactor!=null&&(l.PER_LEVEL_IDEAL_EDGE_LENGTH_FACTOR=c.PER_LEVEL_IDEAL_EDGE_LENGTH_FACTOR=d.nestingFactor),d.gravity!=null&&(l.DEFAULT_GRAVITY_STRENGTH=c.DEFAULT_GRAVITY_STRENGTH=d.gravity),d.numIter!=null&&(l.MAX_ITERATIONS=c.MAX_ITERATIONS=d.numIter),d.gravityRange!=null&&(l.DEFAULT_GRAVITY_RANGE_FACTOR=c.DEFAULT_GRAVITY_RANGE_FACTOR=d.gravityRange),d.gravityCompound!=null&&(l.DEFAULT_COMPOUND_GRAVITY_STRENGTH=c.DEFAULT_COMPOUND_GRAVITY_STRENGTH=d.gravityCompound),d.gravityRangeCompound!=null&&(l.DEFAULT_COMPOUND_GRAVITY_RANGE_FACTOR=c.DEFAULT_COMPOUND_GRAVITY_RANGE_FACTOR=d.gravityRangeCompound),d.initialEnergyOnIncremental!=null&&(l.DEFAULT_COOLING_FACTOR_INCREMENTAL=c.DEFAULT_COOLING_FACTOR_INCREMENTAL=d.initialEnergyOnIncremental),d.tilingCompareBy!=null&&(l.TILING_COMPARE_BY=d.tilingCompareBy),d.quality=="proof"?o.QUALITY=2:o.QUALITY=0,l.NODE_DIMENSIONS_INCLUDE_LABELS=c.NODE_DIMENSIONS_INCLUDE_LABELS=o.NODE_DIMENSIONS_INCLUDE_LABELS=d.nodeDimensionsIncludeLabels,l.DEFAULT_INCREMENTAL=c.DEFAULT_INCREMENTAL=o.DEFAULT_INCREMENTAL=!d.randomize,l.ANIMATE=c.ANIMATE=o.ANIMATE=d.animate,l.TILE=d.tile,l.TILING_PADDING_VERTICAL=typeof d.tilingPaddingVertical=="function"?d.tilingPaddingVertical.call():d.tilingPaddingVertical,l.TILING_PADDING_HORIZONTAL=typeof d.tilingPaddingHorizontal=="function"?d.tilingPaddingHorizontal.call():d.tilingPaddingHorizontal,l.DEFAULT_INCREMENTAL=c.DEFAULT_INCREMENTAL=o.DEFAULT_INCREMENTAL=!0,l.PURE_INCREMENTAL=!d.randomize,o.DEFAULT_UNIFORM_LEAF_NODE_SIZES=d.uniformNodeDimensions,d.step=="transformed"&&(l.TRANSFORM_ON_CONSTRAINT_HANDLING=!0,l.ENFORCE_CONSTRAINTS=!1,l.APPLY_LAYOUT=!1),d.step=="enforced"&&(l.TRANSFORM_ON_CONSTRAINT_HANDLING=!1,l.ENFORCE_CONSTRAINTS=!0,l.APPLY_LAYOUT=!1),d.step=="cose"&&(l.TRANSFORM_ON_CONSTRAINT_HANDLING=!1,l.ENFORCE_CONSTRAINTS=!1,l.APPLY_LAYOUT=!0),d.step=="all"&&(d.randomize?l.TRANSFORM_ON_CONSTRAINT_HANDLING=!0:l.TRANSFORM_ON_CONSTRAINT_HANDLING=!1,l.ENFORCE_CONSTRAINTS=!0,l.APPLY_LAYOUT=!0),d.fixedNodeConstraint||d.alignmentConstraint||d.relativePlacementConstraint?l.TREE_REDUCTION_ON_INCREMENTAL=!1:l.TREE_REDUCTION_ON_INCREMENTAL=!0;var w=new a,R=w.newGraphManager();return E(R.addRoot(),f.getTopMostNodes(P),w,d),p(w,R,J),I(w,d),w.runLayout(),rt};i.exports={coseLayout:T}},212:(i,r,e)=>{var f=function(){function d(L,F){for(var M=0;M0)if(v){var I=t.getTopMostNodes(M.eles.nodes());if(D=t.connectComponents(P,M.eles,I),D.forEach(function(vt){var it=vt.boundingBox();rt.push({x:it.x1+it.w/2,y:it.y1+it.h/2})}),M.randomize&&D.forEach(function(vt){M.eles=vt,V.push(o(M))}),M.quality=="default"||M.quality=="proof"){var w=P.collection();if(M.tile){var R=new Map,H=[],x=[],k=0,W={nodeIndexes:R,xCoords:H,yCoords:x},U=[];if(D.forEach(function(vt,it){vt.edges().length==0&&(vt.nodes().forEach(function(ut,Tt){w.merge(vt.nodes()[Tt]),ut.isParent()||(W.nodeIndexes.set(vt.nodes()[Tt].id(),k++),W.xCoords.push(vt.nodes()[0].position().x),W.yCoords.push(vt.nodes()[0].position().y))}),U.push(it))}),w.length>1){var et=w.boundingBox();rt.push({x:et.x1+et.w/2,y:et.y1+et.h/2}),D.push(w),V.push(W);for(var z=U.length-1;z>=0;z--)D.splice(U[z],1),V.splice(U[z],1),rt.splice(U[z],1)}}D.forEach(function(vt,it){M.eles=vt,Q.push(l(M,V[it])),t.relocateComponent(rt[it],Q[it],M)})}else D.forEach(function(vt,it){t.relocateComponent(rt[it],V[it],M)});var O=new Set;if(D.length>1){var X=[],B=J.filter(function(vt){return vt.css("display")=="none"});D.forEach(function(vt,it){var ut=void 0;if(M.quality=="draft"&&(ut=V[it].nodeIndexes),vt.nodes().not(B).length>0){var Tt={};Tt.edges=[],Tt.nodes=[];var At=void 0;vt.nodes().not(B).forEach(function(Dt){if(M.quality=="draft")if(!Dt.isParent())At=ut.get(Dt.id()),Tt.nodes.push({x:V[it].xCoords[At]-Dt.boundingbox().w/2,y:V[it].yCoords[At]-Dt.boundingbox().h/2,width:Dt.boundingbox().w,height:Dt.boundingbox().h});else{var mt=t.calcBoundingBox(Dt,V[it].xCoords,V[it].yCoords,ut);Tt.nodes.push({x:mt.topLeftX,y:mt.topLeftY,width:mt.width,height:mt.height})}else Q[it][Dt.id()]&&Tt.nodes.push({x:Q[it][Dt.id()].getLeft(),y:Q[it][Dt.id()].getTop(),width:Q[it][Dt.id()].getWidth(),height:Q[it][Dt.id()].getHeight()})}),vt.edges().forEach(function(Dt){var mt=Dt.source(),xt=Dt.target();if(mt.css("display")!="none"&&xt.css("display")!="none")if(M.quality=="draft"){var St=ut.get(mt.id()),Vt=ut.get(xt.id()),Xt=[],Ut=[];if(mt.isParent()){var bt=t.calcBoundingBox(mt,V[it].xCoords,V[it].yCoords,ut);Xt.push(bt.topLeftX+bt.width/2),Xt.push(bt.topLeftY+bt.height/2)}else Xt.push(V[it].xCoords[St]),Xt.push(V[it].yCoords[St]);if(xt.isParent()){var Ht=t.calcBoundingBox(xt,V[it].xCoords,V[it].yCoords,ut);Ut.push(Ht.topLeftX+Ht.width/2),Ut.push(Ht.topLeftY+Ht.height/2)}else Ut.push(V[it].xCoords[Vt]),Ut.push(V[it].yCoords[Vt]);Tt.edges.push({startX:Xt[0],startY:Xt[1],endX:Ut[0],endY:Ut[1]})}else Q[it][mt.id()]&&Q[it][xt.id()]&&Tt.edges.push({startX:Q[it][mt.id()].getCenterX(),startY:Q[it][mt.id()].getCenterY(),endX:Q[it][xt.id()].getCenterX(),endY:Q[it][xt.id()].getCenterY()})}),Tt.nodes.length>0&&(X.push(Tt),O.add(it))}});var _=m.packComponents(X,M.randomize).shifts;if(M.quality=="draft")V.forEach(function(vt,it){var ut=vt.xCoords.map(function(At){return At+_[it].dx}),Tt=vt.yCoords.map(function(At){return At+_[it].dy});vt.xCoords=ut,vt.yCoords=Tt});else{var lt=0;O.forEach(function(vt){Object.keys(Q[vt]).forEach(function(it){var ut=Q[vt][it];ut.setCenter(ut.getCenterX()+_[lt].dx,ut.getCenterY()+_[lt].dy)}),lt++})}}}else{var E=M.eles.boundingBox();if(rt.push({x:E.x1+E.w/2,y:E.y1+E.h/2}),M.randomize){var p=o(M);V.push(p)}M.quality=="default"||M.quality=="proof"?(Q.push(l(M,V[0])),t.relocateComponent(rt[0],Q[0],M)):t.relocateComponent(rt[0],V[0],M)}var q=function(it,ut){if(M.quality=="default"||M.quality=="proof"){typeof it=="number"&&(it=ut);var Tt=void 0,At=void 0,Dt=it.data("id");return Q.forEach(function(xt){Dt in xt&&(Tt={x:xt[Dt].getRect().getCenterX(),y:xt[Dt].getRect().getCenterY()},At=xt[Dt])}),M.nodeDimensionsIncludeLabels&&(At.labelWidth&&(At.labelPosHorizontal=="left"?Tt.x+=At.labelWidth/2:At.labelPosHorizontal=="right"&&(Tt.x-=At.labelWidth/2)),At.labelHeight&&(At.labelPosVertical=="top"?Tt.y+=At.labelHeight/2:At.labelPosVertical=="bottom"&&(Tt.y-=At.labelHeight/2))),Tt==null&&(Tt={x:it.position("x"),y:it.position("y")}),{x:Tt.x,y:Tt.y}}else{var mt=void 0;return V.forEach(function(xt){var St=xt.nodeIndexes.get(it.id());St!=null&&(mt={x:xt.xCoords[St],y:xt.yCoords[St]})}),mt==null&&(mt={x:it.position("x"),y:it.position("y")}),{x:mt.x,y:mt.y}}};if(M.quality=="default"||M.quality=="proof"||M.randomize){var Rt=t.calcParentsWithoutChildren(P,J),Lt=J.filter(function(vt){return vt.css("display")=="none"});M.eles=J.not(Lt),J.nodes().not(":parent").not(Lt).layoutPositions(F,M,q),Rt.length>0&&Rt.forEach(function(vt){vt.position(q(vt))})}else console.log("If randomize option is set to false, then quality option must be 'default' or 'proof'.")}}]),d}();i.exports=u},657:(i,r,e)=>{var f=e(548),a=e(140).layoutBase.Matrix,y=e(140).layoutBase.SVD,t=function(o){var c=o.cy,l=o.eles,T=l.nodes(),u=l.nodes(":parent"),d=new Map,L=new Map,F=new Map,M=[],P=[],J=[],V=[],Q=[],D=[],rt=[],n=[],m=void 0,v=1e8,E=1e-9,p=o.piTol,I=o.samplingType,w=o.nodeSeparation,R=void 0,H=function(){for(var b=0,$=0,K=!1;$=at;){ot=Z[at++];for(var It=M[ot],ft=0;ftdt&&(dt=Q[Ct],wt=Ct)}return wt},k=function(b){var $=void 0;if(b){$=Math.floor(Math.random()*m);for(var Z=0;Z=1)break;j=tt}for(var yt=0;yt=1)break;j=tt}for(var ft=0;ft0&&($.isParent()?M[b].push(F.get($.id())):M[b].push($.id()))})});var Lt=function(b){var $=L.get(b),K=void 0;d.get(b).forEach(function(Z){c.getElementById(Z).isParent()?K=F.get(Z):K=Z,M[$].push(K),M[L.get(K)].push(b)})},vt=!0,it=!1,ut=void 0;try{for(var Tt=d.keys()[Symbol.iterator](),At;!(vt=(At=Tt.next()).done);vt=!0){var Dt=At.value;Lt(Dt)}}catch(S){it=!0,ut=S}finally{try{!vt&&Tt.return&&Tt.return()}finally{if(it)throw ut}}m=L.size;var mt=void 0;if(m>2){R=m{var f=e(212),a=function(t){t&&t("layout","fcose",f)};typeof cytoscape<"u"&&a(cytoscape),i.exports=a},140:i=>{i.exports=A}},N={};function g(i){var r=N[i];if(r!==void 0)return r.exports;var e=N[i]={exports:{}};return G[i](e,e.exports,g),e.exports}var s=g(579);return s})()})})(be);var gr=be.exports;const ur=ke(gr);var xe={L:"left",R:"right",T:"top",B:"bottom"},Ie={L:nt(C=>`${C},${C/2} 0,${C} 0,0`,"L"),R:nt(C=>`0,${C/2} ${C},0 ${C},${C}`,"R"),T:nt(C=>`0,0 ${C},0 ${C/2},${C}`,"T"),B:nt(C=>`${C/2},0 ${C},${C} 0,${C}`,"B")},he={L:nt((C,Y)=>C-Y+2,"L"),R:nt((C,Y)=>C-2,"R"),T:nt((C,Y)=>C-Y+2,"T"),B:nt((C,Y)=>C-2,"B")},dr=nt(function(C){return zt(C)?C==="L"?"R":"L":C==="T"?"B":"T"},"getOppositeArchitectureDirection"),Re=nt(function(C){const Y=C;return Y==="L"||Y==="R"||Y==="T"||Y==="B"},"isArchitectureDirection"),zt=nt(function(C){const Y=C;return Y==="L"||Y==="R"},"isArchitectureDirectionX"),Qt=nt(function(C){const Y=C;return Y==="T"||Y==="B"},"isArchitectureDirectionY"),Pe=nt(function(C,Y){const A=zt(C)&&Qt(Y),G=Qt(C)&&zt(Y);return A||G},"isArchitectureDirectionXY"),vr=nt(function(C){const Y=C[0],A=C[1],G=zt(Y)&&Qt(A),N=Qt(Y)&&zt(A);return G||N},"isArchitecturePairXY"),pr=nt(function(C){return C!=="LL"&&C!=="RR"&&C!=="TT"&&C!=="BB"},"isValidArchitectureDirectionPair"),me=nt(function(C,Y){const A=`${C}${Y}`;return pr(A)?A:void 0},"getArchitectureDirectionPair"),yr=nt(function([C,Y],A){const G=A[0],N=A[1];return zt(G)?Qt(N)?[C+(G==="L"?-1:1),Y+(N==="T"?1:-1)]:[C+(G==="L"?-1:1),Y]:zt(N)?[C+(N==="L"?1:-1),Y+(G==="T"?1:-1)]:[C,Y+(G==="T"?1:-1)]},"shiftPositionByArchitectureDirectionPair"),Er=nt(function(C){return C==="LT"||C==="TL"?[1,1]:C==="BL"||C==="LB"?[1,-1]:C==="BR"||C==="RB"?[-1,-1]:[-1,1]},"getArchitectureDirectionXYFactors"),mr=nt(function(C){return C.type==="service"},"isArchitectureService"),Tr=nt(function(C){return C.type==="junction"},"isArchitectureJunction"),Ge=nt(C=>C.data(),"edgeData"),ne=nt(C=>C.data(),"nodeData"),Ue=qe.architecture,pt=new hr(()=>({nodes:{},groups:{},edges:[],registeredIds:{},config:Ue,dataStructures:void 0,elements:{}})),Nr=nt(()=>{pt.reset(),ar()},"clear"),Lr=nt(function({id:C,icon:Y,in:A,title:G,iconText:N}){if(pt.records.registeredIds[C]!==void 0)throw new Error(`The service id [${C}] is already in use by another ${pt.records.registeredIds[C]}`);if(A!==void 0){if(C===A)throw new Error(`The service [${C}] cannot be placed within itself`);if(pt.records.registeredIds[A]===void 0)throw new Error(`The service [${C}]'s parent does not exist. Please make sure the parent is created before this service`);if(pt.records.registeredIds[A]==="node")throw new Error(`The service [${C}]'s parent is not a group`)}pt.records.registeredIds[C]="node",pt.records.nodes[C]={id:C,type:"service",icon:Y,iconText:N,title:G,edges:[],in:A}},"addService"),Cr=nt(()=>Object.values(pt.records.nodes).filter(mr),"getServices"),Mr=nt(function({id:C,in:Y}){pt.records.registeredIds[C]="node",pt.records.nodes[C]={id:C,type:"junction",edges:[],in:Y}},"addJunction"),Ar=nt(()=>Object.values(pt.records.nodes).filter(Tr),"getJunctions"),wr=nt(()=>Object.values(pt.records.nodes),"getNodes"),Or=nt(C=>pt.records.nodes[C],"getNode"),Dr=nt(function({id:C,icon:Y,in:A,title:G}){if(pt.records.registeredIds[C]!==void 0)throw new Error(`The group id [${C}] is already in use by another ${pt.records.registeredIds[C]}`);if(A!==void 0){if(C===A)throw new Error(`The group [${C}] cannot be placed within itself`);if(pt.records.registeredIds[A]===void 0)throw new Error(`The group [${C}]'s parent does not exist. Please make sure the parent is created before this group`);if(pt.records.registeredIds[A]==="node")throw new Error(`The group [${C}]'s parent is not a group`)}pt.records.registeredIds[C]="group",pt.records.groups[C]={id:C,icon:Y,title:G,in:A}},"addGroup"),xr=nt(()=>Object.values(pt.records.groups),"getGroups"),Ir=nt(function({lhsId:C,rhsId:Y,lhsDir:A,rhsDir:G,lhsInto:N,rhsInto:g,lhsGroup:s,rhsGroup:i,title:r}){if(!Re(A))throw new Error(`Invalid direction given for left hand side of edge ${C}--${Y}. Expected (L,R,T,B) got ${A}`);if(!Re(G))throw new Error(`Invalid direction given for right hand side of edge ${C}--${Y}. Expected (L,R,T,B) got ${G}`);if(pt.records.nodes[C]===void 0&&pt.records.groups[C]===void 0)throw new Error(`The left-hand id [${C}] does not yet exist. Please create the service/group before declaring an edge to it.`);if(pt.records.nodes[Y]===void 0&&pt.records.groups[C]===void 0)throw new Error(`The right-hand id [${Y}] does not yet exist. Please create the service/group before declaring an edge to it.`);const e=pt.records.nodes[C].in,f=pt.records.nodes[Y].in;if(s&&e&&f&&e==f)throw new Error(`The left-hand id [${C}] is modified to traverse the group boundary, but the edge does not pass through two groups.`);if(i&&e&&f&&e==f)throw new Error(`The right-hand id [${Y}] is modified to traverse the group boundary, but the edge does not pass through two groups.`);const a={lhsId:C,lhsDir:A,lhsInto:N,lhsGroup:s,rhsId:Y,rhsDir:G,rhsInto:g,rhsGroup:i,title:r};pt.records.edges.push(a),pt.records.nodes[C]&&pt.records.nodes[Y]&&(pt.records.nodes[C].edges.push(pt.records.edges[pt.records.edges.length-1]),pt.records.nodes[Y].edges.push(pt.records.edges[pt.records.edges.length-1]))},"addEdge"),Rr=nt(()=>pt.records.edges,"getEdges"),Sr=nt(()=>{if(pt.records.dataStructures===void 0){const C=Object.entries(pt.records.nodes).reduce((s,[i,r])=>(s[i]=r.edges.reduce((e,f)=>{if(f.lhsId===i){const a=me(f.lhsDir,f.rhsDir);a&&(e[a]=f.rhsId)}else{const a=me(f.rhsDir,f.lhsDir);a&&(e[a]=f.lhsId)}return e},{}),s),{}),Y=Object.keys(C)[0],A={[Y]:1},G=Object.keys(C).reduce((s,i)=>i===Y?s:{...s,[i]:1},{}),N=nt(s=>{const i={[s]:[0,0]},r=[s];for(;r.length>0;){const e=r.shift();if(e){A[e]=1,delete G[e];const f=C[e],[a,y]=i[e];Object.entries(f).forEach(([t,h])=>{A[h]||(i[h]=yr([a,y],t),r.push(h))})}}return i},"BFS"),g=[N(Y)];for(;Object.keys(G).length>0;)g.push(N(Object.keys(G)[0]));pt.records.dataStructures={adjList:C,spatialMaps:g}}return pt.records.dataStructures},"getDataStructures"),Fr=nt((C,Y)=>{pt.records.elements[C]=Y},"setElementForId"),br=nt(C=>pt.records.elements[C],"getElementById"),le={clear:Nr,setDiagramTitle:Ke,getDiagramTitle:je,setAccTitle:_e,getAccTitle:tr,setAccDescription:er,getAccDescription:rr,addService:Lr,getServices:Cr,addJunction:Mr,getJunctions:Ar,getNodes:wr,getNode:Or,addGroup:Dr,getGroups:xr,addEdge:Ir,getEdges:Rr,setElementForId:Fr,getElementById:br,getDataStructures:Sr};function Pt(C){const Y=fe().architecture;return Y!=null&&Y[C]?Y[C]:Ue[C]}nt(Pt,"getConfigField");var Pr=nt((C,Y)=>{sr(C,Y),C.groups.map(Y.addGroup),C.services.map(A=>Y.addService({...A,type:"service"})),C.junctions.map(A=>Y.addJunction({...A,type:"junction"})),C.edges.map(Y.addEdge)},"populateDb"),Gr={parse:nt(async C=>{const Y=await lr("architecture",C);Se.debug(Y),Pr(Y,le)},"parse")},Ur=nt(C=>` .edge { stroke-width: ${C.archEdgeWidth}; stroke: ${C.archEdgeColor}; diff --git a/assets/basePickBy-Cyiz-f_r.js b/assets/basePickBy-BMIT5f2S.js similarity index 94% rename from assets/basePickBy-Cyiz-f_r.js rename to assets/basePickBy-BMIT5f2S.js index fd2f7fde3..1df7568d4 100644 --- a/assets/basePickBy-Cyiz-f_r.js +++ b/assets/basePickBy-BMIT5f2S.js @@ -1 +1 @@ -import{e as I,c as l,g as m,k as N,j as P,l as A,m as M,n as b,t as p,o as w}from"./baseUniq-j141U2p6.js";import{aK as g,ay as E,aL as F,aM as _,aN as B,aO as o,aP as S,aQ as T,aR as c,aS as L}from"./mermaid.core-IUatkdtb.js";var R=/\s/;function $(n){for(var r=n.length;r--&&R.test(n.charAt(r)););return r}var G=/^\s+/;function K(n){return n&&n.slice(0,$(n)+1).replace(G,"")}var x=NaN,q=/^[-+]0x[0-9a-f]+$/i,y=/^0b[01]+$/i,z=/^0o[0-7]+$/i,C=parseInt;function H(n){if(typeof n=="number")return n;if(I(n))return x;if(g(n)){var r=typeof n.valueOf=="function"?n.valueOf():n;n=g(r)?r+"":r}if(typeof n!="string")return n===0?n:+n;n=K(n);var t=y.test(n);return t||z.test(n)?C(n.slice(2),t?2:8):q.test(n)?x:+n}var v=1/0,Q=17976931348623157e292;function W(n){if(!n)return n===0?n:0;if(n=H(n),n===v||n===-v){var r=n<0?-1:1;return r*Q}return n===n?n:0}function X(n){var r=W(n),t=r%1;return r===r?t?r-t:r:0}function tn(n){var r=n==null?0:n.length;return r?l(n):[]}var O=Object.prototype,Y=O.hasOwnProperty,an=E(function(n,r){n=Object(n);var t=-1,e=r.length,i=e>2?r[2]:void 0;for(i&&F(r[0],r[1],i)&&(e=1);++t-1?i[f?r[a]:a]:void 0}}var J=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=J(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=S(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 J=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=J(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=S(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 H(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 H(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 i,a as s,b as e,d as n,w as d,e as p}from"./app-Dp4t6tDQ.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/blackhole.html-BFJc9_Nr.js b/assets/blackhole.html-DfpkkgPY.js
similarity index 97%
rename from assets/blackhole.html-BFJc9_Nr.js
rename to assets/blackhole.html-DfpkkgPY.js
index 39034a3a3..c325333b0 100644
--- a/assets/blackhole.html-BFJc9_Nr.js
+++ b/assets/blackhole.html-DfpkkgPY.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-BClOOpdM.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-Dp4t6tDQ.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-XOKhneJi.js b/assets/blackhole.html-Dm6vb_2V.js
similarity index 98%
rename from assets/blackhole.html-XOKhneJi.js
rename to assets/blackhole.html-Dm6vb_2V.js
index 3d7e5df92..d618e0fac 100644
--- a/assets/blackhole.html-XOKhneJi.js
+++ b/assets/blackhole.html-Dm6vb_2V.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-BClOOpdM.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-Dp4t6tDQ.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/blockDiagram-EN3ZKWFM-aV_THrNU.js b/assets/blockDiagram-EN3ZKWFM-ypLrqQ_-.js
similarity index 99%
rename from assets/blockDiagram-EN3ZKWFM-aV_THrNU.js
rename to assets/blockDiagram-EN3ZKWFM-ypLrqQ_-.js
index 139f1fa70..34ea43082 100644
--- a/assets/blockDiagram-EN3ZKWFM-aV_THrNU.js
+++ b/assets/blockDiagram-EN3ZKWFM-ypLrqQ_-.js
@@ -1,4 +1,4 @@
-import{a as Re,i as Be,p as ke,m as Pe}from"./chunk-UGV5ZQQN-BxKEe51B.js";import{i as xe,p as Fe}from"./chunk-YWFND7JV-CtqGT_XT.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-IUatkdtb.js";import{c as je}from"./clone-DBEsGdWr.js";import{G as Ue}from"./graph-CKGFjaQu.js";import{c as Xe}from"./channel-C9cXYHlc.js";import"./app-BClOOpdM.js";import"./baseUniq-j141U2p6.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-UGV5ZQQN-B0KztNbp.js";import{i as xe,p as Fe}from"./chunk-YWFND7JV-DqutOh5-.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-VsNG6kTl.js";import{c as je}from"./clone-CyxiHGLh.js";import{G as Ue}from"./graph-DebN9_Dg.js";import{c as Xe}from"./channel-Bqz4IE8G.js";import"./app-Dp4t6tDQ.js";import"./baseUniq-Bpwj4IW2.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-CB_B_9rS.js b/assets/browser_dialer.html-9mg-S3B0.js
similarity index 99%
rename from assets/browser_dialer.html-CB_B_9rS.js
rename to assets/browser_dialer.html-9mg-S3B0.js
index 7b0a3fef2..532c76822 100644
--- a/assets/browser_dialer.html-CB_B_9rS.js
+++ b/assets/browser_dialer.html-9mg-S3B0.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-BClOOpdM.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-Dp4t6tDQ.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-Kq-_Dh1k.js b/assets/browser_dialer.html-DPoLLonb.js similarity index 98% rename from assets/browser_dialer.html-Kq-_Dh1k.js rename to assets/browser_dialer.html-DPoLLonb.js index 600975148..c788f42ef 100644 --- a/assets/browser_dialer.html-Kq-_Dh1k.js +++ b/assets/browser_dialer.html-DPoLLonb.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-BClOOpdM.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-Dp4t6tDQ.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-BHxcHS_p.js b/assets/browser_dialer.html-TLjtzU25.js similarity index 99% rename from assets/browser_dialer.html-BHxcHS_p.js rename to assets/browser_dialer.html-TLjtzU25.js index 740f5288e..977a7b5f2 100644 --- a/assets/browser_dialer.html-BHxcHS_p.js +++ b/assets/browser_dialer.html-TLjtzU25.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-BClOOpdM.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-Dp4t6tDQ.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-THADGKDP-BrQI6Wg6.js b/assets/c4Diagram-THADGKDP-BV0ojTgT.js similarity index 99% rename from assets/c4Diagram-THADGKDP-BrQI6Wg6.js rename to assets/c4Diagram-THADGKDP-BV0ojTgT.js index c8f578aa3..9e4bd8391 100644 --- a/assets/c4Diagram-THADGKDP-BrQI6Wg6.js +++ b/assets/c4Diagram-THADGKDP-BV0ojTgT.js @@ -1,4 +1,4 @@ -import{d as Se,g as De}from"./chunk-XVOYOM2C-fmD0yIZV.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-IUatkdtb.js";import"./app-BClOOpdM.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-XVOYOM2C-BZTXkaha.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-VsNG6kTl.js";import"./app-Dp4t6tDQ.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-DQT8PYpt.js b/assets/ch01-preface.html-C0a0dqvP.js similarity index 99% rename from assets/ch01-preface.html-DQT8PYpt.js rename to assets/ch01-preface.html-C0a0dqvP.js index a8a9c3a11..9221ab133 100644 --- a/assets/ch01-preface.html-DQT8PYpt.js +++ b/assets/ch01-preface.html-C0a0dqvP.js @@ -1 +1 @@ -import{_ as s,r as o,o as p,c as a,a as r,e as t}from"./app-BClOOpdM.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-Dp4t6tDQ.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-Cb_Ov8Tj.js b/assets/ch01-preface.html-D77cA9Yz.js similarity index 99% rename from assets/ch01-preface.html-Cb_Ov8Tj.js rename to assets/ch01-preface.html-D77cA9Yz.js index c4de4a142..58ef417b7 100644 --- a/assets/ch01-preface.html-Cb_Ov8Tj.js +++ b/assets/ch01-preface.html-D77cA9Yz.js @@ -1 +1 @@ -import{_ as s,r as a,o as n,c as o,a as r,e}from"./app-BClOOpdM.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-Dp4t6tDQ.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-N4amw0Ox.js b/assets/ch01-preface.html-DlvnkN2h.js similarity index 99% rename from assets/ch01-preface.html-N4amw0Ox.js rename to assets/ch01-preface.html-DlvnkN2h.js index ab2e28aae..459684cd7 100644 --- a/assets/ch01-preface.html-N4amw0Ox.js +++ b/assets/ch01-preface.html-DlvnkN2h.js @@ -1 +1 @@ -import{_ as t,r as o,o as i,c as n,a,e as s}from"./app-BClOOpdM.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-Dp4t6tDQ.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-_Og0J-0X.js b/assets/ch02-preparation.html-B8tpsGb2.js similarity index 98% rename from assets/ch02-preparation.html-_Og0J-0X.js rename to assets/ch02-preparation.html-B8tpsGb2.js index e3f88d4ba..89e62cfa2 100644 --- a/assets/ch02-preparation.html-_Og0J-0X.js +++ b/assets/ch02-preparation.html-B8tpsGb2.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-BClOOpdM.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-Dp4t6tDQ.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/ch02-preparation.html-BNLBNj5J.js b/assets/ch02-preparation.html-BTFVBYnb.js similarity index 99% rename from assets/ch02-preparation.html-BNLBNj5J.js rename to assets/ch02-preparation.html-BTFVBYnb.js index 01ef97968..075d550cd 100644 --- a/assets/ch02-preparation.html-BNLBNj5J.js +++ b/assets/ch02-preparation.html-BTFVBYnb.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-BClOOpdM.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-Dp4t6tDQ.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-Cf5azvGS.js b/assets/ch02-preparation.html-COiMyrPE.js similarity index 98% rename from assets/ch02-preparation.html-Cf5azvGS.js rename to assets/ch02-preparation.html-COiMyrPE.js index 817063db5..4a9f6351c 100644 --- a/assets/ch02-preparation.html-Cf5azvGS.js +++ b/assets/ch02-preparation.html-COiMyrPE.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-BClOOpdM.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-Dp4t6tDQ.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/ch03-ssh.html-DTz6D2Rh.js b/assets/ch03-ssh.html-BOqQ3pux.js similarity index 99% rename from assets/ch03-ssh.html-DTz6D2Rh.js rename to assets/ch03-ssh.html-BOqQ3pux.js index 861973f40..8d77077f8 100644 --- a/assets/ch03-ssh.html-DTz6D2Rh.js +++ b/assets/ch03-ssh.html-BOqQ3pux.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-BClOOpdM.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-Dp4t6tDQ.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-B2d2lltd.js b/assets/ch03-ssh.html-CBC8l8gj.js similarity index 99% rename from assets/ch03-ssh.html-B2d2lltd.js rename to assets/ch03-ssh.html-CBC8l8gj.js index 703166fe7..f7cc488ef 100644 --- a/assets/ch03-ssh.html-B2d2lltd.js +++ b/assets/ch03-ssh.html-CBC8l8gj.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-BClOOpdM.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-Dp4t6tDQ.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-BBlWjSPH.js b/assets/ch03-ssh.html-DMelmJ53.js similarity index 99% rename from assets/ch03-ssh.html-BBlWjSPH.js rename to assets/ch03-ssh.html-DMelmJ53.js index a73ee8c0b..28456f6cc 100644 --- a/assets/ch03-ssh.html-BBlWjSPH.js +++ b/assets/ch03-ssh.html-DMelmJ53.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-BClOOpdM.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-Dp4t6tDQ.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-_r_wrIQN.js b/assets/ch04-security.html-CKLdMMrq.js similarity index 99% rename from assets/ch04-security.html-_r_wrIQN.js rename to assets/ch04-security.html-CKLdMMrq.js index 02db2ef0b..3112e2318 100644 --- a/assets/ch04-security.html-_r_wrIQN.js +++ b/assets/ch04-security.html-CKLdMMrq.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-BClOOpdM.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-Dp4t6tDQ.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-C0QRw92W.js b/assets/ch04-security.html-CSWtjUmG.js
          similarity index 99%
          rename from assets/ch04-security.html-C0QRw92W.js
          rename to assets/ch04-security.html-CSWtjUmG.js
          index c7db86f3b..006d4f8c5 100644
          --- a/assets/ch04-security.html-C0QRw92W.js
          +++ b/assets/ch04-security.html-CSWtjUmG.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-BClOOpdM.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-Dp4t6tDQ.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-DtoTR_GG.js b/assets/ch04-security.html-lWMkPygX.js
          similarity index 99%
          rename from assets/ch04-security.html-DtoTR_GG.js
          rename to assets/ch04-security.html-lWMkPygX.js
          index 6a5827b73..b7af1d60c 100644
          --- a/assets/ch04-security.html-DtoTR_GG.js
          +++ b/assets/ch04-security.html-lWMkPygX.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-BClOOpdM.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-Dp4t6tDQ.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-BFDR3pBN.js b/assets/ch05-webpage.html-BFGvmjSO.js
              similarity index 99%
              rename from assets/ch05-webpage.html-BFDR3pBN.js
              rename to assets/ch05-webpage.html-BFGvmjSO.js
              index 5ef4834de..e8f4d77cd 100644
              --- a/assets/ch05-webpage.html-BFDR3pBN.js
              +++ b/assets/ch05-webpage.html-BFGvmjSO.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-BClOOpdM.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-Dp4t6tDQ.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-Dt_H9ckT.js b/assets/ch05-webpage.html-C9hDniXJ.js
                  similarity index 99%
                  rename from assets/ch05-webpage.html-Dt_H9ckT.js
                  rename to assets/ch05-webpage.html-C9hDniXJ.js
                  index c0c3c94af..06e7c38ed 100644
                  --- a/assets/ch05-webpage.html-Dt_H9ckT.js
                  +++ b/assets/ch05-webpage.html-C9hDniXJ.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-BClOOpdM.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-Dp4t6tDQ.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-BP0EdKmB.js b/assets/ch05-webpage.html-Ttc51XZa.js
                      similarity index 99%
                      rename from assets/ch05-webpage.html-BP0EdKmB.js
                      rename to assets/ch05-webpage.html-Ttc51XZa.js
                      index 7e74bd1ef..6fc634891 100644
                      --- a/assets/ch05-webpage.html-BP0EdKmB.js
                      +++ b/assets/ch05-webpage.html-Ttc51XZa.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-BClOOpdM.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-Dp4t6tDQ.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-D-kQ9qhu.js b/assets/ch06-certificates.html-DTfFRe9A.js
                          similarity index 99%
                          rename from assets/ch06-certificates.html-D-kQ9qhu.js
                          rename to assets/ch06-certificates.html-DTfFRe9A.js
                          index 0bcad96d4..444723756 100644
                          --- a/assets/ch06-certificates.html-D-kQ9qhu.js
                          +++ b/assets/ch06-certificates.html-DTfFRe9A.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-BClOOpdM.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-Dp4t6tDQ.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-BmShiB5T.js b/assets/ch06-certificates.html-GiWXSBdk.js
                              similarity index 99%
                              rename from assets/ch06-certificates.html-BmShiB5T.js
                              rename to assets/ch06-certificates.html-GiWXSBdk.js
                              index 4fb43aace..fa1850ef1 100644
                              --- a/assets/ch06-certificates.html-BmShiB5T.js
                              +++ b/assets/ch06-certificates.html-GiWXSBdk.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-BClOOpdM.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-Dp4t6tDQ.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/ch06-certificates.html-hZw22qFC.js b/assets/ch06-certificates.html-R61iRZQr.js
                                  similarity index 99%
                                  rename from assets/ch06-certificates.html-hZw22qFC.js
                                  rename to assets/ch06-certificates.html-R61iRZQr.js
                                  index 17dc9374f..9b659b51b 100644
                                  --- a/assets/ch06-certificates.html-hZw22qFC.js
                                  +++ b/assets/ch06-certificates.html-R61iRZQr.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-BClOOpdM.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-Dp4t6tDQ.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/ch07-xray-server.html-C8PxlQdU.js b/assets/ch07-xray-server.html-9lLGK84R.js
                                  similarity index 99%
                                  rename from assets/ch07-xray-server.html-C8PxlQdU.js
                                  rename to assets/ch07-xray-server.html-9lLGK84R.js
                                  index 31f2950e2..e753bcb12 100644
                                  --- a/assets/ch07-xray-server.html-C8PxlQdU.js
                                  +++ b/assets/ch07-xray-server.html-9lLGK84R.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-BClOOpdM.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-Dp4t6tDQ.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/ch07-xray-server.html-grk6pMf0.js b/assets/ch07-xray-server.html-CDn-775a.js
                                  similarity index 99%
                                  rename from assets/ch07-xray-server.html-grk6pMf0.js
                                  rename to assets/ch07-xray-server.html-CDn-775a.js
                                  index 1d29a0579..a29ff806c 100644
                                  --- a/assets/ch07-xray-server.html-grk6pMf0.js
                                  +++ b/assets/ch07-xray-server.html-CDn-775a.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-BClOOpdM.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-Dp4t6tDQ.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-Jl0JVjmz.js b/assets/ch07-xray-server.html-CeBPCvns.js
                                    similarity index 99%
                                    rename from assets/ch07-xray-server.html-Jl0JVjmz.js
                                    rename to assets/ch07-xray-server.html-CeBPCvns.js
                                    index a58468c67..1953c9986 100644
                                    --- a/assets/ch07-xray-server.html-Jl0JVjmz.js
                                    +++ b/assets/ch07-xray-server.html-CeBPCvns.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-BClOOpdM.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-Dp4t6tDQ.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/ch08-xray-clients.html-CmT1Ytes.js b/assets/ch08-xray-clients.html-4HRoOenM.js
                                      similarity index 99%
                                      rename from assets/ch08-xray-clients.html-CmT1Ytes.js
                                      rename to assets/ch08-xray-clients.html-4HRoOenM.js
                                      index 765431341..7ef82cf3f 100644
                                      --- a/assets/ch08-xray-clients.html-CmT1Ytes.js
                                      +++ b/assets/ch08-xray-clients.html-4HRoOenM.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-BClOOpdM.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-Dp4t6tDQ.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-BGGs_7Co.js b/assets/ch08-xray-clients.html-CEOoUra3.js
                                      similarity index 99%
                                      rename from assets/ch08-xray-clients.html-BGGs_7Co.js
                                      rename to assets/ch08-xray-clients.html-CEOoUra3.js
                                      index 1a3be0c69..62daeacd5 100644
                                      --- a/assets/ch08-xray-clients.html-BGGs_7Co.js
                                      +++ b/assets/ch08-xray-clients.html-CEOoUra3.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-BClOOpdM.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-Dp4t6tDQ.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-C8H6XK9U.js b/assets/ch08-xray-clients.html-DLNDZslA.js
                                      similarity index 99%
                                      rename from assets/ch08-xray-clients.html-C8H6XK9U.js
                                      rename to assets/ch08-xray-clients.html-DLNDZslA.js
                                      index 97a2a7dca..300316150 100644
                                      --- a/assets/ch08-xray-clients.html-C8H6XK9U.js
                                      +++ b/assets/ch08-xray-clients.html-DLNDZslA.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-BClOOpdM.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-Dp4t6tDQ.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-Df8p5LWP.js b/assets/ch09-appendix.html-Bfj0ily0.js
                                      similarity index 99%
                                      rename from assets/ch09-appendix.html-Df8p5LWP.js
                                      rename to assets/ch09-appendix.html-Bfj0ily0.js
                                      index 2a298c5b2..fbcd00689 100644
                                      --- a/assets/ch09-appendix.html-Df8p5LWP.js
                                      +++ b/assets/ch09-appendix.html-Bfj0ily0.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-BClOOpdM.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-Dp4t6tDQ.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-Ct0MNjdR.js b/assets/ch09-appendix.html-CozFZEJT.js
                                      similarity index 99%
                                      rename from assets/ch09-appendix.html-Ct0MNjdR.js
                                      rename to assets/ch09-appendix.html-CozFZEJT.js
                                      index 7992c6b55..53c907282 100644
                                      --- a/assets/ch09-appendix.html-Ct0MNjdR.js
                                      +++ b/assets/ch09-appendix.html-CozFZEJT.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-BClOOpdM.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-Dp4t6tDQ.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/ch09-appendix.html-lyRlTtzf.js b/assets/ch09-appendix.html-Dxssa-41.js
                                      similarity index 99%
                                      rename from assets/ch09-appendix.html-lyRlTtzf.js
                                      rename to assets/ch09-appendix.html-Dxssa-41.js
                                      index 9b23311b3..e79519e82 100644
                                      --- a/assets/ch09-appendix.html-lyRlTtzf.js
                                      +++ b/assets/ch09-appendix.html-Dxssa-41.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-BClOOpdM.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-Dp4t6tDQ.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/channel-Bqz4IE8G.js b/assets/channel-Bqz4IE8G.js
                                      new file mode 100644
                                      index 000000000..50aa94481
                                      --- /dev/null
                                      +++ b/assets/channel-Bqz4IE8G.js
                                      @@ -0,0 +1 @@
                                      +import{U as a,E as n}from"./mermaid.core-VsNG6kTl.js";const t=(r,o)=>a.lang.round(n.parse(r)[o]);export{t as c};
                                      diff --git a/assets/channel-C9cXYHlc.js b/assets/channel-C9cXYHlc.js
                                      deleted file mode 100644
                                      index 5a5a2517c..000000000
                                      --- a/assets/channel-C9cXYHlc.js
                                      +++ /dev/null
                                      @@ -1 +0,0 @@
                                      -import{U as a,E as n}from"./mermaid.core-IUatkdtb.js";const t=(r,o)=>a.lang.round(n.parse(r)[o]);export{t as c};
                                      diff --git a/assets/chunk-2JBRQKJ5-BMSx-IbG.js b/assets/chunk-2JBRQKJ5-c3I5MwZ1.js
                                      similarity index 99%
                                      rename from assets/chunk-2JBRQKJ5-BMSx-IbG.js
                                      rename to assets/chunk-2JBRQKJ5-c3I5MwZ1.js
                                      index 47093f996..7e7a5a3fd 100644
                                      --- a/assets/chunk-2JBRQKJ5-BMSx-IbG.js
                                      +++ b/assets/chunk-2JBRQKJ5-c3I5MwZ1.js
                                      @@ -1,4 +1,4 @@
                                      -import{g as De,s as Ce}from"./chunk-DUMQOTYW-Bze3ZeWr.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-IUatkdtb.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-DUMQOTYW-Bi8JUtJi.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-VsNG6kTl.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-2RYQ3QTB-U6oRI5CH.js b/assets/chunk-2RYQ3QTB-8PgX7ysJ.js
                                      similarity index 66%
                                      rename from assets/chunk-2RYQ3QTB-U6oRI5CH.js
                                      rename to assets/chunk-2RYQ3QTB-8PgX7ysJ.js
                                      index 272cebeff..aa04f86e2 100644
                                      --- a/assets/chunk-2RYQ3QTB-U6oRI5CH.js
                                      +++ b/assets/chunk-2RYQ3QTB-8PgX7ysJ.js
                                      @@ -1 +1 @@
                                      -import{_ as s}from"./mermaid.core-IUatkdtb.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-VsNG6kTl.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-BAVOGKFW-B2dDM16w.js b/assets/chunk-BAVOGKFW-DK_Q78_U.js
                                      similarity index 99%
                                      rename from assets/chunk-BAVOGKFW-B2dDM16w.js
                                      rename to assets/chunk-BAVOGKFW-DK_Q78_U.js
                                      index 6708adc9e..0ff1d8a55 100644
                                      --- a/assets/chunk-BAVOGKFW-B2dDM16w.js
                                      +++ b/assets/chunk-BAVOGKFW-DK_Q78_U.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-IUatkdtb.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-VsNG6kTl.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-DUMQOTYW-Bze3ZeWr.js b/assets/chunk-DUMQOTYW-Bi8JUtJi.js
                                      similarity index 90%
                                      rename from assets/chunk-DUMQOTYW-Bze3ZeWr.js
                                      rename to assets/chunk-DUMQOTYW-Bi8JUtJi.js
                                      index b8ce915d5..1f0838133 100644
                                      --- a/assets/chunk-DUMQOTYW-Bze3ZeWr.js
                                      +++ b/assets/chunk-DUMQOTYW-Bi8JUtJi.js
                                      @@ -1 +1 @@
                                      -import{_ as n,j as r,k as g,l as d}from"./mermaid.core-IUatkdtb.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);g(t,s,a,i);const c=w(h,x,a,s,e);t.attr("viewBox",c),d.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 g,l as d}from"./mermaid.core-VsNG6kTl.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);g(t,s,a,i);const c=w(h,x,a,s,e);t.attr("viewBox",c),d.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-OQCM5LHU-CGij_B7M.js b/assets/chunk-OQCM5LHU-Cbp36FHa.js
                                      similarity index 78%
                                      rename from assets/chunk-OQCM5LHU-CGij_B7M.js
                                      rename to assets/chunk-OQCM5LHU-Cbp36FHa.js
                                      index 0085a0102..79beea640 100644
                                      --- a/assets/chunk-OQCM5LHU-CGij_B7M.js
                                      +++ b/assets/chunk-OQCM5LHU-Cbp36FHa.js
                                      @@ -1 +1 @@
                                      -import{_ as l}from"./mermaid.core-IUatkdtb.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-VsNG6kTl.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-UGV5ZQQN-BxKEe51B.js b/assets/chunk-UGV5ZQQN-B0KztNbp.js
                                      similarity index 98%
                                      rename from assets/chunk-UGV5ZQQN-BxKEe51B.js
                                      rename to assets/chunk-UGV5ZQQN-B0KztNbp.js
                                      index b84bc04d2..9b199fa06 100644
                                      --- a/assets/chunk-UGV5ZQQN-BxKEe51B.js
                                      +++ b/assets/chunk-UGV5ZQQN-B0KztNbp.js
                                      @@ -1,4 +1,4 @@
                                      -import{a as y}from"./chunk-YWFND7JV-CtqGT_XT.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-IUatkdtb.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-YWFND7JV-DqutOh5-.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-VsNG6kTl.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-XVOYOM2C-fmD0yIZV.js b/assets/chunk-XVOYOM2C-BZTXkaha.js
                                      similarity index 95%
                                      rename from assets/chunk-XVOYOM2C-fmD0yIZV.js
                                      rename to assets/chunk-XVOYOM2C-BZTXkaha.js
                                      index 2d34be29c..444288154 100644
                                      --- a/assets/chunk-XVOYOM2C-fmD0yIZV.js
                                      +++ b/assets/chunk-XVOYOM2C-BZTXkaha.js
                                      @@ -1 +1 @@
                                      -import{_ as n,n as c,m as l}from"./mermaid.core-IUatkdtb.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-VsNG6kTl.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-YWFND7JV-CtqGT_XT.js b/assets/chunk-YWFND7JV-DqutOh5-.js
                                      similarity index 99%
                                      rename from assets/chunk-YWFND7JV-CtqGT_XT.js
                                      rename to assets/chunk-YWFND7JV-DqutOh5-.js
                                      index 36cb839f0..7569edd22 100644
                                      --- a/assets/chunk-YWFND7JV-CtqGT_XT.js
                                      +++ b/assets/chunk-YWFND7JV-DqutOh5-.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-IUatkdtb.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-VsNG6kTl.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-4BHYIK4I-a2lMBkUS.js b/assets/classDiagram-4BHYIK4I-DaH_u7n6.js similarity index 96% rename from assets/classDiagram-4BHYIK4I-a2lMBkUS.js rename to assets/classDiagram-4BHYIK4I-DaH_u7n6.js index e0b5d53a2..342fde2be 100644 --- a/assets/classDiagram-4BHYIK4I-a2lMBkUS.js +++ b/assets/classDiagram-4BHYIK4I-DaH_u7n6.js @@ -1,2 +1,2 @@ -import{c as G,a as N,s as I}from"./chunk-BAVOGKFW-B2dDM16w.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-IUatkdtb.js";import{G as Y}from"./graph-CKGFjaQu.js";import{l as $}from"./layout-Bmwgbrwx.js";import"./app-BClOOpdM.js";import"./baseUniq-j141U2p6.js";import"./basePickBy-Cyiz-f_r.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-BAVOGKFW-DK_Q78_U.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-VsNG6kTl.js";import{G as Y}from"./graph-DebN9_Dg.js";import{l as $}from"./layout-BkNI4twY.js";import"./app-Dp4t6tDQ.js";import"./baseUniq-Bpwj4IW2.js";import"./basePickBy-BMIT5f2S.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-FI7KE7WJ-Cv9pEPw6.js b/assets/classDiagram-v2-FI7KE7WJ-CbLiwjWK.js similarity index 96% rename from assets/classDiagram-v2-FI7KE7WJ-Cv9pEPw6.js rename to assets/classDiagram-v2-FI7KE7WJ-CbLiwjWK.js index 3061be29a..3c4e9a49c 100644 --- a/assets/classDiagram-v2-FI7KE7WJ-Cv9pEPw6.js +++ b/assets/classDiagram-v2-FI7KE7WJ-CbLiwjWK.js @@ -1,2 +1,2 @@ -import{m as tt,c as et,i as nt,a as it,p as st}from"./chunk-UGV5ZQQN-BxKEe51B.js";import{c as at,a as G,s as rt}from"./chunk-BAVOGKFW-B2dDM16w.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-YWFND7JV-CtqGT_XT.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-IUatkdtb.js";import{G as q}from"./graph-CKGFjaQu.js";import{l as wt}from"./layout-Bmwgbrwx.js";import{w as S}from"./json-BbAt_51R.js";import"./app-BClOOpdM.js";import"./baseUniq-j141U2p6.js";import"./basePickBy-Cyiz-f_r.js";import"./clone-DBEsGdWr.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-UGV5ZQQN-B0KztNbp.js";import{c as at,a as G,s as rt}from"./chunk-BAVOGKFW-DK_Q78_U.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-YWFND7JV-DqutOh5-.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-VsNG6kTl.js";import{G as q}from"./graph-DebN9_Dg.js";import{l as wt}from"./layout-BkNI4twY.js";import{w as S}from"./json-BpfjFNGZ.js";import"./app-Dp4t6tDQ.js";import"./baseUniq-Bpwj4IW2.js";import"./basePickBy-BMIT5f2S.js";import"./clone-CyxiHGLh.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-CyxiHGLh.js b/assets/clone-CyxiHGLh.js new file mode 100644 index 000000000..03a438123 --- /dev/null +++ b/assets/clone-CyxiHGLh.js @@ -0,0 +1 @@ +import{b as r}from"./baseUniq-Bpwj4IW2.js";var e=4;function a(o){return r(o,e)}export{a as c}; diff --git a/assets/clone-DBEsGdWr.js b/assets/clone-DBEsGdWr.js deleted file mode 100644 index a3393e5b7..000000000 --- a/assets/clone-DBEsGdWr.js +++ /dev/null @@ -1 +0,0 @@ -import{b as r}from"./baseUniq-j141U2p6.js";var e=4;function a(o){return r(o,e)}export{a as c}; diff --git a/assets/command.html-Blm6CTPO.js b/assets/command.html-B6aFEOgE.js similarity index 99% rename from assets/command.html-Blm6CTPO.js rename to assets/command.html-B6aFEOgE.js index 6f6b9db3a..524f234cb 100644 --- a/assets/command.html-Blm6CTPO.js +++ b/assets/command.html-B6aFEOgE.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-BClOOpdM.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-Dp4t6tDQ.js";const u={},v=o(`

                                      Командные аргументы

                                      Подсказка

                                      Xray использует команды и аргументы в стиле Go.

                                      Базовые команды

                                      Вы можете запустить xray help, чтобы получить список всех базовых команд Xray, а также их описание и примеры использования.

                                      Xray is a platform for building proxies.
                                       
                                       Usage:
                                       
                                      diff --git a/assets/command.html-BF0VD3ix.js b/assets/command.html-C74Zzwa_.js
                                      similarity index 99%
                                      rename from assets/command.html-BF0VD3ix.js
                                      rename to assets/command.html-C74Zzwa_.js
                                      index 58ead4b1e..5951ba84e 100644
                                      --- a/assets/command.html-BF0VD3ix.js
                                      +++ b/assets/command.html-C74Zzwa_.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-BClOOpdM.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-Dp4t6tDQ.js";const v={},u=o(`

                                      命令参数

                                      提示

                                      Xray 使用 Go 风格的命令及参数

                                      获取基本命令

                                      您可以运行 xray help 来获得所有 xray 最基础的用法, 以及可用的命令及说明。

                                      Xray is a platform for building proxies.
                                       
                                       Usage:
                                       
                                      diff --git a/assets/command.html-uXs_G-wM.js b/assets/command.html-EcRoAGlR.js
                                      similarity index 99%
                                      rename from assets/command.html-uXs_G-wM.js
                                      rename to assets/command.html-EcRoAGlR.js
                                      index bd6c2b0e3..11dc6c821 100644
                                      --- a/assets/command.html-uXs_G-wM.js
                                      +++ b/assets/command.html-EcRoAGlR.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-BClOOpdM.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-Dp4t6tDQ.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/compile.html-CjZXx27q.js b/assets/compile.html-BrZYwGdl.js
                                      similarity index 99%
                                      rename from assets/compile.html-CjZXx27q.js
                                      rename to assets/compile.html-BrZYwGdl.js
                                      index 48f28ebea..b525f0bf7 100644
                                      --- a/assets/compile.html-CjZXx27q.js
                                      +++ b/assets/compile.html-BrZYwGdl.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-BClOOpdM.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-Dp4t6tDQ.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/compile.html-DuAS5vnR.js b/assets/compile.html-CB5wbp39.js
                                      similarity index 99%
                                      rename from assets/compile.html-DuAS5vnR.js
                                      rename to assets/compile.html-CB5wbp39.js
                                      index 449e83f6f..dbdb632bd 100644
                                      --- a/assets/compile.html-DuAS5vnR.js
                                      +++ b/assets/compile.html-CB5wbp39.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-BClOOpdM.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"},"СОВЕТ",-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-Dp4t6tDQ.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"},"СОВЕТ",-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-ByJLQtO8.js b/assets/compile.html-gJ9_uLGu.js
                                      similarity index 99%
                                      rename from assets/compile.html-ByJLQtO8.js
                                      rename to assets/compile.html-gJ9_uLGu.js
                                      index 4ddfdc27f..68d97ab69 100644
                                      --- a/assets/compile.html-ByJLQtO8.js
                                      +++ b/assets/compile.html-gJ9_uLGu.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-BClOOpdM.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-Dp4t6tDQ.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/config.html-CLIWPOuR.js b/assets/config.html-BzsuZqqV.js
                                      similarity index 99%
                                      rename from assets/config.html-CLIWPOuR.js
                                      rename to assets/config.html-BzsuZqqV.js
                                      index 13f4eb38b..67a2531ff 100644
                                      --- a/assets/config.html-CLIWPOuR.js
                                      +++ b/assets/config.html-BzsuZqqV.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-BClOOpdM.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-Dp4t6tDQ.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/config.html-BT24bI8Z.js b/assets/config.html-CaEweKA5.js
                                      similarity index 99%
                                      rename from assets/config.html-BT24bI8Z.js
                                      rename to assets/config.html-CaEweKA5.js
                                      index 1d654b717..fb243638f 100644
                                      --- a/assets/config.html-BT24bI8Z.js
                                      +++ b/assets/config.html-CaEweKA5.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-BClOOpdM.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-Dp4t6tDQ.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-DsMaT424.js b/assets/config.html-vruIm5ed.js
                                      similarity index 99%
                                      rename from assets/config.html-DsMaT424.js
                                      rename to assets/config.html-vruIm5ed.js
                                      index 187287ca6..169c8f585 100644
                                      --- a/assets/config.html-DsMaT424.js
                                      +++ b/assets/config.html-vruIm5ed.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-BClOOpdM.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-Dp4t6tDQ.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/dagre-P3YPLUS5-fdtXHwJa.js b/assets/dagre-P3YPLUS5-D2h4pGrn.js
                                      similarity index 97%
                                      rename from assets/dagre-P3YPLUS5-fdtXHwJa.js
                                      rename to assets/dagre-P3YPLUS5-D2h4pGrn.js
                                      index 7ee2934d6..c16975cfd 100644
                                      --- a/assets/dagre-P3YPLUS5-fdtXHwJa.js
                                      +++ b/assets/dagre-P3YPLUS5-D2h4pGrn.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as X,am as M,an as F,ao as Y,ap as _,l as i,d as j,aq as H,ar as q,as as z,ae as K,at as O,au as Q,av as U,aw as V,ax as W}from"./mermaid.core-IUatkdtb.js";import{G as k}from"./graph-CKGFjaQu.js";import{l as Z}from"./layout-Bmwgbrwx.js";import{w as N}from"./json-BbAt_51R.js";import"./app-BClOOpdM.js";import"./baseUniq-j141U2p6.js";import"./basePickBy-Cyiz-f_r.js";import"./clone-DBEsGdWr.js";var f=new Map,p=new Map,B=new Map,$=X(()=>{p.clear(),B.clear(),f.clear()},"clear"),D=X((e,t)=>{const n=p.get(t)||[];return i.trace("In isDescendant",t," ",e," = ",n.includes(e)),n.includes(e)},"isDescendant"),I=X((e,t)=>{const n=p.get(t)||[];return i.info("Descendants of ",t," is ",n),i.info("Edge is ",e),e.v===t||e.w===t?!1:n?n.includes(e.v)||D(e.v,t)||D(e.w,t)||n.includes(e.w):(i.debug("Tilt, ",t,",not in descendants"),!1)},"edgeInCluster"),A=X((e,t,n,o)=>{i.warn("Copying children of ",e,"root",o,"data",t.node(e),o);const d=t.children(e)||[];e!==o&&d.push(e),i.warn("Copying (nodes) clusterId",e,"nodes",d),d.forEach(c=>{if(t.children(c).length>0)A(c,t,n,o);else{const r=t.node(c);i.info("cp ",c," to ",o," with parent ",e),n.setNode(c,r),o!==t.parent(c)&&(i.warn("Setting parent",c,t.parent(c)),n.setParent(c,t.parent(c))),e!==o&&c!==e?(i.debug("Setting parent",c,e),n.setParent(c,e)):(i.info("In copy ",e,"root",o,"data",t.node(e),o),i.debug("Not Setting parent for node=",c,"cluster!==rootId",e!==o,"node!==clusterId",c!==e));const u=t.edges(c);i.debug("Copying Edges",u),u.forEach(l=>{i.info("Edge",l);const v=t.edge(l.v,l.w,l.name);i.info("Edge data",v,o);try{I(l,o)?(i.info("Copying as ",l.v,l.w,v,l.name),n.setEdge(l.v,l.w,v,l.name),i.info("newGraph edges ",n.edges(),n.edge(n.edges()[0]))):i.info("Skipping copy of edge ",l.v,"-->",l.w," rootId: ",o," clusterId:",e)}catch(C){i.error(C)}})}i.debug("Removing node",c),t.removeNode(c)})},"copy"),J=X((e,t)=>{const n=t.children(e);let o=[...n];for(const d of n)B.set(d,e),o=[...o,...J(d,t)];return o},"extractDescendants"),L=X((e,t,n)=>{const o=e.edges().filter(l=>l.v===t||l.w===t),d=e.edges().filter(l=>l.v===n||l.w===n),c=o.map(l=>({v:l.v===t?n:l.v,w:l.w===t?t:l.w})),r=d.map(l=>({v:l.v,w:l.w}));return c.filter(l=>r.some(v=>l.v===v.v&&l.w===v.w))},"findCommonEdges"),S=X((e,t,n)=>{const o=t.children(e);if(i.trace("Searching children of id ",e,o),o.length<1)return e;let d;for(const c of o){const r=S(c,t,n),u=L(t,n,r);if(r)if(u.length>0)d=r;else return r}return d},"findNonClusterChild"),P=X(e=>!f.has(e)||!f.get(e).externalConnections?e:f.has(e)?f.get(e).id:e,"getAnchorId"),ee=X((e,t)=>{if(!e||t>10){i.debug("Opting out, no graph ");return}else i.debug("Opting in, graph ");e.nodes().forEach(function(n){e.children(n).length>0&&(i.warn("Cluster identified",n," Replacement id in edges: ",S(n,e,n)),p.set(n,J(n,e)),f.set(n,{id:S(n,e,n),clusterData:e.node(n)}))}),e.nodes().forEach(function(n){const o=e.children(n),d=e.edges();o.length>0?(i.debug("Cluster identified",n,p),d.forEach(c=>{const r=D(c.v,n),u=D(c.w,n);r^u&&(i.warn("Edge: ",c," leaves cluster ",n),i.warn("Descendants of XXX ",n,": ",p.get(n)),f.get(n).externalConnections=!0)})):i.debug("Not a cluster ",n,p)});for(let n of f.keys()){const o=f.get(n).id,d=e.parent(o);d!==n&&f.has(d)&&!f.get(d).externalConnections&&(f.get(n).id=d)}e.edges().forEach(function(n){const o=e.edge(n);i.warn("Edge "+n.v+" -> "+n.w+": "+JSON.stringify(n)),i.warn("Edge "+n.v+" -> "+n.w+": "+JSON.stringify(e.edge(n)));let d=n.v,c=n.w;if(i.warn("Fix XXX",f,"ids:",n.v,n.w,"Translating: ",f.get(n.v)," --- ",f.get(n.w)),f.get(n.v)||f.get(n.w)){if(i.warn("Fixing and trying - removing XXX",n.v,n.w,n.name),d=P(n.v),c=P(n.w),e.removeEdge(n.v,n.w,n.name),d!==n.v){const r=e.parent(d);f.get(r).externalConnections=!0,o.fromCluster=n.v}if(c!==n.w){const r=e.parent(c);f.get(r).externalConnections=!0,o.toCluster=n.w}i.warn("Fix Replacing with XXX",d,c,n.name),e.setEdge(d,c,o,n.name)}}),i.warn("Adjusted Graph",N(e)),G(e,0),i.trace(f)},"adjustClustersAndEdges"),G=X((e,t)=>{var d,c;if(i.warn("extractor - ",t,N(e),e.children("D")),t>10){i.error("Bailing out");return}let n=e.nodes(),o=!1;for(const r of n){const u=e.children(r);o=o||u.length>0}if(!o){i.debug("Done, no node has children",e.nodes());return}i.debug("Nodes = ",n,t);for(const r of n)if(i.debug("Extracting node",r,f,f.has(r)&&!f.get(r).externalConnections,!e.parent(r),e.node(r),e.children("D")," Depth ",t),!f.has(r))i.debug("Not a cluster",r,t);else if(!f.get(r).externalConnections&&e.children(r)&&e.children(r).length>0){i.warn("Cluster without external connections, without a parent and with children",r,t);let l=e.graph().rankdir==="TB"?"LR":"TB";(c=(d=f.get(r))==null?void 0:d.clusterData)!=null&&c.dir&&(l=f.get(r).clusterData.dir,i.warn("Fixing dir",f.get(r).clusterData.dir,l));const v=new k({multigraph:!0,compound:!0}).setGraph({rankdir:l,nodesep:50,ranksep:50,marginx:8,marginy:8}).setDefaultEdgeLabel(function(){return{}});i.warn("Old graph before copy",N(e)),A(r,e,v,r),e.setNode(r,{clusterNode:!0,id:r,clusterData:f.get(r).clusterData,label:f.get(r).label,graph:v}),i.warn("New graph after copy node: (",r,")",N(v)),i.debug("Old graph after copy",N(e))}else i.warn("Cluster ** ",r," **not meeting the criteria !externalConnections:",!f.get(r).externalConnections," no parent: ",!e.parent(r)," children ",e.children(r)&&e.children(r).length>0,e.children("D"),t),i.debug(f);n=e.nodes(),i.warn("New list of nodes",n);for(const r of n){const u=e.node(r);i.warn(" Now next level",r,u),u!=null&&u.clusterNode&&G(u.graph,t+1)}},"extractor"),R=X((e,t)=>{if(t.length===0)return[];let n=Object.assign([],t);return t.forEach(o=>{const d=e.children(o),c=R(e,d);n=[...n,...c]}),n},"sorter"),ne=X(e=>R(e,e.children()),"sortNodesByHierarchy"),T=X(async(e,t,n,o,d,c)=>{i.warn("Graph in recursive render:XAX",N(t),d);const r=t.graph().rankdir;i.trace("Dir in recursive render - dir:",r);const u=e.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 l=u.insert("g").attr("class","clusters"),v=u.insert("g").attr("class","edgePaths"),C=u.insert("g").attr("class","edgeLabels"),g=u.insert("g").attr("class","nodes");await Promise.all(t.nodes().map(async function(a){const s=t.node(a);if(d!==void 0){const m=JSON.parse(JSON.stringify(d.clusterData));i.trace(`Setting data for parent cluster XXX
                                      +import{_ as X,am as M,an as F,ao as Y,ap as _,l as i,d as j,aq as H,ar as q,as as z,ae as K,at as O,au as Q,av as U,aw as V,ax as W}from"./mermaid.core-VsNG6kTl.js";import{G as k}from"./graph-DebN9_Dg.js";import{l as Z}from"./layout-BkNI4twY.js";import{w as N}from"./json-BpfjFNGZ.js";import"./app-Dp4t6tDQ.js";import"./baseUniq-Bpwj4IW2.js";import"./basePickBy-BMIT5f2S.js";import"./clone-CyxiHGLh.js";var f=new Map,p=new Map,B=new Map,$=X(()=>{p.clear(),B.clear(),f.clear()},"clear"),D=X((e,t)=>{const n=p.get(t)||[];return i.trace("In isDescendant",t," ",e," = ",n.includes(e)),n.includes(e)},"isDescendant"),I=X((e,t)=>{const n=p.get(t)||[];return i.info("Descendants of ",t," is ",n),i.info("Edge is ",e),e.v===t||e.w===t?!1:n?n.includes(e.v)||D(e.v,t)||D(e.w,t)||n.includes(e.w):(i.debug("Tilt, ",t,",not in descendants"),!1)},"edgeInCluster"),A=X((e,t,n,o)=>{i.warn("Copying children of ",e,"root",o,"data",t.node(e),o);const d=t.children(e)||[];e!==o&&d.push(e),i.warn("Copying (nodes) clusterId",e,"nodes",d),d.forEach(c=>{if(t.children(c).length>0)A(c,t,n,o);else{const r=t.node(c);i.info("cp ",c," to ",o," with parent ",e),n.setNode(c,r),o!==t.parent(c)&&(i.warn("Setting parent",c,t.parent(c)),n.setParent(c,t.parent(c))),e!==o&&c!==e?(i.debug("Setting parent",c,e),n.setParent(c,e)):(i.info("In copy ",e,"root",o,"data",t.node(e),o),i.debug("Not Setting parent for node=",c,"cluster!==rootId",e!==o,"node!==clusterId",c!==e));const u=t.edges(c);i.debug("Copying Edges",u),u.forEach(l=>{i.info("Edge",l);const v=t.edge(l.v,l.w,l.name);i.info("Edge data",v,o);try{I(l,o)?(i.info("Copying as ",l.v,l.w,v,l.name),n.setEdge(l.v,l.w,v,l.name),i.info("newGraph edges ",n.edges(),n.edge(n.edges()[0]))):i.info("Skipping copy of edge ",l.v,"-->",l.w," rootId: ",o," clusterId:",e)}catch(C){i.error(C)}})}i.debug("Removing node",c),t.removeNode(c)})},"copy"),J=X((e,t)=>{const n=t.children(e);let o=[...n];for(const d of n)B.set(d,e),o=[...o,...J(d,t)];return o},"extractDescendants"),L=X((e,t,n)=>{const o=e.edges().filter(l=>l.v===t||l.w===t),d=e.edges().filter(l=>l.v===n||l.w===n),c=o.map(l=>({v:l.v===t?n:l.v,w:l.w===t?t:l.w})),r=d.map(l=>({v:l.v,w:l.w}));return c.filter(l=>r.some(v=>l.v===v.v&&l.w===v.w))},"findCommonEdges"),S=X((e,t,n)=>{const o=t.children(e);if(i.trace("Searching children of id ",e,o),o.length<1)return e;let d;for(const c of o){const r=S(c,t,n),u=L(t,n,r);if(r)if(u.length>0)d=r;else return r}return d},"findNonClusterChild"),P=X(e=>!f.has(e)||!f.get(e).externalConnections?e:f.has(e)?f.get(e).id:e,"getAnchorId"),ee=X((e,t)=>{if(!e||t>10){i.debug("Opting out, no graph ");return}else i.debug("Opting in, graph ");e.nodes().forEach(function(n){e.children(n).length>0&&(i.warn("Cluster identified",n," Replacement id in edges: ",S(n,e,n)),p.set(n,J(n,e)),f.set(n,{id:S(n,e,n),clusterData:e.node(n)}))}),e.nodes().forEach(function(n){const o=e.children(n),d=e.edges();o.length>0?(i.debug("Cluster identified",n,p),d.forEach(c=>{const r=D(c.v,n),u=D(c.w,n);r^u&&(i.warn("Edge: ",c," leaves cluster ",n),i.warn("Descendants of XXX ",n,": ",p.get(n)),f.get(n).externalConnections=!0)})):i.debug("Not a cluster ",n,p)});for(let n of f.keys()){const o=f.get(n).id,d=e.parent(o);d!==n&&f.has(d)&&!f.get(d).externalConnections&&(f.get(n).id=d)}e.edges().forEach(function(n){const o=e.edge(n);i.warn("Edge "+n.v+" -> "+n.w+": "+JSON.stringify(n)),i.warn("Edge "+n.v+" -> "+n.w+": "+JSON.stringify(e.edge(n)));let d=n.v,c=n.w;if(i.warn("Fix XXX",f,"ids:",n.v,n.w,"Translating: ",f.get(n.v)," --- ",f.get(n.w)),f.get(n.v)||f.get(n.w)){if(i.warn("Fixing and trying - removing XXX",n.v,n.w,n.name),d=P(n.v),c=P(n.w),e.removeEdge(n.v,n.w,n.name),d!==n.v){const r=e.parent(d);f.get(r).externalConnections=!0,o.fromCluster=n.v}if(c!==n.w){const r=e.parent(c);f.get(r).externalConnections=!0,o.toCluster=n.w}i.warn("Fix Replacing with XXX",d,c,n.name),e.setEdge(d,c,o,n.name)}}),i.warn("Adjusted Graph",N(e)),G(e,0),i.trace(f)},"adjustClustersAndEdges"),G=X((e,t)=>{var d,c;if(i.warn("extractor - ",t,N(e),e.children("D")),t>10){i.error("Bailing out");return}let n=e.nodes(),o=!1;for(const r of n){const u=e.children(r);o=o||u.length>0}if(!o){i.debug("Done, no node has children",e.nodes());return}i.debug("Nodes = ",n,t);for(const r of n)if(i.debug("Extracting node",r,f,f.has(r)&&!f.get(r).externalConnections,!e.parent(r),e.node(r),e.children("D")," Depth ",t),!f.has(r))i.debug("Not a cluster",r,t);else if(!f.get(r).externalConnections&&e.children(r)&&e.children(r).length>0){i.warn("Cluster without external connections, without a parent and with children",r,t);let l=e.graph().rankdir==="TB"?"LR":"TB";(c=(d=f.get(r))==null?void 0:d.clusterData)!=null&&c.dir&&(l=f.get(r).clusterData.dir,i.warn("Fixing dir",f.get(r).clusterData.dir,l));const v=new k({multigraph:!0,compound:!0}).setGraph({rankdir:l,nodesep:50,ranksep:50,marginx:8,marginy:8}).setDefaultEdgeLabel(function(){return{}});i.warn("Old graph before copy",N(e)),A(r,e,v,r),e.setNode(r,{clusterNode:!0,id:r,clusterData:f.get(r).clusterData,label:f.get(r).label,graph:v}),i.warn("New graph after copy node: (",r,")",N(v)),i.debug("Old graph after copy",N(e))}else i.warn("Cluster ** ",r," **not meeting the criteria !externalConnections:",!f.get(r).externalConnections," no parent: ",!e.parent(r)," children ",e.children(r)&&e.children(r).length>0,e.children("D"),t),i.debug(f);n=e.nodes(),i.warn("New list of nodes",n);for(const r of n){const u=e.node(r);i.warn(" Now next level",r,u),u!=null&&u.clusterNode&&G(u.graph,t+1)}},"extractor"),R=X((e,t)=>{if(t.length===0)return[];let n=Object.assign([],t);return t.forEach(o=>{const d=e.children(o),c=R(e,d);n=[...n,...c]}),n},"sorter"),ne=X(e=>R(e,e.children()),"sortNodesByHierarchy"),T=X(async(e,t,n,o,d,c)=>{i.warn("Graph in recursive render:XAX",N(t),d);const r=t.graph().rankdir;i.trace("Dir in recursive render - dir:",r);const u=e.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 l=u.insert("g").attr("class","clusters"),v=u.insert("g").attr("class","edgePaths"),C=u.insert("g").attr("class","edgeLabels"),g=u.insert("g").attr("class","nodes");await Promise.all(t.nodes().map(async function(a){const s=t.node(a);if(d!==void 0){const m=JSON.parse(JSON.stringify(d.clusterData));i.trace(`Setting data for parent cluster XXX
                                        Node.id = `,a,`
                                        data=`,m.height,`
                                       Parent cluster`,d.height),t.setNode(d.id,m),t.parent(a)||(i.trace("Setting parent",a,d.id),t.setParent(a,d.id,m))}if(i.info("(Insert) Node XXX"+a+": "+JSON.stringify(t.node(a))),s!=null&&s.clusterNode){i.info("Cluster identified XBX",a,s.width,t.node(a));const{ranksep:m,nodesep:h}=t.graph();s.graph.setGraph({...s.graph.graph(),ranksep:m+25,nodesep:h});const b=await T(g,s.graph,n,o,t.node(a),c),x=b.elem;H(s,x),s.diff=b.diff||0,i.info("New compound node after recursive render XAX",a,"width",s.width,"height",s.height),q(x,s)}else t.children(a).length>0?(i.trace("Cluster - the non recursive path XBX",a,s.id,s,s.width,"Graph:",t),i.trace(S(s.id,t)),f.set(s.id,{id:S(s.id,t),node:s})):(i.trace("Node - the non recursive path XAX",a,g,t.node(a),r),await z(g,t.node(a),r))})),await X(async()=>{const a=t.edges().map(async function(s){const m=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",f,"ids:",s.v,s.w,"Translating: ",f.get(s.v),f.get(s.w)),await W(C,m)});await Promise.all(a)},"processEdges")(),i.info("Graph before layout:",JSON.stringify(N(t))),i.info("############################################# XXX"),i.info("###                Layout                 ### XXX"),i.info("############################################# XXX"),Z(t),i.info("Graph after layout:",JSON.stringify(N(t)));let E=0,{subGraphTitleTotalMargin:y}=K(c);return await Promise.all(ne(t).map(async function(a){var m;const s=t.node(a);if(i.info("Position XBX => "+a+": ("+s.x,","+s.y,") width: ",s.width," height: ",s.height),s!=null&&s.clusterNode)s.y+=y,i.info("A tainted cluster node XBX1",a,s.id,s.width,s.height,s.x,s.y,t.parent(a)),f.get(s.id).node=s,O(s);else if(t.children(a).length>0){i.info("A pure cluster node XBX1",a,s.id,s.x,s.y,s.width,s.height,t.parent(a)),s.height+=y,t.node(s.parentId);const h=(s==null?void 0:s.padding)/2||0,b=((m=s==null?void 0:s.labelBBox)==null?void 0:m.height)||0,x=b-h||0;i.debug("OffsetY",x,"labelHeight",b,"halfPadding",h),await Q(l,s),f.get(s.id).node=s}else{const h=t.node(s.parentId);s.y+=y/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(a){const s=t.edge(a);i.info("Edge "+a.v+" -> "+a.w+": "+JSON.stringify(s),s),s.points.forEach(x=>x.y+=y/2);const m=t.node(a.v);var h=t.node(a.w);const b=U(v,s,f,n,m,h,o);V(s,b)}),t.nodes().forEach(function(a){const s=t.node(a);i.info(a,s.type,s.diff),s.isGroup&&(E=s.diff)}),i.warn("Returning from recursive render XAX",u,E),{elem:u,diff:E}},"recursiveRender"),le=X(async(e,t)=>{var c,r,u,l,v,C;const n=new k({multigraph:!0,compound:!0}).setGraph({rankdir:e.direction,nodesep:((c=e.config)==null?void 0:c.nodeSpacing)||((u=(r=e.config)==null?void 0:r.flowchart)==null?void 0:u.nodeSpacing)||e.nodeSpacing,ranksep:((l=e.config)==null?void 0:l.rankSpacing)||((C=(v=e.config)==null?void 0:v.flowchart)==null?void 0:C.rankSpacing)||e.rankSpacing,marginx:8,marginy:8}).setDefaultEdgeLabel(function(){return{}}),o=t.select("g");M(o,e.markers,e.type,e.diagramId),F(),Y(),_(),$(),e.nodes.forEach(g=>{n.setNode(g.id,{...g}),g.parentId&&n.setParent(g.id,g.parentId)}),i.debug("Edges:",e.edges),e.edges.forEach(g=>{if(g.start===g.end){const w=g.start,E=w+"---"+w+"---1",y=w+"---"+w+"---2",a=n.node(w);n.setNode(E,{domId:E,id:E,parentId:a.parentId,labelStyle:"",label:"",padding:0,shape:"labelRect",style:"",width:10,height:10}),n.setParent(E,a.parentId),n.setNode(y,{domId:y,id:y,parentId:a.parentId,labelStyle:"",padding:0,shape:"labelRect",label:"",style:"",width:10,height:10}),n.setParent(y,a.parentId);const s=structuredClone(g),m=structuredClone(g),h=structuredClone(g);s.label="",s.arrowTypeEnd="none",s.id=w+"-cyclic-special-1",m.arrowTypeEnd="none",m.id=w+"-cyclic-special-mid",h.label="",a.isGroup&&(s.fromCluster=w,h.toCluster=w),h.id=w+"-cyclic-special-2",n.setEdge(w,E,s,w+"-cyclic-special-0"),n.setEdge(E,y,m,w+"-cyclic-special-1"),n.setEdge(y,w,h,w+"-cyc设计目标
                                      • 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-Dp4t6tDQ.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/design.html-hf-r5dmK.js b/assets/design.html-CD_tRvvq.js similarity index 98% rename from assets/design.html-hf-r5dmK.js rename to assets/design.html-CD_tRvvq.js index 90d5ca78f..90c605af5 100644 --- a/assets/design.html-hf-r5dmK.js +++ b/assets/design.html-CD_tRvvq.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-BClOOpdM.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-Dp4t6tDQ.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-XfD5aROW.js b/assets/design.html-TCBoryCh.js similarity index 98% rename from assets/design.html-XfD5aROW.js rename to assets/design.html-TCBoryCh.js index 09a9f6cbf..3b4eca198 100644 --- a/assets/design.html-XfD5aROW.js +++ b/assets/design.html-TCBoryCh.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-BClOOpdM.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-Dp4t6tDQ.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/diagram-QS5GVLUX-Cm0gimUA.js b/assets/diagram-QS5GVLUX-xW2B2nxk.js similarity index 91% rename from assets/diagram-QS5GVLUX-Cm0gimUA.js rename to assets/diagram-QS5GVLUX-xW2B2nxk.js index ee2d344ec..12b7b58d8 100644 --- a/assets/diagram-QS5GVLUX-Cm0gimUA.js +++ b/assets/diagram-QS5GVLUX-xW2B2nxk.js @@ -1,4 +1,4 @@ -import{p as w}from"./chunk-OQCM5LHU-CGij_B7M.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-IUatkdtb.js";import{p as N}from"./gitGraph-YCYPL57B-BhMcSVnW.js";import"./app-BClOOpdM.js";import"./baseUniq-j141U2p6.js";import"./basePickBy-Cyiz-f_r.js";import"./clone-DBEsGdWr.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-OQCM5LHU-Cbp36FHa.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-VsNG6kTl.js";import{p as N}from"./gitGraph-YCYPL57B-CW0sFWI7.js";import"./app-Dp4t6tDQ.js";import"./baseUniq-Bpwj4IW2.js";import"./basePickBy-BMIT5f2S.js";import"./clone-CyxiHGLh.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-CKM_Wq5k.js b/assets/dns.html-8KXbkngf.js similarity index 99% rename from assets/dns.html-CKM_Wq5k.js rename to assets/dns.html-8KXbkngf.js index 30da22711..acf1fbac3 100644 --- a/assets/dns.html-CKM_Wq5k.js +++ b/assets/dns.html-8KXbkngf.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-BClOOpdM.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-Dp4t6tDQ.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-Bho_gUMA.js b/assets/dns.html-D7WmQBVs.js
                                      similarity index 98%
                                      rename from assets/dns.html-Bho_gUMA.js
                                      rename to assets/dns.html-D7WmQBVs.js
                                      index 43ccd6bbe..dcf17be21 100644
                                      --- a/assets/dns.html-Bho_gUMA.js
                                      +++ b/assets/dns.html-D7WmQBVs.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-BClOOpdM.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-Dp4t6tDQ.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-DHy15IYN.js b/assets/dns.html-DLTBofHa.js
                                      similarity index 98%
                                      rename from assets/dns.html-DHy15IYN.js
                                      rename to assets/dns.html-DLTBofHa.js
                                      index 3c4b49f58..518637c6e 100644
                                      --- a/assets/dns.html-DHy15IYN.js
                                      +++ b/assets/dns.html-DLTBofHa.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-BClOOpdM.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-Dp4t6tDQ.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-U3P3hT9J.js b/assets/dns.html-DR4B6jjx.js
                                      similarity index 99%
                                      rename from assets/dns.html-U3P3hT9J.js
                                      rename to assets/dns.html-DR4B6jjx.js
                                      index 2642a512d..64bf06b32 100644
                                      --- a/assets/dns.html-U3P3hT9J.js
                                      +++ b/assets/dns.html-DR4B6jjx.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as l,r as c,o as u,c as d,a as o,b as s,d as n,w as e,e as t}from"./app-BClOOpdM.js";const i={},r=t(`

                                      Встроенный DNS-сервер

                                      DNS-сервер

                                      Встроенный DNS-модуль Xray имеет два основных назначения:

                                      • На этапе маршрутизации: разрешает доменные имена в IP-адреса и выполняет сопоставление правил на основе полученных IP-адресов для разделения трафика. Разрешение доменных имен и разделение трафика зависят от значения domainStrategy в конфигурации модуля маршрутизации. Встроенный DNS-сервер будет использоваться для DNS-запросов только в том случае, если установлено одно из следующих двух значений:

                                        • "IPIfNonMatch": при запросе доменного имени выполняется сопоставление домена в маршрутизации, если совпадение не найдено, для этого доменного имени используется встроенный DNS-сервер для выполнения DNS-запроса, и возвращенный IP-адрес используется для повторного сопоставления IP-маршрутизации.
                                        • "IPOnDemand": при обнаружении любого правила на основе IP-адреса доменное имя немедленно разрешается в IP-адрес для сопоставления.
                                      • Разрешает целевой адрес для подключения.

                                        • Например, если в исходящем подключении freedom установить domainStrategy равным UseIP, то запросы, отправленные этим исходящим подключением, сначала будут разрешены во встроенном сервере из доменного имени в IP-адрес, а затем будет выполнено подключение.
                                        • Например, если в sockopt установить domainStrategy равным UseIP, то системные подключения, инициированные этим исходящим подключением, сначала будут разрешены во встроенном сервере из доменного имени в IP-адрес, а затем будет выполнено подключение.

                                      СОВЕТ 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:
                                        • По умолчанию выполнит «откат DNS-запроса (fallback)»: DNS-серверы, которые не использовались в предыдущем неудачном запросе и для которых skipFallback имеет значение по умолчанию false, будут использоваться для запроса по очереди. Если запрос не удался или expectIPs не совпадает, то возвращается пустое разрешение; в противном случае возвращается разрешенный IP-адрес.
                                        • Если disableFallback установлен в true, то «откат DNS-запроса (fallback)» выполняться не будет.
                                      • Не совпадает ни с 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 l,r as c,o as u,c as d,a as o,b as s,d as n,w as e,e as t}from"./app-Dp4t6tDQ.js";const i={},r=t(`

                                      Встроенный DNS-сервер

                                      DNS-сервер

                                      Встроенный DNS-модуль Xray имеет два основных назначения:

                                      • На этапе маршрутизации: разрешает доменные имена в IP-адреса и выполняет сопоставление правил на основе полученных IP-адресов для разделения трафика. Разрешение доменных имен и разделение трафика зависят от значения domainStrategy в конфигурации модуля маршрутизации. Встроенный DNS-сервер будет использоваться для DNS-запросов только в том случае, если установлено одно из следующих двух значений:

                                        • "IPIfNonMatch": при запросе доменного имени выполняется сопоставление домена в маршрутизации, если совпадение не найдено, для этого доменного имени используется встроенный DNS-сервер для выполнения DNS-запроса, и возвращенный IP-адрес используется для повторного сопоставления IP-маршрутизации.
                                        • "IPOnDemand": при обнаружении любого правила на основе IP-адреса доменное имя немедленно разрешается в IP-адрес для сопоставления.
                                      • Разрешает целевой адрес для подключения.

                                        • Например, если в исходящем подключении freedom установить domainStrategy равным UseIP, то запросы, отправленные этим исходящим подключением, сначала будут разрешены во встроенном сервере из доменного имени в IP-адрес, а затем будет выполнено подключение.
                                        • Например, если в sockopt установить domainStrategy равным UseIP, то системные подключения, инициированные этим исходящим подключением, сначала будут разрешены во встроенном сервере из доменного имени в IP-адрес, а затем будет выполнено подключение.

                                      СОВЕТ 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:
                                        • По умолчанию выполнит «откат DNS-запроса (fallback)»: DNS-серверы, которые не использовались в предыдущем неудачном запросе и для которых skipFallback имеет значение по умолчанию false, будут использоваться для запроса по очереди. Если запрос не удался или expectIPs не совпадает, то возвращается пустое разрешение; в противном случае возвращается разрешенный IP-адрес.
                                        • Если disableFallback установлен в true, то «откат DNS-запроса (fallback)» выполняться не будет.
                                      • Не совпадает ни с 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-fEPhd3oF.js b/assets/dns.html-DteCkEye.js
                                      similarity index 98%
                                      rename from assets/dns.html-fEPhd3oF.js
                                      rename to assets/dns.html-DteCkEye.js
                                      index cb26918c5..0ccf3b30b 100644
                                      --- a/assets/dns.html-fEPhd3oF.js
                                      +++ b/assets/dns.html-DteCkEye.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-BClOOpdM.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-Dp4t6tDQ.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-BqTOgtqG.js b/assets/dns.html-Rqqe7q81.js
                                      similarity index 99%
                                      rename from assets/dns.html-BqTOgtqG.js
                                      rename to assets/dns.html-Rqqe7q81.js
                                      index 6fa401ff7..c4a718f0a 100644
                                      --- a/assets/dns.html-BqTOgtqG.js
                                      +++ b/assets/dns.html-Rqqe7q81.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-BClOOpdM.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-Dp4t6tDQ.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/document.html-BfgqK0AW.js b/assets/document.html-BZ1SIqVg.js
                                      similarity index 98%
                                      rename from assets/document.html-BfgqK0AW.js
                                      rename to assets/document.html-BZ1SIqVg.js
                                      index 25297b79a..71087824c 100644
                                      --- a/assets/document.html-BfgqK0AW.js
                                      +++ b/assets/document.html-BZ1SIqVg.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-BClOOpdM.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-Dp4t6tDQ.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/document.html-D33r7piT.js b/assets/document.html-CQH_IQX-.js similarity index 98% rename from assets/document.html-D33r7piT.js rename to assets/document.html-CQH_IQX-.js index 385efd68b..82ff12506 100644 --- a/assets/document.html-D33r7piT.js +++ b/assets/document.html-CQH_IQX-.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-BClOOpdM.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-Dp4t6tDQ.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-nQC-96qj.js b/assets/document.html-Dc52ImNq.js similarity index 98% rename from assets/document.html-nQC-96qj.js rename to assets/document.html-Dc52ImNq.js index a03c0cd75..739744960 100644 --- a/assets/document.html-nQC-96qj.js +++ b/assets/document.html-Dc52ImNq.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-BClOOpdM.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-Dp4t6tDQ.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/dokodemo.html-DOvjc4cT.js b/assets/dokodemo.html-BBd3QiE-.js similarity index 99% rename from assets/dokodemo.html-DOvjc4cT.js rename to assets/dokodemo.html-BBd3QiE-.js index aa1244638..494bd6190 100644 --- a/assets/dokodemo.html-DOvjc4cT.js +++ b/assets/dokodemo.html-BBd3QiE-.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-BClOOpdM.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-Dp4t6tDQ.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-DZ-7Us1_.js b/assets/dokodemo.html-BRscbUqJ.js
                                      similarity index 99%
                                      rename from assets/dokodemo.html-DZ-7Us1_.js
                                      rename to assets/dokodemo.html-BRscbUqJ.js
                                      index 76c4fcaf1..3cce66f5d 100644
                                      --- a/assets/dokodemo.html-DZ-7Us1_.js
                                      +++ b/assets/dokodemo.html-BRscbUqJ.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-BClOOpdM.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-Dp4t6tDQ.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-bRch7wZq.js b/assets/dokodemo.html-VXFl6Ejr.js
                                      similarity index 99%
                                      rename from assets/dokodemo.html-bRch7wZq.js
                                      rename to assets/dokodemo.html-VXFl6Ejr.js
                                      index 5d3796827..123ae8b56 100644
                                      --- a/assets/dokodemo.html-bRch7wZq.js
                                      +++ b/assets/dokodemo.html-VXFl6Ejr.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-BClOOpdM.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-Dp4t6tDQ.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-BgPWlS3M.js b/assets/env.html-0m4UBMJO.js
                                      similarity index 97%
                                      rename from assets/env.html-BgPWlS3M.js
                                      rename to assets/env.html-0m4UBMJO.js
                                      index ffff62ee8..c1b484711 100644
                                      --- a/assets/env.html-BgPWlS3M.js
                                      +++ b/assets/env.html-0m4UBMJO.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-BClOOpdM.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-Dp4t6tDQ.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/env.html-DU1GD2FF.js b/assets/env.html-CxuA45IG.js similarity index 97% rename from assets/env.html-DU1GD2FF.js rename to assets/env.html-CxuA45IG.js index 6a3d6b7e4..33b08c625 100644 --- a/assets/env.html-DU1GD2FF.js +++ b/assets/env.html-CxuA45IG.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-BClOOpdM.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-Dp4t6tDQ.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-RA7PrAQR.js b/assets/env.html-Oz3j8oFe.js similarity index 98% rename from assets/env.html-RA7PrAQR.js rename to assets/env.html-Oz3j8oFe.js index 82f03bc79..2c6c69ca6 100644 --- a/assets/env.html-RA7PrAQR.js +++ b/assets/env.html-Oz3j8oFe.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-BClOOpdM.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-Dp4t6tDQ.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/erDiagram-62CBQV5Y-kGzN7AR2.js b/assets/erDiagram-62CBQV5Y-eD5vQ31J.js similarity index 99% rename from assets/erDiagram-62CBQV5Y-kGzN7AR2.js rename to assets/erDiagram-62CBQV5Y-eD5vQ31J.js index e5593dedb..0a6cc85db 100644 --- a/assets/erDiagram-62CBQV5Y-kGzN7AR2.js +++ b/assets/erDiagram-62CBQV5Y-eD5vQ31J.js @@ -1,4 +1,4 @@ -import{_ as u,d as U,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-IUatkdtb.js";import{G as It}from"./graph-CKGFjaQu.js";import{l as Dt}from"./layout-Bmwgbrwx.js";import"./app-BClOOpdM.js";import"./baseUniq-j141U2p6.js";import"./basePickBy-Cyiz-f_r.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 v=[];for(let t=0;t<256;++t)v.push((t+256).toString(16).slice(1));function Ct(t,e=0){return v[t[e+0]]+v[t[e+1]]+v[t[e+2]]+v[t[e+3]]+"-"+v[t[e+4]]+v[t[e+5]]+"-"+v[t[e+6]]+v[t[e+7]]+"-"+v[t[e+8]]+v[t[e+9]]+"-"+v[t[e+10]]+v[t[e+11]]+v[t[e+12]]+v[t[e+13]]+v[t[e+14]]+v[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;x=k,k=m,m=it(g,30)>>>0,g=h,h=b}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]+x>>>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(w,i,n,l){for(n=n||{},l=w.length;l--;n[w[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],x=[1,25],p=[6,8,10,13,15,18,19,20,22,24,26,27,28,41,42,43,44,45],O=[1,34],b=[27,28,46,47],Y=[41,42,43,44,45],Z=[17,34],F=[1,54],M=[1,53],S=[17,34,36,38],N={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:x}),{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:O},{11:35,27:y,28:o},{40:36,46:[1,37],47:[1,38]},t(b,[2,34]),t(b,[2,35]),t(b,[2,36]),t(b,[2,37]),t(b,[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:O},{31:42,34:[1,43]},{34:[2,27]},{19:[1,44]},{39:45,41:h,42:g,43:m,44:k,45:x},t(Y,[2,39]),t(Y,[2,40]),{14:46,27:[1,49],28:[1,48],48:[1,47]},t(e,[2,9]),{17:[2,22]},t(Z,[2,23],{32:50,33:51,35:52,37:F,38:M}),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(Z,[2,24],{33:56,36:[1,57],38:M}),t(Z,[2,25]),t(S,[2,29]),t(Z,[2,32]),t(S,[2,31]),{16:58,17:[1,59],29:32,30:33,34:O},t(Z,[2,26]),{35:60,37:F},{17:[1,61]},t(e,[2,13]),t(S,[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),A=Object.create(this.lexer),H={yy:{}};for(var $ in this.yy)Object.prototype.hasOwnProperty.call(this.yy,$)&&(H.yy[$]=this.yy[$]);A.setInput(i,H.yy),H.yy.lexer=A,H.yy.parser=this,typeof A.yylloc>"u"&&(A.yylloc={});var tt=A.yylloc;a.push(tt);var gt=A.options&&A.options.ranges;typeof H.yy.parseError=="function"?this.parseError=H.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function mt(D){l.length=l.length-2*D,E.length=E.length-D,a.length=a.length-D}u(mt,"popStack");function ht(){var D;return D=d.pop()||A.lex()||ct,typeof D!="number"&&(D instanceof Array&&(d=D,D=d.pop()),D=n.symbols_[D]||D),D}u(ht,"lex");for(var I,z,B,et,K={},q,W,dt,J;;){if(z=l[l.length-1],this.defaultActions[z]?B=this.defaultActions[z]:((I===null||typeof I>"u")&&(I=ht()),B=V[z]&&V[z][I]),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]+"'");A.showPosition?rt="Parse error on line "+(j+1)+`: +import{_ as u,d as U,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-VsNG6kTl.js";import{G as It}from"./graph-DebN9_Dg.js";import{l as Dt}from"./layout-BkNI4twY.js";import"./app-Dp4t6tDQ.js";import"./baseUniq-Bpwj4IW2.js";import"./basePickBy-BMIT5f2S.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 v=[];for(let t=0;t<256;++t)v.push((t+256).toString(16).slice(1));function Ct(t,e=0){return v[t[e+0]]+v[t[e+1]]+v[t[e+2]]+v[t[e+3]]+"-"+v[t[e+4]]+v[t[e+5]]+"-"+v[t[e+6]]+v[t[e+7]]+"-"+v[t[e+8]]+v[t[e+9]]+"-"+v[t[e+10]]+v[t[e+11]]+v[t[e+12]]+v[t[e+13]]+v[t[e+14]]+v[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;x=k,k=m,m=it(g,30)>>>0,g=h,h=b}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]+x>>>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(w,i,n,l){for(n=n||{},l=w.length;l--;n[w[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],x=[1,25],p=[6,8,10,13,15,18,19,20,22,24,26,27,28,41,42,43,44,45],O=[1,34],b=[27,28,46,47],Y=[41,42,43,44,45],Z=[17,34],F=[1,54],M=[1,53],S=[17,34,36,38],N={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:x}),{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:O},{11:35,27:y,28:o},{40:36,46:[1,37],47:[1,38]},t(b,[2,34]),t(b,[2,35]),t(b,[2,36]),t(b,[2,37]),t(b,[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:O},{31:42,34:[1,43]},{34:[2,27]},{19:[1,44]},{39:45,41:h,42:g,43:m,44:k,45:x},t(Y,[2,39]),t(Y,[2,40]),{14:46,27:[1,49],28:[1,48],48:[1,47]},t(e,[2,9]),{17:[2,22]},t(Z,[2,23],{32:50,33:51,35:52,37:F,38:M}),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(Z,[2,24],{33:56,36:[1,57],38:M}),t(Z,[2,25]),t(S,[2,29]),t(Z,[2,32]),t(S,[2,31]),{16:58,17:[1,59],29:32,30:33,34:O},t(Z,[2,26]),{35:60,37:F},{17:[1,61]},t(e,[2,13]),t(S,[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),A=Object.create(this.lexer),H={yy:{}};for(var $ in this.yy)Object.prototype.hasOwnProperty.call(this.yy,$)&&(H.yy[$]=this.yy[$]);A.setInput(i,H.yy),H.yy.lexer=A,H.yy.parser=this,typeof A.yylloc>"u"&&(A.yylloc={});var tt=A.yylloc;a.push(tt);var gt=A.options&&A.options.ranges;typeof H.yy.parseError=="function"?this.parseError=H.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function mt(D){l.length=l.length-2*D,E.length=E.length-D,a.length=a.length-D}u(mt,"popStack");function ht(){var D;return D=d.pop()||A.lex()||ct,typeof D!="number"&&(D instanceof Array&&(d=D,D=d.pop()),D=n.symbols_[D]||D),D}u(ht,"lex");for(var I,z,B,et,K={},q,W,dt,J;;){if(z=l[l.length-1],this.defaultActions[z]?B=this.defaultActions[z]:((I===null||typeof I>"u")&&(I=ht()),B=V[z]&&V[z][I]),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]+"'");A.showPosition?rt="Parse error on line "+(j+1)+`: `+A.showPosition()+` Expecting `+J.join(", ")+", got '"+(this.terminals_[I]||I)+"'":rt="Parse error on line "+(j+1)+": Unexpected "+(I==ct?"end of input":"'"+(this.terminals_[I]||I)+"'"),this.parseError(rt,{text:A.match,token:this.terminals_[I]||I,line:A.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: "+I);switch(B[0]){case 1:l.push(I),E.push(A.yytext),a.push(A.yylloc),l.push(B[1]),I=null,lt=A.yyleng,s=A.yytext,j=A.yylineno,tt=A.yylloc;break;case 2:if(W=this.productions_[B[1]][1],K.$=E[E.length-W],K._$={first_line:a[a.length-(W||1)].first_line,last_line:a[a.length-1].last_line,first_column:a[a.length-(W||1)].first_column,last_column:a[a.length-1].last_column},gt&&(K._$.range=[a[a.length-(W||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;W&&(l=l.slice(0,-1*W*2),E=E.slice(0,-1*W),a=a.slice(0,-1*W)),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")},T=function(){var w={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-BgcTIXgw.js b/assets/fakedns.html-CXq9EuY-.js similarity index 99% rename from assets/fakedns.html-BgcTIXgw.js rename to assets/fakedns.html-CXq9EuY-.js index 3e2c7807e..99eab7077 100644 --- a/assets/fakedns.html-BgcTIXgw.js +++ b/assets/fakedns.html-CXq9EuY-.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-BClOOpdM.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-Dp4t6tDQ.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-w8mpOaBa.js b/assets/fakedns.html-CpDHPnS9.js
                                      similarity index 99%
                                      rename from assets/fakedns.html-w8mpOaBa.js
                                      rename to assets/fakedns.html-CpDHPnS9.js
                                      index 2eb2d70e0..c8357ea9d 100644
                                      --- a/assets/fakedns.html-w8mpOaBa.js
                                      +++ b/assets/fakedns.html-CpDHPnS9.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-BClOOpdM.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-Dp4t6tDQ.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-zTVe-lF4.js b/assets/fakedns.html-t4xl7UEa.js
                                      similarity index 99%
                                      rename from assets/fakedns.html-zTVe-lF4.js
                                      rename to assets/fakedns.html-t4xl7UEa.js
                                      index 8ded0d307..a3498e6dc 100644
                                      --- a/assets/fakedns.html-zTVe-lF4.js
                                      +++ b/assets/fakedns.html-t4xl7UEa.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-BClOOpdM.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-Dp4t6tDQ.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/fallback.html-BRqaP6rq.js b/assets/fallback.html-DdkmPffb.js
                                      similarity index 99%
                                      rename from assets/fallback.html-BRqaP6rq.js
                                      rename to assets/fallback.html-DdkmPffb.js
                                      index 522bee73e..0b4c94194 100644
                                      --- a/assets/fallback.html-BRqaP6rq.js
                                      +++ b/assets/fallback.html-DdkmPffb.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-BClOOpdM.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-Dp4t6tDQ.js";const b={},k=s(`

                                      Fallback

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

                                      Fallback обеспечивает Xray высокой степенью защиты от активного зондирования и имеет уникальный механизм резервирования первого пакета.

                                      Fallback также может разделять трафик различных типов по пути, что позволяет совместно использовать один порт для нескольких служб.

                                      В настоящее время вы можете использовать функцию fallback при использовании протоколов VLESS или Trojan, настроив fallbacks, и создавать очень разнообразные комбинации.

                                      Настройка fallbacks

                                        "fallbacks": [
                                           {
                                             "dest": 80
                                           }
                                      diff --git a/assets/fallback.html-BrN0kAZC.js b/assets/fallback.html-E73rITGw.js
                                      similarity index 99%
                                      rename from assets/fallback.html-BrN0kAZC.js
                                      rename to assets/fallback.html-E73rITGw.js
                                      index 89f1cd06d..52777f4fd 100644
                                      --- a/assets/fallback.html-BrN0kAZC.js
                                      +++ b/assets/fallback.html-E73rITGw.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-BClOOpdM.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-Dp4t6tDQ.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-Dorx_zZZ.js b/assets/fallback.html-uhRPRVcx.js
                                      similarity index 99%
                                      rename from assets/fallback.html-Dorx_zZZ.js
                                      rename to assets/fallback.html-uhRPRVcx.js
                                      index ff148a422..7919a29ab 100644
                                      --- a/assets/fallback.html-Dorx_zZZ.js
                                      +++ b/assets/fallback.html-uhRPRVcx.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-BClOOpdM.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-Dp4t6tDQ.js";const b={},k=t(`

                                      Fallback 回落

                                      Fallback 是 Xray 的最强大功能之一, 可有效防止主动探测, 自由配置常用端口多服务共享

                                      fallback 为 Xray 提供了高强度的防主动探测性, 并且具有独创的首包回落机制.

                                      fallback 也可以将不同类型的流量根据 path 进行分流, 从而实现一个端口, 多种服务共享.

                                      目前您可以在使用 VLESS 或者 trojan 协议时, 通过配置 fallbacks 来使用回落这一特性, 并且创造出非常丰富的组合玩法.

                                      fallbacks 配置

                                        "fallbacks": [
                                           {
                                             "dest": 80
                                           }
                                      diff --git a/assets/fallbacks-lv1.html-tiE_cj9R.js b/assets/fallbacks-lv1.html-BTlqatoV.js
                                      similarity index 99%
                                      rename from assets/fallbacks-lv1.html-tiE_cj9R.js
                                      rename to assets/fallbacks-lv1.html-BTlqatoV.js
                                      index e4be68882..1f50b96bb 100644
                                      --- a/assets/fallbacks-lv1.html-tiE_cj9R.js
                                      +++ b/assets/fallbacks-lv1.html-BTlqatoV.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-BClOOpdM.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-Dp4t6tDQ.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-DPcjjXwW.js b/assets/fallbacks-lv1.html-Bg8dj7Kh.js
                                      similarity index 99%
                                      rename from assets/fallbacks-lv1.html-DPcjjXwW.js
                                      rename to assets/fallbacks-lv1.html-Bg8dj7Kh.js
                                      index 326e38c86..d4c6a7cb9 100644
                                      --- a/assets/fallbacks-lv1.html-DPcjjXwW.js
                                      +++ b/assets/fallbacks-lv1.html-Bg8dj7Kh.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-BClOOpdM.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-Dp4t6tDQ.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-Ckp_6TD3.js b/assets/fallbacks-lv1.html-DYR8pz2w.js
                                      similarity index 99%
                                      rename from assets/fallbacks-lv1.html-Ckp_6TD3.js
                                      rename to assets/fallbacks-lv1.html-DYR8pz2w.js
                                      index 22ee40606..4f8878ead 100644
                                      --- a/assets/fallbacks-lv1.html-Ckp_6TD3.js
                                      +++ b/assets/fallbacks-lv1.html-DYR8pz2w.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-BClOOpdM.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-Dp4t6tDQ.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-BM_lo7LS.js b/assets/fallbacks-with-sni.html-B9Z6PoAs.js
                                      similarity index 99%
                                      rename from assets/fallbacks-with-sni.html-BM_lo7LS.js
                                      rename to assets/fallbacks-with-sni.html-B9Z6PoAs.js
                                      index 5fb3adf9c..a0ffbcaa6 100644
                                      --- a/assets/fallbacks-with-sni.html-BM_lo7LS.js
                                      +++ b/assets/fallbacks-with-sni.html-B9Z6PoAs.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-BClOOpdM.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-Dp4t6tDQ.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-CeYEzXyB.js b/assets/fallbacks-with-sni.html-Do5jNPZL.js
                                      similarity index 99%
                                      rename from assets/fallbacks-with-sni.html-CeYEzXyB.js
                                      rename to assets/fallbacks-with-sni.html-Do5jNPZL.js
                                      index 27f842450..d8c87c4e2 100644
                                      --- a/assets/fallbacks-with-sni.html-CeYEzXyB.js
                                      +++ b/assets/fallbacks-with-sni.html-Do5jNPZL.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-BClOOpdM.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-Dp4t6tDQ.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-DuBUlL52.js b/assets/fallbacks-with-sni.html-eKJVkRJ1.js
                                      similarity index 99%
                                      rename from assets/fallbacks-with-sni.html-DuBUlL52.js
                                      rename to assets/fallbacks-with-sni.html-eKJVkRJ1.js
                                      index 21f0c682e..ace480b9d 100644
                                      --- a/assets/fallbacks-with-sni.html-DuBUlL52.js
                                      +++ b/assets/fallbacks-with-sni.html-eKJVkRJ1.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-BClOOpdM.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-Dp4t6tDQ.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-JSIZSE4D-CkrFR_87.js b/assets/flowDiagram-JSIZSE4D-CWnhT7dd.js
                                      similarity index 99%
                                      rename from assets/flowDiagram-JSIZSE4D-CkrFR_87.js
                                      rename to assets/flowDiagram-JSIZSE4D-CWnhT7dd.js
                                      index 795b33d84..daf88b007 100644
                                      --- a/assets/flowDiagram-JSIZSE4D-CkrFR_87.js
                                      +++ b/assets/flowDiagram-JSIZSE4D-CWnhT7dd.js
                                      @@ -1,4 +1,4 @@
                                      -import{g as pt,s as ft}from"./chunk-DUMQOTYW-Bze3ZeWr.js";import"./chunk-YWFND7JV-CtqGT_XT.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-IUatkdtb.js";import{c as _t}from"./channel-C9cXYHlc.js";import"./app-BClOOpdM.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-DUMQOTYW-Bi8JUtJi.js";import"./chunk-YWFND7JV-DqutOh5-.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-VsNG6kTl.js";import{c as _t}from"./channel-Bqz4IE8G.js";import"./app-Dp4t6tDQ.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-BaZQj-Ms.js b/assets/freedom.html-BpiDXzpq.js
                                      similarity index 99%
                                      rename from assets/freedom.html-BaZQj-Ms.js
                                      rename to assets/freedom.html-BpiDXzpq.js
                                      index 6b9fb7205..a0dc710f7 100644
                                      --- a/assets/freedom.html-BaZQj-Ms.js
                                      +++ b/assets/freedom.html-BpiDXzpq.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-BClOOpdM.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 s,e as a}from"./app-Dp4t6tDQ.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-CsYhhuOD.js b/assets/freedom.html-ByGWvIrV.js
                                      similarity index 99%
                                      rename from assets/freedom.html-CsYhhuOD.js
                                      rename to assets/freedom.html-ByGWvIrV.js
                                      index 0bdbe42f9..29de96fa4 100644
                                      --- a/assets/freedom.html-CsYhhuOD.js
                                      +++ b/assets/freedom.html-ByGWvIrV.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-BClOOpdM.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 s,e as a}from"./app-Dp4t6tDQ.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-DBKermX9.js b/assets/freedom.html-CMut6erm.js
                                      similarity index 99%
                                      rename from assets/freedom.html-DBKermX9.js
                                      rename to assets/freedom.html-CMut6erm.js
                                      index ef6f40c2d..6f6e06116 100644
                                      --- a/assets/freedom.html-DBKermX9.js
                                      +++ b/assets/freedom.html-CMut6erm.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-BClOOpdM.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-Dp4t6tDQ.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/ganttDiagram-ASEIQ4P5-CoW2hfbL.js b/assets/ganttDiagram-ASEIQ4P5-DxQ9ChJm.js
                                      similarity index 99%
                                      rename from assets/ganttDiagram-ASEIQ4P5-CoW2hfbL.js
                                      rename to assets/ganttDiagram-ASEIQ4P5-DxQ9ChJm.js
                                      index aa6a6f4e4..a88b989a4 100644
                                      --- a/assets/ganttDiagram-ASEIQ4P5-CoW2hfbL.js
                                      +++ b/assets/ganttDiagram-ASEIQ4P5-DxQ9ChJm.js
                                      @@ -1,4 +1,4 @@
                                      -import{aT as Je,aU as Ke,aV as $e,aW as tn,aX as Fn,aY as re,aZ as En,aF as Te,aG as be,_ as d,a_ 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-IUatkdtb.js";import{b as Bn,t as Ie,c as Zn,a as qn,l as Xn}from"./linear-CAdJTZmH.js";import{i as Gn}from"./init-Gi6I4Gst.js";import"./app-BClOOpdM.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,F=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]+F,R=+N[N.length-1]+F,B=(e.bandwidth?er:tr)(e.copy(),F),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+F):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))+F)})),x.remove(),D.attr("d",t===qt||t===ae?s?"M"+g*s+","+H+"H"+F+"V"+R+"H"+g*s:"M"+F+","+H+"V"+R:s?"M"+H+","+g*s+"V"+F+"H"+R+"V"+g*s:"M"+H+","+F+"H"+R),W.attr("opacity",1).attr("transform",function(p){return S(B(p)+F)}),_.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?(F=+b,C):F},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=Fn(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 F=[];if(i=a.ceil(i),k=k==null?1:Math.floor(k),!(i0))return F;let g;do F.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),Yt=wt(4),pr=wt(5),vr=wt(6);mn.range;Kt.range;yr.range;kr.range;Yt.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 Y(T){return i[T.getDay()]}function o(T){return F[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 F[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 Yr(t,e,n){var r=nt.exec(e.slice(n,n+2));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.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?Yt(t):Yt.ceil(t)}function ya(t,e){return t=pn(t),P(Yt.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?Yt(t):Yt.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,F,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(F(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 F=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"):F.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={},F=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=F(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)):Y?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 Ya=bn.exports;const Fa=be(Ya);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,F=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 F.ordinal(k.$D);case"gggg":return k.weekYear();case"GGGG":return k.isoWeekYear();case"wo":return F.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],F=[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,Y,o,f){var c=o.length-1;switch(Y){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:F,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:F,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=[],Y=[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,Y.length=Y.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{aT as Je,aU as Ke,aV as $e,aW as tn,aX as Fn,aY as re,aZ as En,aF as Te,aG as be,_ as d,a_ 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-VsNG6kTl.js";import{b as Bn,t as Ie,c as Zn,a as qn,l as Xn}from"./linear-S87t6Dgt.js";import{i as Gn}from"./init-Gi6I4Gst.js";import"./app-Dp4t6tDQ.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,F=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]+F,R=+N[N.length-1]+F,B=(e.bandwidth?er:tr)(e.copy(),F),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+F):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))+F)})),x.remove(),D.attr("d",t===qt||t===ae?s?"M"+g*s+","+H+"H"+F+"V"+R+"H"+g*s:"M"+F+","+H+"V"+R:s?"M"+H+","+g*s+"V"+F+"H"+R+"V"+g*s:"M"+H+","+F+"H"+R),W.attr("opacity",1).attr("transform",function(p){return S(B(p)+F)}),_.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?(F=+b,C):F},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=Fn(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 F=[];if(i=a.ceil(i),k=k==null?1:Math.floor(k),!(i0))return F;let g;do F.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),Yt=wt(4),pr=wt(5),vr=wt(6);mn.range;Kt.range;yr.range;kr.range;Yt.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 Y(T){return i[T.getDay()]}function o(T){return F[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 F[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 Yr(t,e,n){var r=nt.exec(e.slice(n,n+2));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.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?Yt(t):Yt.ceil(t)}function ya(t,e){return t=pn(t),P(Yt.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?Yt(t):Yt.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,F,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(F(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 F=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"):F.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={},F=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=F(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)):Y?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 Ya=bn.exports;const Fa=be(Ya);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,F=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 F.ordinal(k.$D);case"gggg":return k.weekYear();case"GGGG":return k.isoWeekYear();case"wo":return F.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],F=[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,Y,o,f){var c=o.length-1;switch(Y){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:F,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:F,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=[],Y=[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,Y.length=Y.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),Y.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.$=Y[Y.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],Y,o].concat(G)),typeof ot<"u")return ot;ft&&(v=v.slice(0,-1*ft*2),Y=Y.slice(0,-1*ft),o=o.slice(0,-1*ft)),v.push(this.productions_[X[1]][0]),Y.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 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: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=[Y[0],Y[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-YCYPL57B-BhMcSVnW.js b/assets/gitGraph-YCYPL57B-CW0sFWI7.js
                                      similarity index 99%
                                      rename from assets/gitGraph-YCYPL57B-BhMcSVnW.js
                                      rename to assets/gitGraph-YCYPL57B-CW0sFWI7.js
                                      index 4ddd6947e..523c35f46 100644
                                      --- a/assets/gitGraph-YCYPL57B-BhMcSVnW.js
                                      +++ b/assets/gitGraph-YCYPL57B-CW0sFWI7.js
                                      @@ -1,4 +1,4 @@
                                      -var Fc=Object.defineProperty;var Gc=(n,e,t)=>e in n?Fc(n,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):n[e]=t;var Je=(n,e,t)=>(Gc(n,typeof e!="symbol"?e+"":e,t),t);import{h as Vt}from"./app-BClOOpdM.js";import{bx as Uc,by as Bc,aO as so,bh as Vc,aS as Wc,aP as Z,ay as jc,az as Ji,b7 as Hc,ba as ao,bb as oo,bm as Qi,b8 as Kc,aB as mt,aC as D,aQ as Zi,aK as zc}from"./mermaid.core-IUatkdtb.js";import{k as kt,l as Ti,g as Ot,S as qc,w as Yc,x as Xc,c as lo,v as K,y as co,m as Jc,z as Qc,A as Zc,B as eu,C as tu,a as uo,d as C,i as ze,h as _,r as oe,f as Ee,D as q}from"./baseUniq-j141U2p6.js";import{i as Ri,m as S,d as nu,f as Ne,g as St,h as Ai,l as It,e as ru}from"./basePickBy-Cyiz-f_r.js";import{c as te}from"./clone-DBEsGdWr.js";var iu=Object.prototype,su=iu.hasOwnProperty,Ae=Uc(function(n,e){if(Bc(e)||so(e)){Vc(e,kt(e),n);return}for(var t in e)su.call(e,t)&&Wc(n,t,e[t])});function fo(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=cu&&(s=Xc,a=!1,e=new qc(e));e:for(;++i-1:!!i&&co(n,e,t)>-1}function es(n,e,t){var r=n==null?0:n.length;if(!r)return-1;var i=0;return co(n,e,i)}var Tu="[object RegExp]";function Ru(n){return ao(n)&&oo(n)==Tu}var ts=Qi&&Qi.isRegExp,qe=ts?Kc(ts):Ru,Au="Expected a function";function Eu(n){if(typeof n!="function")throw new TypeError(Au);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=Jc(Qc(n),function(r){return[r]});return e=Ot(e),nu(n,t,function(r,i){return e(r,i[0])})}function rr(n,e){var t=Z(n)?Zc:eu;return t(n,Eu(Ot(e)))}function vu(n,e){var t;return Ti(n,function(r,i,s){return t=e(r,i,s),!t}),!!t}function ho(n,e,t){var r=Z(n)?tu:vu;return r(n,Ot(e))}function Ei(n){return n&&n.length?uo(n):[]}function ku(n,e){return n&&n.length?uo(n,Ot(e)):[]}function ae(n){return typeof n=="object"&&n!==null&&typeof n.$type=="string"}function Ge(n){return typeof n=="object"&&n!==null&&typeof n.$refText=="string"}function Su(n){return typeof n=="object"&&n!==null&&typeof n.name=="string"&&typeof n.type=="string"&&typeof n.path=="string"}function xn(n){return typeof n=="object"&&n!==null&&ae(n.container)&&Ge(n.reference)&&typeof n.message=="string"}class po{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 xt(n){return typeof n=="object"&&n!==null&&Array.isArray(n.content)}function mo(n){return typeof n=="object"&&n!==null&&typeof n.tokenType=="object"}function go(n){return xt(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 xe})}join(e=","){const t=this.iterator();let r="",i,s=!1;do i=t.next(),i.done||(s&&(r+=e),r+=Iu(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?xe:{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 xe})}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($n(s))t.iterator=s[Symbol.iterator]();else return{done:!1,value:s}}}while(t.iterator);return xe})}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($n(s))r.iterator=s[Symbol.iterator]();else return{done:!1,value:s}}while(r.iterator);return xe})}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?xe: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 Iu(n){return typeof n=="string"?n:typeof n>"u"?"undefined":typeof n.toString=="function"?n.toString():Object.prototype.toString.call(n)}function $n(n){return!!n&&typeof n[Symbol.iterator]=="function"}const xu=new ie(()=>{},()=>xe),xe=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($n(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 xe})}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 Pr(n){return new vi(n,e=>xt(e)?e.content:[],{includeRoot:!0})}function Nu(n,e){for(;n.container;)if(n=n.container,n===e)return!0;return!1}function Mr(n){return{start:{character:n.startColumn-1,line:n.startLine-1},end:{character:n.endColumn,line:n.endLine-1}}}function On(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 Cu(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 wu=/^[\w\p{L}]$/u;function Lu(n,e){if(n){const t=$u(n,!0);if(t&&ns(t,e))return t;if(go(n)){const r=n.content.findIndex(i=>!i.hidden);for(let i=r-1;i>=0;i--){const s=n.content[i];if(ns(s,e))return s}}}}function ns(n,e){return mo(n)&&e.includes(n.tokenType.name)}function $u(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 yo extends Error{constructor(e,t){super(e?`${t} at ${e.range.start.line}:${e.range.start.character}`:t)}}function ir(n){throw new Error("Error! The input value was not handled.")}const Ar="AbstractRule",Er="AbstractType",rs="Condition",Ou="TypeDefinition",is="ValueLiteral",To="AbstractElement";function bu(n){return M.isInstance(n,To)}const Pu="ArrayLiteral",Mu="ArrayType",Ro="BooleanLiteral";function Du(n){return M.isInstance(n,Ro)}const Ao="Conjunction";function Fu(n){return M.isInstance(n,Ao)}const Eo="Disjunction";function Gu(n){return M.isInstance(n,Eo)}const Uu="Grammar",vo="InferredType";function ko(n){return M.isInstance(n,vo)}const So="Interface";function Io(n){return M.isInstance(n,So)}const xo="Negation";function Bu(n){return M.isInstance(n,xo)}const Vu="NumberLiteral",Wu="Parameter",No="ParameterReference";function ju(n){return M.isInstance(n,No)}const Co="ParserRule";function Ce(n){return M.isInstance(n,Co)}const Hu="ReferenceType",Ku="ReturnType";function zu(n){return M.isInstance(n,Ku)}const _o="SimpleType";function qu(n){return M.isInstance(n,_o)}const Yu="StringLiteral",Dr="TerminalRule";function gt(n){return M.isInstance(n,Dr)}const wo="Type";function Lo(n){return M.isInstance(n,wo)}const Xu="UnionType",$o="Action";function sr(n){return M.isInstance(n,$o)}const Oo="Alternatives";function bo(n){return M.isInstance(n,Oo)}const Po="Assignment";function ut(n){return M.isInstance(n,Po)}const Mo="CharacterRange";function Ju(n){return M.isInstance(n,Mo)}const Do="CrossReference";function ki(n){return M.isInstance(n,Do)}const Fo="EndOfFile";function Qu(n){return M.isInstance(n,Fo)}const Go="Group";function Si(n){return M.isInstance(n,Go)}const Uo="Keyword";function dt(n){return M.isInstance(n,Uo)}const Bo="NegatedToken";function Zu(n){return M.isInstance(n,Bo)}const Vo="RegexToken";function ed(n){return M.isInstance(n,Vo)}const Wo="RuleCall";function ft(n){return M.isInstance(n,Wo)}const jo="TerminalAlternatives";function td(n){return M.isInstance(n,jo)}const Ho="TerminalGroup";function nd(n){return M.isInstance(n,Ho)}const Ko="TerminalRuleCall";function rd(n){return M.isInstance(n,Ko)}const zo="UnorderedGroup";function qo(n){return M.isInstance(n,zo)}const Yo="UntilToken";function id(n){return M.isInstance(n,Yo)}const Xo="Wildcard";function sd(n){return M.isInstance(n,Xo)}class Jo extends po{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 $o:case Oo:case Po:case Mo:case Do:case Fo:case Go:case Uo:case Bo:case Vo:case Wo:case jo:case Ho:case Ko:case zo:case Yo:case Xo:return this.isSubtype(To,t);case Pu:case Vu:case Yu:return this.isSubtype(is,t);case Mu:case Hu:case _o:case Xu:return this.isSubtype(Ou,t);case Ro:return this.isSubtype(rs,t)||this.isSubtype(is,t);case Ao:case Eo:case xo:case No:return this.isSubtype(rs,t);case vo:case So:case wo:return this.isSubtype(Er,t);case Co:return this.isSubtype(Ar,t)||this.isSubtype(Er,t);case Dr:return this.isSubtype(Ar,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 Ar;case"Grammar:usedGrammars":return Uu;case"NamedArgument:parameter":case"ParameterReference:parameter":return Wu;case"TerminalRuleCall:rule":return Dr;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 Jo;function ad(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 ar(n,e){let t=n;for(;t;){if(e(t))return t;t=t.$container}}function Ue(n){const t=od(n).$document;if(!t)throw new Error("AST node has no document.");return t}function od(n){for(;n.$container;)n=n.$container;return n}function Ii(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.keyIndexIi(t,e))}function Et(n,e){if(!n)throw new Error("Root node must be an AstNode.");return new vi(n,t=>Ii(t,e),{includeRoot:!0})}function ss(n,e){var t;if(!e)return!0;const r=(t=n.$cstNode)===null||t===void 0?void 0:t.range;return r?_u(r,e):!1}function Qo(n){return new ie(()=>({keys:Object.keys(n),keyIndex:0,arrayIndex:0}),e=>{for(;e.keyIndexe in n?Fc(n,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):n[e]=t;var Je=(n,e,t)=>(Gc(n,typeof e!="symbol"?e+"":e,t),t);import{h as Vt}from"./app-Dp4t6tDQ.js";import{bx as Uc,by as Bc,aO as so,bh as Vc,aS as Wc,aP as Z,ay as jc,az as Ji,b7 as Hc,ba as ao,bb as oo,bm as Qi,b8 as Kc,aB as mt,aC as D,aQ as Zi,aK as zc}from"./mermaid.core-VsNG6kTl.js";import{k as kt,l as Ti,g as Ot,S as qc,w as Yc,x as Xc,c as lo,v as K,y as co,m as Jc,z as Qc,A as Zc,B as eu,C as tu,a as uo,d as C,i as ze,h as _,r as oe,f as Ee,D as q}from"./baseUniq-Bpwj4IW2.js";import{i as Ri,m as S,d as nu,f as Ne,g as St,h as Ai,l as It,e as ru}from"./basePickBy-BMIT5f2S.js";import{c as te}from"./clone-CyxiHGLh.js";var iu=Object.prototype,su=iu.hasOwnProperty,Ae=Uc(function(n,e){if(Bc(e)||so(e)){Vc(e,kt(e),n);return}for(var t in e)su.call(e,t)&&Wc(n,t,e[t])});function fo(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=cu&&(s=Xc,a=!1,e=new qc(e));e:for(;++i-1:!!i&&co(n,e,t)>-1}function es(n,e,t){var r=n==null?0:n.length;if(!r)return-1;var i=0;return co(n,e,i)}var Tu="[object RegExp]";function Ru(n){return ao(n)&&oo(n)==Tu}var ts=Qi&&Qi.isRegExp,qe=ts?Kc(ts):Ru,Au="Expected a function";function Eu(n){if(typeof n!="function")throw new TypeError(Au);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=Jc(Qc(n),function(r){return[r]});return e=Ot(e),nu(n,t,function(r,i){return e(r,i[0])})}function rr(n,e){var t=Z(n)?Zc:eu;return t(n,Eu(Ot(e)))}function vu(n,e){var t;return Ti(n,function(r,i,s){return t=e(r,i,s),!t}),!!t}function ho(n,e,t){var r=Z(n)?tu:vu;return r(n,Ot(e))}function Ei(n){return n&&n.length?uo(n):[]}function ku(n,e){return n&&n.length?uo(n,Ot(e)):[]}function ae(n){return typeof n=="object"&&n!==null&&typeof n.$type=="string"}function Ge(n){return typeof n=="object"&&n!==null&&typeof n.$refText=="string"}function Su(n){return typeof n=="object"&&n!==null&&typeof n.name=="string"&&typeof n.type=="string"&&typeof n.path=="string"}function xn(n){return typeof n=="object"&&n!==null&&ae(n.container)&&Ge(n.reference)&&typeof n.message=="string"}class po{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 xt(n){return typeof n=="object"&&n!==null&&Array.isArray(n.content)}function mo(n){return typeof n=="object"&&n!==null&&typeof n.tokenType=="object"}function go(n){return xt(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 xe})}join(e=","){const t=this.iterator();let r="",i,s=!1;do i=t.next(),i.done||(s&&(r+=e),r+=Iu(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?xe:{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 xe})}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($n(s))t.iterator=s[Symbol.iterator]();else return{done:!1,value:s}}}while(t.iterator);return xe})}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($n(s))r.iterator=s[Symbol.iterator]();else return{done:!1,value:s}}while(r.iterator);return xe})}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?xe: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 Iu(n){return typeof n=="string"?n:typeof n>"u"?"undefined":typeof n.toString=="function"?n.toString():Object.prototype.toString.call(n)}function $n(n){return!!n&&typeof n[Symbol.iterator]=="function"}const xu=new ie(()=>{},()=>xe),xe=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($n(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 xe})}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 Pr(n){return new vi(n,e=>xt(e)?e.content:[],{includeRoot:!0})}function Nu(n,e){for(;n.container;)if(n=n.container,n===e)return!0;return!1}function Mr(n){return{start:{character:n.startColumn-1,line:n.startLine-1},end:{character:n.endColumn,line:n.endLine-1}}}function On(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 Cu(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 wu=/^[\w\p{L}]$/u;function Lu(n,e){if(n){const t=$u(n,!0);if(t&&ns(t,e))return t;if(go(n)){const r=n.content.findIndex(i=>!i.hidden);for(let i=r-1;i>=0;i--){const s=n.content[i];if(ns(s,e))return s}}}}function ns(n,e){return mo(n)&&e.includes(n.tokenType.name)}function $u(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 yo extends Error{constructor(e,t){super(e?`${t} at ${e.range.start.line}:${e.range.start.character}`:t)}}function ir(n){throw new Error("Error! The input value was not handled.")}const Ar="AbstractRule",Er="AbstractType",rs="Condition",Ou="TypeDefinition",is="ValueLiteral",To="AbstractElement";function bu(n){return M.isInstance(n,To)}const Pu="ArrayLiteral",Mu="ArrayType",Ro="BooleanLiteral";function Du(n){return M.isInstance(n,Ro)}const Ao="Conjunction";function Fu(n){return M.isInstance(n,Ao)}const Eo="Disjunction";function Gu(n){return M.isInstance(n,Eo)}const Uu="Grammar",vo="InferredType";function ko(n){return M.isInstance(n,vo)}const So="Interface";function Io(n){return M.isInstance(n,So)}const xo="Negation";function Bu(n){return M.isInstance(n,xo)}const Vu="NumberLiteral",Wu="Parameter",No="ParameterReference";function ju(n){return M.isInstance(n,No)}const Co="ParserRule";function Ce(n){return M.isInstance(n,Co)}const Hu="ReferenceType",Ku="ReturnType";function zu(n){return M.isInstance(n,Ku)}const _o="SimpleType";function qu(n){return M.isInstance(n,_o)}const Yu="StringLiteral",Dr="TerminalRule";function gt(n){return M.isInstance(n,Dr)}const wo="Type";function Lo(n){return M.isInstance(n,wo)}const Xu="UnionType",$o="Action";function sr(n){return M.isInstance(n,$o)}const Oo="Alternatives";function bo(n){return M.isInstance(n,Oo)}const Po="Assignment";function ut(n){return M.isInstance(n,Po)}const Mo="CharacterRange";function Ju(n){return M.isInstance(n,Mo)}const Do="CrossReference";function ki(n){return M.isInstance(n,Do)}const Fo="EndOfFile";function Qu(n){return M.isInstance(n,Fo)}const Go="Group";function Si(n){return M.isInstance(n,Go)}const Uo="Keyword";function dt(n){return M.isInstance(n,Uo)}const Bo="NegatedToken";function Zu(n){return M.isInstance(n,Bo)}const Vo="RegexToken";function ed(n){return M.isInstance(n,Vo)}const Wo="RuleCall";function ft(n){return M.isInstance(n,Wo)}const jo="TerminalAlternatives";function td(n){return M.isInstance(n,jo)}const Ho="TerminalGroup";function nd(n){return M.isInstance(n,Ho)}const Ko="TerminalRuleCall";function rd(n){return M.isInstance(n,Ko)}const zo="UnorderedGroup";function qo(n){return M.isInstance(n,zo)}const Yo="UntilToken";function id(n){return M.isInstance(n,Yo)}const Xo="Wildcard";function sd(n){return M.isInstance(n,Xo)}class Jo extends po{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 $o:case Oo:case Po:case Mo:case Do:case Fo:case Go:case Uo:case Bo:case Vo:case Wo:case jo:case Ho:case Ko:case zo:case Yo:case Xo:return this.isSubtype(To,t);case Pu:case Vu:case Yu:return this.isSubtype(is,t);case Mu:case Hu:case _o:case Xu:return this.isSubtype(Ou,t);case Ro:return this.isSubtype(rs,t)||this.isSubtype(is,t);case Ao:case Eo:case xo:case No:return this.isSubtype(rs,t);case vo:case So:case wo:return this.isSubtype(Er,t);case Co:return this.isSubtype(Ar,t)||this.isSubtype(Er,t);case Dr:return this.isSubtype(Ar,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 Ar;case"Grammar:usedGrammars":return Uu;case"NamedArgument:parameter":case"ParameterReference:parameter":return Wu;case"TerminalRuleCall:rule":return Dr;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 Jo;function ad(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 ar(n,e){let t=n;for(;t;){if(e(t))return t;t=t.$container}}function Ue(n){const t=od(n).$document;if(!t)throw new Error("AST node has no document.");return t}function od(n){for(;n.$container;)n=n.$container;return n}function Ii(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.keyIndexIi(t,e))}function Et(n,e){if(!n)throw new Error("Root node must be an AstNode.");return new vi(n,t=>Ii(t,e),{includeRoot:!0})}function ss(n,e){var t;if(!e)return!0;const r=(t=n.$cstNode)===null||t===void 0?void 0:t.range;return r?_u(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-OQCM5LHU-Cbp36FHa.js";import{I as F}from"./chunk-2RYQ3QTB-8PgX7ysJ.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-VsNG6kTl.js";import{p as gr}from"./gitGraph-YCYPL57B-CW0sFWI7.js";import"./app-Dp4t6tDQ.js";import"./baseUniq-Bpwj4IW2.js";import"./basePickBy-BMIT5f2S.js";import"./clone-CyxiHGLh.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-CKGFjaQu.js b/assets/graph-DebN9_Dg.js
                                      similarity index 97%
                                      rename from assets/graph-CKGFjaQu.js
                                      rename to assets/graph-DebN9_Dg.js
                                      index 162cac110..868aaa663 100644
                                      --- a/assets/graph-CKGFjaQu.js
                                      +++ b/assets/graph-DebN9_Dg.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-j141U2p6.js";import{ay as y,az as P,aA as m,aB as E,aC as C}from"./mermaid.core-IUatkdtb.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-Bpwj4IW2.js";import{ay as y,az as P,aA as m,aB as E,aC as C}from"./mermaid.core-VsNG6kTl.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-CKj98XZP.js b/assets/grpc.html-2RCEkU0J.js
                                      similarity index 99%
                                      rename from assets/grpc.html-CKj98XZP.js
                                      rename to assets/grpc.html-2RCEkU0J.js
                                      index 50f10eb46..e057dc942 100644
                                      --- a/assets/grpc.html-CKj98XZP.js
                                      +++ b/assets/grpc.html-2RCEkU0J.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-BClOOpdM.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-Dp4t6tDQ.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/grpc.html-CuUtjqB-.js b/assets/grpc.html-C8FaUDz7.js
                                      similarity index 99%
                                      rename from assets/grpc.html-CuUtjqB-.js
                                      rename to assets/grpc.html-C8FaUDz7.js
                                      index 3e9bc15ee..37d62bca0 100644
                                      --- a/assets/grpc.html-CuUtjqB-.js
                                      +++ b/assets/grpc.html-C8FaUDz7.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-BClOOpdM.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-Dp4t6tDQ.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-BBtDCpfw.js b/assets/grpc.html-CbqWvXkn.js
                                      similarity index 99%
                                      rename from assets/grpc.html-BBtDCpfw.js
                                      rename to assets/grpc.html-CbqWvXkn.js
                                      index 996fba185..149ca745b 100644
                                      --- a/assets/grpc.html-BBtDCpfw.js
                                      +++ b/assets/grpc.html-CbqWvXkn.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-BClOOpdM.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-Dp4t6tDQ.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/guide.html-DarpIlI5.js b/assets/guide.html-B-RTAIpY.js
                                      similarity index 99%
                                      rename from assets/guide.html-DarpIlI5.js
                                      rename to assets/guide.html-B-RTAIpY.js
                                      index 215249209..8783c5fb2 100644
                                      --- a/assets/guide.html-DarpIlI5.js
                                      +++ b/assets/guide.html-B-RTAIpY.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-BClOOpdM.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-Dp4t6tDQ.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/guide.html-Dwzng_V-.js b/assets/guide.html-BaiH9eLl.js
                                      similarity index 99%
                                      rename from assets/guide.html-Dwzng_V-.js
                                      rename to assets/guide.html-BaiH9eLl.js
                                      index b078a9cd7..11346fba9 100644
                                      --- a/assets/guide.html-Dwzng_V-.js
                                      +++ b/assets/guide.html-BaiH9eLl.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-BClOOpdM.js";const h={},u=i('

                                      Правила разработки

                                      Основные принципы

                                      Система контроля версий

                                      Код проекта 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"},m={href:"https://github.com/XTLS/Xray-docs-next",target:"_blank",rel:"noopener noreferrer"},b={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,"Предварительные версии могут быть ежедневными сборками, в основном используются для тестирования в определенных ситуациях, ознакомления с новыми функциями и получения обратной связи для дальнейшего улучшения."),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"},T=e("li",null,"Если вам нужно использовать другие проекты, сначала создайте issue для обсуждения.",-1),q=e("li",null,[l("Другие "),e("ul",null,[e("li",null,"Можно использовать любые инструменты, которые не нарушают лицензии обеих сторон и полезны для проекта.")])],-1),G=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),P={href:"https://github.com/XTLS/Xray-core/issues",target:"_blank",rel:"noopener noreferrer"},R=e("h3",{id:"изменение-кода",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#изменение-кода"},[e("span",null,"Изменение кода")])],-1),C={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),B=e("li",null,[l("Если вам нужно изменить protobuf, например, добавить новый параметр конфигурации, выполните команду: "),e("code",null,"go generate core/proto.go"),l(".")],-1),I=e("li",null,[l("Перед отправкой pull request рекомендуется запустить тесты: "),e("code",null,"go test ./..."),l(".")],-1),E=e("li",null,"Перед отправкой pull request рекомендуется, чтобы новый код имел покрытие кода (code coverage) не менее 70%.",-1),w=e("li",null,[l("Другие "),e("ul",null,[e("li",null,"Обратите внимание на читаемость кода.")])],-1),F=i(`

                                      Запрос на включение изменений (Pull Request)

                                      • Перед отправкой PR сначала выполните команду git pull https://github.com/XTLS/Xray-core.git, чтобы убедиться, что слияние пройдет гладко.
                                      • Один PR должен решать только одну задачу. Если вы исправляете несколько ошибок, отправьте по одному PR для каждой ошибки.
                                      • Из-за особенностей Golang (пути к пакетам) процесс PR для проектов Go отличается от других проектов. Рекомендуемый процесс следующий:
                                        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. Наконец, отправьте PR из своей ветки в ветку main репозитория XTLS/Xray-core.
                                        9. В заголовке и описании PR четко опишите проблему, которую решает этот PR / новую функцию / цель изменений кода.
                                        10. Дождитесь ответа разработчиков.

                                      Изменения кода

                                      Проблемы с функциональностью

                                      Отправьте хотя бы один тестовый пример (Test Case), чтобы проверить изменения в существующей функциональности.

                                      Проблемы с производительностью

                                      Отправьте необходимые тестовые данные, чтобы подтвердить проблемы с производительностью существующего кода или улучшение производительности нового кода.

                                      Новые функции

                                      • Если новая функция не влияет на существующую функциональность, предоставьте переключатель (например, флаг) для ее включения/отключения и оставьте ее отключенной по умолчанию.
                                      • Перед разработкой новой крупной функции (например, добавления нового протокола) создайте issue для обсуждения.

                                      Другое

                                      Зависит от конкретной ситуации.

                                      Стандарты кодирования Xray

                                      Следующие правила применяются к коду Golang в Xray.

                                      Структура кода

                                      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-Dp4t6tDQ.js";const h={},u=i('

                                      Правила разработки

                                      Основные принципы

                                      Система контроля версий

                                      Код проекта 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"},m={href:"https://github.com/XTLS/Xray-docs-next",target:"_blank",rel:"noopener noreferrer"},b={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,"Предварительные версии могут быть ежедневными сборками, в основном используются для тестирования в определенных ситуациях, ознакомления с новыми функциями и получения обратной связи для дальнейшего улучшения."),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"},T=e("li",null,"Если вам нужно использовать другие проекты, сначала создайте issue для обсуждения.",-1),q=e("li",null,[l("Другие "),e("ul",null,[e("li",null,"Можно использовать любые инструменты, которые не нарушают лицензии обеих сторон и полезны для проекта.")])],-1),G=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),P={href:"https://github.com/XTLS/Xray-core/issues",target:"_blank",rel:"noopener noreferrer"},R=e("h3",{id:"изменение-кода",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#изменение-кода"},[e("span",null,"Изменение кода")])],-1),C={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),B=e("li",null,[l("Если вам нужно изменить protobuf, например, добавить новый параметр конфигурации, выполните команду: "),e("code",null,"go generate core/proto.go"),l(".")],-1),I=e("li",null,[l("Перед отправкой pull request рекомендуется запустить тесты: "),e("code",null,"go test ./..."),l(".")],-1),E=e("li",null,"Перед отправкой pull request рекомендуется, чтобы новый код имел покрытие кода (code coverage) не менее 70%.",-1),w=e("li",null,[l("Другие "),e("ul",null,[e("li",null,"Обратите внимание на читаемость кода.")])],-1),F=i(`

                                      Запрос на включение изменений (Pull Request)

                                      • Перед отправкой PR сначала выполните команду git pull https://github.com/XTLS/Xray-core.git, чтобы убедиться, что слияние пройдет гладко.
                                      • Один PR должен решать только одну задачу. Если вы исправляете несколько ошибок, отправьте по одному PR для каждой ошибки.
                                      • Из-за особенностей Golang (пути к пакетам) процесс PR для проектов Go отличается от других проектов. Рекомендуемый процесс следующий:
                                        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. Наконец, отправьте PR из своей ветки в ветку main репозитория XTLS/Xray-core.
                                        9. В заголовке и описании PR четко опишите проблему, которую решает этот PR / новую функцию / цель изменений кода.
                                        10. Дождитесь ответа разработчиков.

                                      Изменения кода

                                      Проблемы с функциональностью

                                      Отправьте хотя бы один тестовый пример (Test Case), чтобы проверить изменения в существующей функциональности.

                                      Проблемы с производительностью

                                      Отправьте необходимые тестовые данные, чтобы подтвердить проблемы с производительностью существующего кода или улучшение производительности нового кода.

                                      Новые функции

                                      • Если новая функция не влияет на существующую функциональность, предоставьте переключатель (например, флаг) для ее включения/отключения и оставьте ее отключенной по умолчанию.
                                      • Перед разработкой новой крупной функции (например, добавления нового протокола) создайте issue для обсуждения.

                                      Другое

                                      Зависит от конкретной ситуации.

                                      Стандарты кодирования Xray

                                      Следующие правила применяются к коду Golang в Xray.

                                      Структура кода

                                      Xray-core
                                       ├── app        // Модули приложений
                                       │   ├── router // Маршрутизация
                                       ├── common     // Общий код
                                      diff --git a/assets/guide.html-B9jnIFkQ.js b/assets/guide.html-UAu-Y-4H.js
                                      similarity index 99%
                                      rename from assets/guide.html-B9jnIFkQ.js
                                      rename to assets/guide.html-UAu-Y-4H.js
                                      index 21a86bf45..b3d24174d 100644
                                      --- a/assets/guide.html-B9jnIFkQ.js
                                      +++ b/assets/guide.html-UAu-Y-4H.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as s,r as o,o as c,c as d,a as n,b as e,d as l,e as i}from"./app-BClOOpdM.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"},T=e("li",null,"如需引用其它项目,请事先创建 issue 讨论;",-1),P=e("li",null,[l("其它 "),e("ul",null,[e("li",null,"不违反双方的协议,且对项目有帮助的工具,都可以使用。")])],-1),q=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),R={href:"https://github.com/XTLS/Xray-core/issues",target:"_blank",rel:"noopener noreferrer"},B=e("h3",{id:"修改代码",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#修改代码"},[e("span",null,"修改代码")])],-1),E={href:"https://golang.org/doc/effective_go.html",target:"_blank",rel:"noopener noreferrer"},F=e("li",null,[l("每一次 push 之前,请运行:"),e("code",null,"go generate core/format.go"),l(";")],-1),G=e("li",null,[l("如果需要修改 protobuf,例如增加新配置项,请运行:"),e("code",null,"go generate core/proto.go"),l(";")],-1),S=e("li",null,[l("提交 pull request 之前,建议测试通过:"),e("code",null,"go test ./..."),l(";")],-1),I=e("li",null,"提交 pull request 之前,建议新增代码有超过 70% 的代码覆盖率(code coverage);",-1),A=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 s,r as o,o as c,c as d,a as n,b as e,d as l,e as i}from"./app-Dp4t6tDQ.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"},T=e("li",null,"如需引用其它项目,请事先创建 issue 讨论;",-1),P=e("li",null,[l("其它 "),e("ul",null,[e("li",null,"不违反双方的协议,且对项目有帮助的工具,都可以使用。")])],-1),q=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),R={href:"https://github.com/XTLS/Xray-core/issues",target:"_blank",rel:"noopener noreferrer"},B=e("h3",{id:"修改代码",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#修改代码"},[e("span",null,"修改代码")])],-1),E={href:"https://golang.org/doc/effective_go.html",target:"_blank",rel:"noopener noreferrer"},F=e("li",null,[l("每一次 push 之前,请运行:"),e("code",null,"go generate core/format.go"),l(";")],-1),G=e("li",null,[l("如果需要修改 protobuf,例如增加新配置项,请运行:"),e("code",null,"go generate core/proto.go"),l(";")],-1),S=e("li",null,[l("提交 pull request 之前,建议测试通过:"),e("code",null,"go test ./..."),l(";")],-1),I=e("li",null,"提交 pull request 之前,建议新增代码有超过 70% 的代码覆盖率(code coverage);",-1),A=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/h2.html-RTLybXpz.js b/assets/h2.html-ChGHILPS.js
                                      similarity index 98%
                                      rename from assets/h2.html-RTLybXpz.js
                                      rename to assets/h2.html-ChGHILPS.js
                                      index 878f438ce..9fc199a12 100644
                                      --- a/assets/h2.html-RTLybXpz.js
                                      +++ b/assets/h2.html-ChGHILPS.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-BClOOpdM.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-Dp4t6tDQ.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-CdlAqNdU.js b/assets/http.html-B-9rXNoS.js
                                      similarity index 98%
                                      rename from assets/http.html-CdlAqNdU.js
                                      rename to assets/http.html-B-9rXNoS.js
                                      index 4966f0f26..d6ba2fa47 100644
                                      --- a/assets/http.html-CdlAqNdU.js
                                      +++ b/assets/http.html-B-9rXNoS.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-BClOOpdM.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-Dp4t6tDQ.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-BYmjDBWA.js b/assets/http.html-B-jc76lJ.js
                                      similarity index 98%
                                      rename from assets/http.html-BYmjDBWA.js
                                      rename to assets/http.html-B-jc76lJ.js
                                      index 48b3dbcf1..d128b89d6 100644
                                      --- a/assets/http.html-BYmjDBWA.js
                                      +++ b/assets/http.html-B-jc76lJ.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-BClOOpdM.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-Dp4t6tDQ.js";const c={},i=p(`

                                      HTTP

                                      Протокол HTTP.

                                      Предупреждение

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

                                      Подсказка

                                      HTTP может проксировать только протоколы TCP и не может обрабатывать протоколы на основе UDP.

                                      OutboundConfigurationObject

                                      {
                                         "servers": [
                                           {
                                             "address": "192.168.108.1",
                                      diff --git a/assets/http.html-DDZB0k1M.js b/assets/http.html-BK7TKRvo.js
                                      similarity index 98%
                                      rename from assets/http.html-DDZB0k1M.js
                                      rename to assets/http.html-BK7TKRvo.js
                                      index 687be1b1d..2b5b6f3b7 100644
                                      --- a/assets/http.html-DDZB0k1M.js
                                      +++ b/assets/http.html-BK7TKRvo.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-BClOOpdM.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-Dp4t6tDQ.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-CshzrTyQ.js b/assets/http.html-BNAuY1-K.js
                                      similarity index 99%
                                      rename from assets/http.html-CshzrTyQ.js
                                      rename to assets/http.html-BNAuY1-K.js
                                      index 7449b6200..528273794 100644
                                      --- a/assets/http.html-CshzrTyQ.js
                                      +++ b/assets/http.html-BNAuY1-K.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 i}from"./app-BClOOpdM.js";const r={},u=i(`

                                      HTTP

                                      Тип транспорта, основанный на HTTP/2 или HTTP/3.

                                      Он полностью реализован в соответствии со стандартом HTTP и может быть проксирован через другие HTTP-серверы (например, Nginx).

                                      Клиент должен включить TLS для корректной работы этого типа транспорта.

                                      HTTP/2 и 3 имеют встроенное мультиплексирование, поэтому не рекомендуется включать mux.cool при их использовании.

                                      Подсказка

                                      В текущей версии для транспорта HTTP/2 не требуется обязательная настройка TLS на стороне сервера.

                                      Это позволяет использовать Xray в качестве бэкенд-приложения в специальных сценариях развертывания с разделением трафика, где внешний шлюз обрабатывает TLS-соединение, а связь между шлюзом и Xray осуществляется по протоколу HTTP без шифрования.

                                      Подсказка

                                      Этот транспорт будет работать в режиме h3, только если alpn содержит только h3.

                                      Внимание

                                      • HTTP/2 и HTTP/3 не могут быть разделены по путям отката Xray. Использование разделения по путям отката не рекомендуется.

                                      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 i}from"./app-Dp4t6tDQ.js";const r={},u=i(`

                                      HTTP

                                      Тип транспорта, основанный на HTTP/2 или HTTP/3.

                                      Он полностью реализован в соответствии со стандартом HTTP и может быть проксирован через другие HTTP-серверы (например, Nginx).

                                      Клиент должен включить TLS для корректной работы этого типа транспорта.

                                      HTTP/2 и 3 имеют встроенное мультиплексирование, поэтому не рекомендуется включать mux.cool при их использовании.

                                      Подсказка

                                      В текущей версии для транспорта HTTP/2 не требуется обязательная настройка TLS на стороне сервера.

                                      Это позволяет использовать Xray в качестве бэкенд-приложения в специальных сценариях развертывания с разделением трафика, где внешний шлюз обрабатывает TLS-соединение, а связь между шлюзом и Xray осуществляется по протоколу HTTP без шифрования.

                                      Подсказка

                                      Этот транспорт будет работать в режиме h3, только если alpn содержит только h3.

                                      Внимание

                                      • HTTP/2 и HTTP/3 не могут быть разделены по путям отката Xray. Использование разделения по путям отката не рекомендуется.

                                      HttpObject

                                      HttpObject соответствует элементу httpSettings в конфигурации транспорта.

                                      {
                                         "host": ["xray.com"],
                                         "path": "/random/path",
                                         "read_idle_timeout": 10,
                                      diff --git a/assets/http.html-CS41BEAS.js b/assets/http.html-BoEkf3hc.js
                                      similarity index 98%
                                      rename from assets/http.html-CS41BEAS.js
                                      rename to assets/http.html-BoEkf3hc.js
                                      index 97da0e03b..7035ee95d 100644
                                      --- a/assets/http.html-CS41BEAS.js
                                      +++ b/assets/http.html-BoEkf3hc.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as p,r as s,o as c,c as r,a as o,b as t,d as n,e as l}from"./app-BClOOpdM.js";const i={},u=l(`

                                      HTTP

                                      基于 HTTP/2 或 HTTP/3 的传输方式。

                                      它完整按照 HTTP 标准实现,可以通过其它的 HTTP 服务器(如 Nginx)进行中转。

                                      客户端必须开启 TLS 才可以正常使用这个传输方式。

                                      HTTP/2和3 内置多路复用,不建议使用时启用 mux.cool。

                                      提示

                                      当前版本的 HTTP/2 的传输方式并不强制要求入站服务端)有 TLS 配置. 这使得可以在特殊用途的分流部署环境中,由外部网关组件完成 TLS 层对话,Xray 作为后端应用,网关和 Xray 间使用明文HTTP进行通讯。

                                      提示

                                      当alpn有且仅有 h3 时,该传输才会工作在h3模式。

                                      注意

                                      • HTTP/2 和 HTTP/3 无法通过xray的回落 Path 进行分流,不建议使用回落分流。

                                      HttpObject

                                      HttpObject 对应传输配置的 httpSettings 项。

                                      {
                                      +import{_ as p,r as s,o as c,c as r,a as o,b as t,d as n,e as l}from"./app-Dp4t6tDQ.js";const i={},u=l(`

                                      HTTP

                                      基于 HTTP/2 或 HTTP/3 的传输方式。

                                      它完整按照 HTTP 标准实现,可以通过其它的 HTTP 服务器(如 Nginx)进行中转。

                                      客户端必须开启 TLS 才可以正常使用这个传输方式。

                                      HTTP/2和3 内置多路复用,不建议使用时启用 mux.cool。

                                      提示

                                      当前版本的 HTTP/2 的传输方式并不强制要求入站服务端)有 TLS 配置. 这使得可以在特殊用途的分流部署环境中,由外部网关组件完成 TLS 层对话,Xray 作为后端应用,网关和 Xray 间使用明文HTTP进行通讯。

                                      提示

                                      当alpn有且仅有 h3 时,该传输才会工作在h3模式。

                                      注意

                                      • HTTP/2 和 HTTP/3 无法通过xray的回落 Path 进行分流,不建议使用回落分流。

                                      HttpObject

                                      HttpObject 对应传输配置的 httpSettings 项。

                                      {
                                         "host": ["xray.com"],
                                         "path": "/random/path",
                                         "read_idle_timeout": 10,
                                      diff --git a/assets/http.html-BeOSDU9A.js b/assets/http.html-BvJL3-d2.js
                                      similarity index 98%
                                      rename from assets/http.html-BeOSDU9A.js
                                      rename to assets/http.html-BvJL3-d2.js
                                      index 97da0e03b..7035ee95d 100644
                                      --- a/assets/http.html-BeOSDU9A.js
                                      +++ b/assets/http.html-BvJL3-d2.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as p,r as s,o as c,c as r,a as o,b as t,d as n,e as l}from"./app-BClOOpdM.js";const i={},u=l(`

                                      HTTP

                                      基于 HTTP/2 或 HTTP/3 的传输方式。

                                      它完整按照 HTTP 标准实现,可以通过其它的 HTTP 服务器(如 Nginx)进行中转。

                                      客户端必须开启 TLS 才可以正常使用这个传输方式。

                                      HTTP/2和3 内置多路复用,不建议使用时启用 mux.cool。

                                      提示

                                      当前版本的 HTTP/2 的传输方式并不强制要求入站服务端)有 TLS 配置. 这使得可以在特殊用途的分流部署环境中,由外部网关组件完成 TLS 层对话,Xray 作为后端应用,网关和 Xray 间使用明文HTTP进行通讯。

                                      提示

                                      当alpn有且仅有 h3 时,该传输才会工作在h3模式。

                                      注意

                                      • HTTP/2 和 HTTP/3 无法通过xray的回落 Path 进行分流,不建议使用回落分流。

                                      HttpObject

                                      HttpObject 对应传输配置的 httpSettings 项。

                                      {
                                      +import{_ as p,r as s,o as c,c as r,a as o,b as t,d as n,e as l}from"./app-Dp4t6tDQ.js";const i={},u=l(`

                                      HTTP

                                      基于 HTTP/2 或 HTTP/3 的传输方式。

                                      它完整按照 HTTP 标准实现,可以通过其它的 HTTP 服务器(如 Nginx)进行中转。

                                      客户端必须开启 TLS 才可以正常使用这个传输方式。

                                      HTTP/2和3 内置多路复用,不建议使用时启用 mux.cool。

                                      提示

                                      当前版本的 HTTP/2 的传输方式并不强制要求入站服务端)有 TLS 配置. 这使得可以在特殊用途的分流部署环境中,由外部网关组件完成 TLS 层对话,Xray 作为后端应用,网关和 Xray 间使用明文HTTP进行通讯。

                                      提示

                                      当alpn有且仅有 h3 时,该传输才会工作在h3模式。

                                      注意

                                      • HTTP/2 和 HTTP/3 无法通过xray的回落 Path 进行分流,不建议使用回落分流。

                                      HttpObject

                                      HttpObject 对应传输配置的 httpSettings 项。

                                      {
                                         "host": ["xray.com"],
                                         "path": "/random/path",
                                         "read_idle_timeout": 10,
                                      diff --git a/assets/http.html-CrilsEvo.js b/assets/http.html-Cokq0RDI.js
                                      similarity index 99%
                                      rename from assets/http.html-CrilsEvo.js
                                      rename to assets/http.html-Cokq0RDI.js
                                      index 9af0fcc5e..e44f8996c 100644
                                      --- a/assets/http.html-CrilsEvo.js
                                      +++ b/assets/http.html-Cokq0RDI.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-BClOOpdM.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-Dp4t6tDQ.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-EVA_u-iB.js b/assets/http.html-DOvT0y9w.js
                                      similarity index 98%
                                      rename from assets/http.html-EVA_u-iB.js
                                      rename to assets/http.html-DOvT0y9w.js
                                      index 1e83af663..9767ed523 100644
                                      --- a/assets/http.html-EVA_u-iB.js
                                      +++ b/assets/http.html-DOvT0y9w.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-BClOOpdM.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-Dp4t6tDQ.js";const c={},i=p(`

                                      HTTP

                                      HTTP 协议。

                                      警告

                                      http 协议没有对传输加密,不适宜经公网中传输,更容易成为被人用作攻击的肉鸡。

                                      提示

                                      http 只能代理 tcp 协议,udp 系的协议均不能通过。

                                      OutboundConfigurationObject

                                      {
                                         "servers": [
                                           {
                                             "address": "192.168.108.1",
                                      diff --git a/assets/http.html-C5N79PRn.js b/assets/http.html-DxP83VAp.js
                                      similarity index 98%
                                      rename from assets/http.html-C5N79PRn.js
                                      rename to assets/http.html-DxP83VAp.js
                                      index 544160d89..edf7ac05b 100644
                                      --- a/assets/http.html-C5N79PRn.js
                                      +++ b/assets/http.html-DxP83VAp.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-BClOOpdM.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-Dp4t6tDQ.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/httpupgrade.html-DUTYtYRX.js b/assets/httpupgrade.html-B2K1tBnW.js
                                      similarity index 98%
                                      rename from assets/httpupgrade.html-DUTYtYRX.js
                                      rename to assets/httpupgrade.html-B2K1tBnW.js
                                      index 2813cc184..dd4ffe895 100644
                                      --- a/assets/httpupgrade.html-DUTYtYRX.js
                                      +++ b/assets/httpupgrade.html-B2K1tBnW.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-BClOOpdM.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-Dp4t6tDQ.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-DlzaZq--.js b/assets/httpupgrade.html-CIAeTyxj.js
                                      similarity index 98%
                                      rename from assets/httpupgrade.html-DlzaZq--.js
                                      rename to assets/httpupgrade.html-CIAeTyxj.js
                                      index 1a61e2cfa..0efe077da 100644
                                      --- a/assets/httpupgrade.html-DlzaZq--.js
                                      +++ b/assets/httpupgrade.html-CIAeTyxj.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-BClOOpdM.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-Dp4t6tDQ.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-DyeHB5qe.js b/assets/httpupgrade.html-D0PJ7P8D.js
                                      similarity index 98%
                                      rename from assets/httpupgrade.html-DyeHB5qe.js
                                      rename to assets/httpupgrade.html-D0PJ7P8D.js
                                      index 9ba74a285..5c5f0649b 100644
                                      --- a/assets/httpupgrade.html-DyeHB5qe.js
                                      +++ b/assets/httpupgrade.html-D0PJ7P8D.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-BClOOpdM.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-Dp4t6tDQ.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-Bn25952w.js b/assets/inbound.html-BItHMh7T.js
                                      similarity index 99%
                                      rename from assets/inbound.html-Bn25952w.js
                                      rename to assets/inbound.html-BItHMh7T.js
                                      index 2a0dd0772..1dc6b6597 100644
                                      --- a/assets/inbound.html-Bn25952w.js
                                      +++ b/assets/inbound.html-BItHMh7T.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 t}from"./app-BClOOpdM.js";const k={},q=n("h1",{id:"入站代理",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#入站代理"},[n("span",null,"入站代理")])],-1),b=t(`

                                      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 t}from"./app-Dp4t6tDQ.js";const k={},q=n("h1",{id:"入站代理",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#入站代理"},[n("span",null,"入站代理")])],-1),b=t(`

                                      InboundObject

                                      InboundObject 对应配置文件中 inbounds 项的一个子元素。

                                      {
                                         "inbounds": [
                                           {
                                             "listen": "127.0.0.1",
                                      diff --git a/assets/inbound.html-BnCvi1ip.js b/assets/inbound.html-BiWuRsHt.js
                                      similarity index 99%
                                      rename from assets/inbound.html-BnCvi1ip.js
                                      rename to assets/inbound.html-BiWuRsHt.js
                                      index 2bdc76189..6d1c1c46c 100644
                                      --- a/assets/inbound.html-BnCvi1ip.js
                                      +++ b/assets/inbound.html-BiWuRsHt.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-BClOOpdM.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-Dp4t6tDQ.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-Df7BiaXd.js b/assets/inbound.html-L9a0cvjw.js
                                      similarity index 99%
                                      rename from assets/inbound.html-Df7BiaXd.js
                                      rename to assets/inbound.html-L9a0cvjw.js
                                      index ce3b3560c..c1dc7138b 100644
                                      --- a/assets/inbound.html-Df7BiaXd.js
                                      +++ b/assets/inbound.html-L9a0cvjw.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-BClOOpdM.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 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-Dp4t6tDQ.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/index.html-CWk5bGVN.js b/assets/index.html-B15e5H01.js
                                      similarity index 99%
                                      rename from assets/index.html-CWk5bGVN.js
                                      rename to assets/index.html-B15e5H01.js
                                      index 8b25a44c4..16364e261 100644
                                      --- a/assets/index.html-CWk5bGVN.js
                                      +++ b/assets/index.html-B15e5H01.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-BClOOpdM.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-Dp4t6tDQ.js";const i={},d=r(`

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

                                      Обзор

                                      Конфигурационный файл Xray имеет формат JSON. Формат конфигурации одинаков для клиента и сервера, но фактическое содержимое отличается.
                                      Он выглядит следующим образом:

                                      {
                                         "log": {},
                                         "api": {},
                                         "dns": {},
                                      diff --git a/assets/index.html-CC-ntY8u.js b/assets/index.html-B2bo5ZOO.js
                                      similarity index 99%
                                      rename from assets/index.html-CC-ntY8u.js
                                      rename to assets/index.html-B2bo5ZOO.js
                                      index df233fbc1..b59485117 100644
                                      --- a/assets/index.html-CC-ntY8u.js
                                      +++ b/assets/index.html-B2bo5ZOO.js
                                      @@ -1 +1 @@
                                      -import{_ as s,r as n,o as c,c as i,a as l,b as e,d as r,w as h,e as u}from"./app-BClOOpdM.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"},b={href:"https://github.com/XTLS/Xray-core/discussions",target:"_blank",rel:"noopener noreferrer"},f={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"},L=e("ul",null,[e("li",null,"Официальная группа для некитайскоговорящих пользователей (в основном русскоязычных).")],-1),S={href:"https://t.me/projectXtls",target:"_blank",rel:"noopener noreferrer"},j=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),v=e("h3",{id:"подробнее-о-project-x",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#подробнее-о-project-x"},[e("span",null,"Подробнее о Project X")])],-1),N={href:"https://github.com/XTLS/Xray-core/discussions/3633#discussioncomment-10231076",target:"_blank",rel:"noopener noreferrer"},I=e("h3",{id:"лицензия",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#лицензия"},[e("span",null,"Лицензия")])],-1),w={href:"https://github.com/XTLS/Xray-core/blob/main/LICENSE",target:"_blank",rel:"noopener noreferrer"},E=e("h3",{id:"динамика-звезд-на-github",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#динамика-звезд-на-github"},[e("span",null,"Динамика звезд на GitHub")])],-1),R={href:"https://starchart.cc/XTLS/Xray-core",target:"_blank",rel:"noopener noreferrer"},q=e("img",{src:"https://starchart.cc/XTLS/Xray-core.svg",alt:"Stargazers over time"},null,-1);function B(C,F){const o=n("I18nTip"),t=n("ExternalLinkIcon"),a=n("RouterLink");return c(),i("div",null,[l(o),d,e("ul",null,[p,e("li",null,[r("📩 Создавайте конструктивные или важные задачи и обсуждения в "),e("a",X,[r("GitHub Issues"),l(t)]),r(" или "),e("a",b,[r("Discussion area"),l(t)]),r(".")]),e("li",null,[r("📝 Поделитесь своим опытом использования и отправьте его на "),e("a",f,[r("сайт документации"),l(t)]),r(" Xray.")]),g,m]),y,e("ul",null,[e("li",null,[e("p",null,[e("a",x,[r("Группа обсуждения Project X"),l(t)])]),k]),e("li",null,[e("p",null,[e("a",T,[r("Project VLESS Group"),l(t)])]),L]),e("li",null,[e("p",null,[e("a",S,[r("Канал Project X"),l(t)])]),j])]),P,V,v,e("ul",null,[e("li",null,[r("Если вы хотите узнать больше об истории и развитии Project X, нажмите "),l(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",N,[r("here"),l(t)])])]),I,e("p",null,[e("a",w,[r("Mozilla Public License Version 2.0"),l(t)])]),E,e("p",null,[e("a",R,[q,l(t)])])])}const z=s(_,[["render",B],["__file","index.html.vue"]]);export{z as default}; +import{_ as s,r as n,o as c,c as i,a as l,b as e,d as r,w as h,e as u}from"./app-Dp4t6tDQ.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"},b={href:"https://github.com/XTLS/Xray-core/discussions",target:"_blank",rel:"noopener noreferrer"},f={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"},L=e("ul",null,[e("li",null,"Официальная группа для некитайскоговорящих пользователей (в основном русскоязычных).")],-1),S={href:"https://t.me/projectXtls",target:"_blank",rel:"noopener noreferrer"},j=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),v=e("h3",{id:"подробнее-о-project-x",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#подробнее-о-project-x"},[e("span",null,"Подробнее о Project X")])],-1),N={href:"https://github.com/XTLS/Xray-core/discussions/3633#discussioncomment-10231076",target:"_blank",rel:"noopener noreferrer"},I=e("h3",{id:"лицензия",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#лицензия"},[e("span",null,"Лицензия")])],-1),w={href:"https://github.com/XTLS/Xray-core/blob/main/LICENSE",target:"_blank",rel:"noopener noreferrer"},E=e("h3",{id:"динамика-звезд-на-github",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#динамика-звезд-на-github"},[e("span",null,"Динамика звезд на GitHub")])],-1),R={href:"https://starchart.cc/XTLS/Xray-core",target:"_blank",rel:"noopener noreferrer"},q=e("img",{src:"https://starchart.cc/XTLS/Xray-core.svg",alt:"Stargazers over time"},null,-1);function B(C,F){const o=n("I18nTip"),t=n("ExternalLinkIcon"),a=n("RouterLink");return c(),i("div",null,[l(o),d,e("ul",null,[p,e("li",null,[r("📩 Создавайте конструктивные или важные задачи и обсуждения в "),e("a",X,[r("GitHub Issues"),l(t)]),r(" или "),e("a",b,[r("Discussion area"),l(t)]),r(".")]),e("li",null,[r("📝 Поделитесь своим опытом использования и отправьте его на "),e("a",f,[r("сайт документации"),l(t)]),r(" Xray.")]),g,m]),y,e("ul",null,[e("li",null,[e("p",null,[e("a",x,[r("Группа обсуждения Project X"),l(t)])]),k]),e("li",null,[e("p",null,[e("a",T,[r("Project VLESS Group"),l(t)])]),L]),e("li",null,[e("p",null,[e("a",S,[r("Канал Project X"),l(t)])]),j])]),P,V,v,e("ul",null,[e("li",null,[r("Если вы хотите узнать больше об истории и развитии Project X, нажмите "),l(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",N,[r("here"),l(t)])])]),I,e("p",null,[e("a",w,[r("Mozilla Public License Version 2.0"),l(t)])]),E,e("p",null,[e("a",R,[q,l(t)])])])}const z=s(_,[["render",B],["__file","index.html.vue"]]);export{z as default}; diff --git a/assets/index.html-q7kj9qZg.js b/assets/index.html-BA6EnvF3.js similarity index 98% rename from assets/index.html-q7kj9qZg.js rename to assets/index.html-BA6EnvF3.js index 8dab0402e..0546873fa 100644 --- a/assets/index.html-q7kj9qZg.js +++ b/assets/index.html-BA6EnvF3.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-BClOOpdM.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-Dp4t6tDQ.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-ISZNMRDN.js b/assets/index.html-BCkfQtsq.js similarity index 98% rename from assets/index.html-ISZNMRDN.js rename to assets/index.html-BCkfQtsq.js index cfeeacc5c..3fa22c2c3 100644 --- a/assets/index.html-ISZNMRDN.js +++ b/assets/index.html-BCkfQtsq.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-BClOOpdM.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-Dp4t6tDQ.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-BBBxkEh9.js b/assets/index.html-BEqfzz3v.js similarity index 94% rename from assets/index.html-BBBxkEh9.js rename to assets/index.html-BEqfzz3v.js index 64b0f92b7..fbc8cbaec 100644 --- a/assets/index.html-BBBxkEh9.js +++ b/assets/index.html-BEqfzz3v.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-BClOOpdM.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-Dp4t6tDQ.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-Dd_tdi9r.js b/assets/index.html-BHnedDAt.js similarity index 98% rename from assets/index.html-Dd_tdi9r.js rename to assets/index.html-BHnedDAt.js index a8f1210c1..aa9faa371 100644 --- a/assets/index.html-Dd_tdi9r.js +++ b/assets/index.html-BHnedDAt.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-BClOOpdM.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-Dp4t6tDQ.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-DTyCliON.js b/assets/index.html-BJJLWPxO.js similarity index 98% rename from assets/index.html-DTyCliON.js rename to assets/index.html-BJJLWPxO.js index c6067536d..04ddbe5ce 100644 --- a/assets/index.html-DTyCliON.js +++ b/assets/index.html-BJJLWPxO.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-BClOOpdM.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-Dp4t6tDQ.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-ynExHE2C.js b/assets/index.html-BVGw8-M8.js similarity index 97% rename from assets/index.html-ynExHE2C.js rename to assets/index.html-BVGw8-M8.js index 66d0b70de..36583a498 100644 --- a/assets/index.html-ynExHE2C.js +++ b/assets/index.html-BVGw8-M8.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-BClOOpdM.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-Dp4t6tDQ.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-jM25DbUH.js b/assets/index.html-CccDmH3c.js similarity index 98% rename from assets/index.html-jM25DbUH.js rename to assets/index.html-CccDmH3c.js index 271339698..0824a43f3 100644 --- a/assets/index.html-jM25DbUH.js +++ b/assets/index.html-CccDmH3c.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-BClOOpdM.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-Dp4t6tDQ.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-CZ9m8Lcw.js b/assets/index.html-CvwzfGmP.js similarity index 98% rename from assets/index.html-CZ9m8Lcw.js rename to assets/index.html-CvwzfGmP.js index 331d878ed..6949d839b 100644 --- a/assets/index.html-CZ9m8Lcw.js +++ b/assets/index.html-CvwzfGmP.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-BClOOpdM.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-Dp4t6tDQ.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-C8eaj_Mf.js b/assets/index.html-DENfAWCd.js similarity index 99% rename from assets/index.html-C8eaj_Mf.js rename to assets/index.html-DENfAWCd.js index 072912182..ec8b495ec 100644 --- a/assets/index.html-C8eaj_Mf.js +++ b/assets/index.html-DENfAWCd.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-BClOOpdM.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-Dp4t6tDQ.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-CrBamsFA.js b/assets/index.html-DaEmYnBK.js
                                      similarity index 97%
                                      rename from assets/index.html-CrBamsFA.js
                                      rename to assets/index.html-DaEmYnBK.js
                                      index 5cd8f7678..36029fbc1 100644
                                      --- a/assets/index.html-CrBamsFA.js
                                      +++ b/assets/index.html-DaEmYnBK.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-BClOOpdM.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-Dp4t6tDQ.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-CJ7rc5gT.js b/assets/index.html-DbxdBC_G.js
                                      similarity index 94%
                                      rename from assets/index.html-CJ7rc5gT.js
                                      rename to assets/index.html-DbxdBC_G.js
                                      index cda961c79..cba99968e 100644
                                      --- a/assets/index.html-CJ7rc5gT.js
                                      +++ b/assets/index.html-DbxdBC_G.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-BClOOpdM.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-Dp4t6tDQ.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-CBYNGVas.js b/assets/index.html-DdX7oNPd.js
                                      similarity index 98%
                                      rename from assets/index.html-CBYNGVas.js
                                      rename to assets/index.html-DdX7oNPd.js
                                      index cef7eec00..30356ac2c 100644
                                      --- a/assets/index.html-CBYNGVas.js
                                      +++ b/assets/index.html-DdX7oNPd.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-BClOOpdM.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-Dp4t6tDQ.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-CUdXYj6p.js b/assets/index.html-DiLddjw-.js
                                      similarity index 98%
                                      rename from assets/index.html-CUdXYj6p.js
                                      rename to assets/index.html-DiLddjw-.js
                                      index 230309177..5ccf5fe6d 100644
                                      --- a/assets/index.html-CUdXYj6p.js
                                      +++ b/assets/index.html-DiLddjw-.js
                                      @@ -1 +1 @@
                                      -import{_ as c,r as l,o as d,c as h,a as t,b as e,d as o,w as s}from"./app-BClOOpdM.js";const _={},i=e("h1",{id:"руководство-по-разработке",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#руководство-по-разработке"},[e("span",null,"Руководство по разработке")])],-1),u=e("h2",{id:"сборка-документации",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#сборка-документации"},[e("span",null,"Сборка документации")])],-1),p=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,"В этом разделе описываются правила, которым необходимо следовать при получении кода, разработке и отправке запросов на включение изменений (pull request), а также соответствующие стандарты кодирования.",-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"},S=e("p",null,"Протокол Mux.Cool - это транспортный протокол мультиплексирования, который используется для передачи нескольких независимых потоков данных по одному установленному потоку данных.",-1),w={id:"протокол-mkcp",tabindex:"-1"},B={class:"header-anchor",href:"#протокол-mkcp"},K={href:"https://github.com/skywind3000/kcp",target:"_blank",rel:"noopener noreferrer"};function N(P,T){const a=l("I18nTip"),n=l("RouterLink"),r=l("ExternalLinkIcon");return d(),h("div",null,[t(a),i,u,p,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})])])]),S,e("h3",w,[e("a",B,[e("span",null,[t(n,{to:"/ru/development/protocols/mkcp.html"},{default:s(()=>[o("Протокол mKCP")]),_:1})])])]),e("p",null,[o("mKCP - это потоковый транспортный протокол, основанный на "),e("a",K,[o("протоколе KCP"),t(r)]),o(", который может передавать любые потоки данных по порядку.")])])}const q=c(_,[["render",N],["__file","index.html.vue"]]);export{q as default};
                                      +import{_ as c,r as l,o as d,c as h,a as t,b as e,d as o,w as s}from"./app-Dp4t6tDQ.js";const _={},i=e("h1",{id:"руководство-по-разработке",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#руководство-по-разработке"},[e("span",null,"Руководство по разработке")])],-1),u=e("h2",{id:"сборка-документации",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#сборка-документации"},[e("span",null,"Сборка документации")])],-1),p=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,"В этом разделе описываются правила, которым необходимо следовать при получении кода, разработке и отправке запросов на включение изменений (pull request), а также соответствующие стандарты кодирования.",-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"},S=e("p",null,"Протокол Mux.Cool - это транспортный протокол мультиплексирования, который используется для передачи нескольких независимых потоков данных по одному установленному потоку данных.",-1),w={id:"протокол-mkcp",tabindex:"-1"},B={class:"header-anchor",href:"#протокол-mkcp"},K={href:"https://github.com/skywind3000/kcp",target:"_blank",rel:"noopener noreferrer"};function N(P,T){const a=l("I18nTip"),n=l("RouterLink"),r=l("ExternalLinkIcon");return d(),h("div",null,[t(a),i,u,p,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})])])]),S,e("h3",w,[e("a",B,[e("span",null,[t(n,{to:"/ru/development/protocols/mkcp.html"},{default:s(()=>[o("Протокол mKCP")]),_:1})])])]),e("p",null,[o("mKCP - это потоковый транспортный протокол, основанный на "),e("a",K,[o("протоколе KCP"),t(r)]),o(", который может передавать любые потоки данных по порядку.")])])}const q=c(_,[["render",N],["__file","index.html.vue"]]);export{q as default};
                                      diff --git a/assets/index.html-DJZ8xXVB.js b/assets/index.html-Di_c7H8I.js
                                      similarity index 97%
                                      rename from assets/index.html-DJZ8xXVB.js
                                      rename to assets/index.html-Di_c7H8I.js
                                      index 9a5ab3cae..0cca03e4a 100644
                                      --- a/assets/index.html-DJZ8xXVB.js
                                      +++ b/assets/index.html-Di_c7H8I.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-BClOOpdM.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-Dp4t6tDQ.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/index.html-d88pFbkg.js b/assets/index.html-Dw33NxP-.js
                                      similarity index 96%
                                      rename from assets/index.html-d88pFbkg.js
                                      rename to assets/index.html-Dw33NxP-.js
                                      index 4320bfbcc..d58e5c145 100644
                                      --- a/assets/index.html-d88pFbkg.js
                                      +++ b/assets/index.html-Dw33NxP-.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-BClOOpdM.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-Dp4t6tDQ.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-CCiP37z4.js b/assets/index.html-_0Ezskfc.js
                                      similarity index 98%
                                      rename from assets/index.html-CCiP37z4.js
                                      rename to assets/index.html-_0Ezskfc.js
                                      index 623a61482..b2f2f572f 100644
                                      --- a/assets/index.html-CCiP37z4.js
                                      +++ b/assets/index.html-_0Ezskfc.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-BClOOpdM.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-Dp4t6tDQ.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-a34UBYSn.js b/assets/index.html-gKYIFezi.js
                                      similarity index 99%
                                      rename from assets/index.html-a34UBYSn.js
                                      rename to assets/index.html-gKYIFezi.js
                                      index 685a635a8..4a0a02c3c 100644
                                      --- a/assets/index.html-a34UBYSn.js
                                      +++ b/assets/index.html-gKYIFezi.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-BClOOpdM.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-Dp4t6tDQ.js";const r={},d=i(`

                                      这个章节将告诉您所有的 Xray 配置细节,掌握这些内容,在您手中 Xray 将发挥更大威力。

                                      概述

                                      Xray 的配置文件为 json 格式, 客户端和服务端的配置格式没有区别, 只是实际的配置内容不一样。
                                      形式如下:

                                      {
                                         "log": {},
                                         "api": {},
                                         "dns": {},
                                      diff --git a/assets/index.html-CVR1ZGSF.js b/assets/index.html-gmKSBbSu.js
                                      similarity index 98%
                                      rename from assets/index.html-CVR1ZGSF.js
                                      rename to assets/index.html-gmKSBbSu.js
                                      index 187427281..26690d9f6 100644
                                      --- a/assets/index.html-CVR1ZGSF.js
                                      +++ b/assets/index.html-gmKSBbSu.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-BClOOpdM.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-Dp4t6tDQ.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-WChIF31z.js b/assets/index.html-mwD5RiEN.js
                                      similarity index 98%
                                      rename from assets/index.html-WChIF31z.js
                                      rename to assets/index.html-mwD5RiEN.js
                                      index f39ad6245..047f144e9 100644
                                      --- a/assets/index.html-WChIF31z.js
                                      +++ b/assets/index.html-mwD5RiEN.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-BClOOpdM.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-Dp4t6tDQ.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/infoDiagram-7APDZ6AT-CjHjl5ga.js b/assets/infoDiagram-7APDZ6AT-Cw5OHrUt.js
                                      similarity index 62%
                                      rename from assets/infoDiagram-7APDZ6AT-CjHjl5ga.js
                                      rename to assets/infoDiagram-7APDZ6AT-Cw5OHrUt.js
                                      index d77d82cdf..ebd090c89 100644
                                      --- a/assets/infoDiagram-7APDZ6AT-CjHjl5ga.js
                                      +++ b/assets/infoDiagram-7APDZ6AT-Cw5OHrUt.js
                                      @@ -1,2 +1,2 @@
                                      -import{_ as e,l as s,K as n,k as i,L as p}from"./mermaid.core-IUatkdtb.js";import{p as g}from"./gitGraph-YCYPL57B-BhMcSVnW.js";import"./app-BClOOpdM.js";import"./baseUniq-j141U2p6.js";import"./basePickBy-Cyiz-f_r.js";import"./clone-DBEsGdWr.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-VsNG6kTl.js";import{p as g}from"./gitGraph-YCYPL57B-CW0sFWI7.js";import"./app-Dp4t6tDQ.js";import"./baseUniq-Bpwj4IW2.js";import"./basePickBy-BMIT5f2S.js";import"./clone-CyxiHGLh.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-CzbCyu0D.js b/assets/install.html-BqABFEgq.js
                                      similarity index 99%
                                      rename from assets/install.html-CzbCyu0D.js
                                      rename to assets/install.html-BqABFEgq.js
                                      index 65be66325..6b490ba31 100644
                                      --- a/assets/install.html-CzbCyu0D.js
                                      +++ b/assets/install.html-BqABFEgq.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-BClOOpdM.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-Dp4t6tDQ.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-Bw8Wfs-_.js b/assets/install.html-DzAGXbV7.js similarity index 99% rename from assets/install.html-Bw8Wfs-_.js rename to assets/install.html-DzAGXbV7.js index 147dd6d90..ccb7be71a 100644 --- a/assets/install.html-Bw8Wfs-_.js +++ b/assets/install.html-DzAGXbV7.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-BClOOpdM.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-Dp4t6tDQ.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/install.html-uqLzyLFC.js b/assets/install.html-EtxbwpEb.js similarity index 99% rename from assets/install.html-uqLzyLFC.js rename to assets/install.html-EtxbwpEb.js index 7d481e124..c50cc6f57 100644 --- a/assets/install.html-uqLzyLFC.js +++ b/assets/install.html-EtxbwpEb.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-BClOOpdM.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-Dp4t6tDQ.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/iptables_gid.html-B7BAabEG.js b/assets/iptables_gid.html-8qdut9aE.js similarity index 99% rename from assets/iptables_gid.html-B7BAabEG.js rename to assets/iptables_gid.html-8qdut9aE.js index 631dafa1a..3a4dcf961 100644 --- a/assets/iptables_gid.html-B7BAabEG.js +++ b/assets/iptables_gid.html-8qdut9aE.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-BClOOpdM.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-Dp4t6tDQ.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-DiTyvfAc.js b/assets/iptables_gid.html-BioBNJrh.js
                                      similarity index 99%
                                      rename from assets/iptables_gid.html-DiTyvfAc.js
                                      rename to assets/iptables_gid.html-BioBNJrh.js
                                      index ae4d85ec1..62df410c7 100644
                                      --- a/assets/iptables_gid.html-DiTyvfAc.js
                                      +++ b/assets/iptables_gid.html-BioBNJrh.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-BClOOpdM.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-Dp4t6tDQ.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/iptables_gid.html-C0pRP5Rs.js b/assets/iptables_gid.html-DNk5paAn.js
                                      similarity index 99%
                                      rename from assets/iptables_gid.html-C0pRP5Rs.js
                                      rename to assets/iptables_gid.html-DNk5paAn.js
                                      index 72d547478..a3649c992 100644
                                      --- a/assets/iptables_gid.html-C0pRP5Rs.js
                                      +++ b/assets/iptables_gid.html-DNk5paAn.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-BClOOpdM.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-Dp4t6tDQ.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/journeyDiagram-G5LC7W2K-nbd-YhOX.js b/assets/journeyDiagram-G5LC7W2K-D5obEO4H.js
                                      similarity index 98%
                                      rename from assets/journeyDiagram-G5LC7W2K-nbd-YhOX.js
                                      rename to assets/journeyDiagram-G5LC7W2K-D5obEO4H.js
                                      index 7c0e47a89..907c92bd7 100644
                                      --- a/assets/journeyDiagram-G5LC7W2K-nbd-YhOX.js
                                      +++ b/assets/journeyDiagram-G5LC7W2K-D5obEO4H.js
                                      @@ -1,4 +1,4 @@
                                      -import{d as ft,f as gt,g as at,b as mt}from"./chunk-XVOYOM2C-fmD0yIZV.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-IUatkdtb.js";import{d as tt}from"./arc-BJstDFsX.js";import"./app-BClOOpdM.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-XVOYOM2C-BZTXkaha.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-VsNG6kTl.js";import{d as tt}from"./arc-TolVAfGG.js";import"./app-Dp4t6tDQ.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-BbAt_51R.js b/assets/json-BpfjFNGZ.js
                                      similarity index 68%
                                      rename from assets/json-BbAt_51R.js
                                      rename to assets/json-BpfjFNGZ.js
                                      index 0603510a3..efa8357b1 100644
                                      --- a/assets/json-BbAt_51R.js
                                      +++ b/assets/json-BpfjFNGZ.js
                                      @@ -1 +1 @@
                                      -import"./graph-CKGFjaQu.js";import{i as o}from"./baseUniq-j141U2p6.js";import{c as d}from"./clone-DBEsGdWr.js";import{m as t}from"./basePickBy-Cyiz-f_r.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-DebN9_Dg.js";import{i as o}from"./baseUniq-Bpwj4IW2.js";import{c as d}from"./clone-CyxiHGLh.js";import{m as t}from"./basePickBy-BMIT5f2S.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-Bmwgbrwx.js b/assets/layout-BkNI4twY.js
                                      similarity index 99%
                                      rename from assets/layout-Bmwgbrwx.js
                                      rename to assets/layout-BkNI4twY.js
                                      index 096676f5c..b2c35c188 100644
                                      --- a/assets/layout-Bmwgbrwx.js
                                      +++ b/assets/layout-BkNI4twY.js
                                      @@ -1 +1 @@
                                      -import{G as k}from"./graph-CKGFjaQu.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 M,v as y,r as O}from"./baseUniq-j141U2p6.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-Cyiz-f_r.js";import{b4 as Dn,b5 as qn,b6 as $n,aM as Wn,b7 as jn,aQ as mn,aP as wn,b8 as zn,aL as W,ay as Xn,aS as Un,aA as Hn,b9 as j}from"./mermaid.core-IUatkdtb.js";function Jn(n){return Dn(qn(n,void 0,N),n+"")}var Qn=1,Zn=4;function Kn(n){return Pn(n,Qn|Zn)}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=M(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,{}),K(n),Z(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=Q;function Ue(n){Q(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=Qe(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 Qe(n){return O(n.edges(),function(e,r){return e+n.edge(r).weight},0)}function Ze(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 Ke(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=M(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=I(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=M(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(M(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=I(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 Mn(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=M(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=Mn(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)&&In(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 In(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=I(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=M(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,{}),K(n),Z(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=Q;function Ue(n){Q(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=Qe(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 Qe(n){return O(n.edges(),function(e,r){return e+n.edge(r).weight},0)}function Ze(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 Ke(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=M(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=I(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=M(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(M(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=I(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 Mn(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=M(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=Mn(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)&&In(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 In(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=I(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 _(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=_(F),dn=sn.right;_(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 Z(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 H={"%":(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)=>Z(n*100,t),r:Z,s:Fn,X:n=>Math.round(n).toString(16).toUpperCase(),x:n=>Math.round(n).toString(16)};function J(n){return n}var K=Array.prototype.map,Q=["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?J:jn(K.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?J:Pn(K.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"):H[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=H[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"?Q[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=Q[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 W=[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 Un(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 Yn(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 Un(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 Zn(){var n=Xn();return n.copy=function(){return On(n,Zn())},cn.apply(n,arguments),Yn(n)}export{On as a,_ as b,Xn as c,Zn as l,wn as t};
                                      +import{a$ as un,b0 as I,b1 as U,b2 as Y,b3 as fn}from"./mermaid.core-VsNG6kTl.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 _(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=_(F),dn=sn.right;_(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 Z(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 H={"%":(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)=>Z(n*100,t),r:Z,s:Fn,X:n=>Math.round(n).toString(16).toUpperCase(),x:n=>Math.round(n).toString(16)};function J(n){return n}var K=Array.prototype.map,Q=["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?J:jn(K.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?J:Pn(K.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"):H[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=H[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"?Q[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=Q[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 W=[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 Un(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 Yn(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 Un(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 Zn(){var n=Xn();return n.copy=function(){return On(n,Zn())},cn.apply(n,arguments),Yn(n)}export{On as a,_ as b,Xn as c,Zn as l,wn as t};
                                      diff --git a/assets/log.html-B-5T4nul.js b/assets/log.html-B5OAPKR7.js
                                      similarity index 97%
                                      rename from assets/log.html-B-5T4nul.js
                                      rename to assets/log.html-B5OAPKR7.js
                                      index 6df10e48d..1e3fbcf16 100644
                                      --- a/assets/log.html-B-5T4nul.js
                                      +++ b/assets/log.html-B5OAPKR7.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as e,r as t,o as n,c as a,a as s,e as l}from"./app-BClOOpdM.js";const c={},r=l(`

                                      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 l}from"./app-Dp4t6tDQ.js";const c={},r=l(`

                                      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-D7gRP2SF.js b/assets/log.html-BXL_0fB7.js
                                      similarity index 99%
                                      rename from assets/log.html-D7gRP2SF.js
                                      rename to assets/log.html-BXL_0fB7.js
                                      index ede922d64..7a87e2d67 100644
                                      --- a/assets/log.html-D7gRP2SF.js
                                      +++ b/assets/log.html-BXL_0fB7.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as e,r as n,o as s,c as t,a,e as c}from"./app-BClOOpdM.js";const l={},u=c(`

                                      Настройка журнала

                                      Настройка журнала управляет тем, как Xray выводит журналы.

                                      Xray имеет два типа журналов: журнал доступа и журнал ошибок.
                                      Вы можете настроить способ вывода каждого типа журнала отдельно.

                                      LogObject

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

                                      {
                                      +import{_ as e,r as n,o as s,c as t,a,e as c}from"./app-Dp4t6tDQ.js";const l={},u=c(`

                                      Настройка журнала

                                      Настройка журнала управляет тем, как Xray выводит журналы.

                                      Xray имеет два типа журналов: журнал доступа и журнал ошибок.
                                      Вы можете настроить способ вывода каждого типа журнала отдельно.

                                      LogObject

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

                                      {
                                         "log": {
                                           "access": "путь/к/файлу",
                                           "error": "путь/к/файлу",
                                      diff --git a/assets/log.html-DoZScHqi.js b/assets/log.html-Bo--iN1M.js
                                      similarity index 97%
                                      rename from assets/log.html-DoZScHqi.js
                                      rename to assets/log.html-Bo--iN1M.js
                                      index 3094f9a2a..602fb9f41 100644
                                      --- a/assets/log.html-DoZScHqi.js
                                      +++ b/assets/log.html-Bo--iN1M.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-BClOOpdM.js";const l={},u=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-Dp4t6tDQ.js";const l={},u=c(`

                                      日志配置

                                      日志配置,控制 Xray 输出日志的方式.

                                      Xray 有两种日志, 访问日志和错误日志, 你可以分别配置两种日志的输出方式.

                                      LogObject

                                      LogObject 对应配置文件的 log 项。

                                      {
                                         "log": {
                                           "access": "文件地址",
                                           "error": "文件地址",
                                      diff --git a/assets/loopback.html-HZZKgpGg.js b/assets/loopback.html-DNsapIsk.js
                                      similarity index 99%
                                      rename from assets/loopback.html-HZZKgpGg.js
                                      rename to assets/loopback.html-DNsapIsk.js
                                      index bc7a42c10..c79324ceb 100644
                                      --- a/assets/loopback.html-HZZKgpGg.js
                                      +++ b/assets/loopback.html-DNsapIsk.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as s,r as a,o as t,c as o,a as p,e}from"./app-BClOOpdM.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-Dp4t6tDQ.js";const c={},u=e(`

                                      Loopback

                                      Loopback 是个出站数据协议,其作用为将经该出站传出的数据重新送入路由入站,以达到数据无需离开 Xray-core 即可再次被路由处理的效果。

                                      OutboundConfigurationObject

                                      {
                                         "inboundTag": "TagUseAsInbound"
                                       }
                                       

                                      inboundTag: string

                                      用于重新路由的入站协议标识。

                                      该标识可以在路由中用于 inboundTag ,表示该出站中的数据可以被对应的路由规则再次处理。

                                      如何使用?

                                      如果需要将已经通过路由规则分流过的流量再由其它路由规则做更细致的分流,比如由同一组路由规则分流后的 TCP 流量和 UDP 要走不同的出站,则可以使用 loopback 出站完成。

                                      {
                                      diff --git a/assets/loopback.html-Ni1oAZCT.js b/assets/loopback.html-f6MTGwlS.js
                                      similarity index 99%
                                      rename from assets/loopback.html-Ni1oAZCT.js
                                      rename to assets/loopback.html-f6MTGwlS.js
                                      index 4898a5164..39aca393a 100644
                                      --- a/assets/loopback.html-Ni1oAZCT.js
                                      +++ b/assets/loopback.html-f6MTGwlS.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as s,r as a,o as t,c as o,a as p,e}from"./app-BClOOpdM.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-Dp4t6tDQ.js";const c={},u=e(`

                                      Loopback

                                      Loopback - это исходящий протокол данных, который перенаправляет данные, прошедшие через это исходящее соединение, обратно на вход маршрутизатора, что позволяет повторно обработать данные по правилам маршрутизации, не покидая Xray-core.

                                      OutboundConfigurationObject

                                      {
                                         "inboundTag": "TagUseAsInbound"
                                       }
                                       

                                      inboundTag: string

                                      Идентификатор входящего протокола, используемый для повторной маршрутизации.

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

                                      Как использовать?

                                      Если необходимо, чтобы трафик, уже разделенный по правилам маршрутизации, был перенаправлен другими правилами маршрутизации (например, трафик TCP и UDP, разделенный одними и теми же правилами маршрутизации, должен идти через разные исходящие соединения), можно использовать исходящее соединение loopback.

                                      {
                                      diff --git a/assets/loopback.html-4t4spiuV.js b/assets/loopback.html-lkkEOlDw.js
                                      similarity index 96%
                                      rename from assets/loopback.html-4t4spiuV.js
                                      rename to assets/loopback.html-lkkEOlDw.js
                                      index 250c17f04..4b03bfd6b 100644
                                      --- a/assets/loopback.html-4t4spiuV.js
                                      +++ b/assets/loopback.html-lkkEOlDw.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-BClOOpdM.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-Dp4t6tDQ.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/mermaid.core-IUatkdtb.js b/assets/mermaid.core-VsNG6kTl.js
                                      similarity index 99%
                                      rename from assets/mermaid.core-IUatkdtb.js
                                      rename to assets/mermaid.core-VsNG6kTl.js
                                      index bb27b6249..34c9f9f4a 100644
                                      --- a/assets/mermaid.core-IUatkdtb.js
                                      +++ b/assets/mermaid.core-VsNG6kTl.js
                                      @@ -1,4 +1,4 @@
                                      -var ig=Object.defineProperty;var ng=(t,e,r)=>e in t?ig(t,e,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[e]=r;var rt=(t,e,r)=>(ng(t,typeof e!="symbol"?e+"":e,r),r),ag=(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)=>(ag(t,e,"access private method"),r);import{h as it}from"./app-BClOOpdM.js";var sg=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{};function og(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}var Zc={exports:{}};(function(t,e){(function(r,i){t.exports=i()})(sg,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",x=/^(\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,b={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 A=["th","st","nd","rd"],T=M%100;return"["+M+(A[(T-20)%10]||A[T]||A[0])+"]"}},v=function(M,A,T){var F=String(M);return!F||F.length>=A?M:""+Array(A+1-F.length).join(T)+M},L={s:v,z:function(M){var A=-M.utcOffset(),T=Math.abs(A),F=Math.floor(T/60),S=T%60;return(A<=0?"+":"-")+v(F,2,"0")+":"+v(S,2,"0")},m:function M(A,T){if(A.date()1)return M(I[0])}else{var J=A.name;$[J]=A,S=J}return!F&&S&&(O=S),S||!F&&O},R=function(M,A){if(G(M))return M.clone();var T=typeof A=="object"?A:{};return T.date=M,T.args=arguments,new lt(T)},D=L;D.l=Z,D.i=G,D.w=function(M,A){return R(M,{locale:A.$L,utc:A.$u,x:A.$x,$offset:A.$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 A=M.prototype;return A.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(x);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()},A.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()},A.$utils=function(){return D},A.isValid=function(){return this.$d.toString()!==m},A.isSame=function(T,F){var S=R(T);return this.startOf(F)<=S&&S<=this.endOf(F)},A.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},ug={dec2hex:t=>{const e=Math.round(t).toString(16);return e.length>1?e:`0${e}`}},U={channel:ln,lang:hg,unit:ug},Me={};for(let t=0;t<=255;t++)Me[t]=U.unit.dec2hex(t);const wt={ALL:0,RGB:1,HSL:2};class fg{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 dg{constructor(e,r){this.color=r,this.changed=!1,this.data=e,this.type=new fg}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 na=new dg({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 na.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 na.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 na.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)},Kc=(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 Kc(t,{a:e});const n=na.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)},pg=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)},gg=t=>pg(t)>=.5,Mi=t=>!gg(t),Qc=(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)=>Qc(t,"l",e),W=(t,e)=>Qc(t,"l",-e),_=(t,e)=>{const r=fe.parse(t),i={};for(const n in e)e[n]&&(i[n]=r[n]+e[n]);return Kc(t,i)},mg=(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,x=1-m,C=i*m+o*x,b=n*m+l*x,v=a*m+c*x,L=s*f+h*(1-f);return ti(C,b,v,L)},B=(t,e=100)=>{const r=fe.parse(t);return r.r=255-r.r,r.g=255-r.g,r.b=255-r.b,mg(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:Jc,setPrototypeOf:xl,isFrozen:yg,getPrototypeOf:xg,getOwnPropertyDescriptor:bg}=Object;let{freeze:It,seal:Xt,create:th}=Object,{apply:es,construct:rs}=typeof Reflect<"u"&&Reflect;It||(It=function(e){return e});Xt||(Xt=function(e){return e});es||(es=function(e,r,i){return e.apply(r,i)});rs||(rs=function(e,r){return new e(...r)});const Xi=jt(Array.prototype.forEach),bl=jt(Array.prototype.pop),Rr=jt(Array.prototype.push),cn=jt(String.prototype.toLowerCase),Ia=jt(String.prototype.toString),_l=jt(String.prototype.match),Dr=jt(String.prototype.replace),_g=jt(String.prototype.indexOf),Cg=jt(String.prototype.trim),Kt=jt(Object.prototype.hasOwnProperty),Ft=jt(RegExp.prototype.test),Pr=vg(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;xl&&xl(t,null);let i=e.length;for(;i--;){let n=e[i];if(typeof n=="string"){const a=r(n);a!==n&&(yg(e)||(e[i]=a),n=a)}t[n]=!0}return t}function kg(t){for(let e=0;e/gm),Ag=Xt(/\${[\w\W]*}/gm),Bg=Xt(/^data-[\-\w.\u00B7-\uFFFF]/),Eg=Xt(/^aria-[\-\w]+$/),eh=Xt(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i),Mg=Xt(/^(?:\w+script|data):/i),Fg=Xt(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g),rh=Xt(/^html$/i),Og=Xt(/^[a-z][.\w]*(-[.\w]+)+$/i);var Tl=Object.freeze({__proto__:null,MUSTACHE_EXPR:Sg,ERB_EXPR:Lg,TMPLIT_EXPR:Ag,DATA_ATTR:Bg,ARIA_ATTR:Eg,IS_ALLOWED_URI:eh,IS_SCRIPT_OR_DATA:Mg,ATTR_WHITESPACE:Fg,DOCTYPE_NAME:rh,CUSTOM_ELEMENT:Og});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},$g=function(){return typeof window>"u"?null:window},Ig=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 ih(){let t=arguments.length>0&&arguments[0]!==void 0?arguments[0]:$g();const e=z=>ih(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"),x=Zi(g,"nextSibling"),C=Zi(g,"childNodes"),b=Zi(g,"parentNode");if(typeof s=="function"){const z=r.createElement("template");z.content&&z.content.ownerDocument&&(r=z.content.ownerDocument)}let v,L="";const{implementation:O,createNodeIterator:$,createDocumentFragment:E,getElementsByTagName:G}=r,{importNode:Z}=i;let R={};e.isSupported=typeof Jc=="function"&&typeof b=="function"&&O&&O.createHTMLDocument!==void 0;const{MUSTACHE_EXPR:D,ERB_EXPR:lt,TMPLIT_EXPR:st,DATA_ATTR:M,ARIA_ATTR:A,IS_SCRIPT_OR_DATA:T,ATTR_WHITESPACE:F,CUSTOM_ELEMENT:S}=Tl;let{IS_ALLOWED_URI:H}=Tl,I=null;const J=X({},[...Cl,...Ra,...Da,...Pa,...vl]);let Y=null;const ct=X({},[...kl,...Na,...wl,...Ki]);let V=Object.seal(th(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,Aa=!1,Ba=!1,ar=!1,Hi=!1,ji=!1,Ko=!0,Qo=!1;const Xp="user-content-";let Ea=!0,Fr=!1,sr={},or=null;const Jo=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 tl=null;const el=X({},["audio","video","img","source","image","track"]);let Ma=null;const rl=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,Fa=!1,Oa=null;const Zp=X({},[Ui,Yi,xe],Ia);let Or=null;const Kp=["application/xhtml+xml","text/html"],Qp="text/html";let mt=null,cr=null;const Jp=r.createElement("form"),il=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),Or=Kp.indexOf(y.PARSER_MEDIA_TYPE)===-1?Qp:y.PARSER_MEDIA_TYPE,mt=Or==="application/xhtml+xml"?Ia:cn,I=Kt(y,"ALLOWED_TAGS")?X({},y.ALLOWED_TAGS,mt):J,Y=Kt(y,"ALLOWED_ATTR")?X({},y.ALLOWED_ATTR,mt):ct,Oa=Kt(y,"ALLOWED_NAMESPACES")?X({},y.ALLOWED_NAMESPACES,Ia):Zp,Ma=Kt(y,"ADD_URI_SAFE_ATTR")?X(Ne(rl),y.ADD_URI_SAFE_ATTR,mt):rl,tl=Kt(y,"ADD_DATA_URI_TAGS")?X(Ne(el),y.ADD_DATA_URI_TAGS,mt):el,or=Kt(y,"FORBID_CONTENTS")?X({},y.FORBID_CONTENTS,mt):Jo,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,Ba=y.FORCE_BODY||!1,Ko=y.SANITIZE_DOM!==!1,Qo=y.SANITIZE_NAMED_PROPS||!1,Ea=y.KEEP_CONTENT!==!1,Fr=y.IN_PLACE||!1,H=y.ALLOWED_URI_REGEXP||eh,lr=y.NAMESPACE||xe,V=y.CUSTOM_ELEMENT_HANDLING||{},y.CUSTOM_ELEMENT_HANDLING&&il(y.CUSTOM_ELEMENT_HANDLING.tagNameCheck)&&(V.tagNameCheck=y.CUSTOM_ELEMENT_HANDLING.tagNameCheck),y.CUSTOM_ELEMENT_HANDLING&&il(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({},vl),Y=[],sr.html===!0&&(X(I,Cl),X(Y,kl)),sr.svg===!0&&(X(I,Ra),X(Y,Na),X(Y,Ki)),sr.svgFilters===!0&&(X(I,Da),X(Y,Na),X(Y,Ki)),sr.mathMl===!0&&(X(I,Pa),X(Y,wl),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(Ma,y.ADD_URI_SAFE_ATTR,mt),y.FORBID_CONTENTS&&(or===Jo&&(or=Ne(or)),X(or,y.FORBID_CONTENTS,mt)),Ea&&(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,L=v.createHTML("")}else v===void 0&&(v=Ig(p,n)),v!==null&&typeof L=="string"&&(L=v.createHTML(""));It&&It(y),cr=y}},nl=X({},["mi","mo","mn","ms","mtext"]),al=X({},["foreignobject","annotation-xml"]),tg=X({},["title","style","font","a","script"]),sl=X({},[...Ra,...Da,...wg]),ol=X({},[...Pa,...Tg]),eg=function(y){let w=b(y);(!w||!w.tagName)&&(w={namespaceURI:lr,tagName:"template"});const P=cn(y.tagName),et=cn(w.tagName);return Oa[y.namespaceURI]?y.namespaceURI===Yi?w.namespaceURI===xe?P==="svg":w.namespaceURI===Ui?P==="svg"&&(et==="annotation-xml"||nl[et]):!!sl[P]:y.namespaceURI===Ui?w.namespaceURI===xe?P==="math":w.namespaceURI===Yi?P==="math"&&al[et]:!!ol[P]:y.namespaceURI===xe?w.namespaceURI===Yi&&!al[et]||w.namespaceURI===Ui&&!nl[et]?!1:!ol[P]&&(tg[P]||!sl[P]):!!(Or==="application/xhtml+xml"&&Oa[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{}},ll=function(y){let w=null,P=null;if(Ba)y=""+y;else{const bt=_l(y,/^[\r\n\t ]+/);P=bt&&bt[0]}Or==="application/xhtml+xml"&&lr===xe&&(y=''+y+"");const et=v?v.createHTML(y):y;if(lr===xe)try{w=new u().parseFromString(et,Or)}catch{}if(!w||!w.documentElement){w=O.createDocument(lr,"template",null);try{w.documentElement.innerHTML=Fa?L: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},cl=function(y){return $.call(y.ownerDocument||y,y,c.SHOW_ELEMENT|c.SHOW_COMMENT|c.SHOW_TEXT|c.SHOW_PROCESSING_INSTRUCTION|c.SHOW_CDATA_SECTION,null)},hl=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")},ul=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)})},fl=function(y){let w=null;if(be("beforeSanitizeElements",y,null),hl(y))return se(y),!0;const P=mt(y.nodeName);if(be("uponSanitizeElement",y,{tagName:P,allowedTags:I}),y.hasChildNodes()&&!ul(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]&&pl(P)&&(V.tagNameCheck instanceof RegExp&&Ft(V.tagNameCheck,P)||V.tagNameCheck instanceof Function&&V.tagNameCheck(P)))return!1;if(Ea&&!or[P]){const et=b(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,x(y))}}}return se(y),!0}return y instanceof l&&!eg(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)},dl=function(y,w,P){if(Ko&&(w==="id"||w==="name")&&(P in r||P in Jp))return!1;if(!(me&&!ie[w]&&Ft(M,w))){if(!(ne&&Ft(A,w))){if(!Y[w]||ie[w]){if(!(pl(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(!Ma[w]){if(!Ft(H,Dr(P,F,""))){if(!((w==="src"||w==="xlink:href"||w==="href")&&y!=="script"&&_g(P,"data:")===0&&tl[y])){if(!(ae&&!Ft(T,Dr(P,F,"")))){if(P)return!1}}}}}}return!0},pl=function(y){return y!=="annotation-xml"&&_l(y,S)},gl=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,$r=mt(bt);let Mt=bt==="value"?oe:Cg(oe);if(P.attrName=$r,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],yl=>{Mt=Dr(Mt,yl," ")});const ml=mt(y.nodeName);if(dl(ml,$r,Mt)){if(Qo&&($r==="id"||$r==="name")&&(Gi(bt,y),Mt=Xp+Mt),v&&typeof p=="object"&&typeof p.getAttributeType=="function"&&!Rt)switch(p.getAttributeType(ml,$r)){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),hl(y)?se(y):bl(e.removed)}catch{}}}be("afterSanitizeAttributes",y,null)},rg=function z(y){let w=null;const P=cl(y);for(be("beforeSanitizeShadowDOM",y,null);w=P.nextNode();)be("uponSanitizeShadowNode",w,null),!fl(w)&&(w.content instanceof a&&z(w.content),gl(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(Fa=!z,Fa&&(z=""),typeof z!="string"&&!ul(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(Aa||$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=ll(""),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=ll(z),!w)return ar?null:ji?L:""}w&&Ba&&se(w.firstChild);const bt=cl(Fr?z:w);for(;et=bt.nextNode();)fl(et)||(et.content instanceof a&&rg(et.content),gl(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(rh,w.ownerDocument.doctype.name)&&(Rt="
                                      +var ig=Object.defineProperty;var ng=(t,e,r)=>e in t?ig(t,e,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[e]=r;var rt=(t,e,r)=>(ng(t,typeof e!="symbol"?e+"":e,r),r),ag=(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)=>(ag(t,e,"access private method"),r);import{h as it}from"./app-Dp4t6tDQ.js";var sg=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{};function og(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}var Zc={exports:{}};(function(t,e){(function(r,i){t.exports=i()})(sg,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",x=/^(\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,b={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 A=["th","st","nd","rd"],T=M%100;return"["+M+(A[(T-20)%10]||A[T]||A[0])+"]"}},v=function(M,A,T){var F=String(M);return!F||F.length>=A?M:""+Array(A+1-F.length).join(T)+M},L={s:v,z:function(M){var A=-M.utcOffset(),T=Math.abs(A),F=Math.floor(T/60),S=T%60;return(A<=0?"+":"-")+v(F,2,"0")+":"+v(S,2,"0")},m:function M(A,T){if(A.date()1)return M(I[0])}else{var J=A.name;$[J]=A,S=J}return!F&&S&&(O=S),S||!F&&O},R=function(M,A){if(G(M))return M.clone();var T=typeof A=="object"?A:{};return T.date=M,T.args=arguments,new lt(T)},D=L;D.l=Z,D.i=G,D.w=function(M,A){return R(M,{locale:A.$L,utc:A.$u,x:A.$x,$offset:A.$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 A=M.prototype;return A.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(x);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()},A.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()},A.$utils=function(){return D},A.isValid=function(){return this.$d.toString()!==m},A.isSame=function(T,F){var S=R(T);return this.startOf(F)<=S&&S<=this.endOf(F)},A.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},ug={dec2hex:t=>{const e=Math.round(t).toString(16);return e.length>1?e:`0${e}`}},U={channel:ln,lang:hg,unit:ug},Me={};for(let t=0;t<=255;t++)Me[t]=U.unit.dec2hex(t);const wt={ALL:0,RGB:1,HSL:2};class fg{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 dg{constructor(e,r){this.color=r,this.changed=!1,this.data=e,this.type=new fg}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 na=new dg({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 na.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 na.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 na.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)},Kc=(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 Kc(t,{a:e});const n=na.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)},pg=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)},gg=t=>pg(t)>=.5,Mi=t=>!gg(t),Qc=(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)=>Qc(t,"l",e),W=(t,e)=>Qc(t,"l",-e),_=(t,e)=>{const r=fe.parse(t),i={};for(const n in e)e[n]&&(i[n]=r[n]+e[n]);return Kc(t,i)},mg=(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,x=1-m,C=i*m+o*x,b=n*m+l*x,v=a*m+c*x,L=s*f+h*(1-f);return ti(C,b,v,L)},B=(t,e=100)=>{const r=fe.parse(t);return r.r=255-r.r,r.g=255-r.g,r.b=255-r.b,mg(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:Jc,setPrototypeOf:xl,isFrozen:yg,getPrototypeOf:xg,getOwnPropertyDescriptor:bg}=Object;let{freeze:It,seal:Xt,create:th}=Object,{apply:es,construct:rs}=typeof Reflect<"u"&&Reflect;It||(It=function(e){return e});Xt||(Xt=function(e){return e});es||(es=function(e,r,i){return e.apply(r,i)});rs||(rs=function(e,r){return new e(...r)});const Xi=jt(Array.prototype.forEach),bl=jt(Array.prototype.pop),Rr=jt(Array.prototype.push),cn=jt(String.prototype.toLowerCase),Ia=jt(String.prototype.toString),_l=jt(String.prototype.match),Dr=jt(String.prototype.replace),_g=jt(String.prototype.indexOf),Cg=jt(String.prototype.trim),Kt=jt(Object.prototype.hasOwnProperty),Ft=jt(RegExp.prototype.test),Pr=vg(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;xl&&xl(t,null);let i=e.length;for(;i--;){let n=e[i];if(typeof n=="string"){const a=r(n);a!==n&&(yg(e)||(e[i]=a),n=a)}t[n]=!0}return t}function kg(t){for(let e=0;e/gm),Ag=Xt(/\${[\w\W]*}/gm),Bg=Xt(/^data-[\-\w.\u00B7-\uFFFF]/),Eg=Xt(/^aria-[\-\w]+$/),eh=Xt(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i),Mg=Xt(/^(?:\w+script|data):/i),Fg=Xt(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g),rh=Xt(/^html$/i),Og=Xt(/^[a-z][.\w]*(-[.\w]+)+$/i);var Tl=Object.freeze({__proto__:null,MUSTACHE_EXPR:Sg,ERB_EXPR:Lg,TMPLIT_EXPR:Ag,DATA_ATTR:Bg,ARIA_ATTR:Eg,IS_ALLOWED_URI:eh,IS_SCRIPT_OR_DATA:Mg,ATTR_WHITESPACE:Fg,DOCTYPE_NAME:rh,CUSTOM_ELEMENT:Og});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},$g=function(){return typeof window>"u"?null:window},Ig=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 ih(){let t=arguments.length>0&&arguments[0]!==void 0?arguments[0]:$g();const e=z=>ih(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"),x=Zi(g,"nextSibling"),C=Zi(g,"childNodes"),b=Zi(g,"parentNode");if(typeof s=="function"){const z=r.createElement("template");z.content&&z.content.ownerDocument&&(r=z.content.ownerDocument)}let v,L="";const{implementation:O,createNodeIterator:$,createDocumentFragment:E,getElementsByTagName:G}=r,{importNode:Z}=i;let R={};e.isSupported=typeof Jc=="function"&&typeof b=="function"&&O&&O.createHTMLDocument!==void 0;const{MUSTACHE_EXPR:D,ERB_EXPR:lt,TMPLIT_EXPR:st,DATA_ATTR:M,ARIA_ATTR:A,IS_SCRIPT_OR_DATA:T,ATTR_WHITESPACE:F,CUSTOM_ELEMENT:S}=Tl;let{IS_ALLOWED_URI:H}=Tl,I=null;const J=X({},[...Cl,...Ra,...Da,...Pa,...vl]);let Y=null;const ct=X({},[...kl,...Na,...wl,...Ki]);let V=Object.seal(th(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,Aa=!1,Ba=!1,ar=!1,Hi=!1,ji=!1,Ko=!0,Qo=!1;const Xp="user-content-";let Ea=!0,Fr=!1,sr={},or=null;const Jo=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 tl=null;const el=X({},["audio","video","img","source","image","track"]);let Ma=null;const rl=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,Fa=!1,Oa=null;const Zp=X({},[Ui,Yi,xe],Ia);let Or=null;const Kp=["application/xhtml+xml","text/html"],Qp="text/html";let mt=null,cr=null;const Jp=r.createElement("form"),il=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),Or=Kp.indexOf(y.PARSER_MEDIA_TYPE)===-1?Qp:y.PARSER_MEDIA_TYPE,mt=Or==="application/xhtml+xml"?Ia:cn,I=Kt(y,"ALLOWED_TAGS")?X({},y.ALLOWED_TAGS,mt):J,Y=Kt(y,"ALLOWED_ATTR")?X({},y.ALLOWED_ATTR,mt):ct,Oa=Kt(y,"ALLOWED_NAMESPACES")?X({},y.ALLOWED_NAMESPACES,Ia):Zp,Ma=Kt(y,"ADD_URI_SAFE_ATTR")?X(Ne(rl),y.ADD_URI_SAFE_ATTR,mt):rl,tl=Kt(y,"ADD_DATA_URI_TAGS")?X(Ne(el),y.ADD_DATA_URI_TAGS,mt):el,or=Kt(y,"FORBID_CONTENTS")?X({},y.FORBID_CONTENTS,mt):Jo,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,Ba=y.FORCE_BODY||!1,Ko=y.SANITIZE_DOM!==!1,Qo=y.SANITIZE_NAMED_PROPS||!1,Ea=y.KEEP_CONTENT!==!1,Fr=y.IN_PLACE||!1,H=y.ALLOWED_URI_REGEXP||eh,lr=y.NAMESPACE||xe,V=y.CUSTOM_ELEMENT_HANDLING||{},y.CUSTOM_ELEMENT_HANDLING&&il(y.CUSTOM_ELEMENT_HANDLING.tagNameCheck)&&(V.tagNameCheck=y.CUSTOM_ELEMENT_HANDLING.tagNameCheck),y.CUSTOM_ELEMENT_HANDLING&&il(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({},vl),Y=[],sr.html===!0&&(X(I,Cl),X(Y,kl)),sr.svg===!0&&(X(I,Ra),X(Y,Na),X(Y,Ki)),sr.svgFilters===!0&&(X(I,Da),X(Y,Na),X(Y,Ki)),sr.mathMl===!0&&(X(I,Pa),X(Y,wl),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(Ma,y.ADD_URI_SAFE_ATTR,mt),y.FORBID_CONTENTS&&(or===Jo&&(or=Ne(or)),X(or,y.FORBID_CONTENTS,mt)),Ea&&(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,L=v.createHTML("")}else v===void 0&&(v=Ig(p,n)),v!==null&&typeof L=="string"&&(L=v.createHTML(""));It&&It(y),cr=y}},nl=X({},["mi","mo","mn","ms","mtext"]),al=X({},["foreignobject","annotation-xml"]),tg=X({},["title","style","font","a","script"]),sl=X({},[...Ra,...Da,...wg]),ol=X({},[...Pa,...Tg]),eg=function(y){let w=b(y);(!w||!w.tagName)&&(w={namespaceURI:lr,tagName:"template"});const P=cn(y.tagName),et=cn(w.tagName);return Oa[y.namespaceURI]?y.namespaceURI===Yi?w.namespaceURI===xe?P==="svg":w.namespaceURI===Ui?P==="svg"&&(et==="annotation-xml"||nl[et]):!!sl[P]:y.namespaceURI===Ui?w.namespaceURI===xe?P==="math":w.namespaceURI===Yi?P==="math"&&al[et]:!!ol[P]:y.namespaceURI===xe?w.namespaceURI===Yi&&!al[et]||w.namespaceURI===Ui&&!nl[et]?!1:!ol[P]&&(tg[P]||!sl[P]):!!(Or==="application/xhtml+xml"&&Oa[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{}},ll=function(y){let w=null,P=null;if(Ba)y=""+y;else{const bt=_l(y,/^[\r\n\t ]+/);P=bt&&bt[0]}Or==="application/xhtml+xml"&&lr===xe&&(y=''+y+"");const et=v?v.createHTML(y):y;if(lr===xe)try{w=new u().parseFromString(et,Or)}catch{}if(!w||!w.documentElement){w=O.createDocument(lr,"template",null);try{w.documentElement.innerHTML=Fa?L: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},cl=function(y){return $.call(y.ownerDocument||y,y,c.SHOW_ELEMENT|c.SHOW_COMMENT|c.SHOW_TEXT|c.SHOW_PROCESSING_INSTRUCTION|c.SHOW_CDATA_SECTION,null)},hl=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")},ul=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)})},fl=function(y){let w=null;if(be("beforeSanitizeElements",y,null),hl(y))return se(y),!0;const P=mt(y.nodeName);if(be("uponSanitizeElement",y,{tagName:P,allowedTags:I}),y.hasChildNodes()&&!ul(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]&&pl(P)&&(V.tagNameCheck instanceof RegExp&&Ft(V.tagNameCheck,P)||V.tagNameCheck instanceof Function&&V.tagNameCheck(P)))return!1;if(Ea&&!or[P]){const et=b(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,x(y))}}}return se(y),!0}return y instanceof l&&!eg(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)},dl=function(y,w,P){if(Ko&&(w==="id"||w==="name")&&(P in r||P in Jp))return!1;if(!(me&&!ie[w]&&Ft(M,w))){if(!(ne&&Ft(A,w))){if(!Y[w]||ie[w]){if(!(pl(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(!Ma[w]){if(!Ft(H,Dr(P,F,""))){if(!((w==="src"||w==="xlink:href"||w==="href")&&y!=="script"&&_g(P,"data:")===0&&tl[y])){if(!(ae&&!Ft(T,Dr(P,F,"")))){if(P)return!1}}}}}}return!0},pl=function(y){return y!=="annotation-xml"&&_l(y,S)},gl=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,$r=mt(bt);let Mt=bt==="value"?oe:Cg(oe);if(P.attrName=$r,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],yl=>{Mt=Dr(Mt,yl," ")});const ml=mt(y.nodeName);if(dl(ml,$r,Mt)){if(Qo&&($r==="id"||$r==="name")&&(Gi(bt,y),Mt=Xp+Mt),v&&typeof p=="object"&&typeof p.getAttributeType=="function"&&!Rt)switch(p.getAttributeType(ml,$r)){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),hl(y)?se(y):bl(e.removed)}catch{}}}be("afterSanitizeAttributes",y,null)},rg=function z(y){let w=null;const P=cl(y);for(be("beforeSanitizeShadowDOM",y,null);w=P.nextNode();)be("uponSanitizeShadowNode",w,null),!fl(w)&&(w.content instanceof a&&z(w.content),gl(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(Fa=!z,Fa&&(z=""),typeof z!="string"&&!ul(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(Aa||$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=ll(""),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=ll(z),!w)return ar?null:ji?L:""}w&&Ba&&se(w.firstChild);const bt=cl(Fr?z:w);for(;et=bt.nextNode();)fl(et)||(et.content instanceof a&&rg(et.content),gl(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(rh,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),Aa=!0},e.clearConfig=function(){cr=null,Aa=!1},e.isValidAttribute=function(z,y,w){cr||$a({});const P=mt(z),et=mt(y);return dl(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 bl(R[z])},e.removeHooks=function(z){R[z]&&(R[z]=[])},e.removeAllHooks=function(){R={}},e}var yr=ih(),nh=Object.defineProperty,d=(t,e)=>nh(t,"name",{value:e,configurable:!0}),Rg=(t,e)=>{for(var r in e)nh(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")},Zs=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${cg().format("ss.SSS")} : ${t} : `,"format"),ah=/^-{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,Dg=/\s*%%.*\n/gm,vi,sh=(vi=class extends Error{constructor(e){super(e),this.name="UnknownDiagramError"}},d(vi,"UnknownDiagramError"),vi),xr={},Ks=d(function(t,e){t=t.replace(ah,"").replace(ei,"").replace(Dg,`
                                       `);for(const[r,{detector:i}]of Object.entries(xr))if(i(t,e))return r;throw new sh(`No diagram type detected matching given configuration for text: ${t}`)},"detectType"),oh=d((...t)=>{for(const{id:e,detector:r,loader:i}of t)lh(e,r,i)},"registerLazyLoadedDiagrams"),lh=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"),Pg=d(t=>xr[t].loader,"getDiagramLoader"),is=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=>is(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]=is(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=is,aa="#ffffff",sa="#f2f2f2",Ot=d((t,e)=>e?_(t,{s:-40,l:10}):_(t,{s:-40,l:-10}),"mkBorder"),ki,Ng=(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||_(this.primaryColor,{h:-120}),this.tertiaryColor=this.tertiaryColor||_(this.primaryColor,{h:180,l:5}),this.primaryBorderColor=this.primaryBorderColor||Ot(this.primaryColor,this.darkMode),this.secondaryBorderColor=this.secondaryBorderColor||Ot(this.secondaryColor,this.darkMode),this.tertiaryBorderColor=this.tertiaryBorderColor||Ot(this.tertiaryColor,this.darkMode),this.noteBorderColor=this.noteBorderColor||Ot(this.noteBkgColor,this.darkMode),this.noteBkgColor=this.noteBkgColor||"#fff5ad",this.noteTextColor=this.noteTextColor||"#333",this.secondaryTextColor=this.secondaryTextColor||B(this.secondaryColor),this.tertiaryTextColor=this.tertiaryTextColor||B(this.tertiaryColor),this.lineColor=this.lineColor||B(this.background),this.arrowheadColor=this.arrowheadColor||B(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||B(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||_(this.primaryColor,{h:30}),this.cScale4=this.cScale4||_(this.primaryColor,{h:60}),this.cScale5=this.cScale5||_(this.primaryColor,{h:90}),this.cScale6=this.cScale6||_(this.primaryColor,{h:120}),this.cScale7=this.cScale7||_(this.primaryColor,{h:150}),this.cScale8=this.cScale8||_(this.primaryColor,{h:210,l:150}),this.cScale9=this.cScale9||_(this.primaryColor,{h:270}),this.cScale10=this.cScale10||_(this.primaryColor,{h:300}),this.cScale11=this.cScale11||_(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),zg=d(t=>{const e=new Ng;return e.calculate(t),e},"getThemeVariables"),wi,qg=(wi=class{constructor(){this.background="#333",this.primaryColor="#1f2020",this.secondaryColor=q(this.primaryColor,16),this.tertiaryColor=_(this.primaryColor,{h:-160}),this.primaryBorderColor=B(this.background),this.secondaryBorderColor=Ot(this.secondaryColor,this.darkMode),this.tertiaryBorderColor=Ot(this.tertiaryColor,this.darkMode),this.primaryTextColor=B(this.primaryColor),this.secondaryTextColor=B(this.secondaryColor),this.tertiaryTextColor=B(this.tertiaryColor),this.lineColor=B(this.background),this.textColor=B(this.background),this.mainBkg="#1f2020",this.secondBkg="calculated",this.mainContrastColor="lightgrey",this.darkTextColor=q(B("#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.archEdgeColor="calculated",this.archEdgeArrowColor="calculated",this.archEdgeWidth="3",this.archGroupBorderColor=this.primaryBorderColor,this.archGroupBorderWidth="2px",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.archEdgeColor=this.lineColor,this.archEdgeArrowColor=this.lineColor,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=_(this.primaryColor,{h:64}),this.fillType3=_(this.secondaryColor,{h:64}),this.fillType4=_(this.primaryColor,{h:-64}),this.fillType5=_(this.secondaryColor,{h:-64}),this.fillType6=_(this.primaryColor,{h:128}),this.fillType7=_(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||_(this.primaryColor,{h:30}),this.cScale4=this.cScale4||_(this.primaryColor,{h:60}),this.cScale5=this.cScale5||_(this.primaryColor,{h:90}),this.cScale6=this.cScale6||_(this.primaryColor,{h:120}),this.cScale7=this.cScale7||_(this.primaryColor,{h:150}),this.cScale8=this.cScale8||_(this.primaryColor,{h:210}),this.cScale9=this.cScale9||_(this.primaryColor,{h:270}),this.cScale10=this.cScale10||_(this.primaryColor,{h:300}),this.cScale11=this.cScale11||_(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),Wg=d(t=>{const e=new qg;return e.calculate(t),e},"getThemeVariables"),Ti,Hg=(Ti=class{constructor(){this.background="#f4f4f4",this.primaryColor="#ECECFF",this.secondaryColor=_(this.primaryColor,{h:120}),this.secondaryColor="#ffffde",this.tertiaryColor=_(this.primaryColor,{h:-160}),this.primaryBorderColor=Ot(this.primaryColor,this.darkMode),this.secondaryBorderColor=Ot(this.secondaryColor,this.darkMode),this.tertiaryBorderColor=Ot(this.tertiaryColor,this.darkMode),this.primaryTextColor=B(this.primaryColor),this.secondaryTextColor=B(this.secondaryColor),this.tertiaryTextColor=B(this.tertiaryColor),this.lineColor=B(this.background),this.textColor=B(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.archEdgeColor="calculated",this.archEdgeArrowColor="calculated",this.archEdgeWidth="3",this.archGroupBorderColor=this.primaryBorderColor,this.archGroupBorderWidth="2px",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||_(this.primaryColor,{h:30}),this.cScale4=this.cScale4||_(this.primaryColor,{h:60}),this.cScale5=this.cScale5||_(this.primaryColor,{h:90}),this.cScale6=this.cScale6||_(this.primaryColor,{h:120}),this.cScale7=this.cScale7||_(this.primaryColor,{h:150}),this.cScale8=this.cScale8||_(this.primaryColor,{h:210}),this.cScale9=this.cScale9||_(this.primaryColor,{h:270}),this.cScale10=this.cScale10||_(this.primaryColor,{h:300}),this.cScale11=this.cScale11||_(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),jg=d(t=>{const e=new Hg;return e.calculate(t),e},"getThemeVariables"),Si,Ug=(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=Ot(this.primaryColor,this.darkMode),this.secondaryBorderColor=Ot(this.secondaryColor,this.darkMode),this.tertiaryBorderColor=Ot(this.tertiaryColor,this.darkMode),this.primaryTextColor=B(this.primaryColor),this.secondaryTextColor=B(this.secondaryColor),this.tertiaryTextColor=B(this.primaryColor),this.lineColor=B(this.background),this.textColor=B(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.archEdgeColor="calculated",this.archEdgeArrowColor="calculated",this.archEdgeWidth="3",this.archGroupBorderColor=this.primaryBorderColor,this.archGroupBorderWidth="2px",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||_(this.primaryColor,{h:30}),this.cScale4=this.cScale4||_(this.primaryColor,{h:60}),this.cScale5=this.cScale5||_(this.primaryColor,{h:90}),this.cScale6=this.cScale6||_(this.primaryColor,{h:120}),this.cScale7=this.cScale7||_(this.primaryColor,{h:150}),this.cScale8=this.cScale8||_(this.primaryColor,{h:210}),this.cScale9=this.cScale9||_(this.primaryColor,{h:270}),this.cScale10=this.cScale10||_(this.primaryColor,{h:300}),this.cScale11=this.cScale11||_(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),Yg=d(t=>{const e=new Ug;return e.calculate(t),e},"getThemeVariables"),Li,Gg=(Li=class{constructor(){this.primaryColor="#eee",this.contrast="#707070",this.secondaryColor=q(this.contrast,55),this.background="#ffffff",this.tertiaryColor=_(this.primaryColor,{h:-160}),this.primaryBorderColor=Ot(this.primaryColor,this.darkMode),this.secondaryBorderColor=Ot(this.secondaryColor,this.darkMode),this.tertiaryBorderColor=Ot(this.tertiaryColor,this.darkMode),this.primaryTextColor=B(this.primaryColor),this.secondaryTextColor=B(this.secondaryColor),this.tertiaryTextColor=B(this.tertiaryColor),this.lineColor=B(this.background),this.textColor=B(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.archEdgeColor="calculated",this.archEdgeArrowColor="calculated",this.archEdgeWidth="3",this.archGroupBorderColor=this.primaryBorderColor,this.archGroupBorderWidth="2px",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),Vg=d(t=>{const e=new Gg;return e.calculate(t),e},"getThemeVariables"),ke={base:{getThemeVariables:zg},dark:{getThemeVariables:Wg},default:{getThemeVariables:jg},forest:{getThemeVariables:Yg},neutral:{getThemeVariables:Vg}},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},architecture:{useMaxWidth:!0,padding:40,iconSize:80,fontSize:16},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},ch={...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}},hh=d((t,e="")=>Object.keys(t).reduce((r,i)=>Array.isArray(t[i])?r:typeof t[i]=="object"&&t[i]!==null?[...r,e+i,...hh(t[i],"")]:[...r,e+i],[]),"keyify"),Xg=new Set(hh(ch,"")),Zg=ch,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")||!Xg.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]=Kg(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"),Kg=d(t=>{let e=0,r=0;for(const i of t){if(e{let r=Ct({},t),i={};for(const n of e)ph(n),i=Ct(i,n);if(r=Ct(r,i),i.theme&&i.theme in ke){const n=Ct({},uh),a=Ct(n.themeVariables||{},i.themeVariables);r.theme&&r.theme in ke&&(r.themeVariables=ke[r.theme].getThemeVariables(a))}return ri=r,gh(ri),ri},"updateCurrentConfig"),Qg=d(t=>(Pt=Ct({},br),Pt=Ct(Pt,t),t.theme&&ke[t.theme]&&(Pt.themeVariables=ke[t.theme].getThemeVariables(t.themeVariables)),oa(Pt,_r),Pt),"setSiteConfig"),Jg=d(t=>{uh=Ct({},t)},"saveConfigFromInitialize"),tm=d(t=>(Pt=Ct(Pt,t),oa(Pt,_r),Pt),"updateSiteConfig"),fh=d(()=>Ct({},Pt),"getSiteConfig"),dh=d(t=>(gh(t),Ct(ri,t),Se()),"setConfig"),Se=d(()=>Ct({},ri),"getConfig"),ph=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"&&ph(t[e])}))},"sanitize"),em=d(t=>{var e;Cn(t),t.fontFamily&&!((e=t.themeVariables)!=null&&e.fontFamily)&&(t.themeVariables={...t.themeVariables,fontFamily:t.fontFamily}),_r.push(t),oa(Pt,_r)},"addDirective"),vn=d((t=Pt)=>{_r=[],oa(t,_r)},"reset"),rm={LAZY_LOAD_DEPRECATED:"The configuration options lazyLoadedDiagrams and loadExternalDiagramsAtStartup are deprecated. Please use registerExternalDiagrams instead."},Sl={},im=d(t=>{Sl[t]||(k.warn(rm[t]),Sl[t]=!0)},"issueWarning"),gh=d(t=>{t&&(t.lazyLoadedDiagrams||t.loadExternalDiagramsAtStartup)&&im("LAZY_LOAD_DEPRECATED")},"checkConfig"),Fi=//gi,nm=d(t=>t?xh(t).replace(/\\n/g,"#br#").split("#br#"):[""],"getRows"),am=(()=>{let t=!1;return()=>{t||(mh(),t=!0)}})();function mh(){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(mh,"setupDompurifyHooks");var yh=d(t=>(am(),yr.sanitize(t)),"removeScript"),Ll=d((t,e)=>{var r;if(((r=e.flowchart)==null?void 0:r.htmlLabels)!==!1){const i=e.securityLevel;i==="antiscript"||i==="strict"?t=yh(t):i!=="loose"&&(t=xh(t),t=t.replace(//g,">"),t=t.replace(/=/g,"="),t=cm(t))}return t},"sanitizeMore"),Cr=d((t,e)=>t&&(e.dompurifyConfig?t=yr.sanitize(Ll(t,e),e.dompurifyConfig).toString():t=yr.sanitize(Ll(t,e),{FORBID_TAGS:["style"]}).toString(),t),"sanitizeText"),sm=d((t,e)=>typeof t=="string"?Cr(t,e):t.flat().map(r=>Cr(r,e)),"sanitizeTextOrArray"),om=d(t=>Fi.test(t),"hasBreaks"),lm=d(t=>t.split(Fi),"splitBreaks"),cm=d(t=>t.replace(/#br#/g,"
                                      "),"placeholderToBreak"),xh=d(t=>t.replace(Fi,"#br#"),"breakToPlaceholder"),hm=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"),um=d(function(...t){const e=t.filter(r=>!isNaN(r));return Math.max(...e)},"getMax"),fm=d(function(...t){const e=t.filter(r=>!isNaN(r));return Math.min(...e)},"getMin"),sL=d(function(t){const e=t.split(/(,)/),r=[];for(let i=0;i0&&i+1Math.max(0,t.split(e).length-1),"countOccurrence"),dm=d((t,e)=>{const r=ns(t,"~"),i=ns(e,"~");return r===1&&i===1},"shouldCombineSets"),pm=d(t=>{const e=ns(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"),Al=d(()=>window.MathMLElement!==void 0,"isMathMLSupported"),as=/\$\$(.*)\$\$/g,si=d(t=>{var e;return(((e=t.match(as))==null?void 0:e.length)??0)>0},"hasKatex"),oL=d(async(t,e)=>{t=await Qs(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"),Qs=d(async(t,e)=>{if(!si(t))return t;if(!(Al()||e.legacyMathML||e.forceLegacyMathML))return t.replace(as,"MathML is unsupported in this environment.");const{default:r}=await it(()=>import("./katex-rPiVaalG.js"),__vite__mapDeps([])),i=e.forceLegacyMathML||!Al()&&e.legacyMathML?"htmlAndMathml":"mathml";return t.split(Fi).map(n=>si(n)?`
                                      ${n}
                                      `:`
                                      ${n}
                                      `).join("").replace(as,(n,a)=>r.renderToString(a,{throwOnError:!0,displayMode:!0,output:i}).replace(/\n/g," ").replace(//g,""))},"renderKatex"),Ar={getRows:nm,sanitizeText:Cr,sanitizeTextOrArray:sm,hasBreaks:om,splitBreaks:lm,lineBreakRegex:Fi,removeScript:yh,getUrl:hm,evaluate:ee,getMax:um,getMin:fm},gm=d(function(t,e){for(let r of e)t.attr(r[0],r[1])},"d3Attrs"),mm=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"),bh=d(function(t,e,r,i){const n=mm(e,r,i);gm(t,n)},"configureSvgSize"),ym=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}`),bh(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={},xm=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"),Rk=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"),Dk=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=Rk(0,0,c,o,l),x=p.path(m,g);f=n.insert(()=>x,":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"),Pk=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"),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=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=Pk(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"),zk=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"),qk=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=zk(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"),Wk=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=Wk(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"),jk=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"),Uk=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=jk(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"),Yk=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"),$c={state:mk,stateStart:bk,stateEnd:_k,fork:Oc,join:Oc,choice:Ck,note:vk,roundedRect:yk,rectWithTitle:wk,squareRect:xk,stadium:kk,subroutine:Tk,cylinder:Bk,circle:Ek,doublecircle:Mk,odd:Ok,diamond:Ik,hexagon:Dk,lean_right:Nk,lean_left:qk,trapezoid:Hk,inv_trapezoid:Uk,labelRect:Yk},mr=new Map,Gk=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 $c[e.shape](i,e,r)}else n=await $c[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"),SL=d((t,e)=>{mr.set(e.id,t)},"setNodeElem"),LL=d(()=>{mr.clear()},"clear"),AL=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"),Vk={common:Ar,getConfig:Se,insertCluster:Uv,insertEdge:Jv,insertEdgeLabel:Vv,insertMarkers:uk,insertNode:Gk,interpolateToCurve:Co,labelHelper:At,log:k,positionEdgeLabel:Xv},gi={},vf=d(t=>{for(const e of t)gi[e.name]=e},"registerLayoutLoaders"),Xk=d(()=>{vf([{name:"dagre",loader:d(async()=>await it(()=>import("./dagre-P3YPLUS5-fdtXHwJa.js"),__vite__mapDeps([0,1,2,3,4,5,6,7])),"loader")}])},"registerDefaultLayoutLoaders");Xk();var BL=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,Vk,{algorithm:r.algorithm})},"render"),EL=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"),Ic="11.2.1",Zk=d(t=>{var n;const{securityLevel:e}=K();let r=at("body");if(e==="sandbox"){const s=((n=at(`#i${t}`).node())==null?void 0:n.contentDocument)??document;r=at(s.body)}return r.select(`#${t}`)},"selectSvgElement"),kf="comm",wf="rule",Tf="decl",Kk="@import",Qk="@keyframes",Jk="@layer",Sf=Math.abs,zo=String.fromCharCode;function Lf(t){return t.trim()}function mn(t,e,r){return t.replace(e,r)}function tw(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 ew(t){return t.length}function on(t,e){return e.push(t),t}var ka=1,wr=1,Af=0,Zt=0,ft=0,Mr="";function qo(t,e,r,i,n,a,s,o){return{value:t,root:e,parent:r,type:i,props:n,children:a,line:ka,column:wr,length:s,return:"",siblings:o}}function rw(){return ft}function iw(){return ft=Zt>0?mi(Mr,--Zt):0,wr--,ft===10&&(wr=1,ka--),ft}function Jt(){return ft=Zt2||Ss(ft)>3?"":" "}function ow(t,e){for(;--e&&Jt()&&!(ft<48||ft>102||ft>57&&ft<65||ft>70&&ft<97););return wa(t,yn()+(e<6&&Xe()==32&&Jt()==32))}function Ls(t){for(;Jt();)switch(ft){case t:return Zt;case 34:case 39:t!==34&&t!==39&&Ls(ft);break;case 40:t===41&&Ls(t);break;case 92:Jt();break}return Zt}function lw(t,e){for(;Jt()&&t+ft!==57;)if(t+ft===84&&Xe()===47)break;return"/*"+wa(e,Zt-1)+"*"+zo(t===47?t:Jt())}function cw(t){for(;!Ss(Xe());)Jt();return wa(t,Zt)}function hw(t){return aw(xn("",null,null,null,[""],t=nw(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,x=1,C=1,b=0,v="",L=n,O=a,$=i,E=v;x;)switch(g=b,b=Jt()){case 40:if(g!=108&&mi(E,f-1)==58){tw(E+=mn(Qa(b),"&","&\f"),"&\f",Sf(c?o[c-1]:0))!=-1&&(C=-1);break}case 34:case 39:case 91:E+=Qa(b);break;case 9:case 10:case 13:case 32:E+=sw(g);break;case 92:E+=ow(yn()-1,7);continue;case 47:switch(Xe()){case 42:case 47:on(uw(lw(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(b){case 0:case 125:x=0;case 59+h:C==-1&&(E=mn(E,/\f/g,"")),p>0&&ve(E)-f&&on(p>32?Dc(E+";",i,r,f-1,l):Dc(mn(E," ","")+";",i,r,f-2,l),l);break;case 59:E+=";";default:if(on($=Rc(E,e,r,c,h,n,o,v,L=[],O=[],f,a),a),b===123)if(h===0)xn(E,e,$,$,L,a,f,o,O);else switch(u===99&&mi(E,3)===110?100:u){case 100:case 108:case 109:case 115:xn(t,$,$,i&&on(Rc(t,$,$,0,0,n,o,v,n,L=[],f,O),O),n,O,f,o,i?L:O);break;default:xn(E,$,$,$,[""],O,0,o,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(b==123)--m;else if(b==125&&m++==0&&iw()==125)continue}switch(E+=zo(b),b*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+=Qa(Jt())),u=Xe(),h=f=ve(v=E+=cw(yn())),b++;break;case 45:g===45&&ve(E)==2&&(m=0)}}return a}function Rc(t,e,r,i,n,a,s,o,l,c,h,f){for(var u=n-1,p=n===0?a:[""],g=ew(p),m=0,x=0,C=0;m0?p[b]+" "+v:mn(v,/&\f/g,p[b])))&&(l[C++]=L);return qo(t,e,r,n===0?wf:o,l,c,h,f)}function uw(t,e,r,i){return qo(t,e,r,kf,zo(rw()),yi(t,2,-2),0,i)}function Dc(t,e,r,i,n){return qo(t,e,r,Tf,yi(t,0,i),yi(t,i+1,-1),i,n)}function As(t,e){for(var r="",i=0;i/^\s*C4Context|C4Container|C4Component|C4Dynamic|C4Deployment/.test(t),"detector"),Aw=d(async()=>{const{diagram:t}=await it(()=>import("./c4Diagram-THADGKDP-BrQI6Wg6.js"),__vite__mapDeps([8,9,7]));return{id:Bf,diagram:t}},"loader"),Bw={id:Bf,detector:Lw,loader:Aw},Ew=Bw,Ef="flowchart",Mw=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"),Fw=d(async()=>{const{diagram:t}=await it(()=>import("./flowDiagram-JSIZSE4D-CkrFR_87.js"),__vite__mapDeps([10,11,12,13,7]));return{id:Ef,diagram:t}},"loader"),Ow={id:Ef,detector:Mw,loader:Fw},$w=Ow,Mf="flowchart-v2",Iw=d((t,e)=>{var r,i,n;return((r=e==null?void 0:e.flowchart)==null?void 0:r.defaultRenderer)==="dagre-d3"?!1:(((i=e==null?void 0:e.flowchart)==null?void 0:i.defaultRenderer)==="elk"&&(e.layout="elk"),/^\s*graph/.test(t)&&((n=e==null?void 0:e.flowchart)==null?void 0:n.defaultRenderer)==="dagre-wrapper"?!0:/^\s*flowchart/.test(t))},"detector"),Rw=d(async()=>{const{diagram:t}=await it(()=>import("./flowDiagram-JSIZSE4D-CkrFR_87.js"),__vite__mapDeps([10,11,12,13,7]));return{id:Mf,diagram:t}},"loader"),Dw={id:Mf,detector:Iw,loader:Rw},Pw=Dw,Ff="er",Nw=d(t=>/^\s*erDiagram/.test(t),"detector"),zw=d(async()=>{const{diagram:t}=await it(()=>import("./erDiagram-62CBQV5Y-kGzN7AR2.js"),__vite__mapDeps([14,1,2,3,4,7]));return{id:Ff,diagram:t}},"loader"),qw={id:Ff,detector:Nw,loader:zw},Ww=qw,Of="gitGraph",Hw=d(t=>/^\s*gitGraph/.test(t),"detector"),jw=d(async()=>{const{diagram:t}=await it(()=>import("./gitGraphDiagram-UL5UFKDR-N-DngFFf.js"),__vite__mapDeps([15,16,17,18,7,2,4,6]));return{id:Of,diagram:t}},"loader"),Uw={id:Of,detector:Hw,loader:jw},Yw=Uw,$f="gantt",Gw=d(t=>/^\s*gantt/.test(t),"detector"),Vw=d(async()=>{const{diagram:t}=await it(()=>import("./ganttDiagram-ASEIQ4P5-CoW2hfbL.js"),__vite__mapDeps([19,20,21,7]));return{id:$f,diagram:t}},"loader"),Xw={id:$f,detector:Gw,loader:Vw},Zw=Xw,If="info",Kw=d(t=>/^\s*info/.test(t),"detector"),Qw=d(async()=>{const{diagram:t}=await it(()=>import("./infoDiagram-7APDZ6AT-CjHjl5ga.js"),__vite__mapDeps([22,18,7,2,4,6]));return{id:If,diagram:t}},"loader"),Jw={id:If,detector:Kw,loader:Qw},Rf="pie",tT=d(t=>/^\s*pie/.test(t),"detector"),eT=d(async()=>{const{diagram:t}=await it(()=>import("./pieDiagram-OZX6XH5M-BajVz6ZT.js"),__vite__mapDeps([23,16,18,7,2,4,6,24,25,21]));return{id:Rf,diagram:t}},"loader"),rT={id:Rf,detector:tT,loader:eT},Df="quadrantChart",iT=d(t=>/^\s*quadrantChart/.test(t),"detector"),nT=d(async()=>{const{diagram:t}=await it(()=>import("./quadrantDiagram-VG34DGKC-CqrCarqp.js"),__vite__mapDeps([26,20,21,7]));return{id:Df,diagram:t}},"loader"),aT={id:Df,detector:iT,loader:nT},sT=aT,Pf="xychart",oT=d(t=>/^\s*xychart-beta/.test(t),"detector"),lT=d(async()=>{const{diagram:t}=await it(()=>import("./xychartDiagram-LESROZAQ-BnJ8kkeI.js"),__vite__mapDeps([27,21,25,20,7]));return{id:Pf,diagram:t}},"loader"),cT={id:Pf,detector:oT,loader:lT},hT=cT,Nf="requirement",uT=d(t=>/^\s*requirement(Diagram)?/.test(t),"detector"),fT=d(async()=>{const{diagram:t}=await it(()=>import("./requirementDiagram-FPZB6IJI-CtznTREQ.js"),__vite__mapDeps([28,1,2,3,4,7]));return{id:Nf,diagram:t}},"loader"),dT={id:Nf,detector:uT,loader:fT},pT=dT,zf="sequence",gT=d(t=>/^\s*sequenceDiagram/.test(t),"detector"),mT=d(async()=>{const{diagram:t}=await it(()=>import("./sequenceDiagram-PQT5PN7B-DljhtIMV.js"),__vite__mapDeps([29,9,17,7]));return{id:zf,diagram:t}},"loader"),yT={id:zf,detector:gT,loader:mT},xT=yT,qf="class",bT=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"),_T=d(async()=>{const{diagram:t}=await it(()=>import("./classDiagram-4BHYIK4I-a2lMBkUS.js"),__vite__mapDeps([30,31,1,2,3,4,7]));return{id:qf,diagram:t}},"loader"),CT={id:qf,detector:bT,loader:_T},vT=CT,Wf="classDiagram",kT=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"),wT=d(async()=>{const{diagram:t}=await it(()=>import("./classDiagram-v2-FI7KE7WJ-Cv9pEPw6.js"),__vite__mapDeps([32,33,12,31,1,2,3,4,5,6,7]));return{id:Wf,diagram:t}},"loader"),TT={id:Wf,detector:kT,loader:wT},ST=TT,Hf="state",LT=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"),AT=d(async()=>{const{diagram:t}=await it(()=>import("./stateDiagram-TQSDS2D4-CKjMI_Q3.js"),__vite__mapDeps([34,35,11,12,1,2,3,4,7]));return{id:Hf,diagram:t}},"loader"),BT={id:Hf,detector:LT,loader:AT},ET=BT,jf="stateDiagram",MT=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"),FT=d(async()=>{const{diagram:t}=await it(()=>import("./stateDiagram-v2-J5TZWJW5-BzVT64Mf.js"),__vite__mapDeps([36,35,11,12,7]));return{id:jf,diagram:t}},"loader"),OT={id:jf,detector:MT,loader:FT},$T=OT,Uf="journey",IT=d(t=>/^\s*journey/.test(t),"detector"),RT=d(async()=>{const{diagram:t}=await it(()=>import("./journeyDiagram-G5LC7W2K-nbd-YhOX.js"),__vite__mapDeps([37,9,24,7]));return{id:Uf,diagram:t}},"loader"),DT={id:Uf,detector:IT,loader:RT},PT=DT,NT=d((t,e,r)=>{k.debug(`rendering svg for syntax error -`);const i=Zk(e),n=i.append("g");i.attr("viewBox","0 0 2412 512"),bh(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"),Yf={draw:NT},zT=Yf,qT={db:{},renderer:Yf,parser:{parse:d(()=>{},"parse")}},WT=qT,Gf="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"),jT=d(async()=>{const{diagram:t}=await it(()=>import("./flowDiagram-JSIZSE4D-CkrFR_87.js"),__vite__mapDeps([10,11,12,13,7]));return{id:Gf,diagram:t}},"loader"),UT={id:Gf,detector:HT,loader:jT},YT=UT,Vf="timeline",GT=d(t=>/^\s*timeline/.test(t),"detector"),VT=d(async()=>{const{diagram:t}=await it(()=>import("./timeline-definition-KYQAIZUX-CfFf7B0p.js"),__vite__mapDeps([38,24,7]));return{id:Vf,diagram:t}},"loader"),XT={id:Vf,detector:GT,loader:VT},ZT=XT,Xf="mindmap",KT=d(t=>/^\s*mindmap/.test(t),"detector"),QT=d(async()=>{const{diagram:t}=await it(()=>import("./mindmap-definition-FCEC46F3-DXSM7Uv5.js"),__vite__mapDeps([39,40,7]));return{id:Xf,diagram:t}},"loader"),JT={id:Xf,detector:KT,loader:QT},t2=JT,Zf="sankey",e2=d(t=>/^\s*sankey-beta/.test(t),"detector"),r2=d(async()=>{const{diagram:t}=await it(()=>import("./sankeyDiagram-KMMQDL5K-i3x2cUcG.js"),__vite__mapDeps([41,25,21,7]));return{id:Zf,diagram:t}},"loader"),i2={id:Zf,detector:e2,loader:r2},n2=i2,Kf="packet",a2=d(t=>/^\s*packet-beta/.test(t),"detector"),s2=d(async()=>{const{diagram:t}=await it(()=>import("./diagram-QS5GVLUX-Cm0gimUA.js"),__vite__mapDeps([42,16,18,7,2,4,6]));return{id:Kf,diagram:t}},"loader"),o2={id:Kf,detector:a2,loader:s2},Qf="block",l2=d(t=>/^\s*block-beta/.test(t),"detector"),c2=d(async()=>{const{diagram:t}=await it(()=>import("./blockDiagram-EN3ZKWFM-aV_THrNU.js"),__vite__mapDeps([43,33,12,6,2,1,13,7]));return{id:Qf,diagram:t}},"loader"),h2={id:Qf,detector:l2,loader:c2},u2=h2,Jf="architecture",f2=d(t=>/^\s*architecture/.test(t),"detector"),d2=d(async()=>{const{diagram:t}=await it(()=>import("./architectureDiagram-V6B76FHG-DgmvuR6V.js"),__vite__mapDeps([44,16,17,18,7,2,4,6,40]));return{id:Jf,diagram:t}},"loader"),p2={id:Jf,detector:f2,loader:d2},g2=p2,jc=!1,Ta=d(()=>{jc||(jc=!0,wn("error",WT,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("---")),oh(Ew,ST,vT,Ww,Zw,Jw,rT,pT,xT,YT,Pw,$w,t2,ZT,Yw,$T,ET,PT,sT,n2,o2,hT,u2,g2))},"addDiagrams"),m2=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{ss(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"),y2="graphics-document document";function td(t,e){t.attr("role",y2),e!==""&&t.attr("aria-roledescription",e)}d(td,"setA11yDiagramInfo");function ed(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(ed,"addSVGa11yTitleDescription");var Lr,Os=(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=Ks(e,i);e=PC(e)+` +res:`,ut.polygon(e,c,u)),ut.polygon(e,c,u)},n},"question"),Rk=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"),Dk=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=Rk(0,0,c,o,l),x=p.path(m,g);f=n.insert(()=>x,":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"),Pk=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"),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=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=Pk(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"),zk=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"),qk=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=zk(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"),Wk=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=Wk(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"),jk=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"),Uk=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=jk(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"),Yk=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"),$c={state:mk,stateStart:bk,stateEnd:_k,fork:Oc,join:Oc,choice:Ck,note:vk,roundedRect:yk,rectWithTitle:wk,squareRect:xk,stadium:kk,subroutine:Tk,cylinder:Bk,circle:Ek,doublecircle:Mk,odd:Ok,diamond:Ik,hexagon:Dk,lean_right:Nk,lean_left:qk,trapezoid:Hk,inv_trapezoid:Uk,labelRect:Yk},mr=new Map,Gk=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 $c[e.shape](i,e,r)}else n=await $c[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"),SL=d((t,e)=>{mr.set(e.id,t)},"setNodeElem"),LL=d(()=>{mr.clear()},"clear"),AL=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"),Vk={common:Ar,getConfig:Se,insertCluster:Uv,insertEdge:Jv,insertEdgeLabel:Vv,insertMarkers:uk,insertNode:Gk,interpolateToCurve:Co,labelHelper:At,log:k,positionEdgeLabel:Xv},gi={},vf=d(t=>{for(const e of t)gi[e.name]=e},"registerLayoutLoaders"),Xk=d(()=>{vf([{name:"dagre",loader:d(async()=>await it(()=>import("./dagre-P3YPLUS5-D2h4pGrn.js"),__vite__mapDeps([0,1,2,3,4,5,6,7])),"loader")}])},"registerDefaultLayoutLoaders");Xk();var BL=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,Vk,{algorithm:r.algorithm})},"render"),EL=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"),Ic="11.2.1",Zk=d(t=>{var n;const{securityLevel:e}=K();let r=at("body");if(e==="sandbox"){const s=((n=at(`#i${t}`).node())==null?void 0:n.contentDocument)??document;r=at(s.body)}return r.select(`#${t}`)},"selectSvgElement"),kf="comm",wf="rule",Tf="decl",Kk="@import",Qk="@keyframes",Jk="@layer",Sf=Math.abs,zo=String.fromCharCode;function Lf(t){return t.trim()}function mn(t,e,r){return t.replace(e,r)}function tw(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 ew(t){return t.length}function on(t,e){return e.push(t),t}var ka=1,wr=1,Af=0,Zt=0,ft=0,Mr="";function qo(t,e,r,i,n,a,s,o){return{value:t,root:e,parent:r,type:i,props:n,children:a,line:ka,column:wr,length:s,return:"",siblings:o}}function rw(){return ft}function iw(){return ft=Zt>0?mi(Mr,--Zt):0,wr--,ft===10&&(wr=1,ka--),ft}function Jt(){return ft=Zt2||Ss(ft)>3?"":" "}function ow(t,e){for(;--e&&Jt()&&!(ft<48||ft>102||ft>57&&ft<65||ft>70&&ft<97););return wa(t,yn()+(e<6&&Xe()==32&&Jt()==32))}function Ls(t){for(;Jt();)switch(ft){case t:return Zt;case 34:case 39:t!==34&&t!==39&&Ls(ft);break;case 40:t===41&&Ls(t);break;case 92:Jt();break}return Zt}function lw(t,e){for(;Jt()&&t+ft!==57;)if(t+ft===84&&Xe()===47)break;return"/*"+wa(e,Zt-1)+"*"+zo(t===47?t:Jt())}function cw(t){for(;!Ss(Xe());)Jt();return wa(t,Zt)}function hw(t){return aw(xn("",null,null,null,[""],t=nw(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,x=1,C=1,b=0,v="",L=n,O=a,$=i,E=v;x;)switch(g=b,b=Jt()){case 40:if(g!=108&&mi(E,f-1)==58){tw(E+=mn(Qa(b),"&","&\f"),"&\f",Sf(c?o[c-1]:0))!=-1&&(C=-1);break}case 34:case 39:case 91:E+=Qa(b);break;case 9:case 10:case 13:case 32:E+=sw(g);break;case 92:E+=ow(yn()-1,7);continue;case 47:switch(Xe()){case 42:case 47:on(uw(lw(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(b){case 0:case 125:x=0;case 59+h:C==-1&&(E=mn(E,/\f/g,"")),p>0&&ve(E)-f&&on(p>32?Dc(E+";",i,r,f-1,l):Dc(mn(E," ","")+";",i,r,f-2,l),l);break;case 59:E+=";";default:if(on($=Rc(E,e,r,c,h,n,o,v,L=[],O=[],f,a),a),b===123)if(h===0)xn(E,e,$,$,L,a,f,o,O);else switch(u===99&&mi(E,3)===110?100:u){case 100:case 108:case 109:case 115:xn(t,$,$,i&&on(Rc(t,$,$,0,0,n,o,v,n,L=[],f,O),O),n,O,f,o,i?L:O);break;default:xn(E,$,$,$,[""],O,0,o,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(b==123)--m;else if(b==125&&m++==0&&iw()==125)continue}switch(E+=zo(b),b*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+=Qa(Jt())),u=Xe(),h=f=ve(v=E+=cw(yn())),b++;break;case 45:g===45&&ve(E)==2&&(m=0)}}return a}function Rc(t,e,r,i,n,a,s,o,l,c,h,f){for(var u=n-1,p=n===0?a:[""],g=ew(p),m=0,x=0,C=0;m0?p[b]+" "+v:mn(v,/&\f/g,p[b])))&&(l[C++]=L);return qo(t,e,r,n===0?wf:o,l,c,h,f)}function uw(t,e,r,i){return qo(t,e,r,kf,zo(rw()),yi(t,2,-2),0,i)}function Dc(t,e,r,i,n){return qo(t,e,r,Tf,yi(t,0,i),yi(t,i+1,-1),i,n)}function As(t,e){for(var r="",i=0;i/^\s*C4Context|C4Container|C4Component|C4Dynamic|C4Deployment/.test(t),"detector"),Aw=d(async()=>{const{diagram:t}=await it(()=>import("./c4Diagram-THADGKDP-BV0ojTgT.js"),__vite__mapDeps([8,9,7]));return{id:Bf,diagram:t}},"loader"),Bw={id:Bf,detector:Lw,loader:Aw},Ew=Bw,Ef="flowchart",Mw=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"),Fw=d(async()=>{const{diagram:t}=await it(()=>import("./flowDiagram-JSIZSE4D-CWnhT7dd.js"),__vite__mapDeps([10,11,12,13,7]));return{id:Ef,diagram:t}},"loader"),Ow={id:Ef,detector:Mw,loader:Fw},$w=Ow,Mf="flowchart-v2",Iw=d((t,e)=>{var r,i,n;return((r=e==null?void 0:e.flowchart)==null?void 0:r.defaultRenderer)==="dagre-d3"?!1:(((i=e==null?void 0:e.flowchart)==null?void 0:i.defaultRenderer)==="elk"&&(e.layout="elk"),/^\s*graph/.test(t)&&((n=e==null?void 0:e.flowchart)==null?void 0:n.defaultRenderer)==="dagre-wrapper"?!0:/^\s*flowchart/.test(t))},"detector"),Rw=d(async()=>{const{diagram:t}=await it(()=>import("./flowDiagram-JSIZSE4D-CWnhT7dd.js"),__vite__mapDeps([10,11,12,13,7]));return{id:Mf,diagram:t}},"loader"),Dw={id:Mf,detector:Iw,loader:Rw},Pw=Dw,Ff="er",Nw=d(t=>/^\s*erDiagram/.test(t),"detector"),zw=d(async()=>{const{diagram:t}=await it(()=>import("./erDiagram-62CBQV5Y-eD5vQ31J.js"),__vite__mapDeps([14,1,2,3,4,7]));return{id:Ff,diagram:t}},"loader"),qw={id:Ff,detector:Nw,loader:zw},Ww=qw,Of="gitGraph",Hw=d(t=>/^\s*gitGraph/.test(t),"detector"),jw=d(async()=>{const{diagram:t}=await it(()=>import("./gitGraphDiagram-UL5UFKDR-yPILUU1f.js"),__vite__mapDeps([15,16,17,18,7,2,4,6]));return{id:Of,diagram:t}},"loader"),Uw={id:Of,detector:Hw,loader:jw},Yw=Uw,$f="gantt",Gw=d(t=>/^\s*gantt/.test(t),"detector"),Vw=d(async()=>{const{diagram:t}=await it(()=>import("./ganttDiagram-ASEIQ4P5-DxQ9ChJm.js"),__vite__mapDeps([19,20,21,7]));return{id:$f,diagram:t}},"loader"),Xw={id:$f,detector:Gw,loader:Vw},Zw=Xw,If="info",Kw=d(t=>/^\s*info/.test(t),"detector"),Qw=d(async()=>{const{diagram:t}=await it(()=>import("./infoDiagram-7APDZ6AT-Cw5OHrUt.js"),__vite__mapDeps([22,18,7,2,4,6]));return{id:If,diagram:t}},"loader"),Jw={id:If,detector:Kw,loader:Qw},Rf="pie",tT=d(t=>/^\s*pie/.test(t),"detector"),eT=d(async()=>{const{diagram:t}=await it(()=>import("./pieDiagram-OZX6XH5M-BSVm6OG3.js"),__vite__mapDeps([23,16,18,7,2,4,6,24,25,21]));return{id:Rf,diagram:t}},"loader"),rT={id:Rf,detector:tT,loader:eT},Df="quadrantChart",iT=d(t=>/^\s*quadrantChart/.test(t),"detector"),nT=d(async()=>{const{diagram:t}=await it(()=>import("./quadrantDiagram-VG34DGKC-GWgA8Rrq.js"),__vite__mapDeps([26,20,21,7]));return{id:Df,diagram:t}},"loader"),aT={id:Df,detector:iT,loader:nT},sT=aT,Pf="xychart",oT=d(t=>/^\s*xychart-beta/.test(t),"detector"),lT=d(async()=>{const{diagram:t}=await it(()=>import("./xychartDiagram-LESROZAQ-CAWMdezr.js"),__vite__mapDeps([27,21,25,20,7]));return{id:Pf,diagram:t}},"loader"),cT={id:Pf,detector:oT,loader:lT},hT=cT,Nf="requirement",uT=d(t=>/^\s*requirement(Diagram)?/.test(t),"detector"),fT=d(async()=>{const{diagram:t}=await it(()=>import("./requirementDiagram-FPZB6IJI-74hMwT5u.js"),__vite__mapDeps([28,1,2,3,4,7]));return{id:Nf,diagram:t}},"loader"),dT={id:Nf,detector:uT,loader:fT},pT=dT,zf="sequence",gT=d(t=>/^\s*sequenceDiagram/.test(t),"detector"),mT=d(async()=>{const{diagram:t}=await it(()=>import("./sequenceDiagram-PQT5PN7B-OiVI6n8n.js"),__vite__mapDeps([29,9,17,7]));return{id:zf,diagram:t}},"loader"),yT={id:zf,detector:gT,loader:mT},xT=yT,qf="class",bT=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"),_T=d(async()=>{const{diagram:t}=await it(()=>import("./classDiagram-4BHYIK4I-DaH_u7n6.js"),__vite__mapDeps([30,31,1,2,3,4,7]));return{id:qf,diagram:t}},"loader"),CT={id:qf,detector:bT,loader:_T},vT=CT,Wf="classDiagram",kT=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"),wT=d(async()=>{const{diagram:t}=await it(()=>import("./classDiagram-v2-FI7KE7WJ-CbLiwjWK.js"),__vite__mapDeps([32,33,12,31,1,2,3,4,5,6,7]));return{id:Wf,diagram:t}},"loader"),TT={id:Wf,detector:kT,loader:wT},ST=TT,Hf="state",LT=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"),AT=d(async()=>{const{diagram:t}=await it(()=>import("./stateDiagram-TQSDS2D4-CEpT6xhM.js"),__vite__mapDeps([34,35,11,12,1,2,3,4,7]));return{id:Hf,diagram:t}},"loader"),BT={id:Hf,detector:LT,loader:AT},ET=BT,jf="stateDiagram",MT=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"),FT=d(async()=>{const{diagram:t}=await it(()=>import("./stateDiagram-v2-J5TZWJW5-CIAps9nC.js"),__vite__mapDeps([36,35,11,12,7]));return{id:jf,diagram:t}},"loader"),OT={id:jf,detector:MT,loader:FT},$T=OT,Uf="journey",IT=d(t=>/^\s*journey/.test(t),"detector"),RT=d(async()=>{const{diagram:t}=await it(()=>import("./journeyDiagram-G5LC7W2K-D5obEO4H.js"),__vite__mapDeps([37,9,24,7]));return{id:Uf,diagram:t}},"loader"),DT={id:Uf,detector:IT,loader:RT},PT=DT,NT=d((t,e,r)=>{k.debug(`rendering svg for syntax error +`);const i=Zk(e),n=i.append("g");i.attr("viewBox","0 0 2412 512"),bh(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"),Yf={draw:NT},zT=Yf,qT={db:{},renderer:Yf,parser:{parse:d(()=>{},"parse")}},WT=qT,Gf="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"),jT=d(async()=>{const{diagram:t}=await it(()=>import("./flowDiagram-JSIZSE4D-CWnhT7dd.js"),__vite__mapDeps([10,11,12,13,7]));return{id:Gf,diagram:t}},"loader"),UT={id:Gf,detector:HT,loader:jT},YT=UT,Vf="timeline",GT=d(t=>/^\s*timeline/.test(t),"detector"),VT=d(async()=>{const{diagram:t}=await it(()=>import("./timeline-definition-KYQAIZUX-bG0Ln98x.js"),__vite__mapDeps([38,24,7]));return{id:Vf,diagram:t}},"loader"),XT={id:Vf,detector:GT,loader:VT},ZT=XT,Xf="mindmap",KT=d(t=>/^\s*mindmap/.test(t),"detector"),QT=d(async()=>{const{diagram:t}=await it(()=>import("./mindmap-definition-FCEC46F3-D7JZQwFv.js"),__vite__mapDeps([39,40,7]));return{id:Xf,diagram:t}},"loader"),JT={id:Xf,detector:KT,loader:QT},t2=JT,Zf="sankey",e2=d(t=>/^\s*sankey-beta/.test(t),"detector"),r2=d(async()=>{const{diagram:t}=await it(()=>import("./sankeyDiagram-KMMQDL5K-D2j-_3G0.js"),__vite__mapDeps([41,25,21,7]));return{id:Zf,diagram:t}},"loader"),i2={id:Zf,detector:e2,loader:r2},n2=i2,Kf="packet",a2=d(t=>/^\s*packet-beta/.test(t),"detector"),s2=d(async()=>{const{diagram:t}=await it(()=>import("./diagram-QS5GVLUX-xW2B2nxk.js"),__vite__mapDeps([42,16,18,7,2,4,6]));return{id:Kf,diagram:t}},"loader"),o2={id:Kf,detector:a2,loader:s2},Qf="block",l2=d(t=>/^\s*block-beta/.test(t),"detector"),c2=d(async()=>{const{diagram:t}=await it(()=>import("./blockDiagram-EN3ZKWFM-ypLrqQ_-.js"),__vite__mapDeps([43,33,12,6,2,1,13,7]));return{id:Qf,diagram:t}},"loader"),h2={id:Qf,detector:l2,loader:c2},u2=h2,Jf="architecture",f2=d(t=>/^\s*architecture/.test(t),"detector"),d2=d(async()=>{const{diagram:t}=await it(()=>import("./architectureDiagram-V6B76FHG-BixTwIPG.js"),__vite__mapDeps([44,16,17,18,7,2,4,6,40]));return{id:Jf,diagram:t}},"loader"),p2={id:Jf,detector:f2,loader:d2},g2=p2,jc=!1,Ta=d(()=>{jc||(jc=!0,wn("error",WT,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("---")),oh(Ew,ST,vT,Ww,Zw,Jw,rT,pT,xT,YT,Pw,$w,t2,ZT,Yw,$T,ET,PT,sT,n2,o2,hT,u2,g2))},"addDiagrams"),m2=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{ss(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"),y2="graphics-document document";function td(t,e){t.attr("role",y2),e!==""&&t.attr("aria-roledescription",e)}d(td,"setA11yDiagramInfo");function ed(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(ed,"addSVGa11yTitleDescription");var Lr,Os=(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=Ks(e,i);e=PC(e)+` `;try{ss(n)}catch{const f=Pg(n);if(!f)throw new sh(`Diagram ${n} not found.`);const{id:u,diagram:p}=await f();wn(u,p)}const{db:a,parser:s,renderer:o,init:l}=ss(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),Uc=[],x2=d(()=>{Uc.forEach(t=>{t()}),Uc=[]},"attachFunctions"),b2=d(t=>t.replace(/^\s*%%(?!{)[^\n]+\n?/gm,"").trimStart(),"cleanupComments");function Wo(t){return typeof t>"u"||t===null}d(Wo,"isNothing");function rd(t){return typeof t=="object"&&t!==null}d(rd,"isObject");function id(t){return Array.isArray(t)?t:Wo(t)?[]:[t]}d(id,"toArray");function nd(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 od(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 ML=Object.freeze(Object.defineProperty({__proto__:null,default:iL},Symbol.toStringTag,{value:"Module"}));export{_L as $,ee as A,rf as B,xa as C,Ro as D,fe as E,Zg as F,Lo as G,Se as H,EC as I,Em as J,Zk as K,Ic as L,wb as M,Kl as N,Zl as O,bL as P,pL as Q,yL as R,mL as S,fL as T,U,uo as V,xL as W,dL as X,hr as Y,CL as Z,d as _,Ct as a,oo as a$,gL as a0,jg as a1,Ab as a2,si as a3,oL as a4,Qs as a5,So as a6,CC as a7,eu as a8,sL as a9,hC as aA,yo as aB,Hc as aC,_v as aD,Tb as aE,sg as aF,og as aG,Jm as aH,t0 as aI,hL as aJ,er as aK,xC as aL,ku as aM,da as aN,ya as aO,Nn as aP,Tu as aQ,vu as aR,V1 as aS,so as aT,Ph as aU,zt as aV,$i as aW,Ky as aX,qh as aY,uL as aZ,cg as a_,ym as aa,Mu as ab,Co as ac,Jh as ad,kh as ae,r0 as af,BC as ag,Rg as ah,_h as ai,Mi as aj,q as ak,W as al,uk as am,LL as an,TL as ao,wL as ap,dt as aq,SL as ar,Gk as as,AL as at,Uv as au,Jv as av,Xv as aw,Vv as ax,yC as ay,c1 as az,Tm as b,Fe as b0,ci as b1,jl as b2,nx as b3,mC as b4,cC as b5,Z_ as b6,xo as b7,j1 as b8,_C as b9,Ri as ba,Br as bb,Rn as bc,eC as bd,mw as be,Ii as bf,Pn as bg,X1 as bh,mu as bi,J_ as bj,t1 as bk,We as bl,fc as bm,e1 as bn,bo,Q_ as bp,n1 as bq,Er as br,De as bs,oc as bt,_o as bu,xu as bv,Ms as bw,bC as bx,ma as by,ML as bz,wm as c,K as d,Ar as e,Ou as f,km as g,di as h,Cr as i,at as j,bh as k,k as l,wh as m,Fi as n,lL as o,cL as p,Sm as q,Lm as r,vm as s,Cm as t,le as u,vL as v,OC as w,EL as x,BL as y,ti as z}; function __vite__mapDeps(indexes) { if (!__vite__mapDeps.viteFileDeps) { - __vite__mapDeps.viteFileDeps = ["assets/dagre-P3YPLUS5-fdtXHwJa.js","assets/graph-CKGFjaQu.js","assets/baseUniq-j141U2p6.js","assets/layout-Bmwgbrwx.js","assets/basePickBy-Cyiz-f_r.js","assets/json-BbAt_51R.js","assets/clone-DBEsGdWr.js","assets/app-BClOOpdM.js","assets/c4Diagram-THADGKDP-BrQI6Wg6.js","assets/chunk-XVOYOM2C-fmD0yIZV.js","assets/flowDiagram-JSIZSE4D-CkrFR_87.js","assets/chunk-DUMQOTYW-Bze3ZeWr.js","assets/chunk-YWFND7JV-CtqGT_XT.js","assets/channel-C9cXYHlc.js","assets/erDiagram-62CBQV5Y-kGzN7AR2.js","assets/gitGraphDiagram-UL5UFKDR-N-DngFFf.js","assets/chunk-OQCM5LHU-CGij_B7M.js","assets/chunk-2RYQ3QTB-U6oRI5CH.js","assets/gitGraph-YCYPL57B-BhMcSVnW.js","assets/ganttDiagram-ASEIQ4P5-CoW2hfbL.js","assets/linear-CAdJTZmH.js","assets/init-Gi6I4Gst.js","assets/infoDiagram-7APDZ6AT-CjHjl5ga.js","assets/pieDiagram-OZX6XH5M-BajVz6ZT.js","assets/arc-BJstDFsX.js","assets/ordinal-Cboi1Yqb.js","assets/quadrantDiagram-VG34DGKC-CqrCarqp.js","assets/xychartDiagram-LESROZAQ-BnJ8kkeI.js","assets/requirementDiagram-FPZB6IJI-CtznTREQ.js","assets/sequenceDiagram-PQT5PN7B-DljhtIMV.js","assets/classDiagram-4BHYIK4I-a2lMBkUS.js","assets/chunk-BAVOGKFW-B2dDM16w.js","assets/classDiagram-v2-FI7KE7WJ-Cv9pEPw6.js","assets/chunk-UGV5ZQQN-BxKEe51B.js","assets/stateDiagram-TQSDS2D4-CKjMI_Q3.js","assets/chunk-2JBRQKJ5-BMSx-IbG.js","assets/stateDiagram-v2-J5TZWJW5-BzVT64Mf.js","assets/journeyDiagram-G5LC7W2K-nbd-YhOX.js","assets/timeline-definition-KYQAIZUX-CfFf7B0p.js","assets/mindmap-definition-FCEC46F3-DXSM7Uv5.js","assets/cytoscape.esm-DjcA8a8N.js","assets/sankeyDiagram-KMMQDL5K-i3x2cUcG.js","assets/diagram-QS5GVLUX-Cm0gimUA.js","assets/blockDiagram-EN3ZKWFM-aV_THrNU.js","assets/architectureDiagram-V6B76FHG-DgmvuR6V.js"] + __vite__mapDeps.viteFileDeps = ["assets/dagre-P3YPLUS5-D2h4pGrn.js","assets/graph-DebN9_Dg.js","assets/baseUniq-Bpwj4IW2.js","assets/layout-BkNI4twY.js","assets/basePickBy-BMIT5f2S.js","assets/json-BpfjFNGZ.js","assets/clone-CyxiHGLh.js","assets/app-Dp4t6tDQ.js","assets/c4Diagram-THADGKDP-BV0ojTgT.js","assets/chunk-XVOYOM2C-BZTXkaha.js","assets/flowDiagram-JSIZSE4D-CWnhT7dd.js","assets/chunk-DUMQOTYW-Bi8JUtJi.js","assets/chunk-YWFND7JV-DqutOh5-.js","assets/channel-Bqz4IE8G.js","assets/erDiagram-62CBQV5Y-eD5vQ31J.js","assets/gitGraphDiagram-UL5UFKDR-yPILUU1f.js","assets/chunk-OQCM5LHU-Cbp36FHa.js","assets/chunk-2RYQ3QTB-8PgX7ysJ.js","assets/gitGraph-YCYPL57B-CW0sFWI7.js","assets/ganttDiagram-ASEIQ4P5-DxQ9ChJm.js","assets/linear-S87t6Dgt.js","assets/init-Gi6I4Gst.js","assets/infoDiagram-7APDZ6AT-Cw5OHrUt.js","assets/pieDiagram-OZX6XH5M-BSVm6OG3.js","assets/arc-TolVAfGG.js","assets/ordinal-Cboi1Yqb.js","assets/quadrantDiagram-VG34DGKC-GWgA8Rrq.js","assets/xychartDiagram-LESROZAQ-CAWMdezr.js","assets/requirementDiagram-FPZB6IJI-74hMwT5u.js","assets/sequenceDiagram-PQT5PN7B-OiVI6n8n.js","assets/classDiagram-4BHYIK4I-DaH_u7n6.js","assets/chunk-BAVOGKFW-DK_Q78_U.js","assets/classDiagram-v2-FI7KE7WJ-CbLiwjWK.js","assets/chunk-UGV5ZQQN-B0KztNbp.js","assets/stateDiagram-TQSDS2D4-CEpT6xhM.js","assets/chunk-2JBRQKJ5-c3I5MwZ1.js","assets/stateDiagram-v2-J5TZWJW5-CIAps9nC.js","assets/journeyDiagram-G5LC7W2K-D5obEO4H.js","assets/timeline-definition-KYQAIZUX-bG0Ln98x.js","assets/mindmap-definition-FCEC46F3-D7JZQwFv.js","assets/cytoscape.esm-DjcA8a8N.js","assets/sankeyDiagram-KMMQDL5K-D2j-_3G0.js","assets/diagram-QS5GVLUX-xW2B2nxk.js","assets/blockDiagram-EN3ZKWFM-ypLrqQ_-.js","assets/architectureDiagram-V6B76FHG-BixTwIPG.js"] } return indexes.map((i) => __vite__mapDeps.viteFileDeps[i]) } diff --git a/assets/metrics.html-CLlGz2fL.js b/assets/metrics.html-B3-FRGDI.js similarity index 99% rename from assets/metrics.html-CLlGz2fL.js rename to assets/metrics.html-B3-FRGDI.js index 185e05e94..d03c2fb74 100644 --- a/assets/metrics.html-CLlGz2fL.js +++ b/assets/metrics.html-B3-FRGDI.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-BClOOpdM.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-Dp4t6tDQ.js";const r={},c=e(`

                                      Metrics

                                      更直接(希望更好)的统计导出方式。

                                      相关配置

                                      可以在 inbounds 配置中增加一个 metrics 的 inbound

                                          "inbounds": [
                                               {
                                                   "listen": "127.0.0.1",
                                                   "port": 11111,
                                      diff --git a/assets/metrics.html-CrYEopPV.js b/assets/metrics.html-BLVGjqEG.js
                                      similarity index 99%
                                      rename from assets/metrics.html-CrYEopPV.js
                                      rename to assets/metrics.html-BLVGjqEG.js
                                      index 4ebbaf0d8..9223c347f 100644
                                      --- a/assets/metrics.html-CrYEopPV.js
                                      +++ b/assets/metrics.html-BLVGjqEG.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-BClOOpdM.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-Dp4t6tDQ.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-CVc9hI8H.js b/assets/metrics.html-Dkomm98b.js
                                      similarity index 99%
                                      rename from assets/metrics.html-CVc9hI8H.js
                                      rename to assets/metrics.html-Dkomm98b.js
                                      index c58fd90ea..1e2e29b70 100644
                                      --- a/assets/metrics.html-CVc9hI8H.js
                                      +++ b/assets/metrics.html-Dkomm98b.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-BClOOpdM.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-Dp4t6tDQ.js";const r={},c=e(`

                                      Метрики

                                      Более простой (и, надеюсь, лучший) способ экспорта статистики.

                                      Связанные настройки

                                      Можно добавить входящее подключение metrics в раздел inbounds:

                                          "inbounds": [
                                               {
                                                   "listen": "127.0.0.1",
                                                   "port": 11111,
                                      diff --git a/assets/mindmap-definition-FCEC46F3-DXSM7Uv5.js b/assets/mindmap-definition-FCEC46F3-D7JZQwFv.js
                                      similarity index 99%
                                      rename from assets/mindmap-definition-FCEC46F3-DXSM7Uv5.js
                                      rename to assets/mindmap-definition-FCEC46F3-D7JZQwFv.js
                                      index a6a2ed858..23032967a 100644
                                      --- a/assets/mindmap-definition-FCEC46F3-DXSM7Uv5.js
                                      +++ b/assets/mindmap-definition-FCEC46F3-D7JZQwFv.js
                                      @@ -1,4 +1,4 @@
                                      -import{aF as at,aG as Nt,_ as S,l as z,j as Dt,D as mt,a6 as Ot,d as ot,K as At,aa as It,F as tt,i as et,aj as Ct,ak as Rt,al as xt}from"./mermaid.core-IUatkdtb.js";import{c as pt}from"./cytoscape.esm-DjcA8a8N.js";import"./app-BClOOpdM.js";var dt={exports:{}},it={exports:{}},nt={exports:{}},ut;function Mt(){return ut||(ut=1,function(I,w){(function(m,y){I.exports=y()})(at,function(){return function(f){var m={};function y(r){if(m[r])return m[r].exports;var t=m[r]={i:r,l:!1,exports:{}};return f[r].call(t.exports,t,t.exports,y),t.l=!0,t.exports}return y.m=f,y.c=m,y.i=function(r){return r},y.d=function(r,t,e){y.o(r,t)||Object.defineProperty(r,t,{configurable:!1,enumerable:!0,get:e})},y.n=function(r){var t=r&&r.__esModule?function(){return r.default}:function(){return r};return y.d(t,"a",t),t},y.o=function(r,t){return Object.prototype.hasOwnProperty.call(r,t)},y.p="",y(y.s=26)}([function(f,m,y){function r(){}r.QUALITY=1,r.DEFAULT_CREATE_BENDS_AS_NEEDED=!1,r.DEFAULT_INCREMENTAL=!1,r.DEFAULT_ANIMATION_ON_LAYOUT=!0,r.DEFAULT_ANIMATION_DURING_LAYOUT=!1,r.DEFAULT_ANIMATION_PERIOD=50,r.DEFAULT_UNIFORM_LEAF_NODE_SIZES=!1,r.DEFAULT_GRAPH_MARGIN=15,r.NODE_DIMENSIONS_INCLUDE_LABELS=!1,r.SIMPLE_NODE_SIZE=40,r.SIMPLE_NODE_HALF_SIZE=r.SIMPLE_NODE_SIZE/2,r.EMPTY_COMPOUND_NODE_SIZE=40,r.MIN_EDGE_LENGTH=1,r.WORLD_BOUNDARY=1e6,r.INITIAL_WORLD_BOUNDARY=r.WORLD_BOUNDARY/1e3,r.WORLD_CENTER_X=1200,r.WORLD_CENTER_Y=900,f.exports=r},function(f,m,y){var r=y(2),t=y(8),e=y(9);function i(g,a,v){r.call(this,v),this.isOverlapingSourceAndTarget=!1,this.vGraphObject=v,this.bendpoints=[],this.source=g,this.target=a}i.prototype=Object.create(r.prototype);for(var o in r)i[o]=r[o];i.prototype.getSource=function(){return this.source},i.prototype.getTarget=function(){return this.target},i.prototype.isInterGraph=function(){return this.isInterGraph},i.prototype.getLength=function(){return this.length},i.prototype.isOverlapingSourceAndTarget=function(){return this.isOverlapingSourceAndTarget},i.prototype.getBendpoints=function(){return this.bendpoints},i.prototype.getLca=function(){return this.lca},i.prototype.getSourceInLca=function(){return this.sourceInLca},i.prototype.getTargetInLca=function(){return this.targetInLca},i.prototype.getOtherEnd=function(g){if(this.source===g)return this.target;if(this.target===g)return this.source;throw"Node is not incident with this edge"},i.prototype.getOtherEndInGraph=function(g,a){for(var v=this.getOtherEnd(g),n=a.getGraphManager().getRoot();;){if(v.getOwner()==a)return v;if(v.getOwner()==n)break;v=v.getOwner().getParent()}return null},i.prototype.updateLength=function(){var g=new Array(4);this.isOverlapingSourceAndTarget=t.getIntersection(this.target.getRect(),this.source.getRect(),g),this.isOverlapingSourceAndTarget||(this.lengthX=g[0]-g[2],this.lengthY=g[1]-g[3],Math.abs(this.lengthX)<1&&(this.lengthX=e.sign(this.lengthX)),Math.abs(this.lengthY)<1&&(this.lengthY=e.sign(this.lengthY)),this.length=Math.sqrt(this.lengthX*this.lengthX+this.lengthY*this.lengthY))},i.prototype.updateLengthSimple=function(){this.lengthX=this.target.getCenterX()-this.source.getCenterX(),this.lengthY=this.target.getCenterY()-this.source.getCenterY(),Math.abs(this.lengthX)<1&&(this.lengthX=e.sign(this.lengthX)),Math.abs(this.lengthY)<1&&(this.lengthY=e.sign(this.lengthY)),this.length=Math.sqrt(this.lengthX*this.lengthX+this.lengthY*this.lengthY)},f.exports=i},function(f,m,y){function r(t){this.vGraphObject=t}f.exports=r},function(f,m,y){var r=y(2),t=y(10),e=y(13),i=y(0),o=y(16),g=y(4);function a(n,c,l,E){l==null&&E==null&&(E=c),r.call(this,E),n.graphManager!=null&&(n=n.graphManager),this.estimatedSize=t.MIN_VALUE,this.inclusionTreeDepth=t.MAX_VALUE,this.vGraphObject=E,this.edges=[],this.graphManager=n,l!=null&&c!=null?this.rect=new e(c.x,c.y,l.width,l.height):this.rect=new e}a.prototype=Object.create(r.prototype);for(var v in r)a[v]=r[v];a.prototype.getEdges=function(){return this.edges},a.prototype.getChild=function(){return this.child},a.prototype.getOwner=function(){return this.owner},a.prototype.getWidth=function(){return this.rect.width},a.prototype.setWidth=function(n){this.rect.width=n},a.prototype.getHeight=function(){return this.rect.height},a.prototype.setHeight=function(n){this.rect.height=n},a.prototype.getCenterX=function(){return this.rect.x+this.rect.width/2},a.prototype.getCenterY=function(){return this.rect.y+this.rect.height/2},a.prototype.getCenter=function(){return new g(this.rect.x+this.rect.width/2,this.rect.y+this.rect.height/2)},a.prototype.getLocation=function(){return new g(this.rect.x,this.rect.y)},a.prototype.getRect=function(){return this.rect},a.prototype.getDiagonal=function(){return Math.sqrt(this.rect.width*this.rect.width+this.rect.height*this.rect.height)},a.prototype.getHalfTheDiagonal=function(){return Math.sqrt(this.rect.height*this.rect.height+this.rect.width*this.rect.width)/2},a.prototype.setRect=function(n,c){this.rect.x=n.x,this.rect.y=n.y,this.rect.width=c.width,this.rect.height=c.height},a.prototype.setCenter=function(n,c){this.rect.x=n-this.rect.width/2,this.rect.y=c-this.rect.height/2},a.prototype.setLocation=function(n,c){this.rect.x=n,this.rect.y=c},a.prototype.moveBy=function(n,c){this.rect.x+=n,this.rect.y+=c},a.prototype.getEdgeListToNode=function(n){var c=[],l=this;return l.edges.forEach(function(E){if(E.target==n){if(E.source!=l)throw"Incorrect edge source!";c.push(E)}}),c},a.prototype.getEdgesBetween=function(n){var c=[],l=this;return l.edges.forEach(function(E){if(!(E.source==l||E.target==l))throw"Incorrect edge source and/or target";(E.target==n||E.source==n)&&c.push(E)}),c},a.prototype.getNeighborsList=function(){var n=new Set,c=this;return c.edges.forEach(function(l){if(l.source==c)n.add(l.target);else{if(l.target!=c)throw"Incorrect incidency!";n.add(l.source)}}),n},a.prototype.withChildren=function(){var n=new Set,c,l;if(n.add(this),this.child!=null)for(var E=this.child.getNodes(),T=0;Tc&&(this.rect.x-=(this.labelWidth-c)/2,this.setWidth(this.labelWidth)),this.labelHeight>l&&(this.labelPos=="center"?this.rect.y-=(this.labelHeight-l)/2:this.labelPos=="top"&&(this.rect.y-=this.labelHeight-l),this.setHeight(this.labelHeight))}}},a.prototype.getInclusionTreeDepth=function(){if(this.inclusionTreeDepth==t.MAX_VALUE)throw"assert failed";return this.inclusionTreeDepth},a.prototype.transform=function(n){var c=this.rect.x;c>i.WORLD_BOUNDARY?c=i.WORLD_BOUNDARY:c<-i.WORLD_BOUNDARY&&(c=-i.WORLD_BOUNDARY);var l=this.rect.y;l>i.WORLD_BOUNDARY?l=i.WORLD_BOUNDARY:l<-i.WORLD_BOUNDARY&&(l=-i.WORLD_BOUNDARY);var E=new g(c,l),T=n.inverseTransformPoint(E);this.setLocation(T.x,T.y)},a.prototype.getLeft=function(){return this.rect.x},a.prototype.getRight=function(){return this.rect.x+this.rect.width},a.prototype.getTop=function(){return this.rect.y},a.prototype.getBottom=function(){return this.rect.y+this.rect.height},a.prototype.getParent=function(){return this.owner==null?null:this.owner.getParent()},f.exports=a},function(f,m,y){function r(t,e){t==null&&e==null?(this.x=0,this.y=0):(this.x=t,this.y=e)}r.prototype.getX=function(){return this.x},r.prototype.getY=function(){return this.y},r.prototype.setX=function(t){this.x=t},r.prototype.setY=function(t){this.y=t},r.prototype.getDifference=function(t){return new DimensionD(this.x-t.x,this.y-t.y)},r.prototype.getCopy=function(){return new r(this.x,this.y)},r.prototype.translate=function(t){return this.x+=t.width,this.y+=t.height,this},f.exports=r},function(f,m,y){var r=y(2),t=y(10),e=y(0),i=y(6),o=y(3),g=y(1),a=y(13),v=y(12),n=y(11);function c(E,T,D){r.call(this,D),this.estimatedSize=t.MIN_VALUE,this.margin=e.DEFAULT_GRAPH_MARGIN,this.edges=[],this.nodes=[],this.isConnected=!1,this.parent=E,T!=null&&T instanceof i?this.graphManager=T:T!=null&&T instanceof Layout&&(this.graphManager=T.graphManager)}c.prototype=Object.create(r.prototype);for(var l in r)c[l]=r[l];c.prototype.getNodes=function(){return this.nodes},c.prototype.getEdges=function(){return this.edges},c.prototype.getGraphManager=function(){return this.graphManager},c.prototype.getParent=function(){return this.parent},c.prototype.getLeft=function(){return this.left},c.prototype.getRight=function(){return this.right},c.prototype.getTop=function(){return this.top},c.prototype.getBottom=function(){return this.bottom},c.prototype.isConnected=function(){return this.isConnected},c.prototype.add=function(E,T,D){if(T==null&&D==null){var L=E;if(this.graphManager==null)throw"Graph has no graph mgr!";if(this.getNodes().indexOf(L)>-1)throw"Node already in graph!";return L.owner=this,this.getNodes().push(L),L}else{var O=E;if(!(this.getNodes().indexOf(T)>-1&&this.getNodes().indexOf(D)>-1))throw"Source or target not in graph!";if(!(T.owner==D.owner&&T.owner==this))throw"Both owners must be this graph!";return T.owner!=D.owner?null:(O.source=T,O.target=D,O.isInterGraph=!1,this.getEdges().push(O),T.edges.push(O),D!=T&&D.edges.push(O),O)}},c.prototype.remove=function(E){var T=E;if(E instanceof o){if(T==null)throw"Node is null!";if(!(T.owner!=null&&T.owner==this))throw"Owner graph is invalid!";if(this.graphManager==null)throw"Owner graph manager is invalid!";for(var D=T.edges.slice(),L,O=D.length,d=0;d-1&&h>-1))throw"Source and/or target doesn't know this edge!";L.source.edges.splice(s,1),L.target!=L.source&&L.target.edges.splice(h,1);var N=L.source.owner.getEdges().indexOf(L);if(N==-1)throw"Not in owner's edge list!";L.source.owner.getEdges().splice(N,1)}},c.prototype.updateLeftTop=function(){for(var E=t.MAX_VALUE,T=t.MAX_VALUE,D,L,O,d=this.getNodes(),N=d.length,s=0;sD&&(E=D),T>L&&(T=L)}return E==t.MAX_VALUE?null:(d[0].getParent().paddingLeft!=null?O=d[0].getParent().paddingLeft:O=this.margin,this.left=T-O,this.top=E-O,new v(this.left,this.top))},c.prototype.updateBounds=function(E){for(var T=t.MAX_VALUE,D=-t.MAX_VALUE,L=t.MAX_VALUE,O=-t.MAX_VALUE,d,N,s,h,u,p=this.nodes,A=p.length,C=0;Cd&&(T=d),Ds&&(L=s),Od&&(T=d),Ds&&(L=s),O=this.nodes.length){var A=0;D.forEach(function(C){C.owner==E&&A++}),A==this.nodes.length&&(this.isConnected=!0)}},f.exports=c},function(f,m,y){var r,t=y(1);function e(i){r=y(5),this.layout=i,this.graphs=[],this.edges=[]}e.prototype.addRoot=function(){var i=this.layout.newGraph(),o=this.layout.newNode(null),g=this.add(i,o);return this.setRootGraph(g),this.rootGraph},e.prototype.add=function(i,o,g,a,v){if(g==null&&a==null&&v==null){if(i==null)throw"Graph is null!";if(o==null)throw"Parent node is null!";if(this.graphs.indexOf(i)>-1)throw"Graph already in this graph mgr!";if(this.graphs.push(i),i.parent!=null)throw"Already has a parent!";if(o.child!=null)throw"Already has a child!";return i.parent=o,o.child=i,i}else{v=g,a=o,g=i;var n=a.getOwner(),c=v.getOwner();if(!(n!=null&&n.getGraphManager()==this))throw"Source not in this graph mgr!";if(!(c!=null&&c.getGraphManager()==this))throw"Target not in this graph mgr!";if(n==c)return g.isInterGraph=!1,n.add(g,a,v);if(g.isInterGraph=!0,g.source=a,g.target=v,this.edges.indexOf(g)>-1)throw"Edge already in inter-graph edge list!";if(this.edges.push(g),!(g.source!=null&&g.target!=null))throw"Edge source and/or target is null!";if(!(g.source.edges.indexOf(g)==-1&&g.target.edges.indexOf(g)==-1))throw"Edge already in source and/or target incidency list!";return g.source.edges.push(g),g.target.edges.push(g),g}},e.prototype.remove=function(i){if(i instanceof r){var o=i;if(o.getGraphManager()!=this)throw"Graph not in this graph mgr";if(!(o==this.rootGraph||o.parent!=null&&o.parent.graphManager==this))throw"Invalid parent node!";var g=[];g=g.concat(o.getEdges());for(var a,v=g.length,n=0;n=i.getRight()?o[0]+=Math.min(i.getX()-e.getX(),e.getRight()-i.getRight()):i.getX()<=e.getX()&&i.getRight()>=e.getRight()&&(o[0]+=Math.min(e.getX()-i.getX(),i.getRight()-e.getRight())),e.getY()<=i.getY()&&e.getBottom()>=i.getBottom()?o[1]+=Math.min(i.getY()-e.getY(),e.getBottom()-i.getBottom()):i.getY()<=e.getY()&&i.getBottom()>=e.getBottom()&&(o[1]+=Math.min(e.getY()-i.getY(),i.getBottom()-e.getBottom()));var v=Math.abs((i.getCenterY()-e.getCenterY())/(i.getCenterX()-e.getCenterX()));i.getCenterY()===e.getCenterY()&&i.getCenterX()===e.getCenterX()&&(v=1);var n=v*o[0],c=o[1]/v;o[0]n)return o[0]=g,o[1]=l,o[2]=v,o[3]=p,!1;if(av)return o[0]=c,o[1]=a,o[2]=h,o[3]=n,!1;if(gv?(o[0]=T,o[1]=D,x=!0):(o[0]=E,o[1]=l,x=!0):U===M&&(g>v?(o[0]=c,o[1]=l,x=!0):(o[0]=L,o[1]=D,x=!0)),-X===M?v>g?(o[2]=u,o[3]=p,_=!0):(o[2]=h,o[3]=s,_=!0):X===M&&(v>g?(o[2]=N,o[3]=s,_=!0):(o[2]=A,o[3]=p,_=!0)),x&&_)return!1;if(g>v?a>n?(G=this.getCardinalDirection(U,M,4),F=this.getCardinalDirection(X,M,2)):(G=this.getCardinalDirection(-U,M,3),F=this.getCardinalDirection(-X,M,1)):a>n?(G=this.getCardinalDirection(-U,M,1),F=this.getCardinalDirection(-X,M,3)):(G=this.getCardinalDirection(U,M,2),F=this.getCardinalDirection(X,M,4)),!x)switch(G){case 1:Y=l,b=g+-d/M,o[0]=b,o[1]=Y;break;case 2:b=L,Y=a+O*M,o[0]=b,o[1]=Y;break;case 3:Y=D,b=g+d/M,o[0]=b,o[1]=Y;break;case 4:b=T,Y=a+-O*M,o[0]=b,o[1]=Y;break}if(!_)switch(F){case 1:H=s,k=v+-R/M,o[2]=k,o[3]=H;break;case 2:k=A,H=n+C*M,o[2]=k,o[3]=H;break;case 3:H=p,k=v+R/M,o[2]=k,o[3]=H;break;case 4:k=u,H=n+-C*M,o[2]=k,o[3]=H;break}}return!1},t.getCardinalDirection=function(e,i,o){return e>i?o:1+o%4},t.getIntersection=function(e,i,o,g){if(g==null)return this.getIntersection2(e,i,o);var a=e.x,v=e.y,n=i.x,c=i.y,l=o.x,E=o.y,T=g.x,D=g.y,L=void 0,O=void 0,d=void 0,N=void 0,s=void 0,h=void 0,u=void 0,p=void 0,A=void 0;return d=c-v,s=a-n,u=n*v-a*c,N=D-E,h=l-T,p=T*E-l*D,A=d*h-N*s,A===0?null:(L=(s*p-h*u)/A,O=(N*u-d*p)/A,new r(L,O))},t.angleOfVector=function(e,i,o,g){var a=void 0;return e!==o?(a=Math.atan((g-i)/(o-e)),o0?1:t<0?-1:0},r.floor=function(t){return t<0?Math.ceil(t):Math.floor(t)},r.ceil=function(t){return t<0?Math.floor(t):Math.ceil(t)},f.exports=r},function(f,m,y){function r(){}r.MAX_VALUE=2147483647,r.MIN_VALUE=-2147483648,f.exports=r},function(f,m,y){var r=function(){function a(v,n){for(var c=0;c"u"?"undefined":r(e);return e==null||i!="object"&&i!="function"},f.exports=t},function(f,m,y){function r(l){if(Array.isArray(l)){for(var E=0,T=Array(l.length);E0&&E;){for(d.push(s[0]);d.length>0&&E;){var h=d[0];d.splice(0,1),O.add(h);for(var u=h.getEdges(),L=0;L-1&&s.splice(R,1)}O=new Set,N=new Map}}return l},c.prototype.createDummyNodesForBendpoints=function(l){for(var E=[],T=l.source,D=this.graphManager.calcLowestCommonAncestor(l.source,l.target),L=0;L0){for(var D=this.edgeToDummyNodes.get(T),L=0;L=0&&E.splice(p,1);var A=N.getNeighborsList();A.forEach(function(x){if(T.indexOf(x)<0){var _=D.get(x),U=_-1;U==1&&h.push(x),D.set(x,U)}})}T=T.concat(h),(E.length==1||E.length==2)&&(L=!0,O=E[0])}return O},c.prototype.setGraphManager=function(l){this.graphManager=l},f.exports=c},function(f,m,y){function r(){}r.seed=1,r.x=0,r.nextDouble=function(){return r.x=Math.sin(r.seed++)*1e4,r.x-Math.floor(r.x)},f.exports=r},function(f,m,y){var r=y(4);function t(e,i){this.lworldOrgX=0,this.lworldOrgY=0,this.ldeviceOrgX=0,this.ldeviceOrgY=0,this.lworldExtX=1,this.lworldExtY=1,this.ldeviceExtX=1,this.ldeviceExtY=1}t.prototype.getWorldOrgX=function(){return this.lworldOrgX},t.prototype.setWorldOrgX=function(e){this.lworldOrgX=e},t.prototype.getWorldOrgY=function(){return this.lworldOrgY},t.prototype.setWorldOrgY=function(e){this.lworldOrgY=e},t.prototype.getWorldExtX=function(){return this.lworldExtX},t.prototype.setWorldExtX=function(e){this.lworldExtX=e},t.prototype.getWorldExtY=function(){return this.lworldExtY},t.prototype.setWorldExtY=function(e){this.lworldExtY=e},t.prototype.getDeviceOrgX=function(){return this.ldeviceOrgX},t.prototype.setDeviceOrgX=function(e){this.ldeviceOrgX=e},t.prototype.getDeviceOrgY=function(){return this.ldeviceOrgY},t.prototype.setDeviceOrgY=function(e){this.ldeviceOrgY=e},t.prototype.getDeviceExtX=function(){return this.ldeviceExtX},t.prototype.setDeviceExtX=function(e){this.ldeviceExtX=e},t.prototype.getDeviceExtY=function(){return this.ldeviceExtY},t.prototype.setDeviceExtY=function(e){this.ldeviceExtY=e},t.prototype.transformX=function(e){var i=0,o=this.lworldExtX;return o!=0&&(i=this.ldeviceOrgX+(e-this.lworldOrgX)*this.ldeviceExtX/o),i},t.prototype.transformY=function(e){var i=0,o=this.lworldExtY;return o!=0&&(i=this.ldeviceOrgY+(e-this.lworldOrgY)*this.ldeviceExtY/o),i},t.prototype.inverseTransformX=function(e){var i=0,o=this.ldeviceExtX;return o!=0&&(i=this.lworldOrgX+(e-this.ldeviceOrgX)*this.lworldExtX/o),i},t.prototype.inverseTransformY=function(e){var i=0,o=this.ldeviceExtY;return o!=0&&(i=this.lworldOrgY+(e-this.ldeviceOrgY)*this.lworldExtY/o),i},t.prototype.inverseTransformPoint=function(e){var i=new r(this.inverseTransformX(e.x),this.inverseTransformY(e.y));return i},f.exports=t},function(f,m,y){function r(n){if(Array.isArray(n)){for(var c=0,l=Array(n.length);ce.ADAPTATION_LOWER_NODE_LIMIT&&(this.coolingFactor=Math.max(this.coolingFactor*e.COOLING_ADAPTATION_FACTOR,this.coolingFactor-(n-e.ADAPTATION_LOWER_NODE_LIMIT)/(e.ADAPTATION_UPPER_NODE_LIMIT-e.ADAPTATION_LOWER_NODE_LIMIT)*this.coolingFactor*(1-e.COOLING_ADAPTATION_FACTOR))),this.maxNodeDisplacement=e.MAX_NODE_DISPLACEMENT_INCREMENTAL):(n>e.ADAPTATION_LOWER_NODE_LIMIT?this.coolingFactor=Math.max(e.COOLING_ADAPTATION_FACTOR,1-(n-e.ADAPTATION_LOWER_NODE_LIMIT)/(e.ADAPTATION_UPPER_NODE_LIMIT-e.ADAPTATION_LOWER_NODE_LIMIT)*(1-e.COOLING_ADAPTATION_FACTOR)):this.coolingFactor=1,this.initialCoolingFactor=this.coolingFactor,this.maxNodeDisplacement=e.MAX_NODE_DISPLACEMENT),this.maxIterations=Math.max(this.getAllNodes().length*5,this.maxIterations),this.totalDisplacementThreshold=this.displacementThresholdPerNode*this.getAllNodes().length,this.repulsionRange=this.calcRepulsionRange()},a.prototype.calcSpringForces=function(){for(var n=this.getAllEdges(),c,l=0;l0&&arguments[0]!==void 0?arguments[0]:!0,c=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!1,l,E,T,D,L=this.getAllNodes(),O;if(this.useFRGridVariant)for(this.totalIterations%e.GRID_CALCULATION_CHECK_PERIOD==1&&n&&this.updateGrid(),O=new Set,l=0;ld||O>d)&&(n.gravitationForceX=-this.gravityConstant*T,n.gravitationForceY=-this.gravityConstant*D)):(d=c.getEstimatedSize()*this.compoundGravityRangeFactor,(L>d||O>d)&&(n.gravitationForceX=-this.gravityConstant*T*this.compoundGravityConstant,n.gravitationForceY=-this.gravityConstant*D*this.compoundGravityConstant))},a.prototype.isConverged=function(){var n,c=!1;return this.totalIterations>this.maxIterations/3&&(c=Math.abs(this.totalDisplacement-this.oldTotalDisplacement)<2),n=this.totalDisplacement=L.length||d>=L[0].length)){for(var N=0;Na}}]),o}();f.exports=i},function(f,m,y){var r=function(){function i(o,g){for(var a=0;a2&&arguments[2]!==void 0?arguments[2]:1,v=arguments.length>3&&arguments[3]!==void 0?arguments[3]:-1,n=arguments.length>4&&arguments[4]!==void 0?arguments[4]:-1;t(this,i),this.sequence1=o,this.sequence2=g,this.match_score=a,this.mismatch_penalty=v,this.gap_penalty=n,this.iMax=o.length+1,this.jMax=g.length+1,this.grid=new Array(this.iMax);for(var c=0;c=0;o--){var g=this.listeners[o];g.event===e&&g.callback===i&&this.listeners.splice(o,1)}},t.emit=function(e,i){for(var o=0;og.coolingFactor*g.maxNodeDisplacement&&(this.displacementX=g.coolingFactor*g.maxNodeDisplacement*e.sign(this.displacementX)),Math.abs(this.displacementY)>g.coolingFactor*g.maxNodeDisplacement&&(this.displacementY=g.coolingFactor*g.maxNodeDisplacement*e.sign(this.displacementY)),this.child==null?this.moveBy(this.displacementX,this.displacementY):this.child.getNodes().length==0?this.moveBy(this.displacementX,this.displacementY):this.propogateDisplacementToChildren(this.displacementX,this.displacementY),g.totalDisplacement+=Math.abs(this.displacementX)+Math.abs(this.displacementY),this.springForceX=0,this.springForceY=0,this.repulsionForceX=0,this.repulsionForceY=0,this.gravitationForceX=0,this.gravitationForceY=0,this.displacementX=0,this.displacementY=0},i.prototype.propogateDisplacementToChildren=function(g,a){for(var v=this.getChild().getNodes(),n,c=0;c0)this.positionNodesRadially(s);else{this.reduceTrees(),this.graphManager.resetAllNodesToApplyGravitation();var h=new Set(this.getAllNodes()),u=this.nodesWithGravity.filter(function(p){return h.has(p)});this.graphManager.setAllNodesToApplyGravitation(u),this.positionNodesRandomly()}}return this.initSpringEmbedder(),this.runSpringEmbedder(),!0},d.prototype.tick=function(){if(this.totalIterations++,this.totalIterations===this.maxIterations&&!this.isTreeGrowing&&!this.isGrowthFinished)if(this.prunedNodesAll.length>0)this.isTreeGrowing=!0;else return!0;if(this.totalIterations%v.CONVERGENCE_CHECK_PERIOD==0&&!this.isTreeGrowing&&!this.isGrowthFinished){if(this.isConverged())if(this.prunedNodesAll.length>0)this.isTreeGrowing=!0;else return!0;this.coolingCycle++,this.layoutQuality==0?this.coolingAdjuster=this.coolingCycle:this.layoutQuality==1&&(this.coolingAdjuster=this.coolingCycle/3),this.coolingFactor=Math.max(this.initialCoolingFactor-Math.pow(this.coolingCycle,Math.log(100*(this.initialCoolingFactor-this.finalTemperature))/Math.log(this.maxCoolingCycle))/100*this.coolingAdjuster,this.finalTemperature),this.animationPeriod=Math.ceil(this.initialAnimationPeriod*Math.sqrt(this.coolingFactor))}if(this.isTreeGrowing){if(this.growTreeIterations%10==0)if(this.prunedNodesAll.length>0){this.graphManager.updateBounds(),this.updateGrid(),this.growTree(this.prunedNodesAll),this.graphManager.resetAllNodesToApplyGravitation();var s=new Set(this.getAllNodes()),h=this.nodesWithGravity.filter(function(A){return s.has(A)});this.graphManager.setAllNodesToApplyGravitation(h),this.graphManager.updateBounds(),this.updateGrid(),this.coolingFactor=v.DEFAULT_COOLING_FACTOR_INCREMENTAL}else this.isTreeGrowing=!1,this.isGrowthFinished=!0;this.growTreeIterations++}if(this.isGrowthFinished){if(this.isConverged())return!0;this.afterGrowthIterations%10==0&&(this.graphManager.updateBounds(),this.updateGrid()),this.coolingFactor=v.DEFAULT_COOLING_FACTOR_INCREMENTAL*((100-this.afterGrowthIterations)/100),this.afterGrowthIterations++}var u=!this.isTreeGrowing&&!this.isGrowthFinished,p=this.growTreeIterations%10==1&&this.isTreeGrowing||this.afterGrowthIterations%10==1&&this.isGrowthFinished;return this.totalDisplacement=0,this.graphManager.updateBounds(),this.calcSpringForces(),this.calcRepulsionForces(u,p),this.calcGravitationalForces(),this.moveNodes(),this.animate(),!1},d.prototype.getPositionsData=function(){for(var s=this.graphManager.getAllNodes(),h={},u=0;u1){var x;for(x=0;xp&&(p=Math.floor(R.y)),C=Math.floor(R.x+a.DEFAULT_COMPONENT_SEPERATION)}this.transform(new l(n.WORLD_CENTER_X-R.x/2,n.WORLD_CENTER_Y-R.y/2))},d.radialLayout=function(s,h,u){var p=Math.max(this.maxDiagonalInTree(s),a.DEFAULT_RADIAL_SEPARATION);d.branchRadialLayout(h,null,0,359,0,p);var A=L.calculateBounds(s),C=new O;C.setDeviceOrgX(A.getMinX()),C.setDeviceOrgY(A.getMinY()),C.setWorldOrgX(u.x),C.setWorldOrgY(u.y);for(var R=0;R1;){var H=k[0];k.splice(0,1);var P=M.indexOf(H);P>=0&&M.splice(P,1),b--,G--}h!=null?Y=(M.indexOf(k[0])+1)%b:Y=0;for(var B=Math.abs(p-u)/G,$=Y;F!=G;$=++$%b){var K=M[$].getOtherEnd(s);if(K!=h){var Q=(u+F*B)%360,J=(Q+B)%360;d.branchRadialLayout(K,s,Q,J,A+C,C),F++}}},d.maxDiagonalInTree=function(s){for(var h=T.MIN_VALUE,u=0;uh&&(h=A)}return h},d.prototype.calcRepulsionRange=function(){return 2*(this.level+1)*this.idealEdgeLength},d.prototype.groupZeroDegreeMembers=function(){var s=this,h={};this.memberGroups={},this.idToDummyNode={};for(var u=[],p=this.graphManager.getAllNodes(),A=0;A"u"&&(h[x]=[]),h[x]=h[x].concat(C)}Object.keys(h).forEach(function(_){if(h[_].length>1){var U="DummyCompound_"+_;s.memberGroups[U]=h[_];var X=h[_][0].getParent(),M=new o(s.graphManager);M.id=U,M.paddingLeft=X.paddingLeft||0,M.paddingRight=X.paddingRight||0,M.paddingBottom=X.paddingBottom||0,M.paddingTop=X.paddingTop||0,s.idToDummyNode[U]=M;var G=s.getGraphManager().add(s.newGraph(),M),F=X.getChild();F.add(M);for(var b=0;b=0;s--){var h=this.compoundOrder[s],u=h.id,p=h.paddingLeft,A=h.paddingTop;this.adjustLocations(this.tiledMemberPack[u],h.rect.x,h.rect.y,p,A)}},d.prototype.repopulateZeroDegreeMembers=function(){var s=this,h=this.tiledZeroDegreePack;Object.keys(h).forEach(function(u){var p=s.idToDummyNode[u],A=p.paddingLeft,C=p.paddingTop;s.adjustLocations(h[u],p.rect.x,p.rect.y,A,C)})},d.prototype.getToBeTiled=function(s){var h=s.id;if(this.toBeTiled[h]!=null)return this.toBeTiled[h];var u=s.getChild();if(u==null)return this.toBeTiled[h]=!1,!1;for(var p=u.getNodes(),A=0;A0)return this.toBeTiled[h]=!1,!1;if(C.getChild()==null){this.toBeTiled[C.id]=!1;continue}if(!this.getToBeTiled(C))return this.toBeTiled[h]=!1,!1}return this.toBeTiled[h]=!0,!0},d.prototype.getNodeDegree=function(s){s.id;for(var h=s.getEdges(),u=0,p=0;p_&&(_=X.rect.height)}u+=_+s.verticalPadding}},d.prototype.tileCompoundMembers=function(s,h){var u=this;this.tiledMemberPack=[],Object.keys(s).forEach(function(p){var A=h[p];u.tiledMemberPack[p]=u.tileNodes(s[p],A.paddingLeft+A.paddingRight),A.rect.width=u.tiledMemberPack[p].width,A.rect.height=u.tiledMemberPack[p].height})},d.prototype.tileNodes=function(s,h){var u=a.TILING_PADDING_VERTICAL,p=a.TILING_PADDING_HORIZONTAL,A={rows:[],rowWidth:[],rowHeight:[],width:0,height:h,verticalPadding:u,horizontalPadding:p};s.sort(function(x,_){return x.rect.width*x.rect.height>_.rect.width*_.rect.height?-1:x.rect.width*x.rect.height<_.rect.width*_.rect.height?1:0});for(var C=0;C0&&(R+=s.horizontalPadding),s.rowWidth[u]=R,s.width0&&(x+=s.verticalPadding);var _=0;x>s.rowHeight[u]&&(_=s.rowHeight[u],s.rowHeight[u]=x,_=s.rowHeight[u]-_),s.height+=_,s.rows[u].push(h)},d.prototype.getShortestRowIndex=function(s){for(var h=-1,u=Number.MAX_VALUE,p=0;pu&&(h=p,u=s.rowWidth[p]);return h},d.prototype.canAddHorizontal=function(s,h,u){var p=this.getShortestRowIndex(s);if(p<0)return!0;var A=s.rowWidth[p];if(A+s.horizontalPadding+h<=s.width)return!0;var C=0;s.rowHeight[p]0&&(C=u+s.verticalPadding-s.rowHeight[p]);var R;s.width-A>=h+s.horizontalPadding?R=(s.height+C)/(A+h+s.horizontalPadding):R=(s.height+C)/s.width,C=u+s.verticalPadding;var x;return s.widthC&&h!=u){p.splice(-1,1),s.rows[u].push(A),s.rowWidth[h]=s.rowWidth[h]-C,s.rowWidth[u]=s.rowWidth[u]+C,s.width=s.rowWidth[instance.getLongestRowIndex(s)];for(var R=Number.MIN_VALUE,x=0;xR&&(R=p[x].height);h>0&&(R+=s.verticalPadding);var _=s.rowHeight[h]+s.rowHeight[u];s.rowHeight[h]=R,s.rowHeight[u]0)for(var F=A;F<=C;F++)G[0]+=this.grid[F][R-1].length+this.grid[F][R].length-1;if(C0)for(var F=R;F<=x;F++)G[3]+=this.grid[A-1][F].length+this.grid[A][F].length-1;for(var b=T.MAX_VALUE,Y,k,H=0;H0){var x;x=O.getGraphManager().add(O.newGraph(),u),this.processChildrenList(x,h,O)}}},l.prototype.stop=function(){return this.stopped=!0,this};var T=function(L){L("layout","cose-bilkent",l)};typeof cytoscape<"u"&&T(cytoscape),m.exports=T}])})})(dt);var St=dt.exports;const Gt=Nt(St);var st=function(){var I=S(function(O,d,N,s){for(N=N||{},s=O.length;s--;N[O[s]]=d);return N},"o"),w=[1,4],f=[1,13],m=[1,12],y=[1,15],r=[1,16],t=[1,20],e=[1,19],i=[6,7,8],o=[1,26],g=[1,24],a=[1,25],v=[6,7,11],n=[1,6,13,15,16,19,22],c=[1,33],l=[1,34],E=[1,6,7,11,13,15,16,19,22],T={trace:S(function(){},"trace"),yy:{},symbols_:{error:2,start:3,mindMap:4,spaceLines:5,SPACELINE:6,NL:7,MINDMAP:8,document:9,stop:10,EOF:11,statement:12,SPACELIST:13,node:14,ICON:15,CLASS:16,nodeWithId:17,nodeWithoutId:18,NODE_DSTART:19,NODE_DESCR:20,NODE_DEND:21,NODE_ID:22,$accept:0,$end:1},terminals_:{2:"error",6:"SPACELINE",7:"NL",8:"MINDMAP",11:"EOF",13:"SPACELIST",15:"ICON",16:"CLASS",19:"NODE_DSTART",20:"NODE_DESCR",21:"NODE_DEND",22:"NODE_ID"},productions_:[0,[3,1],[3,2],[5,1],[5,2],[5,2],[4,2],[4,3],[10,1],[10,1],[10,1],[10,2],[10,2],[9,3],[9,2],[12,2],[12,2],[12,2],[12,1],[12,1],[12,1],[12,1],[12,1],[14,1],[14,1],[18,3],[17,1],[17,4]],performAction:S(function(d,N,s,h,u,p,A){var C=p.length-1;switch(u){case 6:case 7:return h;case 8:h.getLogger().trace("Stop NL ");break;case 9:h.getLogger().trace("Stop EOF ");break;case 11:h.getLogger().trace("Stop NL2 ");break;case 12:h.getLogger().trace("Stop EOF2 ");break;case 15:h.getLogger().info("Node: ",p[C].id),h.addNode(p[C-1].length,p[C].id,p[C].descr,p[C].type);break;case 16:h.getLogger().trace("Icon: ",p[C]),h.decorateNode({icon:p[C]});break;case 17:case 21:h.decorateNode({class:p[C]});break;case 18:h.getLogger().trace("SPACELIST");break;case 19:h.getLogger().trace("Node: ",p[C].id),h.addNode(0,p[C].id,p[C].descr,p[C].type);break;case 20:h.decorateNode({icon:p[C]});break;case 25:h.getLogger().trace("node found ..",p[C-2]),this.$={id:p[C-1],descr:p[C-1],type:h.getType(p[C-2],p[C])};break;case 26:this.$={id:p[C],descr:p[C],type:h.nodeType.DEFAULT};break;case 27:h.getLogger().trace("node found ..",p[C-3]),this.$={id:p[C-3],descr:p[C-1],type:h.getType(p[C-2],p[C])};break}},"anonymous"),table:[{3:1,4:2,5:3,6:[1,5],8:w},{1:[3]},{1:[2,1]},{4:6,6:[1,7],7:[1,8],8:w},{6:f,7:[1,10],9:9,12:11,13:m,14:14,15:y,16:r,17:17,18:18,19:t,22:e},I(i,[2,3]),{1:[2,2]},I(i,[2,4]),I(i,[2,5]),{1:[2,6],6:f,12:21,13:m,14:14,15:y,16:r,17:17,18:18,19:t,22:e},{6:f,9:22,12:11,13:m,14:14,15:y,16:r,17:17,18:18,19:t,22:e},{6:o,7:g,10:23,11:a},I(v,[2,22],{17:17,18:18,14:27,15:[1,28],16:[1,29],19:t,22:e}),I(v,[2,18]),I(v,[2,19]),I(v,[2,20]),I(v,[2,21]),I(v,[2,23]),I(v,[2,24]),I(v,[2,26],{19:[1,30]}),{20:[1,31]},{6:o,7:g,10:32,11:a},{1:[2,7],6:f,12:21,13:m,14:14,15:y,16:r,17:17,18:18,19:t,22:e},I(n,[2,14],{7:c,11:l}),I(E,[2,8]),I(E,[2,9]),I(E,[2,10]),I(v,[2,15]),I(v,[2,16]),I(v,[2,17]),{20:[1,35]},{21:[1,36]},I(n,[2,13],{7:c,11:l}),I(E,[2,11]),I(E,[2,12]),{21:[1,37]},I(v,[2,25]),I(v,[2,27])],defaultActions:{2:[2,1],6:[2,2]},parseError:S(function(d,N){if(N.recoverable)this.trace(d);else{var s=new Error(d);throw s.hash=N,s}},"parseError"),parse:S(function(d){var N=this,s=[0],h=[],u=[null],p=[],A=this.table,C="",R=0,x=0,_=2,U=1,X=p.slice.call(arguments,1),M=Object.create(this.lexer),G={yy:{}};for(var F in this.yy)Object.prototype.hasOwnProperty.call(this.yy,F)&&(G.yy[F]=this.yy[F]);M.setInput(d,G.yy),G.yy.lexer=M,G.yy.parser=this,typeof M.yylloc>"u"&&(M.yylloc={});var b=M.yylloc;p.push(b);var Y=M.options&&M.options.ranges;typeof G.yy.parseError=="function"?this.parseError=G.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function k(V){s.length=s.length-2*V,u.length=u.length-V,p.length=p.length-V}S(k,"popStack");function H(){var V;return V=h.pop()||M.lex()||U,typeof V!="number"&&(V instanceof Array&&(h=V,V=h.pop()),V=N.symbols_[V]||V),V}S(H,"lex");for(var P,B,$,K,Q={},J,j,gt,q;;){if(B=s[s.length-1],this.defaultActions[B]?$=this.defaultActions[B]:((P===null||typeof P>"u")&&(P=H()),$=A[B]&&A[B][P]),typeof $>"u"||!$.length||!$[0]){var rt="";q=[];for(J in A[B])this.terminals_[J]&&J>_&&q.push("'"+this.terminals_[J]+"'");M.showPosition?rt="Parse error on line "+(R+1)+`:
                                      +import{aF as at,aG as Nt,_ as S,l as z,j as Dt,D as mt,a6 as Ot,d as ot,K as At,aa as It,F as tt,i as et,aj as Ct,ak as Rt,al as xt}from"./mermaid.core-VsNG6kTl.js";import{c as pt}from"./cytoscape.esm-DjcA8a8N.js";import"./app-Dp4t6tDQ.js";var dt={exports:{}},it={exports:{}},nt={exports:{}},ut;function Mt(){return ut||(ut=1,function(I,w){(function(m,y){I.exports=y()})(at,function(){return function(f){var m={};function y(r){if(m[r])return m[r].exports;var t=m[r]={i:r,l:!1,exports:{}};return f[r].call(t.exports,t,t.exports,y),t.l=!0,t.exports}return y.m=f,y.c=m,y.i=function(r){return r},y.d=function(r,t,e){y.o(r,t)||Object.defineProperty(r,t,{configurable:!1,enumerable:!0,get:e})},y.n=function(r){var t=r&&r.__esModule?function(){return r.default}:function(){return r};return y.d(t,"a",t),t},y.o=function(r,t){return Object.prototype.hasOwnProperty.call(r,t)},y.p="",y(y.s=26)}([function(f,m,y){function r(){}r.QUALITY=1,r.DEFAULT_CREATE_BENDS_AS_NEEDED=!1,r.DEFAULT_INCREMENTAL=!1,r.DEFAULT_ANIMATION_ON_LAYOUT=!0,r.DEFAULT_ANIMATION_DURING_LAYOUT=!1,r.DEFAULT_ANIMATION_PERIOD=50,r.DEFAULT_UNIFORM_LEAF_NODE_SIZES=!1,r.DEFAULT_GRAPH_MARGIN=15,r.NODE_DIMENSIONS_INCLUDE_LABELS=!1,r.SIMPLE_NODE_SIZE=40,r.SIMPLE_NODE_HALF_SIZE=r.SIMPLE_NODE_SIZE/2,r.EMPTY_COMPOUND_NODE_SIZE=40,r.MIN_EDGE_LENGTH=1,r.WORLD_BOUNDARY=1e6,r.INITIAL_WORLD_BOUNDARY=r.WORLD_BOUNDARY/1e3,r.WORLD_CENTER_X=1200,r.WORLD_CENTER_Y=900,f.exports=r},function(f,m,y){var r=y(2),t=y(8),e=y(9);function i(g,a,v){r.call(this,v),this.isOverlapingSourceAndTarget=!1,this.vGraphObject=v,this.bendpoints=[],this.source=g,this.target=a}i.prototype=Object.create(r.prototype);for(var o in r)i[o]=r[o];i.prototype.getSource=function(){return this.source},i.prototype.getTarget=function(){return this.target},i.prototype.isInterGraph=function(){return this.isInterGraph},i.prototype.getLength=function(){return this.length},i.prototype.isOverlapingSourceAndTarget=function(){return this.isOverlapingSourceAndTarget},i.prototype.getBendpoints=function(){return this.bendpoints},i.prototype.getLca=function(){return this.lca},i.prototype.getSourceInLca=function(){return this.sourceInLca},i.prototype.getTargetInLca=function(){return this.targetInLca},i.prototype.getOtherEnd=function(g){if(this.source===g)return this.target;if(this.target===g)return this.source;throw"Node is not incident with this edge"},i.prototype.getOtherEndInGraph=function(g,a){for(var v=this.getOtherEnd(g),n=a.getGraphManager().getRoot();;){if(v.getOwner()==a)return v;if(v.getOwner()==n)break;v=v.getOwner().getParent()}return null},i.prototype.updateLength=function(){var g=new Array(4);this.isOverlapingSourceAndTarget=t.getIntersection(this.target.getRect(),this.source.getRect(),g),this.isOverlapingSourceAndTarget||(this.lengthX=g[0]-g[2],this.lengthY=g[1]-g[3],Math.abs(this.lengthX)<1&&(this.lengthX=e.sign(this.lengthX)),Math.abs(this.lengthY)<1&&(this.lengthY=e.sign(this.lengthY)),this.length=Math.sqrt(this.lengthX*this.lengthX+this.lengthY*this.lengthY))},i.prototype.updateLengthSimple=function(){this.lengthX=this.target.getCenterX()-this.source.getCenterX(),this.lengthY=this.target.getCenterY()-this.source.getCenterY(),Math.abs(this.lengthX)<1&&(this.lengthX=e.sign(this.lengthX)),Math.abs(this.lengthY)<1&&(this.lengthY=e.sign(this.lengthY)),this.length=Math.sqrt(this.lengthX*this.lengthX+this.lengthY*this.lengthY)},f.exports=i},function(f,m,y){function r(t){this.vGraphObject=t}f.exports=r},function(f,m,y){var r=y(2),t=y(10),e=y(13),i=y(0),o=y(16),g=y(4);function a(n,c,l,E){l==null&&E==null&&(E=c),r.call(this,E),n.graphManager!=null&&(n=n.graphManager),this.estimatedSize=t.MIN_VALUE,this.inclusionTreeDepth=t.MAX_VALUE,this.vGraphObject=E,this.edges=[],this.graphManager=n,l!=null&&c!=null?this.rect=new e(c.x,c.y,l.width,l.height):this.rect=new e}a.prototype=Object.create(r.prototype);for(var v in r)a[v]=r[v];a.prototype.getEdges=function(){return this.edges},a.prototype.getChild=function(){return this.child},a.prototype.getOwner=function(){return this.owner},a.prototype.getWidth=function(){return this.rect.width},a.prototype.setWidth=function(n){this.rect.width=n},a.prototype.getHeight=function(){return this.rect.height},a.prototype.setHeight=function(n){this.rect.height=n},a.prototype.getCenterX=function(){return this.rect.x+this.rect.width/2},a.prototype.getCenterY=function(){return this.rect.y+this.rect.height/2},a.prototype.getCenter=function(){return new g(this.rect.x+this.rect.width/2,this.rect.y+this.rect.height/2)},a.prototype.getLocation=function(){return new g(this.rect.x,this.rect.y)},a.prototype.getRect=function(){return this.rect},a.prototype.getDiagonal=function(){return Math.sqrt(this.rect.width*this.rect.width+this.rect.height*this.rect.height)},a.prototype.getHalfTheDiagonal=function(){return Math.sqrt(this.rect.height*this.rect.height+this.rect.width*this.rect.width)/2},a.prototype.setRect=function(n,c){this.rect.x=n.x,this.rect.y=n.y,this.rect.width=c.width,this.rect.height=c.height},a.prototype.setCenter=function(n,c){this.rect.x=n-this.rect.width/2,this.rect.y=c-this.rect.height/2},a.prototype.setLocation=function(n,c){this.rect.x=n,this.rect.y=c},a.prototype.moveBy=function(n,c){this.rect.x+=n,this.rect.y+=c},a.prototype.getEdgeListToNode=function(n){var c=[],l=this;return l.edges.forEach(function(E){if(E.target==n){if(E.source!=l)throw"Incorrect edge source!";c.push(E)}}),c},a.prototype.getEdgesBetween=function(n){var c=[],l=this;return l.edges.forEach(function(E){if(!(E.source==l||E.target==l))throw"Incorrect edge source and/or target";(E.target==n||E.source==n)&&c.push(E)}),c},a.prototype.getNeighborsList=function(){var n=new Set,c=this;return c.edges.forEach(function(l){if(l.source==c)n.add(l.target);else{if(l.target!=c)throw"Incorrect incidency!";n.add(l.source)}}),n},a.prototype.withChildren=function(){var n=new Set,c,l;if(n.add(this),this.child!=null)for(var E=this.child.getNodes(),T=0;Tc&&(this.rect.x-=(this.labelWidth-c)/2,this.setWidth(this.labelWidth)),this.labelHeight>l&&(this.labelPos=="center"?this.rect.y-=(this.labelHeight-l)/2:this.labelPos=="top"&&(this.rect.y-=this.labelHeight-l),this.setHeight(this.labelHeight))}}},a.prototype.getInclusionTreeDepth=function(){if(this.inclusionTreeDepth==t.MAX_VALUE)throw"assert failed";return this.inclusionTreeDepth},a.prototype.transform=function(n){var c=this.rect.x;c>i.WORLD_BOUNDARY?c=i.WORLD_BOUNDARY:c<-i.WORLD_BOUNDARY&&(c=-i.WORLD_BOUNDARY);var l=this.rect.y;l>i.WORLD_BOUNDARY?l=i.WORLD_BOUNDARY:l<-i.WORLD_BOUNDARY&&(l=-i.WORLD_BOUNDARY);var E=new g(c,l),T=n.inverseTransformPoint(E);this.setLocation(T.x,T.y)},a.prototype.getLeft=function(){return this.rect.x},a.prototype.getRight=function(){return this.rect.x+this.rect.width},a.prototype.getTop=function(){return this.rect.y},a.prototype.getBottom=function(){return this.rect.y+this.rect.height},a.prototype.getParent=function(){return this.owner==null?null:this.owner.getParent()},f.exports=a},function(f,m,y){function r(t,e){t==null&&e==null?(this.x=0,this.y=0):(this.x=t,this.y=e)}r.prototype.getX=function(){return this.x},r.prototype.getY=function(){return this.y},r.prototype.setX=function(t){this.x=t},r.prototype.setY=function(t){this.y=t},r.prototype.getDifference=function(t){return new DimensionD(this.x-t.x,this.y-t.y)},r.prototype.getCopy=function(){return new r(this.x,this.y)},r.prototype.translate=function(t){return this.x+=t.width,this.y+=t.height,this},f.exports=r},function(f,m,y){var r=y(2),t=y(10),e=y(0),i=y(6),o=y(3),g=y(1),a=y(13),v=y(12),n=y(11);function c(E,T,D){r.call(this,D),this.estimatedSize=t.MIN_VALUE,this.margin=e.DEFAULT_GRAPH_MARGIN,this.edges=[],this.nodes=[],this.isConnected=!1,this.parent=E,T!=null&&T instanceof i?this.graphManager=T:T!=null&&T instanceof Layout&&(this.graphManager=T.graphManager)}c.prototype=Object.create(r.prototype);for(var l in r)c[l]=r[l];c.prototype.getNodes=function(){return this.nodes},c.prototype.getEdges=function(){return this.edges},c.prototype.getGraphManager=function(){return this.graphManager},c.prototype.getParent=function(){return this.parent},c.prototype.getLeft=function(){return this.left},c.prototype.getRight=function(){return this.right},c.prototype.getTop=function(){return this.top},c.prototype.getBottom=function(){return this.bottom},c.prototype.isConnected=function(){return this.isConnected},c.prototype.add=function(E,T,D){if(T==null&&D==null){var L=E;if(this.graphManager==null)throw"Graph has no graph mgr!";if(this.getNodes().indexOf(L)>-1)throw"Node already in graph!";return L.owner=this,this.getNodes().push(L),L}else{var O=E;if(!(this.getNodes().indexOf(T)>-1&&this.getNodes().indexOf(D)>-1))throw"Source or target not in graph!";if(!(T.owner==D.owner&&T.owner==this))throw"Both owners must be this graph!";return T.owner!=D.owner?null:(O.source=T,O.target=D,O.isInterGraph=!1,this.getEdges().push(O),T.edges.push(O),D!=T&&D.edges.push(O),O)}},c.prototype.remove=function(E){var T=E;if(E instanceof o){if(T==null)throw"Node is null!";if(!(T.owner!=null&&T.owner==this))throw"Owner graph is invalid!";if(this.graphManager==null)throw"Owner graph manager is invalid!";for(var D=T.edges.slice(),L,O=D.length,d=0;d-1&&h>-1))throw"Source and/or target doesn't know this edge!";L.source.edges.splice(s,1),L.target!=L.source&&L.target.edges.splice(h,1);var N=L.source.owner.getEdges().indexOf(L);if(N==-1)throw"Not in owner's edge list!";L.source.owner.getEdges().splice(N,1)}},c.prototype.updateLeftTop=function(){for(var E=t.MAX_VALUE,T=t.MAX_VALUE,D,L,O,d=this.getNodes(),N=d.length,s=0;sD&&(E=D),T>L&&(T=L)}return E==t.MAX_VALUE?null:(d[0].getParent().paddingLeft!=null?O=d[0].getParent().paddingLeft:O=this.margin,this.left=T-O,this.top=E-O,new v(this.left,this.top))},c.prototype.updateBounds=function(E){for(var T=t.MAX_VALUE,D=-t.MAX_VALUE,L=t.MAX_VALUE,O=-t.MAX_VALUE,d,N,s,h,u,p=this.nodes,A=p.length,C=0;Cd&&(T=d),Ds&&(L=s),Od&&(T=d),Ds&&(L=s),O=this.nodes.length){var A=0;D.forEach(function(C){C.owner==E&&A++}),A==this.nodes.length&&(this.isConnected=!0)}},f.exports=c},function(f,m,y){var r,t=y(1);function e(i){r=y(5),this.layout=i,this.graphs=[],this.edges=[]}e.prototype.addRoot=function(){var i=this.layout.newGraph(),o=this.layout.newNode(null),g=this.add(i,o);return this.setRootGraph(g),this.rootGraph},e.prototype.add=function(i,o,g,a,v){if(g==null&&a==null&&v==null){if(i==null)throw"Graph is null!";if(o==null)throw"Parent node is null!";if(this.graphs.indexOf(i)>-1)throw"Graph already in this graph mgr!";if(this.graphs.push(i),i.parent!=null)throw"Already has a parent!";if(o.child!=null)throw"Already has a child!";return i.parent=o,o.child=i,i}else{v=g,a=o,g=i;var n=a.getOwner(),c=v.getOwner();if(!(n!=null&&n.getGraphManager()==this))throw"Source not in this graph mgr!";if(!(c!=null&&c.getGraphManager()==this))throw"Target not in this graph mgr!";if(n==c)return g.isInterGraph=!1,n.add(g,a,v);if(g.isInterGraph=!0,g.source=a,g.target=v,this.edges.indexOf(g)>-1)throw"Edge already in inter-graph edge list!";if(this.edges.push(g),!(g.source!=null&&g.target!=null))throw"Edge source and/or target is null!";if(!(g.source.edges.indexOf(g)==-1&&g.target.edges.indexOf(g)==-1))throw"Edge already in source and/or target incidency list!";return g.source.edges.push(g),g.target.edges.push(g),g}},e.prototype.remove=function(i){if(i instanceof r){var o=i;if(o.getGraphManager()!=this)throw"Graph not in this graph mgr";if(!(o==this.rootGraph||o.parent!=null&&o.parent.graphManager==this))throw"Invalid parent node!";var g=[];g=g.concat(o.getEdges());for(var a,v=g.length,n=0;n=i.getRight()?o[0]+=Math.min(i.getX()-e.getX(),e.getRight()-i.getRight()):i.getX()<=e.getX()&&i.getRight()>=e.getRight()&&(o[0]+=Math.min(e.getX()-i.getX(),i.getRight()-e.getRight())),e.getY()<=i.getY()&&e.getBottom()>=i.getBottom()?o[1]+=Math.min(i.getY()-e.getY(),e.getBottom()-i.getBottom()):i.getY()<=e.getY()&&i.getBottom()>=e.getBottom()&&(o[1]+=Math.min(e.getY()-i.getY(),i.getBottom()-e.getBottom()));var v=Math.abs((i.getCenterY()-e.getCenterY())/(i.getCenterX()-e.getCenterX()));i.getCenterY()===e.getCenterY()&&i.getCenterX()===e.getCenterX()&&(v=1);var n=v*o[0],c=o[1]/v;o[0]n)return o[0]=g,o[1]=l,o[2]=v,o[3]=p,!1;if(av)return o[0]=c,o[1]=a,o[2]=h,o[3]=n,!1;if(gv?(o[0]=T,o[1]=D,x=!0):(o[0]=E,o[1]=l,x=!0):U===M&&(g>v?(o[0]=c,o[1]=l,x=!0):(o[0]=L,o[1]=D,x=!0)),-X===M?v>g?(o[2]=u,o[3]=p,_=!0):(o[2]=h,o[3]=s,_=!0):X===M&&(v>g?(o[2]=N,o[3]=s,_=!0):(o[2]=A,o[3]=p,_=!0)),x&&_)return!1;if(g>v?a>n?(G=this.getCardinalDirection(U,M,4),F=this.getCardinalDirection(X,M,2)):(G=this.getCardinalDirection(-U,M,3),F=this.getCardinalDirection(-X,M,1)):a>n?(G=this.getCardinalDirection(-U,M,1),F=this.getCardinalDirection(-X,M,3)):(G=this.getCardinalDirection(U,M,2),F=this.getCardinalDirection(X,M,4)),!x)switch(G){case 1:Y=l,b=g+-d/M,o[0]=b,o[1]=Y;break;case 2:b=L,Y=a+O*M,o[0]=b,o[1]=Y;break;case 3:Y=D,b=g+d/M,o[0]=b,o[1]=Y;break;case 4:b=T,Y=a+-O*M,o[0]=b,o[1]=Y;break}if(!_)switch(F){case 1:H=s,k=v+-R/M,o[2]=k,o[3]=H;break;case 2:k=A,H=n+C*M,o[2]=k,o[3]=H;break;case 3:H=p,k=v+R/M,o[2]=k,o[3]=H;break;case 4:k=u,H=n+-C*M,o[2]=k,o[3]=H;break}}return!1},t.getCardinalDirection=function(e,i,o){return e>i?o:1+o%4},t.getIntersection=function(e,i,o,g){if(g==null)return this.getIntersection2(e,i,o);var a=e.x,v=e.y,n=i.x,c=i.y,l=o.x,E=o.y,T=g.x,D=g.y,L=void 0,O=void 0,d=void 0,N=void 0,s=void 0,h=void 0,u=void 0,p=void 0,A=void 0;return d=c-v,s=a-n,u=n*v-a*c,N=D-E,h=l-T,p=T*E-l*D,A=d*h-N*s,A===0?null:(L=(s*p-h*u)/A,O=(N*u-d*p)/A,new r(L,O))},t.angleOfVector=function(e,i,o,g){var a=void 0;return e!==o?(a=Math.atan((g-i)/(o-e)),o0?1:t<0?-1:0},r.floor=function(t){return t<0?Math.ceil(t):Math.floor(t)},r.ceil=function(t){return t<0?Math.floor(t):Math.ceil(t)},f.exports=r},function(f,m,y){function r(){}r.MAX_VALUE=2147483647,r.MIN_VALUE=-2147483648,f.exports=r},function(f,m,y){var r=function(){function a(v,n){for(var c=0;c"u"?"undefined":r(e);return e==null||i!="object"&&i!="function"},f.exports=t},function(f,m,y){function r(l){if(Array.isArray(l)){for(var E=0,T=Array(l.length);E0&&E;){for(d.push(s[0]);d.length>0&&E;){var h=d[0];d.splice(0,1),O.add(h);for(var u=h.getEdges(),L=0;L-1&&s.splice(R,1)}O=new Set,N=new Map}}return l},c.prototype.createDummyNodesForBendpoints=function(l){for(var E=[],T=l.source,D=this.graphManager.calcLowestCommonAncestor(l.source,l.target),L=0;L0){for(var D=this.edgeToDummyNodes.get(T),L=0;L=0&&E.splice(p,1);var A=N.getNeighborsList();A.forEach(function(x){if(T.indexOf(x)<0){var _=D.get(x),U=_-1;U==1&&h.push(x),D.set(x,U)}})}T=T.concat(h),(E.length==1||E.length==2)&&(L=!0,O=E[0])}return O},c.prototype.setGraphManager=function(l){this.graphManager=l},f.exports=c},function(f,m,y){function r(){}r.seed=1,r.x=0,r.nextDouble=function(){return r.x=Math.sin(r.seed++)*1e4,r.x-Math.floor(r.x)},f.exports=r},function(f,m,y){var r=y(4);function t(e,i){this.lworldOrgX=0,this.lworldOrgY=0,this.ldeviceOrgX=0,this.ldeviceOrgY=0,this.lworldExtX=1,this.lworldExtY=1,this.ldeviceExtX=1,this.ldeviceExtY=1}t.prototype.getWorldOrgX=function(){return this.lworldOrgX},t.prototype.setWorldOrgX=function(e){this.lworldOrgX=e},t.prototype.getWorldOrgY=function(){return this.lworldOrgY},t.prototype.setWorldOrgY=function(e){this.lworldOrgY=e},t.prototype.getWorldExtX=function(){return this.lworldExtX},t.prototype.setWorldExtX=function(e){this.lworldExtX=e},t.prototype.getWorldExtY=function(){return this.lworldExtY},t.prototype.setWorldExtY=function(e){this.lworldExtY=e},t.prototype.getDeviceOrgX=function(){return this.ldeviceOrgX},t.prototype.setDeviceOrgX=function(e){this.ldeviceOrgX=e},t.prototype.getDeviceOrgY=function(){return this.ldeviceOrgY},t.prototype.setDeviceOrgY=function(e){this.ldeviceOrgY=e},t.prototype.getDeviceExtX=function(){return this.ldeviceExtX},t.prototype.setDeviceExtX=function(e){this.ldeviceExtX=e},t.prototype.getDeviceExtY=function(){return this.ldeviceExtY},t.prototype.setDeviceExtY=function(e){this.ldeviceExtY=e},t.prototype.transformX=function(e){var i=0,o=this.lworldExtX;return o!=0&&(i=this.ldeviceOrgX+(e-this.lworldOrgX)*this.ldeviceExtX/o),i},t.prototype.transformY=function(e){var i=0,o=this.lworldExtY;return o!=0&&(i=this.ldeviceOrgY+(e-this.lworldOrgY)*this.ldeviceExtY/o),i},t.prototype.inverseTransformX=function(e){var i=0,o=this.ldeviceExtX;return o!=0&&(i=this.lworldOrgX+(e-this.ldeviceOrgX)*this.lworldExtX/o),i},t.prototype.inverseTransformY=function(e){var i=0,o=this.ldeviceExtY;return o!=0&&(i=this.lworldOrgY+(e-this.ldeviceOrgY)*this.lworldExtY/o),i},t.prototype.inverseTransformPoint=function(e){var i=new r(this.inverseTransformX(e.x),this.inverseTransformY(e.y));return i},f.exports=t},function(f,m,y){function r(n){if(Array.isArray(n)){for(var c=0,l=Array(n.length);ce.ADAPTATION_LOWER_NODE_LIMIT&&(this.coolingFactor=Math.max(this.coolingFactor*e.COOLING_ADAPTATION_FACTOR,this.coolingFactor-(n-e.ADAPTATION_LOWER_NODE_LIMIT)/(e.ADAPTATION_UPPER_NODE_LIMIT-e.ADAPTATION_LOWER_NODE_LIMIT)*this.coolingFactor*(1-e.COOLING_ADAPTATION_FACTOR))),this.maxNodeDisplacement=e.MAX_NODE_DISPLACEMENT_INCREMENTAL):(n>e.ADAPTATION_LOWER_NODE_LIMIT?this.coolingFactor=Math.max(e.COOLING_ADAPTATION_FACTOR,1-(n-e.ADAPTATION_LOWER_NODE_LIMIT)/(e.ADAPTATION_UPPER_NODE_LIMIT-e.ADAPTATION_LOWER_NODE_LIMIT)*(1-e.COOLING_ADAPTATION_FACTOR)):this.coolingFactor=1,this.initialCoolingFactor=this.coolingFactor,this.maxNodeDisplacement=e.MAX_NODE_DISPLACEMENT),this.maxIterations=Math.max(this.getAllNodes().length*5,this.maxIterations),this.totalDisplacementThreshold=this.displacementThresholdPerNode*this.getAllNodes().length,this.repulsionRange=this.calcRepulsionRange()},a.prototype.calcSpringForces=function(){for(var n=this.getAllEdges(),c,l=0;l0&&arguments[0]!==void 0?arguments[0]:!0,c=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!1,l,E,T,D,L=this.getAllNodes(),O;if(this.useFRGridVariant)for(this.totalIterations%e.GRID_CALCULATION_CHECK_PERIOD==1&&n&&this.updateGrid(),O=new Set,l=0;ld||O>d)&&(n.gravitationForceX=-this.gravityConstant*T,n.gravitationForceY=-this.gravityConstant*D)):(d=c.getEstimatedSize()*this.compoundGravityRangeFactor,(L>d||O>d)&&(n.gravitationForceX=-this.gravityConstant*T*this.compoundGravityConstant,n.gravitationForceY=-this.gravityConstant*D*this.compoundGravityConstant))},a.prototype.isConverged=function(){var n,c=!1;return this.totalIterations>this.maxIterations/3&&(c=Math.abs(this.totalDisplacement-this.oldTotalDisplacement)<2),n=this.totalDisplacement=L.length||d>=L[0].length)){for(var N=0;Na}}]),o}();f.exports=i},function(f,m,y){var r=function(){function i(o,g){for(var a=0;a2&&arguments[2]!==void 0?arguments[2]:1,v=arguments.length>3&&arguments[3]!==void 0?arguments[3]:-1,n=arguments.length>4&&arguments[4]!==void 0?arguments[4]:-1;t(this,i),this.sequence1=o,this.sequence2=g,this.match_score=a,this.mismatch_penalty=v,this.gap_penalty=n,this.iMax=o.length+1,this.jMax=g.length+1,this.grid=new Array(this.iMax);for(var c=0;c=0;o--){var g=this.listeners[o];g.event===e&&g.callback===i&&this.listeners.splice(o,1)}},t.emit=function(e,i){for(var o=0;og.coolingFactor*g.maxNodeDisplacement&&(this.displacementX=g.coolingFactor*g.maxNodeDisplacement*e.sign(this.displacementX)),Math.abs(this.displacementY)>g.coolingFactor*g.maxNodeDisplacement&&(this.displacementY=g.coolingFactor*g.maxNodeDisplacement*e.sign(this.displacementY)),this.child==null?this.moveBy(this.displacementX,this.displacementY):this.child.getNodes().length==0?this.moveBy(this.displacementX,this.displacementY):this.propogateDisplacementToChildren(this.displacementX,this.displacementY),g.totalDisplacement+=Math.abs(this.displacementX)+Math.abs(this.displacementY),this.springForceX=0,this.springForceY=0,this.repulsionForceX=0,this.repulsionForceY=0,this.gravitationForceX=0,this.gravitationForceY=0,this.displacementX=0,this.displacementY=0},i.prototype.propogateDisplacementToChildren=function(g,a){for(var v=this.getChild().getNodes(),n,c=0;c0)this.positionNodesRadially(s);else{this.reduceTrees(),this.graphManager.resetAllNodesToApplyGravitation();var h=new Set(this.getAllNodes()),u=this.nodesWithGravity.filter(function(p){return h.has(p)});this.graphManager.setAllNodesToApplyGravitation(u),this.positionNodesRandomly()}}return this.initSpringEmbedder(),this.runSpringEmbedder(),!0},d.prototype.tick=function(){if(this.totalIterations++,this.totalIterations===this.maxIterations&&!this.isTreeGrowing&&!this.isGrowthFinished)if(this.prunedNodesAll.length>0)this.isTreeGrowing=!0;else return!0;if(this.totalIterations%v.CONVERGENCE_CHECK_PERIOD==0&&!this.isTreeGrowing&&!this.isGrowthFinished){if(this.isConverged())if(this.prunedNodesAll.length>0)this.isTreeGrowing=!0;else return!0;this.coolingCycle++,this.layoutQuality==0?this.coolingAdjuster=this.coolingCycle:this.layoutQuality==1&&(this.coolingAdjuster=this.coolingCycle/3),this.coolingFactor=Math.max(this.initialCoolingFactor-Math.pow(this.coolingCycle,Math.log(100*(this.initialCoolingFactor-this.finalTemperature))/Math.log(this.maxCoolingCycle))/100*this.coolingAdjuster,this.finalTemperature),this.animationPeriod=Math.ceil(this.initialAnimationPeriod*Math.sqrt(this.coolingFactor))}if(this.isTreeGrowing){if(this.growTreeIterations%10==0)if(this.prunedNodesAll.length>0){this.graphManager.updateBounds(),this.updateGrid(),this.growTree(this.prunedNodesAll),this.graphManager.resetAllNodesToApplyGravitation();var s=new Set(this.getAllNodes()),h=this.nodesWithGravity.filter(function(A){return s.has(A)});this.graphManager.setAllNodesToApplyGravitation(h),this.graphManager.updateBounds(),this.updateGrid(),this.coolingFactor=v.DEFAULT_COOLING_FACTOR_INCREMENTAL}else this.isTreeGrowing=!1,this.isGrowthFinished=!0;this.growTreeIterations++}if(this.isGrowthFinished){if(this.isConverged())return!0;this.afterGrowthIterations%10==0&&(this.graphManager.updateBounds(),this.updateGrid()),this.coolingFactor=v.DEFAULT_COOLING_FACTOR_INCREMENTAL*((100-this.afterGrowthIterations)/100),this.afterGrowthIterations++}var u=!this.isTreeGrowing&&!this.isGrowthFinished,p=this.growTreeIterations%10==1&&this.isTreeGrowing||this.afterGrowthIterations%10==1&&this.isGrowthFinished;return this.totalDisplacement=0,this.graphManager.updateBounds(),this.calcSpringForces(),this.calcRepulsionForces(u,p),this.calcGravitationalForces(),this.moveNodes(),this.animate(),!1},d.prototype.getPositionsData=function(){for(var s=this.graphManager.getAllNodes(),h={},u=0;u1){var x;for(x=0;xp&&(p=Math.floor(R.y)),C=Math.floor(R.x+a.DEFAULT_COMPONENT_SEPERATION)}this.transform(new l(n.WORLD_CENTER_X-R.x/2,n.WORLD_CENTER_Y-R.y/2))},d.radialLayout=function(s,h,u){var p=Math.max(this.maxDiagonalInTree(s),a.DEFAULT_RADIAL_SEPARATION);d.branchRadialLayout(h,null,0,359,0,p);var A=L.calculateBounds(s),C=new O;C.setDeviceOrgX(A.getMinX()),C.setDeviceOrgY(A.getMinY()),C.setWorldOrgX(u.x),C.setWorldOrgY(u.y);for(var R=0;R1;){var H=k[0];k.splice(0,1);var P=M.indexOf(H);P>=0&&M.splice(P,1),b--,G--}h!=null?Y=(M.indexOf(k[0])+1)%b:Y=0;for(var B=Math.abs(p-u)/G,$=Y;F!=G;$=++$%b){var K=M[$].getOtherEnd(s);if(K!=h){var Q=(u+F*B)%360,J=(Q+B)%360;d.branchRadialLayout(K,s,Q,J,A+C,C),F++}}},d.maxDiagonalInTree=function(s){for(var h=T.MIN_VALUE,u=0;uh&&(h=A)}return h},d.prototype.calcRepulsionRange=function(){return 2*(this.level+1)*this.idealEdgeLength},d.prototype.groupZeroDegreeMembers=function(){var s=this,h={};this.memberGroups={},this.idToDummyNode={};for(var u=[],p=this.graphManager.getAllNodes(),A=0;A"u"&&(h[x]=[]),h[x]=h[x].concat(C)}Object.keys(h).forEach(function(_){if(h[_].length>1){var U="DummyCompound_"+_;s.memberGroups[U]=h[_];var X=h[_][0].getParent(),M=new o(s.graphManager);M.id=U,M.paddingLeft=X.paddingLeft||0,M.paddingRight=X.paddingRight||0,M.paddingBottom=X.paddingBottom||0,M.paddingTop=X.paddingTop||0,s.idToDummyNode[U]=M;var G=s.getGraphManager().add(s.newGraph(),M),F=X.getChild();F.add(M);for(var b=0;b=0;s--){var h=this.compoundOrder[s],u=h.id,p=h.paddingLeft,A=h.paddingTop;this.adjustLocations(this.tiledMemberPack[u],h.rect.x,h.rect.y,p,A)}},d.prototype.repopulateZeroDegreeMembers=function(){var s=this,h=this.tiledZeroDegreePack;Object.keys(h).forEach(function(u){var p=s.idToDummyNode[u],A=p.paddingLeft,C=p.paddingTop;s.adjustLocations(h[u],p.rect.x,p.rect.y,A,C)})},d.prototype.getToBeTiled=function(s){var h=s.id;if(this.toBeTiled[h]!=null)return this.toBeTiled[h];var u=s.getChild();if(u==null)return this.toBeTiled[h]=!1,!1;for(var p=u.getNodes(),A=0;A0)return this.toBeTiled[h]=!1,!1;if(C.getChild()==null){this.toBeTiled[C.id]=!1;continue}if(!this.getToBeTiled(C))return this.toBeTiled[h]=!1,!1}return this.toBeTiled[h]=!0,!0},d.prototype.getNodeDegree=function(s){s.id;for(var h=s.getEdges(),u=0,p=0;p_&&(_=X.rect.height)}u+=_+s.verticalPadding}},d.prototype.tileCompoundMembers=function(s,h){var u=this;this.tiledMemberPack=[],Object.keys(s).forEach(function(p){var A=h[p];u.tiledMemberPack[p]=u.tileNodes(s[p],A.paddingLeft+A.paddingRight),A.rect.width=u.tiledMemberPack[p].width,A.rect.height=u.tiledMemberPack[p].height})},d.prototype.tileNodes=function(s,h){var u=a.TILING_PADDING_VERTICAL,p=a.TILING_PADDING_HORIZONTAL,A={rows:[],rowWidth:[],rowHeight:[],width:0,height:h,verticalPadding:u,horizontalPadding:p};s.sort(function(x,_){return x.rect.width*x.rect.height>_.rect.width*_.rect.height?-1:x.rect.width*x.rect.height<_.rect.width*_.rect.height?1:0});for(var C=0;C0&&(R+=s.horizontalPadding),s.rowWidth[u]=R,s.width0&&(x+=s.verticalPadding);var _=0;x>s.rowHeight[u]&&(_=s.rowHeight[u],s.rowHeight[u]=x,_=s.rowHeight[u]-_),s.height+=_,s.rows[u].push(h)},d.prototype.getShortestRowIndex=function(s){for(var h=-1,u=Number.MAX_VALUE,p=0;pu&&(h=p,u=s.rowWidth[p]);return h},d.prototype.canAddHorizontal=function(s,h,u){var p=this.getShortestRowIndex(s);if(p<0)return!0;var A=s.rowWidth[p];if(A+s.horizontalPadding+h<=s.width)return!0;var C=0;s.rowHeight[p]0&&(C=u+s.verticalPadding-s.rowHeight[p]);var R;s.width-A>=h+s.horizontalPadding?R=(s.height+C)/(A+h+s.horizontalPadding):R=(s.height+C)/s.width,C=u+s.verticalPadding;var x;return s.widthC&&h!=u){p.splice(-1,1),s.rows[u].push(A),s.rowWidth[h]=s.rowWidth[h]-C,s.rowWidth[u]=s.rowWidth[u]+C,s.width=s.rowWidth[instance.getLongestRowIndex(s)];for(var R=Number.MIN_VALUE,x=0;xR&&(R=p[x].height);h>0&&(R+=s.verticalPadding);var _=s.rowHeight[h]+s.rowHeight[u];s.rowHeight[h]=R,s.rowHeight[u]0)for(var F=A;F<=C;F++)G[0]+=this.grid[F][R-1].length+this.grid[F][R].length-1;if(C0)for(var F=R;F<=x;F++)G[3]+=this.grid[A-1][F].length+this.grid[A][F].length-1;for(var b=T.MAX_VALUE,Y,k,H=0;H0){var x;x=O.getGraphManager().add(O.newGraph(),u),this.processChildrenList(x,h,O)}}},l.prototype.stop=function(){return this.stopped=!0,this};var T=function(L){L("layout","cose-bilkent",l)};typeof cytoscape<"u"&&T(cytoscape),m.exports=T}])})})(dt);var St=dt.exports;const Gt=Nt(St);var st=function(){var I=S(function(O,d,N,s){for(N=N||{},s=O.length;s--;N[O[s]]=d);return N},"o"),w=[1,4],f=[1,13],m=[1,12],y=[1,15],r=[1,16],t=[1,20],e=[1,19],i=[6,7,8],o=[1,26],g=[1,24],a=[1,25],v=[6,7,11],n=[1,6,13,15,16,19,22],c=[1,33],l=[1,34],E=[1,6,7,11,13,15,16,19,22],T={trace:S(function(){},"trace"),yy:{},symbols_:{error:2,start:3,mindMap:4,spaceLines:5,SPACELINE:6,NL:7,MINDMAP:8,document:9,stop:10,EOF:11,statement:12,SPACELIST:13,node:14,ICON:15,CLASS:16,nodeWithId:17,nodeWithoutId:18,NODE_DSTART:19,NODE_DESCR:20,NODE_DEND:21,NODE_ID:22,$accept:0,$end:1},terminals_:{2:"error",6:"SPACELINE",7:"NL",8:"MINDMAP",11:"EOF",13:"SPACELIST",15:"ICON",16:"CLASS",19:"NODE_DSTART",20:"NODE_DESCR",21:"NODE_DEND",22:"NODE_ID"},productions_:[0,[3,1],[3,2],[5,1],[5,2],[5,2],[4,2],[4,3],[10,1],[10,1],[10,1],[10,2],[10,2],[9,3],[9,2],[12,2],[12,2],[12,2],[12,1],[12,1],[12,1],[12,1],[12,1],[14,1],[14,1],[18,3],[17,1],[17,4]],performAction:S(function(d,N,s,h,u,p,A){var C=p.length-1;switch(u){case 6:case 7:return h;case 8:h.getLogger().trace("Stop NL ");break;case 9:h.getLogger().trace("Stop EOF ");break;case 11:h.getLogger().trace("Stop NL2 ");break;case 12:h.getLogger().trace("Stop EOF2 ");break;case 15:h.getLogger().info("Node: ",p[C].id),h.addNode(p[C-1].length,p[C].id,p[C].descr,p[C].type);break;case 16:h.getLogger().trace("Icon: ",p[C]),h.decorateNode({icon:p[C]});break;case 17:case 21:h.decorateNode({class:p[C]});break;case 18:h.getLogger().trace("SPACELIST");break;case 19:h.getLogger().trace("Node: ",p[C].id),h.addNode(0,p[C].id,p[C].descr,p[C].type);break;case 20:h.decorateNode({icon:p[C]});break;case 25:h.getLogger().trace("node found ..",p[C-2]),this.$={id:p[C-1],descr:p[C-1],type:h.getType(p[C-2],p[C])};break;case 26:this.$={id:p[C],descr:p[C],type:h.nodeType.DEFAULT};break;case 27:h.getLogger().trace("node found ..",p[C-3]),this.$={id:p[C-3],descr:p[C-1],type:h.getType(p[C-2],p[C])};break}},"anonymous"),table:[{3:1,4:2,5:3,6:[1,5],8:w},{1:[3]},{1:[2,1]},{4:6,6:[1,7],7:[1,8],8:w},{6:f,7:[1,10],9:9,12:11,13:m,14:14,15:y,16:r,17:17,18:18,19:t,22:e},I(i,[2,3]),{1:[2,2]},I(i,[2,4]),I(i,[2,5]),{1:[2,6],6:f,12:21,13:m,14:14,15:y,16:r,17:17,18:18,19:t,22:e},{6:f,9:22,12:11,13:m,14:14,15:y,16:r,17:17,18:18,19:t,22:e},{6:o,7:g,10:23,11:a},I(v,[2,22],{17:17,18:18,14:27,15:[1,28],16:[1,29],19:t,22:e}),I(v,[2,18]),I(v,[2,19]),I(v,[2,20]),I(v,[2,21]),I(v,[2,23]),I(v,[2,24]),I(v,[2,26],{19:[1,30]}),{20:[1,31]},{6:o,7:g,10:32,11:a},{1:[2,7],6:f,12:21,13:m,14:14,15:y,16:r,17:17,18:18,19:t,22:e},I(n,[2,14],{7:c,11:l}),I(E,[2,8]),I(E,[2,9]),I(E,[2,10]),I(v,[2,15]),I(v,[2,16]),I(v,[2,17]),{20:[1,35]},{21:[1,36]},I(n,[2,13],{7:c,11:l}),I(E,[2,11]),I(E,[2,12]),{21:[1,37]},I(v,[2,25]),I(v,[2,27])],defaultActions:{2:[2,1],6:[2,2]},parseError:S(function(d,N){if(N.recoverable)this.trace(d);else{var s=new Error(d);throw s.hash=N,s}},"parseError"),parse:S(function(d){var N=this,s=[0],h=[],u=[null],p=[],A=this.table,C="",R=0,x=0,_=2,U=1,X=p.slice.call(arguments,1),M=Object.create(this.lexer),G={yy:{}};for(var F in this.yy)Object.prototype.hasOwnProperty.call(this.yy,F)&&(G.yy[F]=this.yy[F]);M.setInput(d,G.yy),G.yy.lexer=M,G.yy.parser=this,typeof M.yylloc>"u"&&(M.yylloc={});var b=M.yylloc;p.push(b);var Y=M.options&&M.options.ranges;typeof G.yy.parseError=="function"?this.parseError=G.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function k(V){s.length=s.length-2*V,u.length=u.length-V,p.length=p.length-V}S(k,"popStack");function H(){var V;return V=h.pop()||M.lex()||U,typeof V!="number"&&(V instanceof Array&&(h=V,V=h.pop()),V=N.symbols_[V]||V),V}S(H,"lex");for(var P,B,$,K,Q={},J,j,gt,q;;){if(B=s[s.length-1],this.defaultActions[B]?$=this.defaultActions[B]:((P===null||typeof P>"u")&&(P=H()),$=A[B]&&A[B][P]),typeof $>"u"||!$.length||!$[0]){var rt="";q=[];for(J in A[B])this.terminals_[J]&&J>_&&q.push("'"+this.terminals_[J]+"'");M.showPosition?rt="Parse error on line "+(R+1)+`:
                                       `+M.showPosition()+`
                                       Expecting `+q.join(", ")+", got '"+(this.terminals_[P]||P)+"'":rt="Parse error on line "+(R+1)+": Unexpected "+(P==U?"end of input":"'"+(this.terminals_[P]||P)+"'"),this.parseError(rt,{text:M.match,token:this.terminals_[P]||P,line:M.yylineno,loc:b,expected:q})}if($[0]instanceof Array&&$.length>1)throw new Error("Parse Error: multiple actions possible at state: "+B+", token: "+P);switch($[0]){case 1:s.push(P),u.push(M.yytext),p.push(M.yylloc),s.push($[1]),P=null,x=M.yyleng,C=M.yytext,R=M.yylineno,b=M.yylloc;break;case 2:if(j=this.productions_[$[1]][1],Q.$=u[u.length-j],Q._$={first_line:p[p.length-(j||1)].first_line,last_line:p[p.length-1].last_line,first_column:p[p.length-(j||1)].first_column,last_column:p[p.length-1].last_column},Y&&(Q._$.range=[p[p.length-(j||1)].range[0],p[p.length-1].range[1]]),K=this.performAction.apply(Q,[C,x,R,G.yy,$[1],u,p].concat(X)),typeof K<"u")return K;j&&(s=s.slice(0,-1*j*2),u=u.slice(0,-1*j),p=p.slice(0,-1*j)),s.push(this.productions_[$[1]][0]),u.push(Q.$),p.push(Q._$),gt=A[s[s.length-2]][s[s.length-1]],s.push(gt);break;case 3:return!0}}return!0},"parse")},D=function(){var O={EOF:1,parseError:S(function(N,s){if(this.yy.parser)this.yy.parser.parseError(N,s);else throw new Error(N)},"parseError"),setInput:S(function(d,N){return this.yy=N||this.yy||{},this._input=d,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 d=this._input[0];this.yytext+=d,this.yyleng++,this.offset++,this.match+=d,this.matched+=d;var N=d.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),d},"input"),unput:S(function(d){var N=d.length,s=d.split(/(?:\r\n?|\n)/g);this._input=d+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-N),this.offset-=N;var h=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),s.length-1&&(this.yylineno-=s.length-1);var u=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:s?(s.length===h.length?this.yylloc.first_column:0)+h[h.length-s.length].length-s[0].length:this.yylloc.first_column-N},this.options.ranges&&(this.yylloc.range=[u[0],u[0]+this.yyleng-N]),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(d){this.unput(this.match.slice(d))},"less"),pastInput:S(function(){var d=this.matched.substr(0,this.matched.length-this.match.length);return(d.length>20?"...":"")+d.substr(-20).replace(/\n/g,"")},"pastInput"),upcomingInput:S(function(){var d=this.match;return d.length<20&&(d+=this._input.substr(0,20-d.length)),(d.substr(0,20)+(d.length>20?"...":"")).replace(/\n/g,"")},"upcomingInput"),showPosition:S(function(){var d=this.pastInput(),N=new Array(d.length+1).join("-");return d+this.upcomingInput()+`
                                      diff --git a/assets/mkcp.html-A6Lhrl8v.js b/assets/mkcp.html-BKGtAD67.js
                                      similarity index 99%
                                      rename from assets/mkcp.html-A6Lhrl8v.js
                                      rename to assets/mkcp.html-BKGtAD67.js
                                      index da794f5d3..226c9915c 100644
                                      --- a/assets/mkcp.html-A6Lhrl8v.js
                                      +++ b/assets/mkcp.html-BKGtAD67.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-BClOOpdM.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-Dp4t6tDQ.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-BwaiJk20.js b/assets/mkcp.html-B_VgiCh2.js
                                      similarity index 99%
                                      rename from assets/mkcp.html-BwaiJk20.js
                                      rename to assets/mkcp.html-B_VgiCh2.js
                                      index 17cfd0354..d814d3c01 100644
                                      --- a/assets/mkcp.html-BwaiJk20.js
                                      +++ b/assets/mkcp.html-B_VgiCh2.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-BClOOpdM.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)]),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-Dp4t6tDQ.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)]),m])]),u])}const P=i(o,[["render",f],["__file","mkcp.html.vue"]]);export{P as default}; diff --git a/assets/mkcp.html-CtmErV5x.js b/assets/mkcp.html-Cc1dhAxF.js similarity index 99% rename from assets/mkcp.html-CtmErV5x.js rename to assets/mkcp.html-Cc1dhAxF.js index 412c0d660..15674a325 100644 --- a/assets/mkcp.html-CtmErV5x.js +++ b/assets/mkcp.html-Cc1dhAxF.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-BClOOpdM.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-Dp4t6tDQ.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-CJbrAZRy.js b/assets/mkcp.html-Cq8mAMHo.js
                                      similarity index 98%
                                      rename from assets/mkcp.html-CJbrAZRy.js
                                      rename to assets/mkcp.html-Cq8mAMHo.js
                                      index b8fdc68e6..079d69902 100644
                                      --- a/assets/mkcp.html-CJbrAZRy.js
                                      +++ b/assets/mkcp.html-Cq8mAMHo.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-BClOOpdM.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-Dp4t6tDQ.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-BAnAQ47o.js b/assets/mkcp.html-I65vHqSR.js similarity index 98% rename from assets/mkcp.html-BAnAQ47o.js rename to assets/mkcp.html-I65vHqSR.js index e7decb5d4..eda476480 100644 --- a/assets/mkcp.html-BAnAQ47o.js +++ b/assets/mkcp.html-I65vHqSR.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-BClOOpdM.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-Dp4t6tDQ.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-DRciitZ8.js b/assets/mkcp.html-RYDvu18q.js similarity index 99% rename from assets/mkcp.html-DRciitZ8.js rename to assets/mkcp.html-RYDvu18q.js index 2c63f65f1..ef6b1a688 100644 --- a/assets/mkcp.html-DRciitZ8.js +++ b/assets/mkcp.html-RYDvu18q.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-BClOOpdM.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-Dp4t6tDQ.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/multiple.html-4yXCI2Ca.js b/assets/multiple.html-BSBGs6J2.js
                                      similarity index 99%
                                      rename from assets/multiple.html-4yXCI2Ca.js
                                      rename to assets/multiple.html-BSBGs6J2.js
                                      index 621a30e91..71dcc3fff 100644
                                      --- a/assets/multiple.html-4yXCI2Ca.js
                                      +++ b/assets/multiple.html-BSBGs6J2.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as s,r as a,o,c as t,a as e,e as p}from"./app-BClOOpdM.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-Dp4t6tDQ.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/multiple.html-ZrBBPvoT.js b/assets/multiple.html-BybJ5crB.js
                                      similarity index 99%
                                      rename from assets/multiple.html-ZrBBPvoT.js
                                      rename to assets/multiple.html-BybJ5crB.js
                                      index 904d71c88..f9bfc3e8c 100644
                                      --- a/assets/multiple.html-ZrBBPvoT.js
                                      +++ b/assets/multiple.html-BybJ5crB.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-BClOOpdM.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-Dp4t6tDQ.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-Cbuk3VNw.js b/assets/multiple.html-CAuTO5xa.js
                                      similarity index 99%
                                      rename from assets/multiple.html-Cbuk3VNw.js
                                      rename to assets/multiple.html-CAuTO5xa.js
                                      index f2f82739d..873589cad 100644
                                      --- a/assets/multiple.html-Cbuk3VNw.js
                                      +++ b/assets/multiple.html-CAuTO5xa.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as s,r as a,o,c as t,a as p,e}from"./app-BClOOpdM.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-Dp4t6tDQ.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/muxcool.html-D0kuQV6X.js b/assets/muxcool.html-B1gy8ouX.js
                                      similarity index 99%
                                      rename from assets/muxcool.html-D0kuQV6X.js
                                      rename to assets/muxcool.html-B1gy8ouX.js
                                      index d8c98f126..8738b5c75 100644
                                      --- a/assets/muxcool.html-D0kuQV6X.js
                                      +++ b/assets/muxcool.html-B1gy8ouX.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-BClOOpdM.js";const p={},s=h('

                                      Протокол Mux.Cool

                                      Протокол Mux.Cool - это мультиплексирующий транспортный протокол, используемый для передачи нескольких независимых потоков данных по одному установленному потоку данных.

                                      Версия

                                      Текущая версия - 1 Beta.

                                      Зависимости

                                      Базовый протокол

                                      Mux.Cool должен работать поверх установленного надежного потока данных.

                                      Процесс коммуникации

                                      Одно соединение Mux.Cool может передавать несколько подсоединений, каждое из которых имеет свой собственный идентификатор и состояние. Процесс передачи состоит из кадров (Frame), каждый из которых используется для передачи данных определенного подсоединения.

                                      Поведение клиента

                                      Когда требуется соединение и нет доступного существующего соединения, клиент инициирует новое соединение с сервером, которое далее называется "главным соединением".

                                      1. Одно главное соединение может использоваться для отправки нескольких подсоединений. Клиент может самостоятельно определять количество подсоединений, которое может нести главное соединение.
                                      2. Для нового подсоединения клиент должен отправить состояние New, чтобы уведомить сервер о создании подсоединения, а затем использовать состояние Keep для передачи данных.
                                      3. Когда подсоединение завершается, клиент отправляет состояние End, чтобы уведомить сервер о закрытии подсоединения.
                                      4. Клиент может самостоятельно решать, когда закрыть главное соединение, но должен убедиться, что сервер также поддерживает соединение.
                                      5. Клиент может использовать состояние KeepAlive, чтобы предотвратить закрытие главного соединения сервером.

                                      Поведение сервера

                                      Когда сервер получает новое подсоединение, он должен обрабатывать его как обычное соединение.

                                      1. При получении состояния End сервер может закрыть исходящее соединение с целевым адресом.
                                      2. В ответе сервера для передачи данных подсоединения должен использоваться тот же идентификатор, что и в запросе.
                                      3. Сервер не может использовать состояние New.
                                      4. Сервер может использовать состояние KeepAlive, чтобы предотвратить закрытие главного соединения клиентом.

                                      Формат передачи

                                      Mux.Cool использует симметричный формат передачи, то есть клиент и сервер отправляют и получают данные в одинаковом формате.

                                      Формат кадра

                                      2 байтаL байтX байт
                                      Длина метаданных LМетаданныеДополнительные данные

                                      Метаданные

                                      Существует несколько типов метаданных. Все типы метаданных содержат поля ID и Opt, которые означают следующее:

                                      ',21),c=t("li",null,"Для обычных подсоединений Mux ID начинается с 1 и увеличивается",-1),u={href:"https://github.com/XTLS/Xray-core/blob/main/common/xudp/xudp.go",target:"_blank",rel:"noopener noreferrer"},x=t("li",null,[e("Opt: "),t("ul",null,[t("li",null,"D(0x01): есть дополнительные данные")])],-1),b=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, который сервер использует, чтобы гарантировать, что при переподключении 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 добавляет адрес UDP после Opt(D) в том же формате, что и при создании нового подсоединения, но без 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("Для "),t("a",u,[e("Single XUDP"),d(o)]),e(", реализованного в Xray, ID всегда равен 0")])])]),x]),b])}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-Dp4t6tDQ.js";const p={},s=h('

                                      Протокол Mux.Cool

                                      Протокол Mux.Cool - это мультиплексирующий транспортный протокол, используемый для передачи нескольких независимых потоков данных по одному установленному потоку данных.

                                      Версия

                                      Текущая версия - 1 Beta.

                                      Зависимости

                                      Базовый протокол

                                      Mux.Cool должен работать поверх установленного надежного потока данных.

                                      Процесс коммуникации

                                      Одно соединение Mux.Cool может передавать несколько подсоединений, каждое из которых имеет свой собственный идентификатор и состояние. Процесс передачи состоит из кадров (Frame), каждый из которых используется для передачи данных определенного подсоединения.

                                      Поведение клиента

                                      Когда требуется соединение и нет доступного существующего соединения, клиент инициирует новое соединение с сервером, которое далее называется "главным соединением".

                                      1. Одно главное соединение может использоваться для отправки нескольких подсоединений. Клиент может самостоятельно определять количество подсоединений, которое может нести главное соединение.
                                      2. Для нового подсоединения клиент должен отправить состояние New, чтобы уведомить сервер о создании подсоединения, а затем использовать состояние Keep для передачи данных.
                                      3. Когда подсоединение завершается, клиент отправляет состояние End, чтобы уведомить сервер о закрытии подсоединения.
                                      4. Клиент может самостоятельно решать, когда закрыть главное соединение, но должен убедиться, что сервер также поддерживает соединение.
                                      5. Клиент может использовать состояние KeepAlive, чтобы предотвратить закрытие главного соединения сервером.

                                      Поведение сервера

                                      Когда сервер получает новое подсоединение, он должен обрабатывать его как обычное соединение.

                                      1. При получении состояния End сервер может закрыть исходящее соединение с целевым адресом.
                                      2. В ответе сервера для передачи данных подсоединения должен использоваться тот же идентификатор, что и в запросе.
                                      3. Сервер не может использовать состояние New.
                                      4. Сервер может использовать состояние KeepAlive, чтобы предотвратить закрытие главного соединения клиентом.

                                      Формат передачи

                                      Mux.Cool использует симметричный формат передачи, то есть клиент и сервер отправляют и получают данные в одинаковом формате.

                                      Формат кадра

                                      2 байтаL байтX байт
                                      Длина метаданных LМетаданныеДополнительные данные

                                      Метаданные

                                      Существует несколько типов метаданных. Все типы метаданных содержат поля ID и Opt, которые означают следующее:

                                      ',21),c=t("li",null,"Для обычных подсоединений Mux ID начинается с 1 и увеличивается",-1),u={href:"https://github.com/XTLS/Xray-core/blob/main/common/xudp/xudp.go",target:"_blank",rel:"noopener noreferrer"},x=t("li",null,[e("Opt: "),t("ul",null,[t("li",null,"D(0x01): есть дополнительные данные")])],-1),b=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, который сервер использует, чтобы гарантировать, что при переподключении 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 добавляет адрес UDP после Opt(D) в том же формате, что и при создании нового подсоединения, но без 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("Для "),t("a",u,[e("Single XUDP"),d(o)]),e(", реализованного в Xray, ID всегда равен 0")])])]),x]),b])}const m=n(p,[["render",D],["__file","muxcool.html.vue"]]);export{m as default}; diff --git a/assets/muxcool.html-DPVwc3va.js b/assets/muxcool.html-BrGombeu.js similarity index 98% rename from assets/muxcool.html-DPVwc3va.js rename to assets/muxcool.html-BrGombeu.js index 6f19eefcc..ab8296213 100644 --- a/assets/muxcool.html-DPVwc3va.js +++ b/assets/muxcool.html-BrGombeu.js @@ -1 +1 @@ -import{_ as t,r as a,o as n,c as o,a as i,e as s}from"./app-BClOOpdM.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-Dp4t6tDQ.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/muxcool.html-CGZu6T_9.js b/assets/muxcool.html-CUo0YI7_.js similarity index 99% rename from assets/muxcool.html-CGZu6T_9.js rename to assets/muxcool.html-CUo0YI7_.js index 1e37673b1..7a5327925 100644 --- a/assets/muxcool.html-CGZu6T_9.js +++ b/assets/muxcool.html-CUo0YI7_.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-BClOOpdM.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-Dp4t6tDQ.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/news.html-CYdBxwmd.js b/assets/news.html-B91dhz1J.js similarity index 99% rename from assets/news.html-CYdBxwmd.js rename to assets/news.html-B91dhz1J.js index 5b6f6d03a..f28194cb8 100644 --- a/assets/news.html-CYdBxwmd.js +++ b/assets/news.html-B91dhz1J.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-BClOOpdM.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('
                                    22. 圣诞礼物v1.1.5后的元旦礼物 🎁,游戏玩家大福利,全面 FullCone。
                                    23. (UDP 还会继续增强!)
                                    24. 如果你已经拆过圣诞礼物,这次还有比圣诞礼物更精美的包装和小糖果哦。(同样不用问,更新品尝就对了)
                                    25. (不,下面不是广告,是里程碑。)
                                    26. Xray 是有史以来第一个不受限制的多协议平台:只需 Xray 即可解决问题,无需借力其它实现。
                                      • 一人扛起了所有!支持各大主流协议!
                                      • 一骑绝尘的性能!
                                      • 日趋完善的功能!
                                      • 可怕的生命力与社区亲和力!
                                    27. ',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-Dp4t6tDQ.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('
                                    28. 圣诞礼物v1.1.5后的元旦礼物 🎁,游戏玩家大福利,全面 FullCone。
                                    29. (UDP 还会继续增强!)
                                    30. 如果你已经拆过圣诞礼物,这次还有比圣诞礼物更精美的包装和小糖果哦。(同样不用问,更新品尝就对了)
                                    31. (不,下面不是广告,是里程碑。)
                                    32. Xray 是有史以来第一个不受限制的多协议平台:只需 Xray 即可解决问题,无需借力其它实现。
                                      • 一人扛起了所有!支持各大主流协议!
                                      • 一骑绝尘的性能!
                                      • 日趋完善的功能!
                                      • 可怕的生命力与社区亲和力!
                                    33. ',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-CcRjgoWH.js b/assets/news.html-D6AEFpyV.js similarity index 99% rename from assets/news.html-CcRjgoWH.js rename to assets/news.html-D6AEFpyV.js index a2e2eb966..9ee9df5be 100644 --- a/assets/news.html-CcRjgoWH.js +++ b/assets/news.html-D6AEFpyV.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-BClOOpdM.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('
                                    34. The New Year's gift 🎁 following the Christmas gift v1.1.5, a great benefit for gamers, full FullCone support.
                                    35. (UDP will continue to be enhanced!)
                                    36. 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)
                                    37. (No, what's below is not an ad, but a milestone.)
                                    38. 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!
                                    39. ',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-Dp4t6tDQ.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('
                                    40. The New Year's gift 🎁 following the Christmas gift v1.1.5, a great benefit for gamers, full FullCone support.
                                    41. (UDP will continue to be enhanced!)
                                    42. 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)
                                    43. (No, what's below is not an ad, but a milestone.)
                                    44. 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!
                                    45. ',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-BbFI_I_S.js b/assets/news.html-DCjYRQYz.js similarity index 99% rename from assets/news.html-BbFI_I_S.js rename to assets/news.html-DCjYRQYz.js index cc161f7c6..e4e3cabfc 100644 --- a/assets/news.html-BbFI_I_S.js +++ b/assets/news.html-DCjYRQYz.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-BClOOpdM.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-Dp4t6tDQ.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-Dcb_ekpN.js b/assets/nginx_or_haproxy_tls_tunnel.html-4XVDz6M7.js similarity index 99% rename from assets/nginx_or_haproxy_tls_tunnel.html-Dcb_ekpN.js rename to assets/nginx_or_haproxy_tls_tunnel.html-4XVDz6M7.js index 1e798ba0c..1a5d55e79 100644 --- a/assets/nginx_or_haproxy_tls_tunnel.html-Dcb_ekpN.js +++ b/assets/nginx_or_haproxy_tls_tunnel.html-4XVDz6M7.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-BClOOpdM.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-Dp4t6tDQ.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-DR5-FE6s.js b/assets/nginx_or_haproxy_tls_tunnel.html-BBscUhBq.js
                                      similarity index 99%
                                      rename from assets/nginx_or_haproxy_tls_tunnel.html-DR5-FE6s.js
                                      rename to assets/nginx_or_haproxy_tls_tunnel.html-BBscUhBq.js
                                      index 0a055c89e..f48c365c9 100644
                                      --- a/assets/nginx_or_haproxy_tls_tunnel.html-DR5-FE6s.js
                                      +++ b/assets/nginx_or_haproxy_tls_tunnel.html-BBscUhBq.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-BClOOpdM.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-Dp4t6tDQ.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-Cnf3cJ6J.js b/assets/nginx_or_haproxy_tls_tunnel.html-D0KkG3pU.js
                                      similarity index 99%
                                      rename from assets/nginx_or_haproxy_tls_tunnel.html-Cnf3cJ6J.js
                                      rename to assets/nginx_or_haproxy_tls_tunnel.html-D0KkG3pU.js
                                      index 3a3675179..1ee0cca41 100644
                                      --- a/assets/nginx_or_haproxy_tls_tunnel.html-Cnf3cJ6J.js
                                      +++ b/assets/nginx_or_haproxy_tls_tunnel.html-D0KkG3pU.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-BClOOpdM.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-Dp4t6tDQ.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-Dr5cLNKE.js b/assets/observatory.html-BlplEISQ.js
                                      similarity index 99%
                                      rename from assets/observatory.html-Dr5cLNKE.js
                                      rename to assets/observatory.html-BlplEISQ.js
                                      index 79b5967c7..654a44b0d 100644
                                      --- a/assets/observatory.html-Dr5cLNKE.js
                                      +++ b/assets/observatory.html-BlplEISQ.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as n,r as e,o as s,c as t,a,e as c}from"./app-BClOOpdM.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-Dp4t6tDQ.js";const p={},u=c(`

                                      连接观测

                                      连接观测组件使用 HTTPing 的方式探测出站代理的连接状态。观测结果可以被其他组件使用,如负载均衡器。目前有 observatory (后台连接观测)和 burstObservatory (并发连接观测)两种。按需选择其中之一就行。

                                      ObservatoryObject

                                      {
                                         "subjectSelector":[
                                           "outbound"
                                         ],
                                      diff --git a/assets/observatory.html-DVMvM0rf.js b/assets/observatory.html-Bx2LCBH2.js
                                      similarity index 99%
                                      rename from assets/observatory.html-DVMvM0rf.js
                                      rename to assets/observatory.html-Bx2LCBH2.js
                                      index 6161189e8..e95580425 100644
                                      --- a/assets/observatory.html-DVMvM0rf.js
                                      +++ b/assets/observatory.html-Bx2LCBH2.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as e,r as n,o as s,c as t,a,e as c}from"./app-BClOOpdM.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-Dp4t6tDQ.js";const p={},u=c(`

                                      Мониторинг подключений

                                      Компонент мониторинга подключений использует HTTP-пинги для проверки состояния подключения исходящих прокси. Результаты мониторинга могут использоваться другими компонентами, например, балансировщиком нагрузки.
                                      В настоящее время доступны два режима: observatory (фоновый мониторинг подключений) и burstObservatory (мониторинг параллельных подключений).
                                      Выберите один из них в соответствии с вашими потребностями.

                                      ObservatoryObject

                                      {
                                         "subjectSelector":[
                                           "outbound"
                                         ],
                                      diff --git a/assets/observatory.html-BIHhBKex.js b/assets/observatory.html-CTtdzf4U.js
                                      similarity index 99%
                                      rename from assets/observatory.html-BIHhBKex.js
                                      rename to assets/observatory.html-CTtdzf4U.js
                                      index f9b429979..ff7902bbf 100644
                                      --- a/assets/observatory.html-BIHhBKex.js
                                      +++ b/assets/observatory.html-CTtdzf4U.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as e,r as n,o as t,c as s,a,e as c}from"./app-BClOOpdM.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-Dp4t6tDQ.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/outbound.html-zKdIM7bT.js b/assets/outbound.html-DIhD1gph.js
                                      similarity index 99%
                                      rename from assets/outbound.html-zKdIM7bT.js
                                      rename to assets/outbound.html-DIhD1gph.js
                                      index e6e115ea1..3c305c015 100644
                                      --- a/assets/outbound.html-zKdIM7bT.js
                                      +++ b/assets/outbound.html-DIhD1gph.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-BClOOpdM.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-Dp4t6tDQ.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/outbound.html-BnJWujx3.js b/assets/outbound.html-Iw8X2g5l.js
                                      similarity index 99%
                                      rename from assets/outbound.html-BnJWujx3.js
                                      rename to assets/outbound.html-Iw8X2g5l.js
                                      index 9660e7cf6..5aa3435c2 100644
                                      --- a/assets/outbound.html-BnJWujx3.js
                                      +++ b/assets/outbound.html-Iw8X2g5l.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-BClOOpdM.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-Dp4t6tDQ.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-DzO6kzAh.js b/assets/outbound.html-S2rhwo1W.js
                                      similarity index 99%
                                      rename from assets/outbound.html-DzO6kzAh.js
                                      rename to assets/outbound.html-S2rhwo1W.js
                                      index c4f82a24a..93551f061 100644
                                      --- a/assets/outbound.html-DzO6kzAh.js
                                      +++ b/assets/outbound.html-S2rhwo1W.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-BClOOpdM.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-Dp4t6tDQ.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/pieDiagram-OZX6XH5M-BajVz6ZT.js b/assets/pieDiagram-OZX6XH5M-BSVm6OG3.js
                                      similarity index 92%
                                      rename from assets/pieDiagram-OZX6XH5M-BajVz6ZT.js
                                      rename to assets/pieDiagram-OZX6XH5M-BSVm6OG3.js
                                      index 6e2e4ff61..edcc02b25 100644
                                      --- a/assets/pieDiagram-OZX6XH5M-BajVz6ZT.js
                                      +++ b/assets/pieDiagram-OZX6XH5M-BSVm6OG3.js
                                      @@ -1,4 +1,4 @@
                                      -import{p as U}from"./chunk-OQCM5LHU-CGij_B7M.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-IUatkdtb.js";import{p as it}from"./gitGraph-YCYPL57B-BhMcSVnW.js";import{d as O}from"./arc-BJstDFsX.js";import{o as st}from"./ordinal-Cboi1Yqb.js";import"./app-BClOOpdM.js";import"./baseUniq-j141U2p6.js";import"./basePickBy-Cyiz-f_r.js";import"./clone-DBEsGdWr.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-OQCM5LHU-Cbp36FHa.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-VsNG6kTl.js";import{p as it}from"./gitGraph-YCYPL57B-CW0sFWI7.js";import{d as O}from"./arc-TolVAfGG.js";import{o as st}from"./ordinal-Cboi1Yqb.js";import"./app-Dp4t6tDQ.js";import"./baseUniq-Bpwj4IW2.js";import"./basePickBy-BMIT5f2S.js";import"./clone-CyxiHGLh.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-Ac1N2_ym.js b/assets/policy.html-BRsJy0BP.js
                                      similarity index 98%
                                      rename from assets/policy.html-Ac1N2_ym.js
                                      rename to assets/policy.html-BRsJy0BP.js
                                      index 4300ef4ec..5b254ce15 100644
                                      --- a/assets/policy.html-Ac1N2_ym.js
                                      +++ b/assets/policy.html-BRsJy0BP.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-BClOOpdM.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-Dp4t6tDQ.js";const c={},l=p(`

                                      本地策略

                                      本地策略,可以设置不同的用户等级和对应的策略设置,比如连接超时设置。Xray 处理的每一个连接都对应一个用户,按照用户的等级(level)应用不同的策略。

                                      PolicyObject

                                      PolicyObject 对应配置文件的 policy 项。

                                      {
                                         "policy": {
                                           "levels": {
                                             "0": {
                                      diff --git a/assets/policy.html-DbjgMwZW.js b/assets/policy.html-DYGaWyLN.js
                                      similarity index 99%
                                      rename from assets/policy.html-DbjgMwZW.js
                                      rename to assets/policy.html-DYGaWyLN.js
                                      index b91e73ed5..cb9fa9f0a 100644
                                      --- a/assets/policy.html-DbjgMwZW.js
                                      +++ b/assets/policy.html-DYGaWyLN.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-BClOOpdM.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-Dp4t6tDQ.js";const c={},l=t(`

                                      Локальные политики

                                      Локальные политики позволяют настраивать различные уровни пользователей и соответствующие им политики, например, настройки тайм-аута подключения.
                                      Каждое соединение, обрабатываемое Xray, соответствует определенному пользователю, и к нему применяются политики в соответствии с уровнем пользователя (level).

                                      PolicyObject

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

                                      {
                                         "policy": {
                                           "levels": {
                                             "0": {
                                      diff --git a/assets/policy.html-C4brVis9.js b/assets/policy.html-LeuD8U7Z.js
                                      similarity index 98%
                                      rename from assets/policy.html-C4brVis9.js
                                      rename to assets/policy.html-LeuD8U7Z.js
                                      index 9e1c0f7fc..e51385eb9 100644
                                      --- a/assets/policy.html-C4brVis9.js
                                      +++ b/assets/policy.html-LeuD8U7Z.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-BClOOpdM.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-Dp4t6tDQ.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/quadrantDiagram-VG34DGKC-CqrCarqp.js b/assets/quadrantDiagram-VG34DGKC-GWgA8Rrq.js
                                      similarity index 99%
                                      rename from assets/quadrantDiagram-VG34DGKC-CqrCarqp.js
                                      rename to assets/quadrantDiagram-VG34DGKC-GWgA8Rrq.js
                                      index 598901d48..57f6e60f8 100644
                                      --- a/assets/quadrantDiagram-VG34DGKC-CqrCarqp.js
                                      +++ b/assets/quadrantDiagram-VG34DGKC-GWgA8Rrq.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-IUatkdtb.js";import{l as ee}from"./linear-CAdJTZmH.js";import"./app-BClOOpdM.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-VsNG6kTl.js";import{l as ee}from"./linear-S87t6Dgt.js";import"./app-Dp4t6tDQ.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/raw.html-pQj0GMkg.js b/assets/raw.html-2_ieGPf7.js
                                      similarity index 99%
                                      rename from assets/raw.html-pQj0GMkg.js
                                      rename to assets/raw.html-2_ieGPf7.js
                                      index e9c01fdd5..ebd73d33e 100644
                                      --- a/assets/raw.html-pQj0GMkg.js
                                      +++ b/assets/raw.html-2_ieGPf7.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-BClOOpdM.js";const i={},r=o(`

                                      RAW

                                      更名自曾经的tcp传输(原名称稍有歧义) RAW传输出站发送的原始数据,核心不使用其他协议(如 websocket)承载其流量。

                                      可以和各种协议有多种组合模式.

                                      RawObject

                                      RawObject 对应传输配置的 rawSettings 项。

                                      {
                                      +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-Dp4t6tDQ.js";const i={},r=o(`

                                      RAW

                                      更名自曾经的tcp传输(原名称稍有歧义) RAW传输出站发送的原始数据,核心不使用其他协议(如 websocket)承载其流量。

                                      可以和各种协议有多种组合模式.

                                      RawObject

                                      RawObject 对应传输配置的 rawSettings 项。

                                      {
                                         "acceptProxyProtocol": false,
                                         "header": {
                                           "type": "none"
                                      diff --git a/assets/raw.html-C0l7UYo_.js b/assets/raw.html-D1leTOpm.js
                                      similarity index 99%
                                      rename from assets/raw.html-C0l7UYo_.js
                                      rename to assets/raw.html-D1leTOpm.js
                                      index eae90c35b..eb7d131c2 100644
                                      --- a/assets/raw.html-C0l7UYo_.js
                                      +++ b/assets/raw.html-D1leTOpm.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-BClOOpdM.js";const i={},r=o(`

                                      RAW

                                      Режим транспорта RAW — один из рекомендуемых в настоящее время режимов транспорта.

                                      Может использоваться в различных комбинациях с различными протоколами.

                                      RawObject

                                      RawObject соответствует элементу rawSettings в конфигурации транспорта.

                                      {
                                      +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-Dp4t6tDQ.js";const i={},r=o(`

                                      RAW

                                      Режим транспорта RAW — один из рекомендуемых в настоящее время режимов транспорта.

                                      Может использоваться в различных комбинациях с различными протоколами.

                                      RawObject

                                      RawObject соответствует элементу rawSettings в конфигурации транспорта.

                                      {
                                         "acceptProxyProtocol": false,
                                         "header": {
                                           "type": "none"
                                      diff --git a/assets/raw.html-BZcvQwi4.js b/assets/raw.html-moyWEHbs.js
                                      similarity index 99%
                                      rename from assets/raw.html-BZcvQwi4.js
                                      rename to assets/raw.html-moyWEHbs.js
                                      index e9c01fdd5..ebd73d33e 100644
                                      --- a/assets/raw.html-BZcvQwi4.js
                                      +++ b/assets/raw.html-moyWEHbs.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-BClOOpdM.js";const i={},r=o(`

                                      RAW

                                      更名自曾经的tcp传输(原名称稍有歧义) RAW传输出站发送的原始数据,核心不使用其他协议(如 websocket)承载其流量。

                                      可以和各种协议有多种组合模式.

                                      RawObject

                                      RawObject 对应传输配置的 rawSettings 项。

                                      {
                                      +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-Dp4t6tDQ.js";const i={},r=o(`

                                      RAW

                                      更名自曾经的tcp传输(原名称稍有歧义) RAW传输出站发送的原始数据,核心不使用其他协议(如 websocket)承载其流量。

                                      可以和各种协议有多种组合模式.

                                      RawObject

                                      RawObject 对应传输配置的 rawSettings 项。

                                      {
                                         "acceptProxyProtocol": false,
                                         "header": {
                                           "type": "none"
                                      diff --git a/assets/redirect.html-BP4j1duL.js b/assets/redirect.html-7Cirz0bl.js
                                      similarity index 99%
                                      rename from assets/redirect.html-BP4j1duL.js
                                      rename to assets/redirect.html-7Cirz0bl.js
                                      index 59cb18a87..ff57ad97f 100644
                                      --- a/assets/redirect.html-BP4j1duL.js
                                      +++ b/assets/redirect.html-7Cirz0bl.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-BClOOpdM.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-Dp4t6tDQ.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-DYni_bis.js b/assets/redirect.html-B-G6C8Kz.js
                                      similarity index 99%
                                      rename from assets/redirect.html-DYni_bis.js
                                      rename to assets/redirect.html-B-G6C8Kz.js
                                      index f81f9fddd..7b6dc451b 100644
                                      --- a/assets/redirect.html-DYni_bis.js
                                      +++ b/assets/redirect.html-B-G6C8Kz.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-BClOOpdM.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-Dp4t6tDQ.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/redirect.html-IndA836H.js b/assets/redirect.html-DOiNg0s_.js similarity index 99% rename from assets/redirect.html-IndA836H.js rename to assets/redirect.html-DOiNg0s_.js index 94e14e3e4..b59a704ad 100644 --- a/assets/redirect.html-IndA836H.js +++ b/assets/redirect.html-DOiNg0s_.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-BClOOpdM.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-Dp4t6tDQ.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/requirementDiagram-FPZB6IJI-CtznTREQ.js b/assets/requirementDiagram-FPZB6IJI-74hMwT5u.js
                                      similarity index 99%
                                      rename from assets/requirementDiagram-FPZB6IJI-CtznTREQ.js
                                      rename to assets/requirementDiagram-FPZB6IJI-74hMwT5u.js
                                      index c33f87a4a..3ecc72d18 100644
                                      --- a/assets/requirementDiagram-FPZB6IJI-CtznTREQ.js
                                      +++ b/assets/requirementDiagram-FPZB6IJI-74hMwT5u.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-IUatkdtb.js";import{G as He}from"./graph-CKGFjaQu.js";import{l as We}from"./layout-Bmwgbrwx.js";import"./app-BClOOpdM.js";import"./baseUniq-j141U2p6.js";import"./basePickBy-Cyiz-f_r.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-VsNG6kTl.js";import{G as He}from"./graph-DebN9_Dg.js";import{l as We}from"./layout-BkNI4twY.js";import"./app-Dp4t6tDQ.js";import"./baseUniq-Bpwj4IW2.js";import"./basePickBy-BMIT5f2S.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-CNiVmXjg.js b/assets/reverse.html-DWsup7hU.js
                                      similarity index 99%
                                      rename from assets/reverse.html-CNiVmXjg.js
                                      rename to assets/reverse.html-DWsup7hU.js
                                      index 79be599e6..e08e9904a 100644
                                      --- a/assets/reverse.html-CNiVmXjg.js
                                      +++ b/assets/reverse.html-DWsup7hU.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-BClOOpdM.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-Dp4t6tDQ.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-CaSrdJAD.js b/assets/reverse.html-DgBDzGdK.js
                                      similarity index 99%
                                      rename from assets/reverse.html-CaSrdJAD.js
                                      rename to assets/reverse.html-DgBDzGdK.js
                                      index 4bc2267a8..4b05a3e9c 100644
                                      --- a/assets/reverse.html-CaSrdJAD.js
                                      +++ b/assets/reverse.html-DgBDzGdK.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-BClOOpdM.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-Dp4t6tDQ.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/reverse.html-9kvYp4Kb.js b/assets/reverse.html-OgoGtCv-.js
                                      similarity index 99%
                                      rename from assets/reverse.html-9kvYp4Kb.js
                                      rename to assets/reverse.html-OgoGtCv-.js
                                      index d21e95914..26dc4226d 100644
                                      --- a/assets/reverse.html-9kvYp4Kb.js
                                      +++ b/assets/reverse.html-OgoGtCv-.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-BClOOpdM.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-Dp4t6tDQ.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/routing-lv1-part1.html-BeZz17nL.js b/assets/routing-lv1-part1.html-BFenFNvP.js
                                      similarity index 99%
                                      rename from assets/routing-lv1-part1.html-BeZz17nL.js
                                      rename to assets/routing-lv1-part1.html-BFenFNvP.js
                                      index b64829fe2..5c8ad1382 100644
                                      --- a/assets/routing-lv1-part1.html-BeZz17nL.js
                                      +++ b/assets/routing-lv1-part1.html-BFenFNvP.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-BClOOpdM.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-Dp4t6tDQ.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-Wi4pzvd6.js b/assets/routing-lv1-part1.html-CjfPl-AJ.js
                                      similarity index 99%
                                      rename from assets/routing-lv1-part1.html-Wi4pzvd6.js
                                      rename to assets/routing-lv1-part1.html-CjfPl-AJ.js
                                      index d49e3bd78..4d5c018a8 100644
                                      --- a/assets/routing-lv1-part1.html-Wi4pzvd6.js
                                      +++ b/assets/routing-lv1-part1.html-CjfPl-AJ.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-BClOOpdM.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-Dp4t6tDQ.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-part1.html-XgFNj8rA.js b/assets/routing-lv1-part1.html-DgnRljgC.js
                                      similarity index 99%
                                      rename from assets/routing-lv1-part1.html-XgFNj8rA.js
                                      rename to assets/routing-lv1-part1.html-DgnRljgC.js
                                      index 7bb699e5c..651b1a44b 100644
                                      --- a/assets/routing-lv1-part1.html-XgFNj8rA.js
                                      +++ b/assets/routing-lv1-part1.html-DgnRljgC.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-BClOOpdM.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-Dp4t6tDQ.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-part2.html-C8-_AlZd.js b/assets/routing-lv1-part2.html-AY0RcavA.js
                                      similarity index 99%
                                      rename from assets/routing-lv1-part2.html-C8-_AlZd.js
                                      rename to assets/routing-lv1-part2.html-AY0RcavA.js
                                      index e74e3fb68..70b7851b7 100644
                                      --- a/assets/routing-lv1-part2.html-C8-_AlZd.js
                                      +++ b/assets/routing-lv1-part2.html-AY0RcavA.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-BClOOpdM.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-Dp4t6tDQ.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-ByjqcoL7.js b/assets/routing-lv1-part2.html-BqDKZVNr.js
                                      similarity index 99%
                                      rename from assets/routing-lv1-part2.html-ByjqcoL7.js
                                      rename to assets/routing-lv1-part2.html-BqDKZVNr.js
                                      index 0e12d7751..41f218f45 100644
                                      --- a/assets/routing-lv1-part2.html-ByjqcoL7.js
                                      +++ b/assets/routing-lv1-part2.html-BqDKZVNr.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-BClOOpdM.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("
                                    68. 如果需要匹配某个子域名,如 a-name.yourdomain.com,我们使用 full: "a-name.yourdomain.com"
                                    69. 前面的 问题1问题2,就可以通过给 proxy.yourdomain.com 指定 [proxy-out-vless] 出站,给 direct.yourdomain.com 指定 [direct-out] 出站来解决
                                    70. 如果需要匹配 yourdomain.com 的所有子域名,我们使用 domain: "yourdomain.com" 实现
                                    71. 上述两个可以成为两个独立的路由规则,达到某些子域名直连,其他子域名代理的配置
                                    72. ",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-Dp4t6tDQ.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("
                                    73. 如果需要匹配某个子域名,如 a-name.yourdomain.com,我们使用 full: "a-name.yourdomain.com"
                                    74. 前面的 问题1问题2,就可以通过给 proxy.yourdomain.com 指定 [proxy-out-vless] 出站,给 direct.yourdomain.com 指定 [direct-out] 出站来解决
                                    75. 如果需要匹配 yourdomain.com 的所有子域名,我们使用 domain: "yourdomain.com" 实现
                                    76. 上述两个可以成为两个独立的路由规则,达到某些子域名直连,其他子域名代理的配置
                                    77. ",4),g=s("code",null,"[domain]",-1),y=o(`

                                      上述配置如下:

                                      {
                                         "routing": {
                                           "domainStrategy": "AsIs",
                                           "rules": [
                                      diff --git a/assets/routing-lv1-part2.html-CAznfBeq.js b/assets/routing-lv1-part2.html-DRTLdiGd.js
                                      similarity index 99%
                                      rename from assets/routing-lv1-part2.html-CAznfBeq.js
                                      rename to assets/routing-lv1-part2.html-DRTLdiGd.js
                                      index d67add226..108a86d30 100644
                                      --- a/assets/routing-lv1-part2.html-CAznfBeq.js
                                      +++ b/assets/routing-lv1-part2.html-DRTLdiGd.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-BClOOpdM.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("
                                    78. Для сопоставления поддомена, например a-name.yourdomain.com, мы используем full: "a-name.yourdomain.com".
                                    79. Проблемы 1 и 2, описанные выше, можно решить, указав исходящий трафик [proxy-out-vless] для proxy.yourdomain.com и исходящий трафик [direct-out] для direct.yourdomain.com.
                                    80. Для сопоставления всех поддоменов yourdomain.com мы используем domain: "yourdomain.com".
                                    81. Эти два правила могут быть независимыми, чтобы настроить прямое подключение для одних поддоменов и проксирование для других.
                                    82. ",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-Dp4t6tDQ.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("
                                    83. Для сопоставления поддомена, например a-name.yourdomain.com, мы используем full: "a-name.yourdomain.com".
                                    84. Проблемы 1 и 2, описанные выше, можно решить, указав исходящий трафик [proxy-out-vless] для proxy.yourdomain.com и исходящий трафик [direct-out] для direct.yourdomain.com.
                                    85. Для сопоставления всех поддоменов yourdomain.com мы используем domain: "yourdomain.com".
                                    86. Эти два правила могут быть независимыми, чтобы настроить прямое подключение для одних поддоменов и проксирование для других.
                                    87. ",4),b=s("code",null,"[domain]",-1),y=o(`

                                      Конфигурация выглядит следующим образом:

                                      {
                                         "routing": {
                                           "domainStrategy": "AsIs",
                                           "rules": [
                                      diff --git a/assets/routing.html-C0ZSU5uF.js b/assets/routing.html-Bteon3s5.js
                                      similarity index 99%
                                      rename from assets/routing.html-C0ZSU5uF.js
                                      rename to assets/routing.html-Bteon3s5.js
                                      index 9ac001dac..e46a9f163 100644
                                      --- a/assets/routing.html-C0ZSU5uF.js
                                      +++ b/assets/routing.html-Bteon3s5.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-BClOOpdM.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-Dp4t6tDQ.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-Dr5dN-4f.js b/assets/routing.html-C9IlburL.js
                                      similarity index 99%
                                      rename from assets/routing.html-Dr5dN-4f.js
                                      rename to assets/routing.html-C9IlburL.js
                                      index 372215b34..6151288b9 100644
                                      --- a/assets/routing.html-Dr5dN-4f.js
                                      +++ b/assets/routing.html-C9IlburL.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-BClOOpdM.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-Dp4t6tDQ.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-B5ZjveLm.js b/assets/routing.html-DtA5ezO_.js
                                      similarity index 99%
                                      rename from assets/routing.html-B5ZjveLm.js
                                      rename to assets/routing.html-DtA5ezO_.js
                                      index f9b675bfe..e36857ce1 100644
                                      --- a/assets/routing.html-B5ZjveLm.js
                                      +++ b/assets/routing.html-DtA5ezO_.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-BClOOpdM.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-Dp4t6tDQ.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/sankeyDiagram-KMMQDL5K-i3x2cUcG.js b/assets/sankeyDiagram-KMMQDL5K-D2j-_3G0.js
                                      similarity index 99%
                                      rename from assets/sankeyDiagram-KMMQDL5K-i3x2cUcG.js
                                      rename to assets/sankeyDiagram-KMMQDL5K-D2j-_3G0.js
                                      index c5064d791..640faedec 100644
                                      --- a/assets/sankeyDiagram-KMMQDL5K-i3x2cUcG.js
                                      +++ b/assets/sankeyDiagram-KMMQDL5K-D2j-_3G0.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-IUatkdtb.js";import{o as Mt}from"./ordinal-Cboi1Yqb.js";import"./app-BClOOpdM.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-VsNG6kTl.js";import{o as Mt}from"./ordinal-Cboi1Yqb.js";import"./app-Dp4t6tDQ.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-PQT5PN7B-DljhtIMV.js b/assets/sequenceDiagram-PQT5PN7B-OiVI6n8n.js
                                      similarity index 99%
                                      rename from assets/sequenceDiagram-PQT5PN7B-DljhtIMV.js
                                      rename to assets/sequenceDiagram-PQT5PN7B-OiVI6n8n.js
                                      index f76981545..17d50b8fc 100644
                                      --- a/assets/sequenceDiagram-PQT5PN7B-DljhtIMV.js
                                      +++ b/assets/sequenceDiagram-PQT5PN7B-OiVI6n8n.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-XVOYOM2C-fmD0yIZV.js";import{I as Ce}from"./chunk-2RYQ3QTB-U6oRI5CH.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-IUatkdtb.js";import"./app-BClOOpdM.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-XVOYOM2C-BZTXkaha.js";import{I as Ce}from"./chunk-2RYQ3QTB-8PgX7ysJ.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-VsNG6kTl.js";import"./app-Dp4t6tDQ.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-D70GzRWG.js b/assets/shadowsocks.html-B66sBlmf.js
                                      similarity index 99%
                                      rename from assets/shadowsocks.html-D70GzRWG.js
                                      rename to assets/shadowsocks.html-B66sBlmf.js
                                      index ec1f822bb..11b6b0838 100644
                                      --- a/assets/shadowsocks.html-D70GzRWG.js
                                      +++ b/assets/shadowsocks.html-B66sBlmf.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-BClOOpdM.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-Dp4t6tDQ.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-B6IK2Bt5.js b/assets/shadowsocks.html-BoBE3TUs.js
                                      similarity index 99%
                                      rename from assets/shadowsocks.html-B6IK2Bt5.js
                                      rename to assets/shadowsocks.html-BoBE3TUs.js
                                      index d4bfa6d57..d8a73598c 100644
                                      --- a/assets/shadowsocks.html-B6IK2Bt5.js
                                      +++ b/assets/shadowsocks.html-BoBE3TUs.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-BClOOpdM.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-Dp4t6tDQ.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-D1Blunoy.js b/assets/shadowsocks.html-CeqH0S6O.js
                                      similarity index 99%
                                      rename from assets/shadowsocks.html-D1Blunoy.js
                                      rename to assets/shadowsocks.html-CeqH0S6O.js
                                      index a9289368b..4f8a89b9b 100644
                                      --- a/assets/shadowsocks.html-D1Blunoy.js
                                      +++ b/assets/shadowsocks.html-CeqH0S6O.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-BClOOpdM.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-Dp4t6tDQ.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-DWMjTHBI.js b/assets/shadowsocks.html-CfyZl4UT.js
                                      similarity index 99%
                                      rename from assets/shadowsocks.html-DWMjTHBI.js
                                      rename to assets/shadowsocks.html-CfyZl4UT.js
                                      index 54e1c5609..6860fe574 100644
                                      --- a/assets/shadowsocks.html-DWMjTHBI.js
                                      +++ b/assets/shadowsocks.html-CfyZl4UT.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-BClOOpdM.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-Dp4t6tDQ.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/shadowsocks.html-CnY4fOzh.js b/assets/shadowsocks.html-DKR8aoD9.js
                                      similarity index 99%
                                      rename from assets/shadowsocks.html-CnY4fOzh.js
                                      rename to assets/shadowsocks.html-DKR8aoD9.js
                                      index 52200fc7d..a97a60499 100644
                                      --- a/assets/shadowsocks.html-CnY4fOzh.js
                                      +++ b/assets/shadowsocks.html-DKR8aoD9.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-BClOOpdM.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-Dp4t6tDQ.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-DlgWnNHl.js b/assets/shadowsocks.html-Dp7Rjs0q.js
                                      similarity index 99%
                                      rename from assets/shadowsocks.html-DlgWnNHl.js
                                      rename to assets/shadowsocks.html-Dp7Rjs0q.js
                                      index 6bbcff4ea..8abd7b930 100644
                                      --- a/assets/shadowsocks.html-DlgWnNHl.js
                                      +++ b/assets/shadowsocks.html-Dp7Rjs0q.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-BClOOpdM.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-Dp4t6tDQ.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/socks.html-6GLe0ev0.js b/assets/socks.html--OGyrplG.js
                                      similarity index 98%
                                      rename from assets/socks.html-6GLe0ev0.js
                                      rename to assets/socks.html--OGyrplG.js
                                      index d9d2158e3..3e5b172f8 100644
                                      --- a/assets/socks.html-6GLe0ev0.js
                                      +++ b/assets/socks.html--OGyrplG.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-BClOOpdM.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-Dp4t6tDQ.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-DLLiJu-R.js b/assets/socks.html-0_G5pJuv.js
                                      similarity index 99%
                                      rename from assets/socks.html-DLLiJu-R.js
                                      rename to assets/socks.html-0_G5pJuv.js
                                      index 1d2d634ec..39ee97f06 100644
                                      --- a/assets/socks.html-DLLiJu-R.js
                                      +++ b/assets/socks.html-0_G5pJuv.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-BClOOpdM.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-Dp4t6tDQ.js";const i={},d=u(`

                                      Socks

                                      标准 Socks 协议实现,兼容 Socks 5。

                                      警告

                                      Socks 协议没有对传输加密,不适宜经公网中传输

                                      OutboundConfigurationObject

                                      {
                                         "servers": [
                                           {
                                             "address": "127.0.0.1",
                                      diff --git a/assets/socks.html-DagNy3gy.js b/assets/socks.html-CrKlUUFh.js
                                      similarity index 98%
                                      rename from assets/socks.html-DagNy3gy.js
                                      rename to assets/socks.html-CrKlUUFh.js
                                      index 8c8507753..221a7be48 100644
                                      --- a/assets/socks.html-DagNy3gy.js
                                      +++ b/assets/socks.html-CrKlUUFh.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-BClOOpdM.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-Dp4t6tDQ.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-C0gkY3rI.js b/assets/socks.html-DsSoQ2EE.js
                                      similarity index 99%
                                      rename from assets/socks.html-C0gkY3rI.js
                                      rename to assets/socks.html-DsSoQ2EE.js
                                      index ec8d97b8e..17769a561 100644
                                      --- a/assets/socks.html-C0gkY3rI.js
                                      +++ b/assets/socks.html-DsSoQ2EE.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-BClOOpdM.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-Dp4t6tDQ.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/socks.html-Dq9DrPIe.js b/assets/socks.html-qPyShTyR.js
                                      similarity index 99%
                                      rename from assets/socks.html-Dq9DrPIe.js
                                      rename to assets/socks.html-qPyShTyR.js
                                      index fc43125d9..7b330f130 100644
                                      --- a/assets/socks.html-Dq9DrPIe.js
                                      +++ b/assets/socks.html-qPyShTyR.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-BClOOpdM.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-Dp4t6tDQ.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-BvIE__Bw.js b/assets/socks.html-ynBvKVZW.js
                                      similarity index 99%
                                      rename from assets/socks.html-BvIE__Bw.js
                                      rename to assets/socks.html-ynBvKVZW.js
                                      index 5182bb7ea..e349735b3 100644
                                      --- a/assets/socks.html-BvIE__Bw.js
                                      +++ b/assets/socks.html-ynBvKVZW.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-BClOOpdM.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-Dp4t6tDQ.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/splithttp.html-BOBwhNJh.js b/assets/splithttp.html-BSp-VUbt.js
                                      similarity index 95%
                                      rename from assets/splithttp.html-BOBwhNJh.js
                                      rename to assets/splithttp.html-BSp-VUbt.js
                                      index 53a68063e..a90fa94d4 100644
                                      --- a/assets/splithttp.html-BOBwhNJh.js
                                      +++ b/assets/splithttp.html-BSp-VUbt.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":"XmuxObject","slug":"xmuxobject","link":"#xmuxobject","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":1727089720000,"contributors":[{"name":"mmmray","email":"142015632+mmmray@users.noreply.github.com","commits":19}]},"filePathRelative":"en/config/transports/splithttp.md","i18n":{"pathLocale":"/en/","sourceLink":"/config/transports/splithttp.html","untranslated":false,"updatedTime":1727089720000,"sourceUpdatedTime":1729054786000,"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":"XmuxObject","slug":"xmuxobject","link":"#xmuxobject","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":1727089720000,"contributors":[{"name":"mmmray","email":"142015632+mmmray@users.noreply.github.com","commits":19}]},"filePathRelative":"en/config/transports/splithttp.md","i18n":{"pathLocale":"/en/","sourceLink":"/config/transports/splithttp.html","untranslated":false,"updatedTime":1727089720000,"sourceUpdatedTime":1729083737000,"outdated":true}}');export{t as data};
                                      diff --git a/assets/splithttp.html-BYEq0RDl.js b/assets/splithttp.html-BYFFTbwo.js
                                      similarity index 99%
                                      rename from assets/splithttp.html-BYEq0RDl.js
                                      rename to assets/splithttp.html-BYFFTbwo.js
                                      index 136c1dba9..16e8df61c 100644
                                      --- a/assets/splithttp.html-BYEq0RDl.js
                                      +++ b/assets/splithttp.html-BYFFTbwo.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as i,r as o,o as d,c as u,a as s,b as n,d as e,w as p,e as t}from"./app-BClOOpdM.js";const h={},k=n("h1",{id:"splithttp-h2-quic-h3",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#splithttp-h2-quic-h3"},[n("span",null,"SplitHTTP (H2, QUIC H3)")])],-1),b=t(`

                                      Используется для загрузки с помощью HTTP-фрагментированной передачи, загрузка осуществляется с помощью нескольких HTTP POST-запросов.

                                      Может использоваться через CDN, не поддерживающие WebSocket, но есть несколько требований:

                                      • CDN должен поддерживать HTTP-фрагментированную передачу и потоковые ответы без буферизации. Ядро будет отправлять различную информацию, чтобы сообщить CDN об этом, но CDN должна ее соблюдать. Если промежуточный узел не поддерживает потоковые ответы и зависает, этот транспорт, скорее всего, не будет работать.

                                      Цель та же, что и у V2fly Meek, но благодаря использованию фрагментированной загрузки скорость загрузки выше, а скорость отдачи оптимизирована, но все еще очень ограничена, поэтому к HTTP-прокси предъявляются более высокие требования (см. выше).

                                      SplitHTTP также принимает заголовок X-Forwarded-For.

                                      SplitHttpObject

                                      SplitHttpObject соответствует элементу splithttpSettings в конфигурации транспорта.

                                      {
                                      +import{_ as i,r as o,o as d,c as u,a as s,b as n,d as e,w as p,e as t}from"./app-Dp4t6tDQ.js";const h={},k=n("h1",{id:"splithttp-h2-quic-h3",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#splithttp-h2-quic-h3"},[n("span",null,"SplitHTTP (H2, QUIC H3)")])],-1),b=t(`

                                      Используется для загрузки с помощью HTTP-фрагментированной передачи, загрузка осуществляется с помощью нескольких HTTP POST-запросов.

                                      Может использоваться через CDN, не поддерживающие WebSocket, но есть несколько требований:

                                      • CDN должен поддерживать HTTP-фрагментированную передачу и потоковые ответы без буферизации. Ядро будет отправлять различную информацию, чтобы сообщить CDN об этом, но CDN должна ее соблюдать. Если промежуточный узел не поддерживает потоковые ответы и зависает, этот транспорт, скорее всего, не будет работать.

                                      Цель та же, что и у V2fly Meek, но благодаря использованию фрагментированной загрузки скорость загрузки выше, а скорость отдачи оптимизирована, но все еще очень ограничена, поэтому к HTTP-прокси предъявляются более высокие требования (см. выше).

                                      SplitHTTP также принимает заголовок X-Forwarded-For.

                                      SplitHttpObject

                                      SplitHttpObject соответствует элементу splithttpSettings в конфигурации транспорта.

                                      {
                                         "path": "/",
                                         "host": "xray.com",
                                         "headers": {
                                      diff --git a/assets/splithttp.html-LJ7zPnkk.js b/assets/splithttp.html-Bx6q0Pwz.js
                                      similarity index 82%
                                      rename from assets/splithttp.html-LJ7zPnkk.js
                                      rename to assets/splithttp.html-Bx6q0Pwz.js
                                      index 1ab6341ad..b943c14fb 100644
                                      --- a/assets/splithttp.html-LJ7zPnkk.js
                                      +++ b/assets/splithttp.html-Bx6q0Pwz.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":"XmuxObject","slug":"xmuxobject","link":"#xmuxobject","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":1729054786000,"contributors":[{"name":"风扇滑翔翼","email":"Fangliding.fshxy@outlook.com","commits":19},{"name":"mmmray","email":"142015632+mmmray@users.noreply.github.com","commits":8},{"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":1729054786000}}');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":"XmuxObject","slug":"xmuxobject","link":"#xmuxobject","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":1729083737000,"contributors":[{"name":"风扇滑翔翼","email":"Fangliding.fshxy@outlook.com","commits":20},{"name":"mmmray","email":"142015632+mmmray@users.noreply.github.com","commits":8},{"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":1729083737000}}');export{t as data};
                                      diff --git a/assets/splithttp.html-C61Iuay7.js b/assets/splithttp.html-C59rxUsD.js
                                      similarity index 93%
                                      rename from assets/splithttp.html-C61Iuay7.js
                                      rename to assets/splithttp.html-C59rxUsD.js
                                      index e7cd3e267..843fee834 100644
                                      --- a/assets/splithttp.html-C61Iuay7.js
                                      +++ b/assets/splithttp.html-C59rxUsD.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as i,r as o,o as u,c as d,a as e,b as n,d as s,w as p,e as t}from"./app-BClOOpdM.js";const h={},k=n("h1",{id:"splithttp-h2、quic-h3",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#splithttp-h2、quic-h3"},[n("span",null,"SplitHTTP(H2、QUIC H3)")])],-1),b=t(`

                                      使用HTTP分块传输编码流式响应处理下载,使用多个HTTP POST请求进行上传。

                                      可以通过不支持WebSocket的CDN上,但仍有一些要求:

                                      • CDN必须支持HTTP分块传输,且支持流式响应而不会缓冲,核心将会发送各种信息以告知CDN,但是需要CDN遵守。如果中间盒不支持流式响应而导致连接被挂起,则该传输很可能无法工作。

                                      目的与V2fly Meek相同,由于使用了流式响应处理下载,下行速率更为优秀,上行也经过优化但仍非常有限,也因此对 HTTP 中间盒要求更高(见上)。

                                      SplitHTTP 也接受 X-Forwarded-For header。

                                      SplitHttpObject

                                      The SplitHttpObject 对应传输配置的 splithttpSettings 项。

                                      {
                                      +import{_ as i,r as o,o as u,c as d,a as e,b as n,d as s,w as p,e as t}from"./app-Dp4t6tDQ.js";const h={},k=n("h1",{id:"splithttp-h2、quic-h3",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#splithttp-h2、quic-h3"},[n("span",null,"SplitHTTP(H2、QUIC H3)")])],-1),b=t(`

                                      使用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": {
                                      @@ -16,10 +16,10 @@ import{_ as i,r as o,o as u,c as d,a as e,b as n,d as s,w as p,e as t}from"./app
                                           "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

                                      `,32),m=n("code",null,'"100-1000"',-1),q=n("p",null,[s("设置为 "),n("code",null,"-1"),s(" 将完全禁用填充")],-1),T=n("blockquote",null,[n("p",null,[n("code",null,"xmux"),s(": "),n("a",{href:"#xmuxobject"},"XmuxObject")])],-1),v=n("h2",{id:"xmuxobject",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#xmuxobject"},[n("span",null,"XmuxObject")])],-1),x=t(`

                                      仅客户端,允许用户对 SplitHTTP 在 h2 与 h3 中的多路复用行为进行控制。使用该功能时不要启用 mux.cool。

                                      {
                                      -  "maxConcurrency": 16,
                                      -  "maxConnections": 32,
                                      -  "cMaxReuseTimes": 64,
                                      -  "cMaxLifetimeMs": 128
                                      +

                                      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

                                      `,32),q=n("code",null,'"100-1000"',-1),m=n("p",null,[s("设置为 "),n("code",null,"-1"),s(" 将完全禁用填充")],-1),T=n("blockquote",null,[n("p",null,[n("code",null,"xmux"),s(": "),n("a",{href:"#xmuxobject"},"XmuxObject")])],-1),v=n("h2",{id:"xmuxobject",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#xmuxobject"},[n("span",null,"XmuxObject")])],-1),x=t(`

                                      仅客户端,允许用户对 SplitHTTP 在 h2 与 h3 中的多路复用行为进行控制。使用该功能时不要启用 mux.cool。

                                      {
                                      +  "maxConcurrency": "16-32",
                                      +  "maxConnections": 0,
                                      +  "cMaxReuseTimes": "64-128",
                                      +  "cMaxLifetimeMs": 0
                                       }
                                      -

                                      上为全设置为0或者不设置时核心会填入的默认值

                                      术语解释:

                                      `,4),_=n("li",null,"流会复用物理连接,像这样 连接1(流1,流2,流3) 连接2(流4,流5,流6) .. 以此类推 在其他地方你可能看到 连接-子连接 这样的描述,都是一样的东西。",-1),g=t('

                                      maxConcurrency: int/string

                                      默认值为 0(即无限) 每个连接中复用的流的最大数量,连接中流的数量达到该值后核心会新建更多连接以容纳更多的流,类似于 mux.cool 的 concurrency.

                                      maxConnections: int/string

                                      默认值为 0(即无限) 要打开的最大连接数,连接达到此值前核心会积极打开连接,对每一条流都新建一个连接,直到达到该值。然后核心会开始复用已经建立的连接。 与 maxConcurrency 冲突。

                                      cMaxReuseTimes: int/string

                                      默认值为 0(即无限) 一个连接最多被复用几次,当达到该值后核心不会向该连接再分配流,其将在内部最后一条流关闭后断开。

                                      cMaxLifetimeMs: int/string

                                      默认值为 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

                                      ',19),P=n("h2",{id:"协议细节",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#协议细节"},[n("span",null,"协议细节")])],-1),f={href:"https://github.com/XTLS/Xray-core/pull/3412",target:"_blank",rel:"noopener noreferrer"},y={href:"https://github.com/XTLS/Xray-core/pull/3462",target:"_blank",rel:"noopener noreferrer"},H=t('
                                      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 C(S,M){const r=o("I18nTip"),c=o("Badge"),a=o("RouterLink"),l=o("ExternalLinkIcon");return u(),d("div",null,[e(r),k,e(c,{text:"v1.8.16+",type:"warning"}),b,n("p",null,[s("设置请求(出站)和响应(入站)的填充大小,用于减少请求指纹。单位byte, 默认为 "),m,s(" 每次会在该范围中随机选择一个数字。为 "),e(a,{to:"/development/intro/guide.html#int32range"},{default:p(()=>[s("Int32Range")]),_:1}),s(" 类型")]),q,T,v,e(c,{text:"v24.9.19+",type:"warning"}),x,n("ul",null,[_,n("li",null,[s("下述所有字段类型均为 为 "),e(a,{to:"/development/intro/guide.html#int32range"},{default:p(()=>[s("Int32Range")]),_:1}),s(" 类型")])]),g,n("p",null,[s("如果使用HTTPS,该传输还支持 "),e(a,{to:"/config/features/browser_dialer.html"},{default:p(()=>[s("Browser Dialer")]),_:1})]),P,n("p",null,[s("讨论详见 "),n("a",f,[s("#3412"),e(l)]),s(" 和 "),n("a",y,[s("#3462"),e(l)]),s(" 以下是简述和简要兼容实现要求")]),H])}const L=i(h,[["render",C],["__file","splithttp.html.vue"]]);export{L as default}; +

                                      上为全设置为0或者不设置时核心会填入的默认值

                                      术语解释:

                                      `,4),g=n("li",null,"流会复用物理连接,像这样 连接1(流1,流2,流3) 连接2(流4,流5,流6) .. 以此类推 在其他地方你可能看到 连接-子连接 这样的描述,都是一样的东西。",-1),_=t('

                                      maxConcurrency: int/string

                                      默认值为 0(即无限) 每个连接中复用的流的最大数量,连接中流的数量达到该值后核心会新建更多连接以容纳更多的流,类似于 mux.cool 的 concurrency.

                                      maxConnections: int/string

                                      默认值为 0(即无限) 要打开的最大连接数,连接达到此值前核心会积极打开连接,对每一条流都新建一个连接,直到达到该值。然后核心会开始复用已经建立的连接。 与 maxConcurrency 冲突。

                                      cMaxReuseTimes: int/string

                                      默认值为 0(即无限) 一个连接最多被复用几次,当达到该值后核心不会向该连接再分配流,其将在内部最后一条流关闭后断开。

                                      cMaxLifetimeMs: int/string

                                      默认值为 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

                                      ',19),P=n("h2",{id:"协议细节",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#协议细节"},[n("span",null,"协议细节")])],-1),f={href:"https://github.com/XTLS/Xray-core/pull/3412",target:"_blank",rel:"noopener noreferrer"},y={href:"https://github.com/XTLS/Xray-core/pull/3462",target:"_blank",rel:"noopener noreferrer"},H=t('
                                      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 C(S,M){const r=o("I18nTip"),c=o("Badge"),a=o("RouterLink"),l=o("ExternalLinkIcon");return u(),d("div",null,[e(r),k,e(c,{text:"v1.8.16+",type:"warning"}),b,n("p",null,[s("设置请求(出站)和响应(入站)的填充大小,用于减少请求指纹。单位byte, 默认为 "),q,s(" 每次会在该范围中随机选择一个数字。为 "),e(a,{to:"/development/intro/guide.html#int32range"},{default:p(()=>[s("Int32Range")]),_:1}),s(" 类型")]),m,T,v,e(c,{text:"v24.9.19+",type:"warning"}),x,n("ul",null,[g,n("li",null,[s("下述所有字段类型均为 为 "),e(a,{to:"/development/intro/guide.html#int32range"},{default:p(()=>[s("Int32Range")]),_:1}),s(" 类型")])]),_,n("p",null,[s("如果使用HTTPS,该传输还支持 "),e(a,{to:"/config/features/browser_dialer.html"},{default:p(()=>[s("Browser Dialer")]),_:1})]),P,n("p",null,[s("讨论详见 "),n("a",f,[s("#3412"),e(l)]),s(" 和 "),n("a",y,[s("#3462"),e(l)]),s(" 以下是简述和简要兼容实现要求")]),H])}const L=i(h,[["render",C],["__file","splithttp.html.vue"]]);export{L as default}; diff --git a/assets/splithttp.html-CiF71Wo2.js b/assets/splithttp.html-DpYV3dkE.js similarity index 99% rename from assets/splithttp.html-CiF71Wo2.js rename to assets/splithttp.html-DpYV3dkE.js index 1e2961afa..864ee16c1 100644 --- a/assets/splithttp.html-CiF71Wo2.js +++ b/assets/splithttp.html-DpYV3dkE.js @@ -1,4 +1,4 @@ -import{_ as l,r as o,o as p,c as d,a as t,b as e,d as n,w as u,e as a}from"./app-BClOOpdM.js";const h={},m=e("h1",{id:"splithttp",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#splithttp"},[e("span",null,"SplitHTTP")])],-1),b=a(`

                                      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 o,o as p,c as d,a as t,b as e,d as n,w as u,e as a}from"./app-Dp4t6tDQ.js";const h={},m=e("h1",{id:"splithttp",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#splithttp"},[e("span",null,"SplitHTTP")])],-1),b=a(`

                                      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": {
                                      diff --git a/assets/splithttp.html-lyS93xvr.js b/assets/splithttp.html-DyKm1XN4.js
                                      similarity index 95%
                                      rename from assets/splithttp.html-lyS93xvr.js
                                      rename to assets/splithttp.html-DyKm1XN4.js
                                      index e25d357e0..69343ff4f 100644
                                      --- a/assets/splithttp.html-lyS93xvr.js
                                      +++ b/assets/splithttp.html-DyKm1XN4.js
                                      @@ -1 +1 @@
                                      -const t=JSON.parse('{"key":"v-32d545e2","path":"/ru/config/transports/splithttp.html","title":"SplitHTTP (H2, QUIC H3)","lang":"ru-RU","frontmatter":{},"headers":[{"level":2,"title":"SplitHttpObject","slug":"splithttpobject","link":"#splithttpobject","children":[]},{"level":2,"title":"XmuxObject","slug":"xmuxobject","link":"#xmuxobject","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":1727962267000,"contributors":[{"name":"Nikita Korotaev","email":"104270279+iambabyninja@users.noreply.github.com","commits":4}]},"filePathRelative":"ru/config/transports/splithttp.md","i18n":{"pathLocale":"/ru/","sourceLink":"/config/transports/splithttp.html","untranslated":false,"updatedTime":1727962267000,"sourceUpdatedTime":1729054786000,"outdated":true}}');export{t as data};
                                      +const t=JSON.parse('{"key":"v-32d545e2","path":"/ru/config/transports/splithttp.html","title":"SplitHTTP (H2, QUIC H3)","lang":"ru-RU","frontmatter":{},"headers":[{"level":2,"title":"SplitHttpObject","slug":"splithttpobject","link":"#splithttpobject","children":[]},{"level":2,"title":"XmuxObject","slug":"xmuxobject","link":"#xmuxobject","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":1727962267000,"contributors":[{"name":"Nikita Korotaev","email":"104270279+iambabyninja@users.noreply.github.com","commits":4}]},"filePathRelative":"ru/config/transports/splithttp.md","i18n":{"pathLocale":"/ru/","sourceLink":"/config/transports/splithttp.html","untranslated":false,"updatedTime":1727962267000,"sourceUpdatedTime":1729083737000,"outdated":true}}');export{t as data};
                                      diff --git a/assets/stateDiagram-TQSDS2D4-CKjMI_Q3.js b/assets/stateDiagram-TQSDS2D4-CEpT6xhM.js
                                      similarity index 96%
                                      rename from assets/stateDiagram-TQSDS2D4-CKjMI_Q3.js
                                      rename to assets/stateDiagram-TQSDS2D4-CEpT6xhM.js
                                      index 44ff163ad..c51020024 100644
                                      --- a/assets/stateDiagram-TQSDS2D4-CKjMI_Q3.js
                                      +++ b/assets/stateDiagram-TQSDS2D4-CEpT6xhM.js
                                      @@ -1 +1 @@
                                      -import{s as W,a as N,b as P}from"./chunk-2JBRQKJ5-BMSx-IbG.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-IUatkdtb.js";import"./chunk-YWFND7JV-CtqGT_XT.js";import{G as J}from"./graph-CKGFjaQu.js";import{l as X}from"./layout-Bmwgbrwx.js";import"./chunk-DUMQOTYW-Bze3ZeWr.js";import"./app-BClOOpdM.js";import"./baseUniq-j141U2p6.js";import"./basePickBy-Cyiz-f_r.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-2JBRQKJ5-c3I5MwZ1.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-VsNG6kTl.js";import"./chunk-YWFND7JV-DqutOh5-.js";import{G as J}from"./graph-DebN9_Dg.js";import{l as X}from"./layout-BkNI4twY.js";import"./chunk-DUMQOTYW-Bi8JUtJi.js";import"./app-Dp4t6tDQ.js";import"./baseUniq-Bpwj4IW2.js";import"./basePickBy-BMIT5f2S.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-J5TZWJW5-BzVT64Mf.js b/assets/stateDiagram-v2-J5TZWJW5-BzVT64Mf.js deleted file mode 100644 index a43b7c535..000000000 --- a/assets/stateDiagram-v2-J5TZWJW5-BzVT64Mf.js +++ /dev/null @@ -1 +0,0 @@ -import{s as e,a as t,c as r,b as s}from"./chunk-2JBRQKJ5-BMSx-IbG.js";import{_ as i}from"./mermaid.core-IUatkdtb.js";import"./chunk-YWFND7JV-CtqGT_XT.js";import"./chunk-DUMQOTYW-Bze3ZeWr.js";import"./app-BClOOpdM.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-J5TZWJW5-CIAps9nC.js b/assets/stateDiagram-v2-J5TZWJW5-CIAps9nC.js new file mode 100644 index 000000000..2f3d90e1a --- /dev/null +++ b/assets/stateDiagram-v2-J5TZWJW5-CIAps9nC.js @@ -0,0 +1 @@ +import{s as e,a as t,c as r,b as s}from"./chunk-2JBRQKJ5-c3I5MwZ1.js";import{_ as i}from"./mermaid.core-VsNG6kTl.js";import"./chunk-YWFND7JV-DqutOh5-.js";import"./chunk-DUMQOTYW-Bi8JUtJi.js";import"./app-Dp4t6tDQ.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-Bgjxt7xr.js b/assets/stats.html-Bbi2nVPE.js similarity index 97% rename from assets/stats.html-Bgjxt7xr.js rename to assets/stats.html-Bbi2nVPE.js index d05abe4a2..18a392f83 100644 --- a/assets/stats.html-Bgjxt7xr.js +++ b/assets/stats.html-Bbi2nVPE.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-BClOOpdM.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-Dp4t6tDQ.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-BCwtJiO-.js b/assets/stats.html-CfiWDV46.js similarity index 97% rename from assets/stats.html-BCwtJiO-.js rename to assets/stats.html-CfiWDV46.js index d53b8fb39..2c266c07f 100644 --- a/assets/stats.html-BCwtJiO-.js +++ b/assets/stats.html-CfiWDV46.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-BClOOpdM.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-Dp4t6tDQ.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/stats.html-Dx9fcabd.js b/assets/stats.html-DscjAxzk.js similarity index 98% rename from assets/stats.html-Dx9fcabd.js rename to assets/stats.html-DscjAxzk.js index 5c6424179..bda886f03 100644 --- a/assets/stats.html-Dx9fcabd.js +++ b/assets/stats.html-DscjAxzk.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-BClOOpdM.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-Dp4t6tDQ.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/tcp.html-sVHKrGaV.js b/assets/tcp.html-C8W2HTBr.js similarity index 99% rename from assets/tcp.html-sVHKrGaV.js rename to assets/tcp.html-C8W2HTBr.js index 1a50888eb..9f46e4f0c 100644 --- a/assets/tcp.html-sVHKrGaV.js +++ b/assets/tcp.html-C8W2HTBr.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-BClOOpdM.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-Dp4t6tDQ.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/tcp.html-B1TpuKMg.js b/assets/tcp.html-Dvpc5dBq.js
                                      similarity index 91%
                                      rename from assets/tcp.html-B1TpuKMg.js
                                      rename to assets/tcp.html-Dvpc5dBq.js
                                      index efee60a90..12042a7f7 100644
                                      --- a/assets/tcp.html-B1TpuKMg.js
                                      +++ b/assets/tcp.html-Dvpc5dBq.js
                                      @@ -1 +1 @@
                                      -import{_ as a,r as o,o as r,c as _,a as n,b as t,d as e,w as l}from"./app-BClOOpdM.js";const d={},i=t("h1",{id:"tcp",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#tcp"},[t("span",null,"TCP")])],-1),p=t("code",null,'"network": "raw"',-1),h=t("code",null,"rawSettings",-1),u=t("code",null,"tcpSettings",-1);function m(f,w){const c=o("I18nTip"),s=o("RouterLink");return r(),_("div",null,[n(c),i,t("p",null,[e("v24.9.30 版本后,为了更贴近实际行为,tcp传输方式已更名为"),n(s,{to:"raw.html"},{default:l(()=>[e("raw")]),_:1}),e(", 为了兼容性,"),p,e(' 和 "network": "tcp", '),h,e("和"),u,e(" 互为别名")])])}const x=a(d,[["render",m],["__file","tcp.html.vue"]]);export{x as default};
                                      +import{_ as a,r as o,o as r,c as _,a as n,b as t,d as e,w as l}from"./app-Dp4t6tDQ.js";const d={},i=t("h1",{id:"tcp",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#tcp"},[t("span",null,"TCP")])],-1),p=t("code",null,'"network": "raw"',-1),h=t("code",null,"rawSettings",-1),u=t("code",null,"tcpSettings",-1);function m(f,w){const c=o("I18nTip"),s=o("RouterLink");return r(),_("div",null,[n(c),i,t("p",null,[e("v24.9.30 版本后,为了更贴近实际行为,tcp传输方式已更名为"),n(s,{to:"raw.html"},{default:l(()=>[e("raw")]),_:1}),e(", 为了兼容性,"),p,e(' 和 "network": "tcp", '),h,e("和"),u,e(" 互为别名")])])}const x=a(d,[["render",m],["__file","tcp.html.vue"]]);export{x as default};
                                      diff --git a/assets/tcp.html-C1uis9Br.js b/assets/tcp.html-hSF8trgX.js
                                      similarity index 91%
                                      rename from assets/tcp.html-C1uis9Br.js
                                      rename to assets/tcp.html-hSF8trgX.js
                                      index 5597494af..d561505d8 100644
                                      --- a/assets/tcp.html-C1uis9Br.js
                                      +++ b/assets/tcp.html-hSF8trgX.js
                                      @@ -1 +1 @@
                                      -import{_ as a,r as o,o as r,c as _,a as n,b as t,d as e,w as l}from"./app-BClOOpdM.js";const d={},i=t("h1",{id:"tcp",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#tcp"},[t("span",null,"TCP")])],-1),p=t("code",null,'"network": "raw"',-1),h=t("code",null,"rawSettings",-1),u=t("code",null,"tcpSettings",-1);function f(m,w){const c=o("I18nTip"),s=o("RouterLink");return r(),_("div",null,[n(c),i,t("p",null,[e("v24.9.30 版本后,为了更贴近实际行为,tcp传输方式已更名为"),n(s,{to:"/config/transports/raw.html"},{default:l(()=>[e("raw")]),_:1}),e(", 为了兼容性,"),p,e(' 和 "network": "tcp", '),h,e("和"),u,e(" 互为别名")])])}const x=a(d,[["render",f],["__file","tcp.html.vue"]]);export{x as default};
                                      +import{_ as a,r as o,o as r,c as _,a as n,b as t,d as e,w as l}from"./app-Dp4t6tDQ.js";const d={},i=t("h1",{id:"tcp",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#tcp"},[t("span",null,"TCP")])],-1),p=t("code",null,'"network": "raw"',-1),h=t("code",null,"rawSettings",-1),u=t("code",null,"tcpSettings",-1);function f(m,w){const c=o("I18nTip"),s=o("RouterLink");return r(),_("div",null,[n(c),i,t("p",null,[e("v24.9.30 版本后,为了更贴近实际行为,tcp传输方式已更名为"),n(s,{to:"/config/transports/raw.html"},{default:l(()=>[e("raw")]),_:1}),e(", 为了兼容性,"),p,e(' 和 "network": "tcp", '),h,e("和"),u,e(" 互为别名")])])}const x=a(d,[["render",f],["__file","tcp.html.vue"]]);export{x as default};
                                      diff --git a/assets/timeline-definition-KYQAIZUX-CfFf7B0p.js b/assets/timeline-definition-KYQAIZUX-bG0Ln98x.js
                                      similarity index 99%
                                      rename from assets/timeline-definition-KYQAIZUX-CfFf7B0p.js
                                      rename to assets/timeline-definition-KYQAIZUX-bG0Ln98x.js
                                      index 0b5fa9417..802ab36ad 100644
                                      --- a/assets/timeline-definition-KYQAIZUX-CfFf7B0p.js
                                      +++ b/assets/timeline-definition-KYQAIZUX-bG0Ln98x.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-IUatkdtb.js";import{d as nt}from"./arc-BJstDFsX.js";import"./app-BClOOpdM.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-VsNG6kTl.js";import{d as nt}from"./arc-TolVAfGG.js";import"./app-Dp4t6tDQ.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-zMvXk72O.js b/assets/tproxy.html-B25CC21-.js
                                      similarity index 99%
                                      rename from assets/tproxy.html-zMvXk72O.js
                                      rename to assets/tproxy.html-B25CC21-.js
                                      index 8be10b026..907a11040 100644
                                      --- a/assets/tproxy.html-zMvXk72O.js
                                      +++ b/assets/tproxy.html-B25CC21-.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-BClOOpdM.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-Dp4t6tDQ.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-BW7ZdTB0.js b/assets/tproxy.html-DBGuths-.js
                                      similarity index 99%
                                      rename from assets/tproxy.html-BW7ZdTB0.js
                                      rename to assets/tproxy.html-DBGuths-.js
                                      index 36cbece43..cfd6a064e 100644
                                      --- a/assets/tproxy.html-BW7ZdTB0.js
                                      +++ b/assets/tproxy.html-DBGuths-.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as o,r as t,o as l,c as r,a as s,b as n,d as a,e as i}from"./app-BClOOpdM.js";const c={},u=n("h1",{id:"透明代理-tproxy-配置教程",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#透明代理-tproxy-配置教程"},[n("span",null,"透明代理(TProxy)配置教程")])],-1),d={href:"https://guide.v2fly.org/app/tproxy.html",target:"_blank",rel:"noopener noreferrer"},v=n("p",null,"本文中所有配置已在 Raspberry Pi 2B、Ubuntu 20.04 环境下测试成功,如在其它环境中使用请自行调整配置。",-1),k=n("h2",{id:"开始之前",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#开始之前"},[n("span",null,"开始之前")])],-1),m=n("p",null,"请检查您的设备是否有可用的网络连接,且服务端已经配置成功,客户端已经安装完毕。",-1),b={href:"https://github.com/XTLS/Xray-core/discussions/59",target:"_blank",rel:"noopener noreferrer"},q=n("p",null,"这里我想要补充的是,很多透明代理教程会使用 Netfilter 进行分流,使直连流量直接发出而不经过 Xray,这时必须开启 IP 转发;也有的教程,如本文,会将所有流量导入 Xray 之中,由 Xray 的路由模块进行分流,这时无需开启 IP 转发。",-1),g=n("h2",{id:"xray-配置",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#xray-配置"},[n("span",null,"Xray 配置")])],-1),y={href:"https://github.com/Loyalsoldier/v2ray-rules-dat",target:"_blank",rel:"noopener noreferrer"},f=i(`
                                      sudo curl -oL /usr/local/share/xray/geoip.dat https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat
                                      +import{_ as o,r as t,o as l,c as r,a as s,b as n,d as a,e as i}from"./app-Dp4t6tDQ.js";const c={},u=n("h1",{id:"透明代理-tproxy-配置教程",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#透明代理-tproxy-配置教程"},[n("span",null,"透明代理(TProxy)配置教程")])],-1),d={href:"https://guide.v2fly.org/app/tproxy.html",target:"_blank",rel:"noopener noreferrer"},v=n("p",null,"本文中所有配置已在 Raspberry Pi 2B、Ubuntu 20.04 环境下测试成功,如在其它环境中使用请自行调整配置。",-1),k=n("h2",{id:"开始之前",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#开始之前"},[n("span",null,"开始之前")])],-1),m=n("p",null,"请检查您的设备是否有可用的网络连接,且服务端已经配置成功,客户端已经安装完毕。",-1),b={href:"https://github.com/XTLS/Xray-core/discussions/59",target:"_blank",rel:"noopener noreferrer"},q=n("p",null,"这里我想要补充的是,很多透明代理教程会使用 Netfilter 进行分流,使直连流量直接发出而不经过 Xray,这时必须开启 IP 转发;也有的教程,如本文,会将所有流量导入 Xray 之中,由 Xray 的路由模块进行分流,这时无需开启 IP 转发。",-1),g=n("h2",{id:"xray-配置",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#xray-配置"},[n("span",null,"Xray 配置")])],-1),y={href:"https://github.com/Loyalsoldier/v2ray-rules-dat",target:"_blank",rel:"noopener noreferrer"},f=i(`
                                      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-C4Wak-Ch.js b/assets/tproxy.html-Dulb6WIx.js
                                      similarity index 99%
                                      rename from assets/tproxy.html-C4Wak-Ch.js
                                      rename to assets/tproxy.html-Dulb6WIx.js
                                      index 15df865a9..7fa108f62 100644
                                      --- a/assets/tproxy.html-C4Wak-Ch.js
                                      +++ b/assets/tproxy.html-Dulb6WIx.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-BClOOpdM.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-Dp4t6tDQ.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-BNsWytYC.js b/assets/tproxy_ipv4_and_ipv6.html-CmyteKZw.js
                                      similarity index 99%
                                      rename from assets/tproxy_ipv4_and_ipv6.html-BNsWytYC.js
                                      rename to assets/tproxy_ipv4_and_ipv6.html-CmyteKZw.js
                                      index 50f98a20b..11af7d87d 100644
                                      --- a/assets/tproxy_ipv4_and_ipv6.html-BNsWytYC.js
                                      +++ b/assets/tproxy_ipv4_and_ipv6.html-CmyteKZw.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-BClOOpdM.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-Dp4t6tDQ.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-OETh4Y-h.js b/assets/tproxy_ipv4_and_ipv6.html-CoLDDyIl.js
                                      similarity index 99%
                                      rename from assets/tproxy_ipv4_and_ipv6.html-OETh4Y-h.js
                                      rename to assets/tproxy_ipv4_and_ipv6.html-CoLDDyIl.js
                                      index afdd9f7e6..f4f2b450b 100644
                                      --- a/assets/tproxy_ipv4_and_ipv6.html-OETh4Y-h.js
                                      +++ b/assets/tproxy_ipv4_and_ipv6.html-CoLDDyIl.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-BClOOpdM.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-Dp4t6tDQ.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-Cpbn1IZo.js b/assets/tproxy_ipv4_and_ipv6.html-DZorz4ml.js
                                      similarity index 99%
                                      rename from assets/tproxy_ipv4_and_ipv6.html-Cpbn1IZo.js
                                      rename to assets/tproxy_ipv4_and_ipv6.html-DZorz4ml.js
                                      index 6a4d8a467..68a56ebe0 100644
                                      --- a/assets/tproxy_ipv4_and_ipv6.html-Cpbn1IZo.js
                                      +++ b/assets/tproxy_ipv4_and_ipv6.html-DZorz4ml.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-BClOOpdM.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-Dp4t6tDQ.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-BlmP7gwP.js b/assets/traffic_stats.html-BFwn7sHB.js
                                      similarity index 99%
                                      rename from assets/traffic_stats.html-BlmP7gwP.js
                                      rename to assets/traffic_stats.html-BFwn7sHB.js
                                      index 25089cf6e..5e6d47a6c 100644
                                      --- a/assets/traffic_stats.html-BlmP7gwP.js
                                      +++ b/assets/traffic_stats.html-BFwn7sHB.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-BClOOpdM.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-Dp4t6tDQ.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-Bmki1ou2.js b/assets/traffic_stats.html-CJPd3Vx1.js
                                      similarity index 99%
                                      rename from assets/traffic_stats.html-Bmki1ou2.js
                                      rename to assets/traffic_stats.html-CJPd3Vx1.js
                                      index 25089cf6e..5e6d47a6c 100644
                                      --- a/assets/traffic_stats.html-Bmki1ou2.js
                                      +++ b/assets/traffic_stats.html-CJPd3Vx1.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-BClOOpdM.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-Dp4t6tDQ.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-tywRIfWl.js b/assets/traffic_stats.html-F4ztFfj9.js
                                      similarity index 99%
                                      rename from assets/traffic_stats.html-tywRIfWl.js
                                      rename to assets/traffic_stats.html-F4ztFfj9.js
                                      index 071f18b11..334320352 100644
                                      --- a/assets/traffic_stats.html-tywRIfWl.js
                                      +++ b/assets/traffic_stats.html-F4ztFfj9.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-BClOOpdM.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-Dp4t6tDQ.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/transparent_proxy.html-CB7ITqDt.js b/assets/transparent_proxy.html-B1GAn8Vo.js
                                      similarity index 99%
                                      rename from assets/transparent_proxy.html-CB7ITqDt.js
                                      rename to assets/transparent_proxy.html-B1GAn8Vo.js
                                      index 437dbdfa8..a9af85ee3 100644
                                      --- a/assets/transparent_proxy.html-CB7ITqDt.js
                                      +++ b/assets/transparent_proxy.html-B1GAn8Vo.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-BClOOpdM.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-Dp4t6tDQ.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-DDpbn2RR.js b/assets/transparent_proxy.html-DCVZLq4e.js
                                      similarity index 99%
                                      rename from assets/transparent_proxy.html-DDpbn2RR.js
                                      rename to assets/transparent_proxy.html-DCVZLq4e.js
                                      index 795d83c97..613678a5c 100644
                                      --- a/assets/transparent_proxy.html-DDpbn2RR.js
                                      +++ b/assets/transparent_proxy.html-DCVZLq4e.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-BClOOpdM.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-Dp4t6tDQ.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-Dfb29zhW.js b/assets/transparent_proxy.html-DLTkeZqq.js
                                      similarity index 99%
                                      rename from assets/transparent_proxy.html-Dfb29zhW.js
                                      rename to assets/transparent_proxy.html-DLTkeZqq.js
                                      index 5b32b2396..bd32ee4b8 100644
                                      --- a/assets/transparent_proxy.html-Dfb29zhW.js
                                      +++ b/assets/transparent_proxy.html-DLTkeZqq.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-BClOOpdM.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-Dp4t6tDQ.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-_5N6k7Mk.js b/assets/transport.html-5mGZ7PS0.js
                                      similarity index 99%
                                      rename from assets/transport.html-_5N6k7Mk.js
                                      rename to assets/transport.html-5mGZ7PS0.js
                                      index beed1f044..0976eb5ae 100644
                                      --- a/assets/transport.html-_5N6k7Mk.js
                                      +++ b/assets/transport.html-5mGZ7PS0.js
                                      @@ -1,4 +1,4 @@
                                      -import{_ as u,r as c,o as i,c as r,a as t,b as n,d as s,w as p,e as o}from"./app-BClOOpdM.js";const d={},k=o(`

                                      Способы передачи (uTLS, REALITY)

                                      Способ передачи (transport) — это способ взаимодействия текущего узла Xray с другими узлами.

                                      Транспорт определяет способ передачи данных. Обычно оба конца сетевого подключения должны использовать одинаковый транспорт. Например, если один конец использует WebSocket, то другой конец также должен использовать WebSocket, иначе соединение не будет установлено.

                                      StreamSettingsObject

                                      StreamSettingsObject соответствует элементу streamSettings во входящем или исходящем подключении. Для каждого входящего или исходящего подключения можно настроить различные параметры передачи, и можно использовать streamSettings для настройки некоторых параметров передачи.

                                      {
                                      +import{_ as u,r as c,o as i,c as r,a as t,b as n,d as s,w as p,e as o}from"./app-Dp4t6tDQ.js";const d={},k=o(`

                                      Способы передачи (uTLS, REALITY)

                                      Способ передачи (transport) — это способ взаимодействия текущего узла Xray с другими узлами.

                                      Транспорт определяет способ передачи данных. Обычно оба конца сетевого подключения должны использовать одинаковый транспорт. Например, если один конец использует WebSocket, то другой конец также должен использовать WebSocket, иначе соединение не будет установлено.

                                      StreamSettingsObject

                                      StreamSettingsObject соответствует элементу streamSettings во входящем или исходящем подключении. Для каждого входящего или исходящего подключения можно настроить различные параметры передачи, и можно использовать streamSettings для настройки некоторых параметров передачи.

                                      {
                                         "network": "raw",
                                         "security": "none",
                                         "tlsSettings": {},
                                      diff --git a/assets/transport.html-DhvzqRzp.js b/assets/transport.html-8GeYnnYT.js
                                      similarity index 99%
                                      rename from assets/transport.html-DhvzqRzp.js
                                      rename to assets/transport.html-8GeYnnYT.js
                                      index 536464696..caa0a0197 100644
                                      --- a/assets/transport.html-DhvzqRzp.js
                                      +++ b/assets/transport.html-8GeYnnYT.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-BClOOpdM.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-Dp4t6tDQ.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-D2kyr6E5.js b/assets/transport.html-Dv127mMA.js
                                      similarity index 99%
                                      rename from assets/transport.html-D2kyr6E5.js
                                      rename to assets/transport.html-Dv127mMA.js
                                      index 19f465868..d60386cd7 100644
                                      --- a/assets/transport.html-D2kyr6E5.js
                                      +++ b/assets/transport.html-Dv127mMA.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-BClOOpdM.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-Dp4t6tDQ.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-DzAn779h.js b/assets/trojan.html-C9BfolYY.js
                                      similarity index 98%
                                      rename from assets/trojan.html-DzAn779h.js
                                      rename to assets/trojan.html-C9BfolYY.js
                                      index a49a85fea..c1666d0d4 100644
                                      --- a/assets/trojan.html-DzAn779h.js
                                      +++ b/assets/trojan.html-C9BfolYY.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-BClOOpdM.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-Dp4t6tDQ.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-DM5uyqdN.js b/assets/trojan.html-CsEcJ5iO.js
                                      similarity index 98%
                                      rename from assets/trojan.html-DM5uyqdN.js
                                      rename to assets/trojan.html-CsEcJ5iO.js
                                      index 4eae41fea..c8a592511 100644
                                      --- a/assets/trojan.html-DM5uyqdN.js
                                      +++ b/assets/trojan.html-CsEcJ5iO.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-BClOOpdM.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-Dp4t6tDQ.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-BuDWDr3U.js b/assets/trojan.html-DGG1rBaz.js
                                      similarity index 98%
                                      rename from assets/trojan.html-BuDWDr3U.js
                                      rename to assets/trojan.html-DGG1rBaz.js
                                      index a5978aa36..35b25e7eb 100644
                                      --- a/assets/trojan.html-BuDWDr3U.js
                                      +++ b/assets/trojan.html-DGG1rBaz.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-BClOOpdM.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-Dp4t6tDQ.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-DTx446Hu.js b/assets/trojan.html-DGRy70K7.js
                                      similarity index 98%
                                      rename from assets/trojan.html-DTx446Hu.js
                                      rename to assets/trojan.html-DGRy70K7.js
                                      index 56f7694c6..e95522e18 100644
                                      --- a/assets/trojan.html-DTx446Hu.js
                                      +++ b/assets/trojan.html-DGRy70K7.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-BClOOpdM.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-Dp4t6tDQ.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-DEzWkEyk.js b/assets/trojan.html-US2vPEfy.js
                                      similarity index 98%
                                      rename from assets/trojan.html-DEzWkEyk.js
                                      rename to assets/trojan.html-US2vPEfy.js
                                      index 0b183502b..d075e3f81 100644
                                      --- a/assets/trojan.html-DEzWkEyk.js
                                      +++ b/assets/trojan.html-US2vPEfy.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-BClOOpdM.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-Dp4t6tDQ.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-DWkiD9C-.js b/assets/trojan.html-jDz_xw6S.js
                                      similarity index 99%
                                      rename from assets/trojan.html-DWkiD9C-.js
                                      rename to assets/trojan.html-jDz_xw6S.js
                                      index 18f8e850b..1b0246eb9 100644
                                      --- a/assets/trojan.html-DWkiD9C-.js
                                      +++ b/assets/trojan.html-jDz_xw6S.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-BClOOpdM.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-Dp4t6tDQ.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/vless.html-BT7cc7Rr.js b/assets/vless.html-CFcJw_nL.js
                                      similarity index 99%
                                      rename from assets/vless.html-BT7cc7Rr.js
                                      rename to assets/vless.html-CFcJw_nL.js
                                      index 4d95eb103..bc9d84c61 100644
                                      --- a/assets/vless.html-BT7cc7Rr.js
                                      +++ b/assets/vless.html-CFcJw_nL.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-BClOOpdM.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-Dp4t6tDQ.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-BOKM9gNU.js b/assets/vless.html-CR2GlAuv.js similarity index 99% rename from assets/vless.html-BOKM9gNU.js rename to assets/vless.html-CR2GlAuv.js index 3166cba07..533f98b8c 100644 --- a/assets/vless.html-BOKM9gNU.js +++ b/assets/vless.html-CR2GlAuv.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-BClOOpdM.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-Dp4t6tDQ.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-B_Oy3zb3.js b/assets/vless.html-CRUfBMsw.js
                                      similarity index 99%
                                      rename from assets/vless.html-B_Oy3zb3.js
                                      rename to assets/vless.html-CRUfBMsw.js
                                      index 6fce4bf51..035f49820 100644
                                      --- a/assets/vless.html-B_Oy3zb3.js
                                      +++ b/assets/vless.html-CRUfBMsw.js
                                      @@ -1 +1 @@
                                      -import{_ as h,r as n,o as c,c as d,a as o,b as t,d as e,e as r}from"./app-BClOOpdM.js";const l={},p=r('

                                      Протокол VLESS

                                      VLESS - это легковесный, не сохраняющий состояние транспортный протокол, который может служить мостом между клиентом и сервером Xray.

                                      Запрос и ответ

                                      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=t("p",null,'Я всегда считал, что "аутентификация ответа" не является обязательной. В версии ALPHA для повышения производительности генерации случайных чисел мы заменили crypto/rand на math/rand, а теперь в этом нет необходимости.',-1),S=t("p",null,'"Версия протокола" не только выполняет функцию "аутентификации ответа", но и дает VLESS возможность безболезненно обновлять структуру протокола, открывая бесконечные возможности. "Версия протокола" во всех бета-версиях равна 0, в официальной версии - 1, а в будущем, если будут несовместимые изменения в структуре протокола, версия должна быть обновлена.',-1),_=t("p",null,"Сервер VLESS спроектирован по принципу switch version, то есть он одновременно поддерживает все версии VLESS. Если требуется обновить версию протокола (что маловероятно), рекомендуется сначала добавить поддержку на сервере за месяц до обновления клиентов. Запрос VMess также имеет версию протокола, но его информация для аутентификации находится снаружи, а часть с командой сильно связана и имеет фиксированное шифрование, что делает версию протокола внутри бессмысленной. Сервер также не проверяет ее, а ответ не имеет версии протокола. В структуре протокола Trojan нет версии протокола.",-1),f=t("p",null,"Далее идет UUID. Сначала я думал, что 16 байт - это многовато, и подумывал о его сокращении, но потом увидел, что Trojan использует 56 печатаемых символов (56 байт), и полностью отказался от этой идеи. Сервер каждый раз проверяет UUID, поэтому производительность также важна: валидатор VLESS прошел через несколько рефакторингов/обновлений, он очень прост и потребляет мало ресурсов по сравнению с VMess, может одновременно поддерживать очень большое количество пользователей, имеет очень высокую производительность и очень высокую скорость проверки (sync.Map). Динамическое добавление и удаление пользователей через API еще более эффективно и плавно. https://github.com/XTLS/Xray-core/issues/158",-1),V=t("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 по сути делает именно это, и накладные расходы минимальны. Склеенные байты очень компактны, практически не отличаются от решения в ALPHA. Желающие могут вывести их и сравнить.

                                      Чтобы указать различный уровень поддержки дополнительной информации (Addons, которые можно рассматривать как плагины, в будущем их может быть много), в следующей бета-версии перед "длиной дополнительной информации" будет добавлена "версия дополнительной информации". 256 - 1 = 255 байт - это достаточно и разумно (65535 - это слишком много, и кто-то может злонамеренно заполнить их), существующие используют только десятую часть, и в будущем не будет такого количества дополнительной информации, а в большинстве случаев дополнительная информация вообще отсутствует. Если этого действительно не хватит, можно обновить версию VLESS.

                                      Чтобы сократить накладные расходы на логические проверки и т.д., Addons пока не будут использовать многоуровневую структуру. Месяц назад появилась идея "изменяемого формата протокола", pb может переставлять поля, но в этом нет необходимости, поскольку современное шифрование не позволяет стороннему наблюдателю увидеть, что заголовки двух передач одинаковы.

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

                                      Schedulers Flow

                                      Предварительное китайское название: Планировщик трафика (обновление от 03.09.2020: официальное китайское название - "Управление потоком"). Команда передается через ProtoBuf и управляет частью данных.

                                      Я обнаружил, что оригинальная "обфускация метаданных" shake в VMess не вносит никаких значимых изменений при использовании TLS, а только снижает производительность, поэтому в VLESS от нее отказались. Кроме того, термин "обфускация" может быть неверно истолкован как маскировка, поэтому от него тоже отказались. Кстати, я всегда скептически относился к маскировке: если она не может быть полностью идентичной, то это же явная сигнатура? А если может быть полностью идентичной, то почему бы не использовать саму маскировку? Сначала я использовал SSR, но потом понял, что он маскирует трафик только для провайдера, и больше им не пользовался.

                                      Так какую же проблему решает "Планировщик трафика"? Он влияет на макроскопические временные характеристики трафика, а не на микроскопические, которые должны решаться шифрованием. Временные характеристики трафика могут быть обусловлены протоколом, например, рукопожатием Socks5 при использовании Socks5 over TLS. Для наблюдателя различные временные характеристики в TLS соответствуют разным протоколам, поэтому бесконечное количество планировщиков эквивалентно бесконечному количеству протоколов (перераспределение размера отправляемых данных и т.д.). Временные характеристики трафика также могут быть обусловлены поведением, например, сколько файлов загружается при посещении главной страницы Google, в каком порядке и какого размера. Добавление еще одного уровня шифрования не может эффективно скрыть эту информацию.

                                      Schedulers не нужно располагать снаружи, как Encryption, поскольку небольшое количество данных в заголовке ничтожно мало по сравнению с объемом данных, которые следуют за ними.

                                      В BETA 2 планируется выпустить два базовых планировщика: сжатие 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=t("p",null,'Поддерживаются два типа шифрования: одно - полностью независимое шифрование, требующее дополнительного пароля, подходит для личного использования, другое - шифрование с использованием существующего UUID, подходит для общего использования. (Если используется первый тип шифрования и пароль раскрывается каким-либо образом, например, при совместном использовании несколькими людьми, то атака "человек посередине" не за горами.) Переработанный динамический порт может быть выпущен вместе с шифрованием, команда будет передаваться через ProtoBuf, реализация будет отличаться от динамического порта VMess.',-1),y=t("p",null,'Добавить готовое шифрование довольно просто, нужно добавить всего лишь один уровень writer & reader. В BETA 3 планируется добавить поддержку aes-128-gcm и chacha20-ietf-poly1305 из SS: в encryption на клиенте можно указать "auto: ss_aes-128-gcm_0_123456, ss_chacha20-ietf-poly1305_0_987654", auto выберет наиболее подходящий для текущей машины, 0 означает бета-версию, а в конце указывается пароль. В decryption на сервере указывается аналогичная строка, и при получении запроса сервер будет пытаться расшифровать его с помощью каждого указанного метода.',-1),m=t("p",null,'Не все комбинации нужно перебирать: шифрование в VMess состоит из трех частей, первая часть - это информация для аутентификации, которая включает UUID, alterId и временной фактор, вторая часть - это часть с командой, которая шифруется с помощью фиксированного алгоритма, команда содержит информацию об алгоритме шифрования, используемом для части с данными, третья часть - это сами данные. Как видно, VMess фактически использует шифрование "многие ко одному" (адаптация на стороне сервера), а не просто шифрование с помощью UUID. Но шифрование только с помощью UUID тоже довольно сложно, и в ближайшее время оно не будет реализовано, учитывая, что у нас уже есть VMessAEAD. Если в VLESS будет реализован способ шифрования с помощью UUID, это будет означать переработку всего VMess.',-1),q=t("h2",{id:"проблемы-с-udp",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#проблемы-с-udp"},[t("span",null,"Проблемы с UDP")])],-1),T={href:"https://github.com/XTLS/Xray-core/discussions/252",target:"_blank",rel:"noopener noreferrer"},x=r('

                                      Руководство по разработке клиентов

                                      1. Протокол VLESS сам по себе будет обновляться несовместимым образом, но параметры конфигурации клиента в основном будут только добавляться. Реализация протокола в iOS-клиенте должна обновляться соответствующим образом.
                                      2. Визуальный стандарт: используйте VLESS в качестве идентификатора в пользовательском интерфейсе, а не VLess / Vless / vless. Настройки в файле конфигурации не затрагиваются, в коде используйте естественный стиль.
                                      3. encryption должен быть реализован в виде текстового поля, а не выпадающего списка. Значение по умолчанию для новых настроек должно быть none. Если пользователь оставит поле пустым, туда должно быть автоматически подставлено none.

                                      Стандарт общих ссылок VLESS

                                      ',3),A=t("img",{src:"https://avatars2.githubusercontent.com/u/7822648?s=32",width:"32px",height:"32px",alt:"a"},null,-1),M={href:"https://github.com/DuckSoft",target:"_blank",rel:"noopener noreferrer"},U={href:"https://github.com/XTLS/Xray-core/issues/91",target:"_blank",rel:"noopener noreferrer"};function P(v,B){const a=n("I18nTip"),s=n("ExternalLinkIcon");return c(),d("div",null,[o(a),p,t("blockquote",null,[t("p",null,[e('"Аутентификация ответа" была заменена на "версию протокола" и перемещена в начало, что позволяет VLESS обновляться, одновременно устраняя накладные расходы на генерацию псевдослучайных чисел. Структура, связанная с обфускацией, была заменена на дополнительную информацию (ProtoBuf) и перемещена вперед, что придало самому протоколу расширяемость с минимальными накладными расходами ('),t("a",i,[e("gogo/protobuf"),o(s)]),e("). Если нет дополнительной информации, то нет и связанных с ней накладных расходов.")])]),u,S,_,f,V,t("p",null,[e("В целом, изменения от ALPHA 2 до BETA в основном заключаются в следующем: эволюция структуры, очистка и консолидация, повышение производительности и улучшение. Все это происходило постепенно, подробнее см. "),t("a",b,[e("VLESS Changes"),o(s)]),e(".")]),L,t("p",null,[e('По сравнению с VMess, в VLESS достаточно заменить security на encryption, а disableInsecureEncryption на decryption, чтобы решить все проблемы. В настоящее время encryption и decryption принимают только значение "none" и не могут быть пустыми (даже если в будущем будет добавлена проверка безопасности соединения), подробнее см. '),t("a",E,[e("документацию по настройке VLESS"),o(s)]),e(". Encryption не нужно перемещать на уровень выше, во-первых, потому что это не позволит повторно использовать много кода, во-вторых, потому что это повлияет на степень контроля, что станет понятно в будущем.")]),g,y,m,q,t("p",null,[t("a",T,[e("XUDP: VLESS & VMess & Mux UDP FullCone NAT"),o(s)])]),x,t("p",null,[e("Спасибо "),A,e(),t("a",M,[e("@DuckSoft"),o(s)]),e(" за предложение!")]),t("p",null,[e("Подробнее см. "),t("a",U,[e("Предложение по стандарту общих ссылок VMessAEAD / VLESS"),o(s)])])])}const D=h(l,[["render",P],["__file","vless.html.vue"]]);export{D as default}; +import{_ as h,r as n,o as c,c as d,a as o,b as t,d as e,e as r}from"./app-Dp4t6tDQ.js";const l={},p=r('

                                      Протокол VLESS

                                      VLESS - это легковесный, не сохраняющий состояние транспортный протокол, который может служить мостом между клиентом и сервером Xray.

                                      Запрос и ответ

                                      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=t("p",null,'Я всегда считал, что "аутентификация ответа" не является обязательной. В версии ALPHA для повышения производительности генерации случайных чисел мы заменили crypto/rand на math/rand, а теперь в этом нет необходимости.',-1),S=t("p",null,'"Версия протокола" не только выполняет функцию "аутентификации ответа", но и дает VLESS возможность безболезненно обновлять структуру протокола, открывая бесконечные возможности. "Версия протокола" во всех бета-версиях равна 0, в официальной версии - 1, а в будущем, если будут несовместимые изменения в структуре протокола, версия должна быть обновлена.',-1),_=t("p",null,"Сервер VLESS спроектирован по принципу switch version, то есть он одновременно поддерживает все версии VLESS. Если требуется обновить версию протокола (что маловероятно), рекомендуется сначала добавить поддержку на сервере за месяц до обновления клиентов. Запрос VMess также имеет версию протокола, но его информация для аутентификации находится снаружи, а часть с командой сильно связана и имеет фиксированное шифрование, что делает версию протокола внутри бессмысленной. Сервер также не проверяет ее, а ответ не имеет версии протокола. В структуре протокола Trojan нет версии протокола.",-1),f=t("p",null,"Далее идет UUID. Сначала я думал, что 16 байт - это многовато, и подумывал о его сокращении, но потом увидел, что Trojan использует 56 печатаемых символов (56 байт), и полностью отказался от этой идеи. Сервер каждый раз проверяет UUID, поэтому производительность также важна: валидатор VLESS прошел через несколько рефакторингов/обновлений, он очень прост и потребляет мало ресурсов по сравнению с VMess, может одновременно поддерживать очень большое количество пользователей, имеет очень высокую производительность и очень высокую скорость проверки (sync.Map). Динамическое добавление и удаление пользователей через API еще более эффективно и плавно. https://github.com/XTLS/Xray-core/issues/158",-1),V=t("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 по сути делает именно это, и накладные расходы минимальны. Склеенные байты очень компактны, практически не отличаются от решения в ALPHA. Желающие могут вывести их и сравнить.

                                      Чтобы указать различный уровень поддержки дополнительной информации (Addons, которые можно рассматривать как плагины, в будущем их может быть много), в следующей бета-версии перед "длиной дополнительной информации" будет добавлена "версия дополнительной информации". 256 - 1 = 255 байт - это достаточно и разумно (65535 - это слишком много, и кто-то может злонамеренно заполнить их), существующие используют только десятую часть, и в будущем не будет такого количества дополнительной информации, а в большинстве случаев дополнительная информация вообще отсутствует. Если этого действительно не хватит, можно обновить версию VLESS.

                                      Чтобы сократить накладные расходы на логические проверки и т.д., Addons пока не будут использовать многоуровневую структуру. Месяц назад появилась идея "изменяемого формата протокола", pb может переставлять поля, но в этом нет необходимости, поскольку современное шифрование не позволяет стороннему наблюдателю увидеть, что заголовки двух передач одинаковы.

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

                                      Schedulers Flow

                                      Предварительное китайское название: Планировщик трафика (обновление от 03.09.2020: официальное китайское название - "Управление потоком"). Команда передается через ProtoBuf и управляет частью данных.

                                      Я обнаружил, что оригинальная "обфускация метаданных" shake в VMess не вносит никаких значимых изменений при использовании TLS, а только снижает производительность, поэтому в VLESS от нее отказались. Кроме того, термин "обфускация" может быть неверно истолкован как маскировка, поэтому от него тоже отказались. Кстати, я всегда скептически относился к маскировке: если она не может быть полностью идентичной, то это же явная сигнатура? А если может быть полностью идентичной, то почему бы не использовать саму маскировку? Сначала я использовал SSR, но потом понял, что он маскирует трафик только для провайдера, и больше им не пользовался.

                                      Так какую же проблему решает "Планировщик трафика"? Он влияет на макроскопические временные характеристики трафика, а не на микроскопические, которые должны решаться шифрованием. Временные характеристики трафика могут быть обусловлены протоколом, например, рукопожатием Socks5 при использовании Socks5 over TLS. Для наблюдателя различные временные характеристики в TLS соответствуют разным протоколам, поэтому бесконечное количество планировщиков эквивалентно бесконечному количеству протоколов (перераспределение размера отправляемых данных и т.д.). Временные характеристики трафика также могут быть обусловлены поведением, например, сколько файлов загружается при посещении главной страницы Google, в каком порядке и какого размера. Добавление еще одного уровня шифрования не может эффективно скрыть эту информацию.

                                      Schedulers не нужно располагать снаружи, как Encryption, поскольку небольшое количество данных в заголовке ничтожно мало по сравнению с объемом данных, которые следуют за ними.

                                      В BETA 2 планируется выпустить два базовых планировщика: сжатие 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=t("p",null,'Поддерживаются два типа шифрования: одно - полностью независимое шифрование, требующее дополнительного пароля, подходит для личного использования, другое - шифрование с использованием существующего UUID, подходит для общего использования. (Если используется первый тип шифрования и пароль раскрывается каким-либо образом, например, при совместном использовании несколькими людьми, то атака "человек посередине" не за горами.) Переработанный динамический порт может быть выпущен вместе с шифрованием, команда будет передаваться через ProtoBuf, реализация будет отличаться от динамического порта VMess.',-1),y=t("p",null,'Добавить готовое шифрование довольно просто, нужно добавить всего лишь один уровень writer & reader. В BETA 3 планируется добавить поддержку aes-128-gcm и chacha20-ietf-poly1305 из SS: в encryption на клиенте можно указать "auto: ss_aes-128-gcm_0_123456, ss_chacha20-ietf-poly1305_0_987654", auto выберет наиболее подходящий для текущей машины, 0 означает бета-версию, а в конце указывается пароль. В decryption на сервере указывается аналогичная строка, и при получении запроса сервер будет пытаться расшифровать его с помощью каждого указанного метода.',-1),m=t("p",null,'Не все комбинации нужно перебирать: шифрование в VMess состоит из трех частей, первая часть - это информация для аутентификации, которая включает UUID, alterId и временной фактор, вторая часть - это часть с командой, которая шифруется с помощью фиксированного алгоритма, команда содержит информацию об алгоритме шифрования, используемом для части с данными, третья часть - это сами данные. Как видно, VMess фактически использует шифрование "многие ко одному" (адаптация на стороне сервера), а не просто шифрование с помощью UUID. Но шифрование только с помощью UUID тоже довольно сложно, и в ближайшее время оно не будет реализовано, учитывая, что у нас уже есть VMessAEAD. Если в VLESS будет реализован способ шифрования с помощью UUID, это будет означать переработку всего VMess.',-1),q=t("h2",{id:"проблемы-с-udp",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#проблемы-с-udp"},[t("span",null,"Проблемы с UDP")])],-1),T={href:"https://github.com/XTLS/Xray-core/discussions/252",target:"_blank",rel:"noopener noreferrer"},x=r('

                                      Руководство по разработке клиентов

                                      1. Протокол VLESS сам по себе будет обновляться несовместимым образом, но параметры конфигурации клиента в основном будут только добавляться. Реализация протокола в iOS-клиенте должна обновляться соответствующим образом.
                                      2. Визуальный стандарт: используйте VLESS в качестве идентификатора в пользовательском интерфейсе, а не VLess / Vless / vless. Настройки в файле конфигурации не затрагиваются, в коде используйте естественный стиль.
                                      3. encryption должен быть реализован в виде текстового поля, а не выпадающего списка. Значение по умолчанию для новых настроек должно быть none. Если пользователь оставит поле пустым, туда должно быть автоматически подставлено none.

                                      Стандарт общих ссылок VLESS

                                      ',3),A=t("img",{src:"https://avatars2.githubusercontent.com/u/7822648?s=32",width:"32px",height:"32px",alt:"a"},null,-1),M={href:"https://github.com/DuckSoft",target:"_blank",rel:"noopener noreferrer"},U={href:"https://github.com/XTLS/Xray-core/issues/91",target:"_blank",rel:"noopener noreferrer"};function P(v,B){const a=n("I18nTip"),s=n("ExternalLinkIcon");return c(),d("div",null,[o(a),p,t("blockquote",null,[t("p",null,[e('"Аутентификация ответа" была заменена на "версию протокола" и перемещена в начало, что позволяет VLESS обновляться, одновременно устраняя накладные расходы на генерацию псевдослучайных чисел. Структура, связанная с обфускацией, была заменена на дополнительную информацию (ProtoBuf) и перемещена вперед, что придало самому протоколу расширяемость с минимальными накладными расходами ('),t("a",i,[e("gogo/protobuf"),o(s)]),e("). Если нет дополнительной информации, то нет и связанных с ней накладных расходов.")])]),u,S,_,f,V,t("p",null,[e("В целом, изменения от ALPHA 2 до BETA в основном заключаются в следующем: эволюция структуры, очистка и консолидация, повышение производительности и улучшение. Все это происходило постепенно, подробнее см. "),t("a",b,[e("VLESS Changes"),o(s)]),e(".")]),L,t("p",null,[e('По сравнению с VMess, в VLESS достаточно заменить security на encryption, а disableInsecureEncryption на decryption, чтобы решить все проблемы. В настоящее время encryption и decryption принимают только значение "none" и не могут быть пустыми (даже если в будущем будет добавлена проверка безопасности соединения), подробнее см. '),t("a",E,[e("документацию по настройке VLESS"),o(s)]),e(". Encryption не нужно перемещать на уровень выше, во-первых, потому что это не позволит повторно использовать много кода, во-вторых, потому что это повлияет на степень контроля, что станет понятно в будущем.")]),g,y,m,q,t("p",null,[t("a",T,[e("XUDP: VLESS & VMess & Mux UDP FullCone NAT"),o(s)])]),x,t("p",null,[e("Спасибо "),A,e(),t("a",M,[e("@DuckSoft"),o(s)]),e(" за предложение!")]),t("p",null,[e("Подробнее см. "),t("a",U,[e("Предложение по стандарту общих ссылок VMessAEAD / VLESS"),o(s)])])])}const D=h(l,[["render",P],["__file","vless.html.vue"]]);export{D as default}; diff --git a/assets/vless.html-XxiZb3rA.js b/assets/vless.html-Cn6zw_0I.js similarity index 99% rename from assets/vless.html-XxiZb3rA.js rename to assets/vless.html-Cn6zw_0I.js index 6965010bc..cd97a3add 100644 --- a/assets/vless.html-XxiZb3rA.js +++ b/assets/vless.html-Cn6zw_0I.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-BClOOpdM.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-Dp4t6tDQ.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-BIa__9by.js b/assets/vless.html-CtLVfJjP.js
                                      similarity index 99%
                                      rename from assets/vless.html-BIa__9by.js
                                      rename to assets/vless.html-CtLVfJjP.js
                                      index 6038f4cd1..1ae388b55 100644
                                      --- a/assets/vless.html-BIa__9by.js
                                      +++ b/assets/vless.html-CtLVfJjP.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-BClOOpdM.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-Dp4t6tDQ.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-CAkNmt00.js b/assets/vless.html-CzthPHZp.js
                                      similarity index 99%
                                      rename from assets/vless.html-CAkNmt00.js
                                      rename to assets/vless.html-CzthPHZp.js
                                      index 764fdfd97..999b70b0b 100644
                                      --- a/assets/vless.html-CAkNmt00.js
                                      +++ b/assets/vless.html-CzthPHZp.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-BClOOpdM.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 или 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-Dp4t6tDQ.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 или REALITY.")],-1),v=n("p",null,"VLESS - это легкий транспортный протокол без сохранения состояния, который разделен на входящую и исходящую части и может служить мостом между клиентом и сервером Xray.",-1),q=l(`

                                      InboundConfigurationObject

                                      {
                                         "clients": [
                                           {
                                             "id": "5783a3e7-e373-51cd-8642-c83782b807c5",
                                      diff --git a/assets/vless.html-HGlcHtRy.js b/assets/vless.html-DDvmOZHh.js
                                      similarity index 99%
                                      rename from assets/vless.html-HGlcHtRy.js
                                      rename to assets/vless.html-DDvmOZHh.js
                                      index 5ad018b88..af08a5d33 100644
                                      --- a/assets/vless.html-HGlcHtRy.js
                                      +++ b/assets/vless.html-DDvmOZHh.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-BClOOpdM.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-Dp4t6tDQ.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-bxJgGdM4.js b/assets/vless.html-DTd56s9M.js similarity index 99% rename from assets/vless.html-bxJgGdM4.js rename to assets/vless.html-DTd56s9M.js index 204545161..3466dd1dd 100644 --- a/assets/vless.html-bxJgGdM4.js +++ b/assets/vless.html-DTd56s9M.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-BClOOpdM.js";const d={},v=s("h1",{id:"vless-xtls-vision-seed",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#vless-xtls-vision-seed"},[s("span",null,"VLESS(XTLS Vision Seed)")])],-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-Dp4t6tDQ.js";const d={},v=s("h1",{id:"vless-xtls-vision-seed",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#vless-xtls-vision-seed"},[s("span",null,"VLESS(XTLS Vision Seed)")])],-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-DMOzaFBW.js b/assets/vless.html-a9Jkze9g.js
                                      similarity index 99%
                                      rename from assets/vless.html-DMOzaFBW.js
                                      rename to assets/vless.html-a9Jkze9g.js
                                      index 1220d2d47..7c457ebd1 100644
                                      --- a/assets/vless.html-DMOzaFBW.js
                                      +++ b/assets/vless.html-a9Jkze9g.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-BClOOpdM.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-Dp4t6tDQ.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/vmess.html-B0GECYM-.js b/assets/vmess.html-BcLHSwPd.js
                                      similarity index 99%
                                      rename from assets/vmess.html-B0GECYM-.js
                                      rename to assets/vmess.html-BcLHSwPd.js
                                      index 4b1fe824c..9d14868e2 100644
                                      --- a/assets/vmess.html-B0GECYM-.js
                                      +++ b/assets/vmess.html-BcLHSwPd.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-BClOOpdM.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-Dp4t6tDQ.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-tXOkY5oD.js b/assets/vmess.html-CH8R4M0b.js
                                      similarity index 99%
                                      rename from assets/vmess.html-tXOkY5oD.js
                                      rename to assets/vmess.html-CH8R4M0b.js
                                      index 6aa8cfd21..8c65d2c7f 100644
                                      --- a/assets/vmess.html-tXOkY5oD.js
                                      +++ b/assets/vmess.html-CH8R4M0b.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-BClOOpdM.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-Dp4t6tDQ.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-BGyxKyme.js b/assets/vmess.html-CM0l5E2w.js
                                      similarity index 99%
                                      rename from assets/vmess.html-BGyxKyme.js
                                      rename to assets/vmess.html-CM0l5E2w.js
                                      index 6d8fcb04c..e84994b45 100644
                                      --- a/assets/vmess.html-BGyxKyme.js
                                      +++ b/assets/vmess.html-CM0l5E2w.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-BClOOpdM.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-Dp4t6tDQ.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/vmess.html-1xnKx21Y.js b/assets/vmess.html-CX4bhZ0G.js
                                      similarity index 99%
                                      rename from assets/vmess.html-1xnKx21Y.js
                                      rename to assets/vmess.html-CX4bhZ0G.js
                                      index 86f3c13ce..959fe3b35 100644
                                      --- a/assets/vmess.html-1xnKx21Y.js
                                      +++ b/assets/vmess.html-CX4bhZ0G.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-BClOOpdM.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-Dp4t6tDQ.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-Ds0K_f_h.js b/assets/vmess.html-CZoqmIbf.js similarity index 99% rename from assets/vmess.html-Ds0K_f_h.js rename to assets/vmess.html-CZoqmIbf.js index a7e296b46..5338f4e05 100644 --- a/assets/vmess.html-Ds0K_f_h.js +++ b/assets/vmess.html-CZoqmIbf.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-BClOOpdM.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-Dp4t6tDQ.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-CFNH9JT0.js b/assets/vmess.html-D6aAfTYm.js
                                      similarity index 99%
                                      rename from assets/vmess.html-CFNH9JT0.js
                                      rename to assets/vmess.html-D6aAfTYm.js
                                      index 8f4bbdf4b..5bc5adc69 100644
                                      --- a/assets/vmess.html-CFNH9JT0.js
                                      +++ b/assets/vmess.html-D6aAfTYm.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-BClOOpdM.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-Dp4t6tDQ.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-Dnj-lkRC.js b/assets/vmess.html-DShhxEZz.js
                                      similarity index 99%
                                      rename from assets/vmess.html-Dnj-lkRC.js
                                      rename to assets/vmess.html-DShhxEZz.js
                                      index e6af0e3f2..927495dec 100644
                                      --- a/assets/vmess.html-Dnj-lkRC.js
                                      +++ b/assets/vmess.html-DShhxEZz.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-BClOOpdM.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-Dp4t6tDQ.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-CSZyIFqN.js b/assets/vmess.html-hbK08lZx.js similarity index 99% rename from assets/vmess.html-CSZyIFqN.js rename to assets/vmess.html-hbK08lZx.js index 7052f3773..5563938ab 100644 --- a/assets/vmess.html-CSZyIFqN.js +++ b/assets/vmess.html-hbK08lZx.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-BClOOpdM.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-Dp4t6tDQ.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-D1_Hwxuj.js b/assets/vmess.html-iOLQROgD.js
                                      similarity index 99%
                                      rename from assets/vmess.html-D1_Hwxuj.js
                                      rename to assets/vmess.html-iOLQROgD.js
                                      index f84018fb2..7da41510b 100644
                                      --- a/assets/vmess.html-D1_Hwxuj.js
                                      +++ b/assets/vmess.html-iOLQROgD.js
                                      @@ -1 +1 @@
                                      -import{_ as n,r as a,o as s,c as r,a as e,b as t,d as l,e as h}from"./app-BClOOpdM.js";const o={},p=h('

                                      Протокол VMess

                                      VMess - это зашифрованный транспортный протокол, который может служить мостом между клиентом и сервером Xray.

                                      Версия

                                      Текущая версия протокола - 1.

                                      Зависимости

                                      Базовый протокол

                                      VMess - это протокол, основанный на TCP, все данные передаются по TCP.

                                      Идентификатор пользователя

                                      ',8),u={href:"https://en.wikipedia.org/wiki/Universally_unique_identifier",target:"_blank",rel:"noopener noreferrer"},c={href:"https://www.uuidgenerator.net/",target:"_blank",rel:"noopener noreferrer"},b=t("p",null,[l("Идентификатор пользователя можно указать в "),t("a",{href:"../../config"},"файле конфигурации"),l(".")],-1),_=t("h3",{id:"функции",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#функции"},[t("span",null,"Функции")])],-1),x={href:"https://en.wikipedia.org/wiki/MD5",target:"_blank",rel:"noopener noreferrer"},M=t("ul",null,[t("li",null,"Входные данные: массив байтов произвольной длины"),t("li",null,"Выходные данные: массив из 16 байтов")],-1),f={href:"https://en.wikipedia.org/wiki/Hash-based_message_authentication_code",target:"_blank",rel:"noopener noreferrer"},k=t("ul",null,[t("li",null,[l("Входные данные: "),t("ul",null,[t("li",null,"H: хэш-функция"),t("li",null,"K: ключ, массив байтов произвольной длины"),t("li",null,"M: сообщение, массив байтов произвольной длины")])])],-1),C={href:"https://en.wikipedia.org/wiki/SHA-3",target:"_blank",rel:"noopener noreferrer"},y=t("ul",null,[t("li",null,"Входные данные: строка произвольной длины"),t("li",null,"Выходные данные: строка произвольной длины")],-1),V=h('

                                      Процесс коммуникации

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

                                      Клиент VMess отправляет запрос, а сервер проверяет, исходит ли этот запрос от легитимного клиента. Если проверка пройдена, сервер пересылает запрос и отправляет полученный ответ клиенту.

                                      VMess использует асимметричный формат, то есть запрос, отправляемый клиентом, и ответ сервера имеют разные форматы.

                                      Запрос клиента

                                      16 байтX байтОставшаяся часть
                                      Информация для аутентификацииЧасть с командойЧасть с данными

                                      Информация для аутентификации

                                      Информация для аутентификации - это 16-байтовое хэш-значение, которое вычисляется следующим образом:

                                      • H = MD5
                                      • K = идентификатор пользователя (16 байт)
                                      • M = время UTC с точностью до секунды, случайное значение в диапазоне ±30 секунд от текущего времени (8 байт, Big Endian)
                                      • Hash = HMAC(H, K, M)

                                      Часть с командой

                                      Часть с командой шифруется с помощью AES-128-CFB:

                                      • Ключ: MD5(идентификатор пользователя + []byte('c48619fe-8f02-49e0-b9e9-edf763e17e21'))
                                      • Вектор инициализации: 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Вектор инициализации для шифрования данныхКлюч для шифрования данныхАутентификация ответа VОпция OptОстаток PМетод шифрования SecЗарезервированоКоманда CmdПорт PortТип адреса TАдрес AСлучайные данныеКонтрольная сумма F

                                      Подробности опции Opt: (если бит равен 1, опция включена)

                                      01234567
                                      XXXXXMRS

                                      Где:

                                      • Номер версии Ver: всегда равен 1;
                                      • Вектор инициализации для шифрования данных: случайное значение;
                                      • Ключ для шифрования данных: случайное значение;
                                      • Аутентификация ответа V: случайное значение;
                                      • Опция Opt:
                                        • S (0x01): стандартный формат потока данных (рекомендуется включать);
                                        • R (0x02): клиент ожидает повторного использования TCP-соединения (устарело в Xray 2.23+);
                                          • Действительна только при включенной опции S;
                                        • M (0x04): включить обфускацию метаданных (рекомендуется включать);
                                          • Действительна только при включенной опции S;
                                          • Если эта опция включена, клиент и сервер должны создать два экземпляра Shake: RequestMask = Shake(вектор инициализации для шифрования данных запроса), ResponseMask = Shake(вектор инициализации для шифрования данных ответа).
                                        • 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: хэш FNV1a всей части с командой, кроме F;

                                      Часть с данными

                                      Если 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 фактических данных;
                                        • L - 4 байта: фактические данные;
                                      • AES-128-GCM: ключ - это ключ из части с командой, вектор инициализации = count (2 байта) + IV (10 байт). count начинается с 0 и увеличивается на 1 для каждого пакета данных; IV - это байты с 3 по 12 из вектора инициализации части с командой.
                                        • L - 16 байт: фактические данные;
                                        • 16 байт: данные аутентификации GCM
                                      • ChaCha20-Poly1305: ключ = MD5(ключ из части с командой) + MD5(MD5(ключ из части с командой)), вектор инициализации = count (2 байта) + IV (10 байт). count начинается с 0 и увеличивается на 1 для каждого пакета данных; IV - это байты с 3 по 12 из вектора инициализации части с командой.
                                        • L - 16 байт: фактические данные;
                                        • 16 байт: данные аутентификации Poly1305

                                      Ответ сервера

                                      Данные заголовка ответа шифруются с помощью AES-128-CFB, вектор инициализации - MD5(вектор инициализации для шифрования данных), ключ - MD5(ключ для шифрования данных). Фактические данные ответа зависят от настроек шифрования.

                                      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Идентификатор пользователяAlterIDУровень пользователяВремя действия T

                                      Где:

                                      • Порт Port: номер порта в формате Big Endian;
                                      • Время действия T: количество минут;

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

                                      Примечания

                                      • Для обеспечения обратной совместимости все зарезервированные поля должны иметь значение 0.
                                      ',37);function S(P,m){const d=a("I18nTip"),i=a("ExternalLinkIcon");return s(),r("div",null,[e(d),p,t("p",null,[l("ID эквивалентен "),t("a",u,[l("UUID"),e(i)]),l(" - это 16-байтовое случайное число, которое действует как токен. ID выглядит следующим образом: de305d54-75b4-431b-adb2-eb6b9e546014, он практически полностью случаен и может быть сгенерирован с помощью любого генератора UUID, например "),t("a",c,[l("этого"),e(i)]),l(".")]),b,_,t("ul",null,[t("li",null,[l("MD5: функция "),t("a",x,[l("MD5"),e(i)]),M]),t("li",null,[l("HMAC: функция "),t("a",f,[l("HMAC"),e(i)]),k]),t("li",null,[l("Shake: функция "),t("a",C,[l("SHA3-Shake128"),e(i)]),y])]),V])}const g=n(o,[["render",S],["__file","vmess.html.vue"]]);export{g as default}; +import{_ as n,r as a,o as s,c as r,a as e,b as t,d as l,e as h}from"./app-Dp4t6tDQ.js";const o={},p=h('

                                      Протокол VMess

                                      VMess - это зашифрованный транспортный протокол, который может служить мостом между клиентом и сервером Xray.

                                      Версия

                                      Текущая версия протокола - 1.

                                      Зависимости

                                      Базовый протокол

                                      VMess - это протокол, основанный на TCP, все данные передаются по TCP.

                                      Идентификатор пользователя

                                      ',8),u={href:"https://en.wikipedia.org/wiki/Universally_unique_identifier",target:"_blank",rel:"noopener noreferrer"},c={href:"https://www.uuidgenerator.net/",target:"_blank",rel:"noopener noreferrer"},b=t("p",null,[l("Идентификатор пользователя можно указать в "),t("a",{href:"../../config"},"файле конфигурации"),l(".")],-1),_=t("h3",{id:"функции",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#функции"},[t("span",null,"Функции")])],-1),x={href:"https://en.wikipedia.org/wiki/MD5",target:"_blank",rel:"noopener noreferrer"},M=t("ul",null,[t("li",null,"Входные данные: массив байтов произвольной длины"),t("li",null,"Выходные данные: массив из 16 байтов")],-1),f={href:"https://en.wikipedia.org/wiki/Hash-based_message_authentication_code",target:"_blank",rel:"noopener noreferrer"},k=t("ul",null,[t("li",null,[l("Входные данные: "),t("ul",null,[t("li",null,"H: хэш-функция"),t("li",null,"K: ключ, массив байтов произвольной длины"),t("li",null,"M: сообщение, массив байтов произвольной длины")])])],-1),C={href:"https://en.wikipedia.org/wiki/SHA-3",target:"_blank",rel:"noopener noreferrer"},y=t("ul",null,[t("li",null,"Входные данные: строка произвольной длины"),t("li",null,"Выходные данные: строка произвольной длины")],-1),V=h('

                                      Процесс коммуникации

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

                                      Клиент VMess отправляет запрос, а сервер проверяет, исходит ли этот запрос от легитимного клиента. Если проверка пройдена, сервер пересылает запрос и отправляет полученный ответ клиенту.

                                      VMess использует асимметричный формат, то есть запрос, отправляемый клиентом, и ответ сервера имеют разные форматы.

                                      Запрос клиента

                                      16 байтX байтОставшаяся часть
                                      Информация для аутентификацииЧасть с командойЧасть с данными

                                      Информация для аутентификации

                                      Информация для аутентификации - это 16-байтовое хэш-значение, которое вычисляется следующим образом:

                                      • H = MD5
                                      • K = идентификатор пользователя (16 байт)
                                      • M = время UTC с точностью до секунды, случайное значение в диапазоне ±30 секунд от текущего времени (8 байт, Big Endian)
                                      • Hash = HMAC(H, K, M)

                                      Часть с командой

                                      Часть с командой шифруется с помощью AES-128-CFB:

                                      • Ключ: MD5(идентификатор пользователя + []byte('c48619fe-8f02-49e0-b9e9-edf763e17e21'))
                                      • Вектор инициализации: 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Вектор инициализации для шифрования данныхКлюч для шифрования данныхАутентификация ответа VОпция OptОстаток PМетод шифрования SecЗарезервированоКоманда CmdПорт PortТип адреса TАдрес AСлучайные данныеКонтрольная сумма F

                                      Подробности опции Opt: (если бит равен 1, опция включена)

                                      01234567
                                      XXXXXMRS

                                      Где:

                                      • Номер версии Ver: всегда равен 1;
                                      • Вектор инициализации для шифрования данных: случайное значение;
                                      • Ключ для шифрования данных: случайное значение;
                                      • Аутентификация ответа V: случайное значение;
                                      • Опция Opt:
                                        • S (0x01): стандартный формат потока данных (рекомендуется включать);
                                        • R (0x02): клиент ожидает повторного использования TCP-соединения (устарело в Xray 2.23+);
                                          • Действительна только при включенной опции S;
                                        • M (0x04): включить обфускацию метаданных (рекомендуется включать);
                                          • Действительна только при включенной опции S;
                                          • Если эта опция включена, клиент и сервер должны создать два экземпляра Shake: RequestMask = Shake(вектор инициализации для шифрования данных запроса), ResponseMask = Shake(вектор инициализации для шифрования данных ответа).
                                        • 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: хэш FNV1a всей части с командой, кроме F;

                                      Часть с данными

                                      Если 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 фактических данных;
                                        • L - 4 байта: фактические данные;
                                      • AES-128-GCM: ключ - это ключ из части с командой, вектор инициализации = count (2 байта) + IV (10 байт). count начинается с 0 и увеличивается на 1 для каждого пакета данных; IV - это байты с 3 по 12 из вектора инициализации части с командой.
                                        • L - 16 байт: фактические данные;
                                        • 16 байт: данные аутентификации GCM
                                      • ChaCha20-Poly1305: ключ = MD5(ключ из части с командой) + MD5(MD5(ключ из части с командой)), вектор инициализации = count (2 байта) + IV (10 байт). count начинается с 0 и увеличивается на 1 для каждого пакета данных; IV - это байты с 3 по 12 из вектора инициализации части с командой.
                                        • L - 16 байт: фактические данные;
                                        • 16 байт: данные аутентификации Poly1305

                                      Ответ сервера

                                      Данные заголовка ответа шифруются с помощью AES-128-CFB, вектор инициализации - MD5(вектор инициализации для шифрования данных), ключ - MD5(ключ для шифрования данных). Фактические данные ответа зависят от настроек шифрования.

                                      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Идентификатор пользователяAlterIDУровень пользователяВремя действия T

                                      Где:

                                      • Порт Port: номер порта в формате Big Endian;
                                      • Время действия T: количество минут;

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

                                      Примечания

                                      • Для обеспечения обратной совместимости все зарезервированные поля должны иметь значение 0.
                                      ',37);function S(P,m){const d=a("I18nTip"),i=a("ExternalLinkIcon");return s(),r("div",null,[e(d),p,t("p",null,[l("ID эквивалентен "),t("a",u,[l("UUID"),e(i)]),l(" - это 16-байтовое случайное число, которое действует как токен. ID выглядит следующим образом: de305d54-75b4-431b-adb2-eb6b9e546014, он практически полностью случаен и может быть сгенерирован с помощью любого генератора UUID, например "),t("a",c,[l("этого"),e(i)]),l(".")]),b,_,t("ul",null,[t("li",null,[l("MD5: функция "),t("a",x,[l("MD5"),e(i)]),M]),t("li",null,[l("HMAC: функция "),t("a",f,[l("HMAC"),e(i)]),k]),t("li",null,[l("Shake: функция "),t("a",C,[l("SHA3-Shake128"),e(i)]),y])]),V])}const g=n(o,[["render",S],["__file","vmess.html.vue"]]);export{g as default}; diff --git a/assets/warp.html-DgEMK8FR.js b/assets/warp.html-B7-UX_pL.js similarity index 99% rename from assets/warp.html-DgEMK8FR.js rename to assets/warp.html-B7-UX_pL.js index eaa60c13f..3695abbb3 100644 --- a/assets/warp.html-DgEMK8FR.js +++ b/assets/warp.html-B7-UX_pL.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-BClOOpdM.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-Dp4t6tDQ.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-l5rz1Xgi.js b/assets/warp.html-BjjHsRAC.js
                                      similarity index 99%
                                      rename from assets/warp.html-l5rz1Xgi.js
                                      rename to assets/warp.html-BjjHsRAC.js
                                      index ab5944451..b98d19e5b 100644
                                      --- a/assets/warp.html-l5rz1Xgi.js
                                      +++ b/assets/warp.html-BjjHsRAC.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-BClOOpdM.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-Dp4t6tDQ.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-DJ9-KANE.js b/assets/warp.html-D7q1TYSF.js
                                      similarity index 99%
                                      rename from assets/warp.html-DJ9-KANE.js
                                      rename to assets/warp.html-D7q1TYSF.js
                                      index 55835eaee..486982120 100644
                                      --- a/assets/warp.html-DJ9-KANE.js
                                      +++ b/assets/warp.html-D7q1TYSF.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-BClOOpdM.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-Dp4t6tDQ.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-D8U-ZWQv.js b/assets/websocket.html-CER5FpY3.js
                                      similarity index 98%
                                      rename from assets/websocket.html-D8U-ZWQv.js
                                      rename to assets/websocket.html-CER5FpY3.js
                                      index 67673ca6e..aa1e34be4 100644
                                      --- a/assets/websocket.html-D8U-ZWQv.js
                                      +++ b/assets/websocket.html-CER5FpY3.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-BClOOpdM.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-Dp4t6tDQ.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-gylvmC0D.js b/assets/websocket.html-CIfvjdmu.js
                                      similarity index 98%
                                      rename from assets/websocket.html-gylvmC0D.js
                                      rename to assets/websocket.html-CIfvjdmu.js
                                      index 7fee13a5d..53cf43516 100644
                                      --- a/assets/websocket.html-gylvmC0D.js
                                      +++ b/assets/websocket.html-CIfvjdmu.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-BClOOpdM.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-Dp4t6tDQ.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-DUOE6Z_k.js b/assets/websocket.html-tuR9jVHl.js
                                      similarity index 98%
                                      rename from assets/websocket.html-DUOE6Z_k.js
                                      rename to assets/websocket.html-tuR9jVHl.js
                                      index aa53dd398..56f46439e 100644
                                      --- a/assets/websocket.html-DUOE6Z_k.js
                                      +++ b/assets/websocket.html-tuR9jVHl.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-BClOOpdM.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-Dp4t6tDQ.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-B6x6u49u.js b/assets/wireguard.html-B0ggG9X9.js
                                      similarity index 97%
                                      rename from assets/wireguard.html-B6x6u49u.js
                                      rename to assets/wireguard.html-B0ggG9X9.js
                                      index 62a7d80a3..0fc7f4409 100644
                                      --- a/assets/wireguard.html-B6x6u49u.js
                                      +++ b/assets/wireguard.html-B0ggG9X9.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-BClOOpdM.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-Dp4t6tDQ.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-m61ylbO3.js b/assets/wireguard.html-Bh9HPmRj.js
                                      similarity index 99%
                                      rename from assets/wireguard.html-m61ylbO3.js
                                      rename to assets/wireguard.html-Bh9HPmRj.js
                                      index 213cacdbb..534c2954c 100644
                                      --- a/assets/wireguard.html-m61ylbO3.js
                                      +++ b/assets/wireguard.html-Bh9HPmRj.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-BClOOpdM.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-Dp4t6tDQ.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-DfdLmO6b.js b/assets/wireguard.html-DsutH5Up.js
                                      similarity index 97%
                                      rename from assets/wireguard.html-DfdLmO6b.js
                                      rename to assets/wireguard.html-DsutH5Up.js
                                      index 9a1097cb4..696448a37 100644
                                      --- a/assets/wireguard.html-DfdLmO6b.js
                                      +++ b/assets/wireguard.html-DsutH5Up.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-BClOOpdM.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-Dp4t6tDQ.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-X7XXtZyr.js b/assets/wireguard.html-DzgB3EwV.js
                                      similarity index 97%
                                      rename from assets/wireguard.html-X7XXtZyr.js
                                      rename to assets/wireguard.html-DzgB3EwV.js
                                      index e9b05471a..557b68334 100644
                                      --- a/assets/wireguard.html-X7XXtZyr.js
                                      +++ b/assets/wireguard.html-DzgB3EwV.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-BClOOpdM.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-Dp4t6tDQ.js";const i={},c=p(`

                                      Wireguard

                                      User-space Wireguard 协议实现。

                                      警告

                                      Wireguard 协议并非专门为翻墙而设计,若在最外层过墙,存在特征可能导致服务器被封锁

                                      InboundConfigurationObject

                                      {
                                         "secretKey": "PRIVATE_KEY",
                                         "peers": [
                                           {
                                      diff --git a/assets/wireguard.html-BJuFKWp0.js b/assets/wireguard.html-UyKFaqMG.js
                                      similarity index 99%
                                      rename from assets/wireguard.html-BJuFKWp0.js
                                      rename to assets/wireguard.html-UyKFaqMG.js
                                      index c7892fdbd..d43474a70 100644
                                      --- a/assets/wireguard.html-BJuFKWp0.js
                                      +++ b/assets/wireguard.html-UyKFaqMG.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-BClOOpdM.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-Dp4t6tDQ.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-C7d91cx3.js b/assets/wireguard.html-Z-rjO2wB.js
                                      similarity index 99%
                                      rename from assets/wireguard.html-C7d91cx3.js
                                      rename to assets/wireguard.html-Z-rjO2wB.js
                                      index d87e75954..d6c630021 100644
                                      --- a/assets/wireguard.html-C7d91cx3.js
                                      +++ b/assets/wireguard.html-Z-rjO2wB.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-BClOOpdM.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-Dp4t6tDQ.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-0lRGF5LV.js b/assets/work.html-C0sVGft-.js
                                      similarity index 98%
                                      rename from assets/work.html-0lRGF5LV.js
                                      rename to assets/work.html-C0sVGft-.js
                                      index 7ffb23606..343748e7d 100644
                                      --- a/assets/work.html-0lRGF5LV.js
                                      +++ b/assets/work.html-C0sVGft-.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-BClOOpdM.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-Dp4t6tDQ.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-CLfkotRL.js b/assets/work.html-CWo8pB56.js
                                      similarity index 98%
                                      rename from assets/work.html-CLfkotRL.js
                                      rename to assets/work.html-CWo8pB56.js
                                      index 9aa172474..337639ce1 100644
                                      --- a/assets/work.html-CLfkotRL.js
                                      +++ b/assets/work.html-CWo8pB56.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-BClOOpdM.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-Dp4t6tDQ.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-LiUJgLuE.js b/assets/work.html-ClRD37Fr.js
                                      similarity index 98%
                                      rename from assets/work.html-LiUJgLuE.js
                                      rename to assets/work.html-ClRD37Fr.js
                                      index 7ffb23606..343748e7d 100644
                                      --- a/assets/work.html-LiUJgLuE.js
                                      +++ b/assets/work.html-ClRD37Fr.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-BClOOpdM.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-Dp4t6tDQ.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-DkBmDiCN.js b/assets/xtls.html-DG8Gu1K9.js
                                      similarity index 79%
                                      rename from assets/xtls.html-DkBmDiCN.js
                                      rename to assets/xtls.html-DG8Gu1K9.js
                                      index c67744611..c83fa4735 100644
                                      --- a/assets/xtls.html-DkBmDiCN.js
                                      +++ b/assets/xtls.html-DG8Gu1K9.js
                                      @@ -1 +1 @@
                                      -import{_ as t,r as o,o as l,c as r,a as n,b as e}from"./app-BClOOpdM.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-Dp4t6tDQ.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-hZzXSvQP.js b/assets/xtls.html-DW7qpfS8.js
                                      similarity index 83%
                                      rename from assets/xtls.html-hZzXSvQP.js
                                      rename to assets/xtls.html-DW7qpfS8.js
                                      index 03ffb2895..f442cd226 100644
                                      --- a/assets/xtls.html-hZzXSvQP.js
                                      +++ b/assets/xtls.html-DW7qpfS8.js
                                      @@ -1 +1 @@
                                      -import{_ as a,r as t,o as c,c as l,a as n,b as e}from"./app-BClOOpdM.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-Dp4t6tDQ.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-BjuGNIe7.js b/assets/xtls.html-NZ56bZ_i.js
                                      similarity index 77%
                                      rename from assets/xtls.html-BjuGNIe7.js
                                      rename to assets/xtls.html-NZ56bZ_i.js
                                      index 77cd723cb..56ba91e71 100644
                                      --- a/assets/xtls.html-BjuGNIe7.js
                                      +++ b/assets/xtls.html-NZ56bZ_i.js
                                      @@ -1 +1 @@
                                      -import{_ as a,r as t,o as c,c as l,a as n,b as e}from"./app-BClOOpdM.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-Dp4t6tDQ.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-LESROZAQ-BnJ8kkeI.js b/assets/xychartDiagram-LESROZAQ-CAWMdezr.js
                                      similarity index 99%
                                      rename from assets/xychartDiagram-LESROZAQ-BnJ8kkeI.js
                                      rename to assets/xychartDiagram-LESROZAQ-CAWMdezr.js
                                      index 40be62fa4..2fbf8e6a7 100644
                                      --- a/assets/xychartDiagram-LESROZAQ-BnJ8kkeI.js
                                      +++ b/assets/xychartDiagram-LESROZAQ-CAWMdezr.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-IUatkdtb.js";import{i as Si}from"./init-Gi6I4Gst.js";import{o as _i}from"./ordinal-Cboi1Yqb.js";import{l as Wt}from"./linear-CAdJTZmH.js";import"./app-BClOOpdM.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-VsNG6kTl.js";import{i as Si}from"./init-Gi6I4Gst.js";import{o as _i}from"./ordinal-Cboi1Yqb.js";import{l as Wt}from"./linear-S87t6Dgt.js";import"./app-Dp4t6tDQ.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 30c528f2e..9d9fb7501 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 4a7dc0cd8..6218dde7e 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 地址(字符串形式)和 DnsServerObject 。

                                      当值为 "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 b55118bf2..24ce85b26 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 86b480b55..4f56b2ddf 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 6459dc793..98b7f6bc2 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 0a4803478..6e4191188 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 61c187fdc..137f0b1f9 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 bb83628ad..7580190d4 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 1a4f3f795..5c5e66bd3 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 af7e59812..099f6cc91 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 b93b5b1ab..ba45fb093 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 43da34c25..cc5de14a0 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 d4d34bf8a..85be4d5b9 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 a1494f300..85203864d 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 ac205168b..ffc9a55b6 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 a01e96bec..cd1bf866e 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 9393461d3..914e633c3 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 72355abcd..149f1b87f 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 4d2572ae2..685f3d4e0 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: "quarter" | "half" | "full"

                                      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 390d7783b..787a0c20d 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 440654acb..8dc77ca2f 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 48d5c97b2..234e0a699 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 f83e38457..0ec5e27b2 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 86936a874..1d568931b 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 a40479243..df2b378a3 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 黑名单。

                                      "length""interval" 均为 Int32Range 类型

                                      "packets":支持两种分片方式 "1-3" 是 TCP 的流切片,应用于客户端第 1 至第 3 次写数据。"tlshello" 是 TLS 握手包切片。

                                      "length":分片包长 (byte)

                                      "interval":分片间隔(ms)

                                      当其为 0 且设置 "packets": "tlshello" 时,被分片的 Client Hello 将会在一个TCP包中发送(如果其原始大小未超过MSS或MTU导致被系统自动分片)

                                      noises: 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": 延迟,单位毫秒。发送该噪声包后核心会等待该时间后再发送下一个噪声包或真实数据,默认不等待,为 Int32Range 类型

                                      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 d18d4647c..cc467df92 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 509451dff..73d0eb577 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 078fbe69e..5b2639227 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 c5cd3cf99..d53440027 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 8589995fa..2e3489177 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 5b6841ff8..c32f35bf0 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 19d083ecd..85a73675f 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 efff21c64..bfd4a9989 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 6eda8f1bb..8a63772ed 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 790877b46..606c503bb 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 ec220800d..45cd8b735 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 8a96779cc..978f831fc 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 1219f7ccd..2c810fed6 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 来进行一些传输的配置。

                                      {
                                      @@ -174,6 +174,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, Cyc0der, Daniel Ding, Kobe Arthur Scofield, KoriIku, Lumière Élevé, Mikhail Samodurov, Nikita Korotaev, WaterLemons2k, Winston2084, Yang Lu, chika0801, flowerinsnow, lelemka0, lxsq, mayampi01, pvqogw
                                      - + diff --git a/config/transports/grpc.html b/config/transports/grpc.html index fcae12ba0..c8c9fa73d 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/http.html b/config/transports/http.html index 85d03546f..d9e5826e3 100644 --- a/config/transports/http.html +++ b/config/transports/http.html @@ -24,8 +24,8 @@ HTTP | Project X - - + +

                                      HTTP

                                      基于 HTTP/2 或 HTTP/3 的传输方式。

                                      它完整按照 HTTP 标准实现,可以通过其它的 HTTP 服务器(如 Nginx)进行中转。

                                      客户端必须开启 TLS 才可以正常使用这个传输方式。

                                      HTTP/2和3 内置多路复用,不建议使用时启用 mux.cool。

                                      提示

                                      当前版本的 HTTP/2 的传输方式并不强制要求入站服务端)有 TLS 配置. 这使得可以在特殊用途的分流部署环境中,由外部网关组件完成 TLS 层对话,Xray 作为后端应用,网关和 Xray 间使用明文HTTP进行通讯。

                                      提示

                                      当alpn有且仅有 h3 时,该传输才会工作在h3模式。

                                      注意

                                      • HTTP/2 和 HTTP/3 无法通过xray的回落 Path 进行分流,不建议使用回落分流。

                                      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 8bb6d34cd..a869bf71a 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 64323970e..ee8fe18f3 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/raw.html b/config/transports/raw.html index 6cfe525e2..e406ceeb4 100644 --- a/config/transports/raw.html +++ b/config/transports/raw.html @@ -24,8 +24,8 @@ RAW | Project X - - + +

                                      RAW

                                      更名自曾经的tcp传输(原名称稍有歧义) RAW传输出站发送的原始数据,核心不使用其他协议(如 websocket)承载其流量。

                                      可以和各种协议有多种组合模式.

                                      RawObject

                                      RawObject 对应传输配置的 rawSettings 项。

                                      {
                                      @@ -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/splithttp.html b/config/transports/splithttp.html index c955f3647..39db0dd53 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 项。

                                      {
                                      @@ -47,12 +47,12 @@
                                         }
                                       }
                                       

                                      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" 每次会在该范围中随机选择一个数字。为 Int32Range 类型

                                      设置为 -1 将完全禁用填充

                                      xmux: XmuxObject

                                      XmuxObject

                                      v24.9.19+

                                      仅客户端,允许用户对 SplitHTTP 在 h2 与 h3 中的多路复用行为进行控制。使用该功能时不要启用 mux.cool。

                                      {
                                      -  "maxConcurrency": 16,
                                      -  "maxConnections": 32,
                                      -  "cMaxReuseTimes": 64,
                                      -  "cMaxLifetimeMs": 128
                                      +  "maxConcurrency": "16-32",
                                      +  "maxConnections": 0,
                                      +  "cMaxReuseTimes": "64-128",
                                      +  "cMaxLifetimeMs": 0
                                       }
                                       

                                      上为全设置为0或者不设置时核心会填入的默认值

                                      术语解释:

                                      • 流会复用物理连接,像这样 连接1(流1,流2,流3) 连接2(流4,流5,流6) .. 以此类推 在其他地方你可能看到 连接-子连接 这样的描述,都是一样的东西。
                                      • 下述所有字段类型均为 为 Int32Range 类型

                                      maxConcurrency: int/string

                                      默认值为 0(即无限) 每个连接中复用的流的最大数量,连接中流的数量达到该值后核心会新建更多连接以容纳更多的流,类似于 mux.cool 的 concurrency.

                                      maxConnections: int/string

                                      默认值为 0(即无限) 要打开的最大连接数,连接达到此值前核心会积极打开连接,对每一条流都新建一个连接,直到达到该值。然后核心会开始复用已经建立的连接。 与 maxConcurrency 冲突。

                                      cMaxReuseTimes: int/string

                                      默认值为 0(即无限) 一个连接最多被复用几次,当达到该值后核心不会向该连接再分配流,其将在内部最后一条流关闭后断开。

                                      cMaxLifetimeMs: int/string

                                      默认值为 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 ab30677a9..ad9f23cf7 100644 --- a/config/transports/tcp.html +++ b/config/transports/tcp.html @@ -24,11 +24,11 @@ TCP | Project X - - + + - + diff --git a/config/transports/websocket.html b/config/transports/websocket.html index c28499618..9df3667b7 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 34c5efc01..146eb27c8 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 e1b71ac08..a8978b29d 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 7b189dfaa..3bd749d98 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 81c3134d6..946da393f 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 子目录。

                                      Int32Range

                                      For end user

                                      一个表示可选范围的值,可以是以下几种写法

                                      -包含在引号里的单独数字或范围

                                      • "" (视为0) 注意部分字段完全不设置和设置为空可能是两种概念
                                      • "114"
                                      • "114-514"

                                      -独立的int,这种情况下只能是单数字

                                      • 114

                                      For dev

                                      如果需要在配置文件中包含范围,请使用 Int32Range 类型

                                      使用 .From 和 .To 获取值,在 From > To 比如 1919-810 时会自动交换数值确保 From 会小于 To, 如果要获取原始值可以用 .Left 和 .Right

                                      - + diff --git a/development/protocols/mkcp.html b/development/protocols/mkcp.html index 7069b27e8..175ae6adf 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 a28421f04..a45765fff 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 70356ab29..6c3e3a08a 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 43dee5926..e2416c24b 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 3f0aa28ce..8d7a34e8d 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 9c142f571..b2ab5761f 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 ba734f1ed..4b666e152 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 494e1e611..9de4dad63 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 700332e23..257e1ffad 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 4e3d51319..6d472a92b 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 6cc83c2e3..7ac3d7eff 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 57e040a23..9eea86e3e 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 7d8ac9f84..a0a873287 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 d8cd9b5be..15cd6526a 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 f324a866c..679fe61b4 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 53fe0f16e..9f867a995 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 e312c7b2c..aa513d33c 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 df712ab6f..66854affa 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 3b8e2c6c2..3e93df403 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 cd125a6b7..5c145b2f1 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 13a645456..87c99bbde 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 ee90d7993..3c6ad3ffc 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 042f77038..e10d762dc 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 fc547763c..a5664549a 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 0d9f40110..e04cf7ef7 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 04c3de8bb..2d24471af 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 a75d79a0f..cbfda5b75 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 eae1a1805..fce232e49 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 a20eec8ab..925dd93f9 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 fcb0a7256..f2c348791 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 d217bb3b5..9ad5eed59 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 9388852f2..348752682 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 9f42778cf..a06a7b670 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 bb2ec8907..25ff34416 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 d4fac5ae6..1b7ed6d95 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 d18f05e8c..9a3b0ebbd 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 d1ba21657..5e1e6fddd 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 DnsServerObjects.

                  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 2b7397b19..5a3f3568f 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 afe828fd2..35193d76b 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 0f08cd349..6f093a9ef 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 afe3a9390..185e2f3c3 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 65a83c2d1..9dd427104 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 7b4173f66..3c13d37d1 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 aa9612192..eb117ca2b 100644 --- a/en/config/inbound.html +++ b/en/config/inbound.html @@ -24,8 +24,8 @@ Inbound Proxy | Project X - - + +

                  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 659996bbe..0dba82e3a 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 5c397a53e..e00f7adce 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 19afae2f7..969b4d1c5 100644 --- a/en/config/inbounds/shadowsocks.html +++ b/en/config/inbounds/shadowsocks.html @@ -24,8 +24,8 @@ Shadowsocks | Project X - - + +

                  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

                  Required, any of the supported methods

                  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 d912e1c00..175f5f869 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 54aa6f4aa..fb1808e5c 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 9c1edb22c..5b3d94b96 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 ab7145d10..cf6ad291a 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 03f4ea29e..5be2712b6 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 bf836d712..d2fe54678 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 c0bad3c92..428fe1029 100644 --- a/en/config/log.html +++ b/en/config/log.html @@ -24,8 +24,8 @@ Log Configuration | Project X - - + +

                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.

                {
                @@ -38,6 +38,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.

                maskAddress: "quarter" | "half" | "full"

                IP address masking, when enabled, will automatically replace the IP address appearing in the log. It is used to protect privacy when sharing logs. The default is empty and is not enabled.

                Currently available levels are quarter, half, full. The mask form corresponds to the following:

                • ipv4 1.2.*.* 1.*.*.* [Masked IPv4]
                • ipv6 1234:5678::/32 1234::/16 [Masked IPv6]
                - + diff --git a/en/config/metrics.html b/en/config/metrics.html index 2f23b8168..7d7ff896b 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 0ac09680f..012181f8a 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 b6600d22a..bf388a80b 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 7d0b23ead..08922ae2f 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 18a8cedd7..186b0b48f 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 8d2114719..70d6cc6c3 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 (5 October 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 260d2b0bf..9d2036cbe 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 8b2c7b9a0..65585b4c9 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 ec532f96e..83ae8a25e 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 7976b3f74..6ba98fb9b 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 bb11744b2..2d6210cf3 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 90d19b63a..dbb5a8776 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 209b36207..704c53b1e 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 1318c4352..3e1d1d763 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 7fcf2dbad..32e5ac39f 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 6d252b433..24fb8688a 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 d78fa456f..bc05b93f8 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 (25 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 556ab4196..557637587 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 8476ffe7a..b75dec74e 100644 --- a/en/config/transport.html +++ b/en/config/transport.html @@ -24,8 +24,8 @@ Transport | Project X - - + +

                Warning

                This translation was modified on 5 October 2024 and an updated version (6 October 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.

                {
                @@ -168,6 +168,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 222c5b5f5..8ac614272 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 70a05944d..3c50ff591 100644 --- a/en/config/transports/h2.html +++ b/en/config/transports/h2.html @@ -24,8 +24,8 @@ HTTP/2 | Project X - - + +

                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/http.html b/en/config/transports/http.html index 844a48291..eafa71a22 100644 --- a/en/config/transports/http.html +++ b/en/config/transports/http.html @@ -24,8 +24,8 @@ HTTP | Project X - - + +

                Notice

                This page has not yet been translated, see how you can help here.

                HTTP

                基于 HTTP/2 或 HTTP/3 的传输方式。

                它完整按照 HTTP 标准实现,可以通过其它的 HTTP 服务器(如 Nginx)进行中转。

                客户端必须开启 TLS 才可以正常使用这个传输方式。

                HTTP/2和3 内置多路复用,不建议使用时启用 mux.cool。

                提示

                当前版本的 HTTP/2 的传输方式并不强制要求入站服务端)有 TLS 配置. 这使得可以在特殊用途的分流部署环境中,由外部网关组件完成 TLS 层对话,Xray 作为后端应用,网关和 Xray 间使用明文HTTP进行通讯。

                提示

                当alpn有且仅有 h3 时,该传输才会工作在h3模式。

                注意

                • HTTP/2 和 HTTP/3 无法通过xray的回落 Path 进行分流,不建议使用回落分流。

                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/en/config/transports/httpupgrade.html b/en/config/transports/httpupgrade.html index d4d3d49bc..ed9f421f1 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 6193f48a5..5b9d1800d 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/raw.html b/en/config/transports/raw.html index 49a202552..00a0f45a7 100644 --- a/en/config/transports/raw.html +++ b/en/config/transports/raw.html @@ -24,8 +24,8 @@ RAW | Project X - - + +

                Notice

                This page has not yet been translated, see how you can help here.

                RAW

                更名自曾经的tcp传输(原名称稍有歧义) RAW传输出站发送的原始数据,核心不使用其他协议(如 websocket)承载其流量。

                可以和各种协议有多种组合模式.

                RawObject

                RawObject 对应传输配置的 rawSettings 项。

                {
                @@ -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/en/config/transports/splithttp.html b/en/config/transports/splithttp.html index 5dc310ce6..5a867562b 100644 --- a/en/config/transports/splithttp.html +++ b/en/config/transports/splithttp.html @@ -24,8 +24,8 @@ SplitHTTP | Project X - - + +

                Warning

                This translation was modified on 23 September 2024 and an updated version (16 October 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.

                {
                @@ -53,6 +53,6 @@
                   "cMaxLifetimeMs": 0
                 }
                 

                Since the default is unlimited reuse, xmux actually limits this. It's not recommended to enable mux.cool at the same time.

                Terminology: Streams will reuse physical connections, as in, one connection can hold many streams. In other places, streams are called sub-connections, they are the same thing.

                maxConcurrency: int | string

                Default 0 = infinite. The maximum number of streams reused in each connection. After the number of streams in the connection reaches this value, the core will create more connections to accommodate more streams, similar to the concurrency of mux.cool. Mutually exclusive with maxConnections.

                maxConnections: int | string

                Default 0 = infinite. The maximum number of connections to open. Every stream will open a new connection until this value is reached, only then connections will be reused. Mutually exclusive with maxConcurrency.

                cMaxReuseTimes: int | string

                Default 0 = infinite. A connection can be reused at most several times. When this value is reached, the core will not allocate streams to the connection. It will be disconnected after the last internal stream is closed.

                cMaxLifetimeMs: int | string

                Default 0 = infinite. How long can a connection "survive" at most? When the connection is open for more than this value, the core will not redistribute streams to the connection, and it will be disconnected after the last internal stream is closed.

                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 0347dc0eb..1c69b655a 100644 --- a/en/config/transports/tcp.html +++ b/en/config/transports/tcp.html @@ -24,8 +24,8 @@ TCP | Project X - - + +

                Warning

                This translation was modified on 28 March 2023 and an updated version (1 October 2024) is available on the source page. View the original page

                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 b393e4aa1..f5c028c7c 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 6580b6a59..30af9a63e 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 63548a0bb..792e5c611 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 76cf36691..c0fda20a0 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 53ed29fd0..d45f7fa3c 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 (5 October 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 6f3ceed00..d72803cdb 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 3c3352815..168c984cb 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 40ec24ff6..94fa83f9f 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 f38eeb82e..5d258f13f 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 c993a2902..3a32e5920 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 c67c6c396..527931025 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 43d716b43..4b6ad0eaf 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 6765674ca..a892d1254 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 19096a00c..450949b29 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 83ba1f911..9dfff982e 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 60a2af00c..cc5175bb0 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 4dab547ba..408ddde05 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 c533af2e8..958bde9a4 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 5384cad4b..638c7178f 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 613f6c7ee..8d7348e7f 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 7a3295504..5c63a273a 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 81e004274..8f735bc99 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 3c75d0ec1..cea2e04c8 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 d2e6a26d5..241b09669 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 9119519ed..2b163fd06 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 @@
             }
           }
           
        3. 至此,我们就能够完整的画出模板的回落路线了:

        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 dfc44b4bc..c8d2fe221 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 4baba1179..eebf7bc71 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 2db4a989d..c83dddf7f 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 a519cb968..59494cbab 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 7275c87ba..9b3c7cb41 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 3221a5277..0650d6323 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 1af6cc8af..43cd35378 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 f7fcd7d1f..007f46966 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 add5e7135..65a2924ee 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 b26163adc..c345f5510 100644 --- a/en/document/level-2/tproxy.html +++ b/en/document/level-2/tproxy.html @@ -24,8 +24,8 @@ TProxy 透明代理 | Project X - - + +

    透明代理(TProxy)配置教程

    Warning

    This translation was modified on 7 March 2023 and an updated version (4 October 2024) is available on the source page. View the original page

    本配置基于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 86c6b710f..ff1a6db3a 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 0c2822076..a26641f50 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 05bb455a4..391395369 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 fa28079c6..70e90bc1e 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 16ea0e9b5..22ee6497f 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 ae1e6cc86..b91454d22 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 a5237ec7a..c8bc34b82 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 af0ea4371..e7f609a0b 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 79897f676..712f5a6a8 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": при запросе доменного имени выполняется сопоставление домена в маршрутизации, если совпадение не найдено, для этого доменного имени используется встроенный DNS-сервер для выполнения DNS-запроса, и возвращенный IP-адрес используется для повторного сопоставления IP-маршрутизации.
    • "IPOnDemand": при обнаружении любого правила на основе IP-адреса доменное имя немедленно разрешается в IP-адрес для сопоставления.
  • Разрешает целевой адрес для подключения.

    • Например, если в исходящем подключении freedom установить domainStrategy равным UseIP, то запросы, отправленные этим исходящим подключением, сначала будут разрешены во встроенном сервере из доменного имени в IP-адрес, а затем будет выполнено подключение.
    • Например, если в sockopt установить domainStrategy равным UseIP, то системные подключения, инициированные этим исходящим подключением, сначала будут разрешены во встроенном сервере из доменного имени в IP-адрес, а затем будет выполнено подключение.

СОВЕТ 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:
    • По умолчанию выполнит «откат DNS-запроса (fallback)»: DNS-серверы, которые не использовались в предыдущем неудачном запросе и для которых skipFallback имеет значение по умолчанию false, будут использоваться для запроса по очереди. Если запрос не удался или expectIPs не совпадает, то возвращается пустое разрешение; в противном случае возвращается разрешенный IP-адрес.
    • Если disableFallback установлен в true, то «откат DNS-запроса (fallback)» выполняться не будет.
  • Не совпадает ни с 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-адрес (в виде строки) и DnsServerObject.

Значение "localhost" означает использование предустановленной конфигурации DNS на локальной машине.

Если значением является DNS-адрес "IP", например, "8.8.8.8", Xray будет использовать указанный UDP-порт этого адреса для DNS-запросов. Этот запрос следует правилам маршрутизации. По умолчанию используется порт 53.

Если значение имеет вид "tcp://хост", например, "tcp://8.8.8.8", Xray будет использовать DNS over TCP для запроса. Этот запрос следует правилам маршрутизации. По умолчанию используется порт 53.

Если значение имеет вид "tcp+local://хост", например, "tcp+local://8.8.8.8", Xray будет использовать локальный режим TCP (TCPL) для запроса. Это означает, что DNS-запрос не будет проходить через компонент маршрутизации, а будет отправляться непосредственно через исходящее подключение Freedom, чтобы сократить время ожидания. Если порт не указан, по умолчанию используется порт 53.

Если значение имеет вид "https://хост:порт/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://хост:порт/dns-query", например, "https+local://dns.google/dns-query", Xray будет использовать локальный режим DOH (DOHL) для запроса. Это означает, что DOH-запрос не будет проходить через компонент маршрутизации, а будет отправляться непосредственно через исходящее подключение Freedom, чтобы сократить время ожидания. Обычно подходит для использования на сервере. Также можно использовать нестандартные порты и пути.

Если значение имеет вид "quic+local://хост:порт", например, "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-адресов, формат такой же, как и в конфигурации маршрутизации.

Если этот элемент настроен, Xray DNS будет проверять возвращаемые IP-адреса и возвращать только адреса, входящие в список expectIPs.

Если этот элемент не настроен, IP-адреса будут возвращены как есть.

skipFallback: true | false

true - этот сервер будет пропущен при выполнении отката DNS-запроса (fallback), по умолчанию false, то есть сервер не будет пропущен.

- + diff --git a/ru/config/fakedns.html b/ru/config/fakedns.html index fc4d93046..7b9e5038e 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 0a385cfc6..6c087abc9 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 d80a74ce7..d0a165e44 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 e3a47bd5e..011fc1a65 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 05ea26165..45bac1ba9 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 15488372b..8a9b6968c 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 30a70642b..030e5e3ca 100644 --- a/ru/config/inbound.html +++ b/ru/config/inbound.html @@ -24,8 +24,8 @@ Входящие подключения | Project X - - + +

Входящие подключения

Входящие подключения используются для приема данных. Доступные протоколы см. в разделе Входящие протоколы.

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 214122709..68f0751f4 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 438045a6f..7858b880a 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 9684e2f26..5b68ff103 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 5c2ad4e38..37dc59d8b 100644 --- a/ru/config/inbounds/socks.html +++ b/ru/config/inbounds/socks.html @@ -24,8 +24,8 @@ Socks | Project X - - + +

Socks

Реализация стандартного протокола Socks, совместимая с Socks 4Открыть в новой вкладке, Socks 4aОткрыть в новой вкладке, Socks 5 и HTTP.

Предупреждение

Протокол 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 a47ee9d61..f69369340 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 d6f5a37b9..caaade731 100644 --- a/ru/config/inbounds/vless.html +++ b/ru/config/inbounds/vless.html @@ -24,8 +24,8 @@ VLESS(XTLS Vision Seed) | Project X - - + +

VLESS(XTLS Vision Seed)

Предупреждение

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 6e1f19ea0..2c029ad7e 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 47ea8e72b..b6685dce0 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 7cfd40eeb..c1c8c382c 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 94883cd08..a9a393db3 100644 --- a/ru/config/log.html +++ b/ru/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 отключает журнал доступа.

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.

maskAddress: "quarter" | "half" | "full"

Маскировка IP-адресов. При включении автоматически заменяет IP-адреса, встречающиеся в логах, для защиты конфиденциальности при совместном использовании логов. По умолчанию не включено.

В настоящее время доступны следующие уровни маскировки: quarter, half, full. Соответствующие форматы маскировки:

  • ipv4 1.2.*.* 1.*.*.* [Masked IPv4]
  • ipv6 1234:5678::/32 1234::/16 [Masked IPv6]
- + diff --git a/ru/config/metrics.html b/ru/config/metrics.html index 851b4a44c..569f6a779 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 ef15089ff..34b56d558 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 40f3cacea..546ea03d7 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 c11b5d66d..b189bf722 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 6e10692f0..63a57a67b 100644 --- a/ru/config/outbounds/dns.html +++ b/ru/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

Массив целых чисел, блокирующий типы запросов, указанные в массиве. Например, "blockTypes":[65,28] блокирует запросы типа 65 (HTTPS) и 28 (AAAA).

Поскольку nonIPQuery по умолчанию отклоняет все запросы, не относящиеся к A и AAAA, необходимо установить для него значение skip, чтобы этот параметр заработал. Конечно, можно и не менять, а использовать его только для блокировки запросов A или AAAA, чтобы блокировать запросы IPv4/IPv6, но это крайне не рекомендуется. Рекомендуется настроить соответствующие параметры в queryStrategy встроенного DNS-сервера.

Примеры конфигурации DNS В РАЗРАБОТКЕ

- + diff --git a/ru/config/outbounds/freedom.html b/ru/config/outbounds/freedom.html index 71684f8a2..fdf544a51 100644 --- a/ru/config/outbounds/freedom.html +++ b/ru/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.
  • При указании других значений для разрешения будет использоваться встроенный DNS-сервер Xray-core. Если DNSObject не существует, будет использоваться системный DNS. Если имеется несколько подходящих IP-адресов, ядро случайным образом выберет один из них в качестве целевого IP-адреса.
  • "IPv4" означает попытку подключения только по IPv4, "IPv4v6" — попытку подключения по IPv4 или IPv6, но для доменных имен с двумя стеками будет использоваться IPv4 (аналогично для v4v6, не будем повторяться).
  • Если в настройках встроенного DNS указан "queryStrategy", фактическое поведение будет объединено с этим параметром, и будут разрешаться только те типы IP, которые указаны в обоих параметрах. Например, "queryStrategy": "UseIPv4" и "domainStrategy": "UseIP" фактически эквивалентны "domainStrategy": "UseIPv4".
  • При использовании параметров, начинающихся с "Use", если результат разрешения не соответствует требованиям (например, доменное имя имеет только запись A, но используется UseIPv6), будет выполнен откат к AsIs.
  • При использовании параметров, начинающихся с "Force", если результат разрешения не соответствует требованиям, соединение установить не удастся.

СОВЕТ 1

При использовании режимов "UseIP" или "ForceIP" и указании sendThrough в конфигурации исходящего соединения, Freedom будет автоматически определять необходимый тип IP-адреса (IPv4 или IPv6) на основе значения sendThrough. Если вручную указан только один тип IP-адреса (например, UseIPv4), но он не соответствует локальному адресу, указанному в sendThrough, подключение установить не удастся.

redirect: address_port

Freedom будет принудительно отправлять все данные на указанный адрес (а не на адрес, указанный во входящем соединении).

Значение — строка, например: "127.0.0.1:80", ":1234".

Если адрес не указан, например ":443", Freedom не будет изменять исходный целевой адрес. Если порт равен 0, например "xray.com: 0", Freedom не будет изменять исходный порт.

userLevel: number

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

Значение userLevel соответствует значению level в policy. Если не указано, по умолчанию используется значение 0.

fragment: map

Несколько пар «ключ-значение», используемых для управления исходящей фрагментацией TCP. В некоторых случаях это может обмануть системы цензуры, например, обойти черные списки SNI. "length" и "interval" относятся к типу Int32Range

"packets": поддерживаются два режима фрагментации: "1-3" — фрагментация потока TCP, применяется к первым трем операциям записи данных на стороне клиента; "tlshello" — фрагментация пакета TLS-рукопожатия.

"length": длина фрагмента (в байтах).

"interval": интервал между фрагментами (в мс).

Если значение равно 0 и установлено "packets": "tlshello", фрагментированный пакет Client Hello будет отправлен в одном TCP-пакете (если его исходный размер не превышает MSS или MTU, что приводит к автоматической фрагментации системой).

noises: array

UDP-шум, используемый для отправки случайных данных в качестве "шума" перед установлением UDP-соединения. Наличие этой структуры считается включением. Это может обмануть снифферы, но также может нарушить нормальное соединение. Используйте на свой страх и риск. По этой причине он обходит порт 53, так как это нарушает работу DNS.

Массив, в котором можно определить несколько пакетов шума для отправки. Отдельный элемент массива определяется следующим образом:

"type": тип пакета шума. В настоящее время поддерживаются "rand" (случайные данные), "str" (пользовательская строка) и "base64" (пользовательские двоичные данные, закодированные в Base64).

"packet": содержимое пакета данных, основанное на предыдущем значении type.

  • Если type равен rand, здесь указывается длина случайных данных. Это может быть фиксированное значение, например "100", или диапазон значений, например "50-150".
  • Если type равен str, здесь указывается строка для отправки.
  • Если type равен base64, здесь указываются двоичные данные, закодированные в Base64.

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

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 083501135..8a0263fb2 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 90723830b..d6f1190de 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 1e72ec13a..6a8da3daf 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 3e9f20250..3d7f80b76 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 9958f3982..f78a8b6cf 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 c584d80a5..7d441cfbf 100644 --- a/ru/config/outbounds/vless.html +++ b/ru/config/outbounds/vless.html @@ -24,8 +24,8 @@ VLESS(XTLS Vision Seed) | Project X - - + +

VLESS(XTLS Vision Seed)

Предупреждение

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 636dc1020..38b0752ab 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 e3f69adf3..c682e1990 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 83a4d7857..630e688c8 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 d86ae6916..5740978e4 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 8b93e8da9..cdc55113b 100644 --- a/ru/config/routing.html +++ b/ru/config/routing.html @@ -24,8 +24,8 @@ Маршрутизация | Project X - - + +

Маршрутизация

Модуль маршрутизации может отправлять входящие данные через разные исходящие соединения в соответствии с разными правилами для достижения цели проксирования по требованию.

Например, распространенным сценарием использования является разделение внутреннего и внешнего трафика. Xray может использовать внутренние механизмы для определения трафика из разных регионов, а затем отправлять его на разные исходящие прокси.

Более подробный анализ функции маршрутизации: Краткий анализ функции маршрутизации (routing).

RoutingObject

RoutingObject соответствует элементу routing в файле конфигурации.

{
@@ -100,6 +100,6 @@
         }
     ]
 

Предопределенные списки доменов

Этот список встроен в каждый установочный пакет Xray, имя файла - geosite.dat. Этот файл содержит некоторые распространенные доменные имена. Формат использования: geosite:имя_файла, например, geosite:google означает фильтрацию маршрутизации или DNS для доменных имен, соответствующих google в файле.

Распространенные доменные имена:

  • 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 6b8a62a02..8e5872272 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 7ae2fcdce..9af9806b3 100644 --- a/ru/config/transport.html +++ b/ru/config/transport.html @@ -24,8 +24,8 @@ Способы передачи (uTLS, REALITY) | Project X - - + +

Способы передачи (uTLS, REALITY)

Способ передачи (transport) — это способ взаимодействия текущего узла Xray с другими узлами.

Транспорт определяет способ передачи данных. Обычно оба конца сетевого подключения должны использовать одинаковый транспорт. Например, если один конец использует WebSocket, то другой конец также должен использовать WebSocket, иначе соединение не будет установлено.

StreamSettingsObject

StreamSettingsObject соответствует элементу streamSettings во входящем или исходящем подключении. Для каждого входящего или исходящего подключения можно настроить различные параметры передачи, и можно использовать streamSettings для настройки некоторых параметров передачи.

{
@@ -166,6 +166,6 @@
   "customSockopt": []
 }
 

mark: number

Целое число. Если значение не равно нулю, то исходящее соединение помечается этим значением с помощью SO_MARK.

  • Работает только в Linux.
  • Требуются права CAP_NET_ADMIN.

tcpMaxSeg: number

Используется для установки максимального сегмента TCP-пакета (Maximum Segment Size).

tcpFastOpen: true | false | number

Включить TCP Fast OpenОткрыть в новой вкладке.

Если значение равно true или положительному целому числу, то TFO включается; если значение равно false или отрицательному числу, то TFO принудительно отключается; если параметр отсутствует или равен 0, то используются настройки системы по умолчанию. Можно использовать как для входящих, так и для исходящих подключений.

  • Доступно только в следующих (или более новых) версиях операционных систем:

    • Linux 3.16: требуется настройка параметра ядра net.ipv4.tcp_fastopen, который представляет собой битовую маску, где 0x1 означает, что клиент может включать TFO, а 0x2 означает, что сервер может включать TFO; значение по умолчанию — 0x1, если серверу необходимо включить TFO, установите значение этого параметра ядра в 0x3.
    • Windows 10 (1607) (реализовано неправильно)
    • Mac OS 10.11 / iOS 9 (требуется тестирование)
    • FreeBSD 10.3 (Server) / 12.0 (Client): необходимо установить параметры ядра net.inet.tcp.fastopen.server_enabled и net.inet.tcp.fastopen.client_enabled в значение 1. (Требуется тестирование)
  • Для входящих подключений установленное здесь положительное целое число представляет собой максимальное количество ожидающих запросов на подключение TFOОткрыть в новой вкладке, обратите внимание, что не все операционные системы поддерживают эту настройку:

    • Linux / FreeBSD: установленное здесь положительное целое число представляет собой максимальное значение, максимально допустимое значение — 2147483647, если установлено значение true, то используется значение 256; обратите внимание, что в Linux net.core.somaxconn ограничивает максимальное значение, если оно превышает somaxconn, то необходимо также увеличить somaxconn.
    • Mac OS: если здесь установлено значение true или положительное целое число, это означает только включение TFO, максимальное значение необходимо установить отдельно с помощью параметра ядра net.inet.tcp.fastopen_backlog.
    • Windows: если здесь установлено значение true или положительное целое число, это означает только включение TFO.
  • Для исходящих подключений установка значения true или положительного целого числа в любой операционной системе означает только включение TFO.

tproxy: "redirect" | "tproxy" | "off"

Включить ли прозрачное проксирование (только для Linux).

  • "redirect": использовать прозрачное проксирование в режиме перенаправления. Поддерживаются все TCP-соединения на основе IPv4/6.
  • "tproxy": использовать прозрачное проксирование в режиме TProxy. Поддерживаются все TCP- и UDP-соединения на основе IPv4/6.
  • "off": отключить прозрачное проксирование.

Для прозрачного проксирования требуются права root или CAP\_NET\_ADMIN.

Предупреждение

Если в Dokodemo-door указано followRedirect: true и tproxy в настройках Sockopt пуст, то значение tproxy в настройках Sockopt будет установлено в "redirect".

domainStrategy: "AsIs"
"UseIP" | "UseIPv6v4" | "UseIPv6" | "UseIPv4v6" | "UseIPv4"
"ForceIP" | "ForceIPv6v4" | "ForceIPv6" | "ForceIPv4v6" | "ForceIPv4"

В предыдущих версиях, когда Xray пытался установить системное соединение с использованием доменного имени, разрешение доменного имени выполнялось системой и не контролировалось Xray. Это приводило к таким проблемам, как невозможность разрешить доменные имена в нестандартных средах LinuxОткрыть в новой вкладке. Для решения этой проблемы в X

- + diff --git a/ru/config/transports/grpc.html b/ru/config/transports/grpc.html index e09bd5374..e9e491df9 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/http.html b/ru/config/transports/http.html index 4c149efed..0dd393131 100644 --- a/ru/config/transports/http.html +++ b/ru/config/transports/http.html @@ -24,8 +24,8 @@ HTTP | Project X - - + +

HTTP

Тип транспорта, основанный на HTTP/2 или HTTP/3.

Он полностью реализован в соответствии со стандартом HTTP и может быть проксирован через другие HTTP-серверы (например, Nginx).

Клиент должен включить TLS для корректной работы этого типа транспорта.

HTTP/2 и 3 имеют встроенное мультиплексирование, поэтому не рекомендуется включать mux.cool при их использовании.

Подсказка

В текущей версии для транспорта HTTP/2 не требуется обязательная настройка TLS на стороне сервера.

Это позволяет использовать Xray в качестве бэкенд-приложения в специальных сценариях развертывания с разделением трафика, где внешний шлюз обрабатывает TLS-соединение, а связь между шлюзом и Xray осуществляется по протоколу HTTP без шифрования.

Подсказка

Этот транспорт будет работать в режиме h3, только если alpn содержит только h3.

Внимание

  • HTTP/2 и HTTP/3 не могут быть разделены по путям отката Xray. Использование разделения по путям отката не рекомендуется.

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 c513bd455..8c40b8612 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 dc3551b9b..f6ecfc142 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/raw.html b/ru/config/transports/raw.html index c4ba9159c..58c01215d 100644 --- a/ru/config/transports/raw.html +++ b/ru/config/transports/raw.html @@ -24,8 +24,8 @@ RAW | Project X - - + +

Warning

This translation was modified on 1 October 2024 and an updated version (1 October 2024) is available on the source page. View the original page

RAW

Режим транспорта RAW — один из рекомендуемых в настоящее время режимов транспорта.

Может использоваться в различных комбинациях с различными протоколами.

RawObject

RawObject соответствует элементу rawSettings в конфигурации транспорта.

{
@@ -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/splithttp.html b/ru/config/transports/splithttp.html index 4f00d5ce2..5486b000d 100644 --- a/ru/config/transports/splithttp.html +++ b/ru/config/transports/splithttp.html @@ -24,8 +24,8 @@ SplitHTTP (H2, QUIC H3) | Project X - - + +

Warning

This translation was modified on 3 October 2024 and an updated version (16 October 2024) is available on the source page. View the original page

SplitHTTP (H2, QUIC H3)

v1.8.16+

Используется для загрузки с помощью HTTP-фрагментированной передачи, загрузка осуществляется с помощью нескольких HTTP POST-запросов.

Может использоваться через CDN, не поддерживающие WebSocket, но есть несколько требований:

  • CDN должен поддерживать HTTP-фрагментированную передачу и потоковые ответы без буферизации. Ядро будет отправлять различную информацию, чтобы сообщить CDN об этом, но CDN должна ее соблюдать. Если промежуточный узел не поддерживает потоковые ответы и зависает, этот транспорт, скорее всего, не будет работать.

Цель та же, что и у V2fly Meek, но благодаря использованию фрагментированной загрузки скорость загрузки выше, а скорость отдачи оптимизирована, но все еще очень ограничена, поэтому к HTTP-прокси предъявляются более высокие требования (см. выше).

SplitHTTP также принимает заголовок X-Forwarded-For.

SplitHttpObject

SplitHttpObject соответствует элементу splithttpSettings в конфигурации транспорта.

{
@@ -53,6 +53,6 @@
   "cMaxLifetimeMs": 0
 }
 

Поскольку по умолчанию используется неограниченное мультиплексирование, xmux фактически ограничивает его. Кроме того, не включайте mux.cool.

Объяснение терминов:

  • Потоки будут мультиплексироваться в физические соединения, например: Соединение 1 (Поток 1, Поток 2, Поток 3) Соединение 2 (Поток 4, Поток 5, Поток 6) ... и так далее. В других источниках вы можете встретить описание "соединение-подключение", это то же самое.
  • Все следующие поля имеют тип Int32Range:

maxConcurrency: int/string

Значение по умолчанию — 0 (неограниченно). Максимальное количество потоков, мультиплексируемых в одном соединении. Когда количество потоков в соединении достигает этого значения, ядро создает дополнительные соединения для размещения новых потоков, аналогично параметру concurrency в mux.cool.

maxConnections: int/string

Значение по умолчанию — 0 (неограниченно). Максимальное количество открытых соединений. Ядро будет активно открывать новые соединения для каждого потока до тех пор, пока не будет достигнуто это значение. Затем ядро начнет мультиплексировать потоки в уже установленные соединения. Конфликтует с maxConcurrency.

cMaxReuseTimes: int/string

Значение по умолчанию — 0 (неограниченно). Максимальное количество раз, которое соединение может быть использовано повторно. По достижении этого значения ядро больше не будет назначать потоки этому соединению, и оно будет разорвано после закрытия последнего внутреннего потока.

cMaxLifetimeMs: int/string

Значение по умолчанию — 0 (неограниченно). Максимальное время "жизни" соединения. По истечении этого времени ядро больше не будет назначать потоки этому соединению, и оно будет разорвано после закрытия последнего внутреннего потока.

Версия HTTP

Поведение клиента

По умолчанию клиент будет использовать http/1.1, если TLS не включен, и h2, если TLS включен.

Если TLS включен, можно указать конкретную версию HTTP (http/1.1, h2, h3) в массиве alpn в настройках TLS (работает только в том случае, если массив содержит только один элемент, если указано несколько элементов, будет использоваться поведение по умолчанию).

Поведение сервера

По умолчанию сервер будет прослушивать TCP-порт и обрабатывать трафик http/1.1 и h2.

Если TLS включен, можно указать h3 в массиве alpn в настройках TLS. В этом случае сервер будет прослушивать UDP-порт и обрабатывать трафик h3.

Советы

Поскольку этот протокол основан на стандартных HTTP-запросах, он нечувствителен к преобразованию версий HTTP, и различные промежуточные узлы могут преобразовывать версии HTTP.

Например, если вы хотите использовать h3 для подключения к Cloudflare, но Cloudflare не будет использовать h3 для обратного подключения, а будет использовать http/1.1 или h2, то на клиенте alpn должен быть установлен в h3, а на сервере — нет, поскольку запросы, отправляемые на сервер, не будут использовать h3.

Browser Dialer

При использовании HTTPS этот транспорт также поддерживает Browser Dialer.

Подробности протокола

Подробное обсуждение см. в #3412Открыть в новой вкладке и #3462Открыть в новой вкладке. Ниже приведено краткое описание и требования к совместимости реализации:

  1. Загрузка начинается с запроса GET /<UUID>. Сервер немедленно отвечает 200 OK и Transfer Encoding:chunked и сразу же отправляет двухбайтовую полезную нагрузку, чтобы заставить HTTP-промежуточные узлы сбросить заголовки.

На данный момент сервер отправляет следующие заголовки:

  • X-Accel-Buffering: no — отключает буферизацию.
  • Content-Type: text/event-stream — отключает буферизацию на некоторых промежуточных узлах, можно отключить с помощью опции "noSSEHeader".
  • Transfer-Encoding: chunked — кодировка передачи данных, используется только в HTTP/1.1.
  • Cache-Control: no-store — отключает любое возможное кэширование ответов.
  1. Выгрузка начинается с запроса POST /<UUID>/<seq>. seq работает аналогично порядковому номеру TCP, начиная с 0. Пакеты данных могут отправляться одновременно, сервер должен пересобрать данные в соответствии с порядковым номером. Порядковый номер не должен сбрасываться.

    Клиент может открывать запросы на выгрузку и загрузку в любом порядке, любой из них может инициировать сеанс, но соединение GET должно быть открыто в течение 30 секунд, иначе сеанс будет разорван.

  2. Запрос GET будет оставаться открытым до тех пор, пока соединение не будет разорвано. Как сервер, так и клиент могут закрыть соединение. Конкретное поведение зависит от версии HTTP.

Рекомендации:

  • Не ожидайте, что CDN будет правильно передавать все заголовки. Цель этого протокола — обойти CDN, которые не поддерживают WS, а такие CDN обычно ведут себя не очень хорошо.

  • Следует предполагать, что все HTTP-соединения не поддерживают потоковые запросы, поэтому размер каждого пакета, отправляемого по исходящему соединению, должен основываться на задержке, пропускной способности и ограничениях самого промежуточного узла (аналогично MTU и алгоритму Нейгла в TCP).

- + diff --git a/ru/config/transports/tcp.html b/ru/config/transports/tcp.html index 051069f7e..f420b28b5 100644 --- a/ru/config/transports/tcp.html +++ b/ru/config/transports/tcp.html @@ -24,11 +24,11 @@ TCP | Project X - - + +

Notice

This page has not yet been translated, see how you can help here.

TCP

v24.9.30 版本后,为了更贴近实际行为,tcp传输方式已更名为raw, 为了兼容性,"network": "raw" 和 "network": "tcp", rawSettingstcpSettings 互为别名

- + diff --git a/ru/config/transports/websocket.html b/ru/config/transports/websocket.html index 62b90c223..9d7887229 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 5a7cc369a..17143f820 100644 --- a/ru/development/index.html +++ b/ru/development/index.html @@ -24,11 +24,11 @@ Руководство по разработке | Project X - - + +

Руководство по разработке

Сборка документации

Xray поддерживает различные платформы, и вы можете самостоятельно выполнить кросс-компиляцию на многих из них.

Перейдите в документацию по сборке, чтобы узнать больше о процессе сборки.

Принципы проектирования

Ядро Xray предоставляет платформу, на основе которой можно выполнять дальнейшую разработку.

В этом разделе описываются цели проектирования и архитектура Xray.

Перейдите в раздел Принципы проектирования, чтобы узнать больше о целях проектирования и архитектуре Xray.

Правила разработки

В этом разделе описываются правила, которым необходимо следовать при получении кода, разработке и отправке запросов на включение изменений (pull request), а также соответствующие стандарты кодирования.

Перейдите в раздел Правила разработки, чтобы ознакомиться с правилами, которых следует придерживаться при разработке 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 9723ce24e..58962f3b0 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, чтобы просмотреть все поддерживаемые системы и архитектуры.

Воспроизводимая сборка:

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

Внимание

Убедитесь, что вы используете ту же версию Golang, что и для сборки релиза.

- + diff --git a/ru/development/intro/design.html b/ru/development/intro/design.html index 8f028790a..d85abde48 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 899be2d07..a5dd938a8 100644 --- a/ru/development/intro/guide.html +++ b/ru/development/intro/guide.html @@ -24,8 +24,8 @@ Правила разработки | Project X - - + +

Warning

This translation was modified on 3 October 2024 and an updated version (5 October 2024) is available on the source page. View the original page

Правила разработки

Основные принципы

Система контроля версий

Код проекта X размещен на GitHub:

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

Ветки (Branch)

  • Основной веткой проекта является main.
  • Основной веткой для выпуска релизов также является main.
  • Необходимо убедиться, что main в любой момент времени может быть скомпилирован и работает корректно.
  • Если вам нужно разработать новую функцию, создайте новую ветку для разработки. После завершения разработки и тщательного тестирования объедините ее с основной веткой.
  • Удалите ветки, которые были объединены с основной веткой и больше не нужны.

Релизы (Release)

В РАЗРАБОТКЕ
  • Создайте два канала выпуска: для предварительных версий и для стабильных версий.
    • Предварительные версии могут быть ежедневными сборками, в основном используются для тестирования в определенных ситуациях, ознакомления с новыми функциями и получения обратной связи для дальнейшего улучшения.
    • Стабильные версии выпускаются по расписанию (например, ежемесячно) и содержат стабильные изменения.

Использование других проектов

  • Golang
    • В коде рекомендуется использовать стандартную библиотеку Golang и библиотеки из golang.org/x/Открыть в новой вкладке.
    • Если вам нужно использовать другие проекты, сначала создайте issue для обсуждения.
  • Другие
    • Можно использовать любые инструменты, которые не нарушают лицензии обеих сторон и полезны для проекта.

Процесс разработки

Перед написанием кода

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

Изменение кода

  • Golang
    • См. Effective GoОткрыть в новой вкладке.
    • Перед каждой отправкой (push) выполните команду: go generate core/format.go.
    • Если вам нужно изменить protobuf, например, добавить новый параметр конфигурации, выполните команду: go generate core/proto.go.
    • Перед отправкой pull request рекомендуется запустить тесты: go test ./....
    • Перед отправкой pull request рекомендуется, чтобы новый код имел покрытие кода (code coverage) не менее 70%.
  • Другие
    • Обратите внимание на читаемость кода.

Запрос на включение изменений (Pull Request)

  • Перед отправкой PR сначала выполните команду git pull https://github.com/XTLS/Xray-core.git, чтобы убедиться, что слияние пройдет гладко.
  • Один PR должен решать только одну задачу. Если вы исправляете несколько ошибок, отправьте по одному PR для каждой ошибки.
  • Из-за особенностей Golang (пути к пакетам) процесс PR для проектов Go отличается от других проектов. Рекомендуемый процесс следующий:
    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. Наконец, отправьте PR из своей ветки в ветку main репозитория XTLS/Xray-core.
    9. В заголовке и описании PR четко опишите проблему, которую решает этот PR / новую функцию / цель изменений кода.
    10. Дождитесь ответа разработчиков.

Изменения кода

Проблемы с функциональностью

Отправьте хотя бы один тестовый пример (Test Case), чтобы проверить изменения в существующей функциональности.

Проблемы с производительностью

Отправьте необходимые тестовые данные, чтобы подтвердить проблемы с производительностью существующего кода или улучшение производительности нового кода.

Новые функции

  • Если новая функция не влияет на существующую функциональность, предоставьте переключатель (например, флаг) для ее включения/отключения и оставьте ее отключенной по умолчанию.
  • Перед разработкой новой крупной функции (например, добавления нового протокола) создайте issue для обсуждения.

Другое

Зависит от конкретной ситуации.

Стандарты кодирования Xray

Следующие правила применяются к коду Golang в Xray.

Структура кода

Xray-core
@@ -40,6 +40,6 @@
 │   ├── vmess
 ├── transport  // Транспортные модули
 

Стандарты кодирования

В основном соответствуют рекомендациям Golang, за некоторыми исключениями. Приведены здесь для удобства ознакомления с Golang.

Именование

  • Для имен файлов и каталогов по возможности используйте одно английское слово, например, hello.go.
    • Если это невозможно, используйте дефисы для разделения слов в имени каталога и подчеркивания для разделения слов в имени файла, например, hello-world/hello_again.go.
    • Тестовый код должен иметь суффикс _test.go.
  • Для типов используйте нотацию PascalCase, например, ConnectionHandler.
    • Сокращения не обязательно писать в нижнем регистре, то есть HTML не нужно писать как Html.
  • Для публичных переменных-членов также используйте нотацию PascalCase.
  • Для приватных переменных-членов используйте нотацию camelCaseОткрыть в новой вкладке, например, privateAttribute.
  • Для удобства рефакторинга рекомендуется использовать нотацию PascalCase для всех методов.
    • Полностью приватные типы помещайте в каталог internal.

Организация кода

  • Один файл должен содержать один основной тип и связанные с ним приватные функции.
  • Тестовые файлы, такие как Mock и другие утилиты, помещайте в подкаталог testing.

Int32Range

Для конечного пользователя

Значение, представляющее собой необязательный диапазон. Возможные варианты записи:

  • Отдельное число или диапазон, заключенные в кавычки:
    • "" (считается как 0). Обратите внимание, что полное отсутствие настройки поля и установка пустого значения могут иметь разное значение.
    • "114"
    • "114-514"
  • Отдельное целое число (int). В этом случае возможно указать только одно число:
    • 114

Для разработчика

Если вам нужно использовать диапазон в файле конфигурации, используйте тип Int32Range. Для получения значений используйте .From и .To вместо использования строкового типа (string) и последующего ручного разбора.

Метод .EnsureOrder() можно использовать для обмена значений From и To, если From больше, чем To (при необходимости).

- + diff --git a/ru/development/protocols/mkcp.html b/ru/development/protocols/mkcp.html index 7a9462b71..785ff9a35 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.

Функции

  • fnv: хэш-функция FNV-1aОткрыть в новой вкладке
    • Входные данные: строка произвольной длины;
    • Выходные данные: 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/ru/development/protocols/muxcool.html b/ru/development/protocols/muxcool.html index 63bc64d39..18c8cfbcf 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 может передавать несколько подсоединений, каждое из которых имеет свой собственный идентификатор и состояние. Процесс передачи состоит из кадров (Frame), каждый из которых используется для передачи данных определенного подсоединения.

Поведение клиента

Когда требуется соединение и нет доступного существующего соединения, клиент инициирует новое соединение с сервером, которое далее называется "главным соединением".

  1. Одно главное соединение может использоваться для отправки нескольких подсоединений. Клиент может самостоятельно определять количество подсоединений, которое может нести главное соединение.
  2. Для нового подсоединения клиент должен отправить состояние New, чтобы уведомить сервер о создании подсоединения, а затем использовать состояние Keep для передачи данных.
  3. Когда подсоединение завершается, клиент отправляет состояние End, чтобы уведомить сервер о закрытии подсоединения.
  4. Клиент может самостоятельно решать, когда закрыть главное соединение, но должен убедиться, что сервер также поддерживает соединение.
  5. Клиент может использовать состояние KeepAlive, чтобы предотвратить закрытие главного соединения сервером.

Поведение сервера

Когда сервер получает новое подсоединение, он должен обрабатывать его как обычное соединение.

  1. При получении состояния End сервер может закрыть исходящее соединение с целевым адресом.
  2. В ответе сервера для передачи данных подсоединения должен использоваться тот же идентификатор, что и в запросе.
  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, который сервер использует, чтобы гарантировать, что при переподключении 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 добавляет адрес UDP после Opt(D) в том же формате, что и при создании нового подсоединения, но без 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 64762cc07..30db16f26 100644 --- a/ru/development/protocols/vless.html +++ b/ru/development/protocols/vless.html @@ -24,11 +24,11 @@ Протокол VLESS | Project X - - + +

Протокол VLESS

VLESS - это легковесный, не сохраняющий состояние транспортный протокол, который может служить мостом между клиентом и сервером Xray.

Запрос и ответ

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 для повышения производительности генерации случайных чисел мы заменили crypto/rand на math/rand, а теперь в этом нет необходимости.

"Версия протокола" не только выполняет функцию "аутентификации ответа", но и дает VLESS возможность безболезненно обновлять структуру протокола, открывая бесконечные возможности. "Версия протокола" во всех бета-версиях равна 0, в официальной версии - 1, а в будущем, если будут несовместимые изменения в структуре протокола, версия должна быть обновлена.

Сервер VLESS спроектирован по принципу switch version, то есть он одновременно поддерживает все версии VLESS. Если требуется обновить версию протокола (что маловероятно), рекомендуется сначала добавить поддержку на сервере за месяц до обновления клиентов. Запрос VMess также имеет версию протокола, но его информация для аутентификации находится снаружи, а часть с командой сильно связана и имеет фиксированное шифрование, что делает версию протокола внутри бессмысленной. Сервер также не проверяет ее, а ответ не имеет версии протокола. В структуре протокола Trojan нет версии протокола.

Далее идет UUID. Сначала я думал, что 16 байт - это многовато, и подумывал о его сокращении, но потом увидел, что Trojan использует 56 печатаемых символов (56 байт), и полностью отказался от этой идеи. Сервер каждый раз проверяет UUID, поэтому производительность также важна: валидатор VLESS прошел через несколько рефакторингов/обновлений, он очень прост и потребляет мало ресурсов по сравнению с 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 по сути делает именно это, и накладные расходы минимальны. Склеенные байты очень компактны, практически не отличаются от решения в ALPHA. Желающие могут вывести их и сравнить.

Чтобы указать различный уровень поддержки дополнительной информации (Addons, которые можно рассматривать как плагины, в будущем их может быть много), в следующей бета-версии перед "длиной дополнительной информации" будет добавлена "версия дополнительной информации". 256 - 1 = 255 байт - это достаточно и разумно (65535 - это слишком много, и кто-то может злонамеренно заполнить их), существующие используют только десятую часть, и в будущем не будет такого количества дополнительной информации, а в большинстве случаев дополнительная информация вообще отсутствует. Если этого действительно не хватит, можно обновить версию VLESS.

Чтобы сократить накладные расходы на логические проверки и т.д., Addons пока не будут использовать многоуровневую структуру. Месяц назад появилась идея "изменяемого формата протокола", pb может переставлять поля, но в этом нет необходимости, поскольку современное шифрование не позволяет стороннему наблюдателю увидеть, что заголовки двух передач одинаковы.

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

Schedulers Flow

Предварительное китайское название: Планировщик трафика (обновление от 03.09.2020: официальное китайское название - "Управление потоком"). Команда передается через ProtoBuf и управляет частью данных.

Я обнаружил, что оригинальная "обфускация метаданных" shake в VMess не вносит никаких значимых изменений при использовании TLS, а только снижает производительность, поэтому в VLESS от нее отказались. Кроме того, термин "обфускация" может быть неверно истолкован как маскировка, поэтому от него тоже отказались. Кстати, я всегда скептически относился к маскировке: если она не может быть полностью идентичной, то это же явная сигнатура? А если может быть полностью идентичной, то почему бы не использовать саму маскировку? Сначала я использовал SSR, но потом понял, что он маскирует трафик только для провайдера, и больше им не пользовался.

Так какую же проблему решает "Планировщик трафика"? Он влияет на макроскопические временные характеристики трафика, а не на микроскопические, которые должны решаться шифрованием. Временные характеристики трафика могут быть обусловлены протоколом, например, рукопожатием Socks5 при использовании Socks5 over TLS. Для наблюдателя различные временные характеристики в TLS соответствуют разным протоколам, поэтому бесконечное количество планировщиков эквивалентно бесконечному количеству протоколов (перераспределение размера отправляемых данных и т.д.). Временные характеристики трафика также могут быть обусловлены поведением, например, сколько файлов загружается при посещении главной страницы Google, в каком порядке и какого размера. Добавление еще одного уровня шифрования не может эффективно скрыть эту информацию.

Schedulers не нужно располагать снаружи, как Encryption, поскольку небольшое количество данных в заголовке ничтожно мало по сравнению с объемом данных, которые следуют за ними.

В BETA 2 планируется выпустить два базовых планировщика: сжатие 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 планируется добавить поддержку aes-128-gcm и chacha20-ietf-poly1305 из SS: в 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

XUDP: VLESS & VMess & Mux UDP FullCone NATОткрыть в новой вкладке

Руководство по разработке клиентов

  1. Протокол VLESS сам по себе будет обновляться несовместимым образом, но параметры конфигурации клиента в основном будут только добавляться. Реализация протокола в iOS-клиенте должна обновляться соответствующим образом.
  2. Визуальный стандарт: используйте 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 a352d1ffe..3a8366d98 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 эквивалентен UUIDОткрыть в новой вкладке - это 16-байтовое случайное число, которое действует как токен. ID выглядит следующим образом: de305d54-75b4-431b-adb2-eb6b9e546014, он практически полностью случаен и может быть сгенерирован с помощью любого генератора UUID, например этогоОткрыть в новой вкладке.

Идентификатор пользователя можно указать в файле конфигурации.

Функции

Процесс коммуникации

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

Клиент VMess отправляет запрос, а сервер проверяет, исходит ли этот запрос от легитимного клиента. Если проверка пройдена, сервер пересылает запрос и отправляет полученный ответ клиенту.

VMess использует асимметричный формат, то есть запрос, отправляемый клиентом, и ответ сервера имеют разные форматы.

Запрос клиента

16 байтX байтОставшаяся часть
Информация для аутентификацииЧасть с командойЧасть с данными

Информация для аутентификации

Информация для аутентификации - это 16-байтовое хэш-значение, которое вычисляется следующим образом:

  • H = MD5
  • K = идентификатор пользователя (16 байт)
  • M = время UTC с точностью до секунды, случайное значение в диапазоне ±30 секунд от текущего времени (8 байт, Big Endian)
  • Hash = HMAC(H, K, M)

Часть с командой

Часть с командой шифруется с помощью AES-128-CFB:

  • Ключ: MD5(идентификатор пользователя + []byte('c48619fe-8f02-49e0-b9e9-edf763e17e21'))
  • Вектор инициализации: 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Вектор инициализации для шифрования данныхКлюч для шифрования данныхАутентификация ответа VОпция OptОстаток PМетод шифрования SecЗарезервированоКоманда CmdПорт PortТип адреса TАдрес AСлучайные данныеКонтрольная сумма F

Подробности опции Opt: (если бит равен 1, опция включена)

01234567
XXXXXMRS

Где:

  • Номер версии Ver: всегда равен 1;
  • Вектор инициализации для шифрования данных: случайное значение;
  • Ключ для шифрования данных: случайное значение;
  • Аутентификация ответа V: случайное значение;
  • Опция Opt:
    • S (0x01): стандартный формат потока данных (рекомендуется включать);
    • R (0x02): клиент ожидает повторного использования TCP-соединения (устарело в Xray 2.23+);
      • Действительна только при включенной опции S;
    • M (0x04): включить обфускацию метаданных (рекомендуется включать);
      • Действительна только при включенной опции S;
      • Если эта опция включена, клиент и сервер должны создать два экземпляра Shake: RequestMask = Shake(вектор инициализации для шифрования данных запроса), ResponseMask = Shake(вектор инициализации для шифрования данных ответа).
    • 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: хэш FNV1a всей части с командой, кроме F;

Часть с данными

Если 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 фактических данных;
    • L - 4 байта: фактические данные;
  • AES-128-GCM: ключ - это ключ из части с командой, вектор инициализации = count (2 байта) + IV (10 байт). count начинается с 0 и увеличивается на 1 для каждого пакета данных; IV - это байты с 3 по 12 из вектора инициализации части с командой.
    • L - 16 байт: фактические данные;
    • 16 байт: данные аутентификации GCM
  • ChaCha20-Poly1305: ключ = MD5(ключ из части с командой) + MD5(MD5(ключ из части с командой)), вектор инициализации = count (2 байта) + IV (10 байт). count начинается с 0 и увеличивается на 1 для каждого пакета данных; IV - это байты с 3 по 12 из вектора инициализации части с командой.
    • L - 16 байт: фактические данные;
    • 16 байт: данные аутентификации Poly1305

Ответ сервера

Данные заголовка ответа шифруются с помощью AES-128-CFB, вектор инициализации - MD5(вектор инициализации для шифрования данных), ключ - MD5(ключ для шифрования данных). Фактические данные ответа зависят от настроек шифрования.

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Идентификатор пользователяAlterIDУровень пользователяВремя действия T

Где:

  • Порт Port: номер порта в формате Big Endian;
  • Время действия T: количество минут;

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

Примечания

  • Для обеспечения обратной совместимости все зарезервированные поля должны иметь значение 0.
- + diff --git a/ru/document/command.html b/ru/document/command.html index b5dd86540..affed6ffb 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 b27ccdf78..49910604f 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 b752d61d7..29513318e 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 287270cac..8336d5633 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 007684a5d..2455c18bb 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 f9747e758..4b02561e4 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 8d20b4b91..efc62b3f6 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 19e11ecb0..e49c62597 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 445f21e4b..bdc67a112 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 bad4c3c4b..7763dcb6b 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 b84caf576..a8dd8e28b 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 1e003321c..45763f37e 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 8160d7f5a..702ead51c 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 718b892eb..908b9cea7 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 1f8b95f21..762b76c5b 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 9c14526b7..e7677c88c 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 69ded028c..efbd3336d 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 22e4b948a..28bf84714 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 93a368f8e..d5b30fd69 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 257011c30..3fd606bec 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 ce4a86a4e..c4412bdb9 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 4e48d2743..d8ad7acca 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 f1e3c24d4..c333d6ca7 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 ca64ad1a1..705a5e0b6 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 2c58e79d0..e05b42000 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 27c574b03..559d7c2f4 100644 --- a/ru/document/level-2/tproxy.html +++ b/ru/document/level-2/tproxy.html @@ -24,8 +24,8 @@ Прозрачное проксирование TProxy | Project X - - + +

    Руководство по настройке прозрачного проксирования (TProxy)

    Warning

    This translation was modified on 16 July 2024 and an updated version (4 October 2024) is available on the source page. View the original page

    Эта конфигурация основана на Новом руководстве по 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 03250b417..463fc9e85 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 e2e797feb..8103d7b0e 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 433f925af..837ab94eb 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 a4eb39001..009199e59 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 56dc50aca..d49e12b10 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Открыть в новой вкладке

    - +