diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/404.html b/404.html new file mode 100644 index 00000000..09d66ca5 --- /dev/null +++ b/404.html @@ -0,0 +1,40 @@ + + + + + + + + Hydro + + + + + + +

404

Page not found

There’s nothing here.

+ + + diff --git a/CNAME b/CNAME new file mode 100644 index 00000000..73ce4041 --- /dev/null +++ b/CNAME @@ -0,0 +1 @@ +hydro.js.org diff --git a/FAQ/index.html b/FAQ/index.html new file mode 100644 index 00000000..f3db7986 --- /dev/null +++ b/FAQ/index.html @@ -0,0 +1,43 @@ + + + + + + + + 常见问题集合 | Hydro + + + + + + +

常见问题集合


常见问题集合

好消息!本页和各大浏览器均达成了合作,使用 Ctrl-F 即可快速搜索关键词!

更多教程请点击右上角的常用教程查看。

用户QQ群 1085853538

如何快速上手了解系统功能?

参照本文 https://hydro.ac/discuss/6172ceeed850d38c79ae18f9open in new window 无服务器快速体验系统功能。
如果你没有二开很多功能的需求,推荐直接使用在线服务。超过两万题的题库可以直接复制使用,无需购置云服务器,无需手动维护,更省心。
如果你有需要绑定自己的域名或是改 Logo 等等自定义需求,也可在管理面板中开通高级功能自助操作。

系统中的用户只有编辑、禁用功能,没有删除功能,这是为了从根源上防止出现“教学事故”,请不要要求增加相关功能,如果认为自己绝不会误操作,请自行开发相关功能。

什么是 OJ?

现在你所使用的评测系统也仅仅是一个程序,并没有人工智能。因此很多地方需要你来迁就它,如果不这样做,你的答案即使本质上是正确的,由于形式的错误造成系统不能理解,也会导致错误。
系统运行过程如下:

  • 教师在系统中添加题目,并严格定义题目提供输入数据的格式和要求的输出数据格式。
  • 教师根据题目定义的格式向系统中添加若干组测试数据,每组数据都包含输入数据和对应的输出。
  • 学生阅读题目,并根据自己的理解提交程序。
  • 系统编译并运行学生的程序,再将老师事先提供的输入数据“喂”给学生的程序,看它会输出什么。
  • 如果学生程序的输出与老师之前提供的输出完全一致,一字不差,则认为学生的程序是正确的,否则则认为该程序错误。
  • 如果运行过程中出现内存、时间上超出题目限制的情况,则中断程序的运行,并认为答案不正确。

在了解了上面的情况以后,同学们应该理解,如果题目没有要求程序输出“Please Input Two Number”之类的提示信息,那么自行输出这些文字将导致你的程序输出与老师事先告诉系统的输出不能做到“一字不差”,因而将导致系统报答案错误。
如果题目要求每两行输出之间要空一行,结果你没有空,会是格式错误,反之亦然。
也许你会觉得,哦,这系统太烂了,这点东西都不能自动识别;实际上正是这样才能有效训练大家编程的精确性、养成良好的代码习惯。很多程序高手都跟你一样,是从对这个系统吐槽开始学习如何认真仔细的、一丝不苟的进行编程的。
系统为了能用统一的方式运行所有同学的答案,不得不对所有人提交的答案的形式进行限定。
对于学习C、C++语言的同学来说,所有提交给系统的答案必须包含并且只有一个main函数,这个main函数必须返回int类型,并且最好返回0,因为操作系统对非零的返回值认为是运行出错。
编译错误发生时,点击“编译错误”的文字链接可以得到详细解释。

Arch Linux 开发模式安装时出现 [ERR_STREAM_PREMATURE_CLOSE]: Premature close 错误

删除 .yarnrc.yml.yarn 后再试。

为什么我安装完成之后仍然无法访问?

如果您使用的是 阿里云/腾讯云 等服务商,请确保安全组放行了 80 和 443 端口。

为什么我配置完反向代理(caddy/nginx)之后无法登录(出现CsrfTokenError)?

反向代理时请确保设置了正确的 Host Header。详细说明

怎么备份/还原备份/迁移数据?

hydrooj backup hydrooj restore backup-xxx.zip

百度学习 crontab 的用法后,可以使用 sudo crontab -e 定制自动备份计划。

恢复备份时出现 '/data/file/hydro': Directory not empty

关闭 minio (pm2 stop minio) 后手动删除 /data/file/hydro 文件夹再重试。

更新升级

yarn global upgrade-interactive --latest 然后按空格选中除 pm2 之外的所有包更新,回车确认。 然后 pm2 restart hydrooj 重启服务。 重启后 pm2 logs hydrooj --lines 100 没有看到报错并看到了 Server started 则一切正常。

Hydro 的所有历史版本,都可以无损升级到最新版本。如果老系统更新有疑问,随时加官方群咨询群主。

怎么导入题目/创建题目?

题目列表右侧有相应入口。

切记:不要导入过多你暂时用不上的题目,正确的方式是每次训练、作业,导入所需的5-10个题目,比赛作业结束后让题目成为训练题库的一部分。这样能保证题库中题号靠前的题目难度依次上升,适合后来的同学自行训练。不要贪图题目数量而忽视其质量。自己看不懂解法的题目,少用、慎用。

如何限制未登录用户访问?

管理域 -> 管理权限 将 Guest 权限组的 查看此域 权限禁用。

比赛作业里面的时间是什么含义,OI排名跟普通排名有何区别?

时间是指参与人员做出对应题目“花费”的时间:
即:做出题目的时刻 – 比赛开始的时刻 + 惩罚时间
惩罚时间 = 做对之前错误的提交数 * 20分钟。
普通排名按做对的题目数和“花费”的时间进行排名。
OI排名,按得分排名,题目可以按通过的比例进行记分,每题100分。如果希望数据的分值不平均分配,可以使用 config 配置。

脚本把 OJ 装在哪里了?

Hydro 的默认位置可以运行 yarn global dir 得到。(不要直接改代码,更新会覆盖此处的所有修改,请使用插件API)
默认的数据库文件放置在 /data/db,但是不要直接复制文件,而是推荐用 hydrooj backup 进行备份。
测试数据等文件存储于 /data/file
配置文件位于 /root/.config/hydro/root/.hydro。 对于正在运行中的生产服务器,任何操作前请做好离线备份。
备份文件一定要解压查看内部是否包含全部数据,关注备份的大小(大系统备份应该有上百兆),有条件找虚拟机实测还原是否成功

题目的限时和内存限制的精度是怎样的?

题目限时允许设定的字面精度是 1ms,但是由于操作系统内核参数的限定,实测的精度通常为4ms。 内存限制的精度是1MB,对于本地native的编译型语言c/c++/pascal/freebasic/clang等是考察程序本身的内存申请空间; 对于虚拟机和脚本语言,则包含了虚拟机本身或解释器本身的内存消耗。

我想让 Python 支持 numpy 等等库,怎么办?

如果你是 2022/8/12 日前安装,使用 pip3 install numpypm2 restart hydro-sandbox
否则参照请参照 编译器 章节。

使用安装脚本后忘记 MongoDB 的账号密码怎么办?

/root/.hydro/config.json

如何关闭、打开用户注册?

用户注册由 Guest 用户(uid 为 0)的 PRIV_REGISTER_USER 权限控制,默认允许注册。 使用 hydrooj cli user setPriv 0 0 即可关闭注册。 若要重新打开,可使用 hydrooj cli user setPriv 0 8

变更后,请重启 hydrooj 服务:pm2 restart hydrooj

用户名为 Hydro 的用户是干什么的?密码是什么?可以登录么?

用户名为 Hydro 的用户(uid 为 1)仅用于发送系统消息(与 QQ 中的 10000 类似),无法登录。

如何修改网站图标?

使用 hydrooj addon create 创建一个插件,这会自动创建 /root/addon 目录。
进入 /root/addon/public 目录,将您的站点图标放置于该文件夹下。
您需要将以下文件放在该目录中(适配不同浏览器):

  • favicon-16x16.png
  • favicon-32x32.png
  • favicon-96x96.png
  • favicon.ico (32x32)
  • android-chrome-192x192.png
  • apple-touch-icon-180x180.png

分辨率应尽可能对应,但不强制要求。以上图片将在浏览器标签页图片上显示。
您还需要将以下文件放在该目录:

  • nav_logo_dark.png

以上图片将在页面左上角 logo 显示。 之后前往系统设置,找到 nav_logo_dark 设置项,改为 /nav_logo_dark.png ,重启 Hydro 即可应用更改。

记得清理浏览器缓存。

如何重置数据?

Note

此操作会删除所有用户/题目/比赛等数据。请谨慎操作!

此脚本open in new window 下载到服务器运行。

您可按需更改,显示顺序与配置中的排列顺序相同。

评测显示“总时限超过 60s,评测取消”

在系统设置中修改 total_time_limit 为允许的单题最大评测时长即可。

如何在背景中添加线条特效?

在系统设置中找到 footer_extra_html 项,加上如下内容:(写在一行内,不要多加换行)

基于 https://github.com/hustcc/canvas-nest.js ,MIT

<script>(()=>{function e(e,n,t){return e.getAttribute(n)||t}function n(){l=i.width=window.innerWidth||document.documentElement.clientWidth||document.body.clientWidth,u=i.height=window.innerHeight||document.documentElement.clientHeight||document.body.clientHeight}function c(){var t,o,i,a,m;r.clearRect(0,0,l,u),s.forEach(function(e,n){for(e.x+=e.xa,e.y+=e.ya,e.xa*=e.x>l||e.x<0?-1:1,e.ya*=e.y>u||e.y<0?-1:1,r.fillRect(e.x-.5,e.y-.5,1,1),o=n+1;o<d.length;o++)null!==(t=d[o]).x&&null!==t.y&&(i=e.x-t.x,a=e.y-t.y,(m=i*i+a*a)<t.max&&(t===y&&m>=t.max/2&&(e.x-=.03*i,e.y-=.03*a),m=(t.max-m)/t.max,r.beginPath(),r.lineWidth=m/2,r.strokeStyle="rgba("+x.c+","+(.2+m)+")",r.moveTo(e.x,e.y),r.lineTo(t.x,t.y),r.stroke()))}),w(c)}var l,u,d,t,o,i=document.createElement("canvas"),x=(t=(o=document.getElementsByTagName("script")).length,o=o[t-1],{l:t,z:e(o,"zIndex",-1),o:e(o,"opacity",.5),c:e(o,"color","0,0,0"),n:e(o,"count",99)}),a="c_n"+x.l,r=i.getContext("2d"),w=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(e){window.setTimeout(e,1e3/45)},m=Math.random,y={x:null,y:null,max:2e4};i.id=a,i.style.cssText="position:fixed;top:0;left:0;z-index:"+x.z+";opacity:"+x.o,document.getElementsByClassName("main")[0].appendChild(i),n(),window.onresize=n,window.onmousemove=function(e){e=e||window.event,y.x=e.clientX,y.y=e.clientY},window.onmouseout=function(){y.x=null,y.y=null};for(var s=[],h=0;x.n>h;h++){var f=m()*l,g=m()*u,p=2*m()-1,v=2*m()-1;s.push({x:f,y:g,xa:p,ya:v,max:6e3})}d=s.concat([y]),setTimeout(function(){c()},100)})();</script>
+

使用 Hydro 要花多少钱?

不要钱,我们是 AGPL 的。如果你钱多,可以 给我发个红包open in new window

execve: no such file or directory

脚本安装默认只装了一小部分编译器。请参照 编译器 章节安装配置其他编译器。

怎么自定义用户标签?

进入 MongoDB,执行下面的操作即可(根据具体情况替换尖括号中的部分):

use hydro
+db.user.update({"_id": <用户 UID>}, {$set: {"badge": "<标签内容>#<背景颜色(HEX)>#<文字颜色(HEX)>"}})
+

为什么我无法批量下载多个文件?

请使用现代浏览器进行操作,并尝试给网站设置 https。 否则请选择逐个下载文件(Ctrl+点击文件名)。

为什么我的提交页面没有语言可选?

题目 -> 评测设置 -> 允许的语言
域设置 -> 编辑域资料 -> 允许的语言
这两个地方,应该填英文逗号分隔的语言ID,不会填请留空。

The 'yarn global' commands have been remove in 2.x - consider using 'yarn dlx' or a third-party plugin instead

如果你搞不明白这个问题,请老实用安装脚本,不要折腾开发模式。

我是机房用户,大量用户同 IP 操作触发了频率限制,怎么解决?

方案一: 通过在内网架设代理服务器,将内网 ip 发送至服务端。(推荐)
方案二: 使用形如 hydrooj cli system set limit.user_login 999 的命令设置新的频率限制(可在错误页面查看具体是触发了哪条限制)
方案三: 使用 pm2 start hydrooj -- --benchmark 启动,关闭所有频率限制(不推荐)

+ + + diff --git a/api/index.html b/api/index.html new file mode 100644 index 00000000..420e1d3d --- /dev/null +++ b/api/index.html @@ -0,0 +1,40 @@ + + + + + + + + API | Hydro + + + + + + +

API


API

此处列出部分系统通信协议。

+ + + diff --git a/api/judge.html b/api/judge.html new file mode 100644 index 00000000..61b404f6 --- /dev/null +++ b/api/judge.html @@ -0,0 +1,160 @@ + + + + + + + + 评测端通信协议 | Hydro + + + + + + +

评测端通信协议


评测端通信协议

当前版本 v1 。

评测端交互流程

  • GET /judge/files (检查登陆状态是否有效,若无效则跳转登录逻辑,通常每六小时执行一次)
  • WEBSOCKET /judge/conn (主交互通道)

若登录失效,则进行登录操作。

POST /login
+
+{"uname":"USERNAME","password":"PASSWORD","rememberme":true}
+

WebSocket 连接建立流程

WEBSOCKET /judge/conn
+Authorization: Bearer COOKIE_SID
+

连接建立后,评测端向 Web 汇报当前节点状态(可选)
注:下方信息仅作数据格式展示用,不保证真实有效。

{
+    "key": "status",
+    "info": {
+        "mid": "MACHINE_ID",
+        "memory": {
+            "total": 25189552128,
+            "free": 660258800,
+            "used": 24529293328,
+            "active": 1558973164,
+            "available": 23636676608,
+            "buffers": 3075653000,
+            "cached": 1000000000,
+            "slab": 1000000000,
+            "buffcache": 1000000000,
+            "swaptotal": 0,
+            "swapused": 0,
+            "swapfree": 0
+        },
+        "cpu": {
+            "manufacturer": "Intel",
+            "brand": "Xeon® Platinum 8269CY",
+            "vendor": "Intel",
+            "family": "6",
+            "model": "85",
+            "stepping": "7",
+            "speed": 2.5,
+            "cores": 32,
+            "physicalCores": 32,
+            "processors": 2,
+            "flags": "fpu vme de pse tsc ...",
+            "cache": {
+                "l1d": 32768,
+                "l1i": 32768,
+                "l2": 262144,
+                "l3": 6291456
+            }
+        },
+        "load": {
+            "avgLoad": 0.01,
+            "currentLoad": 0.01,
+            "currentLoadUser": 0.01,
+            "currentLoadSystem": 0.01,
+            "currentLoadNice": 0.01,
+            "currentLoadIdle": 0.01,
+            "currentLoadIrq": 0.01
+        },
+        "osinfo": {
+            "platform": "linux",
+            "distro": "Ubuntu",
+            "release": "22.04.2 LTS",
+            "codename": "Jammy Jellyfish",
+            "kernel": "5.15.0-84-generic",
+            "arch": "x64",
+            "hostname": "judge",
+            "codepage": "UTF-8",
+        }
+    }
+}
+

建立连接后每隔 30s,评测端发送 {"key":"ping"}

语言配置下发

在连接建立后,Web 端会向 Judge 分发服务端的语言设置。如果客户端需要进行特殊设置,可忽略此条消息。

评测任务推送

Web 端会通过 WebSocket 向评测端推送评测任务。

{
+    "task": {
+        "type": "judge",
+        "_id": "RECORD_ID",
+        "lang": "cc.cc11",
+        "uid": SUBMITTER_UID,
+        "code": "USER_SUBMITTED_CODE",
+        "domainId": "SUBMISSION_DOMAIN_ID",
+        "pid": PROBLEM_ID,
+        "contest": "CONTEST_ID (optional)",
+        "input": "INPUT",
+        "source": "SOURCE_ID",
+        "meta": {
+            "rejudge": false,
+            "problemOwner": OWNER_UID
+        },
+        "data": [
+            {
+                "name": "FILE_NAME",
+                "size": SIZE_IN_BYTES,
+                "lastModified": "2023-11-15T08:14:57.535Z",
+                "etag": "ETAG"
+            }
+        ]
+    }
+}
+

注1:如果比赛 ID 为 000000000000000000000000 则表示此提交为自测提交,自测提交使用 input 字段值作为程序输入。
注2:source 字段为缓存 ID,同 source 字段的提交使用相同的缓存目录。
注3:source 字段包含且仅包含一个字符 /,建议使用 domainId/pid
注4:测试数据的 etag 用来识别本地缓存的文件是否与云端一致,可使用 hash 或是修改时间的时间戳。

测试数据下载

若推送的评测任务中使用了的测试数据缺失,Judge 端会向 Web 请求缺失或是修改的文件。

POST /d/:domainId/judge/files
+Cookie: sid=COOKIE_SID
+
+{"pid":PROBLEM_ID,"files":["a.in","a.out"]}
+

服务端返回如下:

{
+    "links": {
+        "a.in": "https://cdn.hydro.ac/d/DOMAIN_ID/pid/1/a.in",
+        "a.out": "https://cdn.hydro.ac/d/DOMAIN_ID/pid/1/a.out"
+    }
+}
+

评测结果上报

{
+    "key": "next/end",
+    "domainId": "DOMAIN_ID",
+    "rid": "RECORD_ID",
+
+    "message": "JUDGE_MESSAGE",
+    "compilerText": "COMPILER_OUTPUT",
+    "status": STATUS_CODE,
+    "score": SCORE,
+    "time": TIME_IN_MS,
+    "memory": MEMORY_IN_KB,
+    "progress": PROGRESS_PERCENTAGE,
+    "addProgress": PROGRESS_PERCENTAGE,
+    "case": {
+        "id": ID,
+        "subtaskId": SUBTASK_ID,
+        "score": SCORE,
+        "status": STATUS_CODE,
+        "message": "CHECKER_MESSAGE"
+    }
+}
+

key, domainId, rid 三个字段外,其他字段均为可选。关于 STATUS_CODE 含义请查看 hydro-dev/Hydro/packages/utils/lib/statusopen in new window
keyend 时表示评测任务已经完成,结果确定,Web 端可进行 AC 数计量,登记成绩表等操作。

+ + + diff --git a/assets/404.html-086ab1a5.js b/assets/404.html-086ab1a5.js new file mode 100644 index 00000000..fcf3313a --- /dev/null +++ b/assets/404.html-086ab1a5.js @@ -0,0 +1 @@ +import{_ as e}from"./plugin-vue_export-helper-c27b6911.js";import{o as t,c}from"./app-68b9e0b9.js";const o={};function r(_,n){return t(),c("div")}const f=e(o,[["render",r],["__file","404.html.vue"]]);export{f as default}; diff --git a/assets/404.html-f441bf5f.js b/assets/404.html-f441bf5f.js new file mode 100644 index 00000000..992ef993 --- /dev/null +++ b/assets/404.html-f441bf5f.js @@ -0,0 +1 @@ +const t=JSON.parse('{"key":"v-3706649a","path":"/404.html","title":"","lang":"en-US","frontmatter":{"layout":"NotFound","description":"","head":[["meta",{"property":"og:url","content":"https://hydro.js.org/404.html"}],["meta",{"property":"og:site_name","content":"Hydro"}],["meta",{"property":"og:type","content":"website"}],["meta",{"property":"og:locale","content":"en-US"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"WebPage\\",\\"name\\":\\"\\"}"]]},"headers":[],"git":{},"readingTime":{"minutes":0,"words":0},"filePathRelative":null,"autoDesc":true,"excerpt":""}');export{t as data}; diff --git a/assets/FAQ.html-a854a998.js b/assets/FAQ.html-a854a998.js new file mode 100644 index 00000000..241674d2 --- /dev/null +++ b/assets/FAQ.html-a854a998.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-6d3257b0","path":"/docs/system/FAQ.html","title":"常见问题","lang":"en-US","frontmatter":{"description":"已移动至 此处 (/FAQ/)","head":[["meta",{"property":"og:url","content":"https://hydro.js.org/docs/system/FAQ.html"}],["meta",{"property":"og:site_name","content":"Hydro"}],["meta",{"property":"og:title","content":"常见问题"}],["meta",{"property":"og:description","content":"已移动至 此处 (/FAQ/)"}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2022-03-14T10:46:41.000Z"}],["meta",{"property":"article:modified_time","content":"2022-03-14T10:46:41.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"常见问题\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2022-03-14T10:46:41.000Z\\",\\"author\\":[]}"]]},"headers":[],"git":{"createdTime":1622877676000,"updatedTime":1647254801000,"contributors":[{"name":"undefined","email":"i@undefined.moe","commits":7},{"name":"Macesuted","email":"macesuted@qq.com","commits":3},{"name":"(Macesuted)","email":"1912192337@qq.com","commits":2},{"name":"stong12345","email":"93954074@qq.com","commits":1},{"name":"zryoung","email":"riyang@qq.com","commits":1}]},"readingTime":{"minutes":0.04,"words":11},"filePathRelative":"docs/system/FAQ.md","localizedDate":"June 5, 2021","autoDesc":true,"excerpt":""}');export{e as data}; diff --git a/assets/FAQ.html-a913a06b.js b/assets/FAQ.html-a913a06b.js new file mode 100644 index 00000000..57abc859 --- /dev/null +++ b/assets/FAQ.html-a913a06b.js @@ -0,0 +1 @@ +import{_ as a}from"./plugin-vue_export-helper-c27b6911.js";import{r,o as n,c,a as e,b as t,d as s,w as _}from"./app-68b9e0b9.js";const d={},i=e("h1",{id:"常见问题",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#常见问题","aria-hidden":"true"},"#"),t(" 常见问题")],-1);function l(f,h){const o=r("RouterLink");return n(),c("div",null,[i,e("p",null,[t("已移动至 "),s(o,{to:"/FAQ/"},{default:_(()=>[t("此处")]),_:1})])])}const p=a(d,[["render",l],["__file","FAQ.html.vue"]]);export{p as default}; diff --git a/assets/KaTeX_AMS-Regular-0cdd387c.woff2 b/assets/KaTeX_AMS-Regular-0cdd387c.woff2 new file mode 100644 index 00000000..0acaaff0 Binary files /dev/null and b/assets/KaTeX_AMS-Regular-0cdd387c.woff2 differ diff --git a/assets/KaTeX_AMS-Regular-30da91e8.woff b/assets/KaTeX_AMS-Regular-30da91e8.woff new file mode 100644 index 00000000..b804d7b3 Binary files /dev/null and b/assets/KaTeX_AMS-Regular-30da91e8.woff differ diff --git a/assets/KaTeX_AMS-Regular-68534840.ttf b/assets/KaTeX_AMS-Regular-68534840.ttf new file mode 100644 index 00000000..c6f9a5e7 Binary files /dev/null and b/assets/KaTeX_AMS-Regular-68534840.ttf differ diff --git a/assets/KaTeX_Caligraphic-Bold-07d8e303.ttf b/assets/KaTeX_Caligraphic-Bold-07d8e303.ttf new file mode 100644 index 00000000..9ff4a5e0 Binary files /dev/null and b/assets/KaTeX_Caligraphic-Bold-07d8e303.ttf differ diff --git a/assets/KaTeX_Caligraphic-Bold-1ae6bd74.woff b/assets/KaTeX_Caligraphic-Bold-1ae6bd74.woff new file mode 100644 index 00000000..9759710d Binary files /dev/null and b/assets/KaTeX_Caligraphic-Bold-1ae6bd74.woff differ diff --git a/assets/KaTeX_Caligraphic-Bold-de7701e4.woff2 b/assets/KaTeX_Caligraphic-Bold-de7701e4.woff2 new file mode 100644 index 00000000..f390922e Binary files /dev/null and b/assets/KaTeX_Caligraphic-Bold-de7701e4.woff2 differ diff --git a/assets/KaTeX_Caligraphic-Regular-3398dd02.woff b/assets/KaTeX_Caligraphic-Regular-3398dd02.woff new file mode 100644 index 00000000..9bdd534f Binary files /dev/null and b/assets/KaTeX_Caligraphic-Regular-3398dd02.woff differ diff --git a/assets/KaTeX_Caligraphic-Regular-5d53e70a.woff2 b/assets/KaTeX_Caligraphic-Regular-5d53e70a.woff2 new file mode 100644 index 00000000..75344a1f Binary files /dev/null and b/assets/KaTeX_Caligraphic-Regular-5d53e70a.woff2 differ diff --git a/assets/KaTeX_Caligraphic-Regular-ed0b7437.ttf b/assets/KaTeX_Caligraphic-Regular-ed0b7437.ttf new file mode 100644 index 00000000..f522294f Binary files /dev/null and b/assets/KaTeX_Caligraphic-Regular-ed0b7437.ttf differ diff --git a/assets/KaTeX_Fraktur-Bold-74444efd.woff2 b/assets/KaTeX_Fraktur-Bold-74444efd.woff2 new file mode 100644 index 00000000..395f28be Binary files /dev/null and b/assets/KaTeX_Fraktur-Bold-74444efd.woff2 differ diff --git a/assets/KaTeX_Fraktur-Bold-9163df9c.ttf b/assets/KaTeX_Fraktur-Bold-9163df9c.ttf new file mode 100644 index 00000000..4e98259c Binary files /dev/null and b/assets/KaTeX_Fraktur-Bold-9163df9c.ttf differ diff --git a/assets/KaTeX_Fraktur-Bold-9be7ceb8.woff b/assets/KaTeX_Fraktur-Bold-9be7ceb8.woff new file mode 100644 index 00000000..e7730f66 Binary files /dev/null and b/assets/KaTeX_Fraktur-Bold-9be7ceb8.woff differ diff --git a/assets/KaTeX_Fraktur-Regular-1e6f9579.ttf b/assets/KaTeX_Fraktur-Regular-1e6f9579.ttf new file mode 100644 index 00000000..b8461b27 Binary files /dev/null and b/assets/KaTeX_Fraktur-Regular-1e6f9579.ttf differ diff --git a/assets/KaTeX_Fraktur-Regular-51814d27.woff2 b/assets/KaTeX_Fraktur-Regular-51814d27.woff2 new file mode 100644 index 00000000..735f6948 Binary files /dev/null and b/assets/KaTeX_Fraktur-Regular-51814d27.woff2 differ diff --git a/assets/KaTeX_Fraktur-Regular-5e28753b.woff b/assets/KaTeX_Fraktur-Regular-5e28753b.woff new file mode 100644 index 00000000..acab069f Binary files /dev/null and b/assets/KaTeX_Fraktur-Regular-5e28753b.woff differ diff --git a/assets/KaTeX_Main-Bold-0f60d1b8.woff2 b/assets/KaTeX_Main-Bold-0f60d1b8.woff2 new file mode 100644 index 00000000..ab2ad21d Binary files /dev/null and b/assets/KaTeX_Main-Bold-0f60d1b8.woff2 differ diff --git a/assets/KaTeX_Main-Bold-138ac28d.ttf b/assets/KaTeX_Main-Bold-138ac28d.ttf new file mode 100644 index 00000000..4060e627 Binary files /dev/null and b/assets/KaTeX_Main-Bold-138ac28d.ttf differ diff --git a/assets/KaTeX_Main-Bold-c76c5d69.woff b/assets/KaTeX_Main-Bold-c76c5d69.woff new file mode 100644 index 00000000..f38136ac Binary files /dev/null and b/assets/KaTeX_Main-Bold-c76c5d69.woff differ diff --git a/assets/KaTeX_Main-BoldItalic-70ee1f64.ttf b/assets/KaTeX_Main-BoldItalic-70ee1f64.ttf new file mode 100644 index 00000000..dc007977 Binary files /dev/null and b/assets/KaTeX_Main-BoldItalic-70ee1f64.ttf differ diff --git a/assets/KaTeX_Main-BoldItalic-99cd42a3.woff2 b/assets/KaTeX_Main-BoldItalic-99cd42a3.woff2 new file mode 100644 index 00000000..5931794d Binary files /dev/null and b/assets/KaTeX_Main-BoldItalic-99cd42a3.woff2 differ diff --git a/assets/KaTeX_Main-BoldItalic-a6f7ec0d.woff b/assets/KaTeX_Main-BoldItalic-a6f7ec0d.woff new file mode 100644 index 00000000..67807b0b Binary files /dev/null and b/assets/KaTeX_Main-BoldItalic-a6f7ec0d.woff differ diff --git a/assets/KaTeX_Main-Italic-0d85ae7c.ttf b/assets/KaTeX_Main-Italic-0d85ae7c.ttf new file mode 100644 index 00000000..0e9b0f35 Binary files /dev/null and b/assets/KaTeX_Main-Italic-0d85ae7c.ttf differ diff --git a/assets/KaTeX_Main-Italic-97479ca6.woff2 b/assets/KaTeX_Main-Italic-97479ca6.woff2 new file mode 100644 index 00000000..b50920e1 Binary files /dev/null and b/assets/KaTeX_Main-Italic-97479ca6.woff2 differ diff --git a/assets/KaTeX_Main-Italic-f1d6ef86.woff b/assets/KaTeX_Main-Italic-f1d6ef86.woff new file mode 100644 index 00000000..6f43b594 Binary files /dev/null and b/assets/KaTeX_Main-Italic-f1d6ef86.woff differ diff --git a/assets/KaTeX_Main-Regular-c2342cd8.woff2 b/assets/KaTeX_Main-Regular-c2342cd8.woff2 new file mode 100644 index 00000000..eb24a7ba Binary files /dev/null and b/assets/KaTeX_Main-Regular-c2342cd8.woff2 differ diff --git a/assets/KaTeX_Main-Regular-c6368d87.woff b/assets/KaTeX_Main-Regular-c6368d87.woff new file mode 100644 index 00000000..21f58129 Binary files /dev/null and b/assets/KaTeX_Main-Regular-c6368d87.woff differ diff --git a/assets/KaTeX_Main-Regular-d0332f52.ttf b/assets/KaTeX_Main-Regular-d0332f52.ttf new file mode 100644 index 00000000..dd45e1ed Binary files /dev/null and b/assets/KaTeX_Main-Regular-d0332f52.ttf differ diff --git a/assets/KaTeX_Math-BoldItalic-850c0af5.woff b/assets/KaTeX_Math-BoldItalic-850c0af5.woff new file mode 100644 index 00000000..0ae390d7 Binary files /dev/null and b/assets/KaTeX_Math-BoldItalic-850c0af5.woff differ diff --git a/assets/KaTeX_Math-BoldItalic-dc47344d.woff2 b/assets/KaTeX_Math-BoldItalic-dc47344d.woff2 new file mode 100644 index 00000000..29657023 Binary files /dev/null and b/assets/KaTeX_Math-BoldItalic-dc47344d.woff2 differ diff --git a/assets/KaTeX_Math-BoldItalic-f9377ab0.ttf b/assets/KaTeX_Math-BoldItalic-f9377ab0.ttf new file mode 100644 index 00000000..728ce7a1 Binary files /dev/null and b/assets/KaTeX_Math-BoldItalic-f9377ab0.ttf differ diff --git a/assets/KaTeX_Math-Italic-08ce98e5.ttf b/assets/KaTeX_Math-Italic-08ce98e5.ttf new file mode 100644 index 00000000..70d559b4 Binary files /dev/null and b/assets/KaTeX_Math-Italic-08ce98e5.ttf differ diff --git a/assets/KaTeX_Math-Italic-7af58c5e.woff2 b/assets/KaTeX_Math-Italic-7af58c5e.woff2 new file mode 100644 index 00000000..215c143f Binary files /dev/null and b/assets/KaTeX_Math-Italic-7af58c5e.woff2 differ diff --git a/assets/KaTeX_Math-Italic-8a8d2445.woff b/assets/KaTeX_Math-Italic-8a8d2445.woff new file mode 100644 index 00000000..eb5159d4 Binary files /dev/null and b/assets/KaTeX_Math-Italic-8a8d2445.woff differ diff --git a/assets/KaTeX_SansSerif-Bold-1ece03f7.ttf b/assets/KaTeX_SansSerif-Bold-1ece03f7.ttf new file mode 100644 index 00000000..2f65a8a3 Binary files /dev/null and b/assets/KaTeX_SansSerif-Bold-1ece03f7.ttf differ diff --git a/assets/KaTeX_SansSerif-Bold-e99ae511.woff2 b/assets/KaTeX_SansSerif-Bold-e99ae511.woff2 new file mode 100644 index 00000000..cfaa3bda Binary files /dev/null and b/assets/KaTeX_SansSerif-Bold-e99ae511.woff2 differ diff --git a/assets/KaTeX_SansSerif-Bold-ece03cfd.woff b/assets/KaTeX_SansSerif-Bold-ece03cfd.woff new file mode 100644 index 00000000..8d47c02d Binary files /dev/null and b/assets/KaTeX_SansSerif-Bold-ece03cfd.woff differ diff --git a/assets/KaTeX_SansSerif-Italic-00b26ac8.woff2 b/assets/KaTeX_SansSerif-Italic-00b26ac8.woff2 new file mode 100644 index 00000000..349c06dc Binary files /dev/null and b/assets/KaTeX_SansSerif-Italic-00b26ac8.woff2 differ diff --git a/assets/KaTeX_SansSerif-Italic-3931dd81.ttf b/assets/KaTeX_SansSerif-Italic-3931dd81.ttf new file mode 100644 index 00000000..d5850df9 Binary files /dev/null and b/assets/KaTeX_SansSerif-Italic-3931dd81.ttf differ diff --git a/assets/KaTeX_SansSerif-Italic-91ee6750.woff b/assets/KaTeX_SansSerif-Italic-91ee6750.woff new file mode 100644 index 00000000..7e02df96 Binary files /dev/null and b/assets/KaTeX_SansSerif-Italic-91ee6750.woff differ diff --git a/assets/KaTeX_SansSerif-Regular-11e4dc8a.woff b/assets/KaTeX_SansSerif-Regular-11e4dc8a.woff new file mode 100644 index 00000000..31b84829 Binary files /dev/null and b/assets/KaTeX_SansSerif-Regular-11e4dc8a.woff differ diff --git a/assets/KaTeX_SansSerif-Regular-68e8c73e.woff2 b/assets/KaTeX_SansSerif-Regular-68e8c73e.woff2 new file mode 100644 index 00000000..a90eea85 Binary files /dev/null and b/assets/KaTeX_SansSerif-Regular-68e8c73e.woff2 differ diff --git a/assets/KaTeX_SansSerif-Regular-f36ea897.ttf b/assets/KaTeX_SansSerif-Regular-f36ea897.ttf new file mode 100644 index 00000000..537279f6 Binary files /dev/null and b/assets/KaTeX_SansSerif-Regular-f36ea897.ttf differ diff --git a/assets/KaTeX_Script-Regular-036d4e95.woff2 b/assets/KaTeX_Script-Regular-036d4e95.woff2 new file mode 100644 index 00000000..b3048fc1 Binary files /dev/null and b/assets/KaTeX_Script-Regular-036d4e95.woff2 differ diff --git a/assets/KaTeX_Script-Regular-1c67f068.ttf b/assets/KaTeX_Script-Regular-1c67f068.ttf new file mode 100644 index 00000000..fd679bf3 Binary files /dev/null and b/assets/KaTeX_Script-Regular-1c67f068.ttf differ diff --git a/assets/KaTeX_Script-Regular-d96cdf2b.woff b/assets/KaTeX_Script-Regular-d96cdf2b.woff new file mode 100644 index 00000000..0e7da821 Binary files /dev/null and b/assets/KaTeX_Script-Regular-d96cdf2b.woff differ diff --git a/assets/KaTeX_Size1-Regular-6b47c401.woff2 b/assets/KaTeX_Size1-Regular-6b47c401.woff2 new file mode 100644 index 00000000..c5a8462f Binary files /dev/null and b/assets/KaTeX_Size1-Regular-6b47c401.woff2 differ diff --git a/assets/KaTeX_Size1-Regular-95b6d2f1.ttf b/assets/KaTeX_Size1-Regular-95b6d2f1.ttf new file mode 100644 index 00000000..871fd7d1 Binary files /dev/null and b/assets/KaTeX_Size1-Regular-95b6d2f1.ttf differ diff --git a/assets/KaTeX_Size1-Regular-c943cc98.woff b/assets/KaTeX_Size1-Regular-c943cc98.woff new file mode 100644 index 00000000..7f292d91 Binary files /dev/null and b/assets/KaTeX_Size1-Regular-c943cc98.woff differ diff --git a/assets/KaTeX_Size2-Regular-2014c523.woff b/assets/KaTeX_Size2-Regular-2014c523.woff new file mode 100644 index 00000000..d241d9be Binary files /dev/null and b/assets/KaTeX_Size2-Regular-2014c523.woff differ diff --git a/assets/KaTeX_Size2-Regular-a6b2099f.ttf b/assets/KaTeX_Size2-Regular-a6b2099f.ttf new file mode 100644 index 00000000..7a212caf Binary files /dev/null and b/assets/KaTeX_Size2-Regular-a6b2099f.ttf differ diff --git a/assets/KaTeX_Size2-Regular-d04c5421.woff2 b/assets/KaTeX_Size2-Regular-d04c5421.woff2 new file mode 100644 index 00000000..e1bccfe2 Binary files /dev/null and b/assets/KaTeX_Size2-Regular-d04c5421.woff2 differ diff --git a/assets/KaTeX_Size3-Regular-500e04d5.ttf b/assets/KaTeX_Size3-Regular-500e04d5.ttf new file mode 100644 index 00000000..00bff349 Binary files /dev/null and b/assets/KaTeX_Size3-Regular-500e04d5.ttf differ diff --git a/assets/KaTeX_Size3-Regular-6ab6b62e.woff b/assets/KaTeX_Size3-Regular-6ab6b62e.woff new file mode 100644 index 00000000..e6e9b658 Binary files /dev/null and b/assets/KaTeX_Size3-Regular-6ab6b62e.woff differ diff --git a/assets/KaTeX_Size4-Regular-99f9c675.woff b/assets/KaTeX_Size4-Regular-99f9c675.woff new file mode 100644 index 00000000..e1ec5457 Binary files /dev/null and b/assets/KaTeX_Size4-Regular-99f9c675.woff differ diff --git a/assets/KaTeX_Size4-Regular-a4af7d41.woff2 b/assets/KaTeX_Size4-Regular-a4af7d41.woff2 new file mode 100644 index 00000000..680c1308 Binary files /dev/null and b/assets/KaTeX_Size4-Regular-a4af7d41.woff2 differ diff --git a/assets/KaTeX_Size4-Regular-c647367d.ttf b/assets/KaTeX_Size4-Regular-c647367d.ttf new file mode 100644 index 00000000..74f08921 Binary files /dev/null and b/assets/KaTeX_Size4-Regular-c647367d.ttf differ diff --git a/assets/KaTeX_Typewriter-Regular-71d517d6.woff2 b/assets/KaTeX_Typewriter-Regular-71d517d6.woff2 new file mode 100644 index 00000000..771f1af7 Binary files /dev/null and b/assets/KaTeX_Typewriter-Regular-71d517d6.woff2 differ diff --git a/assets/KaTeX_Typewriter-Regular-e14fed02.woff b/assets/KaTeX_Typewriter-Regular-e14fed02.woff new file mode 100644 index 00000000..2432419f Binary files /dev/null and b/assets/KaTeX_Typewriter-Regular-e14fed02.woff differ diff --git a/assets/KaTeX_Typewriter-Regular-f01f3e87.ttf b/assets/KaTeX_Typewriter-Regular-f01f3e87.ttf new file mode 100644 index 00000000..c83252c5 Binary files /dev/null and b/assets/KaTeX_Typewriter-Regular-f01f3e87.ttf differ diff --git a/assets/PERM_PRIV.html-b2407ae4.js b/assets/PERM_PRIV.html-b2407ae4.js new file mode 100644 index 00000000..1e8d1346 --- /dev/null +++ b/assets/PERM_PRIV.html-b2407ae4.js @@ -0,0 +1 @@ +import{_ as t}from"./plugin-vue_export-helper-c27b6911.js";import{r as n,o as a,c,a as e,b as o,d as s}from"./app-68b9e0b9.js";const l={},_=e("h1",{id:"权限节点",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#权限节点","aria-hidden":"true"},"#"),o(" 权限节点")],-1),d=e("p",null,[o("Hydro 的权限使用位运算处理。"),e("br"),o(" 例:若某用户具有 "),e("code",null,"PRIV_EDIT_SYSTEM"),o(" 与 "),e("code",null,"PRIV_SET_PERM"),o(" 权限,应设置为 "),e("code",null,"(1<<0)|(1<<1)"),o(" (即 3)")],-1),i={href:"https://github.com/hydro-dev/Hydro/blob/master/packages/hydrooj/src/model/builtin.ts",target:"_blank",rel:"noopener noreferrer"};function h(m,u){const r=n("ExternalLinkIcon");return a(),c("div",null,[_,d,e("p",null,[o("可以看 "),e("a",i,[o("代码"),s(r)]),o(" 中关于此部分的内容。")])])}const E=t(l,[["render",h],["__file","PERM_PRIV.html.vue"]]);export{E as default}; diff --git a/assets/PERM_PRIV.html-d6a6de2f.js b/assets/PERM_PRIV.html-d6a6de2f.js new file mode 100644 index 00000000..32735678 --- /dev/null +++ b/assets/PERM_PRIV.html-d6a6de2f.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-82f2a624","path":"/dev/PERM_PRIV.html","title":"权限节点","lang":"en-US","frontmatter":{"description":"Hydro 的权限使用位运算处理。 例:若某用户具有 PRIVEDITSYSTEM 与 PRIVSETPERM 权限,应设置为 `(1","head":[["meta",{"property":"og:url","content":"https://hydro.js.org/dev/PERM_PRIV.html"}],["meta",{"property":"og:site_name","content":"Hydro"}],["meta",{"property":"og:title","content":"权限节点"}],["meta",{"property":"og:description","content":"Hydro 的权限使用位运算处理。 例:若某用户具有 PRIVEDITSYSTEM 与 PRIVSETPERM 权限,应设置为 `(1"}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2022-12-09T10:31:58.000Z"}],["meta",{"property":"article:modified_time","content":"2022-12-09T10:31:58.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"权限节点\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2022-12-09T10:31:58.000Z\\",\\"author\\":[]}"]]},"headers":[],"git":{"createdTime":1611599229000,"updatedTime":1670581918000,"contributors":[{"name":"Macesuted Kysic","email":"macesuted@foxmail.com","commits":3},{"name":"(Macesuted)","email":"macesuted@foxmail.com","commits":1},{"name":"Macesuted","email":"57275149+Macesuted@users.noreply.github.com","commits":1},{"name":"Macesuted","email":"macesuted@qq.com","commits":1},{"name":"undefined","email":"i@undefined.moe","commits":1}]},"readingTime":{"minutes":0.18,"words":54},"filePathRelative":"dev/PERM_PRIV.md","localizedDate":"January 25, 2021","autoDesc":true,"excerpt":""}');export{e as data}; diff --git a/assets/SearchResult-415a63eb.js b/assets/SearchResult-415a63eb.js new file mode 100644 index 00000000..73169fdd --- /dev/null +++ b/assets/SearchResult-415a63eb.js @@ -0,0 +1 @@ +import{u as I,g as M,h as O,i as E,j as V,v as W,t as J,k as w,l as H,m as K,n as P,p as t,R as A,q as N,s as T,x as X,y as Y,z as Z,A as _,B as ee,C as te,L as se,H as ae,D as le,E as ue,F as re,G as q}from"./app-68b9e0b9.js";const ne="search-pro-result-history",o=I(ne,[]),oe=()=>{const{resultHistoryCount:u}=q,c=u>0;return{enabled:c,resultHistory:o,addResultHistory:l=>{c&&(o.value.length{o.value=[...o.value.slice(0,l),...o.value.slice(l+1)]}}},ce=u=>{const c=E(),l=w(!1),h=ee([]);let i;const v=ue(d=>{l.value=!0,i==null||i.terminate(),d?(i=new Worker(`/${q.worker}`,{}),i.addEventListener("message",({data:g})=>{h.value=g,l.value=!1}),i.postMessage({query:d,routeLocale:c.value})):(h.value=[],l.value=!1)},q.delay);return P([u,c],()=>v(u.value),{immediate:!0}),{searching:l,results:h}};var ve=M({name:"SearchResult",props:{query:{type:String,required:!0}},emits:["close","updateQuery"],setup(u,{emit:c}){const l=te(),h=O(),i=E(),v=V(W),{addQueryHistory:d}=se(),{enabled:g,resultHistory:L,addResultHistory:C,removeResultHistory:Q}=oe(),R=J(u,"query"),{results:y,searching:j}=ce(R),r=w(0),a=w(0),D=H(()=>L.value.length>0),f=H(()=>y.value.length>0),$=H(()=>y.value[r.value]||null),F=()=>{r.value=r.value>0?r.value-1:y.value.length-1,a.value=$.value.contents.length-1},U=()=>{r.value=r.value{a.value<$.value.contents.length-1?a.value=a.value+1:U()},B=()=>{a.value>0?a.value=a.value-1:F()},b=e=>e.map(s=>re(s)?s:t(s[0],s[1])),S=e=>{if(e.type==="custom"){const s=ae[e.index]||"$content",[p,m=""]=le(s)?s[i.value].split("$content"):s.split("$content");return b([p,...e.display,m])}return b(e.display)},k=()=>{r.value=0,a.value=0,c("updateQuery",""),c("close")};return K("keydown",e=>{if(f.value){if(e.key==="ArrowUp")B();else if(e.key==="ArrowDown")z();else if(e.key==="Enter"){const s=$.value.contents[a.value];l.value.path!==s.path&&(d(u.query),C(s),h.push(s.path),k())}}}),P([r,a],()=>{var e;(e=document.querySelector(".search-pro-result-list-item.active .search-pro-result-item.active"))==null||e.scrollIntoView(!1)},{flush:"post"}),()=>t("div",{class:["search-pro-result",{empty:R.value?!f.value:!D.value}],id:"search-pro-results"},R.value===""?D.value?t("ul",{class:"search-pro-result-list"},t("li",{class:"search-pro-result-list-item"},[t("div",{class:"search-pro-result-title"},v.value.history),L.value.map((e,s)=>t(A,{to:e.path,class:["search-pro-result-item",{active:a.value===s}],onClick:()=>{k()}},()=>[t(N,{class:"search-pro-result-type"}),t("div",{class:"search-pro-result-content"},[e.type==="content"&&e.header?t("div",{class:"content-header"},e.header):null,t("div",S(e))]),t("button",{class:"search-pro-close-icon",onClick:p=>{p.preventDefault(),p.stopPropagation(),Q(s)}},t(T))]))])):g?v.value.emptyHistory:v.value.emptyResult:j.value?t(X,{hint:v.value.searching}):f.value?t("ul",{class:"search-pro-result-list"},y.value.map(({title:e,contents:s},p)=>{const m=r.value===p;return t("li",{class:["search-pro-result-list-item",{active:m}]},[t("div",{class:"search-pro-result-title"},e||"Documentation"),s.map((n,G)=>{const x=m&&a.value===G;return t(A,{to:n.path,class:["search-pro-result-item",{active:x,"aria-selected":x}],onClick:()=>{d(u.query),C(n),k()}},()=>[n.type==="content"?null:t(n.type==="title"?Y:n.type==="heading"?Z:_,{class:"search-pro-result-type"}),t("div",{class:"search-pro-result-content"},[n.type==="content"&&n.header?t("div",{class:"content-header"},n.header):null,t("div",S(n))])])})])})):v.value.emptyResult)}});export{ve as default}; diff --git a/assets/app-68b9e0b9.js b/assets/app-68b9e0b9.js new file mode 100644 index 00000000..e656fbc2 --- /dev/null +++ b/assets/app-68b9e0b9.js @@ -0,0 +1,8 @@ +const Rc="modulepreload",Oc=function(e){return"/"+e},kl={},$=function(t,n,r){if(!n||n.length===0)return t();const o=document.getElementsByTagName("link");return Promise.all(n.map(l=>{if(l=Oc(l),l in kl)return;kl[l]=!0;const s=l.endsWith(".css"),a=s?'[rel="stylesheet"]':"";if(!!r)for(let f=o.length-1;f>=0;f--){const d=o[f];if(d.href===l&&(!s||d.rel==="stylesheet"))return}else if(document.querySelector(`link[href="${l}"]${a}`))return;const c=document.createElement("link");if(c.rel=s?"stylesheet":Rc,s||(c.as="script",c.crossOrigin=""),c.href=l,document.head.appendChild(c),s)return new Promise((f,d)=>{c.addEventListener("load",f),c.addEventListener("error",()=>d(new Error(`Unable to preload CSS for ${l}`)))})})).then(()=>t())};function Mo(e,t){const n=Object.create(null),r=e.split(",");for(let o=0;o!!n[o.toLowerCase()]:o=>!!n[o]}const be={},sn=[],Ze=()=>{},Sc=()=>!1,Ic=/^on[^a-z]/,Jn=e=>Ic.test(e),Do=e=>e.startsWith("onUpdate:"),Ce=Object.assign,No=(e,t)=>{const n=e.indexOf(t);n>-1&&e.splice(n,1)},$c=Object.prototype.hasOwnProperty,se=(e,t)=>$c.call(e,t),Q=Array.isArray,$n=e=>Sr(e)==="[object Map]",Mc=e=>Sr(e)==="[object Set]",te=e=>typeof e=="function",ue=e=>typeof e=="string",Fo=e=>typeof e=="symbol",we=e=>e!==null&&typeof e=="object",Ys=e=>we(e)&&te(e.then)&&te(e.catch),Dc=Object.prototype.toString,Sr=e=>Dc.call(e),Nc=e=>Sr(e).slice(8,-1),Fc=e=>Sr(e)==="[object Object]",Ho=e=>ue(e)&&e!=="NaN"&&e[0]!=="-"&&""+parseInt(e,10)===e,Mn=Mo(",key,ref,ref_for,ref_key,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted"),Ir=e=>{const t=Object.create(null);return n=>t[n]||(t[n]=e(n))},Hc=/-(\w)/g,We=Ir(e=>e.replace(Hc,(t,n)=>n?n.toUpperCase():"")),Bc=/\B([A-Z])/g,_n=Ir(e=>e.replace(Bc,"-$1").toLowerCase()),Xn=Ir(e=>e.charAt(0).toUpperCase()+e.slice(1)),Kr=Ir(e=>e?`on${Xn(e)}`:""),jn=(e,t)=>!Object.is(e,t),Yr=(e,t)=>{for(let n=0;n{Object.defineProperty(e,t,{configurable:!0,enumerable:!1,value:n})},Vc=e=>{const t=parseFloat(e);return isNaN(t)?e:t},jc=e=>{const t=ue(e)?Number(e):NaN;return isNaN(t)?e:t};let Ll;const ho=()=>Ll||(Ll=typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:typeof global<"u"?global:{});function Bo(e){if(Q(e)){const t={};for(let n=0;n{if(n){const r=n.split(Uc);r.length>1&&(t[r[0].trim()]=r[1].trim())}}),t}function Vo(e){let t="";if(ue(e))t=e;else if(Q(e))for(let n=0;n{const t=new Set(e);return t.w=0,t.n=0,t},Js=e=>(e.w&$t)>0,Xs=e=>(e.n&$t)>0,Xc=({deps:e})=>{if(e.length)for(let t=0;t{const{deps:t}=e;if(t.length){let n=0;for(let r=0;r{(f==="length"||f>=i)&&a.push(c)})}else switch(n!==void 0&&a.push(s.get(n)),t){case"add":Q(e)?Ho(n)&&a.push(s.get("length")):(a.push(s.get(Ut)),$n(e)&&a.push(s.get(mo)));break;case"delete":Q(e)||(a.push(s.get(Ut)),$n(e)&&a.push(s.get(mo)));break;case"set":$n(e)&&a.push(s.get(Ut));break}if(a.length===1)a[0]&&go(a[0]);else{const i=[];for(const c of a)c&&i.push(...c);go(jo(i))}}function go(e,t){const n=Q(e)?e:[...e];for(const r of n)r.computed&&Ol(r);for(const r of n)r.computed||Ol(r)}function Ol(e,t){(e!==Je||e.allowRecurse)&&(e.scheduler?e.scheduler():e.run())}function eu(e,t){var n;return(n=Er.get(e))==null?void 0:n.get(t)}const tu=Mo("__proto__,__v_isRef,__isVue"),ta=new Set(Object.getOwnPropertyNames(Symbol).filter(e=>e!=="arguments"&&e!=="caller").map(e=>Symbol[e]).filter(Fo)),nu=Uo(),ru=Uo(!1,!0),ou=Uo(!0),Sl=lu();function lu(){const e={};return["includes","indexOf","lastIndexOf"].forEach(t=>{e[t]=function(...n){const r=oe(this);for(let l=0,s=this.length;l{e[t]=function(...n){wn();const r=oe(this)[t].apply(this,n);return En(),r}}),e}function su(e){const t=oe(this);return Ne(t,"has",e),t.hasOwnProperty(e)}function Uo(e=!1,t=!1){return function(r,o,l){if(o==="__v_isReactive")return!e;if(o==="__v_isReadonly")return e;if(o==="__v_isShallow")return t;if(o==="__v_raw"&&l===(e?t?Eu:sa:t?la:oa).get(r))return r;const s=Q(r);if(!e){if(s&&se(Sl,o))return Reflect.get(Sl,o,l);if(o==="hasOwnProperty")return su}const a=Reflect.get(r,o,l);return(Fo(o)?ta.has(o):tu(o))||(e||Ne(r,"get",o),t)?a:Pe(a)?s&&Ho(o)?a:a.value:we(a)?e?Cn(a):Tn(a):a}}const au=na(),iu=na(!0);function na(e=!1){return function(n,r,o,l){let s=n[r];if(dn(s)&&Pe(s)&&!Pe(o))return!1;if(!e&&(!Tr(o)&&!dn(o)&&(s=oe(s),o=oe(o)),!Q(n)&&Pe(s)&&!Pe(o)))return s.value=o,!0;const a=Q(n)&&Ho(r)?Number(r)e,$r=e=>Reflect.getPrototypeOf(e);function ar(e,t,n=!1,r=!1){e=e.__v_raw;const o=oe(e),l=oe(t);n||(t!==l&&Ne(o,"get",t),Ne(o,"get",l));const{has:s}=$r(o),a=r?qo:n?Yo:zn;if(s.call(o,t))return a(e.get(t));if(s.call(o,l))return a(e.get(l));e!==o&&e.get(t)}function ir(e,t=!1){const n=this.__v_raw,r=oe(n),o=oe(e);return t||(e!==o&&Ne(r,"has",e),Ne(r,"has",o)),e===o?n.has(e):n.has(e)||n.has(o)}function cr(e,t=!1){return e=e.__v_raw,!t&&Ne(oe(e),"iterate",Ut),Reflect.get(e,"size",e)}function Il(e){e=oe(e);const t=oe(this);return $r(t).has.call(t,e)||(t.add(e),gt(t,"add",e,e)),this}function $l(e,t){t=oe(t);const n=oe(this),{has:r,get:o}=$r(n);let l=r.call(n,e);l||(e=oe(e),l=r.call(n,e));const s=o.call(n,e);return n.set(e,t),l?jn(t,s)&>(n,"set",e,t):gt(n,"add",e,t),this}function Ml(e){const t=oe(this),{has:n,get:r}=$r(t);let o=n.call(t,e);o||(e=oe(e),o=n.call(t,e)),r&&r.call(t,e);const l=t.delete(e);return o&>(t,"delete",e,void 0),l}function Dl(){const e=oe(this),t=e.size!==0,n=e.clear();return t&>(e,"clear",void 0,void 0),n}function ur(e,t){return function(r,o){const l=this,s=l.__v_raw,a=oe(s),i=t?qo:e?Yo:zn;return!e&&Ne(a,"iterate",Ut),s.forEach((c,f)=>r.call(o,i(c),i(f),l))}}function fr(e,t,n){return function(...r){const o=this.__v_raw,l=oe(o),s=$n(l),a=e==="entries"||e===Symbol.iterator&&s,i=e==="keys"&&s,c=o[e](...r),f=n?qo:t?Yo:zn;return!t&&Ne(l,"iterate",i?mo:Ut),{next(){const{value:d,done:p}=c.next();return p?{value:d,done:p}:{value:a?[f(d[0]),f(d[1])]:f(d),done:p}},[Symbol.iterator](){return this}}}}function Ct(e){return function(...t){return e==="delete"?!1:this}}function hu(){const e={get(l){return ar(this,l)},get size(){return cr(this)},has:ir,add:Il,set:$l,delete:Ml,clear:Dl,forEach:ur(!1,!1)},t={get(l){return ar(this,l,!1,!0)},get size(){return cr(this)},has:ir,add:Il,set:$l,delete:Ml,clear:Dl,forEach:ur(!1,!0)},n={get(l){return ar(this,l,!0)},get size(){return cr(this,!0)},has(l){return ir.call(this,l,!0)},add:Ct("add"),set:Ct("set"),delete:Ct("delete"),clear:Ct("clear"),forEach:ur(!0,!1)},r={get(l){return ar(this,l,!0,!0)},get size(){return cr(this,!0)},has(l){return ir.call(this,l,!0)},add:Ct("add"),set:Ct("set"),delete:Ct("delete"),clear:Ct("clear"),forEach:ur(!0,!0)};return["keys","values","entries",Symbol.iterator].forEach(l=>{e[l]=fr(l,!1,!1),n[l]=fr(l,!0,!1),t[l]=fr(l,!1,!0),r[l]=fr(l,!0,!0)}),[e,n,t,r]}const[vu,mu,gu,yu]=hu();function Wo(e,t){const n=t?e?yu:gu:e?mu:vu;return(r,o,l)=>o==="__v_isReactive"?!e:o==="__v_isReadonly"?e:o==="__v_raw"?r:Reflect.get(se(n,o)&&o in r?n:r,o,l)}const bu={get:Wo(!1,!1)},_u={get:Wo(!1,!0)},wu={get:Wo(!0,!1)},oa=new WeakMap,la=new WeakMap,sa=new WeakMap,Eu=new WeakMap;function Tu(e){switch(e){case"Object":case"Array":return 1;case"Map":case"Set":case"WeakMap":case"WeakSet":return 2;default:return 0}}function Cu(e){return e.__v_skip||!Object.isExtensible(e)?0:Tu(Nc(e))}function Tn(e){return dn(e)?e:Ko(e,!1,ra,bu,oa)}function xu(e){return Ko(e,!1,pu,_u,la)}function Cn(e){return Ko(e,!0,du,wu,sa)}function Ko(e,t,n,r,o){if(!we(e)||e.__v_raw&&!(t&&e.__v_isReactive))return e;const l=o.get(e);if(l)return l;const s=Cu(e);if(s===0)return e;const a=new Proxy(e,s===2?r:n);return o.set(e,a),a}function an(e){return dn(e)?an(e.__v_raw):!!(e&&e.__v_isReactive)}function dn(e){return!!(e&&e.__v_isReadonly)}function Tr(e){return!!(e&&e.__v_isShallow)}function aa(e){return an(e)||dn(e)}function oe(e){const t=e&&e.__v_raw;return t?oe(t):e}function ia(e){return wr(e,"__v_skip",!0),e}const zn=e=>we(e)?Tn(e):e,Yo=e=>we(e)?Cn(e):e;function Go(e){Ot&&Je&&(e=oe(e),ea(e.dep||(e.dep=jo())))}function Qo(e,t){e=oe(e);const n=e.dep;n&&go(n)}function Pe(e){return!!(e&&e.__v_isRef===!0)}function X(e){return ca(e,!1)}function bt(e){return ca(e,!0)}function ca(e,t){return Pe(e)?e:new Au(e,t)}class Au{constructor(t,n){this.__v_isShallow=n,this.dep=void 0,this.__v_isRef=!0,this._rawValue=n?t:oe(t),this._value=n?t:zn(t)}get value(){return Go(this),this._value}set value(t){const n=this.__v_isShallow||Tr(t)||dn(t);t=n?t:oe(t),jn(t,this._rawValue)&&(this._rawValue=t,this._value=n?t:zn(t),Qo(this))}}function qt(e){return Pe(e)?e.value:e}const Pu={get:(e,t,n)=>qt(Reflect.get(e,t,n)),set:(e,t,n,r)=>{const o=e[t];return Pe(o)&&!Pe(n)?(o.value=n,!0):Reflect.set(e,t,n,r)}};function ua(e){return an(e)?e:new Proxy(e,Pu)}class ku{constructor(t){this.dep=void 0,this.__v_isRef=!0;const{get:n,set:r}=t(()=>Go(this),()=>Qo(this));this._get=n,this._set=r}get value(){return this._get()}set value(t){this._set(t)}}function Lu(e){return new ku(e)}class Ru{constructor(t,n,r){this._object=t,this._key=n,this._defaultValue=r,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 eu(oe(this._object),this._key)}}class Ou{constructor(t){this._getter=t,this.__v_isRef=!0,this.__v_isReadonly=!0}get value(){return this._getter()}}function Mr(e,t,n){return Pe(e)?e:te(e)?new Ou(e):we(e)&&arguments.length>1?Su(e,t,n):X(e)}function Su(e,t,n){const r=e[t];return Pe(r)?r:new Ru(e,t,n)}class Iu{constructor(t,n,r,o){this._setter=n,this.dep=void 0,this.__v_isRef=!0,this.__v_isReadonly=!1,this._dirty=!0,this.effect=new zo(t,()=>{this._dirty||(this._dirty=!0,Qo(this))}),this.effect.computed=this,this.effect.active=this._cacheable=!o,this.__v_isReadonly=r}get value(){const t=oe(this);return Go(t),(t._dirty||!t._cacheable)&&(t._dirty=!1,t._value=t.effect.run()),t._value}set value(t){this._setter(t)}}function $u(e,t,n=!1){let r,o;const l=te(e);return l?(r=e,o=Ze):(r=e.get,o=e.set),new Iu(r,o,l||!o,n)}function St(e,t,n,r){let o;try{o=r?e(...r):e()}catch(l){Zn(l,t,n)}return o}function Ue(e,t,n,r){if(te(e)){const l=St(e,t,n,r);return l&&Ys(l)&&l.catch(s=>{Zn(s,t,n)}),l}const o=[];for(let l=0;l>>1;qn(Oe[r])st&&Oe.splice(t,1)}function Fu(e){Q(e)?cn.push(...e):(!pt||!pt.includes(e,e.allowRecurse?Vt+1:Vt))&&cn.push(e),da()}function Nl(e,t=Un?st+1:0){for(;tqn(n)-qn(r)),Vt=0;Vte.id==null?1/0:e.id,Hu=(e,t)=>{const n=qn(e)-qn(t);if(n===0){if(e.pre&&!t.pre)return-1;if(t.pre&&!e.pre)return 1}return n};function pa(e){yo=!1,Un=!0,Oe.sort(Hu);const t=Ze;try{for(st=0;stue(g)?g.trim():g)),d&&(o=n.map(Vc))}let a,i=r[a=Kr(t)]||r[a=Kr(We(t))];!i&&l&&(i=r[a=Kr(_n(t))]),i&&Ue(i,e,6,o);const c=r[a+"Once"];if(c){if(!e.emitted)e.emitted={};else if(e.emitted[a])return;e.emitted[a]=!0,Ue(c,e,6,o)}}function ha(e,t,n=!1){const r=t.emitsCache,o=r.get(e);if(o!==void 0)return o;const l=e.emits;let s={},a=!1;if(!te(e)){const i=c=>{const f=ha(c,t,!0);f&&(a=!0,Ce(s,f))};!n&&t.mixins.length&&t.mixins.forEach(i),e.extends&&i(e.extends),e.mixins&&e.mixins.forEach(i)}return!l&&!a?(we(e)&&r.set(e,null),null):(Q(l)?l.forEach(i=>s[i]=null):Ce(s,l),we(e)&&r.set(e,s),s)}function Nr(e,t){return!e||!Jn(t)?!1:(t=t.slice(2).replace(/Once$/,""),se(e,t[0].toLowerCase()+t.slice(1))||se(e,_n(t))||se(e,t))}let ze=null,va=null;function xr(e){const t=ze;return ze=e,va=e&&e.type.__scopeId||null,t}function Vu(e,t=ze,n){if(!t||e._n)return e;const r=(...o)=>{r._d&&Gl(-1);const l=xr(t);let s;try{s=e(...o)}finally{xr(l),r._d&&Gl(1)}return s};return r._n=!0,r._c=!0,r._d=!0,r}function Gr(e){const{type:t,vnode:n,proxy:r,withProxy:o,props:l,propsOptions:[s],slots:a,attrs:i,emit:c,render:f,renderCache:d,data:p,setupState:g,ctx:_,inheritAttrs:w}=e;let E,m;const b=xr(e);try{if(n.shapeFlag&4){const O=o||r;E=Qe(f.call(O,O,d,l,g,p,_)),m=i}else{const O=t;E=Qe(O.length>1?O(l,{attrs:i,slots:a,emit:c}):O(l,null)),m=t.props?i:ju(i)}}catch(O){Hn.length=0,Zn(O,e,1),E=Te(qe)}let S=E;if(m&&w!==!1){const O=Object.keys(m),{shapeFlag:z}=S;O.length&&z&7&&(s&&O.some(Do)&&(m=zu(m,s)),S=Mt(S,m))}return n.dirs&&(S=Mt(S),S.dirs=S.dirs?S.dirs.concat(n.dirs):n.dirs),n.transition&&(S.transition=n.transition),E=S,xr(b),E}const ju=e=>{let t;for(const n in e)(n==="class"||n==="style"||Jn(n))&&((t||(t={}))[n]=e[n]);return t},zu=(e,t)=>{const n={};for(const r in e)(!Do(r)||!(r.slice(9)in t))&&(n[r]=e[r]);return n};function Uu(e,t,n){const{props:r,children:o,component:l}=e,{props:s,children:a,patchFlag:i}=t,c=l.emitsOptions;if(t.dirs||t.transition)return!0;if(n&&i>=0){if(i&1024)return!0;if(i&16)return r?Fl(r,s,c):!!s;if(i&8){const f=t.dynamicProps;for(let d=0;de.__isSuspense;function ma(e,t){t&&t.pendingBranch?Q(e)?t.effects.push(...e):t.effects.push(e):Fu(e)}function Ku(e,t){return Xo(e,null,t)}const dr={};function fe(e,t,n){return Xo(e,t,n)}function Xo(e,t,{immediate:n,deep:r,flush:o,onTrack:l,onTrigger:s}=be){var a;const i=Qs()===((a=Ae)==null?void 0:a.scope)?Ae:null;let c,f=!1,d=!1;if(Pe(e)?(c=()=>e.value,f=Tr(e)):an(e)?(c=()=>e,r=!0):Q(e)?(d=!0,f=e.some(O=>an(O)||Tr(O)),c=()=>e.map(O=>{if(Pe(O))return O.value;if(an(O))return rn(O);if(te(O))return St(O,i,2)})):te(e)?t?c=()=>St(e,i,2):c=()=>{if(!(i&&i.isUnmounted))return p&&p(),Ue(e,i,3,[g])}:c=Ze,t&&r){const O=c;c=()=>rn(O())}let p,g=O=>{p=b.onStop=()=>{St(O,i,4)}},_;if(vn)if(g=Ze,t?n&&Ue(t,i,3,[c(),d?[]:void 0,g]):c(),o==="sync"){const O=zf();_=O.__watcherHandles||(O.__watcherHandles=[])}else return Ze;let w=d?new Array(e.length).fill(dr):dr;const E=()=>{if(b.active)if(t){const O=b.run();(r||f||(d?O.some((z,R)=>jn(z,w[R])):jn(O,w)))&&(p&&p(),Ue(t,i,3,[O,w===dr?void 0:d&&w[0]===dr?[]:w,g]),w=O)}else b.run()};E.allowRecurse=!!t;let m;o==="sync"?m=E:o==="post"?m=()=>Me(E,i&&i.suspense):(E.pre=!0,i&&(E.id=i.uid),m=()=>Dr(E));const b=new zo(c,m);t?n?E():w=b.run():o==="post"?Me(b.run.bind(b),i&&i.suspense):b.run();const S=()=>{b.stop(),i&&i.scope&&No(i.scope.effects,b)};return _&&_.push(S),S}function Yu(e,t,n){const r=this.proxy,o=ue(e)?e.includes(".")?ga(r,e):()=>r[e]:e.bind(r,r);let l;te(t)?l=t:(l=t.handler,n=t);const s=Ae;hn(this);const a=Xo(o,l.bind(r),n);return s?hn(s):Kt(),a}function ga(e,t){const n=t.split(".");return()=>{let r=e;for(let o=0;o{rn(n,t)});else if(Fc(e))for(const n in e)rn(e[n],t);return e}function lt(e,t,n,r){const o=e.dirs,l=t&&t.dirs;for(let s=0;s{e.isMounted=!0}),el(()=>{e.isUnmounting=!0}),e}const Ve=[Function,Array],ba={mode:String,appear:Boolean,persisted:Boolean,onBeforeEnter:Ve,onEnter:Ve,onAfterEnter:Ve,onEnterCancelled:Ve,onBeforeLeave:Ve,onLeave:Ve,onAfterLeave:Ve,onLeaveCancelled:Ve,onBeforeAppear:Ve,onAppear:Ve,onAfterAppear:Ve,onAppearCancelled:Ve},Gu={name:"BaseTransition",props:ba,setup(e,{slots:t}){const n=xn(),r=ya();let o;return()=>{const l=t.default&&Zo(t.default(),!0);if(!l||!l.length)return;let s=l[0];if(l.length>1){for(const w of l)if(w.type!==qe){s=w;break}}const a=oe(e),{mode:i}=a;if(r.isLeaving)return Qr(s);const c=Hl(s);if(!c)return Qr(s);const f=Wn(c,a,r,n);Kn(c,f);const d=n.subTree,p=d&&Hl(d);let g=!1;const{getTransitionKey:_}=c.type;if(_){const w=_();o===void 0?o=w:w!==o&&(o=w,g=!0)}if(p&&p.type!==qe&&(!jt(c,p)||g)){const w=Wn(p,a,r,n);if(Kn(p,w),i==="out-in")return r.isLeaving=!0,w.afterLeave=()=>{r.isLeaving=!1,n.update.active!==!1&&n.update()},Qr(s);i==="in-out"&&c.type!==qe&&(w.delayLeave=(E,m,b)=>{const S=_a(r,p);S[String(p.key)]=p,E._leaveCb=()=>{m(),E._leaveCb=void 0,delete f.delayedLeave},f.delayedLeave=b})}return s}}},Qu=Gu;function _a(e,t){const{leavingVNodes:n}=e;let r=n.get(t.type);return r||(r=Object.create(null),n.set(t.type,r)),r}function Wn(e,t,n,r){const{appear:o,mode:l,persisted:s=!1,onBeforeEnter:a,onEnter:i,onAfterEnter:c,onEnterCancelled:f,onBeforeLeave:d,onLeave:p,onAfterLeave:g,onLeaveCancelled:_,onBeforeAppear:w,onAppear:E,onAfterAppear:m,onAppearCancelled:b}=t,S=String(e.key),O=_a(n,e),z=(P,V)=>{P&&Ue(P,r,9,V)},R=(P,V)=>{const G=V[1];z(P,V),Q(P)?P.every(re=>re.length<=1)&&G():P.length<=1&&G()},Y={mode:l,persisted:s,beforeEnter(P){let V=a;if(!n.isMounted)if(o)V=w||a;else return;P._leaveCb&&P._leaveCb(!0);const G=O[S];G&&jt(e,G)&&G.el._leaveCb&&G.el._leaveCb(),z(V,[P])},enter(P){let V=i,G=c,re=f;if(!n.isMounted)if(o)V=E||i,G=m||c,re=b||f;else return;let H=!1;const Z=P._enterCb=U=>{H||(H=!0,U?z(re,[P]):z(G,[P]),Y.delayedLeave&&Y.delayedLeave(),P._enterCb=void 0)};V?R(V,[P,Z]):Z()},leave(P,V){const G=String(e.key);if(P._enterCb&&P._enterCb(!0),n.isUnmounting)return V();z(d,[P]);let re=!1;const H=P._leaveCb=Z=>{re||(re=!0,V(),Z?z(_,[P]):z(g,[P]),P._leaveCb=void 0,O[G]===e&&delete O[G])};O[G]=e,p?R(p,[P,H]):H()},clone(P){return Wn(P,t,n,r)}};return Y}function Qr(e){if(er(e))return e=Mt(e),e.children=null,e}function Hl(e){return er(e)?e.children?e.children[0]:void 0:e}function Kn(e,t){e.shapeFlag&6&&e.component?Kn(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 Zo(e,t=!1,n){let r=[],o=0;for(let l=0;l1)for(let l=0;lCe({name:e.name},t,{setup:e}))():e}const Dn=e=>!!e.type.__asyncLoader;function ee(e){te(e)&&(e={loader:e});const{loader:t,loadingComponent:n,errorComponent:r,delay:o=200,timeout:l,suspensible:s=!0,onError:a}=e;let i=null,c,f=0;const d=()=>(f++,i=null,p()),p=()=>{let g;return i||(g=i=t().catch(_=>{if(_=_ instanceof Error?_:new Error(String(_)),a)return new Promise((w,E)=>{a(_,()=>w(d()),()=>E(_),f+1)});throw _}).then(_=>g!==i&&i?i:(_&&(_.__esModule||_[Symbol.toStringTag]==="Module")&&(_=_.default),c=_,_)))};return j({name:"AsyncComponentWrapper",__asyncLoader:p,get __asyncResolved(){return c},setup(){const g=Ae;if(c)return()=>Jr(c,g);const _=b=>{i=null,Zn(b,g,13,!r)};if(s&&g.suspense||vn)return p().then(b=>()=>Jr(b,g)).catch(b=>(_(b),()=>r?Te(r,{error:b}):null));const w=X(!1),E=X(),m=X(!!o);return o&&setTimeout(()=>{m.value=!1},o),l!=null&&setTimeout(()=>{if(!w.value&&!E.value){const b=new Error(`Async component timed out after ${l}ms.`);_(b),E.value=b}},l),p().then(()=>{w.value=!0,g.parent&&er(g.parent.vnode)&&Dr(g.parent.update)}).catch(b=>{_(b),E.value=b}),()=>{if(w.value&&c)return Jr(c,g);if(E.value&&r)return Te(r,{error:E.value});if(n&&!m.value)return Te(n)}}})}function Jr(e,t){const{ref:n,props:r,children:o,ce:l}=t.vnode,s=Te(e,r,o);return s.ref=n,s.ce=l,delete t.vnode.ce,s}const er=e=>e.type.__isKeepAlive;function Ju(e,t){wa(e,"a",t)}function Xu(e,t){wa(e,"da",t)}function wa(e,t,n=Ae){const r=e.__wdc||(e.__wdc=()=>{let o=n;for(;o;){if(o.isDeactivated)return;o=o.parent}return e()});if(Fr(t,r,n),n){let o=n.parent;for(;o&&o.parent;)er(o.parent.vnode)&&Zu(r,t,n,o),o=o.parent}}function Zu(e,t,n,r){const o=Fr(t,e,r,!0);tr(()=>{No(r[t],o)},n)}function Fr(e,t,n=Ae,r=!1){if(n){const o=n[e]||(n[e]=[]),l=t.__weh||(t.__weh=(...s)=>{if(n.isUnmounted)return;wn(),hn(n);const a=Ue(t,n,e,s);return Kt(),En(),a});return r?o.unshift(l):o.push(l),l}}const _t=e=>(t,n=Ae)=>(!vn||e==="sp")&&Fr(e,(...r)=>t(...r),n),ef=_t("bm"),Ee=_t("m"),tf=_t("bu"),Ea=_t("u"),el=_t("bum"),tr=_t("um"),nf=_t("sp"),rf=_t("rtg"),of=_t("rtc");function lf(e,t=Ae){Fr("ec",e,t)}const Ta="components";function et(e,t){return af(Ta,e,!0,t)||e}const sf=Symbol.for("v-ndc");function af(e,t,n=!0,r=!1){const o=ze||Ae;if(o){const l=o.type;if(e===Ta){const a=Bf(l,!1);if(a&&(a===t||a===We(t)||a===Xn(We(t))))return l}const s=Bl(o[e]||l[e],t)||Bl(o.appContext[e],t);return!s&&r?l:s}}function Bl(e,t){return e&&(e[t]||e[We(t)]||e[Xn(We(t))])}const bo=e=>e?Da(e)?ll(e)||e.proxy:bo(e.parent):null,Nn=Ce(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=>bo(e.parent),$root:e=>bo(e.root),$emit:e=>e.emit,$options:e=>tl(e),$forceUpdate:e=>e.f||(e.f=()=>Dr(e.update)),$nextTick:e=>e.n||(e.n=Qt.bind(e.proxy)),$watch:e=>Yu.bind(e)}),Xr=(e,t)=>e!==be&&!e.__isScriptSetup&&se(e,t),cf={get({_:e},t){const{ctx:n,setupState:r,data:o,props:l,accessCache:s,type:a,appContext:i}=e;let c;if(t[0]!=="$"){const g=s[t];if(g!==void 0)switch(g){case 1:return r[t];case 2:return o[t];case 4:return n[t];case 3:return l[t]}else{if(Xr(r,t))return s[t]=1,r[t];if(o!==be&&se(o,t))return s[t]=2,o[t];if((c=e.propsOptions[0])&&se(c,t))return s[t]=3,l[t];if(n!==be&&se(n,t))return s[t]=4,n[t];_o&&(s[t]=0)}}const f=Nn[t];let d,p;if(f)return t==="$attrs"&&Ne(e,"get",t),f(e);if((d=a.__cssModules)&&(d=d[t]))return d;if(n!==be&&se(n,t))return s[t]=4,n[t];if(p=i.config.globalProperties,se(p,t))return p[t]},set({_:e},t,n){const{data:r,setupState:o,ctx:l}=e;return Xr(o,t)?(o[t]=n,!0):r!==be&&se(r,t)?(r[t]=n,!0):se(e.props,t)||t[0]==="$"&&t.slice(1)in e?!1:(l[t]=n,!0)},has({_:{data:e,setupState:t,accessCache:n,ctx:r,appContext:o,propsOptions:l}},s){let a;return!!n[s]||e!==be&&se(e,s)||Xr(t,s)||(a=l[0])&&se(a,s)||se(r,s)||se(Nn,s)||se(o.config.globalProperties,s)},defineProperty(e,t,n){return n.get!=null?e._.accessCache[t]=0:se(n,"value")&&this.set(e,t,n.value,null),Reflect.defineProperty(e,t,n)}};function Vl(e){return Q(e)?e.reduce((t,n)=>(t[n]=null,t),{}):e}let _o=!0;function uf(e){const t=tl(e),n=e.proxy,r=e.ctx;_o=!1,t.beforeCreate&&jl(t.beforeCreate,e,"bc");const{data:o,computed:l,methods:s,watch:a,provide:i,inject:c,created:f,beforeMount:d,mounted:p,beforeUpdate:g,updated:_,activated:w,deactivated:E,beforeDestroy:m,beforeUnmount:b,destroyed:S,unmounted:O,render:z,renderTracked:R,renderTriggered:Y,errorCaptured:P,serverPrefetch:V,expose:G,inheritAttrs:re,components:H,directives:Z,filters:U}=t;if(c&&ff(c,r,null),s)for(const ve in s){const ie=s[ve];te(ie)&&(r[ve]=ie.bind(n))}if(o){const ve=o.call(n,n);we(ve)&&(e.data=Tn(ve))}if(_o=!0,l)for(const ve in l){const ie=l[ve],at=te(ie)?ie.bind(n,n):te(ie.get)?ie.get.bind(n,n):Ze,Tt=!te(ie)&&te(ie.set)?ie.set.bind(n):Ze,rt=x({get:at,set:Tt});Object.defineProperty(r,ve,{enumerable:!0,configurable:!0,get:()=>rt.value,set:$e=>rt.value=$e})}if(a)for(const ve in a)Ca(a[ve],r,n,ve);if(i){const ve=te(i)?i.call(n):i;Reflect.ownKeys(ve).forEach(ie=>{Wt(ie,ve[ie])})}f&&jl(f,e,"c");function ae(ve,ie){Q(ie)?ie.forEach(at=>ve(at.bind(n))):ie&&ve(ie.bind(n))}if(ae(ef,d),ae(Ee,p),ae(tf,g),ae(Ea,_),ae(Ju,w),ae(Xu,E),ae(lf,P),ae(of,R),ae(rf,Y),ae(el,b),ae(tr,O),ae(nf,V),Q(G))if(G.length){const ve=e.exposed||(e.exposed={});G.forEach(ie=>{Object.defineProperty(ve,ie,{get:()=>n[ie],set:at=>n[ie]=at})})}else e.exposed||(e.exposed={});z&&e.render===Ze&&(e.render=z),re!=null&&(e.inheritAttrs=re),H&&(e.components=H),Z&&(e.directives=Z)}function ff(e,t,n=Ze){Q(e)&&(e=wo(e));for(const r in e){const o=e[r];let l;we(o)?"default"in o?l=_e(o.from||r,o.default,!0):l=_e(o.from||r):l=_e(o),Pe(l)?Object.defineProperty(t,r,{enumerable:!0,configurable:!0,get:()=>l.value,set:s=>l.value=s}):t[r]=l}}function jl(e,t,n){Ue(Q(e)?e.map(r=>r.bind(t.proxy)):e.bind(t.proxy),t,n)}function Ca(e,t,n,r){const o=r.includes(".")?ga(n,r):()=>n[r];if(ue(e)){const l=t[e];te(l)&&fe(o,l)}else if(te(e))fe(o,e.bind(n));else if(we(e))if(Q(e))e.forEach(l=>Ca(l,t,n,r));else{const l=te(e.handler)?e.handler.bind(n):t[e.handler];te(l)&&fe(o,l,e)}}function tl(e){const t=e.type,{mixins:n,extends:r}=t,{mixins:o,optionsCache:l,config:{optionMergeStrategies:s}}=e.appContext,a=l.get(t);let i;return a?i=a:!o.length&&!n&&!r?i=t:(i={},o.length&&o.forEach(c=>Ar(i,c,s,!0)),Ar(i,t,s)),we(t)&&l.set(t,i),i}function Ar(e,t,n,r=!1){const{mixins:o,extends:l}=t;l&&Ar(e,l,n,!0),o&&o.forEach(s=>Ar(e,s,n,!0));for(const s in t)if(!(r&&s==="expose")){const a=df[s]||n&&n[s];e[s]=a?a(e[s],t[s]):t[s]}return e}const df={data:zl,props:Ul,emits:Ul,methods:In,computed:In,beforeCreate:Ie,created:Ie,beforeMount:Ie,mounted:Ie,beforeUpdate:Ie,updated:Ie,beforeDestroy:Ie,beforeUnmount:Ie,destroyed:Ie,unmounted:Ie,activated:Ie,deactivated:Ie,errorCaptured:Ie,serverPrefetch:Ie,components:In,directives:In,watch:hf,provide:zl,inject:pf};function zl(e,t){return t?e?function(){return Ce(te(e)?e.call(this,this):e,te(t)?t.call(this,this):t)}:t:e}function pf(e,t){return In(wo(e),wo(t))}function wo(e){if(Q(e)){const t={};for(let n=0;n1)return n&&te(t)?t.call(r&&r.proxy):t}}function gf(e,t,n,r=!1){const o={},l={};wr(l,Hr,1),e.propsDefaults=Object.create(null),Aa(e,t,o,l);for(const s in e.propsOptions[0])s in o||(o[s]=void 0);n?e.props=r?o:xu(o):e.type.props?e.props=o:e.props=l,e.attrs=l}function yf(e,t,n,r){const{props:o,attrs:l,vnode:{patchFlag:s}}=e,a=oe(o),[i]=e.propsOptions;let c=!1;if((r||s>0)&&!(s&16)){if(s&8){const f=e.vnode.dynamicProps;for(let d=0;d{i=!0;const[p,g]=Pa(d,t,!0);Ce(s,p),g&&a.push(...g)};!n&&t.mixins.length&&t.mixins.forEach(f),e.extends&&f(e.extends),e.mixins&&e.mixins.forEach(f)}if(!l&&!i)return we(e)&&r.set(e,sn),sn;if(Q(l))for(let f=0;f-1,g[1]=w<0||_-1||se(g,"default"))&&a.push(d)}}}const c=[s,a];return we(e)&&r.set(e,c),c}function ql(e){return e[0]!=="$"}function Wl(e){const t=e&&e.toString().match(/^\s*(function|class) (\w+)/);return t?t[2]:e===null?"null":""}function Kl(e,t){return Wl(e)===Wl(t)}function Yl(e,t){return Q(t)?t.findIndex(n=>Kl(n,e)):te(t)&&Kl(t,e)?0:-1}const ka=e=>e[0]==="_"||e==="$stable",nl=e=>Q(e)?e.map(Qe):[Qe(e)],bf=(e,t,n)=>{if(t._n)return t;const r=Vu((...o)=>nl(t(...o)),n);return r._c=!1,r},La=(e,t,n)=>{const r=e._ctx;for(const o in e){if(ka(o))continue;const l=e[o];if(te(l))t[o]=bf(o,l,r);else if(l!=null){const s=nl(l);t[o]=()=>s}}},Ra=(e,t)=>{const n=nl(t);e.slots.default=()=>n},_f=(e,t)=>{if(e.vnode.shapeFlag&32){const n=t._;n?(e.slots=oe(t),wr(t,"_",n)):La(t,e.slots={})}else e.slots={},t&&Ra(e,t);wr(e.slots,Hr,1)},wf=(e,t,n)=>{const{vnode:r,slots:o}=e;let l=!0,s=be;if(r.shapeFlag&32){const a=t._;a?n&&a===1?l=!1:(Ce(o,t),!n&&a===1&&delete o._):(l=!t.$stable,La(t,o)),s=t}else t&&(Ra(e,t),s={default:1});if(l)for(const a in o)!ka(a)&&!(a in s)&&delete o[a]};function kr(e,t,n,r,o=!1){if(Q(e)){e.forEach((p,g)=>kr(p,t&&(Q(t)?t[g]:t),n,r,o));return}if(Dn(r)&&!o)return;const l=r.shapeFlag&4?ll(r.component)||r.component.proxy:r.el,s=o?null:l,{i:a,r:i}=e,c=t&&t.r,f=a.refs===be?a.refs={}:a.refs,d=a.setupState;if(c!=null&&c!==i&&(ue(c)?(f[c]=null,se(d,c)&&(d[c]=null)):Pe(c)&&(c.value=null)),te(i))St(i,a,12,[s,f]);else{const p=ue(i),g=Pe(i);if(p||g){const _=()=>{if(e.f){const w=p?se(d,i)?d[i]:f[i]:i.value;o?Q(w)&&No(w,l):Q(w)?w.includes(l)||w.push(l):p?(f[i]=[l],se(d,i)&&(d[i]=f[i])):(i.value=[l],e.k&&(f[e.k]=i.value))}else p?(f[i]=s,se(d,i)&&(d[i]=s)):g&&(i.value=s,e.k&&(f[e.k]=s))};s?(_.id=-1,Me(_,n)):_()}}}let xt=!1;const pr=e=>/svg/.test(e.namespaceURI)&&e.tagName!=="foreignObject",hr=e=>e.nodeType===8;function Ef(e){const{mt:t,p:n,o:{patchProp:r,createText:o,nextSibling:l,parentNode:s,remove:a,insert:i,createComment:c}}=e,f=(m,b)=>{if(!b.hasChildNodes()){n(null,m,b),Cr(),b._vnode=m;return}xt=!1,d(b.firstChild,m,null,null,null),Cr(),b._vnode=m,xt&&console.error("Hydration completed but contains mismatches.")},d=(m,b,S,O,z,R=!1)=>{const Y=hr(m)&&m.data==="[",P=()=>w(m,b,S,O,z,Y),{type:V,ref:G,shapeFlag:re,patchFlag:H}=b;let Z=m.nodeType;b.el=m,H===-2&&(R=!1,b.dynamicChildren=null);let U=null;switch(V){case pn:Z!==3?b.children===""?(i(b.el=o(""),s(m),m),U=m):U=P():(m.data!==b.children&&(xt=!0,m.data=b.children),U=l(m));break;case qe:Z!==8||Y?U=P():U=l(m);break;case Fn:if(Y&&(m=l(m),Z=m.nodeType),Z===1||Z===3){U=m;const Le=!b.children.length;for(let ae=0;ae{R=R||!!b.dynamicChildren;const{type:Y,props:P,patchFlag:V,shapeFlag:G,dirs:re}=b,H=Y==="input"&&re||Y==="option";if(H||V!==-1){if(re&<(b,null,S,"created"),P)if(H||!R||V&48)for(const U in P)(H&&U.endsWith("value")||Jn(U)&&!Mn(U))&&r(m,U,null,P[U],!1,void 0,S);else P.onClick&&r(m,"onClick",null,P.onClick,!1,void 0,S);let Z;if((Z=P&&P.onVnodeBeforeMount)&&je(Z,S,b),re&<(b,null,S,"beforeMount"),((Z=P&&P.onVnodeMounted)||re)&&ma(()=>{Z&&je(Z,S,b),re&<(b,null,S,"mounted")},O),G&16&&!(P&&(P.innerHTML||P.textContent))){let U=g(m.firstChild,b,m,S,O,z,R);for(;U;){xt=!0;const Le=U;U=U.nextSibling,a(Le)}}else G&8&&m.textContent!==b.children&&(xt=!0,m.textContent=b.children)}return m.nextSibling},g=(m,b,S,O,z,R,Y)=>{Y=Y||!!b.dynamicChildren;const P=b.children,V=P.length;for(let G=0;G{const{slotScopeIds:Y}=b;Y&&(z=z?z.concat(Y):Y);const P=s(m),V=g(l(m),b,P,S,O,z,R);return V&&hr(V)&&V.data==="]"?l(b.anchor=V):(xt=!0,i(b.anchor=c("]"),P,V),V)},w=(m,b,S,O,z,R)=>{if(xt=!0,b.el=null,R){const V=E(m);for(;;){const G=l(m);if(G&&G!==V)a(G);else break}}const Y=l(m),P=s(m);return a(m),n(null,b,P,Y,S,O,pr(P),z),Y},E=m=>{let b=0;for(;m;)if(m=l(m),m&&hr(m)&&(m.data==="["&&b++,m.data==="]")){if(b===0)return l(m);b--}return m};return[f,d]}const Me=ma;function Tf(e){return Cf(e,Ef)}function Cf(e,t){const n=ho();n.__VUE__=!0;const{insert:r,remove:o,patchProp:l,createElement:s,createText:a,createComment:i,setText:c,setElementText:f,parentNode:d,nextSibling:p,setScopeId:g=Ze,insertStaticContent:_}=e,w=(h,v,y,T=null,A=null,k=null,N=!1,I=null,M=!!v.dynamicChildren)=>{if(h===v)return;h&&!jt(h,v)&&(T=C(h),$e(h,A,k,!0),h=null),v.patchFlag===-2&&(M=!1,v.dynamicChildren=null);const{type:L,ref:W,shapeFlag:B}=v;switch(L){case pn:E(h,v,y,T);break;case qe:m(h,v,y,T);break;case Fn:h==null&&b(v,y,T,N);break;case Be:H(h,v,y,T,A,k,N,I,M);break;default:B&1?z(h,v,y,T,A,k,N,I,M):B&6?Z(h,v,y,T,A,k,N,I,M):(B&64||B&128)&&L.process(h,v,y,T,A,k,N,I,M,D)}W!=null&&A&&kr(W,h&&h.ref,k,v||h,!v)},E=(h,v,y,T)=>{if(h==null)r(v.el=a(v.children),y,T);else{const A=v.el=h.el;v.children!==h.children&&c(A,v.children)}},m=(h,v,y,T)=>{h==null?r(v.el=i(v.children||""),y,T):v.el=h.el},b=(h,v,y,T)=>{[h.el,h.anchor]=_(h.children,v,y,T,h.el,h.anchor)},S=({el:h,anchor:v},y,T)=>{let A;for(;h&&h!==v;)A=p(h),r(h,y,T),h=A;r(v,y,T)},O=({el:h,anchor:v})=>{let y;for(;h&&h!==v;)y=p(h),o(h),h=y;o(v)},z=(h,v,y,T,A,k,N,I,M)=>{N=N||v.type==="svg",h==null?R(v,y,T,A,k,N,I,M):V(h,v,A,k,N,I,M)},R=(h,v,y,T,A,k,N,I)=>{let M,L;const{type:W,props:B,shapeFlag:K,transition:J,dirs:ne}=h;if(M=h.el=s(h.type,k,B&&B.is,B),K&8?f(M,h.children):K&16&&P(h.children,M,null,T,A,k&&W!=="foreignObject",N,I),ne&<(h,null,T,"created"),Y(M,h,h.scopeId,N,T),B){for(const pe in B)pe!=="value"&&!Mn(pe)&&l(M,pe,null,B[pe],k,h.children,T,A,Re);"value"in B&&l(M,"value",null,B.value),(L=B.onVnodeBeforeMount)&&je(L,T,h)}ne&<(h,null,T,"beforeMount");const ye=(!A||A&&!A.pendingBranch)&&J&&!J.persisted;ye&&J.beforeEnter(M),r(M,v,y),((L=B&&B.onVnodeMounted)||ye||ne)&&Me(()=>{L&&je(L,T,h),ye&&J.enter(M),ne&<(h,null,T,"mounted")},A)},Y=(h,v,y,T,A)=>{if(y&&g(h,y),T)for(let k=0;k{for(let L=M;L{const I=v.el=h.el;let{patchFlag:M,dynamicChildren:L,dirs:W}=v;M|=h.patchFlag&16;const B=h.props||be,K=v.props||be;let J;y&&Ht(y,!1),(J=K.onVnodeBeforeUpdate)&&je(J,y,v,h),W&<(v,h,y,"beforeUpdate"),y&&Ht(y,!0);const ne=A&&v.type!=="foreignObject";if(L?G(h.dynamicChildren,L,I,y,T,ne,k):N||ie(h,v,I,null,y,T,ne,k,!1),M>0){if(M&16)re(I,v,B,K,y,T,A);else if(M&2&&B.class!==K.class&&l(I,"class",null,K.class,A),M&4&&l(I,"style",B.style,K.style,A),M&8){const ye=v.dynamicProps;for(let pe=0;pe{J&&je(J,y,v,h),W&<(v,h,y,"updated")},T)},G=(h,v,y,T,A,k,N)=>{for(let I=0;I{if(y!==T){if(y!==be)for(const I in y)!Mn(I)&&!(I in T)&&l(h,I,y[I],null,N,v.children,A,k,Re);for(const I in T){if(Mn(I))continue;const M=T[I],L=y[I];M!==L&&I!=="value"&&l(h,I,L,M,N,v.children,A,k,Re)}"value"in T&&l(h,"value",y.value,T.value)}},H=(h,v,y,T,A,k,N,I,M)=>{const L=v.el=h?h.el:a(""),W=v.anchor=h?h.anchor:a("");let{patchFlag:B,dynamicChildren:K,slotScopeIds:J}=v;J&&(I=I?I.concat(J):J),h==null?(r(L,y,T),r(W,y,T),P(v.children,y,W,A,k,N,I,M)):B>0&&B&64&&K&&h.dynamicChildren?(G(h.dynamicChildren,K,y,A,k,N,I),(v.key!=null||A&&v===A.subTree)&&Oa(h,v,!0)):ie(h,v,y,W,A,k,N,I,M)},Z=(h,v,y,T,A,k,N,I,M)=>{v.slotScopeIds=I,h==null?v.shapeFlag&512?A.ctx.activate(v,y,T,N,M):U(v,y,T,A,k,N,M):Le(h,v,M)},U=(h,v,y,T,A,k,N)=>{const I=h.component=Mf(h,T,A);if(er(h)&&(I.ctx.renderer=D),Df(I),I.asyncDep){if(A&&A.registerDep(I,ae),!h.el){const M=I.subTree=Te(qe);m(null,M,v,y)}return}ae(I,h,v,y,A,k,N)},Le=(h,v,y)=>{const T=v.component=h.component;if(Uu(h,v,y))if(T.asyncDep&&!T.asyncResolved){ve(T,v,y);return}else T.next=v,Nu(T.update),T.update();else v.el=h.el,T.vnode=v},ae=(h,v,y,T,A,k,N)=>{const I=()=>{if(h.isMounted){let{next:W,bu:B,u:K,parent:J,vnode:ne}=h,ye=W,pe;Ht(h,!1),W?(W.el=ne.el,ve(h,W,N)):W=ne,B&&Yr(B),(pe=W.props&&W.props.onVnodeBeforeUpdate)&&je(pe,J,W,ne),Ht(h,!0);const xe=Gr(h),Ge=h.subTree;h.subTree=xe,w(Ge,xe,d(Ge.el),C(Ge),h,A,k),W.el=xe.el,ye===null&&qu(h,xe.el),K&&Me(K,A),(pe=W.props&&W.props.onVnodeUpdated)&&Me(()=>je(pe,J,W,ne),A)}else{let W;const{el:B,props:K}=v,{bm:J,m:ne,parent:ye}=h,pe=Dn(v);if(Ht(h,!1),J&&Yr(J),!pe&&(W=K&&K.onVnodeBeforeMount)&&je(W,ye,v),Ht(h,!0),B&&ce){const xe=()=>{h.subTree=Gr(h),ce(B,h.subTree,h,A,null)};pe?v.type.__asyncLoader().then(()=>!h.isUnmounted&&xe()):xe()}else{const xe=h.subTree=Gr(h);w(null,xe,y,T,h,A,k),v.el=xe.el}if(ne&&Me(ne,A),!pe&&(W=K&&K.onVnodeMounted)){const xe=v;Me(()=>je(W,ye,xe),A)}(v.shapeFlag&256||ye&&Dn(ye.vnode)&&ye.vnode.shapeFlag&256)&&h.a&&Me(h.a,A),h.isMounted=!0,v=y=T=null}},M=h.effect=new zo(I,()=>Dr(L),h.scope),L=h.update=()=>M.run();L.id=h.uid,Ht(h,!0),L()},ve=(h,v,y)=>{v.component=h;const T=h.vnode.props;h.vnode=v,h.next=null,yf(h,v.props,T,y),wf(h,v.children,y),wn(),Nl(),En()},ie=(h,v,y,T,A,k,N,I,M=!1)=>{const L=h&&h.children,W=h?h.shapeFlag:0,B=v.children,{patchFlag:K,shapeFlag:J}=v;if(K>0){if(K&128){Tt(L,B,y,T,A,k,N,I,M);return}else if(K&256){at(L,B,y,T,A,k,N,I,M);return}}J&8?(W&16&&Re(L,A,k),B!==L&&f(y,B)):W&16?J&16?Tt(L,B,y,T,A,k,N,I,M):Re(L,A,k,!0):(W&8&&f(y,""),J&16&&P(B,y,T,A,k,N,I,M))},at=(h,v,y,T,A,k,N,I,M)=>{h=h||sn,v=v||sn;const L=h.length,W=v.length,B=Math.min(L,W);let K;for(K=0;KW?Re(h,A,k,!0,!1,B):P(v,y,T,A,k,N,I,M,B)},Tt=(h,v,y,T,A,k,N,I,M)=>{let L=0;const W=v.length;let B=h.length-1,K=W-1;for(;L<=B&&L<=K;){const J=h[L],ne=v[L]=M?kt(v[L]):Qe(v[L]);if(jt(J,ne))w(J,ne,y,null,A,k,N,I,M);else break;L++}for(;L<=B&&L<=K;){const J=h[B],ne=v[K]=M?kt(v[K]):Qe(v[K]);if(jt(J,ne))w(J,ne,y,null,A,k,N,I,M);else break;B--,K--}if(L>B){if(L<=K){const J=K+1,ne=JK)for(;L<=B;)$e(h[L],A,k,!0),L++;else{const J=L,ne=L,ye=new Map;for(L=ne;L<=K;L++){const Fe=v[L]=M?kt(v[L]):Qe(v[L]);Fe.key!=null&&ye.set(Fe.key,L)}let pe,xe=0;const Ge=K-ne+1;let Zt=!1,xl=0;const Ln=new Array(Ge);for(L=0;L=Ge){$e(Fe,A,k,!0);continue}let ot;if(Fe.key!=null)ot=ye.get(Fe.key);else for(pe=ne;pe<=K;pe++)if(Ln[pe-ne]===0&&jt(Fe,v[pe])){ot=pe;break}ot===void 0?$e(Fe,A,k,!0):(Ln[ot-ne]=L+1,ot>=xl?xl=ot:Zt=!0,w(Fe,v[ot],y,null,A,k,N,I,M),xe++)}const Al=Zt?xf(Ln):sn;for(pe=Al.length-1,L=Ge-1;L>=0;L--){const Fe=ne+L,ot=v[Fe],Pl=Fe+1{const{el:k,type:N,transition:I,children:M,shapeFlag:L}=h;if(L&6){rt(h.component.subTree,v,y,T);return}if(L&128){h.suspense.move(v,y,T);return}if(L&64){N.move(h,v,y,D);return}if(N===Be){r(k,v,y);for(let B=0;BI.enter(k),A);else{const{leave:B,delayLeave:K,afterLeave:J}=I,ne=()=>r(k,v,y),ye=()=>{B(k,()=>{ne(),J&&J()})};K?K(k,ne,ye):ye()}else r(k,v,y)},$e=(h,v,y,T=!1,A=!1)=>{const{type:k,props:N,ref:I,children:M,dynamicChildren:L,shapeFlag:W,patchFlag:B,dirs:K}=h;if(I!=null&&kr(I,null,y,h,!0),W&256){v.ctx.deactivate(h);return}const J=W&1&&K,ne=!Dn(h);let ye;if(ne&&(ye=N&&N.onVnodeBeforeUnmount)&&je(ye,v,h),W&6)sr(h.component,y,T);else{if(W&128){h.suspense.unmount(y,T);return}J&<(h,null,v,"beforeUnmount"),W&64?h.type.remove(h,v,y,A,D,T):L&&(k!==Be||B>0&&B&64)?Re(L,v,y,!1,!0):(k===Be&&B&384||!A&&W&16)&&Re(M,v,y),T&&Jt(h)}(ne&&(ye=N&&N.onVnodeUnmounted)||J)&&Me(()=>{ye&&je(ye,v,h),J&<(h,null,v,"unmounted")},y)},Jt=h=>{const{type:v,el:y,anchor:T,transition:A}=h;if(v===Be){Xt(y,T);return}if(v===Fn){O(h);return}const k=()=>{o(y),A&&!A.persisted&&A.afterLeave&&A.afterLeave()};if(h.shapeFlag&1&&A&&!A.persisted){const{leave:N,delayLeave:I}=A,M=()=>N(y,k);I?I(h.el,k,M):M()}else k()},Xt=(h,v)=>{let y;for(;h!==v;)y=p(h),o(h),h=y;o(v)},sr=(h,v,y)=>{const{bum:T,scope:A,update:k,subTree:N,um:I}=h;T&&Yr(T),A.stop(),k&&(k.active=!1,$e(N,h,v,y)),I&&Me(I,v),Me(()=>{h.isUnmounted=!0},v),v&&v.pendingBranch&&!v.isUnmounted&&h.asyncDep&&!h.asyncResolved&&h.suspenseId===v.pendingId&&(v.deps--,v.deps===0&&v.resolve())},Re=(h,v,y,T=!1,A=!1,k=0)=>{for(let N=k;Nh.shapeFlag&6?C(h.component.subTree):h.shapeFlag&128?h.suspense.next():p(h.anchor||h.el),F=(h,v,y)=>{h==null?v._vnode&&$e(v._vnode,null,null,!0):w(v._vnode||null,h,v,null,null,null,y),Nl(),Cr(),v._vnode=h},D={p:w,um:$e,m:rt,r:Jt,mt:U,mc:P,pc:ie,pbc:G,n:C,o:e};let q,ce;return t&&([q,ce]=t(D)),{render:F,hydrate:q,createApp:mf(F,q)}}function Ht({effect:e,update:t},n){e.allowRecurse=t.allowRecurse=n}function Oa(e,t,n=!1){const r=e.children,o=t.children;if(Q(r)&&Q(o))for(let l=0;l>1,e[n[a]]0&&(t[r]=n[l-1]),n[l]=r)}}for(l=n.length,s=n[l-1];l-- >0;)n[l]=s,s=t[s];return n}const Af=e=>e.__isTeleport,Be=Symbol.for("v-fgt"),pn=Symbol.for("v-txt"),qe=Symbol.for("v-cmt"),Fn=Symbol.for("v-stc"),Hn=[];let Xe=null;function Pf(e=!1){Hn.push(Xe=e?null:[])}function kf(){Hn.pop(),Xe=Hn[Hn.length-1]||null}let Yn=1;function Gl(e){Yn+=e}function Sa(e){return e.dynamicChildren=Yn>0?Xe||sn:null,kf(),Yn>0&&Xe&&Xe.push(e),e}function Tv(e,t,n,r,o,l){return Sa($a(e,t,n,r,o,l,!0))}function Lf(e,t,n,r,o){return Sa(Te(e,t,n,r,o,!0))}function To(e){return e?e.__v_isVNode===!0:!1}function jt(e,t){return e.type===t.type&&e.key===t.key}const Hr="__vInternal",Ia=({key:e})=>e??null,_r=({ref:e,ref_key:t,ref_for:n})=>(typeof e=="number"&&(e=""+e),e!=null?ue(e)||Pe(e)||te(e)?{i:ze,r:e,k:t,f:!!n}:e:null);function $a(e,t=null,n=null,r=0,o=null,l=e===Be?0:1,s=!1,a=!1){const i={__v_isVNode:!0,__v_skip:!0,type:e,props:t,key:t&&Ia(t),ref:t&&_r(t),scopeId:va,slotScopeIds:null,children:n,component:null,suspense:null,ssContent:null,ssFallback:null,dirs:null,transition:null,el:null,anchor:null,target:null,targetAnchor:null,staticCount:0,shapeFlag:l,patchFlag:r,dynamicProps:o,dynamicChildren:null,appContext:null,ctx:ze};return a?(rl(i,n),l&128&&e.normalize(i)):n&&(i.shapeFlag|=ue(n)?8:16),Yn>0&&!s&&Xe&&(i.patchFlag>0||l&6)&&i.patchFlag!==32&&Xe.push(i),i}const Te=Rf;function Rf(e,t=null,n=null,r=0,o=null,l=!1){if((!e||e===sf)&&(e=qe),To(e)){const a=Mt(e,t,!0);return n&&rl(a,n),Yn>0&&!l&&Xe&&(a.shapeFlag&6?Xe[Xe.indexOf(e)]=a:Xe.push(a)),a.patchFlag|=-2,a}if(Vf(e)&&(e=e.__vccOpts),t){t=Of(t);let{class:a,style:i}=t;a&&!ue(a)&&(t.class=Vo(a)),we(i)&&(aa(i)&&!Q(i)&&(i=Ce({},i)),t.style=Bo(i))}const s=ue(e)?1:Wu(e)?128:Af(e)?64:we(e)?4:te(e)?2:0;return $a(e,t,n,r,o,s,l,!0)}function Of(e){return e?aa(e)||Hr in e?Ce({},e):e:null}function Mt(e,t,n=!1){const{props:r,ref:o,patchFlag:l,children:s}=e,a=t?Sf(r||{},t):r;return{__v_isVNode:!0,__v_skip:!0,type:e.type,props:a,key:a&&Ia(a),ref:t&&t.ref?n&&o?Q(o)?o.concat(_r(t)):[o,_r(t)]:_r(t):o,scopeId:e.scopeId,slotScopeIds:e.slotScopeIds,children:s,target:e.target,targetAnchor:e.targetAnchor,staticCount:e.staticCount,shapeFlag:e.shapeFlag,patchFlag:t&&e.type!==Be?l===-1?16:l|16:l,dynamicProps:e.dynamicProps,dynamicChildren:e.dynamicChildren,appContext:e.appContext,dirs:e.dirs,transition:e.transition,component:e.component,suspense:e.suspense,ssContent:e.ssContent&&Mt(e.ssContent),ssFallback:e.ssFallback&&Mt(e.ssFallback),el:e.el,anchor:e.anchor,ctx:e.ctx,ce:e.ce}}function Ma(e=" ",t=0){return Te(pn,null,e,t)}function Cv(e,t){const n=Te(Fn,null,e);return n.staticCount=t,n}function xv(e="",t=!1){return t?(Pf(),Lf(qe,null,e)):Te(qe,null,e)}function Qe(e){return e==null||typeof e=="boolean"?Te(qe):Q(e)?Te(Be,null,e.slice()):typeof e=="object"?kt(e):Te(pn,null,String(e))}function kt(e){return e.el===null&&e.patchFlag!==-1||e.memo?e:Mt(e)}function rl(e,t){let n=0;const{shapeFlag:r}=e;if(t==null)t=null;else if(Q(t))n=16;else if(typeof t=="object")if(r&65){const o=t.default;o&&(o._c&&(o._d=!1),rl(e,o()),o._c&&(o._d=!0));return}else{n=32;const o=t._;!o&&!(Hr in t)?t._ctx=ze:o===3&&ze&&(ze.slots._===1?t._=1:(t._=2,e.patchFlag|=1024))}else te(t)?(t={default:t,_ctx:ze},n=32):(t=String(t),r&64?(n=16,t=[Ma(t)]):n=8);e.children=t,e.shapeFlag|=n}function Sf(...e){const t={};for(let n=0;nAe||ze;let ol,en,Ql="__VUE_INSTANCE_SETTERS__";(en=ho()[Ql])||(en=ho()[Ql]=[]),en.push(e=>Ae=e),ol=e=>{en.length>1?en.forEach(t=>t(e)):en[0](e)};const hn=e=>{ol(e),e.scope.on()},Kt=()=>{Ae&&Ae.scope.off(),ol(null)};function Da(e){return e.vnode.shapeFlag&4}let vn=!1;function Df(e,t=!1){vn=t;const{props:n,children:r}=e.vnode,o=Da(e);gf(e,n,o,t),_f(e,r);const l=o?Nf(e,t):void 0;return vn=!1,l}function Nf(e,t){const n=e.type;e.accessCache=Object.create(null),e.proxy=ia(new Proxy(e.ctx,cf));const{setup:r}=n;if(r){const o=e.setupContext=r.length>1?Hf(e):null;hn(e),wn();const l=St(r,e,0,[e.props,o]);if(En(),Kt(),Ys(l)){if(l.then(Kt,Kt),t)return l.then(s=>{Jl(e,s,t)}).catch(s=>{Zn(s,e,0)});e.asyncDep=l}else Jl(e,l,t)}else Na(e,t)}function Jl(e,t,n){te(t)?e.type.__ssrInlineRender?e.ssrRender=t:e.render=t:we(t)&&(e.setupState=ua(t)),Na(e,n)}let Xl;function Na(e,t,n){const r=e.type;if(!e.render){if(!t&&Xl&&!r.render){const o=r.template||tl(e).template;if(o){const{isCustomElement:l,compilerOptions:s}=e.appContext.config,{delimiters:a,compilerOptions:i}=r,c=Ce(Ce({isCustomElement:l,delimiters:a},s),i);r.render=Xl(o,c)}}e.render=r.render||Ze}hn(e),wn(),uf(e),En(),Kt()}function Ff(e){return e.attrsProxy||(e.attrsProxy=new Proxy(e.attrs,{get(t,n){return Ne(e,"get","$attrs"),t[n]}}))}function Hf(e){const t=n=>{e.exposed=n||{}};return{get attrs(){return Ff(e)},slots:e.slots,emit:e.emit,expose:t}}function ll(e){if(e.exposed)return e.exposeProxy||(e.exposeProxy=new Proxy(ua(ia(e.exposed)),{get(t,n){if(n in t)return t[n];if(n in Nn)return Nn[n](e)},has(t,n){return n in t||n in Nn}}))}function Bf(e,t=!0){return te(e)?e.displayName||e.name:e.name||t&&e.__name}function Vf(e){return te(e)&&"__vccOpts"in e}const x=(e,t)=>$u(e,t,vn);function u(e,t,n){const r=arguments.length;return r===2?we(t)&&!Q(t)?To(t)?Te(e,null,[t]):Te(e,t):Te(e,null,t):(r>3?n=Array.prototype.slice.call(arguments,2):r===3&&To(n)&&(n=[n]),Te(e,t,n))}const jf=Symbol.for("v-scx"),zf=()=>_e(jf),Uf="3.3.4",qf="http://www.w3.org/2000/svg",zt=typeof document<"u"?document:null,Zl=zt&&zt.createElement("template"),Wf={insert:(e,t,n)=>{t.insertBefore(e,n||null)},remove:e=>{const t=e.parentNode;t&&t.removeChild(e)},createElement:(e,t,n,r)=>{const o=t?zt.createElementNS(qf,e):zt.createElement(e,n?{is:n}:void 0);return e==="select"&&r&&r.multiple!=null&&o.setAttribute("multiple",r.multiple),o},createText:e=>zt.createTextNode(e),createComment:e=>zt.createComment(e),setText:(e,t)=>{e.nodeValue=t},setElementText:(e,t)=>{e.textContent=t},parentNode:e=>e.parentNode,nextSibling:e=>e.nextSibling,querySelector:e=>zt.querySelector(e),setScopeId(e,t){e.setAttribute(t,"")},insertStaticContent(e,t,n,r,o,l){const s=n?n.previousSibling:t.lastChild;if(o&&(o===l||o.nextSibling))for(;t.insertBefore(o.cloneNode(!0),n),!(o===l||!(o=o.nextSibling)););else{Zl.innerHTML=r?`${e}`:e;const a=Zl.content;if(r){const i=a.firstChild;for(;i.firstChild;)a.appendChild(i.firstChild);a.removeChild(i)}t.insertBefore(a,n)}return[s?s.nextSibling:t.firstChild,n?n.previousSibling:t.lastChild]}};function Kf(e,t,n){const r=e._vtc;r&&(t=(t?[t,...r]:[...r]).join(" ")),t==null?e.removeAttribute("class"):n?e.setAttribute("class",t):e.className=t}function Yf(e,t,n){const r=e.style,o=ue(n);if(n&&!o){if(t&&!ue(t))for(const l in t)n[l]==null&&Co(r,l,"");for(const l in n)Co(r,l,n[l])}else{const l=r.display;o?t!==n&&(r.cssText=n):t&&e.removeAttribute("style"),"_vod"in e&&(r.display=l)}}const es=/\s*!important$/;function Co(e,t,n){if(Q(n))n.forEach(r=>Co(e,t,r));else if(n==null&&(n=""),t.startsWith("--"))e.setProperty(t,n);else{const r=Gf(e,t);es.test(n)?e.setProperty(_n(r),n.replace(es,""),"important"):e[r]=n}}const ts=["Webkit","Moz","ms"],Zr={};function Gf(e,t){const n=Zr[t];if(n)return n;let r=We(t);if(r!=="filter"&&r in e)return Zr[t]=r;r=Xn(r);for(let o=0;oeo||(nd.then(()=>eo=0),eo=Date.now());function od(e,t){const n=r=>{if(!r._vts)r._vts=Date.now();else if(r._vts<=n.attached)return;Ue(ld(r,n.value),t,5,[r])};return n.value=e,n.attached=rd(),n}function ld(e,t){if(Q(t)){const n=e.stopImmediatePropagation;return e.stopImmediatePropagation=()=>{n.call(e),e._stopped=!0},t.map(r=>o=>!o._stopped&&r&&r(o))}else return t}const os=/^on[a-z]/,sd=(e,t,n,r,o=!1,l,s,a,i)=>{t==="class"?Kf(e,r,o):t==="style"?Yf(e,n,r):Jn(t)?Do(t)||ed(e,t,n,r,s):(t[0]==="."?(t=t.slice(1),!0):t[0]==="^"?(t=t.slice(1),!1):ad(e,t,r,o))?Jf(e,t,r,l,s,a,i):(t==="true-value"?e._trueValue=r:t==="false-value"&&(e._falseValue=r),Qf(e,t,r,o))};function ad(e,t,n,r){return r?!!(t==="innerHTML"||t==="textContent"||t in e&&os.test(t)&&te(n)):t==="spellcheck"||t==="draggable"||t==="translate"||t==="form"||t==="list"&&e.tagName==="INPUT"||t==="type"&&e.tagName==="TEXTAREA"||os.test(t)&&ue(n)?!1:t in e}const At="transition",Rn="animation",Dt=(e,{slots:t})=>u(Qu,Ha(e),t);Dt.displayName="Transition";const Fa={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},id=Dt.props=Ce({},ba,Fa),Bt=(e,t=[])=>{Q(e)?e.forEach(n=>n(...t)):e&&e(...t)},ls=e=>e?Q(e)?e.some(t=>t.length>1):e.length>1:!1;function Ha(e){const t={};for(const H in e)H in Fa||(t[H]=e[H]);if(e.css===!1)return t;const{name:n="v",type:r,duration:o,enterFromClass:l=`${n}-enter-from`,enterActiveClass:s=`${n}-enter-active`,enterToClass:a=`${n}-enter-to`,appearFromClass:i=l,appearActiveClass:c=s,appearToClass:f=a,leaveFromClass:d=`${n}-leave-from`,leaveActiveClass:p=`${n}-leave-active`,leaveToClass:g=`${n}-leave-to`}=e,_=cd(o),w=_&&_[0],E=_&&_[1],{onBeforeEnter:m,onEnter:b,onEnterCancelled:S,onLeave:O,onLeaveCancelled:z,onBeforeAppear:R=m,onAppear:Y=b,onAppearCancelled:P=S}=t,V=(H,Z,U)=>{Pt(H,Z?f:a),Pt(H,Z?c:s),U&&U()},G=(H,Z)=>{H._isLeaving=!1,Pt(H,d),Pt(H,g),Pt(H,p),Z&&Z()},re=H=>(Z,U)=>{const Le=H?Y:b,ae=()=>V(Z,H,U);Bt(Le,[Z,ae]),ss(()=>{Pt(Z,H?i:l),ut(Z,H?f:a),ls(Le)||as(Z,r,w,ae)})};return Ce(t,{onBeforeEnter(H){Bt(m,[H]),ut(H,l),ut(H,s)},onBeforeAppear(H){Bt(R,[H]),ut(H,i),ut(H,c)},onEnter:re(!1),onAppear:re(!0),onLeave(H,Z){H._isLeaving=!0;const U=()=>G(H,Z);ut(H,d),Va(),ut(H,p),ss(()=>{H._isLeaving&&(Pt(H,d),ut(H,g),ls(O)||as(H,r,E,U))}),Bt(O,[H,U])},onEnterCancelled(H){V(H,!1),Bt(S,[H])},onAppearCancelled(H){V(H,!0),Bt(P,[H])},onLeaveCancelled(H){G(H),Bt(z,[H])}})}function cd(e){if(e==null)return null;if(we(e))return[to(e.enter),to(e.leave)];{const t=to(e);return[t,t]}}function to(e){return jc(e)}function ut(e,t){t.split(/\s+/).forEach(n=>n&&e.classList.add(n)),(e._vtc||(e._vtc=new Set)).add(t)}function Pt(e,t){t.split(/\s+/).forEach(r=>r&&e.classList.remove(r));const{_vtc:n}=e;n&&(n.delete(t),n.size||(e._vtc=void 0))}function ss(e){requestAnimationFrame(()=>{requestAnimationFrame(e)})}let ud=0;function as(e,t,n,r){const o=e._endId=++ud,l=()=>{o===e._endId&&r()};if(n)return setTimeout(l,n);const{type:s,timeout:a,propCount:i}=Ba(e,t);if(!s)return r();const c=s+"end";let f=0;const d=()=>{e.removeEventListener(c,p),l()},p=g=>{g.target===e&&++f>=i&&d()};setTimeout(()=>{f(n[_]||"").split(", "),o=r(`${At}Delay`),l=r(`${At}Duration`),s=is(o,l),a=r(`${Rn}Delay`),i=r(`${Rn}Duration`),c=is(a,i);let f=null,d=0,p=0;t===At?s>0&&(f=At,d=s,p=l.length):t===Rn?c>0&&(f=Rn,d=c,p=i.length):(d=Math.max(s,c),f=d>0?s>c?At:Rn:null,p=f?f===At?l.length:i.length:0);const g=f===At&&/\b(transform|all)(,|$)/.test(r(`${At}Property`).toString());return{type:f,timeout:d,propCount:p,hasTransform:g}}function is(e,t){for(;e.lengthcs(n)+cs(e[r])))}function cs(e){return Number(e.slice(0,-1).replace(",","."))*1e3}function Va(){return document.body.offsetHeight}const ja=new WeakMap,za=new WeakMap,Ua={name:"TransitionGroup",props:Ce({},id,{tag:String,moveClass:String}),setup(e,{slots:t}){const n=xn(),r=ya();let o,l;return Ea(()=>{if(!o.length)return;const s=e.moveClass||`${e.name||"v"}-move`;if(!md(o[0].el,n.vnode.el,s))return;o.forEach(pd),o.forEach(hd);const a=o.filter(vd);Va(),a.forEach(i=>{const c=i.el,f=c.style;ut(c,s),f.transform=f.webkitTransform=f.transitionDuration="";const d=c._moveCb=p=>{p&&p.target!==c||(!p||/transform$/.test(p.propertyName))&&(c.removeEventListener("transitionend",d),c._moveCb=null,Pt(c,s))};c.addEventListener("transitionend",d)})}),()=>{const s=oe(e),a=Ha(s);let i=s.tag||Be;o=l,l=t.default?Zo(t.default()):[];for(let c=0;cdelete e.mode;Ua.props;const dd=Ua;function pd(e){const t=e.el;t._moveCb&&t._moveCb(),t._enterCb&&t._enterCb()}function hd(e){za.set(e,e.el.getBoundingClientRect())}function vd(e){const t=ja.get(e),n=za.get(e),r=t.left-n.left,o=t.top-n.top;if(r||o){const l=e.el.style;return l.transform=l.webkitTransform=`translate(${r}px,${o}px)`,l.transitionDuration="0s",e}}function md(e,t,n){const r=e.cloneNode();e._vtc&&e._vtc.forEach(s=>{s.split(/\s+/).forEach(a=>a&&r.classList.remove(a))}),n.split(/\s+/).forEach(s=>s&&r.classList.add(s)),r.style.display="none";const o=t.nodeType===1?t:t.parentNode;o.appendChild(r);const{hasTransform:l}=Ba(r);return o.removeChild(r),l}const gd=Ce({patchProp:sd},Wf);let no,us=!1;function yd(){return no=us?no:Tf(gd),us=!0,no}const bd=(...e)=>{const t=yd().createApp(...e),{mount:n}=t;return t.mount=r=>{const o=_d(r);if(o)return n(o,!0,o instanceof SVGElement)},t};function _d(e){return ue(e)?document.querySelector(e):e}const wd={"v-8daa1a0e":()=>$(()=>import("./index.html-908cadc5.js"),[]).then(({data:e})=>e),"v-74379e72":()=>$(()=>import("./index.html-22922d8e.js"),[]).then(({data:e})=>e),"v-744497ce":()=>$(()=>import("./index.html-19baa366.js"),[]).then(({data:e})=>e),"v-1a155670":()=>$(()=>import("./judge.html-1f357422.js"),[]).then(({data:e})=>e),"v-82f2a624":()=>$(()=>import("./PERM_PRIV.html-d6a6de2f.js"),[]).then(({data:e})=>e),"v-7445cd33":()=>$(()=>import("./index.html-274fe549.js"),[]).then(({data:e})=>e),"v-5c0c76d7":()=>$(()=>import("./frontend-modify.html-a6e61fc5.js"),[]).then(({data:e})=>e),"v-19b5347a":()=>$(()=>import("./hook.html-d65207ab.js"),[]).then(({data:e})=>e),"v-55131a51":()=>$(()=>import("./third-party-auth.html-26afa0e7.js"),[]).then(({data:e})=>e),"v-5ddc85e1":()=>$(()=>import("./typescript.html-9acb6c36.js"),[]).then(({data:e})=>e),"v-147825fb":()=>$(()=>import("./index.html-f38274db.js"),[]).then(({data:e})=>e),"v-67d16688":()=>$(()=>import("./index.html-c0e68838.js"),[]).then(({data:e})=>e),"v-d67234a8":()=>$(()=>import("./elastic.html-d20c72b1.js"),[]).then(({data:e})=>e),"v-6dd45d9b":()=>$(()=>import("./fps-importer.html-d4ca2ee2.js"),[]).then(({data:e})=>e),"v-16bdf429":()=>$(()=>import("./geoip.html-df96a488.js"),[]).then(({data:e})=>e),"v-a08ef0ec":()=>$(()=>import("./hydrojudge.html-db9328db.js"),[]).then(({data:e})=>e),"v-669bced4":()=>$(()=>import("./migrate.html-6ea5e22e.js"),[]).then(({data:e})=>e),"v-fa72264c":()=>$(()=>import("./recaptcha.html-1a8ae2a8.js"),[]).then(({data:e})=>e),"v-52692a96":()=>$(()=>import("./sonic.html-334946eb.js"),[]).then(({data:e})=>e),"v-3096c190":()=>$(()=>import("./vjudge.html-b94954ed.js"),[]).then(({data:e})=>e),"v-fe9aee22":()=>$(()=>import("./index.html-21cf9e92.js"),[]).then(({data:e})=>e),"v-fdd5d9ea":()=>$(()=>import("./compiler.html-128a8b13.js"),[]).then(({data:e})=>e),"v-4def954c":()=>$(()=>import("./proxy.html-f02dcebb.js"),[]).then(({data:e})=>e),"v-6b4a62ea":()=>$(()=>import("./s3.html-96da8c94.js"),[]).then(({data:e})=>e),"v-68002798":()=>$(()=>import("./smtp.html-b6526407.js"),[]).then(({data:e})=>e),"v-6d3257b0":()=>$(()=>import("./FAQ.html-a854a998.js"),[]).then(({data:e})=>e),"v-0a40e55e":()=>$(()=>import("./cdn.html-32eea34b.js"),[]).then(({data:e})=>e),"v-cceda784":()=>$(()=>import("./cli.html-a2d90d68.js"),[]).then(({data:e})=>e),"v-2250b6d9":()=>$(()=>import("./database.html-71ac4dd0.js"),[]).then(({data:e})=>e),"v-023b4bae":()=>$(()=>import("./frontend-modify.html-2c65da3b.js"),[]).then(({data:e})=>e),"v-69f3a96a":()=>$(()=>import("./import-user.html-3fad9582.js"),[]).then(({data:e})=>e),"v-1bffc66e":()=>$(()=>import("./maintain.html-3da0ffe3.js"),[]).then(({data:e})=>e),"v-666426ae":()=>$(()=>import("./index.html-a019e00a.js"),[]).then(({data:e})=>e),"v-62edc12e":()=>$(()=>import("./copy-problem.html-3012fdb5.js"),[]).then(({data:e})=>e),"v-0566f368":()=>$(()=>import("./domain.html-f07b2a6b.js"),[]).then(({data:e})=>e),"v-1d7ad3e6":()=>$(()=>import("./problem-create.html-91deed11.js"),[]).then(({data:e})=>e),"v-dc52bc6a":()=>$(()=>import("./problem-format.html-e4912d61.js"),[]).then(({data:e})=>e),"v-07f380c3":()=>$(()=>import("./problem.html-b71cd321.js"),[]).then(({data:e})=>e),"v-51b3f914":()=>$(()=>import("./testdata.html-32bf797b.js"),[]).then(({data:e})=>e),"v-3706649a":()=>$(()=>import("./404.html-f441bf5f.js"),[]).then(({data:e})=>e),"v-723d0d85":()=>$(()=>import("./index.html-a6352b1b.js"),[]).then(({data:e})=>e)},Ed=JSON.parse(`{"base":"/","lang":"en-US","title":"Hydro","description":"","head":[["link",{"rel":"icon","href":"/hydro.png"}],["link",{"rel":"stylesheet","href":"/twoslash.css"}],["meta",{"name":"theme-color","content":"#ffeded"}],["script",{"async":true,"src":"https://www.googletagmanager.com/gtag/js?id=G-CX4XJ0H0TE"}],["script",{},"window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments);}gtag('js',new Date());gtag('config','G-CX4XJ0H0TE');"]],"locales":{}}`);var Td=([e,t,n])=>e==="meta"&&t.name?`${e}.${t.name}`:["title","base"].includes(e)?e:e==="template"&&t.id?`${e}.${t.id}`:JSON.stringify([e,t,n]),Cd=e=>{const t=new Set,n=[];return e.forEach(r=>{const o=Td(r);t.has(o)||(t.add(o),n.push(r))}),n},xd=e=>e[e.length-1]==="/"||e.endsWith(".html")?e:`${e}/`,Ad=e=>e.startsWith("ftp://"),An=e=>/^(https?:)?\/\//.test(e),Pd=/.md((\?|#).*)?$/,Lr=(e,t="/")=>!!(An(e)||Ad(e)||e.startsWith("/")&&!e.startsWith(t)&&!Pd.test(e)),qa=e=>/^mailto:/.test(e),kd=e=>/^tel:/.test(e),sl=e=>Object.prototype.toString.call(e)==="[object Object]",al=e=>e[e.length-1]==="/"?e.slice(0,-1):e,Wa=e=>e[0]==="/"?e.slice(1):e,Ld=(e,t)=>{const n=Object.keys(e).sort((r,o)=>{const l=o.split("/").length-r.split("/").length;return l!==0?l:o.length-r.length});for(const r of n)if(t.startsWith(r))return r;return"/"};const Ka={"v-8daa1a0e":ee(()=>$(()=>import("./index.html-31f66e54.js"),["assets/index.html-31f66e54.js","assets/plugin-vue_export-helper-c27b6911.js"])),"v-74379e72":ee(()=>$(()=>import("./index.html-bf152e78.js"),["assets/index.html-bf152e78.js","assets/plugin-vue_export-helper-c27b6911.js"])),"v-744497ce":ee(()=>$(()=>import("./index.html-7d740a66.js"),["assets/index.html-7d740a66.js","assets/plugin-vue_export-helper-c27b6911.js"])),"v-1a155670":ee(()=>$(()=>import("./judge.html-19d8b90f.js"),["assets/judge.html-19d8b90f.js","assets/plugin-vue_export-helper-c27b6911.js"])),"v-82f2a624":ee(()=>$(()=>import("./PERM_PRIV.html-b2407ae4.js"),["assets/PERM_PRIV.html-b2407ae4.js","assets/plugin-vue_export-helper-c27b6911.js"])),"v-7445cd33":ee(()=>$(()=>import("./index.html-ca113d25.js"),["assets/index.html-ca113d25.js","assets/plugin-vue_export-helper-c27b6911.js"])),"v-5c0c76d7":ee(()=>$(()=>import("./frontend-modify.html-a43b88b4.js"),["assets/frontend-modify.html-a43b88b4.js","assets/plugin-vue_export-helper-c27b6911.js"])),"v-19b5347a":ee(()=>$(()=>import("./hook.html-6da4899a.js"),["assets/hook.html-6da4899a.js","assets/plugin-vue_export-helper-c27b6911.js"])),"v-55131a51":ee(()=>$(()=>import("./third-party-auth.html-7df2a358.js"),["assets/third-party-auth.html-7df2a358.js","assets/plugin-vue_export-helper-c27b6911.js"])),"v-5ddc85e1":ee(()=>$(()=>import("./typescript.html-82a8a6f2.js"),["assets/typescript.html-82a8a6f2.js","assets/plugin-vue_export-helper-c27b6911.js"])),"v-147825fb":ee(()=>$(()=>import("./index.html-17594d64.js"),["assets/index.html-17594d64.js","assets/plugin-vue_export-helper-c27b6911.js"])),"v-67d16688":ee(()=>$(()=>import("./index.html-e7b92749.js"),["assets/index.html-e7b92749.js","assets/plugin-vue_export-helper-c27b6911.js"])),"v-d67234a8":ee(()=>$(()=>import("./elastic.html-ac4671fb.js"),["assets/elastic.html-ac4671fb.js","assets/plugin-vue_export-helper-c27b6911.js"])),"v-6dd45d9b":ee(()=>$(()=>import("./fps-importer.html-c0843f3a.js"),["assets/fps-importer.html-c0843f3a.js","assets/plugin-vue_export-helper-c27b6911.js"])),"v-16bdf429":ee(()=>$(()=>import("./geoip.html-5b7c767a.js"),["assets/geoip.html-5b7c767a.js","assets/plugin-vue_export-helper-c27b6911.js"])),"v-a08ef0ec":ee(()=>$(()=>import("./hydrojudge.html-e071cd81.js"),["assets/hydrojudge.html-e071cd81.js","assets/plugin-vue_export-helper-c27b6911.js"])),"v-669bced4":ee(()=>$(()=>import("./migrate.html-2c043ed8.js"),["assets/migrate.html-2c043ed8.js","assets/plugin-vue_export-helper-c27b6911.js"])),"v-fa72264c":ee(()=>$(()=>import("./recaptcha.html-9f4fdce6.js"),["assets/recaptcha.html-9f4fdce6.js","assets/plugin-vue_export-helper-c27b6911.js"])),"v-52692a96":ee(()=>$(()=>import("./sonic.html-03c2bb5e.js"),["assets/sonic.html-03c2bb5e.js","assets/plugin-vue_export-helper-c27b6911.js"])),"v-3096c190":ee(()=>$(()=>import("./vjudge.html-22798d18.js"),["assets/vjudge.html-22798d18.js","assets/plugin-vue_export-helper-c27b6911.js"])),"v-fe9aee22":ee(()=>$(()=>import("./index.html-acd9b80b.js"),["assets/index.html-acd9b80b.js","assets/plugin-vue_export-helper-c27b6911.js"])),"v-fdd5d9ea":ee(()=>$(()=>import("./compiler.html-6d1c02e2.js"),["assets/compiler.html-6d1c02e2.js","assets/plugin-vue_export-helper-c27b6911.js"])),"v-4def954c":ee(()=>$(()=>import("./proxy.html-c1efacca.js"),["assets/proxy.html-c1efacca.js","assets/plugin-vue_export-helper-c27b6911.js"])),"v-6b4a62ea":ee(()=>$(()=>import("./s3.html-f0df93b5.js"),["assets/s3.html-f0df93b5.js","assets/plugin-vue_export-helper-c27b6911.js"])),"v-68002798":ee(()=>$(()=>import("./smtp.html-1fbd4657.js"),["assets/smtp.html-1fbd4657.js","assets/plugin-vue_export-helper-c27b6911.js"])),"v-6d3257b0":ee(()=>$(()=>import("./FAQ.html-a913a06b.js"),["assets/FAQ.html-a913a06b.js","assets/plugin-vue_export-helper-c27b6911.js"])),"v-0a40e55e":ee(()=>$(()=>import("./cdn.html-d6a583e7.js"),["assets/cdn.html-d6a583e7.js","assets/plugin-vue_export-helper-c27b6911.js"])),"v-cceda784":ee(()=>$(()=>import("./cli.html-7c5afadb.js"),["assets/cli.html-7c5afadb.js","assets/plugin-vue_export-helper-c27b6911.js"])),"v-2250b6d9":ee(()=>$(()=>import("./database.html-40e6aaf2.js"),["assets/database.html-40e6aaf2.js","assets/plugin-vue_export-helper-c27b6911.js"])),"v-023b4bae":ee(()=>$(()=>import("./frontend-modify.html-73d58e09.js"),["assets/frontend-modify.html-73d58e09.js","assets/plugin-vue_export-helper-c27b6911.js"])),"v-69f3a96a":ee(()=>$(()=>import("./import-user.html-8528e3c4.js"),["assets/import-user.html-8528e3c4.js","assets/plugin-vue_export-helper-c27b6911.js"])),"v-1bffc66e":ee(()=>$(()=>import("./maintain.html-db7b5a4b.js"),["assets/maintain.html-db7b5a4b.js","assets/plugin-vue_export-helper-c27b6911.js"])),"v-666426ae":ee(()=>$(()=>import("./index.html-1c73bfb8.js"),["assets/index.html-1c73bfb8.js","assets/plugin-vue_export-helper-c27b6911.js"])),"v-62edc12e":ee(()=>$(()=>import("./copy-problem.html-28f2f939.js"),["assets/copy-problem.html-28f2f939.js","assets/plugin-vue_export-helper-c27b6911.js"])),"v-0566f368":ee(()=>$(()=>import("./domain.html-a4ae0e2c.js"),["assets/domain.html-a4ae0e2c.js","assets/plugin-vue_export-helper-c27b6911.js"])),"v-1d7ad3e6":ee(()=>$(()=>import("./problem-create.html-478f6e2f.js"),["assets/problem-create.html-478f6e2f.js","assets/plugin-vue_export-helper-c27b6911.js"])),"v-dc52bc6a":ee(()=>$(()=>import("./problem-format.html-1fd54df1.js"),["assets/problem-format.html-1fd54df1.js","assets/plugin-vue_export-helper-c27b6911.js"])),"v-07f380c3":ee(()=>$(()=>import("./problem.html-a0ddedfc.js"),["assets/problem.html-a0ddedfc.js","assets/plugin-vue_export-helper-c27b6911.js"])),"v-51b3f914":ee(()=>$(()=>import("./testdata.html-4376808f.js"),["assets/testdata.html-4376808f.js","assets/plugin-vue_export-helper-c27b6911.js"])),"v-3706649a":ee(()=>$(()=>import("./404.html-086ab1a5.js"),["assets/404.html-086ab1a5.js","assets/plugin-vue_export-helper-c27b6911.js"])),"v-723d0d85":ee(()=>$(()=>import("./index.html-bbe29c8a.js"),["assets/index.html-bbe29c8a.js","assets/plugin-vue_export-helper-c27b6911.js"]))};var Rd=Symbol(""),Od=X(wd),Ya=Cn({key:"",path:"",title:"",lang:"",frontmatter:{},headers:[]}),Lt=X(Ya),he=()=>Lt,Ga=Symbol(""),ke=()=>{const e=_e(Ga);if(!e)throw new Error("usePageFrontmatter() is called without provider.");return e},Qa=Symbol(""),Sd=()=>{const e=_e(Qa);if(!e)throw new Error("usePageHead() is called without provider.");return e},Id=Symbol(""),Ja=Symbol(""),Xa=()=>{const e=_e(Ja);if(!e)throw new Error("usePageLang() is called without provider.");return e},Za=Symbol(""),$d=()=>{const e=_e(Za);if(!e)throw new Error("usePageLayout() is called without provider.");return e},il=Symbol(""),Pn=()=>{const e=_e(il);if(!e)throw new Error("useRouteLocale() is called without provider.");return e},on=X(Ed),ei=()=>on,ti=Symbol(""),Br=()=>{const e=_e(ti);if(!e)throw new Error("useSiteLocaleData() is called without provider.");return e},Md=Symbol(""),Dd="Layout",Nd="NotFound",ft=Tn({resolveLayouts:e=>e.reduce((t,n)=>({...t,...n.layouts}),{}),resolvePageData:async e=>{const t=Od.value[e];return await(t==null?void 0:t())??Ya},resolvePageFrontmatter:e=>e.frontmatter,resolvePageHead:(e,t,n)=>{const r=ue(t.description)?t.description:n.description,o=[...Q(t.head)?t.head:[],...n.head,["title",{},e],["meta",{name:"description",content:r}]];return Cd(o)},resolvePageHeadTitle:(e,t)=>[e.title,t.title].filter(n=>!!n).join(" | "),resolvePageLang:e=>e.lang||"en",resolvePageLayout:(e,t)=>{let n;if(e.path){const r=e.frontmatter.layout;ue(r)?n=r:n=Dd}else n=Nd;return t[n]},resolveRouteLocale:(e,t)=>Ld(e,t),resolveSiteLocaleData:(e,t)=>({...e,...e.locales[t]})}),Vr=j({name:"ClientOnly",setup(e,t){const n=X(!1);return Ee(()=>{n.value=!0}),()=>{var r,o;return n.value?(o=(r=t.slots).default)==null?void 0:o.call(r):null}}}),ni=j({name:"Content",props:{pageKey:{type:String,required:!1,default:""}},setup(e){const t=he(),n=x(()=>Ka[e.pageKey||t.value.key]);return()=>n.value?u(n.value):u("div","404 Not Found")}}),nt=(e={})=>e,Yt=e=>An(e)?e:`/${Wa(e)}`;const Fd={},me=({name:e="",color:t="currentColor"},{slots:n})=>{var r;return u("svg",{xmlns:"http://www.w3.org/2000/svg",class:["icon",`${e}-icon`],viewBox:"0 0 1024 1024",fill:t,"aria-label":`${e} icon`},(r=n.default)==null?void 0:r.call(n))};me.displayName="IconBase";const ri=(e,{slots:t})=>{var n;return(n=t.default)==null?void 0:n.call(t)},oi=()=>u(me,{name:"github"},()=>u("path",{d:"M511.957 21.333C241.024 21.333 21.333 240.981 21.333 512c0 216.832 140.544 400.725 335.574 465.664 24.49 4.395 32.256-10.07 32.256-23.083 0-11.69.256-44.245 0-85.205-136.448 29.61-164.736-64.64-164.736-64.64-22.315-56.704-54.4-71.765-54.4-71.765-44.587-30.464 3.285-29.824 3.285-29.824 49.195 3.413 75.179 50.517 75.179 50.517 43.776 75.008 114.816 53.333 142.762 40.79 4.523-31.66 17.152-53.377 31.19-65.537-108.971-12.458-223.488-54.485-223.488-242.602 0-53.547 19.114-97.323 50.517-131.67-5.035-12.33-21.93-62.293 4.779-129.834 0 0 41.258-13.184 134.912 50.346a469.803 469.803 0 0 1 122.88-16.554c41.642.213 83.626 5.632 122.88 16.554 93.653-63.488 134.784-50.346 134.784-50.346 26.752 67.541 9.898 117.504 4.864 129.834 31.402 34.347 50.474 78.123 50.474 131.67 0 188.586-114.73 230.016-224.042 242.09 17.578 15.232 33.578 44.672 33.578 90.454v135.85c0 13.142 7.936 27.606 32.854 22.87C862.25 912.597 1002.667 728.747 1002.667 512c0-271.019-219.648-490.667-490.71-490.667z"}));oi.displayName="GitHubIcon";const li=()=>u(me,{name:"gitlab"},()=>u("path",{d:"M229.333 78.688C223.52 62 199.895 62 193.895 78.688L87.958 406.438h247.5c-.188 0-106.125-327.75-106.125-327.75zM33.77 571.438c-4.875 15 .563 31.687 13.313 41.25l464.812 345L87.77 406.438zm301.5-165 176.813 551.25 176.812-551.25zm655.125 165-54-165-424.312 551.25 464.812-345c12.938-9.563 18.188-26.25 13.5-41.25zM830.27 78.688c-5.812-16.688-29.437-16.688-35.437 0l-106.125 327.75h247.5z"}));li.displayName="GitLabIcon";const si=()=>u(me,{name:"gitee"},()=>u("path",{d:"M512 992C246.92 992 32 777.08 32 512S246.92 32 512 32s480 214.92 480 480-214.92 480-480 480zm242.97-533.34H482.39a23.7 23.7 0 0 0-23.7 23.7l-.03 59.28c0 13.08 10.59 23.7 23.7 23.7h165.96a23.7 23.7 0 0 1 23.7 23.7v11.85a71.1 71.1 0 0 1-71.1 71.1H375.71a23.7 23.7 0 0 1-23.7-23.7V423.11a71.1 71.1 0 0 1 71.1-71.1h331.8a23.7 23.7 0 0 0 23.7-23.7l.06-59.25a23.73 23.73 0 0 0-23.7-23.73H423.11a177.78 177.78 0 0 0-177.78 177.75v331.83c0 13.08 10.62 23.7 23.7 23.7h349.62a159.99 159.99 0 0 0 159.99-159.99V482.33a23.7 23.7 0 0 0-23.7-23.7z"}));si.displayName="GiteeIcon";const ai=()=>u(me,{name:"bitbucket"},()=>u("path",{d:"M575.256 490.862c6.29 47.981-52.005 85.723-92.563 61.147-45.714-20.004-45.714-92.562-1.133-113.152 38.29-23.442 93.696 7.424 93.696 52.005zm63.451-11.996c-10.276-81.152-102.29-134.839-177.152-101.156-47.433 21.138-79.433 71.424-77.129 124.562 2.853 69.705 69.157 126.866 138.862 120.576S647.3 548.571 638.708 478.83zm136.558-309.723c-25.161-33.134-67.986-38.839-105.728-45.13-106.862-17.151-216.576-17.7-323.438 1.134-35.438 5.706-75.447 11.996-97.719 43.996 36.572 34.304 88.576 39.424 135.424 45.129 84.553 10.862 171.447 11.447 256 .585 47.433-5.705 99.987-10.276 135.424-45.714zm32.585 591.433c-16.018 55.99-6.839 131.438-66.304 163.986-102.29 56.576-226.304 62.867-338.87 42.862-59.43-10.862-129.135-29.696-161.72-85.723-14.3-54.858-23.442-110.848-32.585-166.84l3.438-9.142 10.276-5.157c170.277 112.567 408.576 112.567 579.438 0 26.844 8.01 6.84 40.558 6.29 60.014zm103.424-549.157c-19.42 125.148-41.728 249.71-63.415 374.272-6.29 36.572-41.728 57.162-71.424 72.558-106.862 53.724-231.424 62.866-348.562 50.286-79.433-8.558-160.585-29.696-225.134-79.433-30.28-23.443-30.28-63.415-35.986-97.134-20.005-117.138-42.862-234.277-57.161-352.585 6.839-51.42 64.585-73.728 107.447-89.71 57.16-21.138 118.272-30.866 178.87-36.571 129.134-12.58 261.157-8.01 386.304 28.562 44.581 13.13 92.563 31.415 122.844 69.705 13.714 17.7 9.143 40.01 6.29 60.014z"}));ai.displayName="BitbucketIcon";const ii=()=>u(me,{name:"source"},()=>u("path",{d:"M601.92 475.2c0 76.428-8.91 83.754-28.512 99.594-14.652 11.88-43.956 14.058-78.012 16.434-18.81 1.386-40.392 2.97-62.172 6.534-18.612 2.97-36.432 9.306-53.064 17.424V299.772c37.818-21.978 63.36-62.766 63.36-109.692 0-69.894-56.826-126.72-126.72-126.72S190.08 120.186 190.08 190.08c0 46.926 25.542 87.714 63.36 109.692v414.216c-37.818 21.978-63.36 62.766-63.36 109.692 0 69.894 56.826 126.72 126.72 126.72s126.72-56.826 126.72-126.72c0-31.086-11.286-59.598-29.7-81.576 13.266-9.504 27.522-17.226 39.996-19.206 16.038-2.574 32.868-3.762 50.688-5.148 48.312-3.366 103.158-7.326 148.896-44.55 61.182-49.698 74.25-103.158 75.24-187.902V475.2h-126.72zM316.8 126.72c34.848 0 63.36 28.512 63.36 63.36s-28.512 63.36-63.36 63.36-63.36-28.512-63.36-63.36 28.512-63.36 63.36-63.36zm0 760.32c-34.848 0-63.36-28.512-63.36-63.36s28.512-63.36 63.36-63.36 63.36 28.512 63.36 63.36-28.512 63.36-63.36 63.36zM823.68 158.4h-95.04V63.36h-126.72v95.04h-95.04v126.72h95.04v95.04h126.72v-95.04h95.04z"}));ii.displayName="SourceIcon";const ci=Array.isArray,Hd=e=>typeof e=="function",Bd=e=>typeof e=="string";var ui=e=>/^(https?:)?\/\//.test(e),fi=e=>Object.prototype.toString.call(e)==="[object Object]";const vt=(e,t)=>{const n=t?t._instance:xn();return fi(n==null?void 0:n.appContext.components)&&(e in n.appContext.components||We(e)in n.appContext.components||Xn(We(e))in n.appContext.components)};function Vd(){const e=X(!1);return xn()&&Ee(()=>{e.value=!0}),e}function jd(e){return Vd(),x(()=>!!e())}const zd=()=>jd(()=>typeof window<"u"&&window.navigator&&"userAgent"in window.navigator),di=()=>{const e=zd();return x(()=>e.value&&/\b(?:Android|iPhone)/i.test(navigator.userAgent))},Nt=e=>{const t=Pn();return x(()=>e[t.value])},Ud=e=>[/\((ipad);[-\w),; ]+apple/i,/applecoremedia\/[\w.]+ \((ipad)/i,/\b(ipad)\d\d?,\d\d?[;\]].+ios/i].some(t=>t.test(e)),qd=e=>[/ip[honead]{2,4}\b(?:.*os ([\w]+) like mac|; opera)/i,/cfnetwork\/.+darwin/i].some(t=>t.test(e)),Wd=e=>[/(mac os x) ?([\w. ]*)/i,/(macintosh|mac_powerpc\b)(?!.+haiku)/i].some(t=>t.test(e)),Kd=(e="")=>{if(e){if(typeof e=="number")return new Date(e);const t=Date.parse(e.toString());if(!Number.isNaN(t))return new Date(t)}return null},pi=(e,t)=>{let n=1;for(let r=0;r>6;return n+=n<<3,n^=n>>11,n%t},Gt=e=>typeof e=="string",Gn=(e,t)=>Gt(e)&&e.startsWith(t),tn=(e,t)=>Gt(e)&&e.endsWith(t),hi=Object.entries,Yd=Object.fromEntries,nr=Object.keys,fs=e=>fi(e)&&Gt(e.name),ds=(e,t=!1)=>e?ci(e)?e.map(n=>Gt(n)?{name:n}:fs(n)?n:null).filter(n=>n!==null):Gt(e)?[{name:e}]:fs(e)?[e]:(console.error(`Expect "author" to be \`AuthorInfo[] | AuthorInfo | string[] | string ${t?"":"| false"} | undefined\`, but got`,e),[]):[],vi=(e,t)=>{if(e){if(ci(e)&&e.every(Gt))return e;if(Gt(e))return[e];console.error(`Expect ${t||"value"} to be \`string[] | string | undefined\`, but got`,e)}return[]},Gd=e=>vi(e,"category"),Qd=e=>vi(e,"tag"),cl=e=>Gn(e,"/"),mi=/#.*$/u,Jd=e=>{const t=mi.exec(e);return t?t[0]:""},ps=e=>decodeURI(e).replace(mi,"").replace(/(index)?\.(md|html)$/,""),ul=(e,t)=>{if(t===void 0)return!1;const n=ps(e.path),r=ps(t),o=Jd(t);return o?o===e.hash&&(!r||n===r):n===r},Xd=e=>ui(e)?e:`https://github.com/${e}`,gi=e=>!ui(e)||/github\.com/.test(e)?"GitHub":/bitbucket\.org/.test(e)?"Bitbucket":/gitlab\.com/.test(e)?"GitLab":/gitee\.com/.test(e)?"Gitee":null,fl=(e,...t)=>{const n=e.resolve(...t),r=n.matched[n.matched.length-1];if(!(r!=null&&r.redirect))return n;const{redirect:o}=r,l=Hd(o)?o(n):o,s=Bd(l)?{path:l}:l;return fl(e,{hash:n.hash,query:n.query,params:n.params,...s})};const yi=({type:e="info",text:t="",vertical:n="top",color:r},{slots:o})=>{var l;return u("span",{class:["badge",e,{diy:r}],style:{verticalAlign:n,...r?{backgroundColor:r}:{}}},((l=o.default)==null?void 0:l.call(o))||t)};yi.displayName="Badge";var Zd=j({name:"FontIcon",props:{icon:{type:String,default:""},color:{type:String,default:""},size:{type:[String,Number],default:""}},setup(e){const t=x(()=>{const r=["font-icon icon"],o=`${e.icon}`;return r.push(o),r}),n=x(()=>{const r={};return e.color&&(r.color=e.color),e.size&&(r["font-size"]=Number.isNaN(Number(e.size))?e.size:`${e.size}px`),nr(r).length?r:null});return()=>e.icon?u("span",{key:e.icon,class:t.value,style:n.value}):null}});function kn(e){return Qs()?(Jc(e),!0):!1}function Ke(e){return typeof e=="function"?e():qt(e)}const rr=typeof window<"u",mn=()=>{},hs=ep();function ep(){var e;return rr&&((e=window==null?void 0:window.navigator)==null?void 0:e.userAgent)&&/iP(ad|hone|od)/.test(window.navigator.userAgent)}function dl(e,t){function n(...r){return new Promise((o,l)=>{Promise.resolve(e(()=>t.apply(this,r),{fn:t,thisArg:this,args:r})).then(o).catch(l)})}return n}const bi=e=>e();function tp(e,t={}){let n,r,o=mn;const l=a=>{clearTimeout(a),o(),o=mn};return a=>{const i=Ke(e),c=Ke(t.maxWait);return n&&l(n),i<=0||c!==void 0&&c<=0?(r&&(l(r),r=null),Promise.resolve(a())):new Promise((f,d)=>{o=t.rejectOnCancel?d:f,c&&!r&&(r=setTimeout(()=>{n&&l(n),r=null,f(a())},c)),n=setTimeout(()=>{r&&l(r),r=null,f(a())},i)})}}function np(e,t=!0,n=!0,r=!1){let o=0,l,s=!0,a=mn,i;const c=()=>{l&&(clearTimeout(l),l=void 0,a(),a=mn)};return d=>{const p=Ke(e),g=Date.now()-o,_=()=>i=d();return c(),p<=0?(o=Date.now(),_()):(g>p&&(n||!s)?(o=Date.now(),_()):t&&(i=new Promise((w,E)=>{a=r?E:w,l=setTimeout(()=>{o=Date.now(),s=!0,w(_()),c()},Math.max(0,p-g))})),!n&&!l&&(l=setTimeout(()=>s=!0,p)),s=!1,i)}}function rp(e=bi){const t=X(!0);function n(){t.value=!1}function r(){t.value=!0}const o=(...l)=>{t.value&&e(...l)};return{isActive:Cn(t),pause:n,resume:r,eventFilter:o}}function _i(...e){if(e.length!==1)return Mr(...e);const t=e[0];return typeof t=="function"?Cn(Lu(()=>({get:t,set:mn}))):X(t)}function Av(e,t=200,n={}){return dl(tp(t,n),e)}function op(e,t=200,n=!1,r=!0,o=!1){return dl(np(t,n,r,o),e)}function lp(e,t=!0){xn()?Ee(e):t?e():Qt(e)}function sp(e,t,n={}){const{immediate:r=!0}=n,o=X(!1);let l=null;function s(){l&&(clearTimeout(l),l=null)}function a(){o.value=!1,s()}function i(...c){s(),o.value=!0,l=setTimeout(()=>{o.value=!1,l=null,e(...c)},Ke(t))}return r&&(o.value=!0,rr&&i()),kn(a),{isPending:Cn(o),start:i,stop:a}}function vs(e=!1,t={}){const{truthyValue:n=!0,falsyValue:r=!1}=t,o=Pe(e),l=X(e);function s(a){if(arguments.length)return l.value=a,l.value;{const i=Ke(n);return l.value=l.value===i?Ke(r):i,l.value}}return o?s:[l,s]}var ms=Object.getOwnPropertySymbols,ap=Object.prototype.hasOwnProperty,ip=Object.prototype.propertyIsEnumerable,cp=(e,t)=>{var n={};for(var r in e)ap.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&ms)for(var r of ms(e))t.indexOf(r)<0&&ip.call(e,r)&&(n[r]=e[r]);return n};function up(e,t,n={}){const r=n,{eventFilter:o=bi}=r,l=cp(r,["eventFilter"]);return fe(e,dl(o,t),l)}var fp=Object.defineProperty,dp=Object.defineProperties,pp=Object.getOwnPropertyDescriptors,Rr=Object.getOwnPropertySymbols,wi=Object.prototype.hasOwnProperty,Ei=Object.prototype.propertyIsEnumerable,gs=(e,t,n)=>t in e?fp(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n,hp=(e,t)=>{for(var n in t||(t={}))wi.call(t,n)&&gs(e,n,t[n]);if(Rr)for(var n of Rr(t))Ei.call(t,n)&&gs(e,n,t[n]);return e},vp=(e,t)=>dp(e,pp(t)),mp=(e,t)=>{var n={};for(var r in e)wi.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&Rr)for(var r of Rr(e))t.indexOf(r)<0&&Ei.call(e,r)&&(n[r]=e[r]);return n};function gp(e,t,n={}){const r=n,{eventFilter:o}=r,l=mp(r,["eventFilter"]),{eventFilter:s,pause:a,resume:i,isActive:c}=rp(o);return{stop:up(e,t,vp(hp({},l),{eventFilter:s})),pause:a,resume:i,isActive:c}}function It(e){var t;const n=Ke(e);return(t=n==null?void 0:n.$el)!=null?t:n}const yt=rr?window:void 0,yp=rr?window.document:void 0,bp=rr?window.navigator:void 0;function Se(...e){let t,n,r,o;if(typeof e[0]=="string"||Array.isArray(e[0])?([n,r,o]=e,t=yt):[t,n,r,o]=e,!t)return mn;Array.isArray(n)||(n=[n]),Array.isArray(r)||(r=[r]);const l=[],s=()=>{l.forEach(f=>f()),l.length=0},a=(f,d,p,g)=>(f.addEventListener(d,p,g),()=>f.removeEventListener(d,p,g)),i=fe(()=>[It(t),Ke(o)],([f,d])=>{s(),f&&l.push(...n.flatMap(p=>r.map(g=>a(f,p,g,d))))},{immediate:!0,flush:"post"}),c=()=>{i(),s()};return kn(c),c}function _p(){const e=X(!1);return xn()&&Ee(()=>{e.value=!0}),e}function jr(e){const t=_p();return x(()=>(t.value,!!e()))}function Ti(e,t={}){const{window:n=yt}=t,r=jr(()=>n&&"matchMedia"in n&&typeof n.matchMedia=="function");let o;const l=X(!1),s=()=>{o&&("removeEventListener"in o?o.removeEventListener("change",a):o.removeListener(a))},a=()=>{r.value&&(s(),o=n.matchMedia(_i(e).value),l.value=!!(o!=null&&o.matches),o&&("addEventListener"in o?o.addEventListener("change",a):o.addListener(a)))};return Ku(a),kn(()=>s()),l}function wp(e={}){const{navigator:t=bp,read:n=!1,source:r,copiedDuring:o=1500,legacy:l=!1}=e,s=["copy","cut"],a=jr(()=>t&&"clipboard"in t),i=x(()=>a.value||l),c=X(""),f=X(!1),d=sp(()=>f.value=!1,o);function p(){a.value?t.clipboard.readText().then(E=>{c.value=E}):c.value=w()}if(i.value&&n)for(const E of s)Se(E,p);async function g(E=Ke(r)){i.value&&E!=null&&(a.value?await t.clipboard.writeText(E):_(E),c.value=E,f.value=!0,d.start())}function _(E){const m=document.createElement("textarea");m.value=E??"",m.style.position="absolute",m.style.opacity="0",document.body.appendChild(m),m.select(),document.execCommand("copy"),m.remove()}function w(){var E,m,b;return(b=(m=(E=document==null?void 0:document.getSelection)==null?void 0:E.call(document))==null?void 0:m.toString())!=null?b:""}return{isSupported:i,text:c,copied:f,copy:g}}const vr=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{},mr="__vueuse_ssr_handlers__",Ep=Tp();function Tp(){return mr in vr||(vr[mr]=vr[mr]||{}),vr[mr]}function Cp(e,t){return Ep[e]||t}function xp(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"}var Ap=Object.defineProperty,ys=Object.getOwnPropertySymbols,Pp=Object.prototype.hasOwnProperty,kp=Object.prototype.propertyIsEnumerable,bs=(e,t,n)=>t in e?Ap(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n,_s=(e,t)=>{for(var n in t||(t={}))Pp.call(t,n)&&bs(e,n,t[n]);if(ys)for(var n of ys(t))kp.call(t,n)&&bs(e,n,t[n]);return e};const Lp={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()}},ws="vueuse-storage";function Ci(e,t,n,r={}){var o;const{flush:l="pre",deep:s=!0,listenToStorageChanges:a=!0,writeDefaults:i=!0,mergeDefaults:c=!1,shallow:f,window:d=yt,eventFilter:p,onError:g=P=>{console.error(P)}}=r,_=(f?bt:X)(t);if(!n)try{n=Cp("getDefaultStorage",()=>{var P;return(P=yt)==null?void 0:P.localStorage})()}catch(P){g(P)}if(!n)return _;const w=Ke(t),E=xp(w),m=(o=r.serializer)!=null?o:Lp[E],{pause:b,resume:S}=gp(_,()=>O(_.value),{flush:l,deep:s,eventFilter:p});return d&&a&&(Se(d,"storage",Y),Se(d,ws,R)),Y(),_;function O(P){try{if(P==null)n.removeItem(e);else{const V=m.write(P),G=n.getItem(e);G!==V&&(n.setItem(e,V),d&&d.dispatchEvent(new CustomEvent(ws,{detail:{key:e,oldValue:G,newValue:V,storageArea:n}})))}}catch(V){g(V)}}function z(P){const V=P?P.newValue:n.getItem(e);if(V==null)return i&&w!==null&&n.setItem(e,m.write(w)),w;if(!P&&c){const G=m.read(V);return typeof c=="function"?c(G,w):E==="object"&&!Array.isArray(G)?_s(_s({},w),G):G}else return typeof V!="string"?V:m.read(V)}function R(P){Y(P.detail)}function Y(P){if(!(P&&P.storageArea!==n)){if(P&&P.key==null){_.value=w;return}if(!(P&&P.key!==e)){b();try{_.value=z(P)}catch(V){g(V)}finally{P?Qt(S):S()}}}}}function Rp(e){return Ti("(prefers-color-scheme: dark)",e)}var Es=Object.getOwnPropertySymbols,Op=Object.prototype.hasOwnProperty,Sp=Object.prototype.propertyIsEnumerable,Ip=(e,t)=>{var n={};for(var r in e)Op.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&Es)for(var r of Es(e))t.indexOf(r)<0&&Sp.call(e,r)&&(n[r]=e[r]);return n};function $p(e,t,n={}){const r=n,{window:o=yt}=r,l=Ip(r,["window"]);let s;const a=jr(()=>o&&"ResizeObserver"in o),i=()=>{s&&(s.disconnect(),s=void 0)},c=x(()=>Array.isArray(e)?e.map(p=>It(p)):[It(e)]),f=fe(c,p=>{if(i(),a.value&&o){s=new ResizeObserver(t);for(const g of p)g&&s.observe(g,l)}},{immediate:!0,flush:"post",deep:!0}),d=()=>{i(),f()};return kn(d),{isSupported:a,stop:d}}function Mp(e,t={width:0,height:0},n={}){const{window:r=yt,box:o="content-box"}=n,l=x(()=>{var i,c;return(c=(i=It(e))==null?void 0:i.namespaceURI)==null?void 0:c.includes("svg")}),s=X(t.width),a=X(t.height);return $p(e,([i])=>{const c=o==="border-box"?i.borderBoxSize:o==="content-box"?i.contentBoxSize:i.devicePixelContentBoxSize;if(r&&l.value){const f=It(e);if(f){const d=r.getComputedStyle(f);s.value=parseFloat(d.width),a.value=parseFloat(d.height)}}else if(c){const f=Array.isArray(c)?c:[c];s.value=f.reduce((d,{inlineSize:p})=>d+p,0),a.value=f.reduce((d,{blockSize:p})=>d+p,0)}else s.value=i.contentRect.width,a.value=i.contentRect.height},n),fe(()=>It(e),i=>{s.value=i?t.width:0,a.value=i?t.height:0}),{width:s,height:a}}const Ts=["fullscreenchange","webkitfullscreenchange","webkitendfullscreen","mozfullscreenchange","MSFullscreenChange"];function pl(e,t={}){const{document:n=yp,autoExit:r=!1}=t,o=x(()=>{var m;return(m=It(e))!=null?m:n==null?void 0:n.querySelector("html")}),l=X(!1),s=x(()=>["requestFullscreen","webkitRequestFullscreen","webkitEnterFullscreen","webkitEnterFullScreen","webkitRequestFullScreen","mozRequestFullScreen","msRequestFullscreen"].find(m=>n&&m in n||o.value&&m in o.value)),a=x(()=>["exitFullscreen","webkitExitFullscreen","webkitExitFullScreen","webkitCancelFullScreen","mozCancelFullScreen","msExitFullscreen"].find(m=>n&&m in n||o.value&&m in o.value)),i=x(()=>["fullScreen","webkitIsFullScreen","webkitDisplayingFullscreen","mozFullScreen","msFullscreenElement"].find(m=>n&&m in n||o.value&&m in o.value)),c=["fullscreenElement","webkitFullscreenElement","mozFullScreenElement","msFullscreenElement"].find(m=>n&&m in n),f=jr(()=>o.value&&n&&s.value!==void 0&&a.value!==void 0&&i.value!==void 0),d=()=>c?(n==null?void 0:n[c])===o.value:!1,p=()=>{if(i.value){if(n&&n[i.value]!=null)return n[i.value];{const m=o.value;if((m==null?void 0:m[i.value])!=null)return!!m[i.value]}}return!1};async function g(){if(f.value){if(a.value)if((n==null?void 0:n[a.value])!=null)await n[a.value]();else{const m=o.value;(m==null?void 0:m[a.value])!=null&&await m[a.value]()}l.value=!1}}async function _(){if(!f.value)return;p()&&await g();const m=o.value;s.value&&(m==null?void 0:m[s.value])!=null&&(await m[s.value](),l.value=!0)}async function w(){await(l.value?g():_())}const E=()=>{const m=p();(!m||m&&d())&&(l.value=m)};return Se(n,Ts,E,!1),Se(()=>It(o),Ts,E,!1),r&&kn(g),{isSupported:f,isFullscreen:l,enter:_,exit:g,toggle:w}}function Dp(e,t,n={}){const{window:r=yt}=n;return Ci(e,t,r==null?void 0:r.localStorage,n)}function xi(e){const t=window.getComputedStyle(e);if(t.overflowX==="scroll"||t.overflowY==="scroll"||t.overflowX==="auto"&&e.clientHeight1?!0:(t.preventDefault&&t.preventDefault(),!1)}function hl(e,t=!1){const n=X(t);let r=null,o;fe(_i(e),a=>{if(a){const i=a;o=i.style.overflow,n.value&&(i.style.overflow="hidden")}},{immediate:!0});const l=()=>{const a=Ke(e);!a||n.value||(hs&&(r=Se(a,"touchmove",i=>{Np(i)},{passive:!1})),a.style.overflow="hidden",n.value=!0)},s=()=>{const a=Ke(e);!a||!n.value||(hs&&(r==null||r()),a.style.overflow=o,n.value=!1)};return kn(s),x({get(){return n.value},set(a){a?l():s()}})}function Fp({window:e=yt}={}){if(!e)return{x:X(0),y:X(0)};const t=X(e.scrollX),n=X(e.scrollY);return Se(e,"scroll",()=>{t.value=e.scrollX,n.value=e.scrollY},{capture:!1,passive:!0}),{x:t,y:n}}function Hp(e={}){const{window:t=yt,initialWidth:n=1/0,initialHeight:r=1/0,listenOrientation:o=!0,includeScrollbar:l=!0}=e,s=X(n),a=X(r),i=()=>{t&&(l?(s.value=t.innerWidth,a.value=t.innerHeight):(s.value=t.document.documentElement.clientWidth,a.value=t.document.documentElement.clientHeight))};if(i(),lp(i),Se("resize",i,{passive:!0}),o){const c=Ti("(orientation: portrait)");fe(c,()=>i())}return{width:s,height:a}}const Ai=()=>u(me,{name:"back-to-top"},()=>[u("path",{d:"M512 843.2c-36.2 0-66.4-13.6-85.8-21.8-10.8-4.6-22.6 3.6-21.8 15.2l7 102c.4 6.2 7.6 9.4 12.6 5.6l29-22c3.6-2.8 9-1.8 11.4 2l41 64.2c3 4.8 10.2 4.8 13.2 0l41-64.2c2.4-3.8 7.8-4.8 11.4-2l29 22c5 3.8 12.2.6 12.6-5.6l7-102c.8-11.6-11-20-21.8-15.2-19.6 8.2-49.6 21.8-85.8 21.8z"}),u("path",{d:"m795.4 586.2-96-98.2C699.4 172 513 32 513 32S324.8 172 324.8 488l-96 98.2c-3.6 3.6-5.2 9-4.4 14.2L261.2 824c1.8 11.4 14.2 17 23.6 10.8L419 744s41.4 40 94.2 40c52.8 0 92.2-40 92.2-40l134.2 90.8c9.2 6.2 21.6.6 23.6-10.8l37-223.8c.4-5.2-1.2-10.4-4.8-14zM513 384c-34 0-61.4-28.6-61.4-64s27.6-64 61.4-64c34 0 61.4 28.6 61.4 64S547 384 513 384z"})]);Ai.displayName="BackToTopIcon";var Bp=j({name:"BackToTop",props:{threshold:{type:Number,default:100},noProgress:Boolean},setup(e){const t=ke(),n=Nt({"/":{backToTop:"Back to top"}}),r=bt(),{height:o}=Mp(r),{height:l}=Hp(),{y:s}=Fp(),a=x(()=>t.value.backToTop!==!1&&s.value>e.threshold),i=x(()=>s.value/(o.value-l.value));return Ee(()=>{r.value=document.body}),()=>u(Dt,{name:"fade"},()=>a.value?u("button",{type:"button",class:"back-to-top","aria-label":n.value.backToTop,"data-balloon-pos":"left",onClick:()=>{window.scrollTo({top:0,behavior:"smooth"})}},[e.noProgress?null:u("svg",{class:"scroll-progress"},u("circle",{cx:"50%",cy:"50%",style:{"stroke-dasharray":`calc(${Math.PI*i.value*100}% - ${4*Math.PI}px) calc(${Math.PI*100}% - ${4*Math.PI}px)`}})),u(Ai)]):null)}});const Vp=nt({enhance:({app:e})=>{vt("Badge")||e.component("Badge",yi),vt("FontIcon")||e.component("FontIcon",Zd)},setup:()=>{},rootComponents:[()=>u(Bp,{})]});function jp(e,t,n){var r,o,l;t===void 0&&(t=50),n===void 0&&(n={});var s=(r=n.isImmediate)!=null&&r,a=(o=n.callback)!=null&&o,i=n.maxWait,c=Date.now(),f=[];function d(){if(i!==void 0){var g=Date.now()-c;if(g+t>=i)return i-g}return t}var p=function(){var g=[].slice.call(arguments),_=this;return new Promise(function(w,E){var m=s&&l===void 0;if(l!==void 0&&clearTimeout(l),l=setTimeout(function(){if(l=void 0,c=Date.now(),!s){var S=e.apply(_,g);a&&a(S),f.forEach(function(O){return(0,O.resolve)(S)}),f=[]}},d()),m){var b=e.apply(_,g);return a&&a(b),w(b)}f.push({resolve:w,reject:E})})};return p.cancel=function(g){l!==void 0&&clearTimeout(l),f.forEach(function(_){return(0,_.reject)(g)}),f=[]},p}/*! + * vue-router v4.2.1 + * (c) 2023 Eduardo San Martin Morote + * @license MIT + */const nn=typeof window<"u";function zp(e){return e.__esModule||e[Symbol.toStringTag]==="Module"}const de=Object.assign;function ro(e,t){const n={};for(const r in t){const o=t[r];n[r]=tt(o)?o.map(e):e(o)}return n}const Bn=()=>{},tt=Array.isArray,Up=/\/$/,qp=e=>e.replace(Up,"");function oo(e,t,n="/"){let r,o={},l="",s="";const a=t.indexOf("#");let i=t.indexOf("?");return a=0&&(i=-1),i>-1&&(r=t.slice(0,i),l=t.slice(i+1,a>-1?a:t.length),o=e(l)),a>-1&&(r=r||t.slice(0,a),s=t.slice(a,t.length)),r=Gp(r??t,n),{fullPath:r+(l&&"?")+l+s,path:r,query:o,hash:s}}function Wp(e,t){const n=t.query?e(t.query):"";return t.path+(n&&"?")+n+(t.hash||"")}function Cs(e,t){return!t||!e.toLowerCase().startsWith(t.toLowerCase())?e:e.slice(t.length)||"/"}function Kp(e,t,n){const r=t.matched.length-1,o=n.matched.length-1;return r>-1&&r===o&&gn(t.matched[r],n.matched[o])&&Pi(t.params,n.params)&&e(t.query)===e(n.query)&&t.hash===n.hash}function gn(e,t){return(e.aliasOf||e)===(t.aliasOf||t)}function Pi(e,t){if(Object.keys(e).length!==Object.keys(t).length)return!1;for(const n in e)if(!Yp(e[n],t[n]))return!1;return!0}function Yp(e,t){return tt(e)?xs(e,t):tt(t)?xs(t,e):e===t}function xs(e,t){return tt(t)?e.length===t.length&&e.every((n,r)=>n===t[r]):e.length===1&&e[0]===t}function Gp(e,t){if(e.startsWith("/"))return e;if(!e)return t;const n=t.split("/"),r=e.split("/"),o=r[r.length-1];(o===".."||o===".")&&r.push("");let l=n.length-1,s,a;for(s=0;s1&&l--;else break;return n.slice(0,l).join("/")+"/"+r.slice(s-(s===r.length?1:0)).join("/")}var Qn;(function(e){e.pop="pop",e.push="push"})(Qn||(Qn={}));var Vn;(function(e){e.back="back",e.forward="forward",e.unknown=""})(Vn||(Vn={}));function Qp(e){if(!e)if(nn){const t=document.querySelector("base");e=t&&t.getAttribute("href")||"/",e=e.replace(/^\w+:\/\/[^\/]+/,"")}else e="/";return e[0]!=="/"&&e[0]!=="#"&&(e="/"+e),qp(e)}const Jp=/^[^#]+#/;function Xp(e,t){return e.replace(Jp,"#")+t}function Zp(e,t){const n=document.documentElement.getBoundingClientRect(),r=e.getBoundingClientRect();return{behavior:t.behavior,left:r.left-n.left-(t.left||0),top:r.top-n.top-(t.top||0)}}const zr=()=>({left:window.pageXOffset,top:window.pageYOffset});function eh(e){let t;if("el"in e){const n=e.el,r=typeof n=="string"&&n.startsWith("#"),o=typeof n=="string"?r?document.getElementById(n.slice(1)):document.querySelector(n):n;if(!o)return;t=Zp(o,e)}else t=e;"scrollBehavior"in document.documentElement.style?window.scrollTo(t):window.scrollTo(t.left!=null?t.left:window.pageXOffset,t.top!=null?t.top:window.pageYOffset)}function As(e,t){return(history.state?history.state.position-t:-1)+e}const xo=new Map;function th(e,t){xo.set(e,t)}function nh(e){const t=xo.get(e);return xo.delete(e),t}let rh=()=>location.protocol+"//"+location.host;function ki(e,t){const{pathname:n,search:r,hash:o}=t,l=e.indexOf("#");if(l>-1){let a=o.includes(e.slice(l))?e.slice(l).length:1,i=o.slice(a);return i[0]!=="/"&&(i="/"+i),Cs(i,"")}return Cs(n,e)+r+o}function oh(e,t,n,r){let o=[],l=[],s=null;const a=({state:p})=>{const g=ki(e,location),_=n.value,w=t.value;let E=0;if(p){if(n.value=g,t.value=p,s&&s===_){s=null;return}E=w?p.position-w.position:0}else r(g);o.forEach(m=>{m(n.value,_,{delta:E,type:Qn.pop,direction:E?E>0?Vn.forward:Vn.back:Vn.unknown})})};function i(){s=n.value}function c(p){o.push(p);const g=()=>{const _=o.indexOf(p);_>-1&&o.splice(_,1)};return l.push(g),g}function f(){const{history:p}=window;p.state&&p.replaceState(de({},p.state,{scroll:zr()}),"")}function d(){for(const p of l)p();l=[],window.removeEventListener("popstate",a),window.removeEventListener("beforeunload",f)}return window.addEventListener("popstate",a),window.addEventListener("beforeunload",f,{passive:!0}),{pauseListeners:i,listen:c,destroy:d}}function Ps(e,t,n,r=!1,o=!1){return{back:e,current:t,forward:n,replaced:r,position:window.history.length,scroll:o?zr():null}}function lh(e){const{history:t,location:n}=window,r={value:ki(e,n)},o={value:t.state};o.value||l(r.value,{back:null,current:r.value,forward:null,position:t.length-1,replaced:!0,scroll:null},!0);function l(i,c,f){const d=e.indexOf("#"),p=d>-1?(n.host&&document.querySelector("base")?e:e.slice(d))+i:rh()+e+i;try{t[f?"replaceState":"pushState"](c,"",p),o.value=c}catch(g){console.error(g),n[f?"replace":"assign"](p)}}function s(i,c){const f=de({},t.state,Ps(o.value.back,i,o.value.forward,!0),c,{position:o.value.position});l(i,f,!0),r.value=i}function a(i,c){const f=de({},o.value,t.state,{forward:i,scroll:zr()});l(f.current,f,!0);const d=de({},Ps(r.value,i,null),{position:f.position+1},c);l(i,d,!1),r.value=i}return{location:r,state:o,push:a,replace:s}}function sh(e){e=Qp(e);const t=lh(e),n=oh(e,t.state,t.location,t.replace);function r(l,s=!0){s||n.pauseListeners(),history.go(l)}const o=de({location:"",base:e,go:r,createHref:Xp.bind(null,e)},t,n);return Object.defineProperty(o,"location",{enumerable:!0,get:()=>t.location.value}),Object.defineProperty(o,"state",{enumerable:!0,get:()=>t.state.value}),o}function ah(e){return typeof e=="string"||e&&typeof e=="object"}function Li(e){return typeof e=="string"||typeof e=="symbol"}const dt={path:"/",name:void 0,params:{},query:{},hash:"",fullPath:"/",matched:[],meta:{},redirectedFrom:void 0},Ri=Symbol("");var ks;(function(e){e[e.aborted=4]="aborted",e[e.cancelled=8]="cancelled",e[e.duplicated=16]="duplicated"})(ks||(ks={}));function yn(e,t){return de(new Error,{type:e,[Ri]:!0},t)}function it(e,t){return e instanceof Error&&Ri in e&&(t==null||!!(e.type&t))}const Ls="[^/]+?",ih={sensitive:!1,strict:!1,start:!0,end:!0},ch=/[.+*?^${}()[\]/\\]/g;function uh(e,t){const n=de({},ih,t),r=[];let o=n.start?"^":"";const l=[];for(const c of e){const f=c.length?[]:[90];n.strict&&!c.length&&(o+="/");for(let d=0;dt.length?t.length===1&&t[0]===40+40?1:-1:0}function dh(e,t){let n=0;const r=e.score,o=t.score;for(;n0&&t[t.length-1]<0}const ph={type:0,value:""},hh=/[a-zA-Z0-9_]/;function vh(e){if(!e)return[[]];if(e==="/")return[[ph]];if(!e.startsWith("/"))throw new Error(`Invalid path "${e}"`);function t(g){throw new Error(`ERR (${n})/"${c}": ${g}`)}let n=0,r=n;const o=[];let l;function s(){l&&o.push(l),l=[]}let a=0,i,c="",f="";function d(){c&&(n===0?l.push({type:0,value:c}):n===1||n===2||n===3?(l.length>1&&(i==="*"||i==="+")&&t(`A repeatable param (${c}) must be alone in its segment. eg: '/:ids+.`),l.push({type:1,value:c,regexp:f,repeatable:i==="*"||i==="+",optional:i==="*"||i==="?"})):t("Invalid state to consume buffer"),c="")}function p(){c+=i}for(;a{s(b)}:Bn}function s(f){if(Li(f)){const d=r.get(f);d&&(r.delete(f),n.splice(n.indexOf(d),1),d.children.forEach(s),d.alias.forEach(s))}else{const d=n.indexOf(f);d>-1&&(n.splice(d,1),f.record.name&&r.delete(f.record.name),f.children.forEach(s),f.alias.forEach(s))}}function a(){return n}function i(f){let d=0;for(;d=0&&(f.record.path!==n[d].record.path||!Oi(f,n[d]));)d++;n.splice(d,0,f),f.record.name&&!Ss(f)&&r.set(f.record.name,f)}function c(f,d){let p,g={},_,w;if("name"in f&&f.name){if(p=r.get(f.name),!p)throw yn(1,{location:f});w=p.record.name,g=de(Os(d.params,p.keys.filter(b=>!b.optional).map(b=>b.name)),f.params&&Os(f.params,p.keys.map(b=>b.name))),_=p.stringify(g)}else if("path"in f)_=f.path,p=n.find(b=>b.re.test(_)),p&&(g=p.parse(_),w=p.record.name);else{if(p=d.name?r.get(d.name):n.find(b=>b.re.test(d.path)),!p)throw yn(1,{location:f,currentLocation:d});w=p.record.name,g=de({},d.params,f.params),_=p.stringify(g)}const E=[];let m=p;for(;m;)E.unshift(m.record),m=m.parent;return{name:w,path:_,params:g,matched:E,meta:_h(E)}}return e.forEach(f=>l(f)),{addRoute:l,resolve:c,removeRoute:s,getRoutes:a,getRecordMatcher:o}}function Os(e,t){const n={};for(const r of t)r in e&&(n[r]=e[r]);return n}function yh(e){return{path:e.path,redirect:e.redirect,name:e.name,meta:e.meta||{},aliasOf:void 0,beforeEnter:e.beforeEnter,props:bh(e),children:e.children||[],instances:{},leaveGuards:new Set,updateGuards:new Set,enterCallbacks:{},components:"components"in e?e.components||null:e.component&&{default:e.component}}}function bh(e){const t={},n=e.props||!1;if("component"in e)t.default=n;else for(const r in e.components)t[r]=typeof n=="boolean"?n:n[r];return t}function Ss(e){for(;e;){if(e.record.aliasOf)return!0;e=e.parent}return!1}function _h(e){return e.reduce((t,n)=>de(t,n.meta),{})}function Is(e,t){const n={};for(const r in e)n[r]=r in t?t[r]:e[r];return n}function Oi(e,t){return t.children.some(n=>n===e||Oi(e,n))}const Si=/#/g,wh=/&/g,Eh=/\//g,Th=/=/g,Ch=/\?/g,Ii=/\+/g,xh=/%5B/g,Ah=/%5D/g,$i=/%5E/g,Ph=/%60/g,Mi=/%7B/g,kh=/%7C/g,Di=/%7D/g,Lh=/%20/g;function vl(e){return encodeURI(""+e).replace(kh,"|").replace(xh,"[").replace(Ah,"]")}function Rh(e){return vl(e).replace(Mi,"{").replace(Di,"}").replace($i,"^")}function Ao(e){return vl(e).replace(Ii,"%2B").replace(Lh,"+").replace(Si,"%23").replace(wh,"%26").replace(Ph,"`").replace(Mi,"{").replace(Di,"}").replace($i,"^")}function Oh(e){return Ao(e).replace(Th,"%3D")}function Sh(e){return vl(e).replace(Si,"%23").replace(Ch,"%3F")}function Ih(e){return e==null?"":Sh(e).replace(Eh,"%2F")}function Or(e){try{return decodeURIComponent(""+e)}catch{}return""+e}function $h(e){const t={};if(e===""||e==="?")return t;const r=(e[0]==="?"?e.slice(1):e).split("&");for(let o=0;ol&&Ao(l)):[r&&Ao(r)]).forEach(l=>{l!==void 0&&(t+=(t.length?"&":"")+n,l!=null&&(t+="="+l))})}return t}function Mh(e){const t={};for(const n in e){const r=e[n];r!==void 0&&(t[n]=tt(r)?r.map(o=>o==null?null:""+o):r==null?r:""+r)}return t}const Dh=Symbol(""),Ms=Symbol(""),Ur=Symbol(""),ml=Symbol(""),Po=Symbol("");function On(){let e=[];function t(r){return e.push(r),()=>{const o=e.indexOf(r);o>-1&&e.splice(o,1)}}function n(){e=[]}return{add:t,list:()=>e,reset:n}}function Rt(e,t,n,r,o){const l=r&&(r.enterCallbacks[o]=r.enterCallbacks[o]||[]);return()=>new Promise((s,a)=>{const i=d=>{d===!1?a(yn(4,{from:n,to:t})):d instanceof Error?a(d):ah(d)?a(yn(2,{from:t,to:d})):(l&&r.enterCallbacks[o]===l&&typeof d=="function"&&l.push(d),s())},c=e.call(r&&r.instances[o],t,n,i);let f=Promise.resolve(c);e.length<3&&(f=f.then(i)),f.catch(d=>a(d))})}function lo(e,t,n,r){const o=[];for(const l of e)for(const s in l.components){let a=l.components[s];if(!(t!=="beforeRouteEnter"&&!l.instances[s]))if(Nh(a)){const c=(a.__vccOpts||a)[t];c&&o.push(Rt(c,n,r,l,s))}else{let i=a();o.push(()=>i.then(c=>{if(!c)return Promise.reject(new Error(`Couldn't resolve component "${s}" at "${l.path}"`));const f=zp(c)?c.default:c;l.components[s]=f;const p=(f.__vccOpts||f)[t];return p&&Rt(p,n,r,l,s)()}))}}return o}function Nh(e){return typeof e=="object"||"displayName"in e||"props"in e||"__vccOpts"in e}function ko(e){const t=_e(Ur),n=_e(ml),r=x(()=>t.resolve(qt(e.to))),o=x(()=>{const{matched:i}=r.value,{length:c}=i,f=i[c-1],d=n.matched;if(!f||!d.length)return-1;const p=d.findIndex(gn.bind(null,f));if(p>-1)return p;const g=Ds(i[c-2]);return c>1&&Ds(f)===g&&d[d.length-1].path!==g?d.findIndex(gn.bind(null,i[c-2])):p}),l=x(()=>o.value>-1&&Bh(n.params,r.value.params)),s=x(()=>o.value>-1&&o.value===n.matched.length-1&&Pi(n.params,r.value.params));function a(i={}){return Hh(i)?t[qt(e.replace)?"replace":"push"](qt(e.to)).catch(Bn):Promise.resolve()}return{route:r,href:x(()=>r.value.href),isActive:l,isExactActive:s,navigate:a}}const Fh=j({name:"RouterLink",compatConfig:{MODE:3},props:{to:{type:[String,Object],required:!0},replace:Boolean,activeClass:String,exactActiveClass:String,custom:Boolean,ariaCurrentValue:{type:String,default:"page"}},useLink:ko,setup(e,{slots:t}){const n=Tn(ko(e)),{options:r}=_e(Ur),o=x(()=>({[Ns(e.activeClass,r.linkActiveClass,"router-link-active")]:n.isActive,[Ns(e.exactActiveClass,r.linkExactActiveClass,"router-link-exact-active")]:n.isExactActive}));return()=>{const l=t.default&&t.default(n);return e.custom?l:u("a",{"aria-current":n.isExactActive?e.ariaCurrentValue:null,href:n.href,onClick:n.navigate,class:o.value},l)}}}),mt=Fh;function Hh(e){if(!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)&&!e.defaultPrevented&&!(e.button!==void 0&&e.button!==0)){if(e.currentTarget&&e.currentTarget.getAttribute){const t=e.currentTarget.getAttribute("target");if(/\b_blank\b/i.test(t))return}return e.preventDefault&&e.preventDefault(),!0}}function Bh(e,t){for(const n in t){const r=t[n],o=e[n];if(typeof r=="string"){if(r!==o)return!1}else if(!tt(o)||o.length!==r.length||r.some((l,s)=>l!==o[s]))return!1}return!0}function Ds(e){return e?e.aliasOf?e.aliasOf.path:e.path:""}const Ns=(e,t,n)=>e??t??n,Vh=j({name:"RouterView",inheritAttrs:!1,props:{name:{type:String,default:"default"},route:Object},compatConfig:{MODE:3},setup(e,{attrs:t,slots:n}){const r=_e(Po),o=x(()=>e.route||r.value),l=_e(Ms,0),s=x(()=>{let c=qt(l);const{matched:f}=o.value;let d;for(;(d=f[c])&&!d.components;)c++;return c}),a=x(()=>o.value.matched[s.value]);Wt(Ms,x(()=>s.value+1)),Wt(Dh,a),Wt(Po,o);const i=X();return fe(()=>[i.value,a.value,e.name],([c,f,d],[p,g,_])=>{f&&(f.instances[d]=c,g&&g!==f&&c&&c===p&&(f.leaveGuards.size||(f.leaveGuards=g.leaveGuards),f.updateGuards.size||(f.updateGuards=g.updateGuards))),c&&f&&(!g||!gn(f,g)||!p)&&(f.enterCallbacks[d]||[]).forEach(w=>w(c))},{flush:"post"}),()=>{const c=o.value,f=e.name,d=a.value,p=d&&d.components[f];if(!p)return Fs(n.default,{Component:p,route:c});const g=d.props[f],_=g?g===!0?c.params:typeof g=="function"?g(c):g:null,E=u(p,de({},_,t,{onVnodeUnmounted:m=>{m.component.isUnmounted&&(d.instances[f]=null)},ref:i}));return Fs(n.default,{Component:E,route:c})||E}}});function Fs(e,t){if(!e)return null;const n=e(t);return n.length===1?n[0]:n}const Ni=Vh;function jh(e){const t=gh(e.routes,e),n=e.parseQuery||$h,r=e.stringifyQuery||$s,o=e.history,l=On(),s=On(),a=On(),i=bt(dt);let c=dt;nn&&e.scrollBehavior&&"scrollRestoration"in history&&(history.scrollRestoration="manual");const f=ro.bind(null,C=>""+C),d=ro.bind(null,Ih),p=ro.bind(null,Or);function g(C,F){let D,q;return Li(C)?(D=t.getRecordMatcher(C),q=F):q=C,t.addRoute(q,D)}function _(C){const F=t.getRecordMatcher(C);F&&t.removeRoute(F)}function w(){return t.getRoutes().map(C=>C.record)}function E(C){return!!t.getRecordMatcher(C)}function m(C,F){if(F=de({},F||i.value),typeof C=="string"){const y=oo(n,C,F.path),T=t.resolve({path:y.path},F),A=o.createHref(y.fullPath);return de(y,T,{params:p(T.params),hash:Or(y.hash),redirectedFrom:void 0,href:A})}let D;if("path"in C)D=de({},C,{path:oo(n,C.path,F.path).path});else{const y=de({},C.params);for(const T in y)y[T]==null&&delete y[T];D=de({},C,{params:d(y)}),F.params=d(F.params)}const q=t.resolve(D,F),ce=C.hash||"";q.params=f(p(q.params));const h=Wp(r,de({},C,{hash:Rh(ce),path:q.path})),v=o.createHref(h);return de({fullPath:h,hash:ce,query:r===$s?Mh(C.query):C.query||{}},q,{redirectedFrom:void 0,href:v})}function b(C){return typeof C=="string"?oo(n,C,i.value.path):de({},C)}function S(C,F){if(c!==C)return yn(8,{from:F,to:C})}function O(C){return Y(C)}function z(C){return O(de(b(C),{replace:!0}))}function R(C){const F=C.matched[C.matched.length-1];if(F&&F.redirect){const{redirect:D}=F;let q=typeof D=="function"?D(C):D;return typeof q=="string"&&(q=q.includes("?")||q.includes("#")?q=b(q):{path:q},q.params={}),de({query:C.query,hash:C.hash,params:"path"in q?{}:C.params},q)}}function Y(C,F){const D=c=m(C),q=i.value,ce=C.state,h=C.force,v=C.replace===!0,y=R(D);if(y)return Y(de(b(y),{state:typeof y=="object"?de({},ce,y.state):ce,force:h,replace:v}),F||D);const T=D;T.redirectedFrom=F;let A;return!h&&Kp(r,q,D)&&(A=yn(16,{to:T,from:q}),rt(q,q,!0,!1)),(A?Promise.resolve(A):G(T,q)).catch(k=>it(k)?it(k,2)?k:Tt(k):ie(k,T,q)).then(k=>{if(k){if(it(k,2))return Y(de({replace:v},b(k.to),{state:typeof k.to=="object"?de({},ce,k.to.state):ce,force:h}),F||T)}else k=H(T,q,!0,v,ce);return re(T,q,k),k})}function P(C,F){const D=S(C,F);return D?Promise.reject(D):Promise.resolve()}function V(C){const F=Xt.values().next().value;return F&&typeof F.runWithContext=="function"?F.runWithContext(C):C()}function G(C,F){let D;const[q,ce,h]=zh(C,F);D=lo(q.reverse(),"beforeRouteLeave",C,F);for(const y of q)y.leaveGuards.forEach(T=>{D.push(Rt(T,C,F))});const v=P.bind(null,C,F);return D.push(v),Re(D).then(()=>{D=[];for(const y of l.list())D.push(Rt(y,C,F));return D.push(v),Re(D)}).then(()=>{D=lo(ce,"beforeRouteUpdate",C,F);for(const y of ce)y.updateGuards.forEach(T=>{D.push(Rt(T,C,F))});return D.push(v),Re(D)}).then(()=>{D=[];for(const y of C.matched)if(y.beforeEnter&&!F.matched.includes(y))if(tt(y.beforeEnter))for(const T of y.beforeEnter)D.push(Rt(T,C,F));else D.push(Rt(y.beforeEnter,C,F));return D.push(v),Re(D)}).then(()=>(C.matched.forEach(y=>y.enterCallbacks={}),D=lo(h,"beforeRouteEnter",C,F),D.push(v),Re(D))).then(()=>{D=[];for(const y of s.list())D.push(Rt(y,C,F));return D.push(v),Re(D)}).catch(y=>it(y,8)?y:Promise.reject(y))}function re(C,F,D){for(const q of a.list())V(()=>q(C,F,D))}function H(C,F,D,q,ce){const h=S(C,F);if(h)return h;const v=F===dt,y=nn?history.state:{};D&&(q||v?o.replace(C.fullPath,de({scroll:v&&y&&y.scroll},ce)):o.push(C.fullPath,ce)),i.value=C,rt(C,F,D,v),Tt()}let Z;function U(){Z||(Z=o.listen((C,F,D)=>{if(!sr.listening)return;const q=m(C),ce=R(q);if(ce){Y(de(ce,{replace:!0}),q).catch(Bn);return}c=q;const h=i.value;nn&&th(As(h.fullPath,D.delta),zr()),G(q,h).catch(v=>it(v,12)?v:it(v,2)?(Y(v.to,q).then(y=>{it(y,20)&&!D.delta&&D.type===Qn.pop&&o.go(-1,!1)}).catch(Bn),Promise.reject()):(D.delta&&o.go(-D.delta,!1),ie(v,q,h))).then(v=>{v=v||H(q,h,!1),v&&(D.delta&&!it(v,8)?o.go(-D.delta,!1):D.type===Qn.pop&&it(v,20)&&o.go(-1,!1)),re(q,h,v)}).catch(Bn)}))}let Le=On(),ae=On(),ve;function ie(C,F,D){Tt(C);const q=ae.list();return q.length?q.forEach(ce=>ce(C,F,D)):console.error(C),Promise.reject(C)}function at(){return ve&&i.value!==dt?Promise.resolve():new Promise((C,F)=>{Le.add([C,F])})}function Tt(C){return ve||(ve=!C,U(),Le.list().forEach(([F,D])=>C?D(C):F()),Le.reset()),C}function rt(C,F,D,q){const{scrollBehavior:ce}=e;if(!nn||!ce)return Promise.resolve();const h=!D&&nh(As(C.fullPath,0))||(q||!D)&&history.state&&history.state.scroll||null;return Qt().then(()=>ce(C,F,h)).then(v=>v&&eh(v)).catch(v=>ie(v,C,F))}const $e=C=>o.go(C);let Jt;const Xt=new Set,sr={currentRoute:i,listening:!0,addRoute:g,removeRoute:_,hasRoute:E,getRoutes:w,resolve:m,options:e,push:O,replace:z,go:$e,back:()=>$e(-1),forward:()=>$e(1),beforeEach:l.add,beforeResolve:s.add,afterEach:a.add,onError:ae.add,isReady:at,install(C){const F=this;C.component("RouterLink",mt),C.component("RouterView",Ni),C.config.globalProperties.$router=F,Object.defineProperty(C.config.globalProperties,"$route",{enumerable:!0,get:()=>qt(i)}),nn&&!Jt&&i.value===dt&&(Jt=!0,O(o.location).catch(ce=>{}));const D={};for(const ce in dt)D[ce]=x(()=>i.value[ce]);C.provide(Ur,F),C.provide(ml,Tn(D)),C.provide(Po,i);const q=C.unmount;Xt.add(C),C.unmount=function(){Xt.delete(C),Xt.size<1&&(c=dt,Z&&Z(),Z=null,i.value=dt,Jt=!1,ve=!1),q()}}};function Re(C){return C.reduce((F,D)=>F.then(()=>V(D)),Promise.resolve())}return sr}function zh(e,t){const n=[],r=[],o=[],l=Math.max(t.matched.length,e.matched.length);for(let s=0;sgn(c,a))?r.push(a):n.push(a));const i=e.matched[s];i&&(t.matched.find(c=>gn(c,i))||o.push(i))}return[n,r,o]}function wt(){return _e(Ur)}function Et(){return _e(ml)}const Uh=({headerLinkSelector:e,headerAnchorSelector:t,delay:n,offset:r=5})=>{const o=wt(),s=jp(()=>{var w,E;const a=Math.max(window.scrollY,document.documentElement.scrollTop,document.body.scrollTop);if(Math.abs(a-0)p.some(b=>b.hash===m.hash));for(let m=0;m<_.length;m++){const b=_[m],S=_[m+1],O=a>=(((w=b.parentElement)==null?void 0:w.offsetTop)??0)-r,z=!S||a<(((E=S.parentElement)==null?void 0:E.offsetTop)??0)-r;if(!(O&&z))continue;const Y=decodeURIComponent(o.currentRoute.value.hash),P=decodeURIComponent(b.hash);if(Y===P)return;if(d){for(let V=m+1;V<_.length;V++)if(Y===decodeURIComponent(_[V].hash))return}Hs(o,P);return}},n);Ee(()=>{window.addEventListener("scroll",s)}),el(()=>{window.removeEventListener("scroll",s)})},Hs=async(e,t)=>{const{scrollBehavior:n}=e.options;e.options.scrollBehavior=void 0,await e.replace({query:e.currentRoute.value.query,hash:t,force:!0}).finally(()=>e.options.scrollBehavior=n)},qh=".sidebar-link, .toc-link",Wh=".header-anchor",Kh=200,Yh=5,Gh=nt({setup(){Uh({headerLinkSelector:qh,headerAnchorSelector:Wh,delay:Kh,offset:Yh})}});let Fi=()=>null;const Hi=Symbol(""),Qh=e=>{Fi=e},Jh=()=>_e(Hi),Xh=e=>{e.provide(Hi,Fi)};var Zh=j({name:"AutoCatalog",props:{base:{type:String,default:""},level:{type:Number,default:3},index:Boolean},setup(e){const t=Jh(),n=Nt({"/":{title:"Catalog"}}),r=he(),o=wt(),l=ei(),s=c=>{const f=c.I;return typeof f>"u"||f},a=()=>{const c=e.base||r.value.path.replace(/\/[^/]+$/,"/"),f=o.getRoutes(),d=[];return f.filter(({meta:p,path:g})=>{if(!Gn(g,c)||g===c)return!1;if(c==="/"){const _=nr(l.value.locales).filter(w=>w!=="/");if(g==="/404.html"||_.some(w=>Gn(g,w)))return!1}return(tn(g,".html")&&!tn(g,"/index.html")||tn(g,"/"))&&s(p)}).map(({path:p,meta:g})=>{const _=p.substring(c.length).split("/").length;return{title:g.t||"",icon:g.i,base:p.replace(/\/[^/]+\/?$/,"/"),order:g.O||null,level:tn(p,"/")?_-1:_,path:p}}).filter(({title:p,level:g})=>typeof p=="string"&&p&&g<=e.level).sort(({title:p,level:g,path:_,order:w},{title:E,level:m,path:b,order:S})=>g-m||(tn(_,"/index.html")?-1:tn(b,"/index.html")?1:w===null?S===null?p.localeCompare(E):S:S===null?w:w>0?S>0?w-S:-1:S<0?w-S:1)).forEach(p=>{var g;const{base:_,level:w}=p;switch(w){case 1:d.push(p);break;case 2:{const E=d.find(m=>m.path===_);E&&(E.children??(E.children=[])).push(p);break}default:{const E=d.find(m=>m.path===_.replace(/\/[^/]+\/$/,"/"));if(E){const m=(g=E.children)==null?void 0:g.find(b=>b.path===_);m&&(m.children??(m.children=[])).push(p)}}}}),d},i=x(()=>a());return()=>u("div",{class:"auto-catalog-wrapper"},[u("h2",{class:"main-title"},n.value.title),i.value.map(({children:c=[],icon:f,path:d,title:p},g)=>[u("h3",{id:p,class:["child-title",{"has-children":c.length}]},[u("a",{href:`#${p}`,class:"header-anchor"},"#"),u(mt,{class:"catalog-title",to:d},()=>[e.index?`${g+1}.`:null,f&&t?u(t,{icon:f}):null,p||"Unknown"])]),c.length?u("ul",{class:"child-catalog-wrapper"},c.map(({children:_=[],icon:w,path:E,title:m},b)=>u("li",{class:"child-catalog-item"},[u("div",{class:["sub-title",{"has-children":_.length}]},[u("a",{href:`#${m}`,class:"header-anchor"},"#"),u(mt,{class:"catalog-title",to:E},()=>[e.index?`${g+1}.${b+1}`:null,w&&t?u(t,{icon:w}):null,m||"Unknown"])]),_.length?u("div",{class:"sub-catalog-wrapper"},_.map(({icon:S,path:O,title:z},R)=>u(mt,{class:"sub-catalog-item",to:O},()=>[e.index?`${g+1}.${b+1}.${R+1}`:null,S&&t?u(t,{icon:S}):null,z||"Unknown"]))):null]))):null])])}}),e1=nt({enhance:({app:e})=>{Xh(e),vt("AutoCatalog",e)||e.component("AutoCatalog",Zh)}});const t1=u("svg",{class:"external-link-icon",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",focusable:"false",x:"0px",y:"0px",viewBox:"0 0 100 100",width:"15",height:"15"},[u("path",{fill:"currentColor",d:"M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"}),u("polygon",{fill:"currentColor",points:"45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"})]),Bi=j({name:"ExternalLinkIcon",props:{locales:{type:Object,required:!1,default:()=>({})}},setup(e){const t=Pn(),n=x(()=>e.locales[t.value]??{openInNewWindow:"open in new window"});return()=>u("span",[t1,u("span",{class:"external-link-icon-sr-only"},n.value.openInNewWindow)])}}),n1={},r1=nt({enhance({app:e}){e.component("ExternalLinkIcon",u(Bi,{locales:n1}))}});/** + * NProgress, (c) 2013, 2014 Rico Sta. Cruz - http://ricostacruz.com/nprogress + * @license MIT + */const le={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=le.isStarted();e=so(e,le.settings.minimum,1),le.status=e===1?null:e;const n=le.render(!t),r=n.querySelector(le.settings.barSelector),o=le.settings.speed,l=le.settings.easing;return n.offsetWidth,o1(s=>{gr(r,{transform:"translate3d("+Bs(e)+"%,0,0)",transition:"all "+o+"ms "+l}),e===1?(gr(n,{transition:"none",opacity:"1"}),n.offsetWidth,setTimeout(function(){gr(n,{transition:"all "+o+"ms linear",opacity:"0"}),setTimeout(function(){le.remove(),s()},o)},o)):setTimeout(()=>s(),o)}),le},isStarted:()=>typeof le.status=="number",start:()=>{le.status||le.set(0);const e=()=>{setTimeout(()=>{le.status&&(le.trickle(),e())},le.settings.trickleSpeed)};return le.settings.trickle&&e(),le},done:e=>!e&&!le.status?le:le.inc(.3+.5*Math.random()).set(1),inc:e=>{let t=le.status;return t?(typeof e!="number"&&(e=(1-t)*so(Math.random()*t,.1,.95)),t=so(t+e,0,.994),le.set(t)):le.start()},trickle:()=>le.inc(Math.random()*le.settings.trickleRate),render:e=>{if(le.isRendered())return document.getElementById("nprogress");Vs(document.documentElement,"nprogress-busy");const t=document.createElement("div");t.id="nprogress",t.innerHTML=le.settings.template;const n=t.querySelector(le.settings.barSelector),r=e?"-100":Bs(le.status||0),o=document.querySelector(le.settings.parent);return gr(n,{transition:"all 0 linear",transform:"translate3d("+r+"%,0,0)"}),o!==document.body&&Vs(o,"nprogress-custom-parent"),o==null||o.appendChild(t),t},remove:()=>{js(document.documentElement,"nprogress-busy"),js(document.querySelector(le.settings.parent),"nprogress-custom-parent");const e=document.getElementById("nprogress");e&&l1(e)},isRendered:()=>!!document.getElementById("nprogress")},so=(e,t,n)=>en?n:e,Bs=e=>(-1+e)*100,o1=function(){const e=[];function t(){const n=e.shift();n&&n(t)}return function(n){e.push(n),e.length===1&&t()}}(),gr=function(){const e=["Webkit","O","Moz","ms"],t={};function n(s){return s.replace(/^-ms-/,"ms-").replace(/-([\da-z])/gi,function(a,i){return i.toUpperCase()})}function r(s){const a=document.body.style;if(s in a)return s;let i=e.length;const c=s.charAt(0).toUpperCase()+s.slice(1);let f;for(;i--;)if(f=e[i]+c,f in a)return f;return s}function o(s){return s=n(s),t[s]??(t[s]=r(s))}function l(s,a,i){a=o(a),s.style[a]=i}return function(s,a){for(const i in a){const c=a[i];c!==void 0&&Object.prototype.hasOwnProperty.call(a,i)&&l(s,i,c)}}}(),Vi=(e,t)=>(typeof e=="string"?e:gl(e)).indexOf(" "+t+" ")>=0,Vs=(e,t)=>{const n=gl(e),r=n+t;Vi(n,t)||(e.className=r.substring(1))},js=(e,t)=>{const n=gl(e);if(!Vi(e,t))return;const r=n.replace(" "+t+" "," ");e.className=r.substring(1,r.length-1)},gl=e=>(" "+(e.className||"")+" ").replace(/\s+/gi," "),l1=e=>{e&&e.parentNode&&e.parentNode.removeChild(e)};const s1=()=>{Ee(()=>{const e=wt(),t=new Set;t.add(e.currentRoute.value.path),e.beforeEach(n=>{t.has(n.path)||le.start()}),e.afterEach(n=>{t.add(n.path),le.done()})})},a1=nt({setup(){s1()}}),i1=JSON.parse(`{"encrypt":{},"logo":"/favicon.ico","repo":"hydro-dev/Hydro","pageInfo":false,"docsRepo":"hydro-dev/hydro-dev.github.io","docsBranch":"docs","editLink":true,"locales":{"/":{"lang":"en-US","navbarLocales":{"langName":"English","selectLangAriaLabel":"Select language"},"metaLocales":{"author":"Author","date":"Writing Date","origin":"Original","views":"Page views","category":"Category","tag":"Tag","readingTime":"Reading Time","words":"Words","toc":"On This Page","prev":"Prev","next":"Next","lastUpdated":"Last update","contributors":"Contributors","editLink":"Edit this page","print":"Print"},"outlookLocales":{"themeColor":"Theme Color","darkmode":"Theme Mode","fullscreen":"Full Screen"},"routeLocales":{"skipToContent":"Skip to main content","notFoundTitle":"Page not found","notFoundMsg":["There’s nothing here.","How did we get here?","That’s a Four-Oh-Four.","Looks like we've got some broken links."],"back":"Go back","home":"Take me home","openInNewWindow":"Open in new window"},"navbar":[{"text":"文档","link":"/docs/"},{"text":"常见问题解答","link":"/FAQ/"},{"text":"常用教程","link":"https://hydro.ac/d/faqs/p"},{"text":"开发","link":"/dev/"},{"text":"API","link":"/api/"},{"text":"插件","link":"/plugins/"}],"sidebar":{"/index":[{"text":"常见问题","children":["/FAQ/"]}],"/docs/":[{"text":"总览","children":["/docs/"]},{"text":"部署","children":["/docs/install/","/docs/install/s3","/docs/install/proxy","/docs/install/compiler"]},{"text":"站点管理员文档","children":["/docs/system/maintain","/docs/system/cli","/docs/system/import-user","/docs/system/cdn","/docs/system/database","/docs/system/frontend-modify","/docs/system/FAQ"]},{"text":"用户文档","children":["/docs/user/","/docs/user/domain","/docs/user/problem","/docs/user/testdata","/docs/user/problem-format","/docs/user/copy-problem"]}],"/dev/":[{"text":"开发","children":["/dev/","/dev/PERM_PRIV","/dev/typescript","/dev/hook","/dev/frontend-modify","/dev/third-party-auth"]}],"/api/":[{"text":"API","children":["/api/","/api/judge"]}],"/plugins/":[{"text":"插件","children":["/plugins/","/plugins/fps-importer","/plugins/hydrojudge","/plugins/migrate","/plugins/elastic","/plugins/recaptcha","/plugins/sonic","/plugins/vjudge","/plugins/geoip"]}]}}}}`),c1=X(i1),ji=()=>c1,zi=Symbol(""),u1=()=>{const e=_e(zi);if(!e)throw new Error("useThemeLocaleData() is called without provider.");return e},f1=(e,t)=>{const{locales:n,...r}=e;return{...r,...n==null?void 0:n[t]}},d1=nt({enhance({app:e}){const t=ji(),n=e._context.provides[il],r=x(()=>f1(t.value,n.value));e.provide(zi,r),Object.defineProperties(e.config.globalProperties,{$theme:{get(){return t.value}},$themeLocale:{get(){return r.value}}})}});const p1=800,h1=2e3,v1={"/":{copy:"Copy code",copied:"Copied",hint:"Copied successfully"}},m1=!1,g1=['.theme-hope-content div[class*="language-"] pre'],zs=!1,ao=new Map,y1=()=>{const{copy:e}=wp({legacy:!0}),t=Nt(v1),n=he(),r=di(),o=a=>{if(!a.hasAttribute("copy-code-registered")){const i=document.createElement("button");i.type="button",i.classList.add("copy-code-button"),i.innerHTML='
',i.setAttribute("aria-label",t.value.copy),i.setAttribute("data-copied",t.value.copied),a.parentElement&&a.parentElement.insertBefore(i,a),a.setAttribute("copy-code-registered","")}},l=()=>Qt().then(()=>new Promise(a=>{setTimeout(()=>{g1.forEach(i=>{document.querySelectorAll(i).forEach(o)}),a()},p1)})),s=(a,i,c)=>{let{innerText:f=""}=i;/language-(shellscript|shell|bash|sh|zsh)/.test(a.classList.toString())&&(f=f.replace(/^ *(\$|>) /gm,"")),e(f).then(()=>{c.classList.add("copied"),clearTimeout(ao.get(c));const d=setTimeout(()=>{c.classList.remove("copied"),c.blur(),ao.delete(c)},h1);ao.set(c,d)})};Ee(()=>{(!r.value||zs)&&l(),Se("click",a=>{const i=a.target;if(i.matches('div[class*="language-"] > button.copy')){const c=i.parentElement,f=i.nextElementSibling;f&&s(c,f,i)}else if(i.matches('div[class*="language-"] div.copy-icon')){const c=i.parentElement,f=c.parentElement,d=c.nextElementSibling;d&&s(f,d,c)}}),fe(()=>n.value.path,()=>{(!r.value||zs)&&l()})})};var b1=nt({setup:()=>{y1()}});const _1=nt({enhance:({app:e})=>{}});let w1={};const Ui=Symbol(""),E1=()=>_e(Ui),T1=e=>{e.provide(Ui,w1)};const C1=".theme-hope-content :not(a) > img:not([no-view])",x1={"/":{closeTitle:"Close",downloadTitle:"Download Image",fullscreenTitle:"Switch to full screen",zoomTitle:"Zoom in/out",arrowPrevTitle:"Prev (Arrow Left)",arrowNextTitle:"Next (Arrow Right)"}},A1=800,P1='
',k1=e=>ue(e)?Array.from(document.querySelectorAll(e)):e.map(t=>Array.from(document.querySelectorAll(t))).flat(),qi=e=>new Promise((t,n)=>{e.complete?t({type:"image",element:e,src:e.src,width:e.naturalWidth,height:e.naturalHeight,alt:e.alt,msrc:e.src}):(e.onload=()=>t(qi(e)),e.onerror=r=>n(r))}),L1=()=>{const{isSupported:e,toggle:t}=pl(),n=E1(),r=Nt(x1),o=he();let l;const s=i=>{i.on("uiRegister",()=>{e&&i.ui.registerElement({name:"fullscreen",order:7,isButton:!0,html:'',onClick:()=>{t()}}),i.ui.registerElement({name:"download",order:8,isButton:!0,tagName:"a",html:{isCustomSVG:!0,inner:'',outlineID:"pswp__icn-download"},onInit:(c,f)=>{c.setAttribute("download",""),c.setAttribute("target","_blank"),c.setAttribute("rel","noopener"),f.on("change",()=>{c.setAttribute("href",f.currSlide.data.src)})}}),i.ui.registerElement({name:"bulletsIndicator",className:"photo-swipe-bullets-indicator",appendTo:"wrapper",onInit:(c,f)=>{const d=[];let p=-1;for(let g=0;g{f.goTo(d.indexOf(w.target))},d.push(_),c.appendChild(_)}f.on("change",()=>{p>=0&&d[p].classList.remove("active"),d[f.currIndex].classList.add("active"),p=f.currIndex})}})})},a=()=>Promise.all([$(()=>import("./photoswipe.esm-2450701e.js"),[]),Qt().then(()=>new Promise(i=>setTimeout(i,A1)).then(()=>k1(C1)))]).then(([{default:i},c])=>{const f=c.map(d=>({html:P1,element:d,msrc:d.src}));c.forEach((d,p)=>{const g=()=>{l=new i({preloaderDelay:0,showHideAnimationType:"zoom",...r.value,...n,dataSource:f,index:p,closeOnVerticalDrag:!0,wheelToZoom:!1}),s(l),l.addFilter("thumbEl",()=>d),l.addFilter("placeholderSrc",()=>d.src),l.init()};d.style.cursor="zoom-in",d.addEventListener("click",()=>{g()}),d.addEventListener("keypress",({key:_})=>{_==="Enter"&&g()})}),c.forEach((d,p)=>{qi(d).then(g=>{f.splice(p,1,g),l==null||l.refreshSlideContent(p)})})});Ee(()=>{Se("wheel",()=>{l==null||l.close()}),a(),fe(()=>o.value.path,()=>a())})};var R1=nt({enhance:({app:e})=>{T1(e)},setup:()=>{L1()}});const Wi=()=>{const e=he();return x(()=>e.value.readingTime??null)},Lo=typeof{"/":{word:"About $word words",less1Minute:"Less than 1 minute",time:"About $time min"}}>"u"?null:{"/":{word:"About $word words",less1Minute:"Less than 1 minute",time:"About $time min"}},O1=(e,t)=>{const{minutes:n,words:r}=e,{less1Minute:o,word:l,time:s}=t;return{time:n<1?o:s.replace("$time",Math.round(n).toString()),words:l.replace("$word",r.toString())}},Us={words:"",time:""},S1=()=>Lo?Nt(Lo):x(()=>null),I1=()=>{if(typeof Lo>"u")return x(()=>Us);const e=Wi(),t=S1();return x(()=>e.value&&t.value?O1(e.value,t.value):Us)},or=()=>ji(),ge=()=>u1(),qr=()=>x(()=>!!or().value.pure);var io=j({name:"EmptyComponent",setup:()=>()=>null});const $1="719px",M1="1440px",D1="false",yl={mobileBreakPoint:$1,pcBreakPoint:M1,enableThemeColor:D1},bl={},Ki=e=>{const{icon:t="",color:n,size:r}=e,o={};return n&&(o.color=n),r&&(o.height=Number.isNaN(Number(r))?r:`${r}px`),An(t)?u("img",{class:"icon",src:t,"no-view":"",style:o}):cl(t)?u("img",{class:"icon",src:Yt(t),"no-view":"",style:o}):u(et("FontIcon"),e)};Ki.displayName="HopeIcon";var Ye=Ki,ht=(e=>(e.type="y",e.title="t",e.shortTitle="s",e.icon="i",e.author="a",e.date="d",e.localizedDate="l",e.category="c",e.tag="g",e.isEncrypted="n",e.isOriginal="o",e.readingTime="r",e.excerpt="e",e.sticky="u",e.cover="v",e.index="I",e.order="O",e))(ht||{}),N1=(e=>(e.article="a",e.home="h",e.slide="s",e.page="p",e))(N1||{});const un=(e,t=!1)=>{const n=wt(),{fullPath:r,meta:o,name:l}=fl(n,encodeURI(e));return{text:!t&&o[ht.shortTitle]?o[ht.shortTitle]:o[ht.title]||e,link:l==="404"?e:r,...o[ht.icon]?{icon:o[ht.icon]}:{}}},F1=()=>{const e=wt(),t=Et();return n=>{if(n)if(cl(n))t.path!==n&&e.push(n);else if(An(n)||qa(n))window&&window.open(n);else{const r=t.path.slice(0,t.path.lastIndexOf("/"));e.push(`${r}/${encodeURI(n)}`)}}},Yi=()=>{const e=ge(),t=ke();return x(()=>{const{author:n}=t.value;return n?ds(n):n===!1?[]:ds(e.value.author,!1)})},H1=()=>{const e=ke();return x(()=>Gd(e.value.category).map(t=>({name:t,path:""})))},B1=()=>{const e=ke();return x(()=>Qd(e.value.tag).map(t=>({name:t,path:""})))},V1=()=>{const e=ke(),t=he();return x(()=>{const n=Kd(e.value.date);if(n)return n;const{createdTime:r}=t.value.git||{};return r?new Date(r):null})},j1=()=>{const e=ge(),t=he(),n=ke(),r=Yi(),o=H1(),l=B1(),s=V1(),a=Wi(),i=I1(),c=x(()=>({author:r.value,category:o.value,date:s.value,localizedDate:t.value.localizedDate,tag:l.value,isOriginal:n.value.isOriginal||!1,readingTime:a.value,readingTimeLocale:i.value,pageview:"pageview"in n.value?n.value.pageview:!0})),f=x(()=>"pageInfo"in n.value?n.value.pageInfo:"pageInfo"in e.value?e.value.pageInfo:null);return{info:c,items:f}},{mobileBreakPoint:z1,pcBreakPoint:U1}=yl,qs=e=>e.endsWith("px")?Number(e.slice(0,-2)):null,Wr=()=>{const e=X(!1),t=X(!1),n=()=>{e.value=window.innerWidth<=(qs(z1)??719),t.value=window.innerWidth>=(qs(U1)??1440)};return Ee(()=>{n(),Se("resize",n,!1),Se("orientationchange",n,!1)}),{isMobile:e,isPC:t}},Gi=Symbol(""),lr=()=>{const e=_e(Gi);if(!e)throw new Error("useDarkmode() is called without provider.");return e},q1=e=>{const t=or(),n=Rp(),r=Ci("vuepress-theme-hope-scheme","auto"),o=x(()=>t.value.darkmode||"switch"),l=x(()=>{const a=o.value;return a==="disable"?!1:a==="enable"?!0:a==="auto"?n.value:a==="toggle"?r.value==="dark":r.value==="dark"||r.value==="auto"&&n.value}),s=x(()=>{const a=o.value;return a==="switch"||a==="toggle"});e.provide(Gi,{canToggle:s,config:o,isDarkmode:l,status:r}),Object.defineProperties(e.config.globalProperties,{$isDarkmode:{get:()=>l.value}})},W1=()=>{const{isDarkmode:e}=lr(),t=(n=e.value)=>document.documentElement.setAttribute("data-theme",n?"dark":"light");Ee(()=>{fe(e,t,{immediate:!0})})};var De=j({name:"AutoLink",inheritAttrs:!1,props:{config:{type:Object,required:!0},exact:Boolean,noExternalLinkIcon:Boolean},emits:["focusout"],slots:Object,setup(e,{attrs:t,emit:n,slots:r}){const o=Et(),l=ei(),s=Mr(e,"config"),a=x(()=>An(s.value.link)),i=x(()=>qa(s.value.link)||kd(s.value.link)),c=x(()=>i.value?void 0:s.value.target||(a.value?"_blank":void 0)),f=x(()=>c.value==="_blank"),d=x(()=>!a.value&&!i.value&&!f.value),p=x(()=>i.value?void 0:s.value.rel||(f.value?"noopener noreferrer":void 0)),g=x(()=>s.value.ariaLabel||s.value.text),_=x(()=>{if(e.exact)return!1;const E=nr(l.value.locales);return E.length?E.every(m=>m!==s.value.link):s.value.link!=="/"}),w=x(()=>d.value?s.value.activeMatch?new RegExp(s.value.activeMatch).test(o.path):_.value?Gn(o.path,s.value.link):o.path===s.value.link:!1);return()=>{const{before:E,after:m,default:b}=r,{text:S,icon:O,link:z}=s.value;return d.value?u(mt,{to:z,"aria-label":g.value,...t,class:["nav-link",{active:w.value},t.class],onFocusout:()=>n("focusout")},()=>b?b():[E?E():u(Ye,{icon:O}),S,m==null?void 0:m()]):u("a",{href:z,rel:p.value,target:c.value,"aria-label":g.value,...t,class:["nav-link",t.class],onFocusout:()=>n("focusout")},b?b():[E?E():u(Ye,{icon:O}),S,e.noExternalLinkIcon?null:u(Bi),m==null?void 0:m()])}}});const bn=(e,t,n=!1)=>"activeMatch"in t?new RegExp(t.activeMatch).test(e.path):ul(e,t.link)?!0:t.children&&!n?t.children.some(r=>bn(e,r)):!1,Qi=(e,t)=>t.type==="group"?t.children.some(n=>n.type==="group"?Qi(e,n):n.type==="page"&&bn(e,n,!0))||"prefix"in t&&ul(e,t.prefix):!1,Ji=(e,t)=>ue(e.link)?u(De,{...t,config:e}):u("p",t,[u(Ye,{icon:e.icon}),e.text]),Xi=e=>{const t=Et();return e?u("ul",{class:"sidebar-sub-headers"},e.map(n=>{const r=bn(t,n,!0);return u("li",{class:"sidebar-sub-header"},[Ji(n,{class:["sidebar-link","heading",{active:r}]}),Xi(n.children)])})):null},co=(e="",t="")=>cl(t)?t:`${xd(e)}${t}`,K1=(e,t)=>{const n=he();return{type:"heading",text:e.title,link:`${n.value.path}#${e.slug}`,children:_l(e.children,t)}},_l=(e,t)=>t>0?e.map(n=>K1(n,t-1)):[],Zi=e=>{const t=he();return _l(t.value.headers,e)},Ro=(e,t,n="")=>{const r=he(),o=(l,s=n)=>{var a;const i=ue(l)?un(co(s,l)):l.link?{...l,...Lr(l.link)?{}:{link:un(co(s,l.link)).link}}:l;if("children"in i){const c=co(s,i.prefix),f=i.children==="structure"?bl[c]:i.children;return{type:"group",...i,prefix:c,children:f.map(d=>o(d,c))}}return{type:"page",...i,children:i.link===r.value.path?_l(((a=r.value.headers[0])==null?void 0:a.level)===1?r.value.headers[0].children:r.value.headers,t):[]}};return e.map(l=>o(l))},Y1=(e,t)=>{const n=he(),r=nr(e).sort((o,l)=>l.length-o.length);for(const o of r)if(Gn(decodeURI(n.value.path),o)){const l=e[o];return l?Ro(l==="structure"?bl[o]:l==="heading"?Zi(t):l,t,o):[]}return console.warn(`${n.value.path} is missing sidebar config.`),[]},G1=()=>{const e=Pn(),t=ke(),n=ge(),r=t.value.home?!1:t.value.sidebar??n.value.sidebar??"structure",o=t.value.headerDepth??n.value.headerDepth??2;return r===!1?[]:r==="heading"?Zi(o):r==="structure"?Ro(bl[e.value],o,e.value):Q(r)?Ro(r,o):sl(r)?Y1(r,o):[]},ec=Symbol(""),Q1=()=>{const e=x(()=>G1());Wt(ec,e)},wl=()=>{const e=_e(ec);if(!e)throw new Error("useSidebarItems() is called without provider.");return e};var J1=j({name:"PageFooter",setup(){const e=ke(),t=ge(),n=Yi(),r=x(()=>{const{copyright:s,footer:a}=e.value;return a!==!1&&!!(s||a||t.value.displayFooter)}),o=x(()=>{const{footer:s}=e.value;return s===!1?!1:ue(s)?s:t.value.footer||""}),l=x(()=>"copyright"in e.value?e.value.copyright:"copyright"in t.value?t.value.copyright:n.value.length?`Copyright © ${new Date().getFullYear()} ${n.value[0].name}`:!1);return()=>r.value?u("footer",{class:"footer-wrapper"},[o.value?u("div",{class:"footer",innerHTML:o.value}):null,l.value?u("div",{class:"copyright",innerHTML:l.value}):null]):null}}),X1=j({name:"NavbarDropdownLink",props:{config:{type:Object,required:!0}},slots:Object,setup(e,{slots:t}){const n=he(),r=Mr(e,"config"),o=x(()=>r.value.ariaLabel||r.value.text),l=X(!1);fe(()=>n.value.path,()=>{l.value=!1});const s=a=>{a.detail===0&&(l.value=!l.value)};return()=>{var a;return u("div",{class:["dropdown-wrapper",{open:l.value}]},[u("button",{type:"button",class:"dropdown-title","aria-label":o.value,onClick:s},[((a=t.title)==null?void 0:a.call(t))||u("span",{class:"title"},[u(Ye,{icon:r.value.icon}),e.config.text]),u("span",{class:"arrow"}),u("ul",{class:"nav-dropdown"},r.value.children.map((i,c)=>{const f=c===r.value.children.length-1;return u("li",{class:"dropdown-item"},"children"in i?[u("h4",{class:"dropdown-subtitle"},i.link?u(De,{config:i,onFocusout:()=>{i.children.length===0&&f&&(l.value=!1)}}):u("span",i.text)),u("ul",{class:"dropdown-subitem-wrapper"},i.children.map((d,p)=>u("li",{class:"dropdown-subitem"},u(De,{config:d,onFocusout:()=>{p===i.children.length-1&&f&&(l.value=!1)}}))))]:u(De,{config:i,onFocusout:()=>{f&&(l.value=!1)}}))}))])])}}});const tc=(e,t="")=>ue(e)?un(`${t}${e}`):"children"in e?{...e,...e.link&&!Lr(e.link)?un(`${t}${e.link}`):{},children:e.children.map(n=>tc(n,`${t}${e.prefix||""}`))}:{...e,link:Lr(e.link)?e.link:un(`${t}${e.link}`).link},nc=()=>x(()=>(ge().value.navbar||[]).map(e=>tc(e))),Z1=()=>{const e=ge(),t=x(()=>e.value.repo||null),n=x(()=>t.value?Xd(t.value):null),r=x(()=>t.value?gi(t.value):null),o=x(()=>n.value?e.value.repoLabel??(r.value===null?"Source":r.value):null);return x(()=>!n.value||!o.value||e.value.repoDisplay===!1?null:{type:r.value||"Source",label:o.value,link:n.value})};var e0=j({name:"NavScreenDropdown",props:{config:{type:Object,required:!0}},setup(e){const t=he(),n=Mr(e,"config"),r=x(()=>n.value.ariaLabel||n.value.text),o=X(!1);fe(()=>t.value.path,()=>{o.value=!1});const l=(s,a)=>a[a.length-1]===s;return()=>[u("button",{type:"button",class:["nav-screen-dropdown-title",{active:o.value}],"aria-label":r.value,onClick:()=>{o.value=!o.value}},[u("span",{class:"title"},[u(Ye,{icon:n.value.icon}),e.config.text]),u("span",{class:["arrow",o.value?"down":"end"]})]),u("ul",{class:["nav-screen-dropdown",{hide:!o.value}]},n.value.children.map(s=>u("li",{class:"dropdown-item"},"children"in s?[u("h4",{class:"dropdown-subtitle"},s.link?u(De,{config:s,onFocusout:()=>{l(s,n.value.children)&&s.children.length===0&&(o.value=!1)}}):u("span",s.text)),u("ul",{class:"dropdown-subitem-wrapper"},s.children.map(a=>u("li",{class:"dropdown-subitem"},u(De,{config:a,onFocusout:()=>{l(a,s.children)&&l(s,n.value.children)&&(o.value=!1)}}))))]:u(De,{config:s,onFocusout:()=>{l(s,n.value.children)&&(o.value=!1)}}))))]}}),t0=j({name:"NavScreenLinks",setup(){const e=nc();return()=>e.value.length?u("nav",{class:"nav-screen-links"},e.value.map(t=>u("div",{class:"navbar-links-item"},"children"in t?u(e0,{config:t}):u(De,{config:t})))):null}});const rc=()=>u(me,{name:"dark"},()=>u("path",{d:"M524.8 938.667h-4.267a439.893 439.893 0 0 1-313.173-134.4 446.293 446.293 0 0 1-11.093-597.334A432.213 432.213 0 0 1 366.933 90.027a42.667 42.667 0 0 1 45.227 9.386 42.667 42.667 0 0 1 10.24 42.667 358.4 358.4 0 0 0 82.773 375.893 361.387 361.387 0 0 0 376.747 82.774 42.667 42.667 0 0 1 54.187 55.04 433.493 433.493 0 0 1-99.84 154.88 438.613 438.613 0 0 1-311.467 128z"}));rc.displayName="DarkIcon";const oc=()=>u(me,{name:"light"},()=>u("path",{d:"M952 552h-80a40 40 0 0 1 0-80h80a40 40 0 0 1 0 80zM801.88 280.08a41 41 0 0 1-57.96-57.96l57.96-58a41.04 41.04 0 0 1 58 58l-58 57.96zM512 752a240 240 0 1 1 0-480 240 240 0 0 1 0 480zm0-560a40 40 0 0 1-40-40V72a40 40 0 0 1 80 0v80a40 40 0 0 1-40 40zm-289.88 88.08-58-57.96a41.04 41.04 0 0 1 58-58l57.96 58a41 41 0 0 1-57.96 57.96zM192 512a40 40 0 0 1-40 40H72a40 40 0 0 1 0-80h80a40 40 0 0 1 40 40zm30.12 231.92a41 41 0 0 1 57.96 57.96l-57.96 58a41.04 41.04 0 0 1-58-58l58-57.96zM512 832a40 40 0 0 1 40 40v80a40 40 0 0 1-80 0v-80a40 40 0 0 1 40-40zm289.88-88.08 58 57.96a41.04 41.04 0 0 1-58 58l-57.96-58a41 41 0 0 1 57.96-57.96z"}));oc.displayName="LightIcon";const lc=()=>u(me,{name:"auto"},()=>u("path",{d:"M512 992C246.92 992 32 777.08 32 512S246.92 32 512 32s480 214.92 480 480-214.92 480-480 480zm0-840c-198.78 0-360 161.22-360 360 0 198.84 161.22 360 360 360s360-161.16 360-360c0-198.78-161.22-360-360-360zm0 660V212c165.72 0 300 134.34 300 300 0 165.72-134.28 300-300 300z"}));lc.displayName="AutoIcon";const sc=()=>u(me,{name:"enter-fullscreen"},()=>u("path",{d:"M762.773 90.24h-497.28c-96.106 0-174.4 78.293-174.4 174.4v497.28c0 96.107 78.294 174.4 174.4 174.4h497.28c96.107 0 175.04-78.293 174.4-174.4V264.64c0-96.213-78.186-174.4-174.4-174.4zm-387.2 761.173H215.04c-21.867 0-40.427-17.92-41.067-41.066V649.92c0-22.507 17.92-40.427 40.427-40.427 11.307 0 21.227 4.694 28.48 11.947 7.253 7.253 11.947 17.92 11.947 28.48v62.293l145.28-145.28c15.893-15.893 41.813-15.893 57.706 0 15.894 15.894 15.894 41.814 0 57.707l-145.28 145.28h62.294c22.506 0 40.426 17.92 40.426 40.427s-17.173 41.066-39.68 41.066zM650.24 165.76h160.427c21.866 0 40.426 17.92 41.066 41.067v160.426c0 22.507-17.92 40.427-40.426 40.427-11.307 0-21.227-4.693-28.48-11.947-7.254-7.253-11.947-17.92-11.947-28.48v-62.186L625.6 450.347c-15.893 15.893-41.813 15.893-57.707 0-15.893-15.894-15.893-41.814 0-57.707l145.28-145.28H650.88c-22.507 0-40.427-17.92-40.427-40.427s17.174-41.173 39.787-41.173z"}));sc.displayName="EnterFullScreenIcon";const ac=()=>u(me,{name:"cancel-fullscreen"},()=>u("path",{d:"M778.468 78.62H247.922c-102.514 0-186.027 83.513-186.027 186.027V795.08c0 102.514 83.513 186.027 186.027 186.027h530.432c102.514 0 186.71-83.513 186.026-186.027V264.647C964.494 162.02 880.981 78.62 778.468 78.62zM250.88 574.35h171.122c23.324 0 43.122 19.115 43.804 43.805v171.121c0 24.008-19.114 43.122-43.122 43.122-12.06 0-22.641-5.006-30.378-12.743s-12.743-19.115-12.743-30.379V722.83L224.597 877.91c-16.953 16.952-44.6 16.952-61.553 0-16.953-16.954-16.953-44.602 0-61.554L318.009 661.39h-66.446c-24.007 0-43.122-19.114-43.122-43.122 0-24.12 18.432-43.918 42.439-43.918zm521.899-98.873H601.657c-23.325 0-43.122-19.114-43.805-43.804V260.55c0-24.007 19.115-43.122 43.122-43.122 12.06 0 22.642 5.007 30.379 12.743s12.743 19.115 12.743 30.38v66.445l154.965-154.965c16.953-16.953 44.601-16.953 61.554 0 16.953 16.953 16.953 44.6 0 61.554L705.536 388.55h66.446c24.007 0 43.122 19.115 43.122 43.122.114 24.007-18.318 43.804-42.325 43.804z"}));ac.displayName="CancelFullScreenIcon";const ic=()=>u(me,{name:"outlook"},()=>[u("path",{d:"M224 800c0 9.6 3.2 44.8 6.4 54.4 6.4 48-48 76.8-48 76.8s80 41.6 147.2 0 134.4-134.4 38.4-195.2c-22.4-12.8-41.6-19.2-57.6-19.2C259.2 716.8 227.2 761.6 224 800zM560 675.2l-32 51.2c-51.2 51.2-83.2 32-83.2 32 25.6 67.2 0 112-12.8 128 25.6 6.4 51.2 9.6 80 9.6 54.4 0 102.4-9.6 150.4-32l0 0c3.2 0 3.2-3.2 3.2-3.2 22.4-16 12.8-35.2 6.4-44.8-9.6-12.8-12.8-25.6-12.8-41.6 0-54.4 60.8-99.2 137.6-99.2 6.4 0 12.8 0 22.4 0 12.8 0 38.4 9.6 48-25.6 0-3.2 0-3.2 3.2-6.4 0-3.2 3.2-6.4 3.2-6.4 6.4-16 6.4-16 6.4-19.2 9.6-35.2 16-73.6 16-115.2 0-105.6-41.6-198.4-108.8-268.8C704 396.8 560 675.2 560 675.2zM224 419.2c0-28.8 22.4-51.2 51.2-51.2 28.8 0 51.2 22.4 51.2 51.2 0 28.8-22.4 51.2-51.2 51.2C246.4 470.4 224 448 224 419.2zM320 284.8c0-22.4 19.2-41.6 41.6-41.6 22.4 0 41.6 19.2 41.6 41.6 0 22.4-19.2 41.6-41.6 41.6C339.2 326.4 320 307.2 320 284.8zM457.6 208c0-12.8 12.8-25.6 25.6-25.6 12.8 0 25.6 12.8 25.6 25.6 0 12.8-12.8 25.6-25.6 25.6C470.4 233.6 457.6 220.8 457.6 208zM128 505.6C128 592 153.6 672 201.6 736c28.8-60.8 112-60.8 124.8-60.8-16-51.2 16-99.2 16-99.2l316.8-422.4c-48-19.2-99.2-32-150.4-32C297.6 118.4 128 291.2 128 505.6zM764.8 86.4c-22.4 19.2-390.4 518.4-390.4 518.4-22.4 28.8-12.8 76.8 22.4 99.2l9.6 6.4c35.2 22.4 80 12.8 99.2-25.6 0 0 6.4-12.8 9.6-19.2 54.4-105.6 275.2-524.8 288-553.6 6.4-19.2-3.2-32-19.2-32C777.6 76.8 771.2 80 764.8 86.4z"})]);ic.displayName="OutlookIcon";var cc=j({name:"AppearanceSwitch",setup(){const{config:e,status:t}=lr(),n=()=>{e.value==="switch"?t.value={light:"dark",dark:"auto",auto:"light"}[t.value]:t.value=t.value==="light"?"dark":"light"};return()=>u("button",{type:"button",id:"appearance-switch",onClick:()=>n()},[u(lc,{style:{display:t.value==="auto"?"block":"none"}}),u(rc,{style:{display:t.value==="dark"?"block":"none"}}),u(oc,{style:{display:t.value==="light"?"block":"none"}})])}}),n0=j({name:"AppearanceMode",setup(){const e=ge(),{canToggle:t}=lr(),n=x(()=>e.value.outlookLocales.darkmode);return()=>t.value?u("div",{class:"appearance-wrapper"},[u("label",{class:"appearance-title",for:"appearance-switch"},n.value),u(cc)]):null}});const uo="VUEPRESS_THEME_COLOR";var r0=j({name:"ThemeColorPicker",props:{themeColor:{type:Object,required:!0}},setup(e){const t=(n="")=>{const r=document.documentElement.classList,o=nr(e.themeColor);if(!n){localStorage.removeItem(uo),r.remove(...o);return}r.remove(...o.filter(l=>l!==n)),r.add(n),localStorage.setItem(uo,n)};return Ee(()=>{const n=localStorage.getItem(uo);n&&t(n)}),()=>u("ul",{id:"theme-color-picker"},[u("li",u("span",{class:"theme-color",onClick:()=>t()})),hi(e.themeColor).map(([n,r])=>u("li",u("span",{style:{background:r},onClick:()=>t(n)})))])}});const fn=yl.enableThemeColor==="true",o0=fn?Yd(hi(yl).filter(([e])=>e.startsWith("theme-"))):{};var l0=j({name:"ThemeColor",setup(){const e=ge(),t=x(()=>e.value.outlookLocales.themeColor);return()=>fn?u("div",{class:"theme-color-wrapper"},[u("label",{class:"theme-color-title",for:"theme-color-picker"},t.value),u(r0,{themeColor:o0})]):null}}),uc=j({name:"ToggleFullScreenButton",setup(){const e=ge(),{isSupported:t,isFullscreen:n,toggle:r}=pl(),o=x(()=>e.value.outlookLocales.fullscreen);return()=>t?u("div",{class:"full-screen-wrapper"},[u("label",{class:"full-screen-title",for:"full-screen-switch"},o.value),u("button",{type:"button",class:"full-screen",id:"full-screen-switch",ariaPressed:n.value,onClick:()=>r()},n.value?u(ac):u(sc))]):null}}),fc=j({name:"OutlookSettings",setup(){const e=or(),t=qr(),n=x(()=>!t.value&&e.value.fullscreen);return()=>u(Vr,()=>[fn?u(l0):null,u(n0),n.value?u(uc):null])}}),s0=j({name:"NavScreen",props:{show:Boolean},emits:["close"],slots:Object,setup(e,{emit:t,slots:n}){const r=he(),{isMobile:o}=Wr(),l=bt(),s=hl(l);return Ee(()=>{l.value=document.body,fe(o,a=>{!a&&e.show&&(s.value=!1,t("close"))}),fe(()=>r.value.path,()=>{s.value=!1,t("close")})}),tr(()=>{s.value=!1}),()=>u(Dt,{name:"fade",onEnter:()=>{s.value=!0},onAfterLeave:()=>{s.value=!1}},()=>{var a,i;return e.show?u("div",{id:"nav-screen"},u("div",{class:"container"},[(a=n.before)==null?void 0:a.call(n),u(t0),u("div",{class:"outlook-wrapper"},u(fc)),(i=n.after)==null?void 0:i.call(n)])):null})}}),a0=j({name:"NavbarBrand",setup(){const e=Pn(),t=Br(),n=ge(),r=x(()=>n.value.home||e.value),o=x(()=>t.value.title),l=x(()=>n.value.logo?Yt(n.value.logo):null),s=x(()=>n.value.logoDark?Yt(n.value.logoDark):null);return()=>u(mt,{to:r.value,class:"brand"},()=>[l.value?u("img",{class:["logo",{light:!!s.value}],src:l.value,alt:o.value}):null,s.value?u("img",{class:["logo dark"],src:s.value,alt:o.value}):null,o.value?u("span",{class:["site-name",{"hide-in-pad":l.value&&n.value.hideSiteNameOnMobile!==!1}]},o.value):null])}}),i0=j({name:"NavbarLinks",setup(){const e=nc();return()=>e.value.length?u("nav",{class:"nav-links"},e.value.map(t=>u("div",{class:"nav-item hide-in-mobile"},"children"in t?u(X1,{config:t}):u(De,{config:t})))):null}}),c0=j({name:"RepoLink",components:{BitbucketIcon:ai,GiteeIcon:si,GitHubIcon:oi,GitLabIcon:li,SourceIcon:ii},setup(){const e=Z1();return()=>e.value?u("div",{class:"nav-item"},u("a",{class:"repo-link",href:e.value.link,target:"_blank",rel:"noopener noreferrer","aria-label":e.value.label},u(et(`${e.value.type}Icon`),{style:{width:"1.25rem",height:"1.25rem",verticalAlign:"middle"}}))):null}});const dc=({active:e=!1},{emit:t})=>u("button",{type:"button",class:["toggle-navbar-button",{"is-active":e}],"aria-label":"Toggle Navbar","aria-expanded":e,"aria-controls":"nav-screen",onClick:()=>t("toggle")},u("span",{class:"button-container"},[u("span",{class:"button-top"}),u("span",{class:"button-middle"}),u("span",{class:"button-bottom"})]));dc.displayName="ToggleNavbarButton";var u0=dc;const Oo=(e,{emit:t})=>u("button",{type:"button",class:"toggle-sidebar-button",title:"Toggle Sidebar",onClick:()=>t("toggle")},u("span",{class:"icon"}));Oo.displayName="ToggleSidebarButton",Oo.emits=["toggle"];var f0=Oo,d0=j({name:"OutlookButton",setup(){const{isSupported:e}=pl(),t=or(),n=qr(),r=he(),{canToggle:o}=lr(),l=X(!1),s=x(()=>!n.value&&t.value.fullscreen&&e);return fe(()=>r.value.path,()=>{l.value=!1}),()=>o.value||s.value||fn?u("div",{class:"nav-item hide-in-mobile"},o.value&&!s.value&&!fn?u(cc):s.value&&!o.value&&!fn?u(uc):u("button",{type:"button",class:["outlook-button",{open:l.value}],tabindex:"-1","aria-hidden":!0},[u(ic),u("div",{class:"outlook-dropdown"},u(fc))])):null}}),p0=j({name:"NavBar",emits:["toggleSidebar"],slots:Object,setup(e,{emit:t,slots:n}){const r=ge(),{isMobile:o}=Wr(),l=X(!1),s=x(()=>{const{navbarAutoHide:f="mobile"}=r.value;return f!=="none"&&(f==="always"||o.value)}),a=x(()=>r.value.navbarLayout||{start:["Brand"],center:["Links"],end:["Language","Repo","Outlook","Search"]}),i={Brand:a0,Language:io,Links:i0,Repo:c0,Outlook:d0,Search:vt("Docsearch")?et("Docsearch"):vt("SearchBox")?et("SearchBox"):io},c=f=>i[f]??(vt(f)?et(f):io);return()=>{var f,d,p,g,_,w;return[u("header",{class:["navbar",{"auto-hide":s.value,"hide-icon":r.value.navbarIcon===!1}],id:"navbar"},[u("div",{class:"navbar-start"},[u(f0,{onToggle:()=>{l.value&&(l.value=!1),t("toggleSidebar")}}),(f=n.startBefore)==null?void 0:f.call(n),(a.value.start||[]).map(E=>u(c(E))),(d=n.startAfter)==null?void 0:d.call(n)]),u("div",{class:"navbar-center"},[(p=n.centerBefore)==null?void 0:p.call(n),(a.value.center||[]).map(E=>u(c(E))),(g=n.centerAfter)==null?void 0:g.call(n)]),u("div",{class:"navbar-end"},[(_=n.endBefore)==null?void 0:_.call(n),(a.value.end||[]).map(E=>u(c(E))),(w=n.endAfter)==null?void 0:w.call(n),u(u0,{active:l.value,onToggle:()=>{l.value=!l.value}})])]),u(s0,{show:l.value,onClose:()=>{l.value=!1}},{before:()=>{var E;return(E=n.screenTop)==null?void 0:E.call(n)},after:()=>{var E;return(E=n.screenBottom)==null?void 0:E.call(n)}})]}}}),h0=j({name:"SidebarChild",props:{config:{type:Object,required:!0}},setup(e){const t=Et();return()=>[Ji(e.config,{class:["sidebar-link",`sidebar-${e.config.type}`,{active:bn(t,e.config,!0)}],exact:!0}),Xi(e.config.children)]}}),v0=j({name:"SidebarGroup",props:{config:{type:Object,required:!0},open:{type:Boolean,required:!0}},emits:["toggle"],setup(e,{emit:t}){const n=Et(),r=x(()=>bn(n,e.config)),o=x(()=>bn(n,e.config,!0));return()=>{const{collapsible:l,children:s=[],icon:a,prefix:i,link:c,text:f}=e.config;return u("section",{class:"sidebar-group"},[u(l?"button":"p",{class:["sidebar-heading",{clickable:l||c,exact:o.value,active:r.value}],...l?{type:"button",onClick:()=>t("toggle"),onKeydown:d=>{d.key==="Enter"&&t("toggle")}}:{}},[u(Ye,{icon:a}),c?u(De,{class:"title",config:{text:f,link:c},noExternalLinkIcon:!0}):u("span",{class:"title"},f),l?u("span",{class:["arrow",e.open?"down":"end"]}):null]),e.open||!l?u(pc,{key:i,config:s}):null])}}}),pc=j({name:"SidebarLinks",props:{config:{type:Array,required:!0}},setup(e){const t=Et(),n=X(-1),r=o=>{n.value=o===n.value?-1:o};return fe(()=>t.path,()=>{const o=e.config.findIndex(l=>Qi(t,l));n.value=o},{immediate:!0,flush:"post"}),()=>u("ul",{class:"sidebar-links"},e.config.map((o,l)=>u("li",o.type==="group"?u(v0,{config:o,open:l===n.value,onToggle:()=>r(l)}):u(h0,{config:o}))))}}),m0=j({name:"SideBar",slots:Object,setup(e,{slots:t}){const n=Et(),r=ge(),o=wl(),l=bt();return Ee(()=>{fe(()=>n.hash,s=>{const a=document.querySelector(`.sidebar a.sidebar-link[href="${n.path}${s}"]`);if(!a)return;const{top:i,height:c}=l.value.getBoundingClientRect(),{top:f,height:d}=a.getBoundingClientRect();fi+c&&a.scrollIntoView(!1)})}),()=>{var s,a,i;return u("aside",{class:["sidebar",{"hide-icon":r.value.sidebarIcon===!1}],id:"sidebar",ref:l},[(s=t.top)==null?void 0:s.call(t),((a=t.default)==null?void 0:a.call(t))||u(pc,{config:o.value}),(i=t.bottom)==null?void 0:i.call(t)])}}}),hc=j({name:"CommonWrapper",props:{noNavbar:Boolean,noSidebar:Boolean,noToc:Boolean},slots:Object,setup(e,{slots:t}){const n=wt(),r=he(),o=ke(),l=ge(),{isMobile:s,isPC:a}=Wr(),[i,c]=vs(!1),[f,d]=vs(!1),p=wl(),g=X(!1),_=x(()=>e.noNavbar||o.value.navbar===!1||l.value.navbar===!1?!1:!!(r.value.title||l.value.logo||l.value.repo||l.value.navbar)),w=x(()=>e.noSidebar?!1:o.value.sidebar!==!1&&p.value.length!==0&&!o.value.home),E=x(()=>e.noToc||o.value.home?!1:o.value.toc||l.value.toc!==!1&&o.value.toc!==!1),m={x:0,y:0},b=R=>{m.x=R.changedTouches[0].clientX,m.y=R.changedTouches[0].clientY},S=R=>{const Y=R.changedTouches[0].clientX-m.x,P=R.changedTouches[0].clientY-m.y;Math.abs(Y)>Math.abs(P)*1.5&&Math.abs(Y)>40&&(Y>0&&m.x<=80?c(!0):c(!1))},O=()=>window.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop||0;let z=0;return Se("scroll",op(()=>{const R=O();R<=58||R{R||c(!1)}),Ee(()=>{const R=hl(document.body);fe(i,P=>{R.value=P});const Y=n.afterEach(()=>{c(!1)});tr(()=>{R.value=!1,Y()})}),()=>u(vt("GlobalEncrypt")?et("GlobalEncrypt"):ri,()=>u("div",{class:["theme-container",{"no-navbar":!_.value,"no-sidebar":!w.value&&!(t.sidebar||t.sidebarTop||t.sidebarBottom),"has-toc":E.value,"hide-navbar":g.value,"sidebar-collapsed":!s.value&&!a.value&&f.value,"sidebar-open":s.value&&i.value},o.value.containerClass||""],onTouchStart:b,onTouchEnd:S},[_.value?u(p0,{onToggleSidebar:()=>c()},{startBefore:()=>{var R;return(R=t.navbarStartBefore)==null?void 0:R.call(t)},startAfter:()=>{var R;return(R=t.navbarStartAfter)==null?void 0:R.call(t)},centerBefore:()=>{var R;return(R=t.navbarCenterBefore)==null?void 0:R.call(t)},centerAfter:()=>{var R;return(R=t.navbarCenterAfter)==null?void 0:R.call(t)},endBefore:()=>{var R;return(R=t.navbarEndBefore)==null?void 0:R.call(t)},endAfter:()=>{var R;return(R=t.navbarEndAfter)==null?void 0:R.call(t)},screenTop:()=>{var R;return(R=t.navScreenTop)==null?void 0:R.call(t)},screenBottom:()=>{var R;return(R=t.navScreenBottom)==null?void 0:R.call(t)}}):null,u(Dt,{name:"fade"},()=>i.value?u("div",{class:"sidebar-mask",onClick:()=>c(!1)}):null),u(Dt,{name:"fade"},()=>s.value?null:u("div",{class:"toggle-sidebar-wrapper",onClick:()=>d()},u("span",{class:["arrow",f.value?"end":"start"]}))),u(m0,{},{...t.sidebar?{default:()=>t.sidebar()}:{},top:()=>{var R;return(R=t.sidebarTop)==null?void 0:R.call(t)},bottom:()=>{var R;return(R=t.sidebarBottom)==null?void 0:R.call(t)}}),t.default(),u(J1)]))}}),ln=j({name:"DropTransition",props:{type:{type:String,default:"single"},delay:{type:Number,default:0},duration:{type:Number,default:.25},appear:Boolean},slots:Object,setup(e,{slots:t}){const n=o=>{o.style.transition=`transform ${e.duration}s ease-in-out ${e.delay}s, opacity ${e.duration}s ease-in-out ${e.delay}s`,o.style.transform="translateY(-20px)",o.style.opacity="0"},r=o=>{o.style.transform="translateY(0)",o.style.opacity="1"};return()=>u(e.type==="single"?Dt:dd,{name:"drop",appear:e.appear,onAppear:n,onAfterAppear:r,onEnter:n,onAfterEnter:r,onBeforeLeave:n},()=>t.default())}});const So=({custom:e})=>u(ni,{class:["theme-hope-content",{custom:e}]});So.displayName="MarkdownContent",So.props={custom:Boolean};var vc=So;const mc=()=>u(me,{name:"author"},()=>u("path",{d:"M649.6 633.6c86.4-48 147.2-144 147.2-249.6 0-160-128-288-288-288s-288 128-288 288c0 108.8 57.6 201.6 147.2 249.6-121.6 48-214.4 153.6-240 288-3.2 9.6 0 19.2 6.4 25.6 3.2 9.6 12.8 12.8 22.4 12.8h704c9.6 0 19.2-3.2 25.6-12.8 6.4-6.4 9.6-16 6.4-25.6-25.6-134.4-121.6-240-243.2-288z"}));mc.displayName="AuthorIcon";const gc=()=>u(me,{name:"calendar"},()=>u("path",{d:"M716.4 110.137c0-18.753-14.72-33.473-33.472-33.473-18.753 0-33.473 14.72-33.473 33.473v33.473h66.993v-33.473zm-334.87 0c0-18.753-14.72-33.473-33.473-33.473s-33.52 14.72-33.52 33.473v33.473h66.993v-33.473zm468.81 33.52H716.4v100.465c0 18.753-14.72 33.473-33.472 33.473a33.145 33.145 0 01-33.473-33.473V143.657H381.53v100.465c0 18.753-14.72 33.473-33.473 33.473a33.145 33.145 0 01-33.473-33.473V143.657H180.6A134.314 134.314 0 0046.66 277.595v535.756A134.314 134.314 0 00180.6 947.289h669.74a134.36 134.36 0 00133.94-133.938V277.595a134.314 134.314 0 00-133.94-133.938zm33.473 267.877H147.126a33.145 33.145 0 01-33.473-33.473c0-18.752 14.72-33.473 33.473-33.473h736.687c18.752 0 33.472 14.72 33.472 33.473a33.145 33.145 0 01-33.472 33.473z"}));gc.displayName="CalendarIcon";const yc=()=>u(me,{name:"category"},()=>u("path",{d:"M148.41 106.992h282.176c22.263 0 40.31 18.048 40.31 40.31V429.48c0 22.263-18.047 40.31-40.31 40.31H148.41c-22.263 0-40.311-18.047-40.311-40.31V147.302c0-22.263 18.048-40.31 40.311-40.31zM147.556 553.478H429.73c22.263 0 40.311 18.048 40.311 40.31v282.176c0 22.263-18.048 40.312-40.31 40.312H147.555c-22.263 0-40.311-18.049-40.311-40.312V593.79c0-22.263 18.048-40.311 40.31-40.311zM593.927 106.992h282.176c22.263 0 40.31 18.048 40.31 40.31V429.48c0 22.263-18.047 40.31-40.31 40.31H593.927c-22.263 0-40.311-18.047-40.311-40.31V147.302c0-22.263 18.048-40.31 40.31-40.31zM730.22 920.502H623.926c-40.925 0-74.22-33.388-74.22-74.425V623.992c0-41.038 33.387-74.424 74.425-74.424h222.085c41.038 0 74.424 33.226 74.424 74.067v114.233c0 10.244-8.304 18.548-18.547 18.548s-18.548-8.304-18.548-18.548V623.635c0-20.388-16.746-36.974-37.33-36.974H624.13c-20.585 0-37.331 16.747-37.331 37.33v222.086c0 20.585 16.654 37.331 37.126 37.331H730.22c10.243 0 18.547 8.304 18.547 18.547 0 10.244-8.304 18.547-18.547 18.547z"}));yc.displayName="CategoryIcon";const bc=()=>u(me,{name:"print"},()=>u("path",{d:"M819.2 364.8h-44.8V128c0-17.067-14.933-32-32-32H281.6c-17.067 0-32 14.933-32 32v236.8h-44.8C145.067 364.8 96 413.867 96 473.6v192c0 59.733 49.067 108.8 108.8 108.8h44.8V896c0 17.067 14.933 32 32 32h460.8c17.067 0 32-14.933 32-32V774.4h44.8c59.733 0 108.8-49.067 108.8-108.8v-192c0-59.733-49.067-108.8-108.8-108.8zM313.6 160h396.8v204.8H313.6V160zm396.8 704H313.6V620.8h396.8V864zM864 665.6c0 25.6-19.2 44.8-44.8 44.8h-44.8V588.8c0-17.067-14.933-32-32-32H281.6c-17.067 0-32 14.933-32 32v121.6h-44.8c-25.6 0-44.8-19.2-44.8-44.8v-192c0-25.6 19.2-44.8 44.8-44.8h614.4c25.6 0 44.8 19.2 44.8 44.8v192z"}));bc.displayName="PrintIcon";const _c=()=>u(me,{name:"tag"},()=>u("path",{d:"M939.902 458.563L910.17 144.567c-1.507-16.272-14.465-29.13-30.737-30.737L565.438 84.098h-.402c-3.215 0-5.726 1.005-7.634 2.913l-470.39 470.39a10.004 10.004 0 000 14.164l365.423 365.424c1.909 1.908 4.42 2.913 7.132 2.913s5.223-1.005 7.132-2.913l470.39-470.39c2.01-2.11 3.014-5.023 2.813-8.036zm-240.067-72.121c-35.458 0-64.286-28.828-64.286-64.286s28.828-64.285 64.286-64.285 64.286 28.828 64.286 64.285-28.829 64.286-64.286 64.286z"}));_c.displayName="TagIcon";const wc=()=>u(me,{name:"timer"},()=>u("path",{d:"M799.387 122.15c4.402-2.978 7.38-7.897 7.38-13.463v-1.165c0-8.933-7.38-16.312-16.312-16.312H256.33c-8.933 0-16.311 7.38-16.311 16.312v1.165c0 5.825 2.977 10.874 7.637 13.592 4.143 194.44 97.22 354.963 220.201 392.763-122.204 37.542-214.893 196.511-220.2 389.397-4.661 5.049-7.638 11.651-7.638 19.03v5.825h566.49v-5.825c0-7.379-2.849-13.981-7.509-18.9-5.049-193.016-97.867-351.985-220.2-389.527 123.24-37.67 216.446-198.453 220.588-392.892zM531.16 450.445v352.632c117.674 1.553 211.787 40.778 211.787 88.676H304.097c0-48.286 95.149-87.382 213.728-88.676V450.445c-93.077-3.107-167.901-81.297-167.901-177.093 0-8.803 6.99-15.793 15.793-15.793 8.803 0 15.794 6.99 15.794 15.793 0 80.261 63.69 145.635 142.01 145.635s142.011-65.374 142.011-145.635c0-8.803 6.99-15.793 15.794-15.793s15.793 6.99 15.793 15.793c0 95.019-73.789 172.82-165.96 177.093z"}));wc.displayName="TimerIcon";const Ec=()=>u(me,{name:"word"},()=>[u("path",{d:"M518.217 432.64V73.143A73.143 73.143 0 01603.43 1.097a512 512 0 01419.474 419.474 73.143 73.143 0 01-72.046 85.212H591.36a73.143 73.143 0 01-73.143-73.143z"}),u("path",{d:"M493.714 566.857h340.297a73.143 73.143 0 0173.143 85.577A457.143 457.143 0 11371.566 117.76a73.143 73.143 0 0185.577 73.143v339.383a36.571 36.571 0 0036.571 36.571z"})]);Ec.displayName="WordIcon";const Ft=()=>{const e=ge();return x(()=>e.value.metaLocales)};var g0=j({name:"AuthorInfo",inheritAttrs:!1,props:{author:{type:Array,required:!0},pure:Boolean},setup(e){const t=Ft();return()=>e.author.length?u("span",{class:"page-author-info","aria-label":`${t.value.author}${e.pure?"":"🖊"}`,...e.pure?{}:{"data-balloon-pos":"down"}},[u(mc),u("span",e.author.map(n=>n.url?u("a",{class:"page-author-item",href:n.url,target:"_blank",rel:"noopener noreferrer"},n.name):u("span",{class:"page-author-item"},n.name))),u("span",{property:"author",content:e.author.map(n=>n.name).join(", ")})]):null}}),y0=j({name:"CategoryInfo",inheritAttrs:!1,props:{category:{type:Array,required:!0},pure:Boolean},setup(e){const t=wt(),n=he(),r=Ft(),o=(l,s="")=>{s&&n.value.path!==s&&(l.preventDefault(),t.push(s))};return()=>e.category.length?u("span",{class:"page-category-info","aria-label":`${r.value.category}${e.pure?"":"🌈"}`,...e.pure?{}:{"data-balloon-pos":"down"}},[u(yc),e.category.map(({name:l,path:s})=>u("span",{class:["page-category-item",{[`category${pi(l,9)}`]:!e.pure,clickable:s}],role:s?"navigation":"",onClick:a=>o(a,s)},l)),u("meta",{property:"articleSection",content:e.category.map(({name:l})=>l).join(",")})]):null}}),b0=j({name:"DateInfo",inheritAttrs:!1,props:{date:{type:Object,default:null},localizedDate:{type:String,default:""},pure:Boolean},setup(e){const t=Xa(),n=Ft();return()=>e.date?u("span",{class:"page-date-info","aria-label":`${n.value.date}${e.pure?"":"📅"}`,...e.pure?{}:{"data-balloon-pos":"down"}},[u(gc),u("span",u(Vr,()=>e.localizedDate||e.date.toLocaleDateString(t.value))),u("meta",{property:"datePublished",content:e.date.toISOString()||""})]):null}}),_0=j({name:"OriginalInfo",inheritAttrs:!1,props:{isOriginal:Boolean},setup(e){const t=Ft();return()=>e.isOriginal?u("span",{class:"page-original-info"},t.value.origin):null}}),w0=j({name:"ReadingTimeInfo",inheritAttrs:!1,props:{readingTime:{type:Object,default:()=>null},readingTimeLocale:{type:Object,default:()=>null},pure:Boolean},setup(e){const t=Ft(),n=x(()=>{if(!e.readingTime)return null;const{minutes:r}=e.readingTime;return r<1?"PT1M":`PT${Math.round(r)}M`});return()=>{var r,o;return(r=e.readingTimeLocale)!=null&&r.time?u("span",{class:"page-reading-time-info","aria-label":`${t.value.readingTime}${e.pure?"":"⌛"}`,...e.pure?{}:{"data-balloon-pos":"down"}},[u(wc),u("span",(o=e.readingTimeLocale)==null?void 0:o.time),u("meta",{property:"timeRequired",content:n.value})]):null}}}),E0=j({name:"TagInfo",inheritAttrs:!1,props:{tag:{type:Array,default:()=>[]},pure:Boolean},setup(e){const t=wt(),n=he(),r=Ft(),o=(l,s="")=>{s&&n.value.path!==s&&(l.preventDefault(),t.push(s))};return()=>e.tag.length?u("span",{class:"page-tag-info","aria-label":`${r.value.tag}${e.pure?"":"🏷"}`,...e.pure?{}:{"data-balloon-pos":"down"}},[u(_c),e.tag.map(({name:l,path:s})=>u("span",{class:["page-tag-item",{[`tag${pi(l,9)}`]:!e.pure,clickable:s}],role:s?"navigation":"",onClick:a=>o(a,s)},l)),u("meta",{property:"keywords",content:e.tag.map(({name:l})=>l).join(",")})]):null}}),T0=j({name:"ReadTimeInfo",inheritAttrs:!1,props:{readingTime:{type:Object,default:()=>null},readingTimeLocale:{type:Object,default:()=>null},pure:Boolean},setup(e){const t=Ft();return()=>{var n,r,o;return(n=e.readingTimeLocale)!=null&&n.words?u("span",{class:"page-word-info","aria-label":`${t.value.words}${e.pure?"":"🔠"}`,...e.pure?{}:{"data-balloon-pos":"down"}},[u(Ec),u("span",(r=e.readingTimeLocale)==null?void 0:r.words),u("meta",{property:"wordCount",content:(o=e.readingTime)==null?void 0:o.words})]):null}}}),C0=j({name:"PageInfo",components:{AuthorInfo:g0,CategoryInfo:y0,DateInfo:b0,OriginalInfo:_0,PageViewInfo:()=>null,ReadingTimeInfo:w0,TagInfo:E0,WordInfo:T0},props:{items:{type:[Array,Boolean],default:()=>["Author","Original","Date","PageView","ReadingTime","Category","Tag"]},info:{type:Object,required:!0}},setup(e){const t=qr();return()=>e.items?u("div",{class:"page-info"},e.items.map(n=>u(et(`${n}Info`),{...e.info,pure:t.value}))):null}}),x0=j({name:"PrintButton",setup(){const e=or(),t=ge();return()=>e.value.print===!1?null:u("button",{type:"button",class:"print-button",title:t.value.metaLocales.print,onClick:()=>{window.print()}},u(bc))}});const A0=({title:e,level:t,slug:n})=>u(mt,{to:`#${n}`,class:["toc-link",`level${t}`]},()=>e),Io=(e,t)=>{const n=Et();return e.length&&t>0?u("ul",{class:"toc-list"},e.map(r=>{const o=Io(r.children,t-1);return[u("li",{class:["toc-item",{active:ul(n,`#${r.slug}`)}]},A0(r)),o?u("li",o):null]})):null};var P0=j({name:"TOC",props:{items:{type:Array,default:()=>[]},headerDepth:{type:Number,default:2}},slots:Object,setup(e,{slots:t}){const n=Et(),r=he(),o=Ft(),l=bt(),s=X("-1.7rem"),a=c=>{var f;(f=l.value)==null||f.scrollTo({top:c,behavior:"smooth"})},i=()=>{if(l.value){const c=document.querySelector(".toc-item.active");c?s.value=`${c.getBoundingClientRect().top-l.value.getBoundingClientRect().top+l.value.scrollTop}px`:s.value="-1.7rem"}else s.value="-1.7rem"};return Ee(()=>{fe(()=>n.hash,c=>{if(l.value){const f=document.querySelector(`#toc a.toc-link[href$="${c}"]`);if(!f)return;const{top:d,height:p}=l.value.getBoundingClientRect(),{top:g,height:_}=f.getBoundingClientRect();gd+p&&a(l.value.scrollTop+g+_-d-p)}}),fe(()=>n.fullPath,()=>i(),{flush:"post",immediate:!0})}),()=>{var c,f;const d=e.items.length?Io(e.items,e.headerDepth):r.value.headers?Io(r.value.headers,e.headerDepth):null;return d?u("div",{class:"toc-place-holder"},[u("aside",{id:"toc"},[(c=t.before)==null?void 0:c.call(t),u("div",{class:"toc-header"},[o.value.toc,u(x0)]),u("div",{class:"toc-wrapper",ref:l},[d,u("div",{class:"toc-marker",style:{top:s.value}})]),(f=t.after)==null?void 0:f.call(t)])]):null}}}),Tc=j({name:"SkipLink",props:{content:{type:String,default:"main-content"}},setup(e){const t=he(),n=ge(),r=bt(),o=({target:l})=>{const s=document.querySelector(l.hash);if(s){const a=()=>{s.removeAttribute("tabindex"),s.removeEventListener("blur",a)};s.setAttribute("tabindex","-1"),s.addEventListener("blur",a),s.focus(),window.scrollTo(0,0)}};return Ee(()=>{fe(()=>t.value.path,()=>r.value.focus())}),()=>[u("span",{ref:r,tabindex:"-1"}),u("a",{href:`#${e.content}`,class:"skip-link sr-only",onClick:o},n.value.routeLocales.skipToContent)]}});let fo=null,yr=null;const k0={wait:()=>fo,pending:()=>{fo=new Promise(e=>yr=e)},resolve:()=>{yr==null||yr(),fo=null,yr=null}},Cc=()=>k0;var L0=j({name:"FadeSlideY",slots:Object,setup(e,{slots:t}){const{resolve:n,pending:r}=Cc();return()=>u(Dt,{name:"fade-slide-y",mode:"out-in",onBeforeEnter:n,onBeforeLeave:r},()=>{var o;return(o=t.default)==null?void 0:o.call(t)})}}),R0=j({name:"FeaturePanel",props:{items:{type:Object,default:()=>[]},header:{type:String,default:""}},setup(e){return()=>u("div",{class:"feature-panel"},[e.header?u("h2",{class:"feature-header"},e.header):null,e.items.length?u("div",{class:"feature-wrapper"},e.items.map(t=>{const n=[u("h3",[u(Ye,{icon:t.icon}),u("span",{innerHTML:t.title})]),u("p",{innerHTML:t.details})];return t.link?Lr(t.link)?u("a",{class:"feature-item link",href:t.link,role:"navigation","aria-label":t.title,target:"_blank"},n):u(mt,{class:"feature-item link",to:t.link,role:"navigation","aria-label":t.title},()=>n):u("div",{class:"feature-item"},n)})):null])}}),O0=j({name:"HeroInfo",slots:Object,setup(e,{slots:t}){const n=ke(),r=Br(),o=x(()=>n.value.heroText===!1?!1:n.value.heroText||r.value.title||"Hello"),l=x(()=>n.value.tagline===!1?!1:n.value.tagline||r.value.description||"Welcome to your VuePress site"),s=x(()=>n.value.heroImage?Yt(n.value.heroImage):null),a=x(()=>n.value.heroImageDark?Yt(n.value.heroImageDark):null),i=x(()=>n.value.heroAlt||o.value||"hero"),c=x(()=>n.value.actions??[]);return()=>{var f,d;return u("header",{class:"hero-info-wrapper"},[((f=t.heroImage)==null?void 0:f.call(t))||u(ln,{appear:!0,type:"group"},()=>[s.value?u("img",{key:"light",class:{light:a.value},src:s.value,alt:i.value}):null,a.value?u("img",{key:"dark",class:"dark",src:a.value,alt:i.value}):null]),((d=t.heroInfo)==null?void 0:d.call(t))??u("div",{class:"hero-info"},[o.value?u(ln,{appear:!0,delay:.04},()=>u("h1",{id:"main-title"},o.value)):null,l.value?u(ln,{appear:!0,delay:.08},()=>u("p",{class:"description"},l.value)):null,c.value.length?u(ln,{appear:!0,delay:.12},()=>u("p",{class:"actions"},c.value.map(p=>u(De,{class:["action-button",p.type||"default"],config:p,noExternalLinkIcon:!0})))):null])])}}}),S0=j({name:"HomePage",slots:Object,setup(e,{slots:t}){const n=qr(),r=ke(),o=x(()=>{const{features:l}=r.value;return Q(l)?l.some(s=>!("items"in s))?[{items:l}]:l:[]});return()=>{var l,s,a;return u("main",{class:["home project",{pure:n.value}],id:"main-content","aria-labelledby":r.value.heroText===null?void 0:"main-title"},[(l=t.top)==null?void 0:l.call(t),u(O0),o.value.map(({header:i="",items:c},f)=>u(ln,{appear:!0,delay:.16+f*.08},()=>u(R0,{header:i,items:c}))),(s=t.center)==null?void 0:s.call(t),u(ln,{appear:!0,delay:.16+o.value.length*.08},()=>u(vc)),(a=t.bottom)==null?void 0:a.call(t)])}}});const I0=(e,t)=>{const n=e.replace(t,"/").split("/"),r=[];let o=al(t);return n.forEach((l,s)=>{s!==n.length-1?(o+=`${l}/`,r.push(o)):l!==""&&(o+=l,r.push(o))}),r};var $0=j({name:"BreadCrumb",setup(){const e=wt(),t=he(),n=Pn(),r=ke(),o=ge(),l=bt([]),s=x(()=>(r.value.breadcrumb||r.value.breadcrumb!==!1&&o.value.breadcrumb!==!1)&&l.value.length>1),a=x(()=>r.value.breadcrumbIcon||r.value.breadcrumbIcon!==!1&&o.value.breadcrumbIcon!==!1),i=()=>{const c=e.getRoutes(),f=I0(t.value.path,n.value).map(d=>{const p=c.find(g=>g.path===d);if(p){const{meta:g,path:_}=fl(e,p.path),w=g[ht.shortTitle]||g[ht.title];if(w)return{title:w,icon:g[ht.icon],path:_}}return null}).filter(d=>d!==null);f.length>1&&(l.value=f)};return Ee(()=>{i(),fe(()=>t.value.path,i)}),()=>u("nav",{class:["breadcrumb",{disable:!s.value}]},s.value?u("ol",{vocab:"https://schema.org/",typeof:"BreadcrumbList"},l.value.map((c,f)=>u("li",{class:{"is-active":l.value.length-1===f},property:"itemListElement",typeof:"ListItem"},[u(mt,{to:c.path,property:"item",typeof:"WebPage"},()=>[a.value?u(Ye,{icon:c.icon}):null,u("span",{property:"name"},c.title||"Unknown")]),u("meta",{property:"position",content:f+1})]))):[])}});const Ws=e=>e===!1?!1:ue(e)?un(e,!0):sl(e)?e:null,$o=(e,t,n)=>{const r=e.findIndex(o=>o.link===t);if(r!==-1){const o=e[r+n];return o!=null&&o.link?o:null}for(const o of e)if(o.children){const l=$o(o.children,t,n);if(l)return l}return null};var M0=j({name:"PageNav",setup(){const e=ge(),t=ke(),n=wl(),r=he(),o=F1(),l=x(()=>{const a=Ws(t.value.prev);return a===!1?null:a||(e.value.prevLink===!1?null:$o(n.value,r.value.path,-1))}),s=x(()=>{const a=Ws(t.value.next);return a===!1?null:a||(e.value.nextLink===!1?null:$o(n.value,r.value.path,1))});return Se("keydown",a=>{a.altKey&&(a.key==="ArrowRight"?s.value&&(o(s.value.link),a.preventDefault()):a.key==="ArrowLeft"&&l.value&&(o(l.value.link),a.preventDefault()))}),()=>l.value||s.value?u("nav",{class:"page-nav"},[l.value?u(De,{class:"prev",config:l.value},()=>{var a,i;return[u("div",{class:"hint"},[u("span",{class:"arrow start"}),e.value.metaLocales.prev]),u("div",{class:"link"},[u(Ye,{icon:(a=l.value)==null?void 0:a.icon}),(i=l.value)==null?void 0:i.text])]}):null,s.value?u(De,{class:"next",config:s.value},()=>{var a,i;return[u("div",{class:"hint"},[e.value.metaLocales.next,u("span",{class:"arrow end"})]),u("div",{class:"link"},[(a=s.value)==null?void 0:a.text,u(Ye,{icon:(i=s.value)==null?void 0:i.icon})])]}):null]):null}});const D0={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"},N0=({docsRepo:e,docsBranch:t,docsDir:n,filePathRelative:r,editLinkPattern:o})=>{if(!r)return null;const l=gi(e);let s;return o?s=o:l!==null&&(s=D0[l]),s?s.replace(/:repo/,An(e)?e:`https://github.com/${e}`).replace(/:branch/,t).replace(/:path/,Wa(`${al(n)}/${r}`)):null},F0=()=>{const e=ge(),t=he(),n=ke();return x(()=>{const{repo:r,docsRepo:o=r,docsBranch:l="main",docsDir:s="",editLink:a,editLinkPattern:i=""}=e.value;if(!(n.value.editLink??a??!0)||!o)return null;const c=N0({docsRepo:o,docsBranch:l,docsDir:s,editLinkPattern:i,filePathRelative:t.value.filePathRelative});return c?{text:e.value.metaLocales.editLink,link:c}:null})},H0=()=>{const e=Br(),t=ge(),n=he(),r=ke();return x(()=>{var o,l;return!(r.value.lastUpdated??t.value.lastUpdated??!0)||!((o=n.value.git)!=null&&o.updatedTime)?null:new Date((l=n.value.git)==null?void 0:l.updatedTime).toLocaleString(e.value.lang)})},B0=()=>{const e=ge(),t=he(),n=ke();return x(()=>{var r;return n.value.contributors??e.value.contributors??!0?((r=t.value.git)==null?void 0:r.contributors)??null:null})};var V0=j({name:"PageTitle",setup(){const e=he(),t=ke(),n=ge(),{info:r,items:o}=j1();return()=>u("div",{class:"page-title"},[u("h1",[n.value.titleIcon===!1?null:u(Ye,{icon:t.value.icon}),e.value.title]),u(C0,{info:r.value,...o.value===null?{}:{items:o.value}}),u("hr")])}});const xc=()=>u(me,{name:"edit"},()=>[u("path",{d:"M430.818 653.65a60.46 60.46 0 0 1-50.96-93.281l71.69-114.012 7.773-10.365L816.038 80.138A60.46 60.46 0 0 1 859.225 62a60.46 60.46 0 0 1 43.186 18.138l43.186 43.186a60.46 60.46 0 0 1 0 86.373L588.879 565.55l-8.637 8.637-117.466 68.234a60.46 60.46 0 0 1-31.958 11.229z"}),u("path",{d:"M728.802 962H252.891A190.883 190.883 0 0 1 62.008 771.98V296.934a190.883 190.883 0 0 1 190.883-192.61h267.754a60.46 60.46 0 0 1 0 120.92H252.891a69.962 69.962 0 0 0-69.098 69.099V771.98a69.962 69.962 0 0 0 69.098 69.098h475.911A69.962 69.962 0 0 0 797.9 771.98V503.363a60.46 60.46 0 1 1 120.922 0V771.98A190.883 190.883 0 0 1 728.802 962z"})]);xc.displayName="EditIcon";var j0=j({name:"PageMeta",setup(){const e=ge(),t=F0(),n=H0(),r=B0();return()=>{const{metaLocales:o}=e.value;return u("footer",{class:"page-meta"},[t.value?u("div",{class:"meta-item edit-link"},u(De,{class:"label",config:t.value},{before:()=>u(xc)})):null,u("div",{class:"meta-item git-info"},[n.value?u("div",{class:"update-time"},[u("span",{class:"label"},`${o.lastUpdated}: `),u(Vr,()=>u("span",{class:"info"},n.value))]):null,r.value&&r.value.length?u("div",{class:"contributors"},[u("span",{class:"label"},`${o.contributors}: `),r.value.map(({email:l,name:s},a)=>[u("span",{class:"contributor",title:`email: ${l}`},s),a!==r.value.length-1?",":""])]):null])])}}}),z0=j({name:"NormalPage",slots:Object,setup(e,{slots:t}){const n=ke(),r=he(),{isDarkmode:o}=lr(),l=ge(),s=x(()=>n.value.toc||n.value.toc!==!1&&l.value.toc!==!1);return()=>u("main",{class:"page",id:"main-content"},u(vt("LocalEncrypt")?et("LocalEncrypt"):ri,()=>{var a,i,c,f;return[(a=t.top)==null?void 0:a.call(t),n.value.cover?u("img",{class:"page-cover",src:Yt(n.value.cover),alt:r.value.title,"no-view":""}):null,u($0),u(V0),s.value?u(P0,{headerDepth:n.value.headerDepth??l.value.headerDepth??2},{before:()=>{var d;return(d=t.tocBefore)==null?void 0:d.call(t)},after:()=>{var d;return(d=t.tocAfter)==null?void 0:d.call(t)}}):null,(i=t.contentBefore)==null?void 0:i.call(t),u(vc),(c=t.contentAfter)==null?void 0:c.call(t),u(j0),u(M0),vt("CommentService")?u(et("CommentService"),{darkmode:o.value}):null,(f=t.bottom)==null?void 0:f.call(t)]}))}}),U0=j({name:"Layout",setup(){ge();const e=he(),t=ke(),{isMobile:n}=Wr(),r=x(()=>"none");return()=>[u(Tc),u(hc,{},{default:()=>t.value.home?u(S0):u(L0,()=>u(z0,{key:e.value.path})),...r.value!=="none"?{navScreenBottom:()=>u(et("BloggerInfo"))}:{},...!n.value&&r.value==="always"?{sidebar:()=>u(et("BloggerInfo"))}:{}})]}}),q0=j({name:"NotFoundHint",setup(){const e=ge(),t=()=>{const n=e.value.routeLocales.notFoundMsg;return n[Math.floor(Math.random()*n.length)]};return()=>u("div",{class:"not-found-hint"},[u("p",{class:"error-code"},"404"),u("h1",{class:"error-title"},e.value.routeLocales.notFoundTitle),u("p",{class:"error-hint"},t())])}}),W0=j({name:"NotFound",slots:Object,setup(e,{slots:t}){const n=Pn(),r=ge(),{navigate:o}=ko({to:r.value.home??n.value});return()=>[u(Tc),u(hc,{noSidebar:!0},()=>{var l;return u("main",{class:"page not-found",id:"main-content"},((l=t.default)==null?void 0:l.call(t))||[u(q0),u("div",{class:"actions"},[u("button",{type:"button",class:"action-button",onClick:()=>{window.history.go(-1)}},r.value.routeLocales.back),u("button",{type:"button",class:"action-button",onClick:()=>o()},r.value.routeLocales.home)])])})]}});Qh(Ye);const K0=nt({enhance:({app:e,router:t})=>{const{scrollBehavior:n}=t.options;t.options.scrollBehavior=async(...r)=>(await Cc().wait(),n(...r)),q1(e)},setup:()=>{W1(),Q1()},layouts:{Layout:U0,NotFound:W0}}),Ac=()=>u("svg",{xmlns:"http://www.w3.org/2000/svg",width:"32",height:"32",preserveAspectRatio:"xMidYMid",viewBox:"0 0 100 100"},[u("circle",{cx:"28",cy:"75",r:"11",fill:"currentColor"},u("animate",{attributeName:"fill-opacity",begin:"0s",dur:"1s",keyTimes:"0;0.2;1",repeatCount:"indefinite",values:"0;1;1"})),u("path",{fill:"none",stroke:"#88baf0","stroke-width":"10",d:"M28 47a28 28 0 0 1 28 28"},u("animate",{attributeName:"stroke-opacity",begin:"0.1s",dur:"1s",keyTimes:"0;0.2;1",repeatCount:"indefinite",values:"0;1;1"})),u("path",{fill:"none",stroke:"#88baf0","stroke-width":"10",d:"M28 25a50 50 0 0 1 50 50"},u("animate",{attributeName:"stroke-opacity",begin:"0.2s",dur:"1s",keyTimes:"0;0.2;1",repeatCount:"indefinite",values:"0;1;1"}))]);Ac.displayName="LoadingIcon";const Pc=({hint:e})=>u("div",{class:"search-pro-result loading"},[u(Ac),e]);Pc.displayName="SearchLoading";const Y0=()=>u(me,{name:"close"},()=>u("path",{d:"M507.168 473.232 716.48 263.936a16 16 0 0 1 22.624 0l11.312 11.312a16 16 0 0 1 0 22.624L541.12 507.168 750.4 716.48a16 16 0 0 1 0 22.624l-11.312 11.312a16 16 0 0 1-22.624 0L507.168 541.12 297.872 750.4a16 16 0 0 1-22.624 0l-11.312-11.312a16 16 0 0 1 0-22.624l209.296-209.312-209.296-209.296a16 16 0 0 1 0-22.624l11.312-11.312a16 16 0 0 1 22.624 0l209.296 209.296z"}));Y0.displayName="CloseIcon";const G0=()=>u(me,{name:"heading"},()=>u("path",{d:"M250.4 704.6H64V595.4h202.4l26.2-166.6H94V319.6h214.4L352 64h127.8l-43.6 255.4h211.2L691 64h126.2l-43.6 255.4H960v109.2H756.2l-24.6 166.6H930v109.2H717L672 960H545.8l43.6-255.4H376.6L333 960H206.8l43.6-255.4zm168.4-276L394 595.4h211.2l24.6-166.6h-211z"}));G0.displayName="HeadingIcon";const Q0=()=>u(me,{name:"heart"},()=>u("path",{d:"M1024 358.156C1024 195.698 892.3 64 729.844 64c-86.362 0-164.03 37.218-217.844 96.49C458.186 101.218 380.518 64 294.156 64 131.698 64 0 195.698 0 358.156 0 444.518 37.218 522.186 96.49 576H96l320 320c32 32 64 64 96 64s64-32 96-64l320-320h-.49c59.272-53.814 96.49-131.482 96.49-217.844zM841.468 481.232 517.49 805.49a2981.962 2981.962 0 0 1-5.49 5.48c-1.96-1.95-3.814-3.802-5.49-5.48L182.532 481.234C147.366 449.306 128 405.596 128 358.156 128 266.538 202.538 192 294.156 192c47.44 0 91.15 19.366 123.076 54.532L512 350.912l94.768-104.378C638.696 211.366 682.404 192 729.844 192 821.462 192 896 266.538 896 358.156c0 47.44-19.368 91.15-54.532 123.076z"}));Q0.displayName="HeartIcon";const J0=()=>u(me,{name:"history"},()=>u("path",{d:"M512 1024a512 512 0 1 1 512-512 512 512 0 0 1-512 512zm0-896a384 384 0 1 0 384 384 384 384 0 0 0-384-384zm192 448H512a64 64 0 0 1-64-64V320a64 64 0 0 1 128 0v128h128a64 64 0 0 1 0 128z"}));J0.displayName="HistoryIcon";const X0=()=>u(me,{name:"title"},()=>u("path",{d:"M512 256c70.656 0 134.656 28.672 180.992 75.008A254.933 254.933 0 0 1 768 512c0 83.968-41.024 157.888-103.488 204.48C688.96 748.736 704 788.48 704 832c0 105.984-86.016 192-192 192-106.048 0-192-86.016-192-192h128a64 64 0 1 0 128 0 64 64 0 0 0-64-64 255.19 255.19 0 0 1-181.056-75.008A255.403 255.403 0 0 1 256 512c0-83.968 41.024-157.824 103.488-204.544C335.04 275.264 320 235.584 320 192A192 192 0 0 1 512 0c105.984 0 192 85.952 192 192H576a64.021 64.021 0 0 0-128 0c0 35.328 28.672 64 64 64zM384 512c0 70.656 57.344 128 128 128s128-57.344 128-128-57.344-128-128-128-128 57.344-128 128z"}));X0.displayName="TitleIcon";const El=()=>u(me,{name:"search"},()=>u("path",{d:"M192 480a256 256 0 1 1 512 0 256 256 0 0 1-512 0m631.776 362.496-143.2-143.168A318.464 318.464 0 0 0 768 480c0-176.736-143.264-320-320-320S128 303.264 128 480s143.264 320 320 320a318.016 318.016 0 0 0 184.16-58.592l146.336 146.368c12.512 12.48 32.768 12.48 45.28 0 12.48-12.512 12.48-32.768 0-45.28"}));El.displayName="SearchIcon";const kc={delay:300,queryHistoryCount:5,resultHistoryCount:5,hotKeys:[{key:"k",ctrl:!0},{key:"/",ctrl:!0}],worker:"search-pro.worker.js"},Pv={},Lc=kc.hotKeys,Tl={"/":{cancel:"取消",placeholder:"搜索",search:"搜索",searching:"搜索中",select:"选择",navigate:"切换",exit:"关闭",history:"搜索历史",emptyHistory:"无搜索历史",emptyResult:"没有找到结果",loading:"正在加载搜索索引..."}},Z0="search-pro-query-history",ct=Dp(Z0,[]),ev=()=>{const{queryHistoryCount:e}=kc,t=e>0;return{enabled:t,queryHistory:ct,addQueryHistory:n=>{t&&(ct.value.length{ct.value=[...ct.value.slice(0,n),...ct.value.slice(n+1)]}}};const Cl=Symbol(""),tv=()=>{const e=X(!1);Wt(Cl,e)},nv=e=>e instanceof Element?document.activeElement===e&&(["TEXTAREA","SELECT","INPUT"].includes(e.tagName)||e.hasAttribute("contenteditable")):!1,rv=e=>Lc.some(t=>{const{key:n,ctrl:r=!1,shift:o=!1,alt:l=!1,meta:s=!1}=t;return n===e.key&&r===e.ctrlKey&&o===e.shiftKey&&l===e.altKey&&s===e.metaKey}),ov='',lv='',sv='',av='',po=Lc[0];var iv=j({name:"SearchBox",setup(){const e=Nt(Tl),t=_e(Cl),n=X(!1),r=x(()=>po?[(n.value?["⌃","⇧","⌥","⌘"]:["Ctrl","Shift","Alt","Win"]).filter((o,l)=>po[["ctrl","shift","alt","meta"][l]]),po.key.toUpperCase()]:null);return Se("keydown",o=>{!t.value&&rv(o)&&!nv(o.target)&&(o.preventDefault(),t.value=!0)}),Ee(()=>{const{userAgent:o}=navigator;n.value=Wd(o)||qd(o)||Ud(o)}),()=>[u("button",{type:"button",class:"search-pro-button",role:"search","aria-label":e.value.search,onClick:()=>{t.value=!0}},[u(El),u("div",{class:"placeholder"},e.value.search),r.value?u("div",{class:"key-hints"},r.value.map(o=>u("kbd",{class:"key"},o))):null])]}});const cv=ee({loader:()=>$(()=>import("./SearchResult-415a63eb.js"),[]),loadingComponent:()=>{const e=Nt(Tl);return u(Pc,{hint:e.value.loading})}});var uv=j({name:"SearchModal",setup(){const e=_e(Cl),t=Br(),n=di(),r=Nt(Tl),{enabled:o,queryHistory:l}=ev(),s=X(""),a=bt();return fe(e,i=>{i&&Qt().then(()=>{var c;(c=a.value)==null||c.focus()})}),Se("keydown",i=>{e.value&&i.key==="Escape"&&(e.value=!1)}),Ee(()=>{const i=hl(document.body);fe(e,c=>{i.value=c}),tr(()=>{i.value=!1})}),()=>e.value?u("div",{class:"search-pro-modal-wrapper"},[u("div",{class:"background",onClick:()=>{e.value=!1,s.value=""}}),u("div",{class:"search-pro-modal"},[u("div",{class:"search-pro-box"},[u("form",[u("label",{for:"search-pro","aria-label":r.value.search},u(El)),u("input",{ref:a,type:"search",class:"search-pro-input",id:"search-pro",placeholder:r.value.placeholder,spellcheck:"false",autocapitalize:"off",autocorrect:"off",autocomplete:o?"on":"off",name:`${t.value.title}-search`,list:"search-pro-dataset",value:s.value,"aria-controls":"search-pro-results",onInput:({target:i})=>{s.value=i.value}}),u("dataset",{id:"search-pro-dataset"},l.value.map(i=>u("options",{value:i})))]),u("button",{type:"button",class:"close-button",onClick:()=>{e.value=!1,s.value=""}},r.value.cancel)]),u(cv,{query:s.value,onClose:()=>{e.value=!1},onUpdateQuery:i=>{s.value=i}}),n.value?null:u("div",{class:"search-pro-hints"},[u("span",{class:"search-pro-hint"},[u("kbd",{innerHTML:ov}),r.value.select]),u("span",{class:"search-pro-hint"},[u("kbd",{innerHTML:sv}),u("kbd",{innerHTML:lv}),r.value.navigate]),u("span",{class:"search-pro-hint"},[u("kbd",{innerHTML:av}),r.value.exit])])])]):null}}),fv=nt({enhance({app:e}){e.component("SearchBox",iv)},setup(){tv()},rootComponents:[uv]});const br=[Fd,Vp,Gh,e1,r1,a1,d1,b1,_1,R1,K0,fv],dv=[["v-8daa1a0e","/",{y:"h",t:""},["/index.html","/README.md"]],["v-74379e72","/FAQ/",{y:"a",t:"常见问题集合"},["/FAQ/index.html","/FAQ/README.md"]],["v-744497ce","/api/",{y:"a",t:"API"},["/api/index.html","/api/README.md"]],["v-1a155670","/api/judge.html",{y:"a",t:"评测端通信协议"},["/api/judge","/api/judge.md"]],["v-82f2a624","/dev/PERM_PRIV.html",{y:"a",t:"权限节点"},["/dev/PERM_PRIV","/dev/PERM_PRIV.md"]],["v-7445cd33","/dev/",{y:"a",t:"开发环境部署"},["/dev/index.html","/dev/README.md"]],["v-5c0c76d7","/dev/frontend-modify.html",{y:"a",t:"前端修改"},["/dev/frontend-modify","/dev/frontend-modify.md"]],["v-19b5347a","/dev/hook.html",{y:"a",t:"使用 TypeScript 编写插件"},["/dev/hook","/dev/hook.md"]],["v-55131a51","/dev/third-party-auth.html",{y:"a",t:"接入第三方账号系统"},["/dev/third-party-auth","/dev/third-party-auth.md"]],["v-5ddc85e1","/dev/typescript.html",{y:"a",t:"使用 TypeScript 编写插件"},["/dev/typescript","/dev/typescript.md"]],["v-147825fb","/docs/",{y:"a",t:"介绍"},["/docs/index.html","/docs/README.md"]],["v-67d16688","/plugins/",{y:"a",t:"插件"},["/plugins/index.html","/plugins/README.md"]],["v-d67234a8","/plugins/elastic.html",{y:"a",t:"Elastic search"},["/plugins/elastic","/plugins/elastic.md"]],["v-6dd45d9b","/plugins/fps-importer.html",{y:"a",t:"fps-importer"},["/plugins/fps-importer","/plugins/fps-importer.md"]],["v-16bdf429","/plugins/geoip.html",{y:"a",t:"GeoIP"},["/plugins/geoip","/plugins/geoip.md"]],["v-a08ef0ec","/plugins/hydrojudge.html",{y:"a",t:"hydrojudge"},["/plugins/hydrojudge","/plugins/hydrojudge.md"]],["v-669bced4","/plugins/migrate.html",{y:"a",t:"migrate"},["/plugins/migrate","/plugins/migrate.md"]],["v-fa72264c","/plugins/recaptcha.html",{y:"a",t:"recaptcha"},["/plugins/recaptcha","/plugins/recaptcha.md"]],["v-52692a96","/plugins/sonic.html",{y:"a",t:"Sonic"},["/plugins/sonic","/plugins/sonic.md"]],["v-3096c190","/plugins/vjudge.html",{y:"a",t:"Vjudge"},["/plugins/vjudge","/plugins/vjudge.md"]],["v-fe9aee22","/docs/install/",{y:"a",t:"部署 Hydro"},["/docs/install/index.html","/docs/install/README.md"]],["v-fdd5d9ea","/docs/install/compiler.html",{y:"a",t:"编译器"},["/docs/install/compiler","/docs/install/compiler.md"]],["v-4def954c","/docs/install/proxy.html",{y:"a",t:"反向代理 / SSL 配置"},["/docs/install/proxy","/docs/install/proxy.md"]],["v-6b4a62ea","/docs/install/s3.html",{y:"a",t:"存储"},["/docs/install/s3","/docs/install/s3.md"]],["v-68002798","/docs/install/smtp.html",{y:"a",t:"SMTP"},["/docs/install/smtp","/docs/install/smtp.md"]],["v-6d3257b0","/docs/system/FAQ.html",{y:"a",t:"常见问题"},["/docs/system/FAQ","/docs/system/FAQ.md"]],["v-0a40e55e","/docs/system/cdn.html",{y:"a",t:"使用内容分发网络"},["/docs/system/cdn","/docs/system/cdn.md"]],["v-cceda784","/docs/system/cli.html",{y:"a",t:"Hydro Cli"},["/docs/system/cli","/docs/system/cli.md"]],["v-2250b6d9","/docs/system/database.html",{y:"a",t:"数据库备份和恢复"},["/docs/system/database","/docs/system/database.md"]],["v-023b4bae","/docs/system/frontend-modify.html",{y:"a",t:"前端修改"},["/docs/system/frontend-modify","/docs/system/frontend-modify.md"]],["v-69f3a96a","/docs/system/import-user.html",{y:"a",t:"导入用户"},["/docs/system/import-user","/docs/system/import-user.md"]],["v-1bffc66e","/docs/system/maintain.html",{y:"a",t:"维护"},["/docs/system/maintain","/docs/system/maintain.md"]],["v-666426ae","/docs/user/",{y:"a",t:"用户文档"},["/docs/user/index.html","/docs/user/README.md"]],["v-62edc12e","/docs/user/copy-problem.html",{y:"a",t:"复制题目"},["/docs/user/copy-problem","/docs/user/copy-problem.md"]],["v-0566f368","/docs/user/domain.html",{y:"a",t:"域"},["/docs/user/domain","/docs/user/domain.md"]],["v-1d7ad3e6","/docs/user/problem-create.html",{y:"a",t:"Hydro常见题型的制做心得"},["/docs/user/problem-create","/docs/user/problem-create.md"]],["v-dc52bc6a","/docs/user/problem-format.html",{y:"a",t:"Hydro Problem Format"},["/docs/user/problem-format","/docs/user/problem-format.md"]],["v-07f380c3","/docs/user/problem.html",{y:"a",t:"题目"},["/docs/user/problem","/docs/user/problem.md"]],["v-51b3f914","/docs/user/testdata.html",{y:"a",t:"测试数据格式"},["/docs/user/testdata","/docs/user/testdata.md"]],["v-3706649a","/404.html",{y:"p",t:""},["/404"]],["v-723d0d85","/docs/system/",{y:"p",t:"System"},["/docs/system/index.html"]]];var Ks=j({name:"Vuepress",setup(){const e=$d();return()=>u(e.value)}}),pv=()=>dv.reduce((e,[t,n,r,o])=>(e.push({name:t,path:n,component:Ks,meta:r},...o.map(l=>({path:l,redirect:n}))),e),[{name:"404",path:"/:catchAll(.*)",component:Ks}]),hv=sh,vv=()=>{const e=jh({history:hv(al("/")),routes:pv(),scrollBehavior:(t,n,r)=>r||(t.hash?{el:t.hash}:{top:0})});return e.beforeResolve(async(t,n)=>{var r;(t.path!==n.path||n===dt)&&([Lt.value]=await Promise.all([ft.resolvePageData(t.name),(r=Ka[t.name])==null?void 0:r.__asyncLoader()]))}),e},mv=e=>{e.component("ClientOnly",Vr),e.component("Content",ni)},gv=(e,t,n)=>{const r=X(t.currentRoute.value.path);fe(()=>t.currentRoute.value.path,p=>r.value=p);const o=x(()=>ft.resolveLayouts(n)),l=x(()=>ft.resolveRouteLocale(on.value.locales,r.value)),s=x(()=>ft.resolveSiteLocaleData(on.value,l.value)),a=x(()=>ft.resolvePageFrontmatter(Lt.value)),i=x(()=>ft.resolvePageHeadTitle(Lt.value,s.value)),c=x(()=>ft.resolvePageHead(i.value,a.value,s.value)),f=x(()=>ft.resolvePageLang(Lt.value)),d=x(()=>ft.resolvePageLayout(Lt.value,o.value));return e.provide(Rd,o),e.provide(Ga,a),e.provide(Id,i),e.provide(Qa,c),e.provide(Ja,f),e.provide(Za,d),e.provide(il,l),e.provide(ti,s),Object.defineProperties(e.config.globalProperties,{$frontmatter:{get:()=>a.value},$head:{get:()=>c.value},$headTitle:{get:()=>i.value},$lang:{get:()=>f.value},$page:{get:()=>Lt.value},$routeLocale:{get:()=>l.value},$site:{get:()=>on.value},$siteLocale:{get:()=>s.value},$withBase:{get:()=>Yt}}),{layouts:o,pageData:Lt,pageFrontmatter:a,pageHead:c,pageHeadTitle:i,pageLang:f,pageLayout:d,routeLocale:l,siteData:on,siteLocaleData:s}},yv=()=>{const e=Sd(),t=Xa(),n=X([]),r=()=>{e.value.forEach(l=>{const s=bv(l);s&&n.value.push(s)})},o=()=>{document.documentElement.lang=t.value,n.value.forEach(l=>{l.parentNode===document.head&&document.head.removeChild(l)}),n.value.splice(0,n.value.length),e.value.forEach(l=>{const s=_v(l);s!==null&&(document.head.appendChild(s),n.value.push(s))})};Wt(Md,o),Ee(()=>{r(),o(),fe(()=>e.value,()=>o())})},bv=([e,t,n=""])=>{const r=Object.entries(t).map(([a,i])=>ue(i)?`[${a}=${JSON.stringify(i)}]`:i===!0?`[${a}]`:"").join(""),o=`head > ${e}${r}`;return Array.from(document.querySelectorAll(o)).find(a=>a.innerText===n)||null},_v=([e,t,n])=>{if(!ue(e))return null;const r=document.createElement(e);return sl(t)&&Object.entries(t).forEach(([o,l])=>{ue(l)?r.setAttribute(o,l):l===!0&&r.setAttribute(o,"")}),ue(n)&&r.appendChild(document.createTextNode(n)),r},wv=bd,Ev=async()=>{var n;const e=wv({name:"VuepressApp",setup(){var r;yv();for(const o of br)(r=o.setup)==null||r.call(o);return()=>[u(Ni),...br.flatMap(({rootComponents:o=[]})=>o.map(l=>u(l)))]}}),t=vv();mv(e),gv(e,t,br);for(const r of br)await((n=r.enhance)==null?void 0:n.call(r,{app:e,router:t,siteData:on}));return e.use(t),{app:e,router:t}};Ev().then(({app:e,router:t})=>{t.isReady().then(()=>{e.mount("#app")})});export{Q0 as A,bt as B,he as C,sl as D,Av as E,ue as F,kc as G,Pv as H,ev as L,mt as R,$a as a,Ma as b,Tv as c,Ev as createVueApp,Te as d,Cv as e,xv as f,j as g,wt as h,Pn as i,Nt as j,X as k,x as l,Se as m,fe as n,Pf as o,u as p,J0 as q,et as r,Y0 as s,Mr as t,Dp as u,Tl as v,Vu as w,Pc as x,X0 as y,G0 as z}; diff --git a/assets/cdn.html-32eea34b.js b/assets/cdn.html-32eea34b.js new file mode 100644 index 00000000..49e46228 --- /dev/null +++ b/assets/cdn.html-32eea34b.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-0a40e55e","path":"/docs/system/cdn.html","title":"使用内容分发网络","lang":"en-US","frontmatter":{"description":"如您希望改善 Hydro 的访问质量,在您的服务器带宽较小的情况下,您可以考虑使用内容分发网络,即 CDN ,通常情况下您仅需设置资源 CDN 即可大幅度改善访问质量,关于如何使用内容分发网络和使用中的任何问题请联系各大云厂商。 资源 CDN 创建并配置好资源 CDN ,在控制面板中将 server.cdn 设置项修改为 CDN 域名。(如 https...","head":[["meta",{"property":"og:url","content":"https://hydro.js.org/docs/system/cdn.html"}],["meta",{"property":"og:site_name","content":"Hydro"}],["meta",{"property":"og:title","content":"使用内容分发网络"}],["meta",{"property":"og:description","content":"如您希望改善 Hydro 的访问质量,在您的服务器带宽较小的情况下,您可以考虑使用内容分发网络,即 CDN ,通常情况下您仅需设置资源 CDN 即可大幅度改善访问质量,关于如何使用内容分发网络和使用中的任何问题请联系各大云厂商。 资源 CDN 创建并配置好资源 CDN ,在控制面板中将 server.cdn 设置项修改为 CDN 域名。(如 https..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-05-17T15:15:27.000Z"}],["meta",{"property":"article:modified_time","content":"2023-05-17T15:15:27.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"使用内容分发网络\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-05-17T15:15:27.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"资源 CDN","slug":"资源-cdn","link":"#资源-cdn","children":[]},{"level":2,"title":"全站 CDN","slug":"全站-cdn","link":"#全站-cdn","children":[]}],"git":{"createdTime":1628908242000,"updatedTime":1684336527000,"contributors":[{"name":"undefined","email":"i@undefined.moe","commits":3},{"name":"sosyz","email":"30596875+sosyz@users.noreply.github.com","commits":2},{"name":"Macesuted","email":"macesuted@qq.com","commits":1},{"name":"MasterYuan418","email":"58651976+MasterYuan418@users.noreply.github.com","commits":1},{"name":"panda","email":"panda_dtdyy@outlook.com","commits":1}]},"readingTime":{"minutes":1.35,"words":405},"filePathRelative":"docs/system/cdn.md","localizedDate":"August 14, 2021","autoDesc":true,"excerpt":""}');export{e as data}; diff --git a/assets/cdn.html-d6a583e7.js b/assets/cdn.html-d6a583e7.js new file mode 100644 index 00000000..326c079b --- /dev/null +++ b/assets/cdn.html-d6a583e7.js @@ -0,0 +1 @@ +import{_ as t}from"./plugin-vue_export-helper-c27b6911.js";import{o as d,c as e,e as r}from"./app-68b9e0b9.js";const a={},c=r('

使用内容分发网络

如您希望改善 Hydro 的访问质量,在您的服务器带宽较小的情况下,您可以考虑使用内容分发网络,即 CDN ,通常情况下您仅需设置资源 CDN 即可大幅度改善访问质量,关于如何使用内容分发网络和使用中的任何问题请联系各大云厂商。

资源 CDN

创建并配置好资源 CDN ,在控制面板中将 server.cdn 设置项修改为 CDN 域名。(如 https://cdn.hydro.ac/,以 / 结尾)。

全站 CDN

如果您预算充足,可以使用全站 CDN。

Note

全站 CDN 配置较为繁琐,如您没有相关使用经验请仅建立并配置资源 CDN ,配置资源 CDN 在大部分情况下即可大幅度改善访问质量。 因各服务商全站 CDN 配置方法不同,配置过程不同,需要配置的内容较多,以下仅为参考配置且配置补全,如果有任何问题建议先查阅云服务商文档及咨询云服务商工程师。

缓存设置可以参考以下设置:

类型内容缓存行为
全部文件全部文件遵循源站
文件后缀jpg,js,png,css,gif缓存一天

同时设置添加回源HTTP请求头

头部参数头部取值
X-Forward-For参考所使用服务商CDN文档来设置用户来源IP

且您应当修改系统设置中的 server.xff 值为 X-Forwarded-For,该设置是为了能够让系统正确获取到用户的IP地址。

',12),o=[c];function h(n,s){return d(),e("div",null,o)}const l=t(a,[["render",h],["__file","cdn.html.vue"]]);export{l as default}; diff --git a/assets/cli.html-7c5afadb.js b/assets/cli.html-7c5afadb.js new file mode 100644 index 00000000..b12d1c8f --- /dev/null +++ b/assets/cli.html-7c5afadb.js @@ -0,0 +1,32 @@ +import{_ as r}from"./plugin-vue_export-helper-c27b6911.js";import{r as l,o as t,c,a,b as s,d as o,w as E,e as n}from"./app-68b9e0b9.js";const y={},i=n(`

Hydro Cli

Tips

在使用 cli 之前,请完成数据库配置。
指令中使用 <> 括起来的参数必须给出,用 [] 括起来的参数可以给出,若不给出则按照默认设置。
用户请根据自己的情况替换掉用 <> 或是 [] 包括起来的部分(括号也应替换)

cli 可以帮助用户在控制台下快捷地进行一些操作。
这些命令需要以在终端以 root 用户执行(安装时执行命令的位置)。
下面给出了一些常用的例子。

创建用户

Tips

很少使用。建议通过 控制面板>导入用户 功能代替

hydrooj cli user create <mail> <username> <password> <uid>
+# 该用户的邮箱、用户名和密码
+
+# 如创建邮箱为 hydro@hydro.local,用户名为 Hydro,密码为 hydrohydro ,UID 为 2 的用户:
+# 请确保 UID 为不小于 2 的正整数且未被占用,邮箱和用户名均不重复。
+hydrooj cli user create hydro@hydro.local Hydro hydrohydro 2
+

若一切正常,运行该指令后您会从命令行窗口中看到该用户 uid。

设置全站管理员

hydrooj cli user setSuperAdmin <uid>
+
+# 如设置 uid 为 2 的用户为管理员:
+hydrooj cli user setSuperAdmin 2
+

设置用户权限

hydrooj cli user setPriv <uid> <priv>
+
`,11),d=a("code",null,"[priv]",-1),D=n(`

更改用户密码

hydrooj cli user setPassword <uid> <password>
+
+# 如将 uid 为 1 的用户的密码改为 hydrohydro:
+hydrooj cli user setPassword 1 hydrohydro
+

创建评测账号

创建一个账号

您需要留意运行此指令返回的数字,表示该用户的 uid,需要填入下面的指令中,然后给予该账号评测权限。

hydrooj cli user setJudge <uid>
+

完成后将配置的用户名及密码写入评测机配置文件,评测机即可连接到网页端。

黑名单相关

用户封禁:

hydrooj cli user setPriv <uid> 0
+

IP/邮箱域名封禁:

# key 格式为 ip::xxx.xxx.xxx.xxx (封禁 IP 访问) 或是 mail::xxx.com (禁止 xxx.com 的邮箱注册)
+hydrooj cli blacklist add <key> [duration] # 将 <key> 拉入黑名单,时长为 [duration] (以月为单位的整数,默认为 12,若 duration=0 则永久封禁)
+hydrooj cli blacklist get <key> # 获取黑名单中有关 <key> 的信息
+hydrooj cli blacklist del <key> # 将 <key> 移出黑名单
+

命令列表

`,13),F={href:"https://github.com/hydro-dev/Hydro/tree/master/packages/hydrooj/src/model",target:"_blank",rel:"noopener noreferrer"},C=n(`

这里并没有列出所有可以运行的指令,因为其中很多功能我们更推荐通过 Web 访问。

hydrooj cli user create <mail> <uname> <password> [uid] [regip] [priv]
+# 创建邮箱为 <mail>,用户名为 <uname>,密码为 <password>,ID 为 [uid],注册 ip 为 [regip],权限为 [priv] 的用户
+hydrooj cli user setUname <uid> <unmae> # 将 ID 为 <uid> 的用户的用户名设置为 <uname>
+hydrooj cli user setPriv <uid> <priv> # 将 ID 为 <uid> 的用户的权限设为 <priv>
+hydrooj cli user setPassword <uid> <password> # 将 ID 为 <uid> 的用户的密码设置为 <password>
+hydrooj cli user setEmail <uid> <mail> # 将 ID 为 <uid> 的用户的邮箱设置为 <mail>
+hydrooj cli user setSuperAdmin <uid> # 将 ID 为 <uid> 的用户设为全站管理员
+hydrooj cli problem import <domainId> <file/path> # 将 <file/path> 的Hydro格式题目包导入至 <domainId> 域中
+hydrooj cli problem export <domainId> # 将 <domainId> 域中的所有题目包导出
+hydrooj cli system set <key> <value> # 修改系统设置 <key> 值为 <value>
+
`,2);function A(u,h){const p=l("RouterLink"),e=l("ExternalLinkIcon");return t(),c("div",null,[i,a("p",null,[s("关于参数 "),d,s(" ,可阅读 "),o(p,{to:"/dev/PERM_PRIV/"},{default:E(()=>[s("此处")]),_:1}),s("。")]),D,a("p",null,[s("所有于 "),a("a",F,[s("此文件夹"),o(e)]),s(" 下的函数均可用 cli 调用。")]),C])}const m=r(y,[["render",A],["__file","cli.html.vue"]]);export{m as default}; diff --git a/assets/cli.html-a2d90d68.js b/assets/cli.html-a2d90d68.js new file mode 100644 index 00000000..53db8a62 --- /dev/null +++ b/assets/cli.html-a2d90d68.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-cceda784","path":"/docs/system/cli.html","title":"Hydro Cli","lang":"en-US","frontmatter":{"description":"在使用 cli 之前,请完成数据库配置。 指令中使用 括起来的参数必须给出,用 [] 括起来的参数可以给出,若不给出则按照默认设置。 用户请根据自己的情况替换掉用 或是 [] 包括起来的部分(括号也应替换) cli 可以帮助用户在控制台下快捷地进行一些操作。 这些命令需要以在终端以 root 用户执行(安装时执行命令的位置)。 下面给出了一些常用的例子...","head":[["meta",{"property":"og:url","content":"https://hydro.js.org/docs/system/cli.html"}],["meta",{"property":"og:site_name","content":"Hydro"}],["meta",{"property":"og:title","content":"Hydro Cli"}],["meta",{"property":"og:description","content":"在使用 cli 之前,请完成数据库配置。 指令中使用 括起来的参数必须给出,用 [] 括起来的参数可以给出,若不给出则按照默认设置。 用户请根据自己的情况替换掉用 或是 [] 包括起来的部分(括号也应替换) cli 可以帮助用户在控制台下快捷地进行一些操作。 这些命令需要以在终端以 root 用户执行(安装时执行命令的位置)。 下面给出了一些常用的例子..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-05-12T03:18:30.000Z"}],["meta",{"property":"article:modified_time","content":"2023-05-12T03:18:30.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Hydro Cli\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-05-12T03:18:30.000Z\\",\\"author\\":[]}"]]},"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":[]}],"git":{"createdTime":1632364924000,"updatedTime":1683861510000,"contributors":[{"name":"Macesuted","email":"macesuted@qq.com","commits":1},{"name":"panda","email":"panda_dtdyy@outlook.com","commits":1},{"name":"undefined","email":"i@undefined.moe","commits":1}]},"readingTime":{"minutes":2.75,"words":824},"filePathRelative":"docs/system/cli.md","localizedDate":"September 23, 2021","autoDesc":true,"excerpt":""}');export{e as data}; diff --git a/assets/compiler.html-128a8b13.js b/assets/compiler.html-128a8b13.js new file mode 100644 index 00000000..1a9c80e9 --- /dev/null +++ b/assets/compiler.html-128a8b13.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-fdd5d9ea","path":"/docs/install/compiler.html","title":"编译器","lang":"en-US","frontmatter":{"description":"从 2022/8/12 开始,Hydro 为了避免宿主机环境变化对于评测的影响,对于 此后新安装的实例 默认使用 nix () 管理环境。 如果你是在这之前安装的 Hydro,请使用 apt 安装编译器后使用 pm2 restart hydro-sandbox 重启沙箱,并忽略本章节。 以下是 nix 的简要操作说明: 使用 nix-env -iA n...","head":[["meta",{"property":"og:url","content":"https://hydro.js.org/docs/install/compiler.html"}],["meta",{"property":"og:site_name","content":"Hydro"}],["meta",{"property":"og:title","content":"编译器"}],["meta",{"property":"og:description","content":"从 2022/8/12 开始,Hydro 为了避免宿主机环境变化对于评测的影响,对于 此后新安装的实例 默认使用 nix () 管理环境。 如果你是在这之前安装的 Hydro,请使用 apt 安装编译器后使用 pm2 restart hydro-sandbox 重启沙箱,并忽略本章节。 以下是 nix 的简要操作说明: 使用 nix-env -iA n..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-02-26T07:44:01.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-26T07:44:01.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"编译器\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-26T07:44:01.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"进阶","slug":"进阶","link":"#进阶","children":[]}],"git":{"createdTime":1660293799000,"updatedTime":1677397441000,"contributors":[{"name":"undefined","email":"i@undefined.moe","commits":3}]},"readingTime":{"minutes":1.98,"words":593},"filePathRelative":"docs/install/compiler.md","localizedDate":"August 12, 2022","autoDesc":true,"excerpt":""}');export{e as data}; diff --git a/assets/compiler.html-6d1c02e2.js b/assets/compiler.html-6d1c02e2.js new file mode 100644 index 00000000..69c128cc --- /dev/null +++ b/assets/compiler.html-6d1c02e2.js @@ -0,0 +1,38 @@ +import{_ as o}from"./plugin-vue_export-helper-c27b6911.js";import{r as e,o as c,c as r,a as n,b as s,d as l,e as p}from"./app-68b9e0b9.js";const t={},E=p('

编译器

从 2022/8/12 开始,Hydro 为了避免宿主机环境变化对于评测的影响,对于 此后新安装的实例 默认使用 nix 管理环境。
如果你是在这之前安装的 Hydro,请使用 apt 安装编译器后使用 pm2 restart hydro-sandbox 重启沙箱,并忽略本章节。

以下是 nix 的简要操作说明:

使用 nix-env -iA nixpkgs.编译器名 安装新编译器,后重启沙箱 pm2 restart hydro-sandbox 生效。

',4),i={href:"https://search.nixos.org/packages",target:"_blank",rel:"noopener noreferrer"},y=n("br",null,null,-1),D=p(`
nix-env -iA nixpkgs.busybox nixpkgs.bash nixpkgs.diffutils nixpkgs.unzip # 基础组件,已预装,不建议删除
+nix-env -iA nixpkgs.gcc nixpkgs.fpc # C/C++ 和 Pascal,已预装,不建议删除
+nix-env -iA nixpkgs.ghc # Haskell 
+nix-env -iA nixpkgs.rustc # Rust
+nix-env -iA nixpkgs.python2 # Python2
+nix-env -iA nixpkgs.pythonPackages.numpy # Python2 Numpy 库
+nix-env -iA nixpkgs.python3Minimal
+nix-env -iA nixpkgs.python3Packages.numpy
+nix-env -iA nixpkgs.php # PHP
+nix-env -iA nixpkgs.go # Golang
+nix-env -iA nixpkgs.nodejs # NodeJS
+nix-env -iA nixpkgs.openjdk_headless # Java
+nix-env -iA nixpkgs.ruby # Ruby
+nix-env -iA nixpkgs.mono # C#
+nix-env -iA nixpkgs.julia_17-bin # Julia
+

使用 nix-env -q 查看已安装的列表,后使用 nix-env -e 编译器名 即可删除对应的编译器。
请注意不要误删 Hydro 基础组件,且操作完成后需要重启沙箱 pm2 restart hydro-sandbox 生效。

进阶

如果你需要更加复杂的编译环境配置,我们建议使用编写单独的 nix 文件。

{ 
+  system ? builtins.currentSystem,
+  pkgs ? import <nixpkgs> { system = system; }
+}:
+
+pkgs.buildEnv {
+  name = "hydrojudge-rootfs";
+  paths = with pkgs; [
+    coreutils bash diffutils nix zip unzip gcc
+    # 上方包是评测所需要的,请勿删除,
+    # 在下方列出你所需要的包,查找方式同上文:
+    fpc python3 rustc
+  ];
+  ignoreCollisions = true;
+  pathsToLink = [ "/" ];
+  # 导出一些基本信息和部分编译器所需的 /etc/passwd
+  postBuild = ''
+    mkdir $out/buildInfo
+    echo 'root:x:0:0:root:/root:/bin/bash' >$out/etc/passwd
+    date >$out/buildInfo/timestamp
+  '';
+}
+

复制以上文件,保存为 default.nix ,使用 nix-build 进行构建。
构建后会产生一个 result 文件夹,记住该文件夹所在的路径。
打开 ~/.hydro/mount.yaml 将其中 /root/.nix-profile 替换为编译出的 result 文件夹(切换到新的环境)
之后保存并重启沙箱。

后续若需更改环境配置,仅需要修改 default.nix 文件之后 nix-build 重新构建,再重启沙箱即可生效。
构建过程中的缓存文件可以使用 nix-collect-garbage 进行清理。

`,7),F={href:"https://nixos.org/guides/nix-language.html",target:"_blank",rel:"noopener noreferrer"},d={href:"https://nixos.org/manual/nix/stable/language/index.html",target:"_blank",rel:"noopener noreferrer"};function v(u,C){const a=e("ExternalLinkIcon");return c(),r("div",null,[E,n("p",null,[s("可以在 "),n("a",i,[s("Nixos Search"),l(a)]),s(" 中搜索你需要的编译器。"),y,s(" 以下是常用编译器的示例:")]),D,n("p",null,[s("更详细的 nix 语言介绍,请参照 "),n("a",F,[s("Nix Guide"),l(a)]),s(" 和 "),n("a",d,[s("Nix Manual"),l(a)]),s("。")])])}const m=o(t,[["render",v],["__file","compiler.html.vue"]]);export{m as default}; diff --git a/assets/copy-problem.html-28f2f939.js b/assets/copy-problem.html-28f2f939.js new file mode 100644 index 00000000..f8ed4ab4 --- /dev/null +++ b/assets/copy-problem.html-28f2f939.js @@ -0,0 +1 @@ +import{_ as e}from"./plugin-vue_export-helper-c27b6911.js";import{o as a,c as i,e as r}from"./app-68b9e0b9.js";const l={},t=r('

复制题目

复制题目可以帮助用户将任何有权提交的题目复制到有权创建题目的域中以在比赛/作业/训练计划中使用这些题目。

操作流程

  1. 进入需要复制的题目页面或是题目列表页面。
  2. 点击右侧栏底部的“复制”按钮或是多选题目后点击右侧复制题目按钮。
  3. 在弹出的窗口中输入需要复制到的域的 ID。
  4. 点击“确定”后将自动跳转到复制后的题目连接。

限制

  • 不允许查看/修改复制后的题目的测试数据。
  • 不能复制一个复制来的题目。
  • 部分题目可能不允许复制。这遵循 域设置>编辑域资料 中的管理员设定。
',6),o=[t];function c(n,h){return a(),i("div",null,o)}const _=e(l,[["render",c],["__file","copy-problem.html.vue"]]);export{_ as default}; diff --git a/assets/copy-problem.html-3012fdb5.js b/assets/copy-problem.html-3012fdb5.js new file mode 100644 index 00000000..f4e5d702 --- /dev/null +++ b/assets/copy-problem.html-3012fdb5.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-62edc12e","path":"/docs/user/copy-problem.html","title":"复制题目","lang":"en-US","frontmatter":{"description":"复制题目可以帮助用户将任何有权提交的题目复制到有权创建题目的域中以在比赛/作业/训练计划中使用这些题目。 操作流程 1. 进入需要复制的题目页面或是题目列表页面。 2. 点击右侧栏底部的“复制”按钮或是多选题目后点击右侧复制题目按钮。 3. 在弹出的窗口中输入需要复制到的域的 ID。 4. 点击“确定”后将自动跳转到复制后的题目连接。 限制 不允许查看...","head":[["meta",{"property":"og:url","content":"https://hydro.js.org/docs/user/copy-problem.html"}],["meta",{"property":"og:site_name","content":"Hydro"}],["meta",{"property":"og:title","content":"复制题目"}],["meta",{"property":"og:description","content":"复制题目可以帮助用户将任何有权提交的题目复制到有权创建题目的域中以在比赛/作业/训练计划中使用这些题目。 操作流程 1. 进入需要复制的题目页面或是题目列表页面。 2. 点击右侧栏底部的“复制”按钮或是多选题目后点击右侧复制题目按钮。 3. 在弹出的窗口中输入需要复制到的域的 ID。 4. 点击“确定”后将自动跳转到复制后的题目连接。 限制 不允许查看..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2022-02-25T15:35:42.000Z"}],["meta",{"property":"article:modified_time","content":"2022-02-25T15:35:42.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"复制题目\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2022-02-25T15:35:42.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"操作流程","slug":"操作流程","link":"#操作流程","children":[]},{"level":2,"title":"限制","slug":"限制","link":"#限制","children":[]}],"git":{"createdTime":1636103902000,"updatedTime":1645803342000,"contributors":[{"name":"undefined","email":"i@undefined.moe","commits":2},{"name":"Macesuted","email":"i@macesuted.moe","commits":1}]},"readingTime":{"minutes":0.7,"words":210},"filePathRelative":"docs/user/copy-problem.md","localizedDate":"November 5, 2021","autoDesc":true,"excerpt":""}');export{e as data}; diff --git a/assets/database.html-40e6aaf2.js b/assets/database.html-40e6aaf2.js new file mode 100644 index 00000000..96fcff48 --- /dev/null +++ b/assets/database.html-40e6aaf2.js @@ -0,0 +1 @@ +import{_ as n}from"./plugin-vue_export-helper-c27b6911.js";import{r,o as d,c as s,a as o,b as e,d as t,e as c}from"./app-68b9e0b9.js";const h={},l=c('

数据库备份和恢复

进入数据库

请参考 FAQS 内的数据库连接教程。

快速备份与恢复

为了保证数据安全,请定期备份。

若您使用自动脚本安装,可使用 hydrooj backup 快捷备份数据,备份完成后会在当前目录生成备份压缩包文件,您可使用 hydrooj restore <备份文件路径> 恢复之前备份的数据。

手动备份

',7),i={href:"https://docs.mongodb.com/database-tools/mongodump/",target:"_blank",rel:"noopener noreferrer"},_=o("code",null,"/data/file",-1),u=o("p",null,[e("对于数据库,请"),o("strong",null,"请不要在数据库运行时直接拷贝数据库文件夹"),e("。请每次备份后检查生成的备份文件的大小和内容,确保备份成功。"),o("br"),e(" 请不要把备份数据和 Hydro 系统放在同一台机器上,这样数据丢失的风险仍然较高。")],-1),p=o("h2",{id:"手动恢复备份",tabindex:"-1"},[o("a",{class:"header-anchor",href:"#手动恢复备份","aria-hidden":"true"},"#"),e(" 手动恢复备份")],-1),f={href:"https://docs.mongodb.com/database-tools/mongorestore/",target:"_blank",rel:"noopener noreferrer"},m=o("code",null,"/data/file",-1),b=o("br",null,null,-1),g=o("strong",null,"停止 Hydro 和 MongoDB 服务后",-1),x=o("code",null,"/data/db",-1),k=o("code",null,"/data/file",-1),B=o("code",null,"/root/.hydro/config.json",-1);function y(N,V){const a=r("ExternalLinkIcon");return d(),s("div",null,[l,o("p",null,[e("可使用 MongoDB 自带的 "),o("a",i,[e("mongodump"),t(a)]),e(" 进行数据库备份。并将 "),_,e(" 文件夹备份即可。")]),u,p,o("p",null,[e("使用 MongoDB 自带的 "),o("a",f,[e("mongorestore"),t(a)]),e(" 导入备份的数据库文件,并还原 "),m,e(" 目录文件。"),b,e(" 如果只是想不同机器之间迁移部署,只需要在"),g,e("将相关文件夹(通常为 "),x,e(" 与 "),k,e(" 与 "),B,e(" )复制即可。")])])}const D=n(h,[["render",y],["__file","database.html.vue"]]);export{D as default}; diff --git a/assets/database.html-71ac4dd0.js b/assets/database.html-71ac4dd0.js new file mode 100644 index 00000000..d75f7187 --- /dev/null +++ b/assets/database.html-71ac4dd0.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-2250b6d9","path":"/docs/system/database.html","title":"数据库备份和恢复","lang":"en-US","frontmatter":{"description":"进入数据库 请参考 FAQS 内的数据库连接教程。 快速备份与恢复 为了保证数据安全,请定期备份。 若您使用自动脚本安装,可使用 hydrooj backup 快捷备份数据,备份完成后会在当前目录生成备份压缩包文件,您可使用 hydrooj restore 恢复之前备份的数据。 手动备份 可使用 MongoDB 自带的 mongodump (https...","head":[["meta",{"property":"og:url","content":"https://hydro.js.org/docs/system/database.html"}],["meta",{"property":"og:site_name","content":"Hydro"}],["meta",{"property":"og:title","content":"数据库备份和恢复"}],["meta",{"property":"og:description","content":"进入数据库 请参考 FAQS 内的数据库连接教程。 快速备份与恢复 为了保证数据安全,请定期备份。 若您使用自动脚本安装,可使用 hydrooj backup 快捷备份数据,备份完成后会在当前目录生成备份压缩包文件,您可使用 hydrooj restore 恢复之前备份的数据。 手动备份 可使用 MongoDB 自带的 mongodump (https..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-11-06T08:41:11.000Z"}],["meta",{"property":"article:modified_time","content":"2023-11-06T08:41:11.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"数据库备份和恢复\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-11-06T08:41:11.000Z\\",\\"author\\":[]}"]]},"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":[]}],"git":{"createdTime":1628908242000,"updatedTime":1699260071000,"contributors":[{"name":"undefined","email":"i@undefined.moe","commits":3},{"name":"panda","email":"panda_dtdyy@outlook.com","commits":2},{"name":"Macesuted","email":"macesuted@qq.com","commits":1}]},"readingTime":{"minutes":1.02,"words":305},"filePathRelative":"docs/system/database.md","localizedDate":"August 14, 2021","autoDesc":true,"excerpt":""}');export{e as data}; diff --git a/assets/domain.html-a4ae0e2c.js b/assets/domain.html-a4ae0e2c.js new file mode 100644 index 00000000..bad2ad83 --- /dev/null +++ b/assets/domain.html-a4ae0e2c.js @@ -0,0 +1,27 @@ +import{_ as s}from"./plugin-vue_export-helper-c27b6911.js";import{o as n,c as a,e as l}from"./app-68b9e0b9.js";const e={},o=l(`

简介

域功能类似团队,允许在一套系统中创建多个环境(如不同班级,或是不同功能,等等)
用户可以创建多个域。(需要用户有 PRIV_CREATE_DOMAIN 权限,默认仅开放给管理员账户)。 域间数据完全独立,仅用户信息相通(注册账户后,在该实例的所有域中均有效)。

创建域

登录账号后,在“我的”选项卡中找到“我的域”,并点击“创建域”,填入以下信息:

  • ID: 每个域有一个唯一的 ID,将会在域 URL 中体现。创建后无法修改。
  • 名称: 域的名字,创建后可以更改。
  • 公告: 域主页上显示的公告,创建后可以更改。
  • avatar: 域头像,与用户头像同理,可以使用 gravatar:emailqq:idgithub:nameurl:link 的格式添加。将会在“我的域”界面内显示。

创建域后,您将在此域中拥有管理员权限,可以在域内进行添加题目/创建比赛等操作。

初始化讨论节点

您可以在“管理域”选项卡中点击“初始化讨论节点”按钮初始化讨论节点。

访问控制

未登录用户将默认使用 guest 权限,登录用户将默认使用 default 权限。(所以将登陆用户设为 default 权限后并不会显示在“管理用户”页内,这也表示所有用户默认不会出现在管理列表中)
所以将一个用户的权限设为 default 和将用户移出该域是等价的。

对于不在列表中的用户,点击右上角“添加用户”,在左侧选中用户,右侧选择权限组,再点击“确定”即可。

创建比赛/作业

若您想要创建比赛/作业,您可以在“比赛”或“作业”选项卡中,在页面右侧找到“创建”按钮, 题目一栏支持根据题目ID或是题目名自动筛选。设置完后可点击“创建”按钮创建比赛(描述这类的框不知道写啥就随便填,不能留空)。

Tips

若因为删除作业/比赛内题目导致无法打开,可以通过 /contest/<id>/edit/homework/<id>/edit(即在无法打开的页面页面后加上 /edit)直接访问编辑页并修正。

创建训练

若您想要创建训练,您可以在“训练” 项卡中点击“新建训练计划”,填写以下信息:

  • 标题:该训练的标题;
  • 简介:该训练的简介,会与标题同时显示在列表页面中;
  • 说明:该训练的详细信息;
  • 计划:该训练的具体题目及计划信息,其格式如下:
[
+  {章节详细信息},
+  {章节详细信息},
+  ...
+  {章节详细信息}
+]
+

其中,“章节详细信息”的包含以下部分:

  • _id:章节数字编号;
  • title:章节标题;
  • requireNids:训练此章节之前需要完成的章节数字编号,若无要求则留空,若有多个则使用逗号分隔;
  • pids:此章节中包含的题目的 ID,若有多个则使用逗号分隔。

举例:若要在训练中创建三个章节,章节中分别有 ID 为 1,2,3 的题目。其中章节一、二无前置条件,章节三需要同时完成章节一、二后才能进行,则格式如下:

[
+  {
+    "_id": 1,
+    "title": "入门",
+    "requireNids": [],
+    "pids": [1]
+  },
+  {
+    "_id": 2,
+    "title": "精通",
+    "requireNids": [],
+    "pids": [2]
+  },
+  {
+    "_id": 3,
+    "title": "大师",
+    "requireNids": [1,2],
+    "pids": [3]
+  }
+]
+

Tips

若因为删除训练计划内题目导致训练计划无法打开,可以通过 /training/<id>/edit(即训练计划页面后加上 /edit)直接访问训练计划编辑页并修正配置文件。

`,24),p=[o];function c(t,r){return n(),a("div",null,p)}const F=s(e,[["render",c],["__file","domain.html.vue"]]);export{F as default}; diff --git a/assets/domain.html-f07b2a6b.js b/assets/domain.html-f07b2a6b.js new file mode 100644 index 00000000..a27e52e2 --- /dev/null +++ b/assets/domain.html-f07b2a6b.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-0566f368","path":"/docs/user/domain.html","title":"域","lang":"en-US","frontmatter":{"description":"简介 域功能类似团队,允许在一套系统中创建多个环境(如不同班级,或是不同功能,等等) 用户可以创建多个域。(需要用户有 PRIVCREATEDOMAIN 权限,默认仅开放给管理员账户)。 域间数据完全独立,仅用户信息相通(注册账户后,在该实例的所有域中均有效)。 创建域 登录账号后,在“我的”选项卡中找到“我的域”,并点击“创建域”,填入以下信息: I...","head":[["meta",{"property":"og:url","content":"https://hydro.js.org/docs/user/domain.html"}],["meta",{"property":"og:site_name","content":"Hydro"}],["meta",{"property":"og:title","content":"域"}],["meta",{"property":"og:description","content":"简介 域功能类似团队,允许在一套系统中创建多个环境(如不同班级,或是不同功能,等等) 用户可以创建多个域。(需要用户有 PRIVCREATEDOMAIN 权限,默认仅开放给管理员账户)。 域间数据完全独立,仅用户信息相通(注册账户后,在该实例的所有域中均有效)。 创建域 登录账号后,在“我的”选项卡中找到“我的域”,并点击“创建域”,填入以下信息: I..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-03-20T01:53:27.000Z"}],["meta",{"property":"article:modified_time","content":"2023-03-20T01:53:27.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"域\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-03-20T01:53:27.000Z\\",\\"author\\":[]}"]]},"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":[]}],"git":{"createdTime":1628829220000,"updatedTime":1679277207000,"contributors":[{"name":"(Macesuted)","email":"1912192337@qq.com","commits":2},{"name":"undefined","email":"i@undefined.moe","commits":2},{"name":"Macesuted","email":"macesuted@qq.com","commits":1},{"name":"juruo888","email":"95965215+juruo888@users.noreply.github.com","commits":1}]},"readingTime":{"minutes":3.13,"words":940},"filePathRelative":"docs/user/domain.md","localizedDate":"August 13, 2021","autoDesc":true,"excerpt":""}');export{e as data}; diff --git a/assets/elastic.html-ac4671fb.js b/assets/elastic.html-ac4671fb.js new file mode 100644 index 00000000..3833aa20 --- /dev/null +++ b/assets/elastic.html-ac4671fb.js @@ -0,0 +1 @@ +import{_ as s}from"./plugin-vue_export-helper-c27b6911.js";import{o as c,c as a,a as e,b as t}from"./app-68b9e0b9.js";const o={},l=e("h1",{id:"elastic-search",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#elastic-search","aria-hidden":"true"},"#"),t(" Elastic search")],-1),n=e("p",null,[t("安装 Elasticsearch 后安装 "),e("code",null,"@hydrooj/elastic-search"),t(" 插件。")],-1),r=e("p",null,"进入 HydroOJ 控制面板,在系统设置内正确填写endpoint。",-1),i=e("p",null,"然后在脚本管理中找到重建题目索引,点击运行,参数留空即可。",-1),_=e("p",null,"至此,搜索功能应当可以正常使用。",-1),d=[l,n,r,i,_];function h(u,p){return c(),a("div",null,d)}const x=s(o,[["render",h],["__file","elastic.html.vue"]]);export{x as default}; diff --git a/assets/elastic.html-d20c72b1.js b/assets/elastic.html-d20c72b1.js new file mode 100644 index 00000000..769309d6 --- /dev/null +++ b/assets/elastic.html-d20c72b1.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-d67234a8","path":"/plugins/elastic.html","title":"Elastic search","lang":"en-US","frontmatter":{"description":"安装 Elasticsearch 后安装 @hydrooj/elastic-search 插件。 进入 HydroOJ 控制面板,在系统设置内正确填写endpoint。 然后在脚本管理中找到重建题目索引,点击运行,参数留空即可。 至此,搜索功能应当可以正常使用。","head":[["meta",{"property":"og:url","content":"https://hydro.js.org/plugins/elastic.html"}],["meta",{"property":"og:site_name","content":"Hydro"}],["meta",{"property":"og:title","content":"Elastic search"}],["meta",{"property":"og:description","content":"安装 Elasticsearch 后安装 @hydrooj/elastic-search 插件。 进入 HydroOJ 控制面板,在系统设置内正确填写endpoint。 然后在脚本管理中找到重建题目索引,点击运行,参数留空即可。 至此,搜索功能应当可以正常使用。"}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-05-12T03:18:30.000Z"}],["meta",{"property":"article:modified_time","content":"2023-05-12T03:18:30.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Elastic search\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-05-12T03:18:30.000Z\\",\\"author\\":[]}"]]},"headers":[],"git":{"createdTime":1665539184000,"updatedTime":1683861510000,"contributors":[{"name":"panda","email":"panda_dtdyy@outlook.com","commits":1},{"name":"undefined","email":"i@undefined.moe","commits":1}]},"readingTime":{"minutes":0.23,"words":70},"filePathRelative":"plugins/elastic.md","localizedDate":"October 12, 2022","autoDesc":true,"excerpt":""}');export{e as data}; diff --git a/assets/fps-importer.html-c0843f3a.js b/assets/fps-importer.html-c0843f3a.js new file mode 100644 index 00000000..02645de8 --- /dev/null +++ b/assets/fps-importer.html-c0843f3a.js @@ -0,0 +1 @@ +import{_ as e}from"./plugin-vue_export-helper-c27b6911.js";import{o as r,c as s,e as t}from"./app-68b9e0b9.js";const a={},i=t('

fps-importer

从 fps 文件导入题目

在题库右侧“创建题目”一栏中选择“从 FPS 文件导入”。
在打开的窗口中,您可以上传:

  • fps 格式的 xml 文件
  • zip 文件,其中包含了一个或多个 fps 格式的 xml 文件

由于防止解析 fps 文件消耗大量内存,将拒绝导入超过 64MiB 的文件。
xml 文件需要为 UTF8 编码,否则可能出现中文题面乱码;
若您的文件超过大小限制,可考虑先在本地使用 Easy-Fps-Viewer 等工具进行拆分。

',5),p=[i];function o(c,f){return r(),s("div",null,p)}const d=e(a,[["render",o],["__file","fps-importer.html.vue"]]);export{d as default}; diff --git a/assets/fps-importer.html-d4ca2ee2.js b/assets/fps-importer.html-d4ca2ee2.js new file mode 100644 index 00000000..407b07c9 --- /dev/null +++ b/assets/fps-importer.html-d4ca2ee2.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-6dd45d9b","path":"/plugins/fps-importer.html","title":"fps-importer","lang":"en-US","frontmatter":{"description":"从 fps 文件导入题目 在题库右侧“创建题目”一栏中选择“从 FPS 文件导入”。 在打开的窗口中,您可以上传: fps 格式的 xml 文件; zip 文件,其中包含了一个或多个 fps 格式的 xml 文件; 由于防止解析 fps 文件消耗大量内存,将拒绝导入超过 64MiB 的文件。 xml 文件需要为 UTF8 编码,否则可能出现中文题面乱码...","head":[["meta",{"property":"og:url","content":"https://hydro.js.org/plugins/fps-importer.html"}],["meta",{"property":"og:site_name","content":"Hydro"}],["meta",{"property":"og:title","content":"fps-importer"}],["meta",{"property":"og:description","content":"从 fps 文件导入题目 在题库右侧“创建题目”一栏中选择“从 FPS 文件导入”。 在打开的窗口中,您可以上传: fps 格式的 xml 文件; zip 文件,其中包含了一个或多个 fps 格式的 xml 文件; 由于防止解析 fps 文件消耗大量内存,将拒绝导入超过 64MiB 的文件。 xml 文件需要为 UTF8 编码,否则可能出现中文题面乱码..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2022-12-09T10:31:58.000Z"}],["meta",{"property":"article:modified_time","content":"2022-12-09T10:31:58.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"fps-importer\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2022-12-09T10:31:58.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"从 fps 文件导入题目","slug":"从-fps-文件导入题目","link":"#从-fps-文件导入题目","children":[]}],"git":{"createdTime":1618895412000,"updatedTime":1670581918000,"contributors":[{"name":"Macesuted","email":"macesuted@qq.com","commits":2},{"name":"undefined","email":"i@undefined.moe","commits":2},{"name":"Macesuted","email":"57275149+Macesuted@users.noreply.github.com","commits":1}]},"readingTime":{"minutes":0.49,"words":146},"filePathRelative":"plugins/fps-importer.md","localizedDate":"April 20, 2021","autoDesc":true,"excerpt":""}');export{e as data}; diff --git a/assets/frontend-modify.html-2c65da3b.js b/assets/frontend-modify.html-2c65da3b.js new file mode 100644 index 00000000..47ab15b0 --- /dev/null +++ b/assets/frontend-modify.html-2c65da3b.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-023b4bae","path":"/docs/system/frontend-modify.html","title":"前端修改","lang":"en-US","frontmatter":{"description":"此指南将教您修改前端文件。 如果您正在使用开发者模式,请直接修改 packages/ui-default/templates 下的文件。 如果您使用安装脚本部署: 请先使用 hydrooj addon create 创建一个本地插件(如果之前没有做过的话)。 修改页面翻译或是添加新语言: 修改翻译:在 zh.yaml (https://github.c...","head":[["meta",{"property":"og:url","content":"https://hydro.js.org/docs/system/frontend-modify.html"}],["meta",{"property":"og:site_name","content":"Hydro"}],["meta",{"property":"og:title","content":"前端修改"}],["meta",{"property":"og:description","content":"此指南将教您修改前端文件。 如果您正在使用开发者模式,请直接修改 packages/ui-default/templates 下的文件。 如果您使用安装脚本部署: 请先使用 hydrooj addon create 创建一个本地插件(如果之前没有做过的话)。 修改页面翻译或是添加新语言: 修改翻译:在 zh.yaml (https://github.c..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2022-02-25T15:35:42.000Z"}],["meta",{"property":"article:modified_time","content":"2022-02-25T15:35:42.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"前端修改\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2022-02-25T15:35:42.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"修改页面翻译或是添加新语言:","slug":"修改页面翻译或是添加新语言","link":"#修改页面翻译或是添加新语言","children":[]},{"level":2,"title":"修改页面模板:","slug":"修改页面模板","link":"#修改页面模板","children":[]}],"git":{"createdTime":1627709441000,"updatedTime":1645803342000,"contributors":[{"name":"undefined","email":"i@undefined.moe","commits":3},{"name":"Macesuted","email":"macesuted@qq.com","commits":1}]},"readingTime":{"minutes":1.04,"words":312},"filePathRelative":"docs/system/frontend-modify.md","localizedDate":"July 31, 2021","autoDesc":true,"excerpt":""}');export{e as data}; diff --git a/assets/frontend-modify.html-73d58e09.js b/assets/frontend-modify.html-73d58e09.js new file mode 100644 index 00000000..e8197fe1 --- /dev/null +++ b/assets/frontend-modify.html-73d58e09.js @@ -0,0 +1 @@ +import{_ as n}from"./plugin-vue_export-helper-c27b6911.js";import{r as l,o as r,c as d,a as o,b as e,d as a,e as s}from"./app-68b9e0b9.js";const c={},h=s('

前端修改

此指南将教您修改前端文件。

如果您正在使用开发者模式,请直接修改 packages/ui-default/templates 下的文件。

如果您使用安装脚本部署:

请先使用 hydrooj addon create 创建一个本地插件(如果之前没有做过的话)。

修改页面翻译或是添加新语言:

',6),i={href:"https://github.com/hydro-dev/Hydro/blob/master/packages/ui-default/locales/zh.yaml",target:"_blank",rel:"noopener noreferrer"},_=o("strong",null,"其所在行而非整个文件",-1),u=o("code",null,"~/addon/locales/zh.yaml",-1),p={href:"https://github.com/hydro-dev/Hydro/blob/master/packages/ui-default/locales/zh.yaml",target:"_blank",rel:"noopener noreferrer"},m=o("h2",{id:"修改页面模板",tabindex:"-1"},[o("a",{class:"header-anchor",href:"#修改页面模板","aria-hidden":"true"},"#"),e(" 修改页面模板:")],-1),f=o("code",null,"view-source:",-1),y=o("code",null,"view-source:https://hydro.ac",-1),b=o("code",null,'',-1),g=o("code",null,"data-page",-1),x=o("code",null,"main.html",-1),k={href:"https://github.com/hydro-dev/Hydro/tree/master/packages/ui-default/templates",target:"_blank",rel:"noopener noreferrer"},v=o("strong",null,"文件的全部内容",-1),z=o("code",null,"~/addon/templates/",-1),H=o("p",null,[e("特别的,创建题目时的默认模板位于 "),o("code",null,"partials/problem_default.md"),e(",创建训练计划时的默认模板位于 "),o("code",null,"partials/training_default.json"),e(",修改方式同上。")],-1),N=o("p",null,"以上所有更改均会在重启 Hydro 后生效。",-1);function V(B,E){const t=l("ExternalLinkIcon");return r(),d("div",null,[h,o("ul",null,[o("li",null,[e("修改翻译:在 "),o("a",i,[e("zh.yaml"),a(t)]),e(" 内搜索您需要修改的翻译内容,并将 "),_,e(" 修改后添加至 "),u,e(" 。")]),o("li",null,[e("添加语言:可参照 "),o("a",p,[e("zh.yaml"),a(t)]),e(" 格式创建一个新文件。欢迎社区参与多国化翻译工作。")])]),m,o("p",null,[e("通常的,在您访问的 url 前加上 "),f,e("(如 "),y,e(" 即可查看页面源代码,在第二行的 "),b,e(" 中 "),g,e(" 值即为页面名(首页例外,为 "),x,e(")。 在 "),o("a",k,[e("默认 templates"),a(t)]),e(" 中找到对应文件,将"),v,e(" 复制到 "),z,e(" 文件夹下后进行修改即可。")]),H,N])}const I=n(c,[["render",V],["__file","frontend-modify.html.vue"]]);export{I as default}; diff --git a/assets/frontend-modify.html-a43b88b4.js b/assets/frontend-modify.html-a43b88b4.js new file mode 100644 index 00000000..3ed5aed2 --- /dev/null +++ b/assets/frontend-modify.html-a43b88b4.js @@ -0,0 +1 @@ +import{_ as n}from"./plugin-vue_export-helper-c27b6911.js";import{r,o as a,c as s,a as o,b as e,d as c,w as d}from"./app-68b9e0b9.js";const i={},_=o("h1",{id:"前端修改",tabindex:"-1"},[o("a",{class:"header-anchor",href:"#前端修改","aria-hidden":"true"},"#"),e(" 前端修改")],-1);function f(l,m){const t=r("RouterLink");return a(),s("div",null,[_,o("p",null,[e("参考 "),c(t,{to:"/docs/system/frontend-modify/"},{default:d(()=>[e("前端修改")]),_:1}),e("。")])])}const p=n(i,[["render",f],["__file","frontend-modify.html.vue"]]);export{p as default}; diff --git a/assets/frontend-modify.html-a6e61fc5.js b/assets/frontend-modify.html-a6e61fc5.js new file mode 100644 index 00000000..adb81ff0 --- /dev/null +++ b/assets/frontend-modify.html-a6e61fc5.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-5c0c76d7","path":"/dev/frontend-modify.html","title":"前端修改","lang":"en-US","frontmatter":{"description":"参考 前端修改 (/docs/system/frontend-modify/)。","head":[["meta",{"property":"og:url","content":"https://hydro.js.org/dev/frontend-modify.html"}],["meta",{"property":"og:site_name","content":"Hydro"}],["meta",{"property":"og:title","content":"前端修改"}],["meta",{"property":"og:description","content":"参考 前端修改 (/docs/system/frontend-modify/)。"}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2021-08-13T04:13:21.000Z"}],["meta",{"property":"article:modified_time","content":"2021-08-13T04:13:21.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"前端修改\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2021-08-13T04:13:21.000Z\\",\\"author\\":[]}"]]},"headers":[],"git":{"createdTime":1628828001000,"updatedTime":1628828001000,"contributors":[{"name":"Macesuted","email":"macesuted@qq.com","commits":1}]},"readingTime":{"minutes":0.04,"words":12},"filePathRelative":"dev/frontend-modify.md","localizedDate":"August 13, 2021","autoDesc":true,"excerpt":""}');export{e as data}; diff --git a/assets/geoip.html-5b7c767a.js b/assets/geoip.html-5b7c767a.js new file mode 100644 index 00000000..6f777504 --- /dev/null +++ b/assets/geoip.html-5b7c767a.js @@ -0,0 +1 @@ +import{_ as t}from"./plugin-vue_export-helper-c27b6911.js";import{o as a,c,a as e,b as o}from"./app-68b9e0b9.js";const i={},n=e("h1",{id:"geoip",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#geoip","aria-hidden":"true"},"#"),o(" GeoIP")],-1),r=e("p",null,[o("插件需要 MaxMind 的 "),e("code",null,"Geolite2-City.mmdb"),o(" 支持,在安装插件后需要将mmdb拷贝至插件同一目录下方可启用,如果你不知道这是什么,请勿安装。")],-1),s=[n,r];function d(_,l){return a(),c("div",null,s)}const p=t(i,[["render",d],["__file","geoip.html.vue"]]);export{p as default}; diff --git a/assets/geoip.html-df96a488.js b/assets/geoip.html-df96a488.js new file mode 100644 index 00000000..ed3a88f7 --- /dev/null +++ b/assets/geoip.html-df96a488.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-16bdf429","path":"/plugins/geoip.html","title":"GeoIP","lang":"en-US","frontmatter":{"description":"插件需要 MaxMind 的 Geolite2-City.mmdb 支持,在安装插件后需要将mmdb拷贝至插件同一目录下方可启用,如果你不知道这是什么,请勿安装。","head":[["meta",{"property":"og:url","content":"https://hydro.js.org/plugins/geoip.html"}],["meta",{"property":"og:site_name","content":"Hydro"}],["meta",{"property":"og:title","content":"GeoIP"}],["meta",{"property":"og:description","content":"插件需要 MaxMind 的 Geolite2-City.mmdb 支持,在安装插件后需要将mmdb拷贝至插件同一目录下方可启用,如果你不知道这是什么,请勿安装。"}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-02-25T05:29:05.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-25T05:29:05.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"GeoIP\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-25T05:29:05.000Z\\",\\"author\\":[]}"]]},"headers":[],"git":{"createdTime":1677302945000,"updatedTime":1677302945000,"contributors":[{"name":"panda","email":"panda_dtdyy@outlook.com","commits":1}]},"readingTime":{"minutes":0.16,"words":49},"filePathRelative":"plugins/geoip.md","localizedDate":"February 25, 2023","autoDesc":true,"excerpt":""}');export{e as data}; diff --git a/assets/hook.html-6da4899a.js b/assets/hook.html-6da4899a.js new file mode 100644 index 00000000..a9d2f10b --- /dev/null +++ b/assets/hook.html-6da4899a.js @@ -0,0 +1,14 @@ +import{_ as s}from"./plugin-vue_export-helper-c27b6911.js";import{o as n,c as a,e as l}from"./app-68b9e0b9.js";const p={},o=l(`

使用 TypeScript 编写插件

请注意:在阅读本节之前,请确认您已阅读【使用 TypeScript 编写插件】一节并已完成了插件的创建。

示例

import { Context, Time } from 'hydrooj';
+
+export async function apply(ctx: Context) {
+    // handler 表示路由事件
+    // after 表示在主逻辑完成后运行
+    // RecordDetail 为需要捕获的路由名
+    // get 表示仅捕获 GET 请求
+    ctx.on('handler/after/RecordDetail#get', (h) => {
+        if (h.rdoc._id.getTimestamp() < new Date(Date.now() - Time.day) {
+            h.rdoc.code = '';
+        }
+    });
+}
+
`,4),e=[o];function c(r,t){return n(),a("div",null,e)}const y=s(p,[["render",c],["__file","hook.html.vue"]]);export{y as default}; diff --git a/assets/hook.html-d65207ab.js b/assets/hook.html-d65207ab.js new file mode 100644 index 00000000..74220d33 --- /dev/null +++ b/assets/hook.html-d65207ab.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-19b5347a","path":"/dev/hook.html","title":"使用 TypeScript 编写插件","lang":"en-US","frontmatter":{"description":"请注意:在阅读本节之前,请确认您已阅读【使用 TypeScript 编写插件】一节并已完成了插件的创建。 示例","head":[["meta",{"property":"og:url","content":"https://hydro.js.org/dev/hook.html"}],["meta",{"property":"og:site_name","content":"Hydro"}],["meta",{"property":"og:title","content":"使用 TypeScript 编写插件"}],["meta",{"property":"og:description","content":"请注意:在阅读本节之前,请确认您已阅读【使用 TypeScript 编写插件】一节并已完成了插件的创建。 示例"}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-05-19T14:49:26.000Z"}],["meta",{"property":"article:modified_time","content":"2023-05-19T14:49:26.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"使用 TypeScript 编写插件\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-05-19T14:49:26.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"示例","slug":"示例","link":"#示例","children":[]}],"git":{"createdTime":1684507766000,"updatedTime":1684507766000,"contributors":[{"name":"undefined","email":"i@undefined.moe","commits":1}]},"readingTime":{"minutes":0.37,"words":110},"filePathRelative":"dev/hook.md","localizedDate":"May 19, 2023","autoDesc":true,"excerpt":""}');export{e as data}; diff --git a/assets/hydrojudge.html-db9328db.js b/assets/hydrojudge.html-db9328db.js new file mode 100644 index 00000000..8901595d --- /dev/null +++ b/assets/hydrojudge.html-db9328db.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-a08ef0ec","path":"/plugins/hydrojudge.html","title":"hydrojudge","lang":"en-US","frontmatter":{"description":"您可以通过一键安装脚本快速安装独立评测机,详情请前往 部署Hydro (/docs/install/#部署) 查看。 准备 在配置评测机之前,请确认您的站点已经可以访问并正常登录/注册。 您应该预先下载您所要支持的语言的编译器,若您在配置完评测机后 升级/重新安装 了编译器,您需要重新启动沙箱。 关于编译器说明,请参照 编译器 (/docs/insta...","head":[["meta",{"property":"og:url","content":"https://hydro.js.org/plugins/hydrojudge.html"}],["meta",{"property":"og:site_name","content":"Hydro"}],["meta",{"property":"og:title","content":"hydrojudge"}],["meta",{"property":"og:description","content":"您可以通过一键安装脚本快速安装独立评测机,详情请前往 部署Hydro (/docs/install/#部署) 查看。 准备 在配置评测机之前,请确认您的站点已经可以访问并正常登录/注册。 您应该预先下载您所要支持的语言的编译器,若您在配置完评测机后 升级/重新安装 了编译器,您需要重新启动沙箱。 关于编译器说明,请参照 编译器 (/docs/insta..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-08-01T09:24:40.000Z"}],["meta",{"property":"article:modified_time","content":"2023-08-01T09:24:40.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"hydrojudge\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-08-01T09:24:40.000Z\\",\\"author\\":[]}"]]},"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":"作为附加组件-1","link":"#作为附加组件-1","children":[]},{"level":3,"title":"作为独立进程","slug":"作为独立进程-1","link":"#作为独立进程-1","children":[]}]},{"level":2,"title":"卸载","slug":"卸载","link":"#卸载","children":[]},{"level":2,"title":"评测设置","slug":"评测设置","link":"#评测设置","children":[{"level":3,"title":"作为附加组件","slug":"作为附加组件-2","link":"#作为附加组件-2","children":[]},{"level":3,"title":"作为独立进程","slug":"作为独立进程-2","link":"#作为独立进程-2","children":[]}]},{"level":2,"title":"修改编译选项/添加新语言支持","slug":"修改编译选项-添加新语言支持","link":"#修改编译选项-添加新语言支持","children":[]},{"level":2,"title":"测试数据格式","slug":"测试数据格式","link":"#测试数据格式","children":[]},{"level":2,"title":"调整沙箱空间大小","slug":"调整沙箱空间大小","link":"#调整沙箱空间大小","children":[]},{"level":2,"title":"C/C++ 彩色编译错误信息","slug":"c-c-彩色编译错误信息","link":"#c-c-彩色编译错误信息","children":[]},{"level":2,"title":"开大程序运行栈空间","slug":"开大程序运行栈空间","link":"#开大程序运行栈空间","children":[]},{"level":2,"title":"提高测评精度","slug":"提高测评精度","link":"#提高测评精度","children":[]},{"level":2,"title":"内存计量不准确","slug":"内存计量不准确","link":"#内存计量不准确","children":[]}],"git":{"createdTime":1613893902000,"updatedTime":1690881880000,"contributors":[{"name":"Macesuted","email":"macesuted@qq.com","commits":16},{"name":"undefined","email":"i@undefined.moe","commits":11},{"name":"Macesuted","email":"57275149+Macesuted@users.noreply.github.com","commits":3},{"name":"panda","email":"panda_dtdyy@outlook.com","commits":2},{"name":"Macesuted Kysic","email":"57275149+Macesuted@users.noreply.github.com","commits":1},{"name":"代建杉","email":"wood3s@foxmail.com","commits":1}]},"readingTime":{"minutes":4.92,"words":1475},"filePathRelative":"plugins/hydrojudge.md","localizedDate":"February 21, 2021","autoDesc":true,"excerpt":""}');export{e as data}; diff --git a/assets/hydrojudge.html-e071cd81.js b/assets/hydrojudge.html-e071cd81.js new file mode 100644 index 00000000..3d74eb89 --- /dev/null +++ b/assets/hydrojudge.html-e071cd81.js @@ -0,0 +1,27 @@ +import{_ as p}from"./plugin-vue_export-helper-c27b6911.js";import{r as d,o as c,c as t,a,b as s,d as e,w as r,e as l}from"./app-68b9e0b9.js";const i={},h=a("h1",{id:"hydrojudge",tabindex:"-1"},[a("a",{class:"header-anchor",href:"#hydrojudge","aria-hidden":"true"},"#"),s(" hydrojudge")],-1),y={class:"hint-container tip"},u=a("p",{class:"hint-container-title"},"Tips",-1),E=a("h2",{id:"准备",tabindex:"-1"},[a("a",{class:"header-anchor",href:"#准备","aria-hidden":"true"},"#"),s(" 准备")],-1),F=a("p",null,"在配置评测机之前,请确认您的站点已经可以访问并正常登录/注册。",-1),b=a("p",null,[s("您应该预先下载您所要支持的语言的编译器,若您在配置完评测机后 升级/重新安装 了编译器,您需要重新启动沙箱。"),a("br"),s(" 关于编译器说明,请参照 "),a("a",{href:"/docs/install/compiler"},"编译器"),s(" 章节。")],-1),m=a("br",null,null,-1),D={href:"https://github.com/criyle/go-judge/releases",target:"_blank",rel:"noopener noreferrer"},v=a("strong",null,"以 root 权限",-1),g=a("code",null,"127.0.0.1:5050",-1),f=l(`

安装

作为附加组件

Tips

由于用附加组件安装的评测机与 Hydro 必须在同一台服务器上,每一个 Hydro 实例最多只能有一台评测机由附加组件安装。

在安装 Hydro 的机器上运行下面的指令安装 @hydrooj/hydrojudge

yarn global add @hydrooj/hydrojudge
+hydrooj addon add @hydrooj/hydrojudge
+

重启 Hydro 后 hydrojudge 即可正常运行。

作为独立进程

Tips

该方法可以帮助您在任意服务器上部署评测机。

`,8),_=l(`

然后在运行评测机的服务器上安装 HydroJudge :

. <(curl https://hydro.ac/setup.sh) --judge
+

创建目录 ~/.config/hydro,在该目录下创建文件 judge.yaml,配置文件格式如下:

hosts:
+  localhost:
+    type: hydro # vj4 用户请在此处填写 vj4
+    server_url: http://localhost/ # Hydro 运行的网址
+    uname: judge # 评测账号用户名
+    password: abc123 # 评测账号密码
+    detail: true # 默认为 true
+

设置完之后,使用下面的指令即可开始运行(可以使用 pm2 管理):

hydrojudge
+

更新

HydroJudge 会发布不定期更新。您可以使用 yarn global upgrade-interactive --latest 来检测并进行更新。

关闭

作为附加组件

在 系统设置>hydrojudge 中有一栏 Disable builtin judge,将它勾上,然后重启 Hydro 即可。

作为独立进程

根据开启的方法关闭即可。

卸载

关闭后运行下面指令即可。

yarn global remove @hydrooj/hydrojudge
+hydrooj addon remove @hydrooj/hydrojudge
+

评测设置

作为附加组件

在 系统设置>hydrojudge 修改对应的参数,然后重启 Hydro 和 hydrojudge 即可。

作为独立进程

如果有需要修改单题测试点数量上限等设置,可以在 ~/.config/hydro/judge.yaml 的末尾添加下列内容:

testcases_max: 100 # 单题最多测试点数量
+total_time_limit: 120 # 单题最大总测试时长
+parallelism: 2 # 单评测机评测进程数量
+# 更多可选配置均可添加在此处,格式与前面的三排类似
+
`,22),B={href:"https://github.com/hydro-dev/Hydro/blob/9c0afa38e3e6fa886ab9e9237847893fa6714392/packages/hydrojudge/src/config.ts#L12",target:"_blank",rel:"noopener noreferrer"},C=a("h2",{id:"修改编译选项-添加新语言支持",tabindex:"-1"},[a("a",{class:"header-anchor",href:"#修改编译选项-添加新语言支持","aria-hidden":"true"},"#"),s(" 修改编译选项/添加新语言支持")],-1),x=a("p",null,[s("对于已安装内置评测机的用户(无论内置评测机是否启动),在 控制面板>系统设置 中修改 judge.langs 配置项即可;对于没有安装内置评测机的用户,需要在 "),a("code",null,"~/.config/hydro/langs.yaml"),s(" 中配置。")],-1),A={href:"https://github.com/hydro-dev/Hydro/blob/71bb2f0b517be8f6966f97f835f2521f179b3d84/packages/hydrooj/setting.yaml#L12",target:"_blank",rel:"noopener noreferrer"},k=a("p",null,[s("如果您添加了新的语言,您还需要前往 控制面板>系统设置 中修改 Language Highlight ID 与 Monaco language modes。"),a("br"),s(" 分别表示选择对应的语言后的高亮设置(基于 PrismJS)和 Monaco 编辑器语法规则设置。")],-1),j=a("p",null,"修改完后请重启 Hydro 和 hydrojudge 。",-1),H=a("h2",{id:"测试数据格式",tabindex:"-1"},[a("a",{class:"header-anchor",href:"#测试数据格式","aria-hidden":"true"},"#"),s(" 测试数据格式")],-1),L=l(`

调整沙箱空间大小

Note

如果不调整沙箱的空间大小,当您的评测使用文件 IO 且输入输出文件较大时可能会引发错误。

对于 2022/8/12 前安装的用户:

在服务器上运行下面的代码找到 hydro-sandbox 的运行目录:

pm2 info hydro-sandbox | grep "exec cwd"
+
`,5),U={href:"https://github.com/criyle/go-judge/blob/master/mount.yaml",target:"_blank",rel:"noopener noreferrer"},q=a("code",null,"size",-1),w=a("code",null,"nr_inodes",-1),I=l(`

对于 2022/8/12 后安装的用户:

编辑 /root/.hydro/mount.yaml,修改 size 即可。

C/C++ 彩色编译错误信息

  1. 确认您安装了支持彩色输出的编译器;
  2. 在系统设置中,将 C/C++ 编译命令后加上 -fdiagnostics-color=always

例:

c:
+  compile: /usr/bin/gcc -O2 -Wall -std=c99 -o \${name} foo.c -lm -fdiagnostics-color=always
+

开大程序运行栈空间

2022/8/12 后安装的实例默认已开启无限栈空间,无需手动操作

在很多时候系统默认为程序提供的栈空间并不能满足我们的需求,此时我们需要手动为用户程序提供更大的栈空间。

修改 pm2 中 hydro-sandbox 的启动参数为 ulimit -s unlimited && /usr/bin/hydro-sandbox

pm2 del hydro-sandbox
+pm2 start bash --name hydro-sandbox -- -c "ulimit -s unlimited && hydro-sandbox" 
+

提高测评精度

禁用 CPU 频率缩放与 Intel 睿频加速技术,防止 CPU 频率波动。

禁用内存地址空间随机化,以使得存在内存寻址错误的代码能够得到更多可重复的结果,可以通过在 /etc/sysctl.conf 中添加下面这行并运行 sudo sysctl -p 应用:

kernel.randomize_va_space = 0
+

内存计量不准确

部分 Linux 设备默认使用 cgroup2,而 cgroup2 中移除了精确计量内存消耗的接口。 若要获得更精确的内存计量,推荐启用 cgroup v1 (您可以通过检查 /sys/fs/cgroup/memory/memory.memsw.usage_in_bytes 是否存在来验证是否当前系统是否启用了 cgroup v1 ):

以 Ubuntu 的默认引导器 GRUB 2 为例,编辑 /etc/default/grub: 在其中

GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"
+

后,加入 cgroup_enable=memory swapaccount=1 systemd.unified_cgroup_hierarchy=0 syscall.x32=y,变为:

GRUB_CMDLINE_LINUX_DEFAULT="quiet splash cgroup_enable=memory swapaccount=1 systemd.unified_cgroup_hierarchy=0 syscall.x32=y"
+

运行以下命令更新 GRUB 2 的配置,然后重新启动。

update-grub && reboot
+
`,23);function N(R,T){const o=d("RouterLink"),n=d("ExternalLinkIcon");return c(),t("div",null,[h,a("div",y,[u,a("p",null,[s("您可以通过一键安装脚本快速安装独立评测机,详情请前往 "),e(o,{to:"/docs/install/#%E9%83%A8%E7%BD%B2"},{default:r(()=>[s("部署Hydro")]),_:1}),s(" 查看。")])]),E,F,b,a("p",null,[s("如果不使用自动脚本,您需要按照如下方式手动安装沙箱服务:"),m,s(" 前往 "),a("a",D,[s("criyle/go-judge"),e(n)]),s(" 下载 executorserver。 Executorserver 需要在后台"),v,s("运行并监听 "),g,s(" 。 可使用 pm2 进行管理。")]),f,a("p",null,[s("首先需要创建一个有 PRIV_JUDGE 权限的账户,具体方法参照 "),e(o,{to:"/docs/system/cli/#%E5%88%9B%E5%BB%BA%E8%AF%84%E6%B5%8B%E8%B4%A6%E5%8F%B7"},{default:r(()=>[s("此处")]),_:1}),s("。(在部署 Hydro 的服务器上运行)")]),_,a("p",null,[s("在 "),a("a",B,[s("此处"),e(n)]),s(" 的设置均可添加到此处。")]),C,x,a("p",null,[s("文件格式参照 "),a("a",A,[s("此处"),e(n)]),s(" 。")]),k,j,H,a("p",null,[s("参照 "),e(o,{to:"/docs/user/problem/#%E6%B5%8B%E8%AF%95%E6%95%B0%E6%8D%AE%E6%A0%BC%E5%BC%8F"},{default:r(()=>[s("测试数据格式")]),_:1}),s(" 配置。")]),L,a("p",null,[s("将 "),a("a",U,[s("mount.yaml"),e(n)]),s(" 下载并放置在 sandbox 的运行目录下。然后修改第 64 行和第 68 行的 "),q,s(" 和 "),w,s(" 的大小至您想要的大小,保存后重启 sandbox 即可完成更改。")]),I])}const J=p(i,[["render",N],["__file","hydrojudge.html.vue"]]);export{J as default}; diff --git a/assets/import-user.html-3fad9582.js b/assets/import-user.html-3fad9582.js new file mode 100644 index 00000000..86bc2eaa --- /dev/null +++ b/assets/import-user.html-3fad9582.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-69f3a96a","path":"/docs/system/import-user.html","title":"导入用户","lang":"en-US","frontmatter":{"description":"目前支持 csv 格式(用 , 分隔)或 Excel 格式(用 TAB 分隔) 导入用户数据, 数据既可以用文本编辑器创建,也可以用 Excel 等软件来辅助创建。 每行最少三列,最多五列,分别为: 邮箱,用户名,密码,显示名,用户信息。(显示名和用户信息为可选) 请使用 UTF-8 编码,否则中文可能会乱码。 如果使用 CSV 格式(逗号分隔),则用...","head":[["meta",{"property":"og:url","content":"https://hydro.js.org/docs/system/import-user.html"}],["meta",{"property":"og:site_name","content":"Hydro"}],["meta",{"property":"og:title","content":"导入用户"}],["meta",{"property":"og:description","content":"目前支持 csv 格式(用 , 分隔)或 Excel 格式(用 TAB 分隔) 导入用户数据, 数据既可以用文本编辑器创建,也可以用 Excel 等软件来辅助创建。 每行最少三列,最多五列,分别为: 邮箱,用户名,密码,显示名,用户信息。(显示名和用户信息为可选) 请使用 UTF-8 编码,否则中文可能会乱码。 如果使用 CSV 格式(逗号分隔),则用..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2022-12-29T09:30:13.000Z"}],["meta",{"property":"article:modified_time","content":"2022-12-29T09:30:13.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"导入用户\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2022-12-29T09:30:13.000Z\\",\\"author\\":[]}"]]},"headers":[],"git":{"createdTime":1628908242000,"updatedTime":1672306213000,"contributors":[{"name":"Macesuted","email":"macesuted@qq.com","commits":2},{"name":"panda","email":"panda_dtdyy@outlook.com","commits":2},{"name":"undefined","email":"i@undefined.moe","commits":2}]},"readingTime":{"minutes":0.84,"words":252},"filePathRelative":"docs/system/import-user.md","localizedDate":"August 14, 2021","autoDesc":true,"excerpt":""}');export{e as data}; diff --git a/assets/import-user.html-8528e3c4.js b/assets/import-user.html-8528e3c4.js new file mode 100644 index 00000000..78c37170 --- /dev/null +++ b/assets/import-user.html-8528e3c4.js @@ -0,0 +1,4 @@ +import{_ as e}from"./plugin-vue_export-helper-c27b6911.js";import{o,c as s,e as d}from"./app-68b9e0b9.js";const c={},t=d(`

导入用户

目前支持 csv 格式(用 , 分隔)或 Excel 格式(用 TAB 分隔) 导入用户数据, 数据既可以用文本编辑器创建,也可以用 Excel 等软件来辅助创建。

每行最少三列,最多五列,分别为: 邮箱,用户名,密码,显示名,用户信息。(显示名和用户信息为可选)
请使用 UTF-8 编码,否则中文可能会乱码。
如果使用 CSV 格式(逗号分隔),则用户信息列不可用。

foo@undefined.moe	user1	password1
+bar@undefined.moe	user2	password2	temp
+test@undefined.moe	user3	password3	test	{"group":"class1","studentId":"123","school":"Hydro School"}
+

可以在粘贴后点击预览验证复制入的数据的有效性

这将创建三个用户:

  • user1 密码为 password1 , 邮箱 foo@undefined.moe
  • user2 密码为 password2 ,邮箱 bar@undefined.moe,显示名为 temp
  • user3 密码为 password3,邮箱 test@undefined.moe,显示名为 test,学校为 Hydro School,学号为 123,该用户将会被分配至当前域的 class1 小组内;

Note

用户创建后无法删除,请谨慎操作

`,8),n=[t];function a(r,i){return o(),s("div",null,n)}const u=e(c,[["render",a],["__file","import-user.html.vue"]]);export{u as default}; diff --git a/assets/index.html-17594d64.js b/assets/index.html-17594d64.js new file mode 100644 index 00000000..32be3c28 --- /dev/null +++ b/assets/index.html-17594d64.js @@ -0,0 +1,5 @@ +import{_ as l}from"./plugin-vue_export-helper-c27b6911.js";import{r as s,o as a,c as o,a as d,b as t,d as r,w as i,e}from"./app-68b9e0b9.js";const c="/assets/pict1-1fdc4194.png",f="/assets/pict2-662f781b.png",g="/assets/pict3-adef5567.png",y="/assets/pict4-1f728e83.png",p="/assets/pict5-5f2ffd8e.png",x="/assets/pict6-c3b9346b.png",h="/assets/pict7-95fd5142.png",u="/assets/pict8-1d11715f.png",m={},_=e(`

介绍

为什么使用 Hydro?

  • 安全:使用 cgroup 进行隔离,杜绝卡评测;

  • 高效:Hydro 使用了沙箱复用技术,拥有极高的评测效率;

  • 扩展:Hydro 支持安装额外模块进行扩展;

  • 强大:配合 Judge 模块(或 HydroJudge 独立评测机),可支持 spj,交互题,提交答案题,文件IO 等多种特性;

  • 自定:所有权限节点均可自由设置;

  • 易上手:无需改动源代码,系统设置中预留了大量可自行修改的内容;管理逻辑简洁;

  • 社区:Hydro 正在持续维护中;

  • 如果您正在使用 HustOJ,可以导出题目为 FPS 文件后使用 fps-importer 插件 直接导入 Hydro。

  • 如果您正在使用 QDUOJ, 可以导出题目为 QDUOJ-zip 格式后使用 import-qduoj 插件直接导入 Hydro。

  • 如果您正在使用 Vijos / SYZOJ / HustOJ / UniversalOJ, 可以直接使用 migrate 插件 导入所有数据至 Hydro。

功能对比

Hydro 支持很多其他系统无法支持的题型,可在 https://hydro.ac/d/system_test/p 中查看并免费下载使用样例。(需要登录)
下方对比了 Hydro 与其他主流 OJ 系统的功能。(只进行在不修改源代码情况下的对比)

+:支持
+=:部分支持
+?: 未知
+-:不支持
+
功能HydroHustOJSYZOJ[1]QDUOJVijos
安装一键脚本一键脚本手动搭建dockerdocker
数据库MongoDBMySQLMariaDBPostgresMongoDB
测试数据存储本地/S3 [2]本地本地本地数据库
多评测机+=[3]=[4]=+
测试数据同步按需抓取全量同步全量同步全量同步按需抓取
比赛ACM/OI/IOI/乐多ACM/OIACM/OI/IOIACM/OI/IOIACM/OI
封榜++---
作业功能++--+
修改编译命令/添加语言+=[5]--+
权限系统 [6]+=--+
训练计划(题单)++-[7]-+
团队+ [8]---+
Hack+----
SpecialJudge+ [9]++-=
Subtask+-+--
交互题+-+--
RemoteJudgeCF/SPOJ/UOJ/POJ/LuoguHDU/PKU---
题目导入fps/syzoj/qduoj/hydrofps/qduojsyzojfps/qduoj-

截图

imgimgimgimgimgimgimgimg

现在开始

',10),b=e('
  1. SYZOJ 和 Lyrio (曾用名 syzoj-ng,loj.ac 当前所用系统) 是两套不同的系统,这意味着使用 SYZOJ 无法再导入 loj.ac 的题目,同时 Lyrio 无比赛功能。 ↩︎

  2. S3 指所有兼容 Amazon S3 协议的服务,包括腾讯COS,阿里OSS 等。 ↩︎

  3. 安装配置繁琐,且需要手动在服务器间同步数据。 ↩︎

  4. 需要手动在服务器间同步数据。 ↩︎

  5. 仅能修改部分编译参数,添加语言需要修改源代码。 ↩︎

  6. 此处的权限系统指 除用户/管理员二元化权限之外的 的更细粒度的权限划分。 ↩︎

  7. 部分二次开发版本有此功能。 ↩︎

  8. 通过域功能,允许用户创建域并在域内拥有管理员权限。域之间仅共享账号数据,也可使用域内小组进行权限控制。 ↩︎

  9. 支持所有主流 SPJ 格式。 ↩︎

',2);function O(J,k){const n=s("RouterLink");return a(),o("div",null,[_,d("p",null,[t("点击 "),r(n,{to:"/docs/install/"},{default:i(()=>[t("部署")]),_:1}),t(" ,开始部署您的 OJ 吧!")]),b])}const H=l(m,[["render",O],["__file","index.html.vue"]]);export{H as default}; diff --git a/assets/index.html-19baa366.js b/assets/index.html-19baa366.js new file mode 100644 index 00000000..aa797ca0 --- /dev/null +++ b/assets/index.html-19baa366.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-744497ce","path":"/api/","title":"API","lang":"en-US","frontmatter":{"description":"此处列出部分系统通信协议。","head":[["meta",{"property":"og:url","content":"https://hydro.js.org/api/"}],["meta",{"property":"og:site_name","content":"Hydro"}],["meta",{"property":"og:title","content":"API"}],["meta",{"property":"og:description","content":"此处列出部分系统通信协议。"}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-11-22T01:11:53.000Z"}],["meta",{"property":"article:modified_time","content":"2023-11-22T01:11:53.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"API\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-11-22T01:11:53.000Z\\",\\"author\\":[]}"]]},"headers":[],"git":{"createdTime":1700615513000,"updatedTime":1700615513000,"contributors":[{"name":"undefined","email":"i@undefined.moe","commits":1}]},"readingTime":{"minutes":0.04,"words":13},"filePathRelative":"api/README.md","localizedDate":"November 22, 2023","autoDesc":true,"excerpt":""}');export{e as data}; diff --git a/assets/index.html-1c73bfb8.js b/assets/index.html-1c73bfb8.js new file mode 100644 index 00000000..3926f1e0 --- /dev/null +++ b/assets/index.html-1c73bfb8.js @@ -0,0 +1 @@ +import{_ as e}from"./plugin-vue_export-helper-c27b6911.js";import{o as a,c as i,e as r}from"./app-68b9e0b9.js";const d={},h=r('

用户文档

题目难度

Hydro 中题目的难度,根据递交数、通过率以及每个递交的递交时间和评测结果,通过算法计算得出。

  1. 一般地,难度的数值越大,该题目越难。
  2. 新题目的难度可能不准确;在题目获得大量递交之后,难度才会变得较为准确。
  3. 越早递交评测的用户代码的评测结果对题目难度影响越大。
  4. 题目的难度由算法计算得出,有可能出现不准确的结果。

参与比赛

您可以在比赛的详细界面内点击“参与比赛”按钮进行参与。 比赛过程中“成绩表”会根据比赛规则显示排名。 在比赛截止之后,您仍然可以订正其中的题目,但“成绩表”将停止更新。

发布讨论

若您想发布一个讨论,请先进入一个讨论节点,之后点击“创建一个讨论”按钮并填写:

  • 标题;
  • 内容;
  • 是否高亮:若选择后,该贴的左边将有醒目的红色线条(需要“高亮讨论”权限);
  • Pin:该讨论是否置顶(需要“置顶讨论”权限)。

之后点击“创建”按钮进行发布。

认领作业

您可以在作业的详情页面中,点击“认领作业”。
在作业开始之前,您无法查看作业中的题目。
在作业持续时间内,您与他人的做题情况会被实时统计在“成绩表”内。
在作业进入延期阶段后,您仍然可以提交题目,但成绩表内的分数将根据延期扣分规则按百分比折算。
在作业截止之后,您仍然可以订正其中的题目,但“成绩表”将停止更新。

',12),l=[h];function n(t,o){return a(),i("div",null,l)}const _=e(d,[["render",n],["__file","index.html.vue"]]);export{_ as default}; diff --git a/assets/index.html-21cf9e92.js b/assets/index.html-21cf9e92.js new file mode 100644 index 00000000..60f15552 --- /dev/null +++ b/assets/index.html-21cf9e92.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-fe9aee22","path":"/docs/install/","title":"部署 Hydro","lang":"en-US","frontmatter":{"description":"这里提供了几套方案帮助您建立自己的站点,请选择适合您的方案并继续。 搭建过程中如果遇到问题欢迎 联系我们 (/#联系我们) 提问。 服务器选择 不同服务商提供的 CPU 主频不同,下方数据仅供参考。 最低服务器配置: CPU: 1核 内存: 2G。(约可允许 100 人使用) 请尽量不要使用突发性能实例或共享型实例,这可能会导致评测时间计量不准确 Ce...","head":[["meta",{"property":"og:url","content":"https://hydro.js.org/docs/install/"}],["meta",{"property":"og:site_name","content":"Hydro"}],["meta",{"property":"og:title","content":"部署 Hydro"}],["meta",{"property":"og:description","content":"这里提供了几套方案帮助您建立自己的站点,请选择适合您的方案并继续。 搭建过程中如果遇到问题欢迎 联系我们 (/#联系我们) 提问。 服务器选择 不同服务商提供的 CPU 主频不同,下方数据仅供参考。 最低服务器配置: CPU: 1核 内存: 2G。(约可允许 100 人使用) 请尽量不要使用突发性能实例或共享型实例,这可能会导致评测时间计量不准确 Ce..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-11-30T07:45:11.000Z"}],["meta",{"property":"article:modified_time","content":"2023-11-30T07:45:11.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"部署 Hydro\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-11-30T07:45:11.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"服务器选择","slug":"服务器选择","link":"#服务器选择","children":[]},{"level":2,"title":"部署","slug":"部署","link":"#部署","children":[]}],"git":{"createdTime":1620493369000,"updatedTime":1701330311000,"contributors":[{"name":"undefined","email":"i@undefined.moe","commits":22},{"name":"Macesuted","email":"macesuted@qq.com","commits":7},{"name":"Macesuted","email":"57275149+Macesuted@users.noreply.github.com","commits":1},{"name":"代建杉","email":"wood3s@foxmail.com","commits":1}]},"readingTime":{"minutes":3.12,"words":937},"filePathRelative":"docs/install/README.md","localizedDate":"May 8, 2021","autoDesc":true,"excerpt":""}');export{e as data}; diff --git a/assets/index.html-22922d8e.js b/assets/index.html-22922d8e.js new file mode 100644 index 00000000..0b5b9998 --- /dev/null +++ b/assets/index.html-22922d8e.js @@ -0,0 +1 @@ +const e=JSON.parse(`{"key":"v-74379e72","path":"/FAQ/","title":"常见问题集合","lang":"en-US","frontmatter":{"description":"好消息!本页和各大浏览器均达成了合作,使用 Ctrl-F 即可快速搜索关键词! 更多教程请点击右上角的常用教程查看。 用户QQ群 1085853538 如何快速上手了解系统功能? 参照本文 https://hydro.ac/discuss/6172ceeed850d38c79ae18f9 (https://hydro.ac/discuss/6172ce...","head":[["meta",{"property":"og:url","content":"https://hydro.js.org/FAQ/"}],["meta",{"property":"og:site_name","content":"Hydro"}],["meta",{"property":"og:title","content":"常见问题集合"}],["meta",{"property":"og:description","content":"好消息!本页和各大浏览器均达成了合作,使用 Ctrl-F 即可快速搜索关键词! 更多教程请点击右上角的常用教程查看。 用户QQ群 1085853538 如何快速上手了解系统功能? 参照本文 https://hydro.ac/discuss/6172ceeed850d38c79ae18f9 (https://hydro.ac/discuss/6172ce..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-02-25T05:29:05.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-25T05:29:05.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"常见问题集合\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-25T05:29:05.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"好消息!本页和各大浏览器均达成了合作,使用 Ctrl-F 即可快速搜索关键词!","slug":"好消息-本页和各大浏览器均达成了合作-使用-ctrl-f-即可快速搜索关键词","link":"#好消息-本页和各大浏览器均达成了合作-使用-ctrl-f-即可快速搜索关键词","children":[]},{"level":2,"title":"更多教程请点击右上角的常用教程查看。","slug":"更多教程请点击右上角的常用教程查看。","link":"#更多教程请点击右上角的常用教程查看。","children":[]},{"level":2,"title":"用户QQ群 1085853538","slug":"用户qq群-1085853538","link":"#用户qq群-1085853538","children":[]},{"level":2,"title":"如何快速上手了解系统功能?","slug":"如何快速上手了解系统功能","link":"#如何快速上手了解系统功能","children":[]},{"level":2,"title":"什么是 OJ?","slug":"什么是-oj","link":"#什么是-oj","children":[]},{"level":2,"title":"Arch Linux 开发模式安装时出现 [ERR_STREAM_PREMATURE_CLOSE]: Premature close 错误","slug":"arch-linux-开发模式安装时出现-err-stream-premature-close-premature-close-错误","link":"#arch-linux-开发模式安装时出现-err-stream-premature-close-premature-close-错误","children":[]},{"level":2,"title":"为什么我安装完成之后仍然无法访问?","slug":"为什么我安装完成之后仍然无法访问","link":"#为什么我安装完成之后仍然无法访问","children":[]},{"level":2,"title":"为什么我配置完反向代理(caddy/nginx)之后无法登录(出现CsrfTokenError)?","slug":"为什么我配置完反向代理-caddy-nginx-之后无法登录-出现csrftokenerror","link":"#为什么我配置完反向代理-caddy-nginx-之后无法登录-出现csrftokenerror","children":[]},{"level":2,"title":"怎么备份/还原备份/迁移数据?","slug":"怎么备份-还原备份-迁移数据","link":"#怎么备份-还原备份-迁移数据","children":[]},{"level":2,"title":"恢复备份时出现 '/data/file/hydro': Directory not empty","slug":"恢复备份时出现-data-file-hydro-directory-not-empty","link":"#恢复备份时出现-data-file-hydro-directory-not-empty","children":[]},{"level":2,"title":"更新升级","slug":"更新升级","link":"#更新升级","children":[]},{"level":2,"title":"怎么导入题目/创建题目?","slug":"怎么导入题目-创建题目","link":"#怎么导入题目-创建题目","children":[]},{"level":2,"title":"如何限制未登录用户访问?","slug":"如何限制未登录用户访问","link":"#如何限制未登录用户访问","children":[]},{"level":2,"title":"比赛作业里面的时间是什么含义,OI排名跟普通排名有何区别?","slug":"比赛作业里面的时间是什么含义-oi排名跟普通排名有何区别","link":"#比赛作业里面的时间是什么含义-oi排名跟普通排名有何区别","children":[]},{"level":2,"title":"脚本把 OJ 装在哪里了?","slug":"脚本把-oj-装在哪里了","link":"#脚本把-oj-装在哪里了","children":[]},{"level":2,"title":"题目的限时和内存限制的精度是怎样的?","slug":"题目的限时和内存限制的精度是怎样的","link":"#题目的限时和内存限制的精度是怎样的","children":[]},{"level":2,"title":"我想让 Python 支持 numpy 等等库,怎么办?","slug":"我想让-python-支持-numpy-等等库-怎么办","link":"#我想让-python-支持-numpy-等等库-怎么办","children":[]},{"level":2,"title":"使用安装脚本后忘记 MongoDB 的账号密码怎么办?","slug":"使用安装脚本后忘记-mongodb-的账号密码怎么办","link":"#使用安装脚本后忘记-mongodb-的账号密码怎么办","children":[]},{"level":2,"title":"如何关闭、打开用户注册?","slug":"如何关闭、打开用户注册","link":"#如何关闭、打开用户注册","children":[]},{"level":2,"title":"用户名为 Hydro 的用户是干什么的?密码是什么?可以登录么?","slug":"用户名为-hydro-的用户是干什么的-密码是什么-可以登录么","link":"#用户名为-hydro-的用户是干什么的-密码是什么-可以登录么","children":[]},{"level":2,"title":"如何修改网站图标?","slug":"如何修改网站图标","link":"#如何修改网站图标","children":[]},{"level":2,"title":"如何重置数据?","slug":"如何重置数据","link":"#如何重置数据","children":[]},{"level":2,"title":"评测显示“总时限超过 60s,评测取消”","slug":"评测显示-总时限超过-60s-评测取消","link":"#评测显示-总时限超过-60s-评测取消","children":[]},{"level":2,"title":"如何在背景中添加线条特效?","slug":"如何在背景中添加线条特效","link":"#如何在背景中添加线条特效","children":[]},{"level":2,"title":"使用 Hydro 要花多少钱?","slug":"使用-hydro-要花多少钱","link":"#使用-hydro-要花多少钱","children":[]},{"level":2,"title":"execve: no such file or directory","slug":"execve-no-such-file-or-directory","link":"#execve-no-such-file-or-directory","children":[]},{"level":2,"title":"怎么自定义用户标签?","slug":"怎么自定义用户标签","link":"#怎么自定义用户标签","children":[]},{"level":2,"title":"为什么我无法批量下载多个文件?","slug":"为什么我无法批量下载多个文件","link":"#为什么我无法批量下载多个文件","children":[]},{"level":2,"title":"为什么我的提交页面没有语言可选?","slug":"为什么我的提交页面没有语言可选","link":"#为什么我的提交页面没有语言可选","children":[]},{"level":2,"title":"The 'yarn global' commands have been remove in 2.x - consider using 'yarn dlx' or a third-party plugin instead","slug":"the-yarn-global-commands-have-been-remove-in-2-x-consider-using-yarn-dlx-or-a-third-party-plugin-instead","link":"#the-yarn-global-commands-have-been-remove-in-2-x-consider-using-yarn-dlx-or-a-third-party-plugin-instead","children":[]},{"level":2,"title":"我是机房用户,大量用户同 IP 操作触发了频率限制,怎么解决?","slug":"我是机房用户-大量用户同-ip-操作触发了频率限制-怎么解决","link":"#我是机房用户-大量用户同-ip-操作触发了频率限制-怎么解决","children":[]}],"git":{"createdTime":1647254801000,"updatedTime":1677302945000,"contributors":[{"name":"undefined","email":"i@undefined.moe","commits":9},{"name":"panda","email":"panda_dtdyy@outlook.com","commits":1},{"name":"pt3155420267","email":"33685002+pt3155420267@users.noreply.github.com","commits":1}]},"readingTime":{"minutes":10.2,"words":3060},"filePathRelative":"FAQ/README.md","localizedDate":"March 14, 2022","autoDesc":true,"excerpt":""}`);export{e as data}; diff --git a/assets/index.html-274fe549.js b/assets/index.html-274fe549.js new file mode 100644 index 00000000..026c9ce5 --- /dev/null +++ b/assets/index.html-274fe549.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-7445cd33","path":"/dev/","title":"开发环境部署","lang":"en-US","frontmatter":{"description":"如果您没有过 TypeScript 项目的开发经验,非常不建议自建开发环境。 使用自动脚本安装也可以基于插件系统完成大部分的定制需求(参照左侧【使用 TypeScript 编写插件】章节)。 您可以使用 Gitpod (https://gitpod.io/#https://github.com/hydro-dev/Hydro) 快速打开配置完成的开发环...","head":[["meta",{"property":"og:url","content":"https://hydro.js.org/dev/"}],["meta",{"property":"og:site_name","content":"Hydro"}],["meta",{"property":"og:title","content":"开发环境部署"}],["meta",{"property":"og:description","content":"如果您没有过 TypeScript 项目的开发经验,非常不建议自建开发环境。 使用自动脚本安装也可以基于插件系统完成大部分的定制需求(参照左侧【使用 TypeScript 编写插件】章节)。 您可以使用 Gitpod (https://gitpod.io/#https://github.com/hydro-dev/Hydro) 快速打开配置完成的开发环..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-06-06T04:14:26.000Z"}],["meta",{"property":"article:modified_time","content":"2023-06-06T04:14:26.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"开发环境部署\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-06-06T04:14:26.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"安装依赖","slug":"安装依赖","link":"#安装依赖","children":[]},{"level":2,"title":"安装 Hydro","slug":"安装-hydro","link":"#安装-hydro","children":[]},{"level":2,"title":"插件","slug":"插件","link":"#插件","children":[]},{"level":2,"title":"启动 Hydro","slug":"启动-hydro","link":"#启动-hydro","children":[]},{"level":2,"title":"更新","slug":"更新","link":"#更新","children":[]}],"git":{"createdTime":1611599229000,"updatedTime":1686024866000,"contributors":[{"name":"undefined","email":"i@undefined.moe","commits":10},{"name":"Macesuted Kysic","email":"macesuted@foxmail.com","commits":4},{"name":"Macesuted","email":"macesuted@qq.com","commits":3},{"name":"(Macesuted)","email":"macesuted@foxmail.com","commits":2},{"name":"panda","email":"panda_dtdyy@outlook.com","commits":2},{"name":"(Macesuted)","email":"1912192337@qq.com","commits":1},{"name":"Macesuted Kysic","email":"57275149+Macesuted@users.noreply.github.com","commits":1}]},"readingTime":{"minutes":2.32,"words":696},"filePathRelative":"dev/README.md","localizedDate":"January 25, 2021","autoDesc":true,"excerpt":""}');export{e as data}; diff --git a/assets/index.html-31f66e54.js b/assets/index.html-31f66e54.js new file mode 100644 index 00000000..137f7d19 --- /dev/null +++ b/assets/index.html-31f66e54.js @@ -0,0 +1 @@ +import{_ as n}from"./plugin-vue_export-helper-c27b6911.js";import{r as l,o as s,c as d,a as e,b as o,d as t,e as i}from"./app-68b9e0b9.js";const h={},a=i('

LICENSEGitHub Workflow Statushydroojnpmnode-currentGitHub contributorsGitHub commit activity

Hydro 是一个高效的信息学在线测评系统。特点:易于部署(且提供安装脚本),轻量,功能强大且易于扩展。

',2),c={href:"https://github.com/hydro-dev/Hydro",target:"_blank",rel:"noopener noreferrer"},u=e("br",null,null,-1),_=e("br",null,null,-1),p=e("br",null,null,-1),b=e("br",null,null,-1),m={href:"https://github.com/hydro-dev/Hydro/issues",target:"_blank",rel:"noopener noreferrer"},y={href:"https://gitpod.io/#https://github.com/hydro-dev/Hydro",target:"_blank",rel:"noopener noreferrer"},g={href:"https://hydro.ac/",target:"_blank",rel:"noopener noreferrer"},f=e("h2",{id:"联系我们",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#联系我们","aria-hidden":"true"},"#"),o(" 联系我们")],-1),H=e("a",{href:"mailto:i@undefined.moe"},"i@undefined.moe",-1),k=e("br",null,null,-1),v=e("br",null,null,-1),x={href:"https://t.me/webpack_exports_undefined",target:"_blank",rel:"noopener noreferrer"},j=i('

注:Hydro 为开源框架,任何人均能够在遵守协议的情况下使用这套框架。
版权申诉相关问题请联系对应网站管理者,(通常为其 UID=2 的用户),与开发者无关。

开源许可

本项目基于 AGPL v3 开源。
在您部署 Hydro 时,需要保留底部的 Powered by Hydro 字样,其中的 Hydro 字样需指向 hydro.js.org/本仓库/fork 之一的链接。
若您对源码做出修改,同样需要以 AGPL v3 开源,您可以以 Powered by Hydro, Modified by xxx 格式在页脚注明。
此限制对以下模块仍然有效:

  • Hydro 插件;
  • 包括但不限于使用 http 协议与 Hydro 进行交互的组件;
',4),G=e("br",null,null,-1),w={href:"https://github.com/mamoe/mirai/issues/850",target:"_blank",rel:"noopener noreferrer"},E=i('
  • 项目开源不代表开发者有义务为您提供服务。
  • 在提问前请先阅读《提问的智慧》。
  • 若有必要,开发者有权对您停止任何技术支持。
  • 开发组会 尽可能 保证用户可以进行平滑升级,但无法保证不在新版本引入影响使用的漏洞,且内部实现可能会在不发布任何通知的情况下进行重命名/修改/删除。

如果您对以上条目感到不适,建议您停止使用本项目。

鸣谢

排名不分先后,按照链接字典序。

',4),I={href:"https://github.com/",target:"_blank",rel:"noopener noreferrer"},L={href:"https://github.com/criyle",target:"_blank",rel:"noopener noreferrer"},N={href:"https://github.com/vijos/vj4",target:"_blank",rel:"noopener noreferrer"};function P(V,B){const r=l("ExternalLinkIcon");return s(),d("div",null,[a,e("p",null,[e("a",c,[o("Github 仓库"),t(r)])]),e("p",null,[o("欢迎 star 本项目,这是对开发者的鼓励。"),u,o(" 项目的开发与维护需要资金,欢迎进行捐助。"),_,o(" Hydro 提供收费的功能定制服务,如您需要可与我们联系。"),p,o(" 相关文档若说明的不够详细,请提交 Pull Request 或联系开发组说明。"),b,o(" Bug 和功能建议请在 "),e("a",m,[o("Issues"),t(r)]),o(" 提出。")]),e("p",null,[e("a",y,[o("在 Gitpod 打开已配置完成的测试环境"),t(r)])]),e("p",null,[e("a",g,[o("Hydro Online Judge"),t(r)])]),f,e("p",null,[o("Email "),H,k,o(" Hydro 用户群:1085853538"),v,o(" Telegram "),e("a",x,[o("@webpack_exports_undefined"),t(r)])]),j,e("p",null,[o("若您需要对这些模块闭源处理,请考虑联系我们以购买许可。"),G,o(" 鉴于 Mirai 处的 "),e("a",w,[o("不和谐事件"),t(r)]),o(" 对此项目做如下声明:")]),E,e("ul",null,[e("li",null,[e("a",I,[o("Github"),t(r)]),o(" 为 Hydro 提供了代码托管与自动构建。")]),e("li",null,[e("a",L,[o("criyle"),t(r)]),o(" 提供评测沙箱实现。")]),e("li",null,[e("a",N,[o("Vijos"),t(r)]),o(" 为 Hydro 提供了UI框架。")])])])}const C=n(h,[["render",P],["__file","index.html.vue"]]);export{C as default}; diff --git a/assets/index.html-7d740a66.js b/assets/index.html-7d740a66.js new file mode 100644 index 00000000..2fbfcb39 --- /dev/null +++ b/assets/index.html-7d740a66.js @@ -0,0 +1 @@ +import{_ as t}from"./plugin-vue_export-helper-c27b6911.js";import{o as a,c as o,a as e,b as c}from"./app-68b9e0b9.js";const n={},r=e("h1",{id:"api",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#api","aria-hidden":"true"},"#"),c(" API")],-1),s=e("p",null,"此处列出部分系统通信协议。",-1),_=[r,s];function i(d,l){return a(),o("div",null,_)}const m=t(n,[["render",i],["__file","index.html.vue"]]);export{m as default}; diff --git a/assets/index.html-908cadc5.js b/assets/index.html-908cadc5.js new file mode 100644 index 00000000..afa4e595 --- /dev/null +++ b/assets/index.html-908cadc5.js @@ -0,0 +1 @@ +const t=JSON.parse('{"key":"v-8daa1a0e","path":"/","title":"","lang":"en-US","frontmatter":{"home":true,"heroImage":"/favicon.png","heroText":"Hydro","tagline":"高性能在线测评系统","actions":[{"text":"介绍 💡","link":"/docs/","type":"primary"},{"text":"部署指南","link":"/docs/install/"}],"features":[{"title":"安全","details":"使用 cgroup 隔离用户程序"},{"title":"便捷","details":"支持使用脚本一键搭建"},{"title":"强大","details":"提供了比赛 训练 讨论 题解 作业等功能,并可通过安装附加组件进行扩展"},{"title":"快速","details":"沙箱复用,延迟计算,提高运行效率"}],"footer":"AGPL3.0 Licensed | Copyright © 2021-present Undefined","description":"LICENSE GitHub Workflow Status hydrooj npm node-current GitHub contributors GitHub commit activity Hydro 是一个高效的信息学在线测评系统。特点:易于部署(且提供安装脚本),轻量,功能强大且易于扩展。 Github 仓库 (https://github...","head":[["meta",{"property":"og:url","content":"https://hydro.js.org/"}],["meta",{"property":"og:site_name","content":"Hydro"}],["meta",{"property":"og:description","content":"LICENSE GitHub Workflow Status hydrooj npm node-current GitHub contributors GitHub commit activity Hydro 是一个高效的信息学在线测评系统。特点:易于部署(且提供安装脚本),轻量,功能强大且易于扩展。 Github 仓库 (https://github..."}],["meta",{"property":"og:type","content":"website"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-05-19T14:49:26.000Z"}],["meta",{"property":"article:modified_time","content":"2023-05-19T14:49:26.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"WebPage\\",\\"name\\":\\"\\",\\"description\\":\\"LICENSE GitHub Workflow Status hydrooj npm node-current GitHub contributors GitHub commit activity Hydro 是一个高效的信息学在线测评系统。特点:易于部署(且提供安装脚本),轻量,功能强大且易于扩展。 Github 仓库 (https://github...\\"}"]]},"headers":[{"level":2,"title":"联系我们","slug":"联系我们","link":"#联系我们","children":[]},{"level":2,"title":"开源许可","slug":"开源许可","link":"#开源许可","children":[]},{"level":2,"title":"鸣谢","slug":"鸣谢","link":"#鸣谢","children":[]}],"git":{"createdTime":1595413301000,"updatedTime":1684507766000,"contributors":[{"name":"undefined","email":"i@undefined.moe","commits":7},{"name":"Macesuted Kysic","email":"57275149+Macesuted@users.noreply.github.com","commits":3},{"name":"Macesuted Kysic","email":"macesuted@foxmail.com","commits":3},{"name":"(Macesuted)","email":"macesuted@foxmail.com","commits":2},{"name":"Macesuted","email":"57275149+Macesuted@users.noreply.github.com","commits":2},{"name":"undefined","email":"masnn0@outlook.com","commits":2},{"name":"Macesuted","email":"macesuted@qq.com","commits":1},{"name":"Macesuted Kysic","email":"macesuted@qq.com","commits":1},{"name":"panda","email":"panda_dtdyy@outlook.com","commits":1}]},"readingTime":{"minutes":2.53,"words":758},"filePathRelative":"README.md","localizedDate":"July 22, 2020","autoDesc":true,"excerpt":""}');export{t as data}; diff --git a/assets/index.html-a019e00a.js b/assets/index.html-a019e00a.js new file mode 100644 index 00000000..99343800 --- /dev/null +++ b/assets/index.html-a019e00a.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-666426ae","path":"/docs/user/","title":"用户文档","lang":"en-US","frontmatter":{"description":"题目难度 Hydro 中题目的难度,根据递交数、通过率以及每个递交的递交时间和评测结果,通过算法计算得出。 1. 一般地,难度的数值越大,该题目越难。 2. 新题目的难度可能不准确;在题目获得大量递交之后,难度才会变得较为准确。 3. 越早递交评测的用户代码的评测结果对题目难度影响越大。 4. 题目的难度由算法计算得出,有可能出现不准确的结果。 参与比...","head":[["meta",{"property":"og:url","content":"https://hydro.js.org/docs/user/"}],["meta",{"property":"og:site_name","content":"Hydro"}],["meta",{"property":"og:title","content":"用户文档"}],["meta",{"property":"og:description","content":"题目难度 Hydro 中题目的难度,根据递交数、通过率以及每个递交的递交时间和评测结果,通过算法计算得出。 1. 一般地,难度的数值越大,该题目越难。 2. 新题目的难度可能不准确;在题目获得大量递交之后,难度才会变得较为准确。 3. 越早递交评测的用户代码的评测结果对题目难度影响越大。 4. 题目的难度由算法计算得出,有可能出现不准确的结果。 参与比..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2021-05-08T17:02:49.000Z"}],["meta",{"property":"article:modified_time","content":"2021-05-08T17:02:49.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"用户文档\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2021-05-08T17:02:49.000Z\\",\\"author\\":[]}"]]},"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":[]}],"git":{"createdTime":1620493369000,"updatedTime":1620493369000,"contributors":[{"name":"undefined","email":"i@undefined.moe","commits":1}]},"readingTime":{"minutes":1.53,"words":459},"filePathRelative":"docs/user/README.md","localizedDate":"May 8, 2021","autoDesc":true,"excerpt":""}');export{e as data}; diff --git a/assets/index.html-a6352b1b.js b/assets/index.html-a6352b1b.js new file mode 100644 index 00000000..1809bde0 --- /dev/null +++ b/assets/index.html-a6352b1b.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-723d0d85","path":"/docs/system/","title":"System","lang":"en-US","frontmatter":{"title":"System","article":false,"feed":false,"sitemap":false,"description":"","head":[["meta",{"property":"og:url","content":"https://hydro.js.org/docs/system/"}],["meta",{"property":"og:site_name","content":"Hydro"}],["meta",{"property":"og:title","content":"System"}],["meta",{"property":"og:type","content":"website"}],["meta",{"property":"og:locale","content":"en-US"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"WebPage\\",\\"name\\":\\"System\\"}"]]},"headers":[],"git":{},"readingTime":{"minutes":0,"words":1},"filePathRelative":null,"autoDesc":true,"excerpt":""}');export{e as data}; diff --git a/assets/index.html-acd9b80b.js b/assets/index.html-acd9b80b.js new file mode 100644 index 00000000..cbfa0b9e --- /dev/null +++ b/assets/index.html-acd9b80b.js @@ -0,0 +1,3 @@ +import{_ as t}from"./plugin-vue_export-helper-c27b6911.js";import{r as s,o as i,c as r,a as e,b as n,d as o,w as c,e as p}from"./app-68b9e0b9.js";const d={},h=e("h1",{id:"部署-hydro",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#部署-hydro","aria-hidden":"true"},"#"),n(" 部署 Hydro")],-1),u=e("br",null,null,-1),b=e("h2",{id:"服务器选择",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#服务器选择","aria-hidden":"true"},"#"),n(" 服务器选择")],-1),y=e("p",null,[n("不同服务商提供的 CPU 主频不同,下方数据仅供参考。"),e("br"),n(" 最低服务器配置: CPU: 1核 内存: 2G。(约可允许 100 人使用)"),e("br"),e("strong",null,"请尽量不要使用突发性能实例或共享型实例,这可能会导致评测时间计量不准确")],-1),E={href:"https://www.centos.org/centos-linux-eol/",target:"_blank",rel:"noopener noreferrer"},_=p(`

Tips

兼容大部分 Linux 发行版,推荐使用 Debian 12 / Debian 11 / Ubuntu 22.04 (教程多,成功率高,上手简单),不支持 CentOS 及其各种变种:

  • CentOS
  • Alibaba Cloud Linux
  • TencentOS
  • OpenCloudOS

如果你的机器内存较小(<=2GiB),请避免使用 Ubuntu 22.04,它会消耗较多的内存。建议使用 Debian 12 / Debian 11。
如果你有 Linux 运维经验,Hydro 同样支持在 Alpine Linux 上运行,Alpine Linux 系统启动后仅占用 ~100M 内存,是在低配置服务器上运行的更优方案。

Note

虚拟机用户请注意:

  • Hydro 使用的数据库依赖于 CPU 的 avx 指令集以提高运行性能,大部分虚拟机软件默认没有启用 avx 指令集,请参照您使用的虚拟机软件说明。
  • 虚拟机由于非独占 CPU,会导致评测时间计量精度降低。
  • 由于虚拟机本身的数据保存机制,突然断电很容易导致数据库损坏无法读取,请务必定期备份数据库,有条件请购买 UPS 保证供电稳定。

Docker 用户请注意:

  • 使用安装脚本需要设置 USER 环境变量为 root
  • 需要使用 --privileged 参数启动容器,否则评测机无法运行。

部署

Tips

Hydro 需要使用以下端口: 80, 443, 2019, 8888, 5050, 27017,请确保这些端口空闲。
安装和安装后的所有操作均需要在 root 权限下进行!(sudo su
宝塔面板已知出现多次高危漏洞,为防止数据丢失,请不要在生产环境中使用!

运行下面的脚本,等待几分钟即可(建议复制防止敲错):

LANG=zh . <(curl https://hydro.ac/setup.sh)
+

Tips

如果有特殊需求,安装脚本支持一些可选的高级选项,以此方式调用: . <(curl https://hydro.ac/setup.sh) --foo --bar

  • --no-caddy 不配置安装反向代理,只监听8888端口
  • --judge 仅作为独立评测机安装

阿里云/腾讯云/华为云等等用户安装后如果不能访问 请百度搜索 xx云 放行80端口
脚本默认使用的为清华大学镜像。
安装完成后,从 http://服务器ip/ 访问网页端,注册一个账号,之后在终端中使用

hydrooj cli user setSuperAdmin 2
+

将首个注册用户设置为超级管理员。之后刷新页面,您应当能在上方导航栏看到控制面板入口。
进入控制面板,右侧系统设置,验证管理员密码后按需修改配置,注意 Server BaseURL 一项需要填写访问网站用的完整的 URL,以 / 结尾。(重要,务必正确填写,样例:https://hydro.ac/

系统安装后需要题库,可前往 https://hydro.ac/d/tk/p 免费专区进行下载,支持批量导入。 至此,基础功能安装已全部完成,另,如果你的服务部署在内网,且希望外网的用户可以访问,可以百度搜索 “端口映射” 相关教程。

`,11);function v(x,C){const a=s("RouterLink"),l=s("ExternalLinkIcon");return i(),r("div",null,[h,e("p",null,[n("这里提供了几套方案帮助您建立自己的站点,请选择适合您的方案并继续。"),u,n(" 搭建过程中如果遇到问题欢迎 "),o(a,{to:"/#%E8%81%94%E7%B3%BB%E6%88%91%E4%BB%AC"},{default:c(()=>[n("联系我们")]),_:1}),n(" 提问。")]),b,y,e("p",null,[n("CentOS 8 "),e("a",E,[n("已于 2021-12-31 停止支持"),o(l)]),n(",后续不会为安全漏洞发布补丁,建议重装为其他操作系统。")]),_])}const f=t(d,[["render",v],["__file","index.html.vue"]]);export{f as default}; diff --git a/assets/index.html-bbe29c8a.js b/assets/index.html-bbe29c8a.js new file mode 100644 index 00000000..fc3da446 --- /dev/null +++ b/assets/index.html-bbe29c8a.js @@ -0,0 +1 @@ +import{_ as o}from"./plugin-vue_export-helper-c27b6911.js";import{r as t,o as n,c,d as r}from"./app-68b9e0b9.js";const a={};function _(s,l){const e=t("AutoCatalog");return n(),c("div",null,[r(e)])}const f=o(a,[["render",_],["__file","index.html.vue"]]);export{f as default}; diff --git a/assets/index.html-bf152e78.js b/assets/index.html-bf152e78.js new file mode 100644 index 00000000..d76b4d5a --- /dev/null +++ b/assets/index.html-bf152e78.js @@ -0,0 +1,4 @@ +import{_ as r}from"./plugin-vue_export-helper-c27b6911.js";import{r as p,o as t,c as E,f as c,a,b as s,d as n,w as y,e as o}from"./app-68b9e0b9.js";const D={},F=o('

常见问题集合

好消息!本页和各大浏览器均达成了合作,使用 Ctrl-F 即可快速搜索关键词!

更多教程请点击右上角的常用教程查看。

',3),C=a("h2",{id:"用户qq群-1085853538",tabindex:"-1"},[a("a",{class:"header-anchor",href:"#用户qq群-1085853538","aria-hidden":"true"},"#"),s(" 用户QQ群 1085853538")],-1),d=a("h2",{id:"如何快速上手了解系统功能",tabindex:"-1"},[a("a",{class:"header-anchor",href:"#如何快速上手了解系统功能","aria-hidden":"true"},"#"),s(" 如何快速上手了解系统功能?")],-1),i={href:"https://hydro.ac/discuss/6172ceeed850d38c79ae18f9",target:"_blank",rel:"noopener noreferrer"},h=a("br",null,null,-1),A=a("br",null,null,-1),u=o('

系统中的用户只有编辑、禁用功能,没有删除功能,这是为了从根源上防止出现“教学事故”,请不要要求增加相关功能,如果认为自己绝不会误操作,请自行开发相关功能。

什么是 OJ?

现在你所使用的评测系统也仅仅是一个程序,并没有人工智能。因此很多地方需要你来迁就它,如果不这样做,你的答案即使本质上是正确的,由于形式的错误造成系统不能理解,也会导致错误。
系统运行过程如下:

  • 教师在系统中添加题目,并严格定义题目提供输入数据的格式和要求的输出数据格式。
  • 教师根据题目定义的格式向系统中添加若干组测试数据,每组数据都包含输入数据和对应的输出。
  • 学生阅读题目,并根据自己的理解提交程序。
  • 系统编译并运行学生的程序,再将老师事先提供的输入数据“喂”给学生的程序,看它会输出什么。
  • 如果学生程序的输出与老师之前提供的输出完全一致,一字不差,则认为学生的程序是正确的,否则则认为该程序错误。
  • 如果运行过程中出现内存、时间上超出题目限制的情况,则中断程序的运行,并认为答案不正确。

在了解了上面的情况以后,同学们应该理解,如果题目没有要求程序输出“Please Input Two Number”之类的提示信息,那么自行输出这些文字将导致你的程序输出与老师事先告诉系统的输出不能做到“一字不差”,因而将导致系统报答案错误。
如果题目要求每两行输出之间要空一行,结果你没有空,会是格式错误,反之亦然。
也许你会觉得,哦,这系统太烂了,这点东西都不能自动识别;实际上正是这样才能有效训练大家编程的精确性、养成良好的代码习惯。很多程序高手都跟你一样,是从对这个系统吐槽开始学习如何认真仔细的、一丝不苟的进行编程的。
系统为了能用统一的方式运行所有同学的答案,不得不对所有人提交的答案的形式进行限定。
对于学习C、C++语言的同学来说,所有提交给系统的答案必须包含并且只有一个main函数,这个main函数必须返回int类型,并且最好返回0,因为操作系统对非零的返回值认为是运行出错。
编译错误发生时,点击“编译错误”的文字链接可以得到详细解释。

Arch Linux 开发模式安装时出现 [ERR_STREAM_PREMATURE_CLOSE]: Premature close 错误

删除 .yarnrc.yml.yarn 后再试。

为什么我安装完成之后仍然无法访问?

如果您使用的是 阿里云/腾讯云 等服务商,请确保安全组放行了 80 和 443 端口。

为什么我配置完反向代理(caddy/nginx)之后无法登录(出现CsrfTokenError)?

',10),m=o('

怎么备份/还原备份/迁移数据?

hydrooj backup hydrooj restore backup-xxx.zip

百度学习 crontab 的用法后,可以使用 sudo crontab -e 定制自动备份计划。

恢复备份时出现 '/data/file/hydro': Directory not empty

关闭 minio (pm2 stop minio) 后手动删除 /data/file/hydro 文件夹再重试。

更新升级

yarn global upgrade-interactive --latest 然后按空格选中除 pm2 之外的所有包更新,回车确认。 然后 pm2 restart hydrooj 重启服务。 重启后 pm2 logs hydrooj --lines 100 没有看到报错并看到了 Server started 则一切正常。

Hydro 的所有历史版本,都可以无损升级到最新版本。如果老系统更新有疑问,随时加官方群咨询群主。

怎么导入题目/创建题目?

题目列表右侧有相应入口。

切记:不要导入过多你暂时用不上的题目,正确的方式是每次训练、作业,导入所需的5-10个题目,比赛作业结束后让题目成为训练题库的一部分。这样能保证题库中题号靠前的题目难度依次上升,适合后来的同学自行训练。不要贪图题目数量而忽视其质量。自己看不懂解法的题目,少用、慎用。

如何限制未登录用户访问?

管理域 -> 管理权限 将 Guest 权限组的 查看此域 权限禁用。

比赛作业里面的时间是什么含义,OI排名跟普通排名有何区别?

时间是指参与人员做出对应题目“花费”的时间:
即:做出题目的时刻 – 比赛开始的时刻 + 惩罚时间
惩罚时间 = 做对之前错误的提交数 * 20分钟。
普通排名按做对的题目数和“花费”的时间进行排名。
OI排名,按得分排名,题目可以按通过的比例进行记分,每题100分。如果希望数据的分值不平均分配,可以使用 config 配置。

脚本把 OJ 装在哪里了?

Hydro 的默认位置可以运行 yarn global dir 得到。(不要直接改代码,更新会覆盖此处的所有修改,请使用插件API)
默认的数据库文件放置在 /data/db,但是不要直接复制文件,而是推荐用 hydrooj backup 进行备份。
测试数据等文件存储于 /data/file
配置文件位于 /root/.config/hydro/root/.hydro。 对于正在运行中的生产服务器,任何操作前请做好离线备份。
备份文件一定要解压查看内部是否包含全部数据,关注备份的大小(大系统备份应该有上百兆),有条件找虚拟机实测还原是否成功

题目的限时和内存限制的精度是怎样的?

题目限时允许设定的字面精度是 1ms,但是由于操作系统内核参数的限定,实测的精度通常为4ms。 内存限制的精度是1MB,对于本地native的编译型语言c/c++/pascal/freebasic/clang等是考察程序本身的内存申请空间; 对于虚拟机和脚本语言,则包含了虚拟机本身或解释器本身的内存消耗。

我想让 Python 支持 numpy 等等库,怎么办?

如果你是 2022/8/12 日前安装,使用 pip3 install numpypm2 restart hydro-sandbox
否则参照请参照 编译器 章节。

使用安装脚本后忘记 MongoDB 的账号密码怎么办?

/root/.hydro/config.json

如何关闭、打开用户注册?

用户注册由 Guest 用户(uid 为 0)的 PRIV_REGISTER_USER 权限控制,默认允许注册。 使用 hydrooj cli user setPriv 0 0 即可关闭注册。 若要重新打开,可使用 hydrooj cli user setPriv 0 8

变更后,请重启 hydrooj 服务:pm2 restart hydrooj

用户名为 Hydro 的用户是干什么的?密码是什么?可以登录么?

用户名为 Hydro 的用户(uid 为 1)仅用于发送系统消息(与 QQ 中的 10000 类似),无法登录。

如何修改网站图标?

使用 hydrooj addon create 创建一个插件,这会自动创建 /root/addon 目录。
进入 /root/addon/public 目录,将您的站点图标放置于该文件夹下。
您需要将以下文件放在该目录中(适配不同浏览器):

  • favicon-16x16.png
  • favicon-32x32.png
  • favicon-96x96.png
  • favicon.ico (32x32)
  • android-chrome-192x192.png
  • apple-touch-icon-180x180.png

分辨率应尽可能对应,但不强制要求。以上图片将在浏览器标签页图片上显示。
您还需要将以下文件放在该目录:

  • nav_logo_dark.png

以上图片将在页面左上角 logo 显示。 之后前往系统设置,找到 nav_logo_dark 设置项,改为 /nav_logo_dark.png ,重启 Hydro 即可应用更改。

记得清理浏览器缓存。

如何重置数据?

Note

此操作会删除所有用户/题目/比赛等数据。请谨慎操作!

',37),b={href:"https://github.com/hydro-dev/Hydro/blob/master/install/reset.sh",target:"_blank",rel:"noopener noreferrer"},x=o(`

您可按需更改,显示顺序与配置中的排列顺序相同。

评测显示“总时限超过 60s,评测取消”

在系统设置中修改 total_time_limit 为允许的单题最大评测时长即可。

如何在背景中添加线条特效?

在系统设置中找到 footer_extra_html 项,加上如下内容:(写在一行内,不要多加换行)

基于 https://github.com/hustcc/canvas-nest.js ,MIT

<script>(()=>{function e(e,n,t){return e.getAttribute(n)||t}function n(){l=i.width=window.innerWidth||document.documentElement.clientWidth||document.body.clientWidth,u=i.height=window.innerHeight||document.documentElement.clientHeight||document.body.clientHeight}function c(){var t,o,i,a,m;r.clearRect(0,0,l,u),s.forEach(function(e,n){for(e.x+=e.xa,e.y+=e.ya,e.xa*=e.x>l||e.x<0?-1:1,e.ya*=e.y>u||e.y<0?-1:1,r.fillRect(e.x-.5,e.y-.5,1,1),o=n+1;o<d.length;o++)null!==(t=d[o]).x&&null!==t.y&&(i=e.x-t.x,a=e.y-t.y,(m=i*i+a*a)<t.max&&(t===y&&m>=t.max/2&&(e.x-=.03*i,e.y-=.03*a),m=(t.max-m)/t.max,r.beginPath(),r.lineWidth=m/2,r.strokeStyle="rgba("+x.c+","+(.2+m)+")",r.moveTo(e.x,e.y),r.lineTo(t.x,t.y),r.stroke()))}),w(c)}var l,u,d,t,o,i=document.createElement("canvas"),x=(t=(o=document.getElementsByTagName("script")).length,o=o[t-1],{l:t,z:e(o,"zIndex",-1),o:e(o,"opacity",.5),c:e(o,"color","0,0,0"),n:e(o,"count",99)}),a="c_n"+x.l,r=i.getContext("2d"),w=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(e){window.setTimeout(e,1e3/45)},m=Math.random,y={x:null,y:null,max:2e4};i.id=a,i.style.cssText="position:fixed;top:0;left:0;z-index:"+x.z+";opacity:"+x.o,document.getElementsByClassName("main")[0].appendChild(i),n(),window.onresize=n,window.onmousemove=function(e){e=e||window.event,y.x=e.clientX,y.y=e.clientY},window.onmouseout=function(){y.x=null,y.y=null};for(var s=[],h=0;x.n>h;h++){var f=m()*l,g=m()*u,p=2*m()-1,v=2*m()-1;s.push({x:f,y:g,xa:p,ya:v,max:6e3})}d=s.concat([y]),setTimeout(function(){c()},100)})();</script>
+

使用 Hydro 要花多少钱?

`,8),f={href:"https://pay.undefined.moe",target:"_blank",rel:"noopener noreferrer"},g=o(`

execve: no such file or directory

脚本安装默认只装了一小部分编译器。请参照 编译器 章节安装配置其他编译器。

怎么自定义用户标签?

进入 MongoDB,执行下面的操作即可(根据具体情况替换尖括号中的部分):

use hydro
+db.user.update({"_id": <用户 UID>}, {$set: {"badge": "<标签内容>#<背景颜色(HEX)>#<文字颜色(HEX)>"}})
+

为什么我无法批量下载多个文件?

请使用现代浏览器进行操作,并尝试给网站设置 https。 否则请选择逐个下载文件(Ctrl+点击文件名)。

为什么我的提交页面没有语言可选?

题目 -> 评测设置 -> 允许的语言
域设置 -> 编辑域资料 -> 允许的语言
这两个地方,应该填英文逗号分隔的语言ID,不会填请留空。

The 'yarn global' commands have been remove in 2.x - consider using 'yarn dlx' or a third-party plugin instead

如果你搞不明白这个问题,请老实用安装脚本,不要折腾开发模式。

我是机房用户,大量用户同 IP 操作触发了频率限制,怎么解决?

方案一: 通过在内网架设代理服务器,将内网 ip 发送至服务端。(推荐)
方案二: 使用形如 hydrooj cli system set limit.user_login 999 的命令设置新的频率限制(可在错误页面查看具体是触发了哪条限制)
方案三: 使用 pm2 start hydrooj -- --benchmark 启动,关闭所有频率限制(不推荐)

`,13);function _(B,v){const l=p("ExternalLinkIcon"),e=p("RouterLink");return t(),E("div",null,[F,c(" 本页面遵循能用就行的原则。 "),C,d,a("p",null,[s("参照本文 "),a("a",i,[s("https://hydro.ac/discuss/6172ceeed850d38c79ae18f9"),n(l)]),s(" 无服务器快速体验系统功能。"),h,s(" 如果你没有二开很多功能的需求,推荐直接使用在线服务。超过两万题的题库可以直接复制使用,无需购置云服务器,无需手动维护,更省心。"),A,s(" 如果你有需要绑定自己的域名或是改 Logo 等等自定义需求,也可在管理面板中开通高级功能自助操作。")]),u,a("p",null,[s("反向代理时请确保设置了正确的 Host Header。"),n(e,{to:"/docs/install/proxy.html"},{default:y(()=>[s("详细说明")]),_:1})]),m,a("p",null,[s("将 "),a("a",b,[s("此脚本"),n(l)]),s(" 下载到服务器运行。")]),x,a("p",null,[s("不要钱,我们是 AGPL 的。如果你钱多,可以 "),a("a",f,[s("给我发个红包"),n(l)]),s("。")]),g])}const k=r(D,[["render",_],["__file","index.html.vue"]]);export{k as default}; diff --git a/assets/index.html-c0e68838.js b/assets/index.html-c0e68838.js new file mode 100644 index 00000000..3e05b8ca --- /dev/null +++ b/assets/index.html-c0e68838.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-67d16688","path":"/plugins/","title":"插件","lang":"en-US","frontmatter":{"description":"Hydro 支持使用插件扩展自身所支持的功能。 插件对站点的所有内容具有完全的访问权限,请不要启用来历不明的插件。 附加组件列表 部分斜体字插件需配合额外支持软件,如您只安装插件是无法使用的,详情请前往左侧插件详情查看。 如您为旧版本升级失去博客功能,请直接安装 @hydrooj/blog ,原数据不会丢失。 Hydro 官方目前提供了以下附加组件: ...","head":[["meta",{"property":"og:url","content":"https://hydro.js.org/plugins/"}],["meta",{"property":"og:site_name","content":"Hydro"}],["meta",{"property":"og:title","content":"插件"}],["meta",{"property":"og:description","content":"Hydro 支持使用插件扩展自身所支持的功能。 插件对站点的所有内容具有完全的访问权限,请不要启用来历不明的插件。 附加组件列表 部分斜体字插件需配合额外支持软件,如您只安装插件是无法使用的,详情请前往左侧插件详情查看。 如您为旧版本升级失去博客功能,请直接安装 @hydrooj/blog ,原数据不会丢失。 Hydro 官方目前提供了以下附加组件: ..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-05-12T03:18:30.000Z"}],["meta",{"property":"article:modified_time","content":"2023-05-12T03:18:30.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"插件\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-05-12T03:18:30.000Z\\",\\"author\\":[]}"]]},"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":[]}],"git":{"createdTime":1595413301000,"updatedTime":1683861510000,"contributors":[{"name":"Macesuted Kysic","email":"macesuted@foxmail.com","commits":6},{"name":"undefined","email":"i@undefined.moe","commits":6},{"name":"(Macesuted)","email":"macesuted@foxmail.com","commits":3},{"name":"Macesuted","email":"macesuted@qq.com","commits":3},{"name":"Macesuted","email":"57275149+Macesuted@users.noreply.github.com","commits":2},{"name":"无限UCW","email":"45730483+wuxianucw@users.noreply.github.com","commits":2},{"name":"panda","email":"panda_dtdyy@outlook.com","commits":1},{"name":"undefined","email":"masnn0@outlook.com","commits":1}]},"readingTime":{"minutes":1.76,"words":528},"filePathRelative":"plugins/README.md","localizedDate":"July 22, 2020","autoDesc":true,"excerpt":""}');export{e as data}; diff --git a/assets/index.html-ca113d25.js b/assets/index.html-ca113d25.js new file mode 100644 index 00000000..ebcb9046 --- /dev/null +++ b/assets/index.html-ca113d25.js @@ -0,0 +1,7 @@ +import{_ as a}from"./plugin-vue_export-helper-c27b6911.js";import{r as l,o as r,c as d,a as s,b as o,d as e,e as c}from"./app-68b9e0b9.js";const p={},t=s("h1",{id:"开发环境部署",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#开发环境部署","aria-hidden":"true"},"#"),o(" 开发环境部署")],-1),i=s("p",null,[o("如果您没有过 TypeScript 项目的开发经验,非常不建议自建开发环境。"),s("br"),o(" 使用自动脚本安装也可以基于插件系统完成大部分的定制需求(参照左侧【使用 TypeScript 编写插件】章节)。")],-1),y={href:"https://gitpod.io/#https://github.com/hydro-dev/Hydro",target:"_blank",rel:"noopener noreferrer"},h=s("h2",{id:"安装依赖",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#安装依赖","aria-hidden":"true"},"#"),o(" 安装依赖")],-1),u=s("li",null,"系统要求:Hydro开发环境目前仅支持 Linux/Unix 系统,如您使用 Windows 请使用 WSL2 。",-1),E={href:"https://www.mongodb.com/try/download/community",target:"_blank",rel:"noopener noreferrer"},D=s("li",null,[o("NodeJS:请安装 NodeJS >=18 版本。(若使用 apt 请使用 nodesource 提供的源替代官方源) (推荐使用 nix ,可通过"),s("code",null,". <(curl https://hydro.ac/nix.sh)"),o(" 快速安装)")],-1),b=s("li",null,[o("yarn:安装 yarn 前请先完成 NodeJS 安装。 "),s("code",null,"npm install -g yarn")],-1),F=c(`

尽管这不是必须的,但文档多数区域使用了 npx 工具来调用工作区的程序。如果此命令不存在,你可以在 Hydro 项目文件夹外使用 yarn global add npx 安装它。

安装 Hydro

git clone https://github.com/hydro-dev/Hydro.git /root/Hydro --recursive # 下载至 /root/Hydro 文件夹
+cd /root/Hydro # 进入工作目录
+yarn # 安装依赖包
+yarn build:ui:production # 编译前端
+

插件

开发环境部署完成后默认不启用任何插件。

所有官方插件均随源码仓库下载到安装文件夹的 packages 子文件夹下,可以通过下面的命令启用官方插件(以启用 @hydrooj/ui-default 为例):

npx hydrooj addon add @hydrooj/ui-default
+

对于非官方插件,下载后通过下面的命令启用即可(以启用位置在 /root/addon 下的插件为例):

npx hydrooj addon add /root/addon
+

启动 Hydro

支持如下启动参数:

  • --port=2333 指定启动端口
  • --debug 启用开发模式

使用 yarn debug --port=2333 --watch 启动 Hydro,并在后台运行 yarn build:ui:dev,可以对前端源码进行实时转译,在反复修改时可节省编译时间。启动完成后,您可以在 8000 端口访问到 Hydro 实例,且前端的任何更改将即时生效。(后端热重载可能存在 bug,部分模块修改后可能仍需重启才能生效)
请注意:此功能仅在启用了 @hydrooj/ui-default 插件的情况下才会生效。

首次启动会要求您填写数据库连接信息。请根据您数据库的安装填写(若无密码则留空)
请按照下文说明创建管理员账户即可正常使用。

更新

需要更新的时候进入对应仓库文件夹执行 git pull,然后重新 yarn && yarn build:ui:production 即可。

`,16);function m(_,v){const n=l("ExternalLinkIcon");return r(),d("div",null,[t,i,s("p",null,[o("您可以使用 "),s("a",y,[o("Gitpod"),e(n)]),o(" 快速打开配置完成的开发环境或是按照下方说明进行手动配置。(由于 Gitpod 的限制,hydrojudge 模块无法正常运行,若需要开发 hydrojudge 相关内容请自行部署)")]),h,s("ul",null,[u,s("li",null,[o("MongoDB:Hydro 需要 "),s("a",E,[o("MongoDB"),e(n)]),o(" 提供数据库服务。")]),D,b]),F])}const f=a(p,[["render",m],["__file","index.html.vue"]]);export{f as default}; diff --git a/assets/index.html-e7b92749.js b/assets/index.html-e7b92749.js new file mode 100644 index 00000000..0c15d4b0 --- /dev/null +++ b/assets/index.html-e7b92749.js @@ -0,0 +1,14 @@ +import{_ as a}from"./plugin-vue_export-helper-c27b6911.js";import{o as e,c as n,f as o,e as s}from"./app-68b9e0b9.js";const t={},d=s('

插件

Hydro 支持使用插件扩展自身所支持的功能。

Note

插件对站点的所有内容具有完全的访问权限,请不要启用来历不明的插件。

附加组件列表

Tips

部分斜体字插件需配合额外支持软件,如您只安装插件是无法使用的,详情请前往左侧插件详情查看。

如您为旧版本升级失去博客功能,请直接安装 @hydrooj/blog ,原数据不会丢失。

Hydro 官方目前提供了以下附加组件:

ID描述
@hydrooj/blog博客功能
@hydrooj/fps-importer导入 fps 格式的题目
@hydrooj/geoip显示用户登录地(需要IP库支持)
@hydrooj/hydrojudge评测组件
@hydrooj/import-qduoj导入 QDUOJ 导出的题库
@hydrooj/login-with-github允许用户使用 GitHub 登录
@hydrooj/login-with-google允许用户使用 Google 登录
@hydrooj/migrate从 vijos4/HustOJ/SYZOJ/UniversalOJ 升级
@hydrooj/recaptcha注册时启用 reCAPTCHA 验证码
@hydrooj/ui-defaultHydro 的默认用户界面
@hydrooj/onlyoffice显示 doc/docx 格式题目
@hydrooj/sonic基于 sonic 的题目搜索增强
@hydrooj/elastic-search基于 Elastic 的题目搜索增强
@hydrooj/vjudgeCodeforces/SPOJ/UOJ/POJ/Luogu
@hydrooj/prom-client导出系统状态至 Prometheus
',7),r=s(`

大部分插件的配置均可在安装后于 控制面板>系统设置 中找到。

部分插件若安装后没有正确配置可能会影响系统正常使用!

安装

先全局安装所需模块,再向 hydrooj 注册即可。例:安装 @hydrooj/geoip

yarn global add @hydrooj/geoip
+hydrooj addon add @hydrooj/geoip
+

或者,如果你正在安装一个其他途径获取的插件(自行创建等),请直接使用文件夹 绝对路径: (文件夹路径即为 包含 package.json 的文件夹)

hydrooj addon add /root/xxx
+

请不要将插件与插件嵌套摆放,否则可能会导致一些不可预知的问题。

安装完插件后需要重启 hydrooj 以使插件生效。

查看已注册的插件列表

hydrooj addon list
+

更新

yarn global upgrade-interactive --latest
+

卸载

yarn global remove @hydrooj/geoip
+hydrooj addon remove @hydrooj/geoip
+
`,15);function l(p,i){return e(),n("div",null,[d,o(` +以下插件由社区提供: + +| ID | 作者 | 描述 | +| -------------------------------------------------- | --------- | ---------------------------- | +| [hydro-pdf-preview](//github.com/Ri-moe/hydro-pdf) | wuxianucw | 使用 PDF.js 在题面中插入 PDF | +`),r])}const y=a(t,[["render",l],["__file","index.html.vue"]]);export{y as default}; diff --git a/assets/index.html-f38274db.js b/assets/index.html-f38274db.js new file mode 100644 index 00000000..d1c35a44 --- /dev/null +++ b/assets/index.html-f38274db.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-147825fb","path":"/docs/","title":"介绍","lang":"en-US","frontmatter":{"description":"为什么使用 Hydro? 安全:使用 cgroup 进行隔离,杜绝卡评测;; 高效:Hydro 使用了沙箱复用技术,拥有极高的评测效率;; 扩展:Hydro 支持安装额外模块进行扩展;; 强大:配合 Judge 模块(或 HydroJudge 独立评测机),可支持 spj,交互题,提交答案题,文件IO 等多种特性;; 自定:所有权限节点均可自由设置;;...","head":[["meta",{"property":"og:url","content":"https://hydro.js.org/docs/"}],["meta",{"property":"og:site_name","content":"Hydro"}],["meta",{"property":"og:title","content":"介绍"}],["meta",{"property":"og:description","content":"为什么使用 Hydro? 安全:使用 cgroup 进行隔离,杜绝卡评测;; 高效:Hydro 使用了沙箱复用技术,拥有极高的评测效率;; 扩展:Hydro 支持安装额外模块进行扩展;; 强大:配合 Judge 模块(或 HydroJudge 独立评测机),可支持 spj,交互题,提交答案题,文件IO 等多种特性;; 自定:所有权限节点均可自由设置;;..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:image","content":"https://hydro.js.org/"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-06-21T14:07:07.000Z"}],["meta",{"name":"twitter:card","content":"summary_large_image"}],["meta",{"name":"twitter:image:alt","content":"介绍"}],["meta",{"property":"article:modified_time","content":"2023-06-21T14:07:07.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"介绍\\",\\"image\\":[\\"https://hydro.js.org/\\"],\\"dateModified\\":\\"2023-06-21T14:07:07.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"功能对比","slug":"功能对比","link":"#功能对比","children":[]},{"level":2,"title":"截图","slug":"截图","link":"#截图","children":[]},{"level":2,"title":"现在开始","slug":"现在开始","link":"#现在开始","children":[]}],"git":{"createdTime":1611599229000,"updatedTime":1687356427000,"contributors":[{"name":"undefined","email":"i@undefined.moe","commits":14},{"name":"Macesuted","email":"macesuted@qq.com","commits":4},{"name":"(Macesuted)","email":"macesuted@foxmail.com","commits":2},{"name":"Macesuted","email":"57275149+Macesuted@users.noreply.github.com","commits":1},{"name":"Macesuted Kysic","email":"macesuted@foxmail.com","commits":1},{"name":"panda","email":"panda_dtdyy@outlook.com","commits":1}]},"readingTime":{"minutes":2.47,"words":740},"filePathRelative":"docs/README.md","localizedDate":"January 25, 2021","autoDesc":true,"excerpt":""}');export{e as data}; diff --git a/assets/judge.html-19d8b90f.js b/assets/judge.html-19d8b90f.js new file mode 100644 index 00000000..90b98f7f --- /dev/null +++ b/assets/judge.html-19d8b90f.js @@ -0,0 +1,121 @@ +import{_ as l}from"./plugin-vue_export-helper-c27b6911.js";import{r as o,o as p,c as e,a as n,b as s,d as E,e as F}from"./app-68b9e0b9.js";const t={},c=F(`

评测端通信协议

当前版本 v1 。

评测端交互流程

  • GET /judge/files (检查登陆状态是否有效,若无效则跳转登录逻辑,通常每六小时执行一次)
  • WEBSOCKET /judge/conn (主交互通道)

若登录失效,则进行登录操作。

POST /login
+
+{"uname":"USERNAME","password":"PASSWORD","rememberme":true}
+

WebSocket 连接建立流程

WEBSOCKET /judge/conn
+Authorization: Bearer COOKIE_SID
+

连接建立后,评测端向 Web 汇报当前节点状态(可选)
注:下方信息仅作数据格式展示用,不保证真实有效。

{
+    "key": "status",
+    "info": {
+        "mid": "MACHINE_ID",
+        "memory": {
+            "total": 25189552128,
+            "free": 660258800,
+            "used": 24529293328,
+            "active": 1558973164,
+            "available": 23636676608,
+            "buffers": 3075653000,
+            "cached": 1000000000,
+            "slab": 1000000000,
+            "buffcache": 1000000000,
+            "swaptotal": 0,
+            "swapused": 0,
+            "swapfree": 0
+        },
+        "cpu": {
+            "manufacturer": "Intel",
+            "brand": "Xeon® Platinum 8269CY",
+            "vendor": "Intel",
+            "family": "6",
+            "model": "85",
+            "stepping": "7",
+            "speed": 2.5,
+            "cores": 32,
+            "physicalCores": 32,
+            "processors": 2,
+            "flags": "fpu vme de pse tsc ...",
+            "cache": {
+                "l1d": 32768,
+                "l1i": 32768,
+                "l2": 262144,
+                "l3": 6291456
+            }
+        },
+        "load": {
+            "avgLoad": 0.01,
+            "currentLoad": 0.01,
+            "currentLoadUser": 0.01,
+            "currentLoadSystem": 0.01,
+            "currentLoadNice": 0.01,
+            "currentLoadIdle": 0.01,
+            "currentLoadIrq": 0.01
+        },
+        "osinfo": {
+            "platform": "linux",
+            "distro": "Ubuntu",
+            "release": "22.04.2 LTS",
+            "codename": "Jammy Jellyfish",
+            "kernel": "5.15.0-84-generic",
+            "arch": "x64",
+            "hostname": "judge",
+            "codepage": "UTF-8",
+        }
+    }
+}
+

建立连接后每隔 30s,评测端发送 {"key":"ping"}

语言配置下发

在连接建立后,Web 端会向 Judge 分发服务端的语言设置。如果客户端需要进行特殊设置,可忽略此条消息。

评测任务推送

Web 端会通过 WebSocket 向评测端推送评测任务。

{
+    "task": {
+        "type": "judge",
+        "_id": "RECORD_ID",
+        "lang": "cc.cc11",
+        "uid": SUBMITTER_UID,
+        "code": "USER_SUBMITTED_CODE",
+        "domainId": "SUBMISSION_DOMAIN_ID",
+        "pid": PROBLEM_ID,
+        "contest": "CONTEST_ID (optional)",
+        "input": "INPUT",
+        "source": "SOURCE_ID",
+        "meta": {
+            "rejudge": false,
+            "problemOwner": OWNER_UID
+        },
+        "data": [
+            {
+                "name": "FILE_NAME",
+                "size": SIZE_IN_BYTES,
+                "lastModified": "2023-11-15T08:14:57.535Z",
+                "etag": "ETAG"
+            }
+        ]
+    }
+}
+

注1:如果比赛 ID 为 000000000000000000000000 则表示此提交为自测提交,自测提交使用 input 字段值作为程序输入。
注2:source 字段为缓存 ID,同 source 字段的提交使用相同的缓存目录。
注3:source 字段包含且仅包含一个字符 /,建议使用 domainId/pid
注4:测试数据的 etag 用来识别本地缓存的文件是否与云端一致,可使用 hash 或是修改时间的时间戳。

测试数据下载

若推送的评测任务中使用了的测试数据缺失,Judge 端会向 Web 请求缺失或是修改的文件。

POST /d/:domainId/judge/files
+Cookie: sid=COOKIE_SID
+
+{"pid":PROBLEM_ID,"files":["a.in","a.out"]}
+

服务端返回如下:

{
+    "links": {
+        "a.in": "https://cdn.hydro.ac/d/DOMAIN_ID/pid/1/a.in",
+        "a.out": "https://cdn.hydro.ac/d/DOMAIN_ID/pid/1/a.out"
+    }
+}
+

评测结果上报

{
+    "key": "next/end",
+    "domainId": "DOMAIN_ID",
+    "rid": "RECORD_ID",
+
+    "message": "JUDGE_MESSAGE",
+    "compilerText": "COMPILER_OUTPUT",
+    "status": STATUS_CODE,
+    "score": SCORE,
+    "time": TIME_IN_MS,
+    "memory": MEMORY_IN_KB,
+    "progress": PROGRESS_PERCENTAGE,
+    "addProgress": PROGRESS_PERCENTAGE,
+    "case": {
+        "id": ID,
+        "subtaskId": SUBTASK_ID,
+        "score": SCORE,
+        "status": STATUS_CODE,
+        "message": "CHECKER_MESSAGE"
+    }
+}
+
`,24),r=n("code",null,"key",-1),y=n("code",null,"domainId",-1),i=n("code",null,"rid",-1),C=n("code",null,"STATUS_CODE",-1),u={href:"https://github.com/hydro-dev/Hydro/blob/master/packages/utils/lib/status.ts",target:"_blank",rel:"noopener noreferrer"},d=n("br",null,null,-1),D=n("code",null,"key",-1),B=n("code",null,"end",-1);function v(q,b){const a=o("ExternalLinkIcon");return p(),e("div",null,[c,n("p",null,[s("除 "),r,s(", "),y,s(", "),i,s(" 三个字段外,其他字段均为可选。关于 "),C,s(" 含义请查看 "),n("a",u,[s("hydro-dev/Hydro/packages/utils/lib/status"),E(a)]),s(" 。"),d,s(" 当 "),D,s(" 为 "),B,s(" 时表示评测任务已经完成,结果确定,Web 端可进行 AC 数计量,登记成绩表等操作。")])])}const h=l(t,[["render",v],["__file","judge.html.vue"]]);export{h as default}; diff --git a/assets/judge.html-1f357422.js b/assets/judge.html-1f357422.js new file mode 100644 index 00000000..8d472517 --- /dev/null +++ b/assets/judge.html-1f357422.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-1a155670","path":"/api/judge.html","title":"评测端通信协议","lang":"en-US","frontmatter":{"description":"当前版本 v1 。 评测端交互流程 GET /judge/files (检查登陆状态是否有效,若无效则跳转登录逻辑,通常每六小时执行一次); WEBSOCKET /judge/conn (主交互通道); 若登录失效,则进行登录操作。 WebSocket 连接建立流程 连接建立后,评测端向 Web 汇报当前节点状态(可选) 注:下方信息仅作数据格式展示用...","head":[["meta",{"property":"og:url","content":"https://hydro.js.org/api/judge.html"}],["meta",{"property":"og:site_name","content":"Hydro"}],["meta",{"property":"og:title","content":"评测端通信协议"}],["meta",{"property":"og:description","content":"当前版本 v1 。 评测端交互流程 GET /judge/files (检查登陆状态是否有效,若无效则跳转登录逻辑,通常每六小时执行一次); WEBSOCKET /judge/conn (主交互通道); 若登录失效,则进行登录操作。 WebSocket 连接建立流程 连接建立后,评测端向 Web 汇报当前节点状态(可选) 注:下方信息仅作数据格式展示用..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-11-23T03:00:48.000Z"}],["meta",{"property":"article:modified_time","content":"2023-11-23T03:00:48.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"评测端通信协议\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-11-23T03:00:48.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"评测端交互流程","slug":"评测端交互流程","link":"#评测端交互流程","children":[]},{"level":2,"title":"WebSocket 连接建立流程","slug":"websocket-连接建立流程","link":"#websocket-连接建立流程","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":[]}],"git":{"createdTime":1700615513000,"updatedTime":1700708448000,"contributors":[{"name":"undefined","email":"i@undefined.moe","commits":2}]},"readingTime":{"minutes":2.2,"words":661},"filePathRelative":"api/judge.md","localizedDate":"November 22, 2023","autoDesc":true,"excerpt":""}');export{e as data}; diff --git a/assets/maintain.html-3da0ffe3.js b/assets/maintain.html-3da0ffe3.js new file mode 100644 index 00000000..289836f6 --- /dev/null +++ b/assets/maintain.html-3da0ffe3.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-1bffc66e","path":"/docs/system/maintain.html","title":"维护","lang":"en-US","frontmatter":{"description":"PM2 使用一键安装脚本安装的 Hydro 使用 PM2 对进程进行管理。 进程名称 可以通过下面的指令查看当前 PM2 正在管理的所有进程。 一键安装脚本默认会创建下面几个进程: hydrooj: Hydro 主进程; hydro-sandbox: Hydro 评测沙箱; mongodb: MongoDB 数据库; caddy: 反向代理; 后文的指...","head":[["meta",{"property":"og:url","content":"https://hydro.js.org/docs/system/maintain.html"}],["meta",{"property":"og:site_name","content":"Hydro"}],["meta",{"property":"og:title","content":"维护"}],["meta",{"property":"og:description","content":"PM2 使用一键安装脚本安装的 Hydro 使用 PM2 对进程进行管理。 进程名称 可以通过下面的指令查看当前 PM2 正在管理的所有进程。 一键安装脚本默认会创建下面几个进程: hydrooj: Hydro 主进程; hydro-sandbox: Hydro 评测沙箱; mongodb: MongoDB 数据库; caddy: 反向代理; 后文的指..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-08-24T08:31:37.000Z"}],["meta",{"property":"article:modified_time","content":"2023-08-24T08:31:37.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"维护\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-08-24T08:31:37.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"PM2","slug":"pm2","link":"#pm2","children":[{"level":3,"title":"进程名称","slug":"进程名称","link":"#进程名称","children":[]},{"level":3,"title":"PM2 基本指令","slug":"pm2-基本指令","link":"#pm2-基本指令","children":[]}]},{"level":2,"title":"更新","slug":"更新","link":"#更新","children":[]},{"level":2,"title":"查看已安装版本","slug":"查看已安装版本","link":"#查看已安装版本","children":[]},{"level":2,"title":"清除缓存","slug":"清除缓存","link":"#清除缓存","children":[]}],"git":{"createdTime":1631785934000,"updatedTime":1692865897000,"contributors":[{"name":"undefined","email":"i@undefined.moe","commits":7},{"name":"Macesuted","email":"macesuted@qq.com","commits":2}]},"readingTime":{"minutes":1.71,"words":514},"filePathRelative":"docs/system/maintain.md","localizedDate":"September 16, 2021","autoDesc":true,"excerpt":""}');export{e as data}; diff --git a/assets/maintain.html-db7b5a4b.js b/assets/maintain.html-db7b5a4b.js new file mode 100644 index 00000000..42eb0c74 --- /dev/null +++ b/assets/maintain.html-db7b5a4b.js @@ -0,0 +1,15 @@ +import{_ as s}from"./plugin-vue_export-helper-c27b6911.js";import{o as a,c as n,e as l}from"./app-68b9e0b9.js";const e={},o=l(`

维护

PM2

使用一键安装脚本安装的 Hydro 使用 PM2 对进程进行管理。

进程名称

可以通过下面的指令查看当前 PM2 正在管理的所有进程。

pm2 ls
+

一键安装脚本默认会创建下面几个进程:

  • hydrooj: Hydro 主进程
  • hydro-sandbox: Hydro 评测沙箱
  • mongodb: MongoDB 数据库
  • caddy: 反向代理

后文的指令中将用 <name> 替代此处的进程名称,用 <id> 替代进程 ID(进程 ID 可通过 pm2 ls 查看)。(尖括号同样需要替换)

PM2 基本指令

pm2 ls # 查看进程列表
+pm2 start <id> # 启动进程
+pm2 stop <id> # 关闭进程
+pm2 restart <id> # 重启进程
+pm2 del <id> # 删除进程
+pm2 log <id/name> --lines=100 # 查看该进程的后 100 行日志
+pm2 attach <id> # 与进程交互
+pm2 save # 保存对 PM2 进行的修改(在添加、修改、删除进程后需要执行该指令)
+

在部分环境(常见于 lxc 容器或是精简版系统)下,服务器重启后 Hydro 可能不能正常自启动,这时请使用 pm2 resurrect 手动载入进程列表。

如果手动修改进程列表且已经覆盖掉保存的原列表,请使用 pm2 stop all && pm2 del all 清空所有进程之后重新运行安装脚本。原有数据不会丢失。

Hydro 主进程同样支持多进程启动,但在中低端服务器(不超过4核)中没有必要使用多进程启动 Hydro,会降低性能且成倍提高内存占用。

pm2 start hydrooj -i <n> # 以 n 进程启动 Hydro 主进程
+

更新

Hydro 系统会不定期发布更新,可以使用下面的命令获取更新。

无特殊情况请 不要更新PM2 !此操作可能导致进程列表丢失!

yarn global upgrade-interactive --latest # 在交互式界面中选择想要更新的组件
+pm2 restart hydrooj # 更新完后需重启 hydrooj
+

查看已安装版本

cd \`yarn global dir\` && yarn list --pattern hydrooj
+

清除缓存

yarn cache clean && nix-collect-garbage
+
`,23),p=[o];function r(c,t){return a(),n("div",null,p)}const y=s(e,[["render",r],["__file","maintain.html.vue"]]);export{y as default}; diff --git a/assets/migrate.html-2c043ed8.js b/assets/migrate.html-2c043ed8.js new file mode 100644 index 00000000..83d43fc0 --- /dev/null +++ b/assets/migrate.html-2c043ed8.js @@ -0,0 +1,4 @@ +import{_ as s}from"./plugin-vue_export-helper-c27b6911.js";import{o,c as a,e as n}from"./app-68b9e0b9.js";const l={},p=n(`

migrate

从 HUSTOJ 升级

Note

迁移会删除当前 Hydro 的所有数据(含用户账户信息)并移入 HUSTOJ 的数据。
请注意备份相关文件。

请先完成 Hydro 的部署并完成对文件服务的配置(setting_file)。 在迁移数据之前,请先停止正在运行的 HUSTOJ 服务,仅保留其数据库开启。 请注意 Hydro 所在的数据库不应和源 HUSTOJ 数据库相同。

安装插件后,您应当能够在 控制面板>脚本管理 中找到名为 migrateHustoj 的脚本。 其参数格式如下:

{"host":"localhost","port":3306,"name":"jol","username":"","password":"","domainId":"system","contestType":"","dataDir":"","uploadDir":""}
+
  • host: 数据库地址
  • port: 数据库端口
  • name: 数据库名,一般为 jol
  • username&password: 账号密码,若无则填写空字符串
  • domainId: 迁入的域,默认为 system
  • contestType: oi 或者 acm,视情况而定
  • dataDir: HUSTOJ 中 data 文件夹的位置(这里存储着题目数据等关键信息,需要手动处理)
  • uploadDir: HUSTOJ 中 上传文件的位置(这里存储着上传的图片和文件等信息,默认已指定 /home/judge/src/web/upload/ ,如果此路径与您路径相同,请不要填写此项)

当脚本运行完成后,请重启 Hydro 实例,会自动完成之后的升级操作。 迁移后,请使用原 HUSTOJ 的管理员账号登录实例。

从 SYZOJ 升级

SYZOJ 与 HUSTOJ 迁移方法类似,迁移脚本应运行名为 migrateSyzoj 的脚本外,SYZOJ无需 contestType 参数。 其参数格式如下:

{"host":"localhost","port":3306,"name":"syzoj","username":"","password":"","domainId":"system","dataDir":""}
+
  • host: 数据库地址
  • port: 数据库端口
  • name: 数据库名,一般为 syzoj
  • username&password: 账号密码,若无则填写空字符串
  • domainId: 迁入的域,默认为 system
  • dataDir: SYZOJ 中 data 文件夹的位置(这里存储着题目数据等关键信息,需要手动处理)

由于SYZOJ脚本会将原站所有数据迁移,所以运行耗时较长。 当脚本运行完成后,请重启 Hydro 实例,会自动完成之后的升级操作。 迁移后,请使用原 SYZOJ 的管理员账号登录实例。

从 UniversalOJ 升级

UniversalOJ (常称作UOJ社区版)与前两者迁移方法类似,迁移脚本应运行名为 migrateUniversalOJ 的脚本。

由于其升级过程较为麻烦,安装脚本已提供自动升级服务,如您需要可运行安装脚本一键迁移,手动迁移请在开发群中提问。

由于UniversalOJ脚本会将原站所有数据迁移,所以运行耗时较长。 当脚本运行完成后,请重启 Hydro 实例,会自动完成之后的升级操作。 迁移后,请使用原 UniversalOJ 的管理员账号登录实例。

从 Vijos 升级

Note

迁移会删除当前 Hydro 的所有数据(含用户账户信息)并移入 vj4 的数据。
请注意备份相关文件。

请先完成 Hydro 的部署并完成对文件服务的配置(setting_file)。
在迁移数据之前,请先停止正在运行的 vj4 服务,仅保留其数据库开启。
请注意 Hydro 所在的数据库不应和源 vj4 数据库相同。
若您使用 vj4-docker ,可更改 docker-compose.yml 将数据库映射至其他本机端口。

安装插件后,您应当能够在 控制面板>脚本管理 中找到名为 migrateVijos 的脚本。
其参数格式如下:

{"host":"localhost","port":27017,"name":"vj4","username":"","password":""}
+
  • host: 数据库地址
  • port: 数据库端口
  • name: 数据库名
  • username&password: 账号密码,若无则填写空字符串

Tips

vj4-docker 中数据库名为 vj4,无账号密码。

当脚本运行完成后,请重启 Hydro 实例,会自动完成之后的升级操作。 迁移后,请使用原 vj4 的管理员账号登录实例。

Note

若您的 vj4 是由 vj2 或 tyvj 升级而来,在迁移完成后请不要卸载该插件,否则可能导致部分用户无法登录。

`,26),e=[p];function t(r,c){return o(),a("div",null,e)}const i=s(l,[["render",t],["__file","migrate.html.vue"]]);export{i as default}; diff --git a/assets/migrate.html-6ea5e22e.js b/assets/migrate.html-6ea5e22e.js new file mode 100644 index 00000000..afa01592 --- /dev/null +++ b/assets/migrate.html-6ea5e22e.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-669bced4","path":"/plugins/migrate.html","title":"migrate","lang":"en-US","frontmatter":{"description":"从 HUSTOJ 升级 迁移会删除当前 Hydro 的所有数据(含用户账户信息)并移入 HUSTOJ 的数据。 请注意备份相关文件。 请先完成 Hydro 的部署并完成对文件服务的配置(setting_file)。 在迁移数据之前,请先停止正在运行的 HUSTOJ 服务,仅保留其数据库开启。 请注意 Hydro 所在的数据库不应和源 HUSTOJ 数据...","head":[["meta",{"property":"og:url","content":"https://hydro.js.org/plugins/migrate.html"}],["meta",{"property":"og:site_name","content":"Hydro"}],["meta",{"property":"og:title","content":"migrate"}],["meta",{"property":"og:description","content":"从 HUSTOJ 升级 迁移会删除当前 Hydro 的所有数据(含用户账户信息)并移入 HUSTOJ 的数据。 请注意备份相关文件。 请先完成 Hydro 的部署并完成对文件服务的配置(setting_file)。 在迁移数据之前,请先停止正在运行的 HUSTOJ 服务,仅保留其数据库开启。 请注意 Hydro 所在的数据库不应和源 HUSTOJ 数据..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-05-12T03:18:30.000Z"}],["meta",{"property":"article:modified_time","content":"2023-05-12T03:18:30.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"migrate\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-05-12T03:18:30.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"从 HUSTOJ 升级","slug":"从-hustoj-升级","link":"#从-hustoj-升级","children":[]},{"level":2,"title":"从 SYZOJ 升级","slug":"从-syzoj-升级","link":"#从-syzoj-升级","children":[]},{"level":2,"title":"从 UniversalOJ 升级","slug":"从-universaloj-升级","link":"#从-universaloj-升级","children":[]},{"level":2,"title":"从 Vijos 升级","slug":"从-vijos-升级","link":"#从-vijos-升级","children":[]}],"git":{"createdTime":1665539184000,"updatedTime":1683861510000,"contributors":[{"name":"panda","email":"panda_dtdyy@outlook.com","commits":3},{"name":"cyhforlight","email":"52744639+cyhforlight@users.noreply.github.com","commits":1},{"name":"undefined","email":"i@undefined.moe","commits":1}]},"readingTime":{"minutes":3.32,"words":995},"filePathRelative":"plugins/migrate.md","localizedDate":"October 12, 2022","autoDesc":true,"excerpt":""}');export{e as data}; diff --git a/assets/photoswipe.esm-2450701e.js b/assets/photoswipe.esm-2450701e.js new file mode 100644 index 00000000..8272229e --- /dev/null +++ b/assets/photoswipe.esm-2450701e.js @@ -0,0 +1,4 @@ +/*! + * PhotoSwipe 5.3.7 - https://photoswipe.com + * (c) 2023 Dmytro Semenov + */function m(r,t,i){const e=document.createElement(t);return r&&(e.className=r),i&&i.appendChild(e),e}function u(r,t){return r.x=t.x,r.y=t.y,t.id!==void 0&&(r.id=t.id),r}function M(r){r.x=Math.round(r.x),r.y=Math.round(r.y)}function A(r,t){const i=Math.abs(r.x-t.x),e=Math.abs(r.y-t.y);return Math.sqrt(i*i+e*e)}function x(r,t){return r.x===t.x&&r.y===t.y}function I(r,t,i){return Math.min(Math.max(r,t),i)}function b(r,t,i){let e=`translate3d(${r}px,${t||0}px,0)`;return i!==void 0&&(e+=` scale3d(${i},${i},1)`),e}function v(r,t,i,e){r.style.transform=b(t,i,e)}const U="cubic-bezier(.4,0,.22,1)";function R(r,t,i,e){r.style.transition=t?`${t} ${i}ms ${e||U}`:"none"}function L(r,t,i){r.style.width=typeof t=="number"?`${t}px`:t,r.style.height=typeof i=="number"?`${i}px`:i}function q(r){R(r)}function G(r){return"decode"in r?r.decode().catch(()=>{}):r.complete?Promise.resolve(r):new Promise((t,i)=>{r.onload=()=>t(r),r.onerror=i})}const f={IDLE:"idle",LOADING:"loading",LOADED:"loaded",ERROR:"error"};function K(r){return"button"in r&&r.button===1||r.ctrlKey||r.metaKey||r.altKey||r.shiftKey}function X(r,t,i=document){let e=[];if(r instanceof Element)e=[r];else if(r instanceof NodeList||Array.isArray(r))e=Array.from(r);else{const s=typeof r=="string"?r:t;s&&(e=Array.from(i.querySelectorAll(s)))}return e}function C(){return!!(navigator.vendor&&navigator.vendor.match(/apple/i))}let F=!1;try{window.addEventListener("test",null,Object.defineProperty({},"passive",{get:()=>{F=!0}}))}catch{}class Y{constructor(){this._pool=[]}add(t,i,e,s){this._toggleListener(t,i,e,s)}remove(t,i,e,s){this._toggleListener(t,i,e,s,!0)}removeAll(){this._pool.forEach(t=>{this._toggleListener(t.target,t.type,t.listener,t.passive,!0,!0)}),this._pool=[]}_toggleListener(t,i,e,s,n,o){if(!t)return;const a=n?"removeEventListener":"addEventListener";i.split(" ").forEach(h=>{if(h){o||(n?this._pool=this._pool.filter(d=>d.type!==h||d.listener!==e||d.target!==t):this._pool.push({target:t,type:h,listener:e,passive:s}));const c=F?{passive:s||!1}:!1;t[a](h,e,c)}})}}function B(r,t){if(r.getViewportSizeFn){const i=r.getViewportSizeFn(r,t);if(i)return i}return{x:document.documentElement.clientWidth,y:window.innerHeight}}function S(r,t,i,e,s){let n=0;if(t.paddingFn)n=t.paddingFn(i,e,s)[r];else if(t.padding)n=t.padding[r];else{const o="padding"+r[0].toUpperCase()+r.slice(1);t[o]&&(n=t[o])}return Number(n)||0}function N(r,t,i,e){return{x:t.x-S("left",r,t,i,e)-S("right",r,t,i,e),y:t.y-S("top",r,t,i,e)-S("bottom",r,t,i,e)}}class ${constructor(t){this.slide=t,this.currZoomLevel=1,this.center={x:0,y:0},this.max={x:0,y:0},this.min={x:0,y:0}}update(t){this.currZoomLevel=t,this.slide.width?(this._updateAxis("x"),this._updateAxis("y"),this.slide.pswp.dispatch("calcBounds",{slide:this.slide})):this.reset()}_updateAxis(t){const{pswp:i}=this.slide,e=this.slide[t==="x"?"width":"height"]*this.currZoomLevel,n=S(t==="x"?"left":"top",i.options,i.viewportSize,this.slide.data,this.slide.index),o=this.slide.panAreaSize[t];this.center[t]=Math.round((o-e)/2)+n,this.max[t]=e>o?Math.round(o-e)+n:this.center[t],this.min[t]=e>o?n:this.center[t]}reset(){this.center.x=0,this.center.y=0,this.max.x=0,this.max.y=0,this.min.x=0,this.min.y=0}correctPan(t,i){return I(i,this.max[t],this.min[t])}}const T=4e3;class k{constructor(t,i,e,s){this.pswp=s,this.options=t,this.itemData=i,this.index=e,this.panAreaSize=null,this.elementSize=null,this.fit=1,this.fill=1,this.vFill=1,this.initial=1,this.secondary=1,this.max=1,this.min=1}update(t,i,e){const s={x:t,y:i};this.elementSize=s,this.panAreaSize=e;const n=e.x/s.x,o=e.y/s.y;this.fit=Math.min(1,no?n:o),this.vFill=Math.min(1,o),this.initial=this._getInitial(),this.secondary=this._getSecondary(),this.max=Math.max(this.initial,this.secondary,this._getMax()),this.min=Math.min(this.fit,this.initial,this.secondary),this.pswp&&this.pswp.dispatch("zoomLevelsUpdate",{zoomLevels:this,slideData:this.itemData})}_parseZoomLevelOption(t){const i=t+"ZoomLevel",e=this.options[i];if(e)return typeof e=="function"?e(this):e==="fill"?this.fill:e==="fit"?this.fit:Number(e)}_getSecondary(){let t=this._parseZoomLevelOption("secondary");return t||(t=Math.min(1,this.fit*3),this.elementSize&&t*this.elementSize.x>T&&(t=T/this.elementSize.x),t)}_getInitial(){return this._parseZoomLevelOption("initial")||this.fit}_getMax(){return this._parseZoomLevelOption("max")||Math.max(1,this.fit*4)}}class j{constructor(t,i,e){this.data=t,this.index=i,this.pswp=e,this.isActive=i===e.currIndex,this.currentResolution=0,this.panAreaSize={x:0,y:0},this.pan={x:0,y:0},this.isFirstSlide=this.isActive&&!e.opener.isOpen,this.zoomLevels=new k(e.options,t,i,e),this.pswp.dispatch("gettingData",{slide:this,data:this.data,index:i}),this.content=this.pswp.contentLoader.getContentBySlide(this),this.container=m("pswp__zoom-wrap","div"),this.holderElement=null,this.currZoomLevel=1,this.width=this.content.width,this.height=this.content.height,this.heavyAppended=!1,this.bounds=new $(this),this.prevDisplayedWidth=-1,this.prevDisplayedHeight=-1,this.pswp.dispatch("slideInit",{slide:this})}setIsActive(t){t&&!this.isActive?this.activate():!t&&this.isActive&&this.deactivate()}append(t){this.holderElement=t,this.container.style.transformOrigin="0 0",this.data&&(this.calculateSize(),this.load(),this.updateContentSize(),this.appendHeavy(),this.holderElement.appendChild(this.container),this.zoomAndPanToInitial(),this.pswp.dispatch("firstZoomPan",{slide:this}),this.applyCurrentZoomPan(),this.pswp.dispatch("afterSetContent",{slide:this}),this.isActive&&this.activate())}load(){this.content.load(!1),this.pswp.dispatch("slideLoad",{slide:this})}appendHeavy(){const{pswp:t}=this,i=!0;this.heavyAppended||!t.opener.isOpen||t.mainScroll.isShifted()||!this.isActive&&!i||this.pswp.dispatch("appendHeavy",{slide:this}).defaultPrevented||(this.heavyAppended=!0,this.content.append(),this.pswp.dispatch("appendHeavyContent",{slide:this}))}activate(){this.isActive=!0,this.appendHeavy(),this.content.activate(),this.pswp.dispatch("slideActivate",{slide:this})}deactivate(){this.isActive=!1,this.content.deactivate(),this.currZoomLevel!==this.zoomLevels.initial&&this.calculateSize(),this.currentResolution=0,this.zoomAndPanToInitial(),this.applyCurrentZoomPan(),this.updateContentSize(),this.pswp.dispatch("slideDeactivate",{slide:this})}destroy(){this.content.hasSlide=!1,this.content.remove(),this.container.remove(),this.pswp.dispatch("slideDestroy",{slide:this})}resize(){this.currZoomLevel===this.zoomLevels.initial||!this.isActive?(this.calculateSize(),this.currentResolution=0,this.zoomAndPanToInitial(),this.applyCurrentZoomPan(),this.updateContentSize()):(this.calculateSize(),this.bounds.update(this.currZoomLevel),this.panTo(this.pan.x,this.pan.y))}updateContentSize(t){const i=this.currentResolution||this.zoomLevels.initial;if(!i)return;const e=Math.round(this.width*i)||this.pswp.viewportSize.x,s=Math.round(this.height*i)||this.pswp.viewportSize.y;!this.sizeChanged(e,s)&&!t||this.content.setDisplayedSize(e,s)}sizeChanged(t,i){return t!==this.prevDisplayedWidth||i!==this.prevDisplayedHeight?(this.prevDisplayedWidth=t,this.prevDisplayedHeight=i,!0):!1}getPlaceholderElement(){var t;return(t=this.content.placeholder)==null?void 0:t.element}zoomTo(t,i,e,s){const{pswp:n}=this;if(!this.isZoomable()||n.mainScroll.isShifted())return;n.dispatch("beforeZoomTo",{destZoomLevel:t,centerPoint:i,transitionDuration:e}),n.animations.stopAllPan();const o=this.currZoomLevel;s||(t=I(t,this.zoomLevels.min,this.zoomLevels.max)),this.setZoomLevel(t),this.pan.x=this.calculateZoomToPanOffset("x",i,o),this.pan.y=this.calculateZoomToPanOffset("y",i,o),M(this.pan);const a=()=>{this._setResolution(t),this.applyCurrentZoomPan()};e?n.animations.startTransition({isPan:!0,name:"zoomTo",target:this.container,transform:this.getCurrentTransform(),onComplete:a,duration:e,easing:n.options.easing}):a()}toggleZoom(t){this.zoomTo(this.currZoomLevel===this.zoomLevels.initial?this.zoomLevels.secondary:this.zoomLevels.initial,t,this.pswp.options.zoomAnimationDuration)}setZoomLevel(t){this.currZoomLevel=t,this.bounds.update(this.currZoomLevel)}calculateZoomToPanOffset(t,i,e){if(this.bounds.max[t]-this.bounds.min[t]===0)return this.bounds.center[t];i||(i=this.pswp.getViewportCenterPoint()),e||(e=this.zoomLevels.initial);const n=this.currZoomLevel/e;return this.bounds.correctPan(t,(this.pan[t]-i[t])*n+i[t])}panTo(t,i){this.pan.x=this.bounds.correctPan("x",t),this.pan.y=this.bounds.correctPan("y",i),this.applyCurrentZoomPan()}isPannable(){return!!this.width&&this.currZoomLevel>this.zoomLevels.fit}isZoomable(){return!!this.width&&this.content.isZoomable()}applyCurrentZoomPan(){this._applyZoomTransform(this.pan.x,this.pan.y,this.currZoomLevel),this===this.pswp.currSlide&&this.pswp.dispatch("zoomPanUpdate",{slide:this})}zoomAndPanToInitial(){this.currZoomLevel=this.zoomLevels.initial,this.bounds.update(this.currZoomLevel),u(this.pan,this.bounds.center),this.pswp.dispatch("initialZoomPan",{slide:this})}_applyZoomTransform(t,i,e){e/=this.currentResolution||this.zoomLevels.initial,v(this.container,t,i,e)}calculateSize(){const{pswp:t}=this;u(this.panAreaSize,N(t.options,t.viewportSize,this.data,this.index)),this.zoomLevels.update(this.width,this.height,this.panAreaSize),t.dispatch("calcSlideSize",{slide:this})}getCurrentTransform(){const t=this.currZoomLevel/(this.currentResolution||this.zoomLevels.initial);return b(this.pan.x,this.pan.y,t)}_setResolution(t){t!==this.currentResolution&&(this.currentResolution=t,this.updateContentSize(),this.pswp.dispatch("resolutionChanged"))}}const Q=.35,J=.6,z=.4,O=.5;function tt(r,t){return r*t/(1-t)}class it{constructor(t){this.gestures=t,this.pswp=t.pswp,this.startPan={x:0,y:0}}start(){this.pswp.currSlide&&u(this.startPan,this.pswp.currSlide.pan),this.pswp.animations.stopAll()}change(){const{p1:t,prevP1:i,dragAxis:e}=this.gestures,{currSlide:s}=this.pswp;if(e==="y"&&this.pswp.options.closeOnVerticalDrag&&s&&s.currZoomLevel<=s.zoomLevels.fit&&!this.gestures.isMultitouch){const n=s.pan.y+(t.y-i.y);if(!this.pswp.dispatch("verticalDrag",{panY:n}).defaultPrevented){this._setPanWithFriction("y",n,J);const o=1-Math.abs(this._getVerticalDragRatio(s.pan.y));this.pswp.applyBgOpacity(o),s.applyCurrentZoomPan()}}else this._panOrMoveMainScroll("x")||(this._panOrMoveMainScroll("y"),s&&(M(s.pan),s.applyCurrentZoomPan()))}end(){const{velocity:t}=this.gestures,{mainScroll:i,currSlide:e}=this.pswp;let s=0;if(this.pswp.animations.stopAll(),i.isShifted()){const o=(i.x-i.getCurrSlideX())/this.pswp.viewportSize.x;t.x<-O&&o<0||t.x<.1&&o<-.5?(s=1,t.x=Math.min(t.x,0)):(t.x>O&&o>0||t.x>-.1&&o>.5)&&(s=-1,t.x=Math.max(t.x,0)),i.moveIndexBy(s,!0,t.x)}e&&e.currZoomLevel>e.zoomLevels.max||this.gestures.isMultitouch?this.gestures.zoomLevels.correctZoomPan(!0):(this._finishPanGestureForAxis("x"),this._finishPanGestureForAxis("y"))}_finishPanGestureForAxis(t){const{velocity:i}=this.gestures,{currSlide:e}=this.pswp;if(!e)return;const{pan:s,bounds:n}=e,o=s[t],a=this.pswp.bgOpacity<1&&t==="y",l=.995,h=o+tt(i[t],l);if(a){const g=this._getVerticalDragRatio(o),w=this._getVerticalDragRatio(h);if(g<0&&w<-z||g>0&&w>z){this.pswp.close();return}}const c=n.correctPan(t,h);if(o===c)return;const d=c===h?1:.82,p=this.pswp.bgOpacity,_=c-o;this.pswp.animations.startSpring({name:"panGesture"+t,isPan:!0,start:o,end:c,velocity:i[t],dampingRatio:d,onUpdate:g=>{if(a&&this.pswp.bgOpacity<1){const w=1-(c-g)/_;this.pswp.applyBgOpacity(I(p+(1-p)*w,0,1))}s[t]=Math.floor(g),e.applyCurrentZoomPan()}})}_panOrMoveMainScroll(t){const{p1:i,dragAxis:e,prevP1:s,isMultitouch:n}=this.gestures,{currSlide:o,mainScroll:a}=this.pswp,l=i[t]-s[t],h=a.x+l;if(!l||!o)return!1;if(t==="x"&&!o.isPannable()&&!n)return a.moveTo(h,!0),!0;const{bounds:c}=o,d=o.pan[t]+l;if(this.pswp.options.allowPanToNext&&e==="x"&&t==="x"&&!n){const p=a.getCurrSlideX(),_=a.x-p,g=l>0,w=!g;if(d>c.min[t]&&g){if(c.min[t]<=this.startPan[t])return a.moveTo(h,!0),!0;this._setPanWithFriction(t,d)}else if(d0)return a.moveTo(Math.max(h,p),!0),!0;if(_<0)return a.moveTo(Math.min(h,p),!0),!0}else this._setPanWithFriction(t,d)}else t==="y"?!a.isShifted()&&c.min.y!==c.max.y&&this._setPanWithFriction(t,d):this._setPanWithFriction(t,d);return!1}_getVerticalDragRatio(t){var i;return(t-(((i=this.pswp.currSlide)==null?void 0:i.bounds.center.y)??0))/(this.pswp.viewportSize.y/3)}_setPanWithFriction(t,i,e){const{currSlide:s}=this.pswp;if(!s)return;const{pan:n,bounds:o}=s;if(o.correctPan(t,i)!==i||e){const l=Math.round(i-n[t]);n[t]+=l*(e||Q)}else n[t]=i}}const et=.05,st=.15;function E(r,t,i){return r.x=(t.x+i.x)/2,r.y=(t.y+i.y)/2,r}class nt{constructor(t){this.gestures=t,this._startPan={x:0,y:0},this._startZoomPoint={x:0,y:0},this._zoomPoint={x:0,y:0},this._wasOverFitZoomLevel=!1,this._startZoomLevel=1}start(){const{currSlide:t}=this.gestures.pswp;t&&(this._startZoomLevel=t.currZoomLevel,u(this._startPan,t.pan)),this.gestures.pswp.animations.stopAllPan(),this._wasOverFitZoomLevel=!1}change(){const{p1:t,startP1:i,p2:e,startP2:s,pswp:n}=this.gestures,{currSlide:o}=n;if(!o)return;const a=o.zoomLevels.min,l=o.zoomLevels.max;if(!o.isZoomable()||n.mainScroll.isShifted())return;E(this._startZoomPoint,i,s),E(this._zoomPoint,t,e);let h=1/A(i,s)*A(t,e)*this._startZoomLevel;if(h>o.zoomLevels.initial+o.zoomLevels.initial/15&&(this._wasOverFitZoomLevel=!0),hl&&(h=l+(h-l)*et);o.pan.x=this._calculatePanForZoomLevel("x",h),o.pan.y=this._calculatePanForZoomLevel("y",h),o.setZoomLevel(h),o.applyCurrentZoomPan()}end(){const{pswp:t}=this.gestures,{currSlide:i}=t;(!i||i.currZoomLevele.zoomLevels.max?n=e.zoomLevels.max:(o=!1,n=s);const a=i.bgOpacity,l=i.bgOpacity<1,h=u({x:0,y:0},e.pan);let c=u({x:0,y:0},h);t&&(this._zoomPoint.x=0,this._zoomPoint.y=0,this._startZoomPoint.x=0,this._startZoomPoint.y=0,this._startZoomLevel=s,u(this._startPan,h)),o&&(c={x:this._calculatePanForZoomLevel("x",n),y:this._calculatePanForZoomLevel("y",n)}),e.setZoomLevel(n),c={x:e.bounds.correctPan("x",c.x),y:e.bounds.correctPan("y",c.y)},e.setZoomLevel(s);const d=!x(c,h);if(!d&&!o&&!l){e._setResolution(n),e.applyCurrentZoomPan();return}i.animations.stopAllPan(),i.animations.startSpring({isPan:!0,start:0,end:1e3,velocity:0,dampingRatio:1,naturalFrequency:40,onUpdate:p=>{if(p/=1e3,d||o){if(d&&(e.pan.x=h.x+(c.x-h.x)*p,e.pan.y=h.y+(c.y-h.y)*p),o){const _=s+(n-s)*p;e.setZoomLevel(_)}e.applyCurrentZoomPan()}l&&i.bgOpacity<1&&i.applyBgOpacity(I(a+(1-a)*p,0,1))},onComplete:()=>{e._setResolution(n),e.applyCurrentZoomPan()}})}}function Z(r){return!!r.target.closest(".pswp__container")}class ot{constructor(t){this.gestures=t}click(t,i){const e=i.target.classList,s=e.contains("pswp__img"),n=e.contains("pswp__item")||e.contains("pswp__zoom-wrap");s?this._doClickOrTapAction("imageClick",t,i):n&&this._doClickOrTapAction("bgClick",t,i)}tap(t,i){Z(i)&&this._doClickOrTapAction("tap",t,i)}doubleTap(t,i){Z(i)&&this._doClickOrTapAction("doubleTap",t,i)}_doClickOrTapAction(t,i,e){var l;const{pswp:s}=this.gestures,{currSlide:n}=s,o=t+"Action",a=s.options[o];if(!s.dispatch(o,{point:i,originalEvent:e}).defaultPrevented){if(typeof a=="function"){a.call(s,i,e);return}switch(a){case"close":case"next":s[a]();break;case"zoom":n==null||n.toggleZoom(i);break;case"zoom-or-close":n!=null&&n.isZoomable()&&n.zoomLevels.secondary!==n.zoomLevels.initial?n.toggleZoom(i):s.options.clickToCloseNonZoomable&&s.close();break;case"toggle-controls":(l=this.gestures.pswp.element)==null||l.classList.toggle("pswp--ui-visible");break}}}}const rt=10,at=300,ht=25;class lt{constructor(t){this.pswp=t,this.dragAxis=null,this.p1={x:0,y:0},this.p2={x:0,y:0},this.prevP1={x:0,y:0},this.prevP2={x:0,y:0},this.startP1={x:0,y:0},this.startP2={x:0,y:0},this.velocity={x:0,y:0},this._lastStartP1={x:0,y:0},this._intervalP1={x:0,y:0},this._numActivePoints=0,this._ongoingPointers=[],this._touchEventEnabled="ontouchstart"in window,this._pointerEventEnabled=!!window.PointerEvent,this.supportsTouch=this._touchEventEnabled||this._pointerEventEnabled&&navigator.maxTouchPoints>1,this._numActivePoints=0,this._intervalTime=0,this._velocityCalculated=!1,this.isMultitouch=!1,this.isDragging=!1,this.isZooming=!1,this.raf=null,this._tapTimer=null,this.supportsTouch||(t.options.allowPanToNext=!1),this.drag=new it(this),this.zoomLevels=new nt(this),this.tapHandler=new ot(this),t.on("bindEvents",()=>{t.events.add(t.scrollWrap,"click",this._onClick.bind(this)),this._pointerEventEnabled?this._bindEvents("pointer","down","up","cancel"):this._touchEventEnabled?(this._bindEvents("touch","start","end","cancel"),t.scrollWrap&&(t.scrollWrap.ontouchmove=()=>{},t.scrollWrap.ontouchend=()=>{})):this._bindEvents("mouse","down","up")})}_bindEvents(t,i,e,s){const{pswp:n}=this,{events:o}=n,a=s?t+s:"";o.add(n.scrollWrap,t+i,this.onPointerDown.bind(this)),o.add(window,t+"move",this.onPointerMove.bind(this)),o.add(window,t+e,this.onPointerUp.bind(this)),a&&o.add(n.scrollWrap,a,this.onPointerUp.bind(this))}onPointerDown(t){const i=t.type==="mousedown"||t.pointerType==="mouse";if(i&&t.button>0)return;const{pswp:e}=this;if(!e.opener.isOpen){t.preventDefault();return}e.dispatch("pointerDown",{originalEvent:t}).defaultPrevented||(i&&(e.mouseDetected(),this._preventPointerEventBehaviour(t)),e.animations.stopAll(),this._updatePoints(t,"down"),this._numActivePoints===1&&(this.dragAxis=null,u(this.startP1,this.p1)),this._numActivePoints>1?(this._clearTapTimer(),this.isMultitouch=!0):this.isMultitouch=!1)}onPointerMove(t){t.preventDefault(),this._numActivePoints&&(this._updatePoints(t,"move"),!this.pswp.dispatch("pointerMove",{originalEvent:t}).defaultPrevented&&(this._numActivePoints===1&&!this.isDragging?(this.dragAxis||this._calculateDragDirection(),this.dragAxis&&!this.isDragging&&(this.isZooming&&(this.isZooming=!1,this.zoomLevels.end()),this.isDragging=!0,this._clearTapTimer(),this._updateStartPoints(),this._intervalTime=Date.now(),this._velocityCalculated=!1,u(this._intervalP1,this.p1),this.velocity.x=0,this.velocity.y=0,this.drag.start(),this._rafStopLoop(),this._rafRenderLoop())):this._numActivePoints>1&&!this.isZooming&&(this._finishDrag(),this.isZooming=!0,this._updateStartPoints(),this.zoomLevels.start(),this._rafStopLoop(),this._rafRenderLoop())))}_finishDrag(){this.isDragging&&(this.isDragging=!1,this._velocityCalculated||this._updateVelocity(!0),this.drag.end(),this.dragAxis=null)}onPointerUp(t){this._numActivePoints&&(this._updatePoints(t,"up"),!this.pswp.dispatch("pointerUp",{originalEvent:t}).defaultPrevented&&(this._numActivePoints===0&&(this._rafStopLoop(),this.isDragging?this._finishDrag():!this.isZooming&&!this.isMultitouch&&this._finishTap(t)),this._numActivePoints<2&&this.isZooming&&(this.isZooming=!1,this.zoomLevels.end(),this._numActivePoints===1&&(this.dragAxis=null,this._updateStartPoints()))))}_rafRenderLoop(){(this.isDragging||this.isZooming)&&(this._updateVelocity(),this.isDragging?x(this.p1,this.prevP1)||this.drag.change():(!x(this.p1,this.prevP1)||!x(this.p2,this.prevP2))&&this.zoomLevels.change(),this._updatePrevPoints(),this.raf=requestAnimationFrame(this._rafRenderLoop.bind(this)))}_updateVelocity(t){const i=Date.now(),e=i-this._intervalTime;e<50&&!t||(this.velocity.x=this._getVelocity("x",e),this.velocity.y=this._getVelocity("y",e),this._intervalTime=i,u(this._intervalP1,this.p1),this._velocityCalculated=!0)}_finishTap(t){const{mainScroll:i}=this.pswp;if(i.isShifted()){i.moveIndexBy(0,!0);return}if(t.type.indexOf("cancel")>0)return;if(t.type==="mouseup"||t.pointerType==="mouse"){this.tapHandler.click(this.startP1,t);return}const e=this.pswp.options.doubleTapAction?at:0;this._tapTimer?(this._clearTapTimer(),A(this._lastStartP1,this.startP1){this.tapHandler.tap(this.startP1,t),this._clearTapTimer()},e))}_clearTapTimer(){this._tapTimer&&(clearTimeout(this._tapTimer),this._tapTimer=null)}_getVelocity(t,i){const e=this.p1[t]-this._intervalP1[t];return Math.abs(e)>1&&i>5?e/i:0}_rafStopLoop(){this.raf&&(cancelAnimationFrame(this.raf),this.raf=null)}_preventPointerEventBehaviour(t){t.preventDefault()}_updatePoints(t,i){if(this._pointerEventEnabled){const e=t,s=this._ongoingPointers.findIndex(n=>n.id===e.pointerId);i==="up"&&s>-1?this._ongoingPointers.splice(s,1):i==="down"&&s===-1?this._ongoingPointers.push(this._convertEventPosToPoint(e,{x:0,y:0})):s>-1&&this._convertEventPosToPoint(e,this._ongoingPointers[s]),this._numActivePoints=this._ongoingPointers.length,this._numActivePoints>0&&u(this.p1,this._ongoingPointers[0]),this._numActivePoints>1&&u(this.p2,this._ongoingPointers[1])}else{const e=t;this._numActivePoints=0,e.type.indexOf("touch")>-1?e.touches&&e.touches.length>0&&(this._convertEventPosToPoint(e.touches[0],this.p1),this._numActivePoints++,e.touches.length>1&&(this._convertEventPosToPoint(e.touches[1],this.p2),this._numActivePoints++)):(this._convertEventPosToPoint(t,this.p1),i==="up"?this._numActivePoints=0:this._numActivePoints++)}}_updatePrevPoints(){u(this.prevP1,this.p1),u(this.prevP2,this.p2)}_updateStartPoints(){u(this.startP1,this.p1),u(this.startP2,this.p2),this._updatePrevPoints()}_calculateDragDirection(){if(this.pswp.mainScroll.isShifted())this.dragAxis="x";else{const t=Math.abs(this.p1.x-this.startP1.x)-Math.abs(this.p1.y-this.startP1.y);if(t!==0){const i=t>0?"x":"y";Math.abs(this.p1[i]-this.startP1[i])>=rt&&(this.dragAxis=i)}}}_convertEventPosToPoint(t,i){return i.x=t.pageX-this.pswp.offset.x,i.y=t.pageY-this.pswp.offset.y,"pointerId"in t?i.id=t.pointerId:t.identifier!==void 0&&(i.id=t.identifier),i}_onClick(t){this.pswp.mainScroll.isShifted()&&(t.preventDefault(),t.stopPropagation())}}const ct=.35;class dt{constructor(t){this.pswp=t,this.x=0,this.slideWidth=0,this._currPositionIndex=0,this._prevPositionIndex=0,this._containerShiftIndex=-1,this.itemHolders=[]}resize(t){const{pswp:i}=this,e=Math.round(i.viewportSize.x+i.viewportSize.x*i.options.spacing),s=e!==this.slideWidth;s&&(this.slideWidth=e,this.moveTo(this.getCurrSlideX())),this.itemHolders.forEach((n,o)=>{s&&v(n.el,(o+this._containerShiftIndex)*this.slideWidth),t&&n.slide&&n.slide.resize()})}resetPosition(){this._currPositionIndex=0,this._prevPositionIndex=0,this.slideWidth=0,this._containerShiftIndex=-1}appendHolders(){this.itemHolders=[];for(let t=0;t<3;t++){const i=m("pswp__item","div",this.pswp.container);i.setAttribute("role","group"),i.setAttribute("aria-roledescription","slide"),i.setAttribute("aria-hidden","true"),i.style.display=t===1?"block":"none",this.itemHolders.push({el:i})}}canBeSwiped(){return this.pswp.getNumItems()>1}moveIndexBy(t,i,e){const{pswp:s}=this;let n=s.potentialIndex+t;const o=s.getNumItems();if(s.canLoop()){n=s.getLoopedIndex(n);const l=(t+o)%o;l<=o/2?t=l:t=l-o}else n<0?n=0:n>=o&&(n=o-1),t=n-s.potentialIndex;s.potentialIndex=n,this._currPositionIndex-=t,s.animations.stopMainScroll();const a=this.getCurrSlideX();if(!i)this.moveTo(a),this.updateCurrItem();else{s.animations.startSpring({isMainScroll:!0,start:this.x,end:a,velocity:e||0,naturalFrequency:30,dampingRatio:1,onUpdate:h=>{this.moveTo(h)},onComplete:()=>{this.updateCurrItem(),s.appendHeavy()}});let l=s.potentialIndex-s.currIndex;if(s.canLoop()){const h=(l+o)%o;h<=o/2?l=h:l=h-o}Math.abs(l)>1&&this.updateCurrItem()}return!!t}getCurrSlideX(){return this.slideWidth*this._currPositionIndex}isShifted(){return this.x!==this.getCurrSlideX()}updateCurrItem(){var n;const{pswp:t}=this,i=this._prevPositionIndex-this._currPositionIndex;if(!i)return;this._prevPositionIndex=this._currPositionIndex,t.currIndex=t.potentialIndex;let e=Math.abs(i),s;e>=3&&(this._containerShiftIndex+=i+(i>0?-3:3),e=3);for(let o=0;o0?(s=this.itemHolders.shift(),s&&(this.itemHolders[2]=s,this._containerShiftIndex++,v(s.el,(this._containerShiftIndex+2)*this.slideWidth),t.setContent(s,t.currIndex-e+o+2))):(s=this.itemHolders.pop(),s&&(this.itemHolders.unshift(s),this._containerShiftIndex--,v(s.el,this._containerShiftIndex*this.slideWidth),t.setContent(s,t.currIndex+e-o-2)));Math.abs(this._containerShiftIndex)>50&&!this.isShifted()&&(this.resetPosition(),this.resize()),t.animations.stopAllPan(),this.itemHolders.forEach((o,a)=>{o.slide&&o.slide.setIsActive(a===1)}),t.currSlide=(n=this.itemHolders[1])==null?void 0:n.slide,t.contentLoader.updateLazy(i),t.currSlide&&t.currSlide.applyCurrentZoomPan(),t.dispatch("change")}moveTo(t,i){if(!this.pswp.canLoop()&&i){let e=(this.slideWidth*this._currPositionIndex-t)/this.slideWidth;e+=this.pswp.currIndex;const s=Math.round(t-this.x);(e<0&&s>0||e>=this.pswp.getNumItems()-1&&s<0)&&(t=this.x+s*ct)}this.x=t,this.pswp.container&&v(this.pswp.container,t),this.pswp.dispatch("moveMainScroll",{x:t,dragging:i??!1})}}const pt={Escape:27,z:90,ArrowLeft:37,ArrowUp:38,ArrowRight:39,ArrowDown:40,Tab:9},y=(r,t)=>t?r:pt[r];class ut{constructor(t){this.pswp=t,this._wasFocused=!1,t.on("bindEvents",()=>{t.options.initialPointerPos||this._focusRoot(),t.events.add(document,"focusin",this._onFocusIn.bind(this)),t.events.add(document,"keydown",this._onKeyDown.bind(this))});const i=document.activeElement;t.on("destroy",()=>{t.options.returnFocus&&i&&this._wasFocused&&i.focus()})}_focusRoot(){!this._wasFocused&&this.pswp.element&&(this.pswp.element.focus(),this._wasFocused=!0)}_onKeyDown(t){const{pswp:i}=this;if(i.dispatch("keydown",{originalEvent:t}).defaultPrevented||K(t))return;let e,s,n=!1;const o="key"in t;switch(o?t.key:t.keyCode){case y("Escape",o):i.options.escKey&&(e="close");break;case y("z",o):e="toggleZoom";break;case y("ArrowLeft",o):s="x";break;case y("ArrowUp",o):s="y";break;case y("ArrowRight",o):s="x",n=!0;break;case y("ArrowDown",o):n=!0,s="y";break;case y("Tab",o):this._focusRoot();break}if(s){t.preventDefault();const{currSlide:a}=i;i.options.arrowKeys&&s==="x"&&i.getNumItems()>1?e=n?"next":"prev":a&&a.currZoomLevel>a.zoomLevels.fit&&(a.pan[s]+=n?-80:80,a.panTo(a.pan.x,a.pan.y))}e&&(t.preventDefault(),i[e]())}_onFocusIn(t){const{template:i}=this.pswp;i&&document!==t.target&&i!==t.target&&!i.contains(t.target)&&i.focus()}}const mt="cubic-bezier(.4,0,.22,1)";class ft{constructor(t){this.props=t;const{target:i,onComplete:e,transform:s,onFinish:n=()=>{},duration:o=333,easing:a=mt}=t;this.onFinish=n;const l=s?"transform":"opacity",h=t[l]??"";this._target=i,this._onComplete=e,this._finished=!1,this._onTransitionEnd=this._onTransitionEnd.bind(this),this._helperTimeout=setTimeout(()=>{R(i,l,o,a),this._helperTimeout=setTimeout(()=>{i.addEventListener("transitionend",this._onTransitionEnd,!1),i.addEventListener("transitioncancel",this._onTransitionEnd,!1),this._helperTimeout=setTimeout(()=>{this._finalizeAnimation()},o+500),i.style[l]=h},30)},0)}_onTransitionEnd(t){t.target===this._target&&this._finalizeAnimation()}_finalizeAnimation(){this._finished||(this._finished=!0,this.onFinish(),this._onComplete&&this._onComplete())}destroy(){this._helperTimeout&&clearTimeout(this._helperTimeout),q(this._target),this._target.removeEventListener("transitionend",this._onTransitionEnd,!1),this._target.removeEventListener("transitioncancel",this._onTransitionEnd,!1),this._finished||this._finalizeAnimation()}}const _t=12,gt=.75;class yt{constructor(t,i,e){this.velocity=t*1e3,this._dampingRatio=i||gt,this._naturalFrequency=e||_t,this._dampedFrequency=this._naturalFrequency,this._dampingRatio<1&&(this._dampedFrequency*=Math.sqrt(1-this._dampingRatio*this._dampingRatio))}easeFrame(t,i){let e=0,s;i/=1e3;const n=Math.E**(-this._dampingRatio*this._naturalFrequency*i);if(this._dampingRatio===1)s=this.velocity+this._naturalFrequency*t,e=(t+s*i)*n,this.velocity=e*-this._naturalFrequency+s*n;else if(this._dampingRatio<1){s=1/this._dampedFrequency*(this._dampingRatio*this._naturalFrequency*t+this.velocity);const o=Math.cos(this._dampedFrequency*i),a=Math.sin(this._dampedFrequency*i);e=n*(t*o+s*a),this.velocity=e*-this._naturalFrequency*this._dampingRatio+n*(-this._dampedFrequency*t*a+this._dampedFrequency*s*o)}return e}}class vt{constructor(t){this.props=t,this._raf=0;const{start:i,end:e,velocity:s,onUpdate:n,onComplete:o,onFinish:a=()=>{},dampingRatio:l,naturalFrequency:h}=t;this.onFinish=a;const c=new yt(s,l,h);let d=Date.now(),p=i-e;const _=()=>{this._raf&&(p=c.easeFrame(p,Date.now()-d),Math.abs(p)<1&&Math.abs(c.velocity)<50?(n(e),o&&o(),this.onFinish()):(d=Date.now(),n(p+e),this._raf=requestAnimationFrame(_)))};this._raf=requestAnimationFrame(_)}destroy(){this._raf>=0&&cancelAnimationFrame(this._raf),this._raf=0}}class wt{constructor(){this.activeAnimations=[]}startSpring(t){this._start(t,!0)}startTransition(t){this._start(t)}_start(t,i){const e=i?new vt(t):new ft(t);return this.activeAnimations.push(e),e.onFinish=()=>this.stop(e),e}stop(t){t.destroy();const i=this.activeAnimations.indexOf(t);i>-1&&this.activeAnimations.splice(i,1)}stopAll(){this.activeAnimations.forEach(t=>{t.destroy()}),this.activeAnimations=[]}stopAllPan(){this.activeAnimations=this.activeAnimations.filter(t=>t.props.isPan?(t.destroy(),!1):!0)}stopMainScroll(){this.activeAnimations=this.activeAnimations.filter(t=>t.props.isMainScroll?(t.destroy(),!1):!0)}isPanRunning(){return this.activeAnimations.some(t=>t.props.isPan)}}class Pt{constructor(t){this.pswp=t,t.events.add(t.element,"wheel",this._onWheel.bind(this))}_onWheel(t){t.preventDefault();const{currSlide:i}=this.pswp;let{deltaX:e,deltaY:s}=t;if(i&&!this.pswp.dispatch("wheel",{originalEvent:t}).defaultPrevented)if(t.ctrlKey||this.pswp.options.wheelToZoom){if(i.isZoomable()){let n=-s;t.deltaMode===1?n*=.05:n*=t.deltaMode?1:.002,n=2**n;const o=i.currZoomLevel*n;i.zoomTo(o,{x:t.clientX,y:t.clientY})}}else i.isPannable()&&(t.deltaMode===1&&(e*=18,s*=18),i.panTo(i.pan.x-e,i.pan.y-s))}}function St(r){if(typeof r=="string")return r;if(!r||!r.isCustomSVG)return"";const t=r;let i='",i}class xt{constructor(t,i){const e=i.name||i.className;let s=i.html;if(t.options[e]===!1)return;typeof t.options[e+"SVG"]=="string"&&(s=t.options[e+"SVG"]),t.dispatch("uiElementCreate",{data:i});let n="";i.isButton?(n+="pswp__button ",n+=i.className||`pswp__button--${i.name}`):n+=i.className||`pswp__${i.name}`;let o=i.isButton?i.tagName||"button":i.tagName||"div";o=o.toLowerCase();const a=m(n,o);if(i.isButton){o==="button"&&(a.type="button");let{title:c}=i;const{ariaLabel:d}=i;typeof t.options[e+"Title"]=="string"&&(c=t.options[e+"Title"]),c&&(a.title=c);const p=d||c;p&&a.setAttribute("aria-label",p)}a.innerHTML=St(s),i.onInit&&i.onInit(a,t),i.onClick&&(a.onclick=c=>{typeof i.onClick=="string"?t[i.onClick]():typeof i.onClick=="function"&&i.onClick(c,a,t)});const l=i.appendTo||"bar";let h=t.element;l==="bar"?(t.topBar||(t.topBar=m("pswp__top-bar pswp__hide-on-close","div",t.scrollWrap)),h=t.topBar):(a.classList.add("pswp__hide-on-close"),l==="wrapper"&&(h=t.scrollWrap)),h==null||h.appendChild(t.applyFilters("uiElement",a,i))}}function H(r,t,i){r.classList.add("pswp__button--arrow"),r.setAttribute("aria-controls","pswp__items"),t.on("change",()=>{t.options.loop||(i?r.disabled=!(t.currIndex0))})}const bt={name:"arrowPrev",className:"pswp__button--arrow--prev",title:"Previous",order:10,isButton:!0,appendTo:"wrapper",html:{isCustomSVG:!0,size:60,inner:'',outlineID:"pswp__icn-arrow"},onClick:"prev",onInit:H},It={name:"arrowNext",className:"pswp__button--arrow--next",title:"Next",order:11,isButton:!0,appendTo:"wrapper",html:{isCustomSVG:!0,size:60,inner:'',outlineID:"pswp__icn-arrow"},onClick:"next",onInit:(r,t)=>{H(r,t,!0)}},At={name:"close",title:"Close",order:20,isButton:!0,html:{isCustomSVG:!0,inner:'',outlineID:"pswp__icn-close"},onClick:"close"},Lt={name:"zoom",title:"Zoom",order:10,isButton:!0,html:{isCustomSVG:!0,inner:'',outlineID:"pswp__icn-zoom"},onClick:"toggleZoom"},Ct={name:"preloader",appendTo:"bar",order:7,html:{isCustomSVG:!0,inner:'',outlineID:"pswp__icn-loading"},onInit:(r,t)=>{let i,e=null;const s=(a,l)=>{r.classList.toggle("pswp__preloader--"+a,l)},n=a=>{i!==a&&(i=a,s("active",a))},o=()=>{var a;if(!((a=t.currSlide)!=null&&a.content.isLoading())){n(!1),e&&(clearTimeout(e),e=null);return}e||(e=setTimeout(()=>{var l;n(!!((l=t.currSlide)!=null&&l.content.isLoading())),e=null},t.options.preloaderDelay))};t.on("change",o),t.on("loadComplete",a=>{t.currSlide===a.slide&&o()}),t.ui&&(t.ui.updatePreloaderVisibility=o)}},Tt={name:"counter",order:5,onInit:(r,t)=>{t.on("change",()=>{r.innerText=t.currIndex+1+t.options.indexIndicatorSep+t.getNumItems()})}};function D(r,t){r.classList.toggle("pswp--zoomed-in",t)}class zt{constructor(t){this.pswp=t,this.isRegistered=!1,this.uiElementsData=[],this.items=[],this.updatePreloaderVisibility=()=>{},this._lastUpdatedZoomLevel=void 0}init(){const{pswp:t}=this;this.isRegistered=!1,this.uiElementsData=[At,bt,It,Lt,Ct,Tt],t.dispatch("uiRegister"),this.uiElementsData.sort((i,e)=>(i.order||0)-(e.order||0)),this.items=[],this.isRegistered=!0,this.uiElementsData.forEach(i=>{this.registerElement(i)}),t.on("change",()=>{var i;(i=t.element)==null||i.classList.toggle("pswp--one-slide",t.getNumItems()===1)}),t.on("zoomPanUpdate",()=>this._onZoomPanUpdate())}registerElement(t){this.isRegistered?this.items.push(new xt(this.pswp,t)):this.uiElementsData.push(t)}_onZoomPanUpdate(){const{template:t,currSlide:i,options:e}=this.pswp;if(this.pswp.opener.isClosing||!t||!i)return;let{currZoomLevel:s}=i;if(this.pswp.opener.isOpen||(s=i.zoomLevels.initial),s===this._lastUpdatedZoomLevel)return;this._lastUpdatedZoomLevel=s;const n=i.zoomLevels.initial-i.zoomLevels.secondary;if(Math.abs(n)<.01||!i.isZoomable()){D(t,!1),t.classList.remove("pswp--zoom-allowed");return}t.classList.add("pswp--zoom-allowed");const o=s===i.zoomLevels.initial?i.zoomLevels.secondary:i.zoomLevels.initial;D(t,o<=s),(e.imageClickAction==="zoom"||e.imageClickAction==="zoom-or-close")&&t.classList.add("pswp--click-to-zoom")}}function Ot(r){const t=r.getBoundingClientRect();return{x:t.left,y:t.top,w:t.width}}function Et(r,t,i){const e=r.getBoundingClientRect(),s=e.width/t,n=e.height/i,o=s>n?s:n,a=(e.width-t*o)/2,l=(e.height-i*o)/2,h={x:e.left+a,y:e.top+l,w:t*o};return h.innerRect={w:e.width,h:e.height,x:a,y:l},h}function Zt(r,t,i){const e=i.dispatch("thumbBounds",{index:r,itemData:t,instance:i});if(e.thumbBounds)return e.thumbBounds;const{element:s}=t;let n,o;if(s&&i.options.thumbSelector!==!1){const a=i.options.thumbSelector||"img";o=s.matches(a)?s:s.querySelector(a)}return o=i.applyFilters("thumbEl",o,t,r),o&&(t.thumbCropped?n=Et(o,t.width||t.w||0,t.height||t.h||0):n=Ot(o)),i.applyFilters("thumbBounds",n,t,r)}class Dt{constructor(t,i){this.type=t,this.defaultPrevented=!1,i&&Object.assign(this,i)}preventDefault(){this.defaultPrevented=!0}}class Mt{constructor(){this._listeners={},this._filters={},this.pswp=void 0,this.options=void 0}addFilter(t,i,e=100){var s,n,o;this._filters[t]||(this._filters[t]=[]),(s=this._filters[t])==null||s.push({fn:i,priority:e}),(n=this._filters[t])==null||n.sort((a,l)=>a.priority-l.priority),(o=this.pswp)==null||o.addFilter(t,i,e)}removeFilter(t,i){this._filters[t]&&(this._filters[t]=this._filters[t].filter(e=>e.fn!==i)),this.pswp&&this.pswp.removeFilter(t,i)}applyFilters(t,...i){var e;return(e=this._filters[t])==null||e.forEach(s=>{i[0]=s.fn.apply(this,i)}),i[0]}on(t,i){var e,s;this._listeners[t]||(this._listeners[t]=[]),(e=this._listeners[t])==null||e.push(i),(s=this.pswp)==null||s.on(t,i)}off(t,i){var e;this._listeners[t]&&(this._listeners[t]=this._listeners[t].filter(s=>i!==s)),(e=this.pswp)==null||e.off(t,i)}dispatch(t,i){var s;if(this.pswp)return this.pswp.dispatch(t,i);const e=new Dt(t,i);return(s=this._listeners[t])==null||s.forEach(n=>{n.call(this,e)}),e}}class Rt{constructor(t,i){if(this.element=m("pswp__img pswp__img--placeholder",t?"img":"div",i),t){const e=this.element;e.decoding="async",e.alt="",e.src=t,e.setAttribute("role","presentation")}this.element.setAttribute("aria-hidden","true")}setDisplayedSize(t,i){this.element&&(this.element.tagName==="IMG"?(L(this.element,250,"auto"),this.element.style.transformOrigin="0 0",this.element.style.transform=b(0,0,t/250)):L(this.element,t,i))}destroy(){var t;(t=this.element)!=null&&t.parentNode&&this.element.remove(),this.element=null}}class Ft{constructor(t,i,e){this.instance=i,this.data=t,this.index=e,this.element=void 0,this.placeholder=void 0,this.slide=void 0,this.displayedImageWidth=0,this.displayedImageHeight=0,this.width=Number(this.data.w)||Number(this.data.width)||0,this.height=Number(this.data.h)||Number(this.data.height)||0,this.isAttached=!1,this.hasSlide=!1,this.isDecoding=!1,this.state=f.IDLE,this.data.type?this.type=this.data.type:this.data.src?this.type="image":this.type="html",this.instance.dispatch("contentInit",{content:this})}removePlaceholder(){this.placeholder&&!this.keepPlaceholder()&&setTimeout(()=>{this.placeholder&&(this.placeholder.destroy(),this.placeholder=void 0)},1e3)}load(t,i){if(this.slide&&this.usePlaceholder())if(this.placeholder){const e=this.placeholder.element;e&&!e.parentElement&&this.slide.container.prepend(e)}else{const e=this.instance.applyFilters("placeholderSrc",this.data.msrc&&this.slide.isFirstSlide?this.data.msrc:!1,this);this.placeholder=new Rt(e,this.slide.container)}this.element&&!i||this.instance.dispatch("contentLoad",{content:this,isLazy:t}).defaultPrevented||(this.isImageContent()?(this.element=m("pswp__img","img"),this.displayedImageWidth&&this.loadImage(t)):(this.element=m("pswp__content","div"),this.element.innerHTML=this.data.html||""),i&&this.slide&&this.slide.updateContentSize(!0))}loadImage(t){if(!this.isImageContent()||!this.element||this.instance.dispatch("contentLoadImage",{content:this,isLazy:t}).defaultPrevented)return;const i=this.element;this.updateSrcsetSizes(),this.data.srcset&&(i.srcset=this.data.srcset),i.src=this.data.src??"",i.alt=this.data.alt??"",this.state=f.LOADING,i.complete?this.onLoaded():(i.onload=()=>{this.onLoaded()},i.onerror=()=>{this.onError()})}setSlide(t){this.slide=t,this.hasSlide=!0,this.instance=t.pswp}onLoaded(){this.state=f.LOADED,this.slide&&this.element&&(this.instance.dispatch("loadComplete",{slide:this.slide,content:this}),this.slide.isActive&&this.slide.heavyAppended&&!this.element.parentNode&&(this.append(),this.slide.updateContentSize(!0)),(this.state===f.LOADED||this.state===f.ERROR)&&this.removePlaceholder())}onError(){this.state=f.ERROR,this.slide&&(this.displayError(),this.instance.dispatch("loadComplete",{slide:this.slide,isError:!0,content:this}),this.instance.dispatch("loadError",{slide:this.slide,content:this}))}isLoading(){return this.instance.applyFilters("isContentLoading",this.state===f.LOADING,this)}isError(){return this.state===f.ERROR}isImageContent(){return this.type==="image"}setDisplayedSize(t,i){if(this.element&&(this.placeholder&&this.placeholder.setDisplayedSize(t,i),!this.instance.dispatch("contentResize",{content:this,width:t,height:i}).defaultPrevented&&(L(this.element,t,i),this.isImageContent()&&!this.isError()))){const e=!this.displayedImageWidth&&t;this.displayedImageWidth=t,this.displayedImageHeight=i,e?this.loadImage(!1):this.updateSrcsetSizes(),this.slide&&this.instance.dispatch("imageSizeChange",{slide:this.slide,width:t,height:i,content:this})}}isZoomable(){return this.instance.applyFilters("isContentZoomable",this.isImageContent()&&this.state!==f.ERROR,this)}updateSrcsetSizes(){if(!this.isImageContent()||!this.element||!this.data.srcset)return;const t=this.element,i=this.instance.applyFilters("srcsetSizesWidth",this.displayedImageWidth,this);(!t.dataset.largestUsedSize||i>parseInt(t.dataset.largestUsedSize,10))&&(t.sizes=i+"px",t.dataset.largestUsedSize=String(i))}usePlaceholder(){return this.instance.applyFilters("useContentPlaceholder",this.isImageContent(),this)}lazyLoad(){this.instance.dispatch("contentLazyLoad",{content:this}).defaultPrevented||this.load(!0)}keepPlaceholder(){return this.instance.applyFilters("isKeepingPlaceholder",this.isLoading(),this)}destroy(){this.hasSlide=!1,this.slide=void 0,!this.instance.dispatch("contentDestroy",{content:this}).defaultPrevented&&(this.remove(),this.placeholder&&(this.placeholder.destroy(),this.placeholder=void 0),this.isImageContent()&&this.element&&(this.element.onload=null,this.element.onerror=null,this.element=void 0))}displayError(){var t;if(this.slide){let i=m("pswp__error-msg","div");i.innerText=((t=this.instance.options)==null?void 0:t.errorMsg)??"",i=this.instance.applyFilters("contentErrorElement",i,this),this.element=m("pswp__content pswp__error-msg-container","div"),this.element.appendChild(i),this.slide.container.innerText="",this.slide.container.appendChild(this.element),this.slide.updateContentSize(!0),this.removePlaceholder()}}append(){if(this.isAttached||!this.element)return;if(this.isAttached=!0,this.state===f.ERROR){this.displayError();return}if(this.instance.dispatch("contentAppend",{content:this}).defaultPrevented)return;const t="decode"in this.element;this.isImageContent()?t&&this.slide&&(!this.slide.isActive||C())?(this.isDecoding=!0,this.element.decode().catch(()=>{}).finally(()=>{this.isDecoding=!1,this.appendImage()})):this.appendImage():this.slide&&!this.element.parentNode&&this.slide.container.appendChild(this.element)}activate(){this.instance.dispatch("contentActivate",{content:this}).defaultPrevented||!this.slide||(this.isImageContent()&&this.isDecoding&&!C()?this.appendImage():this.isError()&&this.load(!1,!0),this.slide.holderElement&&this.slide.holderElement.setAttribute("aria-hidden","false"))}deactivate(){this.instance.dispatch("contentDeactivate",{content:this}),this.slide&&this.slide.holderElement&&this.slide.holderElement.setAttribute("aria-hidden","true")}remove(){this.isAttached=!1,!this.instance.dispatch("contentRemove",{content:this}).defaultPrevented&&(this.element&&this.element.parentNode&&this.element.remove(),this.placeholder&&this.placeholder.element&&this.placeholder.element.remove())}appendImage(){this.isAttached&&(this.instance.dispatch("contentAppendImage",{content:this}).defaultPrevented||(this.slide&&this.element&&!this.element.parentNode&&this.slide.container.appendChild(this.element),(this.state===f.LOADED||this.state===f.ERROR)&&this.removePlaceholder()))}}const Bt=5;function W(r,t,i){const e=t.createContentFromData(r,i);let s;const{options:n}=t;if(n){s=new k(n,r,-1);let o;t.pswp?o=t.pswp.viewportSize:o=B(n,t);const a=N(n,o,r,i);s.update(e.width,e.height,a)}return e.lazyLoad(),s&&e.setDisplayedSize(Math.ceil(e.width*s.initial),Math.ceil(e.height*s.initial)),e}function Nt(r,t){const i=t.getItemData(r);if(!t.dispatch("lazyLoadSlide",{index:r,itemData:i}).defaultPrevented)return W(i,t,r)}class kt{constructor(t){this.pswp=t,this.limit=Math.max(t.options.preload[0]+t.options.preload[1]+1,Bt),this._cachedItems=[]}updateLazy(t){const{pswp:i}=this;if(i.dispatch("lazyLoad").defaultPrevented)return;const{preload:e}=i.options,s=t===void 0?!0:t>=0;let n;for(n=0;n<=e[1];n++)this.loadSlideByIndex(i.currIndex+(s?n:-n));for(n=1;n<=e[0];n++)this.loadSlideByIndex(i.currIndex+(s?-n:n))}loadSlideByIndex(t){const i=this.pswp.getLoopedIndex(t);let e=this.getContentByIndex(i);e||(e=Nt(i,this.pswp),e&&this.addToCache(e))}getContentBySlide(t){let i=this.getContentByIndex(t.index);return i||(i=this.pswp.createContentFromData(t.data,t.index),this.addToCache(i)),i.setSlide(t),i}addToCache(t){if(this.removeByIndex(t.index),this._cachedItems.push(t),this._cachedItems.length>this.limit){const i=this._cachedItems.findIndex(e=>!e.isAttached&&!e.hasSlide);i!==-1&&this._cachedItems.splice(i,1)[0].destroy()}}removeByIndex(t){const i=this._cachedItems.findIndex(e=>e.index===t);i!==-1&&this._cachedItems.splice(i,1)}getContentByIndex(t){return this._cachedItems.find(i=>i.index===t)}destroy(){this._cachedItems.forEach(t=>t.destroy()),this._cachedItems=[]}}class Ht extends Mt{getNumItems(){var s;let t=0;const i=(s=this.options)==null?void 0:s.dataSource;i&&"length"in i?t=i.length:i&&"gallery"in i&&(i.items||(i.items=this._getGalleryDOMElements(i.gallery)),i.items&&(t=i.items.length));const e=this.dispatch("numItems",{dataSource:i,numItems:t});return this.applyFilters("numItems",e.numItems,i)}createContentFromData(t,i){return new Ft(t,this,i)}getItemData(t){var o;const i=(o=this.options)==null?void 0:o.dataSource;let e={};Array.isArray(i)?e=i[t]:i&&"gallery"in i&&(i.items||(i.items=this._getGalleryDOMElements(i.gallery)),e=i.items[t]);let s=e;s instanceof Element&&(s=this._domElementToItemData(s));const n=this.dispatch("itemData",{itemData:s||{},index:t});return this.applyFilters("itemData",n.itemData,t)}_getGalleryDOMElements(t){var i,e;return(i=this.options)!=null&&i.children||(e=this.options)!=null&&e.childSelector?X(this.options.children,this.options.childSelector,t)||[]:[t]}_domElementToItemData(t){const i={element:t},e=t.tagName==="A"?t:t.querySelector("a");if(e){i.src=e.dataset.pswpSrc||e.href,e.dataset.pswpSrcset&&(i.srcset=e.dataset.pswpSrcset),i.width=e.dataset.pswpWidth?parseInt(e.dataset.pswpWidth,10):0,i.height=e.dataset.pswpHeight?parseInt(e.dataset.pswpHeight,10):0,i.w=i.width,i.h=i.height,e.dataset.pswpType&&(i.type=e.dataset.pswpType);const s=t.querySelector("img");s&&(i.msrc=s.currentSrc||s.src,i.alt=s.getAttribute("alt")??""),(e.dataset.pswpCropped||e.dataset.cropped)&&(i.thumbCropped=!0)}return this.applyFilters("domItemData",i,t,e)}lazyLoadData(t,i){return W(t,this,i)}}const P=.003;class Wt{constructor(t){this.pswp=t,this.isClosed=!0,this.isOpen=!1,this.isClosing=!1,this.isOpening=!1,this._duration=void 0,this._useAnimation=!1,this._croppedZoom=!1,this._animateRootOpacity=!1,this._animateBgOpacity=!1,this._placeholder=void 0,this._opacityElement=void 0,this._cropContainer1=void 0,this._cropContainer2=void 0,this._thumbBounds=void 0,this._prepareOpen=this._prepareOpen.bind(this),t.on("firstZoomPan",this._prepareOpen)}open(){this._prepareOpen(),this._start()}close(){if(this.isClosed||this.isClosing||this.isOpening)return;const t=this.pswp.currSlide;this.isOpen=!1,this.isOpening=!1,this.isClosing=!0,this._duration=this.pswp.options.hideAnimationDuration,t&&t.currZoomLevel*t.width>=this.pswp.options.maxWidthToAnimate&&(this._duration=0),this._applyStartProps(),setTimeout(()=>{this._start()},this._croppedZoom?30:0)}_prepareOpen(){if(this.pswp.off("firstZoomPan",this._prepareOpen),!this.isOpening){const t=this.pswp.currSlide;this.isOpening=!0,this.isClosing=!1,this._duration=this.pswp.options.showAnimationDuration,t&&t.zoomLevels.initial*t.width>=this.pswp.options.maxWidthToAnimate&&(this._duration=0),this._applyStartProps()}}_applyStartProps(){var s;const{pswp:t}=this,i=this.pswp.currSlide,{options:e}=t;if(e.showHideAnimationType==="fade"?(e.showHideOpacity=!0,this._thumbBounds=void 0):e.showHideAnimationType==="none"?(e.showHideOpacity=!1,this._duration=0,this._thumbBounds=void 0):this.isOpening&&t._initialThumbBounds?this._thumbBounds=t._initialThumbBounds:this._thumbBounds=this.pswp.getThumbBounds(),this._placeholder=i==null?void 0:i.getPlaceholderElement(),t.animations.stopAll(),this._useAnimation=!!(this._duration&&this._duration>50),this._animateZoom=!!this._thumbBounds&&(i==null?void 0:i.content.usePlaceholder())&&(!this.isClosing||!t.mainScroll.isShifted()),this._animateZoom?this._animateRootOpacity=e.showHideOpacity??!1:(this._animateRootOpacity=!0,this.isOpening&&i&&(i.zoomAndPanToInitial(),i.applyCurrentZoomPan())),this._animateBgOpacity=!this._animateRootOpacity&&this.pswp.options.bgOpacity>P,this._opacityElement=this._animateRootOpacity?t.element:t.bg,!this._useAnimation){this._duration=0,this._animateZoom=!1,this._animateBgOpacity=!1,this._animateRootOpacity=!0,this.isOpening&&(t.element&&(t.element.style.opacity=String(P)),t.applyBgOpacity(1));return}this._animateZoom&&this._thumbBounds&&this._thumbBounds.innerRect?(this._croppedZoom=!0,this._cropContainer1=this.pswp.container,this._cropContainer2=(s=this.pswp.currSlide)==null?void 0:s.holderElement,t.container&&(t.container.style.overflow="hidden",t.container.style.width=t.viewportSize.x+"px")):this._croppedZoom=!1,this.isOpening?(this._animateRootOpacity?(t.element&&(t.element.style.opacity=String(P)),t.applyBgOpacity(1)):(this._animateBgOpacity&&t.bg&&(t.bg.style.opacity=String(P)),t.element&&(t.element.style.opacity="1")),this._animateZoom&&(this._setClosedStateZoomPan(),this._placeholder&&(this._placeholder.style.willChange="transform",this._placeholder.style.opacity=String(P)))):this.isClosing&&(t.mainScroll.itemHolders[0]&&(t.mainScroll.itemHolders[0].el.style.display="none"),t.mainScroll.itemHolders[2]&&(t.mainScroll.itemHolders[2].el.style.display="none"),this._croppedZoom&&t.mainScroll.x!==0&&(t.mainScroll.resetPosition(),t.mainScroll.resize()))}_start(){this.isOpening&&this._useAnimation&&this._placeholder&&this._placeholder.tagName==="IMG"?new Promise(t=>{let i=!1,e=!0;G(this._placeholder).finally(()=>{i=!0,e||t(!0)}),setTimeout(()=>{e=!1,i&&t(!0)},50),setTimeout(t,250)}).finally(()=>this._initiate()):this._initiate()}_initiate(){var t,i;(t=this.pswp.element)==null||t.style.setProperty("--pswp-transition-duration",this._duration+"ms"),this.pswp.dispatch(this.isOpening?"openingAnimationStart":"closingAnimationStart"),this.pswp.dispatch("initialZoom"+(this.isOpening?"In":"Out")),(i=this.pswp.element)==null||i.classList.toggle("pswp--ui-visible",this.isOpening),this.isOpening?(this._placeholder&&(this._placeholder.style.opacity="1"),this._animateToOpenState()):this.isClosing&&this._animateToClosedState(),this._useAnimation||this._onAnimationComplete()}_onAnimationComplete(){var i;const{pswp:t}=this;this.isOpen=this.isOpening,this.isClosed=this.isClosing,this.isOpening=!1,this.isClosing=!1,t.dispatch(this.isOpen?"openingAnimationEnd":"closingAnimationEnd"),t.dispatch("initialZoom"+(this.isOpen?"InEnd":"OutEnd")),this.isClosed?t.destroy():this.isOpen&&(this._animateZoom&&t.container&&(t.container.style.overflow="visible",t.container.style.width="100%"),(i=t.currSlide)==null||i.applyCurrentZoomPan())}_animateToOpenState(){const{pswp:t}=this;this._animateZoom&&(this._croppedZoom&&this._cropContainer1&&this._cropContainer2&&(this._animateTo(this._cropContainer1,"transform","translate3d(0,0,0)"),this._animateTo(this._cropContainer2,"transform","none")),t.currSlide&&(t.currSlide.zoomAndPanToInitial(),this._animateTo(t.currSlide.container,"transform",t.currSlide.getCurrentTransform()))),this._animateBgOpacity&&t.bg&&this._animateTo(t.bg,"opacity",String(t.options.bgOpacity)),this._animateRootOpacity&&t.element&&this._animateTo(t.element,"opacity","1")}_animateToClosedState(){const{pswp:t}=this;this._animateZoom&&this._setClosedStateZoomPan(!0),this._animateBgOpacity&&t.bgOpacity>.01&&t.bg&&this._animateTo(t.bg,"opacity","0"),this._animateRootOpacity&&t.element&&this._animateTo(t.element,"opacity","0")}_setClosedStateZoomPan(t){if(!this._thumbBounds)return;const{pswp:i}=this,{innerRect:e}=this._thumbBounds,{currSlide:s,viewportSize:n}=i;if(this._croppedZoom&&e&&this._cropContainer1&&this._cropContainer2){const o=-n.x+(this._thumbBounds.x-e.x)+e.w,a=-n.y+(this._thumbBounds.y-e.y)+e.h,l=n.x-e.w,h=n.y-e.h;t?(this._animateTo(this._cropContainer1,"transform",b(o,a)),this._animateTo(this._cropContainer2,"transform",b(l,h))):(v(this._cropContainer1,o,a),v(this._cropContainer2,l,h))}s&&(u(s.pan,e||this._thumbBounds),s.currZoomLevel=this._thumbBounds.w/s.width,t?this._animateTo(s.container,"transform",s.getCurrentTransform()):s.applyCurrentZoomPan())}_animateTo(t,i,e){if(!this._duration){t.style[i]=e;return}const{animations:s}=this.pswp,n={duration:this._duration,easing:this.pswp.options.easing,onComplete:()=>{s.activeAnimations.length||this._onAnimationComplete()},target:t};n[i]=e,s.startTransition(n)}}const Vt={allowPanToNext:!0,spacing:.1,loop:!0,pinchToClose:!0,closeOnVerticalDrag:!0,hideAnimationDuration:333,showAnimationDuration:333,zoomAnimationDuration:333,escKey:!0,arrowKeys:!0,returnFocus:!0,maxWidthToAnimate:4e3,clickToCloseNonZoomable:!0,imageClickAction:"zoom-or-close",bgClickAction:"close",tapAction:"toggle-controls",doubleTapAction:"zoom",indexIndicatorSep:" / ",preloaderDelay:2e3,bgOpacity:.8,index:0,errorMsg:"The image cannot be loaded",preload:[1,2],easing:"cubic-bezier(.4,0,.22,1)"};class Ut extends Ht{constructor(t){super(),this.options=this._prepareOptions(t||{}),this.offset={x:0,y:0},this._prevViewportSize={x:0,y:0},this.viewportSize={x:0,y:0},this.bgOpacity=1,this.currIndex=0,this.potentialIndex=0,this.isOpen=!1,this.isDestroying=!1,this.hasMouse=!1,this._initialItemData={},this._initialThumbBounds=void 0,this.topBar=void 0,this.element=void 0,this.template=void 0,this.container=void 0,this.scrollWrap=void 0,this.currSlide=void 0,this.events=new Y,this.animations=new wt,this.mainScroll=new dt(this),this.gestures=new lt(this),this.opener=new Wt(this),this.keyboard=new ut(this),this.contentLoader=new kt(this)}init(){if(this.isOpen||this.isDestroying)return!1;this.isOpen=!0,this.dispatch("init"),this.dispatch("beforeOpen"),this._createMainStructure();let t="pswp--open";return this.gestures.supportsTouch&&(t+=" pswp--touch"),this.options.mainClass&&(t+=" "+this.options.mainClass),this.element&&(this.element.className+=" "+t),this.currIndex=this.options.index||0,this.potentialIndex=this.currIndex,this.dispatch("firstUpdate"),this.scrollWheel=new Pt(this),(Number.isNaN(this.currIndex)||this.currIndex<0||this.currIndex>=this.getNumItems())&&(this.currIndex=0),this.gestures.supportsTouch||this.mouseDetected(),this.updateSize(),this.offset.y=window.pageYOffset,this._initialItemData=this.getItemData(this.currIndex),this.dispatch("gettingData",{index:this.currIndex,data:this._initialItemData,slide:void 0}),this._initialThumbBounds=this.getThumbBounds(),this.dispatch("initialLayout"),this.on("openingAnimationEnd",()=>{const{itemHolders:i}=this.mainScroll;i[0]&&(i[0].el.style.display="block",this.setContent(i[0],this.currIndex-1)),i[2]&&(i[2].el.style.display="block",this.setContent(i[2],this.currIndex+1)),this.appendHeavy(),this.contentLoader.updateLazy(),this.events.add(window,"resize",this._handlePageResize.bind(this)),this.events.add(window,"scroll",this._updatePageScrollOffset.bind(this)),this.dispatch("bindEvents")}),this.mainScroll.itemHolders[1]&&this.setContent(this.mainScroll.itemHolders[1],this.currIndex),this.dispatch("change"),this.opener.open(),this.dispatch("afterInit"),!0}getLoopedIndex(t){const i=this.getNumItems();return this.options.loop&&(t>i-1&&(t-=i),t<0&&(t+=i)),I(t,0,i-1)}appendHeavy(){this.mainScroll.itemHolders.forEach(t=>{var i;(i=t.slide)==null||i.appendHeavy()})}goTo(t){this.mainScroll.moveIndexBy(this.getLoopedIndex(t)-this.potentialIndex)}next(){this.goTo(this.potentialIndex+1)}prev(){this.goTo(this.potentialIndex-1)}zoomTo(...t){var i;(i=this.currSlide)==null||i.zoomTo(...t)}toggleZoom(){var t;(t=this.currSlide)==null||t.toggleZoom()}close(){!this.opener.isOpen||this.isDestroying||(this.isDestroying=!0,this.dispatch("close"),this.events.removeAll(),this.opener.close())}destroy(){var t;if(!this.isDestroying){this.options.showHideAnimationType="none",this.close();return}this.dispatch("destroy"),this._listeners={},this.scrollWrap&&(this.scrollWrap.ontouchmove=null,this.scrollWrap.ontouchend=null),(t=this.element)==null||t.remove(),this.mainScroll.itemHolders.forEach(i=>{var e;(e=i.slide)==null||e.destroy()}),this.contentLoader.destroy(),this.events.removeAll()}refreshSlideContent(t){this.contentLoader.removeByIndex(t),this.mainScroll.itemHolders.forEach((i,e)=>{var n,o;let s=(((n=this.currSlide)==null?void 0:n.index)??0)-1+e;this.canLoop()&&(s=this.getLoopedIndex(s)),s===t&&(this.setContent(i,t,!0),e===1&&(this.currSlide=i.slide,(o=i.slide)==null||o.setIsActive(!0)))}),this.dispatch("change")}setContent(t,i,e){if(this.canLoop()&&(i=this.getLoopedIndex(i)),t.slide){if(t.slide.index===i&&!e)return;t.slide.destroy(),t.slide=void 0}if(!this.canLoop()&&(i<0||i>=this.getNumItems()))return;const s=this.getItemData(i);t.slide=new j(s,i,this),i===this.currIndex&&(this.currSlide=t.slide),t.slide.append(t.el)}getViewportCenterPoint(){return{x:this.viewportSize.x/2,y:this.viewportSize.y/2}}updateSize(t){if(this.isDestroying)return;const i=B(this.options,this);!t&&x(i,this._prevViewportSize)||(u(this._prevViewportSize,i),this.dispatch("beforeResize"),u(this.viewportSize,this._prevViewportSize),this._updatePageScrollOffset(),this.dispatch("viewportSize"),this.mainScroll.resize(this.opener.isOpen),!this.hasMouse&&window.matchMedia("(any-hover: hover)").matches&&this.mouseDetected(),this.dispatch("resize"))}applyBgOpacity(t){this.bgOpacity=Math.max(t,0),this.bg&&(this.bg.style.opacity=String(this.bgOpacity*this.options.bgOpacity))}mouseDetected(){var t;this.hasMouse||(this.hasMouse=!0,(t=this.element)==null||t.classList.add("pswp--has_mouse"))}_handlePageResize(){this.updateSize(),/iPhone|iPad|iPod/i.test(window.navigator.userAgent)&&setTimeout(()=>{this.updateSize()},500)}_updatePageScrollOffset(){this.setScrollOffset(0,window.pageYOffset)}setScrollOffset(t,i){this.offset.x=t,this.offset.y=i,this.dispatch("updateScrollOffset")}_createMainStructure(){this.element=m("pswp","div"),this.element.setAttribute("tabindex","-1"),this.element.setAttribute("role","dialog"),this.template=this.element,this.bg=m("pswp__bg","div",this.element),this.scrollWrap=m("pswp__scroll-wrap","section",this.element),this.container=m("pswp__container","div",this.scrollWrap),this.scrollWrap.setAttribute("aria-roledescription","carousel"),this.container.setAttribute("aria-live","off"),this.container.setAttribute("id","pswp__items"),this.mainScroll.appendHolders(),this.ui=new zt(this),this.ui.init(),(this.options.appendToEl||document.body).appendChild(this.element)}getThumbBounds(){return Zt(this.currIndex,this.currSlide?this.currSlide.data:this._initialItemData,this)}canLoop(){return this.options.loop&&this.getNumItems()>2}_prepareOptions(t){return window.matchMedia("(prefers-reduced-motion), (update: slow)").matches&&(t.showHideAnimationType="none",t.zoomAnimationDuration=0),{...Vt,...t}}}export{Ut as default}; diff --git a/assets/pic1-4e2c7292.png b/assets/pic1-4e2c7292.png new file mode 100644 index 00000000..6d32d688 Binary files /dev/null and b/assets/pic1-4e2c7292.png differ diff --git a/assets/pic10-1bff38b7.png b/assets/pic10-1bff38b7.png new file mode 100644 index 00000000..39556754 Binary files /dev/null and b/assets/pic10-1bff38b7.png differ diff --git a/assets/pic11-740aeb33.png b/assets/pic11-740aeb33.png new file mode 100644 index 00000000..6202c428 Binary files /dev/null and b/assets/pic11-740aeb33.png differ diff --git a/assets/pic2-79000156.png b/assets/pic2-79000156.png new file mode 100644 index 00000000..0e75c908 Binary files /dev/null and b/assets/pic2-79000156.png differ diff --git a/assets/pic3-add77060.png b/assets/pic3-add77060.png new file mode 100644 index 00000000..93411c65 Binary files /dev/null and b/assets/pic3-add77060.png differ diff --git a/assets/pic4-00de76cf.png b/assets/pic4-00de76cf.png new file mode 100644 index 00000000..8c7ce83a Binary files /dev/null and b/assets/pic4-00de76cf.png differ diff --git a/assets/pic5-8991222b.png b/assets/pic5-8991222b.png new file mode 100644 index 00000000..4c4e95e7 Binary files /dev/null and b/assets/pic5-8991222b.png differ diff --git a/assets/pic6-422afee3.png b/assets/pic6-422afee3.png new file mode 100644 index 00000000..7cb6dfc6 Binary files /dev/null and b/assets/pic6-422afee3.png differ diff --git a/assets/pic7-a05b71d6.png b/assets/pic7-a05b71d6.png new file mode 100644 index 00000000..a385f820 Binary files /dev/null and b/assets/pic7-a05b71d6.png differ diff --git a/assets/pic8-e2bb7062.png b/assets/pic8-e2bb7062.png new file mode 100644 index 00000000..803d7cd9 Binary files /dev/null and b/assets/pic8-e2bb7062.png differ diff --git a/assets/pic9-1cae8fb0.png b/assets/pic9-1cae8fb0.png new file mode 100644 index 00000000..88f0af15 Binary files /dev/null and b/assets/pic9-1cae8fb0.png differ diff --git a/assets/pict1-1fdc4194.png b/assets/pict1-1fdc4194.png new file mode 100644 index 00000000..2a1c44d7 Binary files /dev/null and b/assets/pict1-1fdc4194.png differ diff --git a/assets/pict2-662f781b.png b/assets/pict2-662f781b.png new file mode 100644 index 00000000..e3b151e4 Binary files /dev/null and b/assets/pict2-662f781b.png differ diff --git a/assets/pict3-adef5567.png b/assets/pict3-adef5567.png new file mode 100644 index 00000000..1b3c7103 Binary files /dev/null and b/assets/pict3-adef5567.png differ diff --git a/assets/pict4-1f728e83.png b/assets/pict4-1f728e83.png new file mode 100644 index 00000000..6fec5c55 Binary files /dev/null and b/assets/pict4-1f728e83.png differ diff --git a/assets/pict5-5f2ffd8e.png b/assets/pict5-5f2ffd8e.png new file mode 100644 index 00000000..fc0dfa04 Binary files /dev/null and b/assets/pict5-5f2ffd8e.png differ diff --git a/assets/pict6-c3b9346b.png b/assets/pict6-c3b9346b.png new file mode 100644 index 00000000..393a2d1d Binary files /dev/null and b/assets/pict6-c3b9346b.png differ diff --git a/assets/pict7-95fd5142.png b/assets/pict7-95fd5142.png new file mode 100644 index 00000000..a70aa071 Binary files /dev/null and b/assets/pict7-95fd5142.png differ diff --git a/assets/pict8-1d11715f.png b/assets/pict8-1d11715f.png new file mode 100644 index 00000000..2770c666 Binary files /dev/null and b/assets/pict8-1d11715f.png differ diff --git a/assets/plugin-vue_export-helper-c27b6911.js b/assets/plugin-vue_export-helper-c27b6911.js new file mode 100644 index 00000000..718edd33 --- /dev/null +++ b/assets/plugin-vue_export-helper-c27b6911.js @@ -0,0 +1 @@ +const s=(t,r)=>{const o=t.__vccOpts||t;for(const[c,e]of r)o[c]=e;return o};export{s as _}; diff --git a/assets/problem-create.html-478f6e2f.js b/assets/problem-create.html-478f6e2f.js new file mode 100644 index 00000000..3569af16 --- /dev/null +++ b/assets/problem-create.html-478f6e2f.js @@ -0,0 +1,201 @@ +import{_ as s}from"./plugin-vue_export-helper-c27b6911.js";import{o as n,c as a,e as l}from"./app-68b9e0b9.js";const p="/assets/pic1-4e2c7292.png",o="/assets/pic11-740aeb33.png",e="/assets/pic10-1bff38b7.png",c="/assets/pic8-e2bb7062.png",t="/assets/pic9-1cae8fb0.png",r="/assets/pic7-a05b71d6.png",E="/assets/pic6-422afee3.png",F="/assets/pic5-8991222b.png",i="/assets/pic4-00de76cf.png",y="/assets/pic3-add77060.png",D="/assets/pic2-79000156.png",d={},C=l('

Hydro常见题型的制做心得

作者: laomai
qq: 29985091
网址: http://82.157.98.222:8888/
日期: 2022/03/16

本文为作者使用hydro时的实验记录,希望对大家有帮助.包括如下内容

零. hydro题目存储格式
一. 制做最简单的oj题
二. 含有自定义头文件的oj题,即函数交互式的题目
三. 半自动对拍的oj题,即不需要录入预期输出的题
四. 完全对拍题,即不需要录入输入数据和输出数据的题
五. 指定输入文件和输出文件
六. 多个子任务
七. 客观题,即制做有标准答案的填空和选择题.

零. hydro题目存储格式

如果想在本地建立好题目,然后批量上传的话. 下面的格式应该对你有帮助
每个题目应自占一个目录,目录名为题目编号比如1 ,2,3,4等等.
每个题目目录下一般有下面的元素:
problem_zh.md 这个文件是就是题目的内容,即题目的描述,是一个markdown格式的文档.
probelm.yaml 文件.这个是题目的配置信息. 比如标题和标签等。
testdata 子目录,对应网站里的测试数据部分里的文件,
里面至少有一个config.yaml文件 用来说明测试的类型.具体内容见后面的例子
如果题目有测试用例,则每个用例至少要提供一个in文件和一个输出文件(但有些测试类型不用,详情见后)
additional_file子目录用来存放给做题者用的额外文件,比如头文件,图片,pdf文档等,在题目的 markdown 文档中可以用下面的格式为这些文件提供下载链接:[提示文字](file://xxx.txt)

下面为手工录入各种题型的步骤,即在网站登录后点创建题目之后的操作.如下图所示 pic1

我们假定题目内容均为下面的markdown文档

# 要求
+
+输入两个整数,输出他们的和
+
+# 样例
+
+\`\`\`input1
+123 500
+\`\`\`
+
+\`\`\`output1
+623
+\`\`\`
+

一 制做最简单的OJ题目

题目网址: http://82.157.98.222:8888/p/P10000

  1. 新建题目之后编辑题目内容,输入题号和标题,然后点创建按钮。如下图所示.
  2. 此时出现下面的图,点创建文件,文件名为 1.in, 表示用例 1 的输入
  3. 编辑 1.in 的内容为两个整数比如 2 和 3 ,空格分开,如下图所示,然后点确定
  4. 类似办法创建一个 1.out 文件,内容为 5 ,注意数字编号必须和 in 文件一致,创建之后的文件列表和下面类似.

pic11

  1. 这样第一个用例的输入和预期输出就录入完毕,现在可以做本题了
  2. 本题的 AC 代码为:
#include <iostream>
+using namespace std;
+int main(int argc,char* argv[]){
+    int a,b;
+    cin>>a>>b;
+    cout <<(a+b);
+    return 0;
+}
+

二、函数交互型题目

题目网址: http://82.157.98.222:8888/p/P10001
本类型和类型一的区别在于出题者要向做题者提供一个额外的头文件,做题者的主函数里可以包含这个头文件以调用出题者提供的某些函数,或者实现头文件里指定的函数.

  1. 题目内容的录入以及测试数据的录入和类型一样
  2. 本题要额外上传两个文件.分别为 tools.hconfig.yaml ,如下图所示

pic10

tools.h 的内容为

#include<iostream>
+using namespace std;
+
+int add(int x,int y);  //留待做题者实现
+
+int main(int argc,char* argv[]){
+    int a,b;
+    cin>>a>>b;
+    cout << add(a,b);
+    return 0;
+}
+

这个头文件里实现了一个主函数,并且声明了需要做题者实现的函数add,当然,出题者应该在题目要求里写明这个函数的原型以及把tools.h文件上传到附加文件列表中,以方便做题者.
题面里可以用如下格式为用户提供下载链接,中括号内的内容可以自己写,[tools.h](file://tools.h) 如下面所示

pic8

pic9

config.yaml文件的内容为

type: default
+filename: null
+user_extra_files:
+  - tools.h
+

本题的ac代码为

#include "tools.h"
+int add(int x,int y){
+    return x+y;
+}
+

可见本类型的题目,做题者包含给定的头文件后,可以不需要自己实现主函数,只需要专心实现给定的函数即可.

三,半对拍-自己指定评测程序并修改测试输出格式

例题网址:http://82.157.98.222:8888/p/P10002
本题型的特点是不需要手工给出每个用例的预期输出,但是要自己编写一个样本程序,测试时会把用户的输出和样本程序的输出进行对比。

仍以两数求和为例

  1. 题目内容和类型一类似
  2. 测试数据部分只需要提供1.in
  3. 编写一个样本程序 checker.cc,内容如下:
#include "testlib.h"
+int main(int argc, char * argv[]) {
+    registerTestlibCmd(argc, argv);
+    int a = inf.readInt();   // 读取输入流的第一个整数
+    int b = inf.readInt();   // 读取输入流的下一个整数
+    int d = a+b;
+    int c = ouf.readInt();   // 读取输出流的下一个整数
+    if (a+b != c)
+        quitf(_wa, "%d + %d expected %d, found %d", a, b,d,c);   //输出错误的具体信息,便于做题者调试
+    else
+        quitf(_ok, "answer of %d +  %d is %d",a,b,c);
+}
+
  1. config.yaml文件的内容如下:
checker_type: testlib
+checker: checker.cc
+cases:
+  - input: 1.in
+    output: /dev/null # 无输出
+

最终的测试文件列表如下所示:

pic7

当程序有错误时,输出的效果如下

可见这里输出了错误细节,便于做题者调试

本题的ac代码和类型一的一样,内容为

#include <iostream>
+using namespace std;
+int main(int argc,char* argv[]){
+    int a,b;
+    cin>>a>>b;
+    cout <<(a+b);
+    return 0;
+}
+

四. 全自动对拍题

如果不希望自己录入输入数据,而是在每次测试时自动动态生成的话,可以将题目类型设为interactive,并提供一个对拍程序.仍以求和为例
例题网址: http://82.157.98.222:8888/p/P10005

最后测试数据部分的文件列表如下图所示

pic6

  1. checker.cc,内容为:
#include "testlib.h"
+#include <iostream>
+using namespace std;
+
+int main(int argc, char* argv[]) {
+    setName("Interactor A+B");
+    registerInteraction(argc, argv);
+    //自动生成两个随机整数
+    rnd.setSeed(time(NULL));
+    int a = rnd.next(1000);
+    int b = rnd.next(1000);
+    int d = a+b;
+    // 本程序的输出将作为用户程序的输入
+    cout << a << " " << b << endl;
+    int c;
+    // 用户程序的最后输出将作为本程序的输入
+    cin >> c;
+    //对比用户结果和预期结果
+    if (a+b != ans)
+        quitf(_wa, "%d + %d expected %d, found %d", a, b,d,c);   //输出错误的具体信息,便于做题者调试
+    else
+        quitf(_ok, "answer of %d +  %d is %d",a,b,c);
+}
+
  1. config.yaml 文件的内容为:
type: interactive
+interactor: checker.cc
+cases:
+- input: /dev/null # no input and no output, dynamic generated
+  output: /dev/null
+- input: /dev/null # no input and no output, dynamic generated
+  output: /dev/null
+

pic

AC 代码和类型一中的相同

五.文件读写测试

例题网址:http://82.157.98.222:8888/p/P10003
有时希望指定输入和输出文件,此时测试文件 1.in1.out 和类型一类似, 但是要提供config.yaml文件,内容类似于下

file: test
+

则运行时测试环境会自动把每个输入文件复制到test.in中,输出内容和test.out的内容进行对比. ac的代码如下:

#include <fstream>
+using namespace std;
+int main(int argc,char* argv[]){
+    int a,b;
+    ifstream ifs("test.in");
+    ifs>>a>>b;
+    ofstream ofs("test.out");
+    ofs <<(a+b);
+    return 0;
+}
+

六,子任务测试.

例题网址: https://hydro.ac/d/system_test/p/7

  1. 提供好题目和各个子任务的输入、输出文件 建议文件名格式为 data<id>-<数字> id为子任务编号
  2. config.yaml文件的内容参考如下
time: 100ms
+memory: 8m
+subtasks:
+  - score: 20
+    id: 0
+    cases:
+      - input: data1-1.in
+        output: data1-1.ans
+      - input: data1-2.in
+        output: data1-2.ans
+      - input: data1-3.in
+        output: data1-3.ans
+      - input: data1-4.in
+        output: data1-4.ans
+      - input: data1-5.in
+        output: data1-5.ans
+  - score: 20
+    id: 1
+    cases:
+      - input: data2-1.in
+        output: data2-1.ans
+      - input: data2-2.in
+        output: data2-2.ans
+      - input: data2-3.in
+        output: data2-3.ans
+      - input: data2-4.in
+        output: data2-4.ans
+      - input: data2-5.in
+        output: data2-5.ans
+  - score: 20
+    id: 2
+    cases:
+      - input: data3-1.in
+        output: data3-1.ans
+      - input: data3-2.in
+        output: data3-2.ans
+      - input: data3-3.in
+        output: data3-3.ans
+      - input: data3-4.in
+        output: data3-4.ans
+      - input: data3-5.in
+        output: data3-5.ans
+  - score: 20
+    id: 3
+    if: [2]
+    cases:
+      - input: data4-1.in
+        output: data4-1.ans
+      - input: data4-2.in
+        output: data4-2.ans
+      - input: data4-3.in
+        output: data4-3.ans
+      - input: data4-4.in
+        output: data4-4.ans
+      - input: data4-5.in
+        output: data4-5.ans
+  - score: 20
+    id: 4
+    if: [1, 3]
+    cases:
+      - input: data5-1.in
+        output: data5-1.ans
+      - input: data5-2.in
+        output: data5-2.ans
+      - input: data5-3.in
+        output: data5-3.ans
+      - input: data5-4.in
+        output: data5-4.ans
+      - input: data5-5.in
+        output: data5-5.ans
+

可以看出if 用来指定前置子任务.
此外,如果某个子任务没有提供cases部分时,测试时会自动寻找类似于 data<id>-x.indata<id>-x.out 的文件,id为子任务编号
上面的例子故意设计为子任务编号和用例文件中的编号不同,所有每个子任务都需要手工指定对应的cases.

七,客观题制做

注意新版的客观题,格式已经更新。

例题网址:http://82.157.98.222:8888/p/P10004
客观题只需要题面和config.yaml文件. 例子如下:

1. 填空题
+
+1+1 = {{ input(1) }}
+
+2. 选择题
+
+{{ select(2) }}
+- 1+1=2
+- 1+1=3
+- 1+1=4
+
+3. 多选题
+
+{{ multiselect(3) }}
+- A
+- B
+- C
+
+

pic4

上传的 config.yaml 内容为

type: objective # 表明该题为客观题
+answers: # 列举出每一题的正确选项与对应的得分
+  '1': ['2', 50]
+  '2': [['A', 'B'], 30] # 填空题支持多答案,满足其一得分
+  '3': [['A', 'B'], 20] # 多选题答案为数组,有部分分
+
+

题目运行效果如下:

pic3

做完之后点提交,效果如下

pic2

可见评分结果正确.

八.小结

对所有编程题目,题面是必须录入的,如果指定了测试程序时,可以不需要录入输出数据.
如果设置测试方式为interactive,输入数据也不需要手工录入.
想指特殊的测试方式时,一般需要上传一个config.yaml文件,并设置对应字段的值.
对编程题,本文档中用到的字段有

type字段一般为default, 对全自动对拍题,设为interactive

checker_type: testlib checker: checker.cc 用来指定自定义的测试程序,即对拍程序

filename: test用来指定对test.in文件和test.out文件进行读写.

cases:

  • input: 1.in

用来指定测试用例.

更详细的介绍见 https://hydro.js.org/docs/user/testdata/

',87),v=[C];function u(B,b){return n(),a("div",null,v)}const h=s(d,[["render",u],["__file","problem-create.html.vue"]]);export{h as default}; diff --git a/assets/problem-create.html-91deed11.js b/assets/problem-create.html-91deed11.js new file mode 100644 index 00000000..ab5c3a3b --- /dev/null +++ b/assets/problem-create.html-91deed11.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-1d7ad3e6","path":"/docs/user/problem-create.html","title":"Hydro常见题型的制做心得","lang":"en-US","frontmatter":{"description":"作者: laomai qq: 29985091 网址: http://82.157.98.222:8888/ 日期: 2022/03/16 本文为作者使用hydro时的实验记录,希望对大家有帮助.包括如下内容 零. hydro题目存储格式 一. 制做最简单的oj题 二. 含有自定义头文件的oj题,即函数交互式的题目 三. 半自动对拍的oj题,即不需要录...","head":[["meta",{"property":"og:url","content":"https://hydro.js.org/docs/user/problem-create.html"}],["meta",{"property":"og:site_name","content":"Hydro"}],["meta",{"property":"og:title","content":"Hydro常见题型的制做心得"}],["meta",{"property":"og:description","content":"作者: laomai qq: 29985091 网址: http://82.157.98.222:8888/ 日期: 2022/03/16 本文为作者使用hydro时的实验记录,希望对大家有帮助.包括如下内容 零. hydro题目存储格式 一. 制做最简单的oj题 二. 含有自定义头文件的oj题,即函数交互式的题目 三. 半自动对拍的oj题,即不需要录..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:image","content":"https://hydro.js.org/"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2022-11-08T15:43:33.000Z"}],["meta",{"name":"twitter:card","content":"summary_large_image"}],["meta",{"name":"twitter:image:alt","content":"Hydro常见题型的制做心得"}],["meta",{"property":"article:modified_time","content":"2022-11-08T15:43:33.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Hydro常见题型的制做心得\\",\\"image\\":[\\"https://hydro.js.org/\\"],\\"dateModified\\":\\"2022-11-08T15:43:33.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"零. hydro题目存储格式","slug":"零-hydro题目存储格式","link":"#零-hydro题目存储格式","children":[]},{"level":2,"title":"一 制做最简单的OJ题目","slug":"一-制做最简单的oj题目","link":"#一-制做最简单的oj题目","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":[]}],"git":{"createdTime":1647413236000,"updatedTime":1667922213000,"contributors":[{"name":"undefined","email":"i@undefined.moe","commits":2},{"name":"laomai","email":"lmxin@tom.com","commits":1}]},"readingTime":{"minutes":8.78,"words":2634},"filePathRelative":"docs/user/problem-create.md","localizedDate":"March 16, 2022","autoDesc":true,"excerpt":""}');export{e as data}; diff --git a/assets/problem-format.html-1fd54df1.js b/assets/problem-format.html-1fd54df1.js new file mode 100644 index 00000000..19bb46ef --- /dev/null +++ b/assets/problem-format.html-1fd54df1.js @@ -0,0 +1,23 @@ +import{_ as s}from"./plugin-vue_export-helper-c27b6911.js";import{o as n,c as a,e}from"./app-68b9e0b9.js";const l={},p=e(`

Hydro Problem Format

为了便于系统间进行数据交换,Hydro 定义了一种基于 zip 的标准格式用于题目传输。压缩包内文件结构如下:

喵? tree
+.
+├── 任意文件名的文件夹
+│   ├── problem.yaml
+│   ├── problem_zh.md
+│   ├── testdata
+│   │   ├── config.yaml
+│   │   ├── a1.in
+│   │   ├── a1.out
+│   │   ├── a2.in
+│   │   ├── a2.out
+│   │   ├── a3.in
+│   │   └── a3.out
+│   └── additional_file
+│       ├── a.png
+│       └── b.pdf
+└── ...
+

其中 problem.yaml 内容如下:

title: 题目名
+tag:
+- 标签1
+- 标签2
+pid: 题号(字母+数字)
+

problem_*.md 中为 markdown 格式的题面,语言代号支持完整形式(如 zh_CN),也支持短形式(如 zh)。若同时存在多个语言的题面,Hydro 将会自动识别并提供切换功能。

testdata 文件夹中存放所有测试数据文件,命名规则和配置文件格式请参照【测试数据格式】章节。

additional_file 中存储附加文件,通常用于存放图片,PDF 等文件。这些文件可以在题面中使用 file://文件名 的路径访问。

`,8),i=[p];function d(o,c){return n(),a("div",null,i)}const m=s(l,[["render",d],["__file","problem-format.html.vue"]]);export{m as default}; diff --git a/assets/problem-format.html-e4912d61.js b/assets/problem-format.html-e4912d61.js new file mode 100644 index 00000000..3fc43c06 --- /dev/null +++ b/assets/problem-format.html-e4912d61.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-dc52bc6a","path":"/docs/user/problem-format.html","title":"Hydro Problem Format","lang":"en-US","frontmatter":{"description":"为了便于系统间进行数据交换,Hydro 定义了一种基于 zip 的标准格式用于题目传输。压缩包内文件结构如下: 其中 problem.yaml 内容如下: problem*.md 中为 markdown 格式的题面,语言代号支持完整形式(如 zhCN),也支持短形式(如 zh)。若同时存在多个语言的题面,Hydro 将会自动识别并提供切换功能。 tes...","head":[["meta",{"property":"og:url","content":"https://hydro.js.org/docs/user/problem-format.html"}],["meta",{"property":"og:site_name","content":"Hydro"}],["meta",{"property":"og:title","content":"Hydro Problem Format"}],["meta",{"property":"og:description","content":"为了便于系统间进行数据交换,Hydro 定义了一种基于 zip 的标准格式用于题目传输。压缩包内文件结构如下: 其中 problem.yaml 内容如下: problem*.md 中为 markdown 格式的题面,语言代号支持完整形式(如 zhCN),也支持短形式(如 zh)。若同时存在多个语言的题面,Hydro 将会自动识别并提供切换功能。 tes..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-05-19T14:49:26.000Z"}],["meta",{"property":"article:modified_time","content":"2023-05-19T14:49:26.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Hydro Problem Format\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-05-19T14:49:26.000Z\\",\\"author\\":[]}"]]},"headers":[],"git":{"createdTime":1684507766000,"updatedTime":1684507766000,"contributors":[{"name":"undefined","email":"i@undefined.moe","commits":1}]},"readingTime":{"minutes":0.78,"words":233},"filePathRelative":"docs/user/problem-format.md","localizedDate":"May 19, 2023","autoDesc":true,"excerpt":""}');export{e as data}; diff --git a/assets/problem.html-a0ddedfc.js b/assets/problem.html-a0ddedfc.js new file mode 100644 index 00000000..af0fdfd4 --- /dev/null +++ b/assets/problem.html-a0ddedfc.js @@ -0,0 +1,32 @@ +import{_ as c}from"./plugin-vue_export-helper-c27b6911.js";import{r as o,o as d,c as t,a as n,b as s,d as l,w as p,f as r,e as a}from"./app-68b9e0b9.js";const E="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAOQAAACOCAMAAAAW5lSDAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAolBMVEX////d3d3x8fHbrXxmlMTx8cSTZmZmZmZmZnyu2/HElGZ8rdvx266uxfHxxZNmZpPE8fGTxfF8ZpOTlGbx8duufGZmfK7b8fF8ZmbElJOTrdv//86XZmZmfrXm////57V/ZmaXzv///+a1fmb/zpdmZpfO///mtH9mmc5mZn+15//OmWZ/tObm/+Z/Zn+1zv9/ZpdmfpeXfmaXZn+15+bOmZdUWXSRAAAAAWJLR0QAiAUdSAAAAAlwSFlzAAAOwwAADsMBx2+oZAAAAAd0SU1FB+UIDQQsA+92IUUAAALQSURBVHja7dzbctowEAZgEwPbAE3rJmnTQmp8ADmR06Sn93+1yjQznSnrYUHOWN78ey2MP2tl1pJFFCGUxUhbsMizzmPUZ0sggQQSSCCBBBJIIP9FPO4WOZkSvTkXnvpkOpa0nJGL+clI9/GOkYu37sIxSv4Kkww59+nJi3fvZ+Pu03UyTUQtFx8uJcir67lnuvaIvLpOZjJkEiBy9vGTpKX7ahGyGebMkOwTGbMnxLSM3aUQIXeZfTMPrCdjEqSrux+cyZF/m4eE5A462htotIv9G7EiZPu3t2TH/jjvD/nZXfALSrpELr6ENiZjOqLiESJv3DET1K5AAgkkkEACCSSQr2oRVr4m3XnDYxbEvRoCCSSQQAIJJJBAAhkucrkiuv2qG5muM/U9mReZ/nQtN1v9SFMZort73UhLtZPud6cuZHNjXa5q3enaIPNCN3J341muMuU/IdVzzmouBvKCK3hQuwIJJJA6kLaW3gmpHiayOXcRssxan/+CR5rbh6IWH9JWA03XHMj/pmQy9ci8YGqwI5A9LsKKkenaJ1mH0ZMlZZF2ZMlMxqhD2jpSj9wVPOzcGmpXIIEEEkhtSFOFjnz+VaKTJ5ctUTWMnjQnTy6Xm60dBpJ7epOn60CQxmsGfRhI9jFcG7LkHsOVIdmHA23I9Nu9fqRhJ410IflsVYZsmeJE7QokkEACCSSQQAJ56OPYCfuyh/TsciCBBBJIIIEEEkggD7RM17WgYbNplXuLh9v6SUQtuwZ7Q1qSINPHKDKifYDp0za4niy//6iFh5StmJab4JDLn7+KjpFeb8VGL/KifZ2LkVa0LGw8h2T3SFtFQqThd0y0XI6QbjzN2pm8Jw0J32JoW6/qBdn8LhCXXfLdBOEjW0/IF+m176A/5O8t/xo639KGVgzIkIakFY8ldn8ralcggQQSSCCBBBLIQ8jX8HfECAQCgUAcF38AwrhosQM5iFAAAAAldEVYdGRhdGU6Y3JlYXRlADIwMjEtMDgtMTNUMDQ6NDI6MzUrMDA6MDAUWYFrAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDIxLTA4LTEzVDA0OjQyOjM1KzAwOjAwZQQ51wAAAABJRU5ErkJggg==",F={},y=a('

题目

创建题目

拥有 PERM_CREATE_PROBLEM 的用户均可以新建题目。
请点击题库页面右下角的 创建题目 按钮。

Tips

题目 ID 不能全为数字。若留空则使用自动分配的数字题号。

',4),A=a(`

导入题目

从 Hydro 导入

上传 Hydro 导出的题目压缩包即可。

如果您的压缩包较大无法上传我们也提供cli导入方法:

hydrooj cli problem import <domainId> <file/path> # 将 <file(压缩文件)/path(解压后的文件夹)> 的Hydro格式题目包导入至 <domainId> 域中。
+

从 SYZOJ 导入

`,6),h={href:"https://github.com/hydro-dev/loj-download",target:"_blank",rel:"noopener noreferrer"},m=n("br",null,null,-1),u=n("h3",{id:"从-fps-文件导入",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#从-fps-文件导入","aria-hidden":"true"},"#"),s(" 从 FPS 文件导入")],-1),v=n("h3",{id:"从-qduoj-导入",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#从-qduoj-导入","aria-hidden":"true"},"#"),s(" 从 QDUOJ 导入")],-1),D=n("p",null,"见插件 import-qduoj。",-1),b=a('

编辑

题面

题面使用 Markdown 语法,并进行了部分扩展。

支持对样例数据分组显示:

```input1\n1 2\n```\n\n```output1\n3\n```

后接的数字为测试点编号,将自动合并,并左右分栏显示。

支持从附加文件引用资源。(您可以先创建题目,上传相关文件后再编辑该题目)

  • 附加文件下载链接: [file](file://input.in)
  • 从附加文件引用一张图片: ![img](file://foo.jpg)
  • 从附加文件引用 pdf 作为题面:@[pdf](file://foo.pdf) (部分情况下若无法使用,请尝试 @[pdf](file://foo.pdf?noDisposition=1)
  • 从附加文件引用 word 文档作为题面: @[doc](file://foo.docx) (依赖 onlyoffice 插件)
',8),C=a(`

题面支持合并表格:

| 1   | 1   | 3   | 4   | 5   |
+| --- | --- | --- | --- | --- |
+| 1   | 1   | 2   | 2   | 6   |
+| 1   | 1   | 2   | 2   | 7   |
+| 1   | 4   | 3   | 5   | 5   |
+

将被渲染为:

img

支持内嵌 HTML:(用来对付部分 Markdown 搞不定的东西)

<span bgcolor="red">foo</span>
+

标签

可点击右侧分类面板快速添加标签,也可以用英文半角逗号分隔多个标签。

文件

您可以在题目右侧“文件”面板上传测试数据和附加文件。(支持拖拽文件至相应位置进行上传)
测试数据格式

客观题

题面

1. 填空题
+
+1+1 = {{ input(1) }}
+
+2. 选择题
+
+{{ select(2) }}
+- 1+1=2
+- 1+1=3
+- 1+1=4
+
+3. 多选题
+
+{{ multiselect(3) }}
+- A
+- B
+- C
+

测试数据

仅需要配置 config.yaml 即可,不需要上传其他文件。

type: objective # 表明该题为客观题
+answers: # 列举出每一题的正确选项与对应的得分
+  '1': ['2', 50] # 填空题/选择题,单答案
+  '2': # 填空题/选择题,多答案,不同答案对应不同分数,注意空格缩进
+    'A': 30 # 也可以使用相同分数,即同时存在多个正确答案
+    'B': 10
+  '3': [['A', 'B'], 20] # 多选题答案为数组,有部分分
+
`,16);function f(B,x){const e=o("RouterLink"),i=o("ExternalLinkIcon");return d(),t("div",null,[y,n("p",null,[s("详见下方题面编辑部分,以及 "),l(e,{to:"/docs/user/problem-create.html"},{default:p(()=>[s("laomai 编写的说明")]),_:1})]),A,n("p",null,[s("Hydro 提供了一个小工具 "),n("a",h,[s("loj-download"),l(i)]),s(",可从基于原版 SYZOJ/SYZOJ-NG 搭建的源站下载到符合Hydro格式的题目压缩包。"),m,s(" 工具使用方法请前往使用教程查看,自行摸索并确保在网络通畅的环境下使用。")]),u,n("p",null,[s("见插件 "),l(e,{to:"/plugins/fps-importer/"},{default:p(()=>[s("fps-importer")]),_:1}),s("。")]),v,D,r(" TODO "),b,r(" TODO "),C])}const k=c(F,[["render",f],["__file","problem.html.vue"]]);export{k as default}; diff --git a/assets/problem.html-b71cd321.js b/assets/problem.html-b71cd321.js new file mode 100644 index 00000000..0580165e --- /dev/null +++ b/assets/problem.html-b71cd321.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-07f380c3","path":"/docs/user/problem.html","title":"题目","lang":"en-US","frontmatter":{"description":"创建题目 拥有 PERMCREATEPROBLEM 的用户均可以新建题目。 请点击题库页面右下角的 创建题目 按钮。 题目 ID 不能全为数字。若留空则使用自动分配的数字题号。 详见下方题面编辑部分,以及 laomai 编写的说明 (./problem-create.md) 导入题目 从 Hydro 导入 上传 Hydro 导出的题目压缩包即可。 如果...","head":[["meta",{"property":"og:url","content":"https://hydro.js.org/docs/user/problem.html"}],["meta",{"property":"og:site_name","content":"Hydro"}],["meta",{"property":"og:title","content":"题目"}],["meta",{"property":"og:description","content":"创建题目 拥有 PERMCREATEPROBLEM 的用户均可以新建题目。 请点击题库页面右下角的 创建题目 按钮。 题目 ID 不能全为数字。若留空则使用自动分配的数字题号。 详见下方题面编辑部分,以及 laomai 编写的说明 (./problem-create.md) 导入题目 从 Hydro 导入 上传 Hydro 导出的题目压缩包即可。 如果..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-05-12T03:18:30.000Z"}],["meta",{"property":"article:modified_time","content":"2023-05-12T03:18:30.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"题目\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-05-12T03:18:30.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"创建题目","slug":"创建题目","link":"#创建题目","children":[]},{"level":2,"title":"导入题目","slug":"导入题目","link":"#导入题目","children":[{"level":3,"title":"从 Hydro 导入","slug":"从-hydro-导入","link":"#从-hydro-导入","children":[]},{"level":3,"title":"从 SYZOJ 导入","slug":"从-syzoj-导入","link":"#从-syzoj-导入","children":[]},{"level":3,"title":"从 FPS 文件导入","slug":"从-fps-文件导入","link":"#从-fps-文件导入","children":[]},{"level":3,"title":"从 QDUOJ 导入","slug":"从-qduoj-导入","link":"#从-qduoj-导入","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":"题面-1","link":"#题面-1","children":[]},{"level":3,"title":"测试数据","slug":"测试数据","link":"#测试数据","children":[]}]}],"git":{"createdTime":1628828001000,"updatedTime":1683861510000,"contributors":[{"name":"undefined","email":"i@undefined.moe","commits":5},{"name":"Macesuted","email":"macesuted@qq.com","commits":4},{"name":"panda","email":"panda_dtdyy@outlook.com","commits":3}]},"readingTime":{"minutes":2.49,"words":746},"filePathRelative":"docs/user/problem.md","localizedDate":"August 13, 2021","autoDesc":true,"excerpt":""}');export{e as data}; diff --git a/assets/proxy.html-c1efacca.js b/assets/proxy.html-c1efacca.js new file mode 100644 index 00000000..bccd684a --- /dev/null +++ b/assets/proxy.html-c1efacca.js @@ -0,0 +1,22 @@ +import{_ as d}from"./plugin-vue_export-helper-c27b6911.js";import{r,o as i,c as o,a as s,b as e,d as a,e as l}from"./app-68b9e0b9.js";const c={},p=l('

反向代理 / SSL 配置

2022/10/27 后使用脚本安装的实例已自动配置 Caddy 反向代理,请直接编辑位于 ~/.hydro/Caddyfile 的配置文件!

Note

若使用反向代理,请注意系统设置中的 server.xff 和 server.xhost 设置项需要填写正确(小写),分别对应反向代理所添加的标头名(通常为 x-forwarded-for 和 x-forwarded-host,部分反代工具会使用 x-real-ip 替代 x-forwarded-for)。
server.xhost 设置项配置错误会导致用户无法登录等问题。(CsrfTokenError)
server.xff 设置项配置错误会导致无法记录用户IP。

除一键安装脚本在安装 Caddy 后会自动配置设置项,其他工具请在使用工具前先配置好系统设置!否则将造成用户无法登录、无法记录用户IP等问题。

若您使用 Nginx,请注意配置 WebSocket 协议的反向代理,否则会导致评测状态无法自动刷新,在线 IDE 无法正常使用等问题。

',3),t={href:"https://github.com/hydro-dev/Hydro/tree/master/examples/reverse_proxy",target:"_blank",rel:"noopener noreferrer"},f={href:"https://caddyserver.com/",target:"_blank",rel:"noopener noreferrer"},v=l(`
hydro.ac {
+  log {
+    output file /data/access.log {
+      roll_size 1gb
+      roll_keep_for 72h
+    }
+    format json
+  }
+  root * /root/.hydro/static
+  @static {
+    file {
+      try_files {path}
+    }
+  }
+  handle @static {
+    file_server
+  }
+  handle {
+    reverse_proxy http://127.0.0.1:8888
+  }
+}
+
`,1);function y(h,m){const n=r("ExternalLinkIcon");return i(),o("div",null,[p,s("p",null,[e("Hydro 支持使用 Caddy, HaProxy 等工具进行反向代理,"),s("a",t,[e("此处"),a(n)]),e(" 提供了一些配置样例。")]),s("p",null,[e("Hydro 推荐您使用 "),s("a",f,[e("Caddy"),a(n)]),e("。以下为样例 Caddyfile。 提示:如果您的服务器位于国内,则需要进行备案后才能使用 80 和 443 端口。")]),v])}const _=d(c,[["render",y],["__file","proxy.html.vue"]]);export{_ as default}; diff --git a/assets/proxy.html-f02dcebb.js b/assets/proxy.html-f02dcebb.js new file mode 100644 index 00000000..a0a4a84b --- /dev/null +++ b/assets/proxy.html-f02dcebb.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-4def954c","path":"/docs/install/proxy.html","title":"反向代理 / SSL 配置","lang":"en-US","frontmatter":{"description":"2022/10/27 后使用脚本安装的实例已自动配置 Caddy 反向代理,请直接编辑位于 ~/.hydro/Caddyfile 的配置文件! 若使用反向代理,请注意系统设置中的 server.xff 和 server.xhost 设置项需要填写正确(小写),分别对应反向代理所添加的标头名(通常为 x-forwarded-for 和 x-forward...","head":[["meta",{"property":"og:url","content":"https://hydro.js.org/docs/install/proxy.html"}],["meta",{"property":"og:site_name","content":"Hydro"}],["meta",{"property":"og:title","content":"反向代理 / SSL 配置"}],["meta",{"property":"og:description","content":"2022/10/27 后使用脚本安装的实例已自动配置 Caddy 反向代理,请直接编辑位于 ~/.hydro/Caddyfile 的配置文件! 若使用反向代理,请注意系统设置中的 server.xff 和 server.xhost 设置项需要填写正确(小写),分别对应反向代理所添加的标头名(通常为 x-forwarded-for 和 x-forward..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-08-23T08:55:42.000Z"}],["meta",{"property":"article:modified_time","content":"2023-08-23T08:55:42.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"反向代理 / SSL 配置\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-08-23T08:55:42.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":3,"title":"2022/10/27 后使用脚本安装的实例已自动配置 Caddy 反向代理,请直接编辑位于 ~/.hydro/Caddyfile 的配置文件!","slug":"_2022-10-27-后使用脚本安装的实例已自动配置-caddy-反向代理-请直接编辑位于-hydro-caddyfile-的配置文件","link":"#_2022-10-27-后使用脚本安装的实例已自动配置-caddy-反向代理-请直接编辑位于-hydro-caddyfile-的配置文件","children":[]}],"git":{"createdTime":1629032113000,"updatedTime":1692780942000,"contributors":[{"name":"undefined","email":"i@undefined.moe","commits":6},{"name":"Macesuted","email":"macesuted@qq.com","commits":2},{"name":"panda","email":"panda_dtdyy@outlook.com","commits":1}]},"readingTime":{"minutes":1.2,"words":359},"filePathRelative":"docs/install/proxy.md","localizedDate":"August 15, 2021","autoDesc":true,"excerpt":""}');export{e as data}; diff --git a/assets/recaptcha.html-1a8ae2a8.js b/assets/recaptcha.html-1a8ae2a8.js new file mode 100644 index 00000000..7807c0c2 --- /dev/null +++ b/assets/recaptcha.html-1a8ae2a8.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-fa72264c","path":"/plugins/recaptcha.html","title":"recaptcha","lang":"en-US","frontmatter":{"description":"我们采用 reCAPTCHA v3 来检验注册者是否是人类,在注册过程中没有看见传统验证码属正常现象。 前往 创建 reCAPTCHA 密钥。 reCAPTCHA 类型请选择“reCAPTCHA 第 3 版”。 创建成功后将客户端密钥和服务端密钥分别填入系统设置 recaptcha 栏下的 key 和 secret 中,重启 Hydro 后 reCAP...","head":[["meta",{"property":"og:url","content":"https://hydro.js.org/plugins/recaptcha.html"}],["meta",{"property":"og:site_name","content":"Hydro"}],["meta",{"property":"og:title","content":"recaptcha"}],["meta",{"property":"og:description","content":"我们采用 reCAPTCHA v3 来检验注册者是否是人类,在注册过程中没有看见传统验证码属正常现象。 前往 创建 reCAPTCHA 密钥。 reCAPTCHA 类型请选择“reCAPTCHA 第 3 版”。 创建成功后将客户端密钥和服务端密钥分别填入系统设置 recaptcha 栏下的 key 和 secret 中,重启 Hydro 后 reCAP..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2021-04-20T05:10:12.000Z"}],["meta",{"property":"article:modified_time","content":"2021-04-20T05:10:12.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"recaptcha\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2021-04-20T05:10:12.000Z\\",\\"author\\":[]}"]]},"headers":[],"git":{"createdTime":1618895412000,"updatedTime":1618895412000,"contributors":[{"name":"Macesuted","email":"57275149+Macesuted@users.noreply.github.com","commits":1}]},"readingTime":{"minutes":0.34,"words":102},"filePathRelative":"plugins/recaptcha.md","localizedDate":"April 20, 2021","autoDesc":true,"excerpt":""}');export{e as data}; diff --git a/assets/recaptcha.html-9f4fdce6.js b/assets/recaptcha.html-9f4fdce6.js new file mode 100644 index 00000000..c07bd85d --- /dev/null +++ b/assets/recaptcha.html-9f4fdce6.js @@ -0,0 +1 @@ +import{_ as a}from"./plugin-vue_export-helper-c27b6911.js";import{r,o as n,c as o,a as e,b as t,d as s}from"./app-68b9e0b9.js";const l={},i=e("h1",{id:"recaptcha",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#recaptcha","aria-hidden":"true"},"#"),t(" recaptcha")],-1),h=e("div",{class:"hint-container tip"},[e("p",{class:"hint-container-title"},"Tips"),e("p",null,"我们采用 reCAPTCHA v3 来检验注册者是否是人类,在注册过程中没有看见传统验证码属正常现象。")],-1),_={href:"https://www.google.com/recaptcha/admin/create",target:"_blank",rel:"noopener noreferrer"},d=e("br",null,null,-1),p=e("p",null,[t("创建成功后将客户端密钥和服务端密钥分别填入系统设置 recaptcha 栏下的 "),e("code",null,"key"),t(" 和 "),e("code",null,"secret"),t(" 中,重启 Hydro 后 reCAPTCHA 即可正常工作。")],-1);function m(u,f){const c=r("ExternalLinkIcon");return n(),o("div",null,[i,h,e("p",null,[t("前往 "),e("a",_,[t("https://www.google.com/recaptcha/admin/create"),s(c)]),t(" 创建 reCAPTCHA 密钥。"),d,t(" reCAPTCHA 类型请选择“reCAPTCHA 第 3 版”。")]),p])}const x=a(l,[["render",m],["__file","recaptcha.html.vue"]]);export{x as default}; diff --git a/assets/s3.html-96da8c94.js b/assets/s3.html-96da8c94.js new file mode 100644 index 00000000..ca72799c --- /dev/null +++ b/assets/s3.html-96da8c94.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-6b4a62ea","path":"/docs/install/s3.html","title":"存储","lang":"en-US","frontmatter":{"description":"使用一键安装脚本部署的 Hydro 一般已自动完成存储配置。 文件默认存储于本地的 /data/file/hydro 目录下,切换存储后端时需要手动复制或移动原有文件。 请根据你使用的存储端类型阅读对应教程。(同时欢迎使用其他存储类型的用户向我们提供详细的存储教程) MinIO 新版本 MinIO 占用较大,如果您为轻量使用,我们不建议使用 MinIO...","head":[["meta",{"property":"og:url","content":"https://hydro.js.org/docs/install/s3.html"}],["meta",{"property":"og:site_name","content":"Hydro"}],["meta",{"property":"og:title","content":"存储"}],["meta",{"property":"og:description","content":"使用一键安装脚本部署的 Hydro 一般已自动完成存储配置。 文件默认存储于本地的 /data/file/hydro 目录下,切换存储后端时需要手动复制或移动原有文件。 请根据你使用的存储端类型阅读对应教程。(同时欢迎使用其他存储类型的用户向我们提供详细的存储教程) MinIO 新版本 MinIO 占用较大,如果您为轻量使用,我们不建议使用 MinIO..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-05-12T03:32:53.000Z"}],["meta",{"property":"article:modified_time","content":"2023-05-12T03:32:53.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"存储\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-05-12T03:32:53.000Z\\",\\"author\\":[]}"]]},"headers":[],"git":{"createdTime":1631714121000,"updatedTime":1683862373000,"contributors":[{"name":"Macesuted","email":"macesuted@qq.com","commits":5},{"name":"undefined","email":"i@undefined.moe","commits":3},{"name":"panda","email":"panda_dtdyy@outlook.com","commits":2}]},"readingTime":{"minutes":1.18,"words":355},"filePathRelative":"docs/install/s3.md","localizedDate":"September 15, 2021","autoDesc":true,"excerpt":""}');export{e as data}; diff --git a/assets/s3.html-f0df93b5.js b/assets/s3.html-f0df93b5.js new file mode 100644 index 00000000..60f31037 --- /dev/null +++ b/assets/s3.html-f0df93b5.js @@ -0,0 +1 @@ +import{_ as d}from"./plugin-vue_export-helper-c27b6911.js";import{r as t,o as l,c as n,a as e,b as o,d as r,e as i}from"./app-68b9e0b9.js";const s={},a=i('

存储

Tips

使用一键安装脚本部署的 Hydro 一般已自动完成存储配置。

文件默认存储于本地的 /data/file/hydro 目录下,切换存储后端时需要手动复制或移动原有文件。
请根据你使用的存储端类型阅读对应教程。(同时欢迎使用其他存储类型的用户向我们提供详细的存储教程)

MinIO

Note

新版本 MinIO 占用较大,如果您为轻量使用,我们不建议使用 MinIO 。旧版本 Hydro 用户大部分可直接切换至 file 模式,由 Hydro 代替读取。

',5),p={href:"https://min.io/",target:"_blank",rel:"noopener noreferrer"},f=i("
  • file.type: s3
  • file.endPointhttp://127.0.0.1:9000(即 MinIO 启动时显示的 endPoint)
  • file.accessKey: 参照 MinIO 配置
  • file.secretKey: 参照 MinIO 配置
  • file.buckethydro(MinIO 内部存储桶名称)
  • file.regionus-east-1
  • file.pathStyle: true
  • file.endPointForUser/fs/
  • file.endPointForJudge/fs/

保存后重启,已有文件请自行复制。

腾讯云COS

进入 控制面板>系统设置>存储桶设置。

  • file.type: s3
  • file.endPointhttp://cos.<存储桶地域>.myqcloud.com (或是 https)
  • file.accessKey: 您的腾讯云 API 密钥的 SecretId
  • file.secretKey: 您的腾讯云 API 密钥的 SecretKey
  • file.bucket: <存储桶名称>
  • file.region: Auto
  • file.pathStyle: true
  • file.endPointForUser: 给用户使用的 EndPoint,若填 /fs/ 则表示由服务器转发
  • file.endPointForJudge: 给 judge 使用的 EndPoint,若填 /fs/ 则表示由服务器转发

保存后重启,已有文件请自行复制。

阿里云OSS

// TODO & PRs Welcome

",8);function h(_,u){const c=t("ExternalLinkIcon");return l(),n("div",null,[a,e("p",null,[e("a",p,[o("安装 MinIO"),r(c)]),o(" 后进入 控制面板>manage_config。")]),f])}const y=d(s,[["render",h],["__file","s3.html.vue"]]);export{y as default}; diff --git a/assets/smtp.html-1fbd4657.js b/assets/smtp.html-1fbd4657.js new file mode 100644 index 00000000..f4cfdd50 --- /dev/null +++ b/assets/smtp.html-1fbd4657.js @@ -0,0 +1 @@ +import{_ as l}from"./plugin-vue_export-helper-c27b6911.js";import{o as i,c as e,e as t}from"./app-68b9e0b9.js";const o={},a=t('

SMTP

以 QQ 邮箱为例。

  • SMTP_USER: 12345678@qq.com
  • SMTP_PASS: 提供的 SMTP 密码
  • SMTP_HOST: smtp.qq.com
  • SMTP_PORT: 465/587 (请参照邮件服务商说明)
  • SMTP_SECURE: 是否使用加密 TLS 连接(请参照邮件服务商说明,使用 STARTTLS 的服务商无需勾选)
  • SMTP_FROM: 发送签名(提示:若不清楚请填写邮件地址,填错会导致邮件无法发送)

已知能够完整兼容的服务商有:

  • QQ 邮箱
  • 腾讯企业邮
  • 网易 163 邮箱
  • 飞书域名邮箱
  • Zeptomail
  • Zoho Mail
  • Outlook
  • Gmail

如果使用其他服务商且没有发现问题,欢迎向此列表 Pull Request。

',6),s=[a];function _(c,r){return i(),e("div",null,s)}const S=l(o,[["render",_],["__file","smtp.html.vue"]]);export{S as default}; diff --git a/assets/smtp.html-b6526407.js b/assets/smtp.html-b6526407.js new file mode 100644 index 00000000..a948c03f --- /dev/null +++ b/assets/smtp.html-b6526407.js @@ -0,0 +1 @@ +const t=JSON.parse('{"key":"v-68002798","path":"/docs/install/smtp.html","title":"SMTP","lang":"en-US","frontmatter":{"description":"以 QQ 邮箱为例。 SMTP_USER: 12345678@qq.com ; SMTP_PASS: 提供的 SMTP 密码 ; SMTP_HOST: smtp.qq.com ; SMTP_PORT: 465/587 (请参照邮件服务商说明) ; SMTP_SECURE: 是否使用加密 TLS 连接(请参照邮件服务商说明,使用 STARTTLS 的服务...","head":[["meta",{"property":"og:url","content":"https://hydro.js.org/docs/install/smtp.html"}],["meta",{"property":"og:site_name","content":"Hydro"}],["meta",{"property":"og:title","content":"SMTP"}],["meta",{"property":"og:description","content":"以 QQ 邮箱为例。 SMTP_USER: 12345678@qq.com ; SMTP_PASS: 提供的 SMTP 密码 ; SMTP_HOST: smtp.qq.com ; SMTP_PORT: 465/587 (请参照邮件服务商说明) ; SMTP_SECURE: 是否使用加密 TLS 连接(请参照邮件服务商说明,使用 STARTTLS 的服务..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2022-12-09T10:31:58.000Z"}],["meta",{"property":"article:modified_time","content":"2022-12-09T10:31:58.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"SMTP\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2022-12-09T10:31:58.000Z\\",\\"author\\":[]}"]]},"headers":[],"git":{"createdTime":1631785934000,"updatedTime":1670581918000,"contributors":[{"name":"undefined","email":"i@undefined.moe","commits":2},{"name":"Macesuted","email":"macesuted@qq.com","commits":1}]},"readingTime":{"minutes":0.5,"words":151},"filePathRelative":"docs/install/smtp.md","localizedDate":"September 16, 2021","autoDesc":true,"excerpt":""}');export{t as data}; diff --git a/assets/sonic.html-03c2bb5e.js b/assets/sonic.html-03c2bb5e.js new file mode 100644 index 00000000..688b98c4 --- /dev/null +++ b/assets/sonic.html-03c2bb5e.js @@ -0,0 +1,72 @@ +import{_ as a}from"./plugin-vue_export-helper-c27b6911.js";import{r as l,o as i,c as d,a as s,b as n,d as p,e as c}from"./app-68b9e0b9.js";const o={},r=s("h1",{id:"sonic",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#sonic","aria-hidden":"true"},"#"),n(" Sonic")],-1),t=s("h2",{id:"安装",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#安装","aria-hidden":"true"},"#"),n(" 安装")],-1),f={id:"安装-sonic-server",tabindex:"-1"},v=s("a",{class:"header-anchor",href:"#安装-sonic-server","aria-hidden":"true"},"#",-1),u={href:"https://github.com/valeriansaliou/sonic",target:"_blank",rel:"noopener noreferrer"},m=c(`

使用 root 用户执行如下命令:

nix-env -iA nixpkgs.sonic-server
+

安装 sonic 插件

使用 root 用户执行如下命令:

yarn global add @hydrooj/sonic
+hydrooj addon add @hydrooj/sonic
+

启动

/root/.sonic/config.cfg(没有的自行建立,也可以换成其他的你喜欢的路径)按照以下配置示例写入配置。

配置示例:

# Sonic
+# Fast, lightweight and schema-less search backend
+# Configuration file
+# Example: https://github.com/valeriansaliou/sonic/blob/master/config.cfg
+
+
+[server]
+
+log_level = "error"
+
+
+[channel]
+
+inet = "127.0.0.1:1491" # 默认监听本机
+tcp_timeout = 300
+
+auth_password = "SecretPassword"
+
+[channel.search]
+
+query_limit_default = 10
+query_limit_maximum = 100
+query_alternates_try = 4
+
+suggest_limit_default = 5
+suggest_limit_maximum = 20
+
+
+[store]
+
+[store.kv]
+
+path = "/data/sonic/store/kv/"
+
+retain_word_objects = 1000
+
+[store.kv.pool]
+
+inactive_after = 1800
+
+[store.kv.database]
+
+flush_after = 900
+
+compress = true
+parallelism = 2
+max_files = 100
+max_compactions = 1
+max_flushes = 1
+write_buffer = 16384
+write_ahead_log = true
+
+[store.fst]
+
+path = "/data/sonic/store/fst/"
+
+[store.fst.pool]
+
+inactive_after = 300
+
+[store.fst.graph]
+
+consolidate_after = 180
+
+max_size = 2048
+max_words = 250000
+

执行如下命令:

pm2 start sonic -- -c /root/.sonic/config.cfg
+pm2 save
+

配置

后端地址配置

进入 HydroOJ 控制面板,配置 sonic 后端地址。

如果您直接复制配置示例,那么按照以下内容配置:

  • host: 127.0.0.1
  • port: 1491
  • auth: SecretPassword

修改完成后,重启 HydroOJ。

重启 HydroOJ

执行命令 pm2 restart hydrooj

重建题目索引

进入 HydroOJ 控制面板,在脚本管理中找到重建题目索引,点击运行,参数留空即可。

至此,搜索功能应当可以正常使用。

FAQ

安装后题目搜索不正常

请更新到 HydroOJ 最新版本后,再运行重建题目索引。

`,25);function b(h,y){const e=l("ExternalLinkIcon");return i(),d("div",null,[r,t,s("h3",f,[v,n(" 安装 "),s("a",u,[n("sonic-server"),p(e)])]),m])}const g=a(o,[["render",b],["__file","sonic.html.vue"]]);export{g as default}; diff --git a/assets/sonic.html-334946eb.js b/assets/sonic.html-334946eb.js new file mode 100644 index 00000000..98b53049 --- /dev/null +++ b/assets/sonic.html-334946eb.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-52692a96","path":"/plugins/sonic.html","title":"Sonic","lang":"en-US","frontmatter":{"description":"安装 安装 sonic-server (https://github.com/valeriansaliou/sonic) 使用 root 用户执行如下命令: 安装 sonic 插件 使用 root 用户执行如下命令: 启动 在 /root/.sonic/config.cfg(没有的自行建立,也可以换成其他的你喜欢的路径)按照以下配置示例写入配置。 配置...","head":[["meta",{"property":"og:url","content":"https://hydro.js.org/plugins/sonic.html"}],["meta",{"property":"og:site_name","content":"Hydro"}],["meta",{"property":"og:title","content":"Sonic"}],["meta",{"property":"og:description","content":"安装 安装 sonic-server (https://github.com/valeriansaliou/sonic) 使用 root 用户执行如下命令: 安装 sonic 插件 使用 root 用户执行如下命令: 启动 在 /root/.sonic/config.cfg(没有的自行建立,也可以换成其他的你喜欢的路径)按照以下配置示例写入配置。 配置..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-02-25T05:29:05.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-25T05:29:05.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Sonic\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-25T05:29:05.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"安装","slug":"安装","link":"#安装","children":[{"level":3,"title":"安装 sonic-server","slug":"安装-sonic-server","link":"#安装-sonic-server","children":[]},{"level":3,"title":"安装 sonic 插件","slug":"安装-sonic-插件","link":"#安装-sonic-插件","children":[]}]},{"level":2,"title":"启动","slug":"启动","link":"#启动","children":[]},{"level":2,"title":"配置","slug":"配置","link":"#配置","children":[{"level":3,"title":"后端地址配置","slug":"后端地址配置","link":"#后端地址配置","children":[]},{"level":3,"title":"重启 HydroOJ","slug":"重启-hydrooj","link":"#重启-hydrooj","children":[]},{"level":3,"title":"重建题目索引","slug":"重建题目索引","link":"#重建题目索引","children":[]}]},{"level":2,"title":"FAQ","slug":"faq","link":"#faq","children":[{"level":3,"title":"安装后题目搜索不正常","slug":"安装后题目搜索不正常","link":"#安装后题目搜索不正常","children":[]}]}],"git":{"createdTime":1621263423000,"updatedTime":1677302945000,"contributors":[{"name":"panda","email":"panda_dtdyy@outlook.com","commits":2},{"name":"undefined","email":"i@undefined.moe","commits":2},{"name":"立言","email":"liyanqwq@duianit.cn","commits":2}]},"readingTime":{"minutes":1.11,"words":333},"filePathRelative":"plugins/sonic.md","localizedDate":"May 17, 2021","autoDesc":true,"excerpt":""}');export{e as data}; diff --git a/assets/style-3c7defdd.css b/assets/style-3c7defdd.css new file mode 100644 index 00000000..157224cc --- /dev/null +++ b/assets/style-3c7defdd.css @@ -0,0 +1 @@ +html[data-theme=dark]{--text-color: #9e9e9e;--bg-color: #0d1117;--bg-color-secondary: #161b22;--bg-color-tertiary: #21262c;--border-color: #30363d;--box-shadow: #282a32;--card-shadow: rgba(0, 0, 0, .3);--black: #fff;--dark-grey: #999;--light-grey: #666;--white: #000;--grey3: #bbb;--grey12: #333;--grey14: #111;--bg-color-light: #161b22;--bg-color-back: #0d1117;--bg-color-float: #161b22;--bg-color-blur: rgba(13, 17, 23, .9);--bg-color-float-blur: rgba(22, 27, 34, .9);--text-color-light: #a8a8a8;--text-color-lighter: #b1b1b1;--text-color-bright: #c5c5c5;--border-color-light: #2e333a;--border-color-dark: #394048}:root{--theme-color: #3eaf7c;--text-color: #2c3e50;--bg-color: #fff;--bg-color-secondary: #f8f8f8;--bg-color-tertiary: #efeef4;--border-color: #eaecef;--box-shadow: #f0f1f2;--card-shadow: rgba(0, 0, 0, .15);--black: #000;--dark-grey: #666;--light-grey: #999;--white: #fff;--grey3: #333;--grey12: #bbb;--grey14: #eee;--navbar-height: 3.75rem;--navbar-horizontal-padding: 1.5rem;--navbar-vertical-padding: .7rem;--navbar-mobile-height: 3.25rem;--navbar-mobile-horizontal-padding: 1rem;--navbar-mobile-vertical-padding: .5rem;--sidebar-width: 18rem;--sidebar-mobile-width: 16rem;--content-width: 780px;--home-page-width: 1160px;--font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", STHeiti, "Microsoft YaHei", SimSun, sans-serif;--font-family-heading: Georgia Pro, Crimson, Georgia, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", STHeiti, "Microsoft YaHei", SimSun, sans-serif;--font-family-mono: Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace;--line-numbers-width: 2.5rem;--color-transition: .3s ease;--transform-transition: .3s ease;--vp-bg: var(--bg-color);--vp-bgl: var(--bg-color-light);--vp-bglt: var(--bg-color-tertiary);--vp-c: var(--text-color);--vp-cl: var(--text-color-light);--vp-clt: var(--text-color-lighter);--vp-brc: var(--border-color);--vp-brcd: var(--border-color-dark);--vp-tc: var(--theme-color);--vp-tcl: var(--theme-color-light);--vp-ct: var(--color-transition);--vp-tt: var(--transform-transition);--bg-color-light: #fff;--bg-color-back: #f8f8f8;--bg-color-float: #fff;--bg-color-blur: rgba(255, 255, 255, .9);--bg-color-float-blur: rgba(255, 255, 255, .9);--text-color-light: #3a5169;--text-color-lighter: #476582;--text-color-bright: #6a8bad;--border-color-light: #eceef1;--border-color-dark: #cfd4db;--theme-color-dark: #389e70;--theme-color-light: #4abf8a;--theme-color-mask: rgba(62, 175, 124, .15)}:root{--badge-tip-color: #42b983;--badge-warning-color: #f4cd00;--badge-danger-color: #f55;--badge-info-color: #0295ff;--badge-note-color: #666}.badge{display:inline-block;vertical-align:top;height:18px;padding:0 6px;border-radius:3px;background:var(--vp-tc);color:var(--white);font-size:14px;line-height:18px;transition:background var(--vp-ct),color var(--vp-ct)}.badge+.badge{-webkit-margin-start:5px;margin-inline-start:5px}.table-of-contents .badge,#toc .badge{vertical-align:middle}.badge.tip{background:var(--badge-tip-color)}.badge.warning{background:var(--badge-warning-color)}.badge.danger{background:var(--badge-danger-color)}.badge.info{background:var(--badge-info-color)}.badge.note{background:var(--badge-note-color)}.font-icon{display:inline-block}.theme-hope-content .font-icon{vertical-align:middle}:root{--balloon-border-radius: 2px;--balloon-color: rgba(16, 16, 16, .95);--balloon-text-color: #fff;--balloon-font-size: 12px;--balloon-move: 4px}button[aria-label][data-balloon-pos]{overflow:visible}[aria-label][data-balloon-pos]{position:relative;cursor:pointer}[aria-label][data-balloon-pos]:after{opacity:0;pointer-events:none;transition:all .18s ease-out .18s;text-indent:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Open Sans,Helvetica Neue,sans-serif;font-weight:400;font-style:normal;text-shadow:none;font-size:var(--balloon-font-size);background:var(--balloon-color);border-radius:2px;color:var(--balloon-text-color);border-radius:var(--balloon-border-radius);content:attr(aria-label);padding:.5em 1em;position:absolute;white-space:nowrap;z-index:10}[aria-label][data-balloon-pos]:before{width:0;height:0;border:5px solid transparent;border-top-color:var(--balloon-color);opacity:0;pointer-events:none;transition:all .18s ease-out .18s;content:"";position:absolute;z-index:10}[aria-label][data-balloon-pos]:hover:before,[aria-label][data-balloon-pos]:hover:after,[aria-label][data-balloon-pos][data-balloon-visible]:before,[aria-label][data-balloon-pos][data-balloon-visible]:after,[aria-label][data-balloon-pos]:not([data-balloon-nofocus]):focus:before,[aria-label][data-balloon-pos]:not([data-balloon-nofocus]):focus:after{opacity:1;pointer-events:none}[aria-label][data-balloon-pos].font-awesome:after{font-family:FontAwesome,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Open Sans,Helvetica Neue,sans-serif}[aria-label][data-balloon-pos][data-balloon-break]:after{white-space:pre}[aria-label][data-balloon-pos][data-balloon-break][data-balloon-length]:after{white-space:pre-line;word-break:break-word}[aria-label][data-balloon-pos][data-balloon-blunt]:before,[aria-label][data-balloon-pos][data-balloon-blunt]:after{transition:none}[aria-label][data-balloon-pos][data-balloon-pos=up]:hover:after,[aria-label][data-balloon-pos][data-balloon-pos=up][data-balloon-visible]:after,[aria-label][data-balloon-pos][data-balloon-pos=down]:hover:after,[aria-label][data-balloon-pos][data-balloon-pos=down][data-balloon-visible]:after{transform:translate(-50%)}[aria-label][data-balloon-pos][data-balloon-pos=up]:hover:before,[aria-label][data-balloon-pos][data-balloon-pos=up][data-balloon-visible]:before,[aria-label][data-balloon-pos][data-balloon-pos=down]:hover:before,[aria-label][data-balloon-pos][data-balloon-pos=down][data-balloon-visible]:before{transform:translate(-50%)}[aria-label][data-balloon-pos][data-balloon-pos*=-left]:after{left:0}[aria-label][data-balloon-pos][data-balloon-pos*=-left]:before{left:5px}[aria-label][data-balloon-pos][data-balloon-pos*=-right]:after{right:0}[aria-label][data-balloon-pos][data-balloon-pos*=-right]:before{right:5px}[aria-label][data-balloon-pos][data-balloon-po*=-left]:hover:after,[aria-label][data-balloon-pos][data-balloon-po*=-left][data-balloon-visible]:after,[aria-label][data-balloon-pos][data-balloon-pos*=-right]:hover:after,[aria-label][data-balloon-pos][data-balloon-pos*=-right][data-balloon-visible]:after{transform:translate(0)}[aria-label][data-balloon-pos][data-balloon-po*=-left]:hover:before,[aria-label][data-balloon-pos][data-balloon-po*=-left][data-balloon-visible]:before,[aria-label][data-balloon-pos][data-balloon-pos*=-right]:hover:before,[aria-label][data-balloon-pos][data-balloon-pos*=-right][data-balloon-visible]:before{transform:translate(0)}[aria-label][data-balloon-pos][data-balloon-pos^=up]:before,[aria-label][data-balloon-pos][data-balloon-pos^=up]:after{bottom:100%;transform-origin:top;transform:translateY(var(--balloon-move))}[aria-label][data-balloon-pos][data-balloon-pos^=up]:after{margin-bottom:10px}[aria-label][data-balloon-pos][data-balloon-pos=up]:before,[aria-label][data-balloon-pos][data-balloon-pos=up]:after{left:50%;transform:translate(-50%,var(--balloon-move))}[aria-label][data-balloon-pos][data-balloon-pos^=down]:before,[aria-label][data-balloon-pos][data-balloon-pos^=down]:after{top:100%;transform:translateY(calc(var(--balloon-move) * -1))}[aria-label][data-balloon-pos][data-balloon-pos^=down]:after{margin-top:10px}[aria-label][data-balloon-pos][data-balloon-pos^=down]:before{width:0;height:0;border:5px solid transparent;border-bottom-color:var(--balloon-color)}[aria-label][data-balloon-pos][data-balloon-pos=down]:after,[aria-label][data-balloon-pos][data-balloon-pos=down]:before{left:50%;transform:translate(-50%,calc(var(--balloon-move) * -1))}[aria-label][data-balloon-pos][data-balloon-pos=left]:hover:after,[aria-label][data-balloon-pos][data-balloon-pos=left][data-balloon-visible]:after,[aria-label][data-balloon-pos][data-balloon-pos=right]:hover:after,[aria-label][data-balloon-pos][data-balloon-pos=right][data-balloon-visible]:after{transform:translateY(-50%)}[aria-label][data-balloon-pos][data-balloon-pos=left]:hover:before,[aria-label][data-balloon-pos][data-balloon-pos=left][data-balloon-visible]:before,[aria-label][data-balloon-pos][data-balloon-pos=right]:hover:before,[aria-label][data-balloon-pos][data-balloon-pos=right][data-balloon-visible]:before{transform:translateY(-50%)}[aria-label][data-balloon-pos][data-balloon-pos=left]:after,[aria-label][data-balloon-pos][data-balloon-pos=left]:before{right:100%;top:50%;transform:translate(var(--balloon-move),-50%)}[aria-label][data-balloon-pos][data-balloon-pos=left]:after{margin-right:10px}[aria-label][data-balloon-pos][data-balloon-pos=left]:before{width:0;height:0;border:5px solid transparent;border-left-color:var(--balloon-color)}[aria-label][data-balloon-pos][data-balloon-pos=right]:after,[aria-label][data-balloon-pos][data-balloon-pos=right]:before{left:100%;top:50%;transform:translate(calc(var(--balloon-move) * -1),-50%)}[aria-label][data-balloon-pos][data-balloon-pos=right]:after{margin-left:10px}[aria-label][data-balloon-pos][data-balloon-pos=right]:before{width:0;height:0;border:5px solid transparent;border-right-color:var(--balloon-color)}[aria-label][data-balloon-pos][data-balloon-length]:after{white-space:normal}[aria-label][data-balloon-pos][data-balloon-length=small]:after{width:80px}[aria-label][data-balloon-pos][data-balloon-length=medium]:after{width:150px}[aria-label][data-balloon-pos][data-balloon-length=large]:after{width:260px}[aria-label][data-balloon-pos][data-balloon-length=xlarge]:after{width:380px}@media screen and (max-width: 768px){[aria-label][data-balloon-pos][data-balloon-length=xlarge]:after{width:90vw}}[aria-label][data-balloon-pos][data-balloon-length=fit]:after{width:100%}.back-to-top{border-width:0;background:transparent;cursor:pointer;position:fixed!important;right:16px;bottom:64px;z-index:100;width:48px;height:48px;padding:8px;border-radius:50%;background:var(--vp-bg);color:var(--vp-tc);box-shadow:2px 2px 10px 4px var(--card-shadow);transition:background var(--vp-ct),color var(--vp-ct),box-shadow var(--vp-ct)}@media (max-width: 719px){.back-to-top{width:36px;height:36px}}@media print{.back-to-top{display:none}}html[dir=rtl] .back-to-top{right:unset;left:16px}.back-to-top:hover{color:var(--vp-tcl)}.back-to-top .back-to-top-icon{overflow:hidden;width:100%;border-radius:50%;fill:currentcolor}.scroll-progress{position:absolute;right:-2px;bottom:-2px;width:52px;height:52px}@media (max-width: 719px){.scroll-progress{width:40px;height:40px}}.scroll-progress circle{opacity:.9;fill:none;stroke:var(--vp-tc);transform:rotate(-90deg);transform-origin:50% 50%;r:22;stroke-dasharray:0% 314.1593%;stroke-width:3px}@media (max-width: 719px){.scroll-progress circle{r:18}}.fade-enter-active,.fade-leave-active{transition:opacity var(--vp-ct)}.fade-enter-from,.fade-leave-to{opacity:0}@media screen{.sr-only{position:absolute;overflow:hidden;clip:rect 0,0,0,0;width:1px;height:1px;margin:-1px;padding:0;border:0}}@media print{.sr-only{display:none}}.auto-catalog-wrapper{margin-top:8px;margin-bottom:8px}.auto-catalog-wrapper .catalog-title{color:inherit;text-decoration:none}.auto-catalog-wrapper .catalog-title:hover{color:var(--vp-tc)}.auto-catalog-wrapper .main-title{font-size:1.75rem}.auto-catalog-wrapper .child-title{font-size:1.3rem}.auto-catalog-wrapper .child-title.has-children{border-bottom:1px solid var(--vp-brc);transition:border-color var(--vp-ct)}.auto-catalog-wrapper .sub-title{color:var(--vp-clt);font-size:1.1rem}.auto-catalog-wrapper .main-title,.auto-catalog-wrapper .child-title,.auto-catalog-wrapper .sub-title{margin-top:calc(.5rem - var(--navbar-height, 3.6rem));margin-bottom:.5rem;padding-top:var(--navbar-height, 3.6rem);font-weight:500}.auto-catalog-wrapper .main-title:first-child,.auto-catalog-wrapper .child-title:first-child,.auto-catalog-wrapper .sub-title:first-child{margin-bottom:.5rem}.auto-catalog-wrapper .font-icon{vertical-align:baseline;-webkit-margin-end:.25rem;margin-inline-end:.25rem}.auto-catalog-wrapper .child-catalog-wrapper{margin:0}.auto-catalog-wrapper .child-catalog-item::marker{color:var(--vp-clt)}.auto-catalog-wrapper .sub-catalog-wrapper{display:flex;flex-wrap:wrap}.auto-catalog-wrapper .sub-catalog-item{display:inline-block;margin:4px 8px;padding:4px 8px;border-radius:6px;background-color:var(--vp-bgl);line-height:1.5;overflow-wrap:break-word;transition:background-color var(--vp-ct),color var(--vp-ct)}.auto-catalog-wrapper .sub-catalog-item:hover{background-color:var(--vp-tcl);color:var(--vp-bg);text-decoration:none}:root{--external-link-icon-color: #aaa}.external-link-icon{position:relative;display:inline-block;color:var(--external-link-icon-color);vertical-align:middle;top:-1px}@media print{.external-link-icon{display:none}}.external-link-icon-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0;-webkit-user-select:none;-moz-user-select:none;user-select:none}:root{--nprogress-color: #29d;--nprogress-z-index: 1031}#nprogress{pointer-events:none}#nprogress .bar{background:var(--nprogress-color);position:fixed;z-index:var(--nprogress-z-index);top:0;left:0;width:100%;height:2px}:root{--copy-icon: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' height='20' width='20' stroke='rgba(128,128,128,1)' stroke-width='2'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' d='M9 5H7a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-2M9 5a2 2 0 0 0 2 2h2a2 2 0 0 0 2-2M9 5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2'/%3E%3C/svg%3E");--copied-icon: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' height='20' width='20' stroke='rgba(128,128,128,1)' stroke-width='2'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' d='M9 5H7a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-2M9 5a2 2 0 0 0 2 2h2a2 2 0 0 0 2-2M9 5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2m-6 9 2 2 4-4'/%3E%3C/svg%3E")}div[class*=language-]>button.copy-code-button{border-width:0;background:transparent;position:absolute;outline:none;cursor:pointer}@media print{div[class*=language-]>button.copy-code-button{display:none}}div[class*=language-]>button.copy-code-button .copy-icon{background:currentcolor;-webkit-mask-image:var(--copy-icon);mask-image:var(--copy-icon);-webkit-mask-position:50%;mask-position:50%;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:1em;mask-size:1em}div[class*=language-]>button.copy-code-button:not(.fancy){border-width:0;background:transparent;cursor:pointer;position:absolute;top:0;right:3em;z-index:5;width:2.5rem;height:2.5rem;padding:0;border-radius:.5rem;opacity:0;transition:opacity .4s}div[class*=language-]>button.copy-code-button:not(.fancy):hover{background:var(--code-hl-bg-color, rgba(0, 0, 0, .66))}div[class*=language-]>button.copy-code-button:not(.fancy).copied:after{content:attr(data-copied);position:absolute;top:0;right:100%;display:block;height:1.25rem;padding:.625rem;border-radius:.5rem;background:var(--code-hl-bg-color, rgba(0, 0, 0, .66));color:var(--code-ln-color, #9e9e9e);font-weight:500;line-height:1.25rem;white-space:nowrap}div[class*=language-]>button.copy-code-button:not(.fancy) .copy-icon{width:1.25rem;height:1.25rem;padding:.625rem;color:var(--code-ln-color, #9e9e9e);font-size:1.25rem}div[class*=language-]>button.copy-code-button.fancy{right:-14px;bottom:-14px;z-index:5;width:2rem;height:2rem;padding:7px 8px;border-radius:50%;background:#339af0;color:#fff}@media (max-width: 419px){div[class*=language-]>button.copy-code-button.fancy{right:0;bottom:0;width:28px;height:28px;border-radius:50% 10% 0}}div[class*=language-]>button.copy-code-button.fancy:hover{background:#228be6}div[class*=language-]>button.copy-code-button.fancy .copy-icon{width:100%;height:100%;color:#fff;font-size:1.25rem}@media (max-width: 419px){div[class*=language-]>button.copy-code-button.fancy .copy-icon{position:relative;top:2px;left:2px}}div[class*=language-]>button.copy-code-button.copied .copy-icon{-webkit-mask-image:var(--copied-icon);mask-image:var(--copied-icon)}div[class*=language-]:hover>button.copy-code-button:not(.fancy),div[class*=language-]>button.copy-code-button:not(.fancy):focus{opacity:1}:root{--info-title-color: #193c47;--info-bg-color: #eef9fd;--info-border-color: #4cb3d4;--info-code-bg-color: rgb(76 179 212 / 10%);--note-title-color: #474748;--note-bg-color: #fdfdfe;--note-border-color: #ccc;--note-code-bg-color: rgb(212 213 216 / 20%);--tip-title-color: #003100;--tip-bg-color: #e6f6e6;--tip-border-color: #009400;--tip-code-bg-color: rgb(0 148 0 / 15%);--warning-title-color: #4d3800;--warning-bg-color: #fff8e6;--warning-border-color: #e6a700;--warning-code-bg-color: rgb(230 167 0 / 15%);--danger-title-color: #4b1113;--danger-bg-color: #ffebec;--danger-border-color: #e13238;--danger-code-bg-color: rgb(225 50 56 / 15%);--detail-bg-color: #eee;--detail-text-color: inherit;--detail-code-bg-color: rgb(127 127 127 / 15%)}html[data-theme=dark]{--info-title-color: #eef9fd;--info-bg-color: #193c47;--note-title-color: #fdfdfe;--note-bg-color: #474748;--tip-title-color: #e6f6e6;--tip-bg-color: #003100;--warning-title-color: #fff8e6;--warning-bg-color: #4d3800;--danger-title-color: #ffebec;--danger-bg-color: #4b1113;--detail-bg-color: #333;--detail-text-color: #a8a8a8}.hint-container{position:relative;transition:background var(--vp-ct),border-color var(--vp-ct),color var(--vp-ct)}@media print{.hint-container{page-break-inside:avoid}}.hint-container .hint-container-title{position:relative;font-weight:600;line-height:1.25}.hint-container.info,.hint-container.note,.hint-container.tip,.hint-container.warning,.hint-container.danger{margin:1rem 0;padding:.25rem 1rem;border-inline-start-width:.3rem;border-inline-start-style:solid;border-radius:.5rem;color:inherit}.hint-container.info .hint-container-title,.hint-container.note .hint-container-title,.hint-container.tip .hint-container-title,.hint-container.warning .hint-container-title,.hint-container.danger .hint-container-title{-webkit-padding-start:1.75rem;padding-inline-start:1.75rem}@media print{.hint-container.info .hint-container-title,.hint-container.note .hint-container-title,.hint-container.tip .hint-container-title,.hint-container.warning .hint-container-title,.hint-container.danger .hint-container-title{-webkit-padding-start:0;padding-inline-start:0}}.hint-container.info .hint-container-title:before,.hint-container.note .hint-container-title:before,.hint-container.tip .hint-container-title:before,.hint-container.warning .hint-container-title:before,.hint-container.danger .hint-container-title:before{content:" ";position:absolute;top:calc(50% - .6125em);left:0;width:1.25em;height:1.25em;background-position:left;background-repeat:no-repeat}@media print{.hint-container.info .hint-container-title:before,.hint-container.note .hint-container-title:before,.hint-container.tip .hint-container-title:before,.hint-container.warning .hint-container-title:before,.hint-container.danger .hint-container-title:before{display:none}}html[dir=rtl] .hint-container.info .hint-container-title:before,html[dir=rtl] .hint-container.note .hint-container-title:before,html[dir=rtl] .hint-container.tip .hint-container-title:before,html[dir=rtl] .hint-container.warning .hint-container-title:before,html[dir=rtl] .hint-container.danger .hint-container-title:before{right:0;left:unset}.hint-container.info p,.hint-container.note p,.hint-container.tip p,.hint-container.warning p,.hint-container.danger p{line-height:1.5}.hint-container.info a,.hint-container.note a,.hint-container.tip a,.hint-container.warning a,.hint-container.danger a{color:var(--vp-tc)}.hint-container.info{border-color:var(--info-border-color);background:var(--info-bg-color)}.hint-container.info>.hint-container-title{color:var(--info-title-color)}.hint-container.info>.hint-container-title:before{background-image:url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm-1-11v6h2v-6h-2zm0-4v2h2V7h-2z' fill='%234cb3d4'/%3E%3C/svg%3E")}.hint-container.info code{background:var(--info-code-bg-color)}.hint-container.note{border-color:var(--note-border-color);background:var(--note-bg-color)}.hint-container.note>.hint-container-title{color:var(--note-title-color)}.hint-container.note>.hint-container-title:before{background-image:url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm-1-11v6h2v-6h-2zm0-4v2h2V7h-2z' fill='%23ccc'/%3E%3C/svg%3E")}.hint-container.note code{background:var(--note-code-bg-color)}.hint-container.tip{border-color:var(--tip-border-color);background:var(--tip-bg-color)}.hint-container.tip>.hint-container-title{color:var(--tip-title-color)}.hint-container.tip>.hint-container-title:before{background-image:url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23009400' d='M7.941 18c-.297-1.273-1.637-2.314-2.187-3a8 8 0 1 1 12.49.002c-.55.685-1.888 1.726-2.185 2.998H7.94zM16 20v1a2 2 0 0 1-2 2h-4a2 2 0 0 1-2-2v-1h8zm-3-9.995V6l-4.5 6.005H11v4l4.5-6H13z'/%3E%3C/svg%3E")}.hint-container.tip code{background:var(--tip-code-bg-color)}.hint-container.warning{border-color:var(--warning-border-color);background:var(--warning-bg-color)}.hint-container.warning>.hint-container-title{color:var(--warning-title-color)}.hint-container.warning>.hint-container-title:before{background-image:url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1024 1024'%3E%3Cpath d='M576.286 752.57v-95.425q0-7.031-4.771-11.802t-11.3-4.772h-96.43q-6.528 0-11.3 4.772t-4.77 11.802v95.424q0 7.031 4.77 11.803t11.3 4.77h96.43q6.528 0 11.3-4.77t4.77-11.803zm-1.005-187.836 9.04-230.524q0-6.027-5.022-9.543-6.529-5.524-12.053-5.524H456.754q-5.524 0-12.053 5.524-5.022 3.516-5.022 10.547l8.538 229.52q0 5.023 5.022 8.287t12.053 3.265h92.913q7.032 0 11.803-3.265t5.273-8.287zM568.25 95.65l385.714 707.142q17.578 31.641-1.004 63.282-8.538 14.564-23.354 23.102t-31.892 8.538H126.286q-17.076 0-31.892-8.538T71.04 866.074q-18.582-31.641-1.004-63.282L455.75 95.65q8.538-15.57 23.605-24.61T512 62t32.645 9.04 23.605 24.61z' fill='%23e6a700'/%3E%3C/svg%3E")}.hint-container.warning code{background:var(--warning-code-bg-color)}.hint-container.danger{border-color:var(--danger-border-color);background:var(--danger-bg-color)}.hint-container.danger>.hint-container-title{color:var(--danger-title-color)}.hint-container.danger>.hint-container-title:before{background-image:url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 2c5.523 0 10 4.477 10 10v3.764a2 2 0 0 1-1.106 1.789L18 19v1a3 3 0 0 1-2.824 2.995L14.95 23a2.5 2.5 0 0 0 .044-.33L15 22.5V22a2 2 0 0 0-1.85-1.995L13 20h-2a2 2 0 0 0-1.995 1.85L9 22v.5c0 .171.017.339.05.5H9a3 3 0 0 1-3-3v-1l-2.894-1.447A2 2 0 0 1 2 15.763V12C2 6.477 6.477 2 12 2zm-4 9a2 2 0 1 0 0 4 2 2 0 0 0 0-4zm8 0a2 2 0 1 0 0 4 2 2 0 0 0 0-4z' fill='%23e13238'/%3E%3C/svg%3E")}.hint-container.danger code{background:var(--danger-code-bg-color)}.hint-container.details{position:relative;display:block;margin:1.6em 0;padding:1.5rem;border-radius:.5rem;background:var(--detail-bg-color);color:var(--detail-text-color);transition:background var(--vp-tt),color var(--vp-tt)}@media print{.hint-container.details{display:none}}.hint-container.details h4{margin-top:0}.hint-container.details figure:last-child,.hint-container.details p:last-child{margin-bottom:0;padding-bottom:0}.hint-container.details a{color:var(--vp-tc)}.hint-container.details code{background:var(--detail-code-bg-color)}.hint-container.details summary{position:relative;margin:-1.5rem;padding-top:1.5rem;padding-bottom:1.5rem;-webkit-padding-start:4rem;padding-inline-start:4rem;-webkit-padding-end:1.5rem;padding-inline-end:1.5rem;list-style:none;cursor:pointer}.hint-container.details summary::-webkit-details-marker,.hint-container.details summary::marker{color:transparent;font-size:0}.hint-container.details summary:before,.hint-container.details summary:after{content:" ";position:absolute;top:calc(50% - .75rem);left:1.5rem;width:1.5rem;height:1.5rem}@media print{.hint-container.details summary:before,.hint-container.details summary:after{display:block}}html[dir=rtl] .hint-container.details summary:before,html[dir=rtl] .hint-container.details summary:after{right:1.5rem;left:unset}.hint-container.details summary:before{border-radius:50%;background:#ccc;transition:background var(--vp-ct),transform var(--vp-tt)}html[data-theme=dark] .hint-container.details summary:before{background:#555}.hint-container.details summary:after{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='rgba(0,0,0,0.5)' d='M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z'/%3E%3C/svg%3E");line-height:normal;transition:transform var(--vp-tt);transform:rotate(90deg)}html[data-theme=dark] .hint-container.details summary:after{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='rgba(255,255,255,0.5)' d='M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z'/%3E%3C/svg%3E")}.hint-container.details[open]>summary{margin-bottom:.5em}.hint-container.details[open]>summary:after{transform:rotate(180deg)}.footnote-item{margin-top:calc(0rem - var(--navbar-height, 3.6rem));padding-top:calc(var(--navbar-height, 3.6rem) + .5rem)}.footnote-item>p{margin-bottom:0}.footnote-ref{position:relative}.footnote-anchor{position:absolute;top:calc(-.5rem - var(--navbar-height, 3.6rem))}@font-face{font-family:KaTeX_AMS;font-style:normal;font-weight:400;src:url(/assets/KaTeX_AMS-Regular-0cdd387c.woff2) format("woff2"),url(/assets/KaTeX_AMS-Regular-30da91e8.woff) format("woff"),url(/assets/KaTeX_AMS-Regular-68534840.ttf) format("truetype")}@font-face{font-family:KaTeX_Caligraphic;font-style:normal;font-weight:700;src:url(/assets/KaTeX_Caligraphic-Bold-de7701e4.woff2) format("woff2"),url(/assets/KaTeX_Caligraphic-Bold-1ae6bd74.woff) format("woff"),url(/assets/KaTeX_Caligraphic-Bold-07d8e303.ttf) format("truetype")}@font-face{font-family:KaTeX_Caligraphic;font-style:normal;font-weight:400;src:url(/assets/KaTeX_Caligraphic-Regular-5d53e70a.woff2) format("woff2"),url(/assets/KaTeX_Caligraphic-Regular-3398dd02.woff) format("woff"),url(/assets/KaTeX_Caligraphic-Regular-ed0b7437.ttf) format("truetype")}@font-face{font-family:KaTeX_Fraktur;font-style:normal;font-weight:700;src:url(/assets/KaTeX_Fraktur-Bold-74444efd.woff2) format("woff2"),url(/assets/KaTeX_Fraktur-Bold-9be7ceb8.woff) format("woff"),url(/assets/KaTeX_Fraktur-Bold-9163df9c.ttf) format("truetype")}@font-face{font-family:KaTeX_Fraktur;font-style:normal;font-weight:400;src:url(/assets/KaTeX_Fraktur-Regular-51814d27.woff2) format("woff2"),url(/assets/KaTeX_Fraktur-Regular-5e28753b.woff) format("woff"),url(/assets/KaTeX_Fraktur-Regular-1e6f9579.ttf) format("truetype")}@font-face{font-family:KaTeX_Main;font-style:normal;font-weight:700;src:url(/assets/KaTeX_Main-Bold-0f60d1b8.woff2) format("woff2"),url(/assets/KaTeX_Main-Bold-c76c5d69.woff) format("woff"),url(/assets/KaTeX_Main-Bold-138ac28d.ttf) format("truetype")}@font-face{font-family:KaTeX_Main;font-style:italic;font-weight:700;src:url(/assets/KaTeX_Main-BoldItalic-99cd42a3.woff2) format("woff2"),url(/assets/KaTeX_Main-BoldItalic-a6f7ec0d.woff) format("woff"),url(/assets/KaTeX_Main-BoldItalic-70ee1f64.ttf) format("truetype")}@font-face{font-family:KaTeX_Main;font-style:italic;font-weight:400;src:url(/assets/KaTeX_Main-Italic-97479ca6.woff2) format("woff2"),url(/assets/KaTeX_Main-Italic-f1d6ef86.woff) format("woff"),url(/assets/KaTeX_Main-Italic-0d85ae7c.ttf) format("truetype")}@font-face{font-family:KaTeX_Main;font-style:normal;font-weight:400;src:url(/assets/KaTeX_Main-Regular-c2342cd8.woff2) format("woff2"),url(/assets/KaTeX_Main-Regular-c6368d87.woff) format("woff"),url(/assets/KaTeX_Main-Regular-d0332f52.ttf) format("truetype")}@font-face{font-family:KaTeX_Math;font-style:italic;font-weight:700;src:url(/assets/KaTeX_Math-BoldItalic-dc47344d.woff2) format("woff2"),url(/assets/KaTeX_Math-BoldItalic-850c0af5.woff) format("woff"),url(/assets/KaTeX_Math-BoldItalic-f9377ab0.ttf) format("truetype")}@font-face{font-family:KaTeX_Math;font-style:italic;font-weight:400;src:url(/assets/KaTeX_Math-Italic-7af58c5e.woff2) format("woff2"),url(/assets/KaTeX_Math-Italic-8a8d2445.woff) format("woff"),url(/assets/KaTeX_Math-Italic-08ce98e5.ttf) format("truetype")}@font-face{font-family:KaTeX_SansSerif;font-style:normal;font-weight:700;src:url(/assets/KaTeX_SansSerif-Bold-e99ae511.woff2) format("woff2"),url(/assets/KaTeX_SansSerif-Bold-ece03cfd.woff) format("woff"),url(/assets/KaTeX_SansSerif-Bold-1ece03f7.ttf) format("truetype")}@font-face{font-family:KaTeX_SansSerif;font-style:italic;font-weight:400;src:url(/assets/KaTeX_SansSerif-Italic-00b26ac8.woff2) format("woff2"),url(/assets/KaTeX_SansSerif-Italic-91ee6750.woff) format("woff"),url(/assets/KaTeX_SansSerif-Italic-3931dd81.ttf) format("truetype")}@font-face{font-family:KaTeX_SansSerif;font-style:normal;font-weight:400;src:url(/assets/KaTeX_SansSerif-Regular-68e8c73e.woff2) format("woff2"),url(/assets/KaTeX_SansSerif-Regular-11e4dc8a.woff) format("woff"),url(/assets/KaTeX_SansSerif-Regular-f36ea897.ttf) format("truetype")}@font-face{font-family:KaTeX_Script;font-style:normal;font-weight:400;src:url(/assets/KaTeX_Script-Regular-036d4e95.woff2) format("woff2"),url(/assets/KaTeX_Script-Regular-d96cdf2b.woff) format("woff"),url(/assets/KaTeX_Script-Regular-1c67f068.ttf) format("truetype")}@font-face{font-family:KaTeX_Size1;font-style:normal;font-weight:400;src:url(/assets/KaTeX_Size1-Regular-6b47c401.woff2) format("woff2"),url(/assets/KaTeX_Size1-Regular-c943cc98.woff) format("woff"),url(/assets/KaTeX_Size1-Regular-95b6d2f1.ttf) format("truetype")}@font-face{font-family:KaTeX_Size2;font-style:normal;font-weight:400;src:url(/assets/KaTeX_Size2-Regular-d04c5421.woff2) format("woff2"),url(/assets/KaTeX_Size2-Regular-2014c523.woff) format("woff"),url(/assets/KaTeX_Size2-Regular-a6b2099f.ttf) format("truetype")}@font-face{font-family:KaTeX_Size3;font-style:normal;font-weight:400;src:url(data:font/woff2;base64,d09GMgABAAAAAA4oAA4AAAAAHbQAAA3TAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAABmAAgRQIDgmcDBEICo1oijYBNgIkA14LMgAEIAWJAAeBHAyBHBvbGiMRdnO0IkRRkiYDgr9KsJ1NUAf2kILNxgUmgqIgq1P89vcbIcmsQbRps3vCcXdYOKSWEPEKgZgQkprQQsxIXUgq0DqpGKmIvrgkeVGtEQD9DzAO29fM9jYhxZEsL2FeURH2JN4MIcTdO049NCVdxQ/w9NrSYFEBKTDKpLKfNkCGDc1RwjZLQcm3vqJ2UW9Xfa3tgAHz6ivp6vgC2yD4/6352ndnN0X0TL7seypkjZlMsjmZnf0Mm5Q+JykRWQBKCVCVPbARPXWyQtb5VgLB6Biq7/Uixcj2WGqdI8tGSgkuRG+t910GKP2D7AQH0DB9FMDW/obJZ8giFI3Wg8Cvevz0M+5m0rTh7XDBlvo9Y4vm13EXmfttwI4mBo1EG15fxJhUiCLbiiyCf/ZA6MFAhg3pGIZGdGIVjtPn6UcMk9A/UUr9PhoNsCENw1APAq0gpH73e+M+0ueyHbabc3vkbcdtzcf/fiy+NxQEjf9ud/ELBHAXJ0nk4z+MXH2Ev/kWyV4k7SkvpPc9Qr38F6RPWnM9cN6DJ0AdD1BhtgABtmoRoFCvPsBAumNm6soZG2Gk5GyVTo2sJncSyp0jQTYoR6WDvTwaaEcHsxHfvuWhHA3a6bN7twRKtcGok6NsCi7jYRrM2jExsUFMxMQYuJbMhuWNOumEJy9hi29Dmg5zMp/A5+hhPG19j1vBrq8JTLr8ki5VLPmG/PynJHVul440bxg5xuymHUFPBshC+nA9I1FmwbRBTNHAcik3Oae0cxKoI3MOriM42UrPe51nsaGxJ+WfXubAsP84aabUlQSJ1IiE0iPETLUU4CATgfXSCSpuRFRmCGbO+wSpAnzaeaCYW1VNEysRtuXCEL1kUFUbbtMv3Tilt/1c11jt3Q5bbMa84cpWipp8Elw3MZhOHsOlwwVUQM3lAR35JiFQbaYCRnMF2lxAWoOg2gyoIV4PouX8HytNIfLhqpJtXB4vjiViUI8IJ7bkC4ikkQvKksnOTKICwnqWSZ9YS5f0WCxmpgjbIq7EJcM4aI2nmhLNY2JIUgOjXZFWBHb+x5oh6cwb0Tv1ackHdKi0I9OO2wE9aogIOn540CCCziyhN+IaejtgAONKznHlHyutPrHGwCx9S6B8kfS4Mfi4Eyv7OU730bT1SCBjt834cXsf43zVjPUqqJjgrjeGnBxSG4aYAKFuVbeCfkDIjAqMb6yLNIbCuvXhMH2/+k2vkNpkORhR59N1CkzoOENvneIosjYmuTxlhUzaGEJQ/iWqx4dmwpmKjrwTiTGTCVozNAYqk/zXOndWxuWSmJkQpJw3pK5KX6QrLt5LATMqpmPAQhkhK6PUjzHUn7E0gHE0kPE0iKkolgkUx9SZmVAdDgpffdyJKg3k7VmzYGCwVXGz/tXmkOIp+vcWs+EMuhhvN0h9uhfzWJziBQmCREGSIFmQIkgVpAnSBRmC//6hkLZwaVhwxlrJSOdqlFtOYxlau9F2QN5Y98xmIAsiM1HVp2VFX+DHHGg6Ecjh3vmqtidX3qHI2qycTk/iwxSt5UzTmEP92ZBnEWTk4Mx8Mpl78ZDokxg/KWb+Q0QkvdKVmq3TMW+RXEgrsziSAfNXFMhDc60N5N9jQzjfO0kBKpUZl0ZmwJ41j/B9Hz6wmRaJB84niNmQrzp9eSlQCDDzazGDdVi3P36VZQ+Jy4f9UBNp+3zTjqI4abaFAm+GShVaXlsGdF3FYzZcDI6cori4kMxUECl9IjJZpzkvitAoxKue+90pDMvcKRxLl53TmOKCmV/xRolNKSqqUxc6LStOETmFOiLZZptlZepcKiAzteG8PEdpnQpbOMNcMsR4RR2Bs0cKFEvSmIjAFcnarqwUL4lDhHmnVkwu1IwshbiCcgvOheZuYyOteufZZwlcTlLgnZ3o/WcYdzZHW/WGaqaVfmTZ1aWCceJjkbZqsfbkOtcFlUZM/jy+hXHDbaUobWqqXaeWobbLO99yG5N3U4wxco0rQGGcOLASFMXeJoham8M+/x6O2WywK2l4HGbq1CoUyC/IZikQhdq3SiuNrvAEj0AVu9x2x3lp/xWzahaxidezFVtdcb5uEnzyl0ZmYiuKI0exvCd4Xc9CV1KB0db00z92wDPde0kukbvZIWN6jUWFTmPIC/Y4UPCm8UfDTFZpZNon1qLFTkBhxzB+FjQRA2Q/YRJT8pQigslMaUpFyAG8TMlXigiqmAZX4xgijKjRlGpLE0GdplRfCaJo0JQaSxNBk6ZmMzcya0FmrcisDdn0Q3HI2sWSppYigmlM1XT/kLQZSNpMJG0WkjYbSZuDpM1F0uYhFc1HxU4m1QJjDK6iL0S5uSj5rgXc3RejEigtcRBtqYPQsiTskmO5vosV+q4VGIKbOkDg0jtRrq+Em1YloaTFar3EGr1EUC8R0kus1Uus00usL97ABr2BjXoDm/QGNhuWtMVBKOwg/i78lT7hBsAvDmwHc/ao3vmUbBmhjeYySZNWvGkfZAgISDSaDo1SVpzGDsAEkF8B+gEapViUoZgUWXcRIGFZNm6gWbAKk0bp0k1MHG9fLYtV4iS2SmLEQFARzRcnf9PUS0LVn05/J9MiRRBU3v2IrvW974v4N00L7ZMk0wXP1409CHo/an8zTRHD3eSJ6m8D4YMkZNl3M79sqeuAsr/m3f+8/yl7A50aiAEJgeBeMWzu7ui9UfUBCe2TIqZIoOd/3/udRBOQidQZUERzb2/VwZN1H/Sju82ew2H2Wfr6qvfVf3hqwDvAIpkQVFy4B9Pe9e4/XvPeceu7h3dvO56iJPf0+A6cqA2ip18ER+iFgggiuOkvj24bby0N9j2UHIkgqIt+sVgfodC4YghLSMjSZbH0VR/6dMDrYJeKHilKTemt6v6kvzvn3/RrdWtr0GoN/xL+Sex/cPYLUpepx9cz/D46UPU5KXgAQa+NDps1v6J3xP1i2HtaDB0M9aX2deA7SYff//+gUCovMmIK/qfsFcOk+4Y5ZN97XlG6zebqtMbKgeRFi51vnxTQYBUik2rS/Cn6PC8ADR8FGxsRPB82dzfND90gIcshOcYUkfjherBz53odpm6TP8txlwOZ71xmfHHOvq053qFF/MRlS3jP0ELudrf2OeN8DHvp6ZceLe8qKYvWz/7yp0u4dKPfli3CYq0O13Ih71mylJ80tOi10On8wi+F4+LWgDPeJ30msSQt9/vkmHq9/Lvo2b461mP801v3W4xTcs6CbvF9UDdrSt+A8OUbpSh55qAUFXWznBBfdeJ8a4d7ugT5tvxUza3h9m4H7ptTqiG4z0g5dc0X29OcGlhpGFMpQo9ytTS+NViZpNdvU4kWx+LKxNY10kQ1yqGXrhe4/1nvP7E+nd5A92TtaRplbHSqoIdOqtRWti+fkB5/n1+/VvCmz12pG1kpQWsfi1ftlBobm0bpngs16CHkbIwdLnParxtTV3QYRlfJ0KFskH7pdN/YDn+yRuSd7sNH3aO0DYPggk6uWuXrfOc+fa3VTxFVvKaNxHsiHmsXyCLIE5yuOeN3/Jdf8HBL/5M6shjyhxHx9BjB1O0+4NLOnjLLSxwO7ukN4jMbOIcD879KLSi6Pk61Oqm2377n8079PXEEQ7cy7OKEC9nbpet118fxweTafpt69x/Bt8UqGzNQt7aelpc44dn5cqhwf71+qKp/Zf/+a0zcizOUWpl/iBcSXip0pplkatCchoH5c5aUM8I7/dWxAej8WicPL1URFZ9BDJelUwEwTkGqUhgSlydVes95YdXvhh9Gfz/aeFWvgVb4tuLbcv4+wLdutVZv/cUonwBD/6eDlE0aSiKK/uoH3+J1wDE/jMVqY2ysGufN84oIXB0sPzy8ollX/LegY74DgJXJR57sn+VGza0x3DnuIgABFM15LmajjjsNlYj+JEZGbuRYcAMOWxFkPN2w6Wd46xo4gVWQR/X4lyI/R6K/YK0110GzudPRW7Y+UOBGTfNNzHeYT0fiH0taunBpq9HEW8OKSaBGj21L0MqenEmNRWBAWDWAk4CpNoEZJ2tTaPFgbQYj8HxtFilErs3BTRwT8uO1NXQaWfIotchmPkAF5mMBAliEmZiOGVgCG9LgRzpscMAOOwowlT3JhusdazXGSC/hxR3UlmWVwWHpOIKheqONvjyhSiTHIkVUco5bnji8m//zL7PKaT1Vl5I6UE609f+gkr6MZKVyKc7zJRmCahLsdlyA5fdQkRSan9LgnnLEyGSkaKJCJog0wAgvepWBt80+1yKln1bMVtCljfNWDueKLsWwaEbBSfSPTEmVRsUcYYMnEjcjeyCZzBXK9E9BYBXLKjOSpUDR+nEV3TFSUdQaz+ot98QxgXwx0GQ+EEUAKB2qZPkQQ0GqFD8UPFMqyaCHM24BZmSGic9EYMagKizOw9Hz50DMrDLrqqLkTAhplMictiCAx5S3BIUQdeJeLnBy2CNtMfz6cV4u8XKoFZQesbf9YZiIERiHjaNodDW6LgcirX/mPnJIkBGDUpTBhSa0EIr38D5hCIszhCM8URGBqImoWjpvpt1ebu/v3Gl3qJfMnNM+9V+kiRFyROTPHQWOcs1dNW94/ukKMPZBvDi55i5CttdeJz84DLngLqjcdwEZ87bFFR8CIG35OAkDVN6VRDZ7aq67NteYqZ2lpT8oYB2CytoBd6VuAx4WgiAsnuj3WohG+LugzXiQRDeM3XYXlULv4dp5VFYC) format("woff2"),url(/assets/KaTeX_Size3-Regular-6ab6b62e.woff) format("woff"),url(/assets/KaTeX_Size3-Regular-500e04d5.ttf) format("truetype")}@font-face{font-family:KaTeX_Size4;font-style:normal;font-weight:400;src:url(/assets/KaTeX_Size4-Regular-a4af7d41.woff2) format("woff2"),url(/assets/KaTeX_Size4-Regular-99f9c675.woff) format("woff"),url(/assets/KaTeX_Size4-Regular-c647367d.ttf) format("truetype")}@font-face{font-family:KaTeX_Typewriter;font-style:normal;font-weight:400;src:url(/assets/KaTeX_Typewriter-Regular-71d517d6.woff2) format("woff2"),url(/assets/KaTeX_Typewriter-Regular-e14fed02.woff) format("woff"),url(/assets/KaTeX_Typewriter-Regular-f01f3e87.ttf) format("truetype")}.katex{text-rendering:auto;font: 1.21em KaTeX_Main,Times New Roman,serif;line-height:1.2;text-indent:0}.katex *{-ms-high-contrast-adjust:none!important;border-color:currentColor}.katex .katex-version:after{content:"0.16.7"}.katex .katex-mathml{clip:rect(1px,1px,1px,1px);border:0;height:1px;overflow:hidden;padding:0;position:absolute;width:1px}.katex .katex-html>.newline{display:block}.katex .base{position:relative;white-space:nowrap;width:-moz-min-content;width:min-content}.katex .base,.katex .strut{display:inline-block}.katex .textbf{font-weight:700}.katex .textit{font-style:italic}.katex .textrm{font-family:KaTeX_Main}.katex .textsf{font-family:KaTeX_SansSerif}.katex .texttt{font-family:KaTeX_Typewriter}.katex .mathnormal{font-family:KaTeX_Math;font-style:italic}.katex .mathit{font-family:KaTeX_Main;font-style:italic}.katex .mathrm{font-style:normal}.katex .mathbf{font-family:KaTeX_Main;font-weight:700}.katex .boldsymbol{font-family:KaTeX_Math;font-style:italic;font-weight:700}.katex .amsrm,.katex .mathbb,.katex .textbb{font-family:KaTeX_AMS}.katex .mathcal{font-family:KaTeX_Caligraphic}.katex .mathfrak,.katex .textfrak{font-family:KaTeX_Fraktur}.katex .mathtt{font-family:KaTeX_Typewriter}.katex .mathscr,.katex .textscr{font-family:KaTeX_Script}.katex .mathsf,.katex .textsf{font-family:KaTeX_SansSerif}.katex .mathboldsf,.katex .textboldsf{font-family:KaTeX_SansSerif;font-weight:700}.katex .mathitsf,.katex .textitsf{font-family:KaTeX_SansSerif;font-style:italic}.katex .mainrm{font-family:KaTeX_Main;font-style:normal}.katex .vlist-t{border-collapse:collapse;display:inline-table;table-layout:fixed}.katex .vlist-r{display:table-row}.katex .vlist{display:table-cell;position:relative;vertical-align:bottom}.katex .vlist>span{display:block;height:0;position:relative}.katex .vlist>span>span{display:inline-block}.katex .vlist>span>.pstrut{overflow:hidden;width:0}.katex .vlist-t2{margin-right:-2px}.katex .vlist-s{display:table-cell;font-size:1px;min-width:2px;vertical-align:bottom;width:2px}.katex .vbox{align-items:baseline;display:inline-flex;flex-direction:column}.katex .hbox{width:100%}.katex .hbox,.katex .thinbox{display:inline-flex;flex-direction:row}.katex .thinbox{max-width:0;width:0}.katex .msupsub{text-align:left}.katex .mfrac>span>span{text-align:center}.katex .mfrac .frac-line{border-bottom-style:solid;display:inline-block;width:100%}.katex .hdashline,.katex .hline,.katex .mfrac .frac-line,.katex .overline .overline-line,.katex .rule,.katex .underline .underline-line{min-height:1px}.katex .mspace{display:inline-block}.katex .clap,.katex .llap,.katex .rlap{position:relative;width:0}.katex .clap>.inner,.katex .llap>.inner,.katex .rlap>.inner{position:absolute}.katex .clap>.fix,.katex .llap>.fix,.katex .rlap>.fix{display:inline-block}.katex .llap>.inner{right:0}.katex .clap>.inner,.katex .rlap>.inner{left:0}.katex .clap>.inner>span{margin-left:-50%;margin-right:50%}.katex .rule{border:0 solid;display:inline-block;position:relative}.katex .hline,.katex .overline .overline-line,.katex .underline .underline-line{border-bottom-style:solid;display:inline-block;width:100%}.katex .hdashline{border-bottom-style:dashed;display:inline-block;width:100%}.katex .sqrt>.root{margin-left:.27777778em;margin-right:-.55555556em}.katex .fontsize-ensurer.reset-size1.size1,.katex .sizing.reset-size1.size1{font-size:1em}.katex .fontsize-ensurer.reset-size1.size2,.katex .sizing.reset-size1.size2{font-size:1.2em}.katex .fontsize-ensurer.reset-size1.size3,.katex .sizing.reset-size1.size3{font-size:1.4em}.katex .fontsize-ensurer.reset-size1.size4,.katex .sizing.reset-size1.size4{font-size:1.6em}.katex .fontsize-ensurer.reset-size1.size5,.katex .sizing.reset-size1.size5{font-size:1.8em}.katex .fontsize-ensurer.reset-size1.size6,.katex .sizing.reset-size1.size6{font-size:2em}.katex .fontsize-ensurer.reset-size1.size7,.katex .sizing.reset-size1.size7{font-size:2.4em}.katex .fontsize-ensurer.reset-size1.size8,.katex .sizing.reset-size1.size8{font-size:2.88em}.katex .fontsize-ensurer.reset-size1.size9,.katex .sizing.reset-size1.size9{font-size:3.456em}.katex .fontsize-ensurer.reset-size1.size10,.katex .sizing.reset-size1.size10{font-size:4.148em}.katex .fontsize-ensurer.reset-size1.size11,.katex .sizing.reset-size1.size11{font-size:4.976em}.katex .fontsize-ensurer.reset-size2.size1,.katex .sizing.reset-size2.size1{font-size:.83333333em}.katex .fontsize-ensurer.reset-size2.size2,.katex .sizing.reset-size2.size2{font-size:1em}.katex .fontsize-ensurer.reset-size2.size3,.katex .sizing.reset-size2.size3{font-size:1.16666667em}.katex .fontsize-ensurer.reset-size2.size4,.katex .sizing.reset-size2.size4{font-size:1.33333333em}.katex .fontsize-ensurer.reset-size2.size5,.katex .sizing.reset-size2.size5{font-size:1.5em}.katex .fontsize-ensurer.reset-size2.size6,.katex .sizing.reset-size2.size6{font-size:1.66666667em}.katex .fontsize-ensurer.reset-size2.size7,.katex .sizing.reset-size2.size7{font-size:2em}.katex .fontsize-ensurer.reset-size2.size8,.katex .sizing.reset-size2.size8{font-size:2.4em}.katex .fontsize-ensurer.reset-size2.size9,.katex .sizing.reset-size2.size9{font-size:2.88em}.katex .fontsize-ensurer.reset-size2.size10,.katex .sizing.reset-size2.size10{font-size:3.45666667em}.katex .fontsize-ensurer.reset-size2.size11,.katex .sizing.reset-size2.size11{font-size:4.14666667em}.katex .fontsize-ensurer.reset-size3.size1,.katex .sizing.reset-size3.size1{font-size:.71428571em}.katex .fontsize-ensurer.reset-size3.size2,.katex .sizing.reset-size3.size2{font-size:.85714286em}.katex .fontsize-ensurer.reset-size3.size3,.katex .sizing.reset-size3.size3{font-size:1em}.katex .fontsize-ensurer.reset-size3.size4,.katex .sizing.reset-size3.size4{font-size:1.14285714em}.katex .fontsize-ensurer.reset-size3.size5,.katex .sizing.reset-size3.size5{font-size:1.28571429em}.katex .fontsize-ensurer.reset-size3.size6,.katex .sizing.reset-size3.size6{font-size:1.42857143em}.katex .fontsize-ensurer.reset-size3.size7,.katex .sizing.reset-size3.size7{font-size:1.71428571em}.katex .fontsize-ensurer.reset-size3.size8,.katex .sizing.reset-size3.size8{font-size:2.05714286em}.katex .fontsize-ensurer.reset-size3.size9,.katex .sizing.reset-size3.size9{font-size:2.46857143em}.katex .fontsize-ensurer.reset-size3.size10,.katex .sizing.reset-size3.size10{font-size:2.96285714em}.katex .fontsize-ensurer.reset-size3.size11,.katex .sizing.reset-size3.size11{font-size:3.55428571em}.katex .fontsize-ensurer.reset-size4.size1,.katex .sizing.reset-size4.size1{font-size:.625em}.katex .fontsize-ensurer.reset-size4.size2,.katex .sizing.reset-size4.size2{font-size:.75em}.katex .fontsize-ensurer.reset-size4.size3,.katex .sizing.reset-size4.size3{font-size:.875em}.katex .fontsize-ensurer.reset-size4.size4,.katex .sizing.reset-size4.size4{font-size:1em}.katex .fontsize-ensurer.reset-size4.size5,.katex .sizing.reset-size4.size5{font-size:1.125em}.katex .fontsize-ensurer.reset-size4.size6,.katex .sizing.reset-size4.size6{font-size:1.25em}.katex .fontsize-ensurer.reset-size4.size7,.katex .sizing.reset-size4.size7{font-size:1.5em}.katex .fontsize-ensurer.reset-size4.size8,.katex .sizing.reset-size4.size8{font-size:1.8em}.katex .fontsize-ensurer.reset-size4.size9,.katex .sizing.reset-size4.size9{font-size:2.16em}.katex .fontsize-ensurer.reset-size4.size10,.katex .sizing.reset-size4.size10{font-size:2.5925em}.katex .fontsize-ensurer.reset-size4.size11,.katex .sizing.reset-size4.size11{font-size:3.11em}.katex .fontsize-ensurer.reset-size5.size1,.katex .sizing.reset-size5.size1{font-size:.55555556em}.katex .fontsize-ensurer.reset-size5.size2,.katex .sizing.reset-size5.size2{font-size:.66666667em}.katex .fontsize-ensurer.reset-size5.size3,.katex .sizing.reset-size5.size3{font-size:.77777778em}.katex .fontsize-ensurer.reset-size5.size4,.katex .sizing.reset-size5.size4{font-size:.88888889em}.katex .fontsize-ensurer.reset-size5.size5,.katex .sizing.reset-size5.size5{font-size:1em}.katex .fontsize-ensurer.reset-size5.size6,.katex .sizing.reset-size5.size6{font-size:1.11111111em}.katex .fontsize-ensurer.reset-size5.size7,.katex .sizing.reset-size5.size7{font-size:1.33333333em}.katex .fontsize-ensurer.reset-size5.size8,.katex .sizing.reset-size5.size8{font-size:1.6em}.katex .fontsize-ensurer.reset-size5.size9,.katex .sizing.reset-size5.size9{font-size:1.92em}.katex .fontsize-ensurer.reset-size5.size10,.katex .sizing.reset-size5.size10{font-size:2.30444444em}.katex .fontsize-ensurer.reset-size5.size11,.katex .sizing.reset-size5.size11{font-size:2.76444444em}.katex .fontsize-ensurer.reset-size6.size1,.katex .sizing.reset-size6.size1{font-size:.5em}.katex .fontsize-ensurer.reset-size6.size2,.katex .sizing.reset-size6.size2{font-size:.6em}.katex .fontsize-ensurer.reset-size6.size3,.katex .sizing.reset-size6.size3{font-size:.7em}.katex .fontsize-ensurer.reset-size6.size4,.katex .sizing.reset-size6.size4{font-size:.8em}.katex .fontsize-ensurer.reset-size6.size5,.katex .sizing.reset-size6.size5{font-size:.9em}.katex .fontsize-ensurer.reset-size6.size6,.katex .sizing.reset-size6.size6{font-size:1em}.katex .fontsize-ensurer.reset-size6.size7,.katex .sizing.reset-size6.size7{font-size:1.2em}.katex .fontsize-ensurer.reset-size6.size8,.katex .sizing.reset-size6.size8{font-size:1.44em}.katex .fontsize-ensurer.reset-size6.size9,.katex .sizing.reset-size6.size9{font-size:1.728em}.katex .fontsize-ensurer.reset-size6.size10,.katex .sizing.reset-size6.size10{font-size:2.074em}.katex .fontsize-ensurer.reset-size6.size11,.katex .sizing.reset-size6.size11{font-size:2.488em}.katex .fontsize-ensurer.reset-size7.size1,.katex .sizing.reset-size7.size1{font-size:.41666667em}.katex .fontsize-ensurer.reset-size7.size2,.katex .sizing.reset-size7.size2{font-size:.5em}.katex .fontsize-ensurer.reset-size7.size3,.katex .sizing.reset-size7.size3{font-size:.58333333em}.katex .fontsize-ensurer.reset-size7.size4,.katex .sizing.reset-size7.size4{font-size:.66666667em}.katex .fontsize-ensurer.reset-size7.size5,.katex .sizing.reset-size7.size5{font-size:.75em}.katex .fontsize-ensurer.reset-size7.size6,.katex .sizing.reset-size7.size6{font-size:.83333333em}.katex .fontsize-ensurer.reset-size7.size7,.katex .sizing.reset-size7.size7{font-size:1em}.katex .fontsize-ensurer.reset-size7.size8,.katex .sizing.reset-size7.size8{font-size:1.2em}.katex .fontsize-ensurer.reset-size7.size9,.katex .sizing.reset-size7.size9{font-size:1.44em}.katex .fontsize-ensurer.reset-size7.size10,.katex .sizing.reset-size7.size10{font-size:1.72833333em}.katex .fontsize-ensurer.reset-size7.size11,.katex .sizing.reset-size7.size11{font-size:2.07333333em}.katex .fontsize-ensurer.reset-size8.size1,.katex .sizing.reset-size8.size1{font-size:.34722222em}.katex .fontsize-ensurer.reset-size8.size2,.katex .sizing.reset-size8.size2{font-size:.41666667em}.katex .fontsize-ensurer.reset-size8.size3,.katex .sizing.reset-size8.size3{font-size:.48611111em}.katex .fontsize-ensurer.reset-size8.size4,.katex .sizing.reset-size8.size4{font-size:.55555556em}.katex .fontsize-ensurer.reset-size8.size5,.katex .sizing.reset-size8.size5{font-size:.625em}.katex .fontsize-ensurer.reset-size8.size6,.katex .sizing.reset-size8.size6{font-size:.69444444em}.katex .fontsize-ensurer.reset-size8.size7,.katex .sizing.reset-size8.size7{font-size:.83333333em}.katex .fontsize-ensurer.reset-size8.size8,.katex .sizing.reset-size8.size8{font-size:1em}.katex .fontsize-ensurer.reset-size8.size9,.katex .sizing.reset-size8.size9{font-size:1.2em}.katex .fontsize-ensurer.reset-size8.size10,.katex .sizing.reset-size8.size10{font-size:1.44027778em}.katex .fontsize-ensurer.reset-size8.size11,.katex .sizing.reset-size8.size11{font-size:1.72777778em}.katex .fontsize-ensurer.reset-size9.size1,.katex .sizing.reset-size9.size1{font-size:.28935185em}.katex .fontsize-ensurer.reset-size9.size2,.katex .sizing.reset-size9.size2{font-size:.34722222em}.katex .fontsize-ensurer.reset-size9.size3,.katex .sizing.reset-size9.size3{font-size:.40509259em}.katex .fontsize-ensurer.reset-size9.size4,.katex .sizing.reset-size9.size4{font-size:.46296296em}.katex .fontsize-ensurer.reset-size9.size5,.katex .sizing.reset-size9.size5{font-size:.52083333em}.katex .fontsize-ensurer.reset-size9.size6,.katex .sizing.reset-size9.size6{font-size:.5787037em}.katex .fontsize-ensurer.reset-size9.size7,.katex .sizing.reset-size9.size7{font-size:.69444444em}.katex .fontsize-ensurer.reset-size9.size8,.katex .sizing.reset-size9.size8{font-size:.83333333em}.katex .fontsize-ensurer.reset-size9.size9,.katex .sizing.reset-size9.size9{font-size:1em}.katex .fontsize-ensurer.reset-size9.size10,.katex .sizing.reset-size9.size10{font-size:1.20023148em}.katex .fontsize-ensurer.reset-size9.size11,.katex .sizing.reset-size9.size11{font-size:1.43981481em}.katex .fontsize-ensurer.reset-size10.size1,.katex .sizing.reset-size10.size1{font-size:.24108004em}.katex .fontsize-ensurer.reset-size10.size2,.katex .sizing.reset-size10.size2{font-size:.28929605em}.katex .fontsize-ensurer.reset-size10.size3,.katex .sizing.reset-size10.size3{font-size:.33751205em}.katex .fontsize-ensurer.reset-size10.size4,.katex .sizing.reset-size10.size4{font-size:.38572806em}.katex .fontsize-ensurer.reset-size10.size5,.katex .sizing.reset-size10.size5{font-size:.43394407em}.katex .fontsize-ensurer.reset-size10.size6,.katex .sizing.reset-size10.size6{font-size:.48216008em}.katex .fontsize-ensurer.reset-size10.size7,.katex .sizing.reset-size10.size7{font-size:.57859209em}.katex .fontsize-ensurer.reset-size10.size8,.katex .sizing.reset-size10.size8{font-size:.69431051em}.katex .fontsize-ensurer.reset-size10.size9,.katex .sizing.reset-size10.size9{font-size:.83317261em}.katex .fontsize-ensurer.reset-size10.size10,.katex .sizing.reset-size10.size10{font-size:1em}.katex .fontsize-ensurer.reset-size10.size11,.katex .sizing.reset-size10.size11{font-size:1.19961427em}.katex .fontsize-ensurer.reset-size11.size1,.katex .sizing.reset-size11.size1{font-size:.20096463em}.katex .fontsize-ensurer.reset-size11.size2,.katex .sizing.reset-size11.size2{font-size:.24115756em}.katex .fontsize-ensurer.reset-size11.size3,.katex .sizing.reset-size11.size3{font-size:.28135048em}.katex .fontsize-ensurer.reset-size11.size4,.katex .sizing.reset-size11.size4{font-size:.32154341em}.katex .fontsize-ensurer.reset-size11.size5,.katex .sizing.reset-size11.size5{font-size:.36173633em}.katex .fontsize-ensurer.reset-size11.size6,.katex .sizing.reset-size11.size6{font-size:.40192926em}.katex .fontsize-ensurer.reset-size11.size7,.katex .sizing.reset-size11.size7{font-size:.48231511em}.katex .fontsize-ensurer.reset-size11.size8,.katex .sizing.reset-size11.size8{font-size:.57877814em}.katex .fontsize-ensurer.reset-size11.size9,.katex .sizing.reset-size11.size9{font-size:.69453376em}.katex .fontsize-ensurer.reset-size11.size10,.katex .sizing.reset-size11.size10{font-size:.83360129em}.katex .fontsize-ensurer.reset-size11.size11,.katex .sizing.reset-size11.size11{font-size:1em}.katex .delimsizing.size1{font-family:KaTeX_Size1}.katex .delimsizing.size2{font-family:KaTeX_Size2}.katex .delimsizing.size3{font-family:KaTeX_Size3}.katex .delimsizing.size4{font-family:KaTeX_Size4}.katex .delimsizing.mult .delim-size1>span{font-family:KaTeX_Size1}.katex .delimsizing.mult .delim-size4>span{font-family:KaTeX_Size4}.katex .nulldelimiter{display:inline-block;width:.12em}.katex .delimcenter,.katex .op-symbol{position:relative}.katex .op-symbol.small-op{font-family:KaTeX_Size1}.katex .op-symbol.large-op{font-family:KaTeX_Size2}.katex .accent>.vlist-t,.katex .op-limits>.vlist-t{text-align:center}.katex .accent .accent-body{position:relative}.katex .accent .accent-body:not(.accent-full){width:0}.katex .overlay{display:block}.katex .mtable .vertical-separator{display:inline-block;min-width:1px}.katex .mtable .arraycolsep{display:inline-block}.katex .mtable .col-align-c>.vlist-t{text-align:center}.katex .mtable .col-align-l>.vlist-t{text-align:left}.katex .mtable .col-align-r>.vlist-t{text-align:right}.katex .svg-align{text-align:left}.katex svg{fill:currentColor;stroke:currentColor;fill-rule:nonzero;fill-opacity:1;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:block;height:inherit;position:absolute;width:100%}.katex svg path{stroke:none}.katex img{border-style:none;max-height:none;max-width:none;min-height:0;min-width:0}.katex .stretchy{display:block;overflow:hidden;position:relative;width:100%}.katex .stretchy:after,.katex .stretchy:before{content:""}.katex .hide-tail{overflow:hidden;position:relative;width:100%}.katex .halfarrow-left{left:0;overflow:hidden;position:absolute;width:50.2%}.katex .halfarrow-right{overflow:hidden;position:absolute;right:0;width:50.2%}.katex .brace-left{left:0;overflow:hidden;position:absolute;width:25.1%}.katex .brace-center{left:25%;overflow:hidden;position:absolute;width:50%}.katex .brace-right{overflow:hidden;position:absolute;right:0;width:25.1%}.katex .x-arrow-pad{padding:0 .5em}.katex .cd-arrow-pad{padding:0 .55556em 0 .27778em}.katex .mover,.katex .munder,.katex .x-arrow{text-align:center}.katex .boxpad{padding:0 .3em}.katex .fbox,.katex .fcolorbox{border:.04em solid;box-sizing:border-box}.katex .cancel-pad{padding:0 .2em}.katex .cancel-lap{margin-left:-.2em;margin-right:-.2em}.katex .sout{border-bottom-style:solid;border-bottom-width:.08em}.katex .angl{border-right:.049em solid;border-top:.049em solid;box-sizing:border-box;margin-right:.03889em}.katex .anglpad{padding:0 .03889em}.katex .eqn-num:before{content:"(" counter(katexEqnNo) ")";counter-increment:katexEqnNo}.katex .mml-eqn-num:before{content:"(" counter(mmlEqnNo) ")";counter-increment:mmlEqnNo}.katex .mtr-glue{width:50%}.katex .cd-vert-arrow{display:inline-block;position:relative}.katex .cd-label-left{display:inline-block;position:absolute;right:calc(50% + .3em);text-align:left}.katex .cd-label-right{display:inline-block;left:calc(50% + .3em);position:absolute;text-align:right}.katex-display{display:block;margin:1em 0;text-align:center}.katex-display>.katex{display:block;text-align:center;white-space:nowrap}.katex-display>.katex>.katex-html{display:block;position:relative}.katex-display>.katex>.katex-html>.tag{position:absolute;right:0}.katex-display.leqno>.katex>.katex-html>.tag{left:0;right:auto}.katex-display.fleqn>.katex{padding-left:2em;text-align:left}body{counter-reset:katexEqnNo mmlEqnNo}.katex{font-size:1.05em;direction:ltr}.katex-display{overflow:auto hidden;-webkit-overflow-scrolling:touch;padding-top:.2em;padding-bottom:.2em}.katex-display::-webkit-scrollbar{height:3px}.katex-display .katex{font-size:1.21em}.katex-error{color:red}/*! PhotoSwipe main CSS by Dmytro Semenov | photoswipe.com */.pswp{--pswp-bg: #000;--pswp-placeholder-bg: #222;--pswp-root-z-index: 100000;--pswp-preloader-color: rgba(79, 79, 79, .4);--pswp-preloader-color-secondary: rgba(255, 255, 255, .9);--pswp-icon-color: #fff;--pswp-icon-color-secondary: #4f4f4f;--pswp-icon-stroke-color: #4f4f4f;--pswp-icon-stroke-width: 2px;--pswp-error-text-color: var(--pswp-icon-color)}.pswp{position:fixed;top:0;left:0;width:100%;height:100%;z-index:var(--pswp-root-z-index);display:none;touch-action:none;outline:0;opacity:.003;contain:layout style size;-webkit-tap-highlight-color:rgba(0,0,0,0)}.pswp:focus{outline:0}.pswp *{box-sizing:border-box}.pswp img{max-width:none}.pswp--open{display:block}.pswp,.pswp__bg{transform:translateZ(0);will-change:opacity}.pswp__bg{opacity:.005;background:var(--pswp-bg)}.pswp,.pswp__scroll-wrap{overflow:hidden}.pswp__scroll-wrap,.pswp__bg,.pswp__container,.pswp__item,.pswp__content,.pswp__img,.pswp__zoom-wrap{position:absolute;top:0;left:0;width:100%;height:100%}.pswp__img,.pswp__zoom-wrap{width:auto;height:auto}.pswp--click-to-zoom.pswp--zoom-allowed .pswp__img{cursor:zoom-in}.pswp--click-to-zoom.pswp--zoomed-in .pswp__img{cursor:move;cursor:grab}.pswp--click-to-zoom.pswp--zoomed-in .pswp__img:active{cursor:grabbing}.pswp--no-mouse-drag.pswp--zoomed-in .pswp__img,.pswp--no-mouse-drag.pswp--zoomed-in .pswp__img:active,.pswp__img{cursor:zoom-out}.pswp__container,.pswp__img,.pswp__button,.pswp__counter{-webkit-user-select:none;-moz-user-select:none;user-select:none}.pswp__item{z-index:1;overflow:hidden}.pswp__hidden{display:none!important}.pswp__content{pointer-events:none}.pswp__content>*{pointer-events:auto}.pswp__error-msg-container{display:grid}.pswp__error-msg{margin:auto;font-size:1em;line-height:1;color:var(--pswp-error-text-color)}.pswp .pswp__hide-on-close{opacity:.005;will-change:opacity;transition:opacity var(--pswp-transition-duration) cubic-bezier(.4,0,.22,1);z-index:10;pointer-events:none}.pswp--ui-visible .pswp__hide-on-close{opacity:1;pointer-events:auto}.pswp__button{position:relative;display:block;width:50px;height:60px;padding:0;margin:0;overflow:hidden;cursor:pointer;background:none;border:0;box-shadow:none;opacity:.85;-webkit-appearance:none;-webkit-touch-callout:none}.pswp__button:hover,.pswp__button:active,.pswp__button:focus{transition:none;padding:0;background:none;border:0;box-shadow:none;opacity:1}.pswp__button:disabled{opacity:.3;cursor:auto}.pswp__icn{fill:var(--pswp-icon-color);color:var(--pswp-icon-color-secondary)}.pswp__icn{position:absolute;top:14px;left:9px;width:32px;height:32px;overflow:hidden;pointer-events:none}.pswp__icn-shadow{stroke:var(--pswp-icon-stroke-color);stroke-width:var(--pswp-icon-stroke-width);fill:none}.pswp__icn:focus{outline:0}div.pswp__img--placeholder,.pswp__img--with-bg{background:var(--pswp-placeholder-bg)}.pswp__top-bar{position:absolute;left:0;top:0;width:100%;height:60px;display:flex;flex-direction:row;justify-content:flex-end;z-index:10;pointer-events:none!important}.pswp__top-bar>*{pointer-events:auto;will-change:opacity}.pswp__button--close{margin-right:6px}.pswp__button--arrow{position:absolute;top:0;width:75px;height:100px;top:50%;margin-top:-50px}.pswp__button--arrow:disabled{display:none;cursor:default}.pswp__button--arrow .pswp__icn{top:50%;margin-top:-30px;width:60px;height:60px;background:none;border-radius:0}.pswp--one-slide .pswp__button--arrow{display:none}.pswp--touch .pswp__button--arrow{visibility:hidden}.pswp--has_mouse .pswp__button--arrow{visibility:visible}.pswp__button--arrow--prev{right:auto;left:0px}.pswp__button--arrow--next{right:0px}.pswp__button--arrow--next .pswp__icn{left:auto;right:14px;transform:scaleX(-1)}.pswp__button--zoom{display:none}.pswp--zoom-allowed .pswp__button--zoom{display:block}.pswp--zoomed-in .pswp__zoom-icn-bar-v{display:none}.pswp__preloader{position:relative;overflow:hidden;width:50px;height:60px;margin-right:auto}.pswp__preloader .pswp__icn{opacity:0;transition:opacity .2s linear;animation:pswp-clockwise .6s linear infinite}.pswp__preloader--active .pswp__icn{opacity:.85}@keyframes pswp-clockwise{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.pswp__counter{height:30px;margin-top:15px;-webkit-margin-start:20px;margin-inline-start:20px;font-size:14px;line-height:30px;color:var(--pswp-icon-color);text-shadow:1px 1px 3px var(--pswp-icon-color-secondary);opacity:.85}.pswp--one-slide .pswp__counter{display:none}.photo-swipe-loading{position:absolute;top:0;left:0;display:flex;align-items:center;justify-content:center;width:100vw;height:100vh}.photo-swipe-bullets-indicator{position:absolute;bottom:30px;left:50%;display:flex;flex-direction:row;align-items:center;transform:translate(-50%)}.photo-swipe-bullet{width:12px;height:6px;margin:0 5px;border-radius:3px;background:#fff;transition:width var(--vp-tt),color var(--vp-ct)}.photo-swipe-bullet.active{width:30px;background:var(--vp-tc)}:root{--navbar-bg-color: var(--bg-color-float-blur);--sidebar-bg-color: var(--bg-color-blur)}html[data-theme=dark]{--navbar-bg-color: var(--bg-color-blur);--sidebar-bg-color: var(--bg-color-blur)}#app{--code-hl-bg-color: var(--code-highlight-line-color);--code-ln-color: var(--code-line-color);--code-ln-wrapper-width: var(--line-numbers-width);--code-tabs-nav-text-color: var(--code-color);--code-tabs-nav-bg-color: var(--code-border-color);--code-tabs-nav-hover-color: var(--code-highlight-line-color);--sidebar-space: var(--sidebar-width)}@media (max-width: 959px){#app{--navbar-height: var(--navbar-mobile-height);--navbar-vertical-padding: var(--navbar-mobile-vertical-padding);--navbar-horizontal-padding: var(--navbar-mobile-horizontal-padding);--sidebar-width: var(--sidebar-mobile-width)}}@media (min-width: 1440px){#app{--sidebar-space: clamp( var(--sidebar-width), max(0px, calc((100vw - var(--content-width)) / 2 - 2rem)), 100vw )}}.DocSearch-Button,.DocSearch{--docsearch-primary-color: var(--vp-tc);--docsearch-text-color: var(--vp-c);--docsearch-highlight-color: var(--vp-tc);--docsearch-muted-color: var(--light-grey);--docsearch-container-background: rgb(9 10 17 / 80%);--docsearch-modal-background: var(--bg-color-float);--docsearch-searchbox-background: var(--bg-color-secondary);--docsearch-searchbox-focus-background: var(--vp-bg);--docsearch-searchbox-shadow: inset 0 0 0 2px var(--vp-tc);--docsearch-hit-color: var(--vp-cl);--docsearch-hit-active-color: var(--vp-bg);--docsearch-hit-background: var(--vp-bg);--docsearch-hit-shadow: 0 1px 3px 0 var(--border-color);--docsearch-footer-background: var(--vp-bg)}html[data-theme=dark] .DocSearch-Button,html[data-theme=dark] .DocSearch{--docsearch-logo-color: var(--vp-c);--docsearch-modal-shadow: inset 1px 1px 0 0 #2c2e40, 0 3px 8px 0 #000309;--docsearch-key-shadow: inset 0 -2px 0 0 #282d55, inset 0 0 1px 1px #51577d, 0 2px 2px 0 rgb(3 4 9 / 30%);--docsearch-key-gradient: linear-gradient(-225deg, #444950, #1c1e21);--docsearch-footer-shadow: inset 0 1px 0 0 rgb(73 76 106 / 50%), 0 -4px 8px 0 rgb(0 0 0 / 20%)}#nprogress{--nprogress-color: var(--vp-tc)}.search-box{--search-bg-color: var(--vp-bg);--search-accent-color: var(--vp-tc);--search-text-color: var(--vp-c);--search-border-color: var(--border-color);--search-item-text-color: var(--vp-clt);--search-item-focus-bg-color: var(--bg-color-secondary)}.external-link-icon{--external-link-icon-color: var(--light-grey)}html,body{margin:0;padding:0;background:#fff}body{min-height:100vh;color:#2c3e50;font-size:16px;font-display:optional;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;-webkit-tap-highlight-color:transparent}@media print{body{font-size:12pt}}a{color:#3eaf7c;font-weight:500;text-decoration:none;overflow-wrap:break-word}kbd{display:inline-block;min-width:1em;margin-inline:.125rem;padding:.25em;border:1px solid #eee;border-radius:.25em;box-shadow:1px 1px 4px #00000026;line-height:1;letter-spacing:-.1em;text-align:center}code{margin:0;padding:.2rem .4rem;border-radius:5px;background:rgba(127,127,127,.12);font-size:.85em;overflow-wrap:break-word}table code{padding:.1rem .4rem}p a code{color:#3eaf7c;font-weight:400}strong{font-weight:600}h1,h2,h3,h4,h5,h6{font-weight:500;line-height:1.25;overflow-wrap:break-word}h1:hover .header-anchor,h2:hover .header-anchor,h3:hover .header-anchor,h4:hover .header-anchor,h5:hover .header-anchor,h6:hover .header-anchor{opacity:1}h1{font-size:2rem}h2{padding-bottom:.3rem;border-bottom:1px solid #eaecef;font-size:1.65rem}h3{font-size:1.35rem}h4{font-size:1.15rem}h5{font-size:1.05rem}h6{font-size:1rem}a.header-anchor{float:left;margin-top:.125em;-webkit-margin-start:-.87em;margin-inline-start:-.87em;-webkit-padding-end:.23em;padding-inline-end:.23em;font-size:.85em;opacity:0;transition:opacity .2s}@media print{a.header-anchor{display:none!important}}a.header-anchor:hover{text-decoration:none}a.header-anchor:focus-visible{opacity:1}p,ul,ol{line-height:1.6;overflow-wrap:break-word}@media print{p,ul,ol{line-height:1.5}}ul,ol{-webkit-padding-start:1.2em;padding-inline-start:1.2em}blockquote{margin:1rem 0;padding:.25rem 0 .25rem 1rem;-webkit-border-start:.2rem solid #ddd;border-inline-start:.2rem solid #ddd;color:#666;font-size:1rem;overflow-wrap:break-word}blockquote>p{margin:0}hr{border:0;border-top:1px solid #eaecef}table{display:block;overflow-x:auto;margin:1rem 0;border-collapse:collapse}tr:nth-child(2n){background:#f6f8fa}th,td{padding:.6em 1em;border:1px solid #dfe2e5}pre{direction:ltr}@page{margin:2cm;font-size:12pt;size:a4}@media print{*,:after,:before{box-shadow:none!important;text-shadow:none!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}a{color:inherit;font-weight:inherit!important;font-size:inherit!important;text-decoration:underline}a[href^="http://"]:after,a[href^="https://"]:after{content:" (" attr(href) ") "}abbr[title]:after{content:" (" attr(title) ")"}pre{border:1px solid #eee;white-space:pre-wrap!important}pre>code{white-space:pre-wrap!important}blockquote{-webkit-border-start:.2rem solid #ddd;border-inline-start:.2rem solid #ddd;color:inherit}blockquote,pre{orphans:5;widows:5}img,tr,canvas{page-break-inside:avoid}}@font-face{font-weight:400;font-style:normal;font-family:Crimson;src:url(data:font/truetype;charset=utf-8;base64,AAEAAAANAIAAAwBQRkZUTYr5mwEAAAyMAAAAHEdERUYAKQATAAAMbAAAAB5PUy8yVsJ0MgAAAVgAAABgY21hcBiKDzgAAAHcAAABWGdhc3D//wADAAAMZAAAAAhnbHlmr+DBdQAAA1AAAAdsaGVhZBZwt+8AAADcAAAANmhoZWEFawEuAAABFAAAACRobXR4BksA9gAAAbgAAAAibG9jYQlsC24AAAM0AAAAHG1heHAAEQBZAAABOAAAACBuYW1lLaFDVAAACrwAAAFrcG9zdAC1AHoAAAwoAAAAPAABAAAAAQAAqBd2H18PPPUACwQAAAAAANqqufwAAAAA2qq5/AAb/9wB4QMeAAAACAACAAAAAAAAAAEAAAMs/ywAXAH9AAAAAAHhAAEAAAAAAAAAAAAAAAAAAAAEAAEAAAANAFkAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAH1AZAABQAAApkCzAAAAI8CmQLMAAAB6wAzAQkAAAIABgMAAAAAAAAAAAABEAAAAAAAAAAAAAAAUGZFZADAADAAOQMs/ywAXAMsANQAAAABAAAAAAMYAAAAAAAgAAEBpwAfAAAAAAFVAAAB/QAfAH0ALQA+ABsAPgAyACgAPgAxAAAAAAADAAAAAwAAABwAAQAAAAAAUgADAAEAAAAcAAQANgAAAAQABAABAAAAOf//AAAAL///AAAAAQAEAAAAAAADAAQABQAGAAcACAAJAAoACwAMAAABBgAAAQAAAAAAAAABAgAAAAIAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAwQFBgcICQoLDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACYAJgAmAGIAwAEeAZIBzgJAApYC2gNiA7YAAQAf/9wBhwMeABIAAAEGBwYHATAXFjM2NzY3ASYnJjcBgxwLCgH+zgMECxIKCgIBLgEDAwMDHhQFBgP85wMEAQgJBgMOAwMDEwAAAAIAH//9Ad0CkAAQACEAABMWFxYXNjc2NzQnJicGBwYHNyY3NjcWFxYXFAcGByYnJjcfATo6amo7OQE5OmxrOjkBXQIlJEE5IyIBIyJEOSQjAgFOkV5eBAReXoqJXl4EBF5eggJ0UlEDA09Qe3xVVgMDU1OEAAAAAAEAff/9AYACkQA+AAA3FAcGBwYHBiMGFQYXNjc2MzIXFhc2JzQnIicmJyY1JjURNjc2MSYnJicjBgcGBwYVFBUUFxYXNjc2NzIXFhXkAQEEBRgYDAMBBB4ZGhweGxofBAEDDBgZBQQBAQMEAQIDBAIFNTZCAgMDBA0XFw0LBQV3GBMVDAgEBAUKCgUCAQICAQIFCgoFBAQIDBUTGAGnLxkbBAYFAQIZGh4BAgECBQUEAwUHBwEICRYAAAAAAQAtAAAB0QKRADoAADcGFxYXITY3NjcmJyYjIgcGBwYHBisBNjc2NzY3NjUmJyYnBgcGBxQXFhc2NzY3FhcWFxYHBgcGBwYHLgEEAwMBYwURERADBwYFBAMDAg8VEx/LJkBAOhsQDwIxMkxSMjIHCAYGCSYmPTIfHwEBCgoeLkJBQg8EBQQCETAwKQICAgEBBCgUEylJSUYhJicsRDIzAgY1NRoEBQYBEyEhAwEjIjYlJCQtQlBQSAAAAAABAD7/+wG+ApEASgAANwYXFhcWFxYzNjc2NyYnJic2NzY3JicmIwYHBgcUFxYXNjc2NxYXFhcGBwYHBgcUFRQXNjc2NxYXFhcGBwYnIicmJyYnJiciBwYXPwEIBwUaHB0VZU5NBAMvLi8eIB4DAywsKzwrKxgEAwUIHR4wLRscAQMvLz8BAQYKEhEQNSYmAgImJSsWExQPCw0NFREMDQE7DgsLBQwFBgE8PWpMKSoGECQkMkAiIQIdHyUHBwcBCRscAwEbGSpCIyUOAgMCAwwIAwUEAQEoKD9XJSQBBQYODg8PAQ0NFQAAAgAb//oB4QKTACIAJQAANxQXFhchFRQXFjMyNzYjNTM2NzY1NCcmJyMRNCcmIwYHBgcBExEbAgMFASEJCRIdCAkBRgIBAQUEBTwFAwgHCQkG/vjmxgUGBgOwBQIBAwKzAgQDCBAMDQEBlAYGBgEICQf+cwEs/tQAAQA+//sBvgKTAEoAADcGFxYXFhcWMzY3NjcmJyYnIgcGBzY3NjczMjc2NzY3NjU0JyYnBgcGByMGBwYHFBcWMzY3NjMWFxYHBgcGJyInJicmJyYnIgcGFz8BCAcFGhwdFWVOTQQBMjJbFx8gFwoJCQlWKB0dFQ4JCAQDBQMdHSKXCREQEgMCBA4bGhNYJyUBAiYlKxYTFA8LDQ0VEQwNATsOCwsFDAUGATw9akU2NwMFBggrMC8uAgICExcZBgQCAgMBAwQBMVNUWAUFBAYFBAMxMTNZIyQBBQYODg8PAQ0NFQAAAgAy//oBzQKXACAAMwAANxQXFhc2NzY3NicmJyIHBgc2NzY3NCcmJwYHBgcGBwYXNyY3Njc2FxYXFgcGBwYHJicmNzM1NV5aOTsCAioqahoiIRsnWFhFAwIHQ0tMOTAZGQFbBAQaGxkXRB8fAQEfIDE9Hh4E511FRwQDPT1ZPEJBBQwLF4Y9PRMGCwwBEiwsPDZFRkkTHyAbCAcBAjAwREYsLQEFREVQAAAAAAEAKP/7AdUCiwApAAATFhcWMzI3Njc2NzYzIQYHBgcWFxYzMjcBNjc2NzQnJiMiBwYjIQYHBgcoAwYHAwYDAwELEBEdAQUJYWJXAQ8PDgcDAQ4LCQgBAQEEBhUVFv7JBgsNDAH6DQMCAQEFKRITFMjHjQcFBgMCPxYSEwoEAgMBAhkrKiAAAAADAD7/9wG/ApIAKABBAFgAADcGFxYXNjc2NyYnJicmJzQ3Njc2NyYnJiMGBwYHFhcWFxYVFAcGBwYHNyY3Njc2MzIzMhcyFxYXFhcGBwYHIicmNxMmNzY3FhcWFRQHBgcGByIjIicmJyY3PwE1M1ZQODgDAykpMQIBAyYlJQMCMC9HRjExAgIiIiMCAiMvLwNTBBQTKgEBAQECAQIBEjU1CAEdHjMrISICGAMYGSYvGxoTEx8CAQIBBAMfJCQBoU8tLQECMjFPOC4uGwIBAgEWJiU7SCYoAjEwQzopKhMBAgECEykpQAQsIiEbAQEBBywsQjUeHQEiI0QBZSMhIAECJiYvKh8gFAEBAhAfIEYAAAIAMf/6AcsClwAgADMAABMGFxYXMjc2NwYHBgcUFxYXNjc2NzY3NjUmJyYnBgcGBzcmNzY3FhcWFRQHBgcGJyYnJjc0AyopahoiIRsoV1hFAwIHQ0tMODEZGQE2NF5ZOjoBWgMfHzE9Hh4EGhoaF0QeHwUBy0dBQgUMCxeFPj0SBwsLAREsLD01RkVPV0dFBQQ8PU8UPCwtAQVFRUklIRsHCAECMDBPAAAADACWAAEAAAAAAAEABwAQAAEAAAAAAAIABwAoAAEAAAAAAAMABwBAAAEAAAAAAAQABwBYAAEAAAAAAAUAHgCeAAEAAAAAAAYABwDNAAMAAQQJAAEADgAAAAMAAQQJAAIADgAYAAMAAQQJAAMADgAwAAMAAQQJAAQADgBIAAMAAQQJAAUAPABgAAMAAQQJAAYADgC9AEMAcgBpAG0AcwBvAG4AAENyaW1zb24AAEMAcgBpAG0AcwBvAG4AAENyaW1zb24AAEMAcgBpAG0AcwBvAG4AAENyaW1zb24AAEMAcgBpAG0AcwBvAG4AAENyaW1zb24AAFYAZQByAHMAaQBvAG4AIAAxAC4AMAA7ACAARgBvAG4AdABFAGQAaQB0AG8AcgAgACgAdgAxAC4AMAApAABWZXJzaW9uIDEuMDsgRm9udEVkaXRvciAodjEuMCkAAEMAcgBpAG0AcwBvAG4AAENyaW1zb24AAAACAAAAAAAAADIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0AAAABAAIAEwAUABUAFgAXABgAGQAaABsAHAAAAAH//wACAAEAAAAMAAAAFgAAAAIAAQADAAwAAQAEAAAAAgAAAAAAAAABAAAAANWkJwgAAAAA2qq5/AAAAADaqrn8) format("truetype")}html,body{background:var(--bg-color);transition:background var(--color-transition)}:root{color-scheme:light}html[data-theme=dark]{color-scheme:dark}body{color:var(--text-color);font-family:var(--font-family)}@media (min-width: 1440px){body{font-size:17px}}a{color:var(--theme-color)}kbd{border-color:var(--border-color-dark);background:var(--bg-color-secondary);font-family:var(--font-family-mono)}code{font-family:var(--font-family-mono);transition:background var(--color-transition),color var(--color-transition)}html[data-theme=dark] code{background:#333}p a code{color:var(--theme-color)}blockquote{border-color:#eee;color:#666;transition:border-color var(--color-transition),color var(--color-transition)}html[data-theme=dark] blockquote{border-color:#333}@media (max-width: 419px){h1{font-size:1.9rem}}h2{border-color:var(--border-color);transition:border-bottom-color var(--color-transition)}hr{border-color:var(--border-color);transition:border-top-color var(--color-transition)}tr:nth-child(2n){background:var(--bg-color-secondary)}th,td{border-color:var(--border-color-dark)}@media print{@page{--text-color: #000 !important;--bg-color: #fff !important}div[class*=language-]{position:relative!important}}.theme-hope-content:not(.custom)>*:first-child{margin-top:0}.breadcrumb{max-width:var(--content-width, 740px);-webkit-margin-start:auto;margin-inline-start:auto;-webkit-margin-end:auto;margin-inline-end:auto;-webkit-padding-start:2.5rem;padding-inline-start:2.5rem;-webkit-padding-end:2.5rem;padding-inline-end:2.5rem;position:relative;z-index:2;padding-top:1rem;font-size:15px}@media (max-width: 959px){.breadcrumb{-webkit-padding-start:1.5rem;padding-inline-start:1.5rem;-webkit-padding-end:1.5rem;padding-inline-end:1.5rem}}@media print{.breadcrumb{max-width:unset}}@media (max-width: 959px){.breadcrumb{font-size:14px}}@media (max-width: 419px){.breadcrumb{padding-top:.5rem;font-size:12.8px}}@media print{.breadcrumb{display:none}}.breadcrumb .icon{-webkit-margin-end:.25em;margin-inline-end:.25em}.breadcrumb a{display:inline-block;padding:0 .5em}.breadcrumb a:before{position:relative;bottom:.125rem;-webkit-margin-end:.25em;margin-inline-end:.25em}.breadcrumb a:hover{color:var(--theme-color)}.breadcrumb ol{margin:0;-webkit-padding-start:0;padding-inline-start:0;list-style:none}.breadcrumb li{display:inline-block;line-height:1.5}.breadcrumb li:first-child a{-webkit-padding-start:0;padding-inline-start:0}.breadcrumb li:last-child a{-webkit-padding-end:0;padding-inline-end:0}.breadcrumb li.is-active a{color:var(--light-grey);cursor:default;pointer-events:none}.breadcrumb li+li:before{content:"/";color:var(--light-grey)}.toggle-sidebar-wrapper{position:fixed;top:var(--navbar-height);bottom:0;left:var(--sidebar-space);z-index:100;display:flex;align-items:center;justify-content:center;font-size:2rem;transition:left var(--transform-transition)}@media (max-width: 719px){.toggle-sidebar-wrapper{display:none}}@media (min-width: 1440px){.toggle-sidebar-wrapper{display:none}}html[dir=rtl] .toggle-sidebar-wrapper{right:var(--sidebar-space);left:unset}.toggle-sidebar-wrapper:hover{background:rgba(127,127,127,.05);cursor:pointer}.toggle-sidebar-wrapper .arrow{display:inline-block;vertical-align:middle;width:1em;height:1em;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='rgba(0,0,0,0.5)' d='M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z'/%3E%3C/svg%3E");line-height:normal;transition:all .3s}html[data-theme=dark] .toggle-sidebar-wrapper .arrow{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='rgba(255,255,255,0.5)' d='M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z'/%3E%3C/svg%3E")}.toggle-sidebar-wrapper .arrow.down{transform:rotate(180deg)}html[dir=rtl] .toggle-sidebar-wrapper .arrow.down{transform:rotate(-180deg)}.toggle-sidebar-wrapper .arrow.end{transform:rotate(90deg)}html[dir=rtl] .toggle-sidebar-wrapper .arrow.end,.toggle-sidebar-wrapper .arrow.start{transform:rotate(-90deg)}html[dir=rtl] .toggle-sidebar-wrapper .arrow.start{transform:rotate(90deg)}.theme-container{display:flex;flex-direction:column;justify-content:space-between;min-height:100vh}.theme-container .page{padding-top:var(--navbar-height);-webkit-padding-start:calc(var(--sidebar-space) + 2rem);padding-inline-start:calc(var(--sidebar-space) + 2rem)}@media (max-width: 719px){.theme-container .page{-webkit-padding-start:0;padding-inline-start:0;-webkit-padding-end:0;padding-inline-end:0}}@media (min-width: 1440px){.theme-container .page{-webkit-padding-end:calc(100vw - var(--content-width) - var(--sidebar-space) - 6rem);padding-inline-end:calc(100vw - var(--content-width) - var(--sidebar-space) - 6rem)}}.theme-container .sidebar{top:var(--navbar-height)}.theme-container.no-navbar .page{padding-top:0}.theme-container.no-navbar .sidebar{top:0}@media (max-width: 719px){.theme-container.no-navbar .sidebar{top:0}}@media (max-width: 719px){.theme-container.hide-navbar .sidebar{top:0}}.theme-container.sidebar-collapsed .page{-webkit-padding-start:0;padding-inline-start:0}.theme-container.sidebar-collapsed .sidebar{box-shadow:none;transform:translate(-100%)}html[dir=rtl] .theme-container.sidebar-collapsed .sidebar{transform:translate(100%)}.theme-container.sidebar-collapsed .toggle-sidebar-wrapper{left:0}html[dir=rtl] .theme-container.sidebar-collapsed .toggle-sidebar-wrapper{right:0;left:unset}.theme-container.no-sidebar .page{-webkit-padding-start:0;padding-inline-start:0;-webkit-padding-end:0;padding-inline-end:0}@media (min-width: 1440px){.theme-container.no-sidebar.has-toc .page{-webkit-padding-end:16rem;padding-inline-end:16rem}}.theme-container.no-sidebar .toggle-sidebar-button,.theme-container.no-sidebar .toggle-sidebar-wrapper,.theme-container.no-sidebar .sidebar{display:none}.theme-container.sidebar-open .sidebar{box-shadow:2px 0 8px var(--card-shadow);transform:translate(0)}.fade-slide-y-enter-active{transition:all .3s ease!important}.fade-slide-y-leave-active{transition:all .3s cubic-bezier(1,.5,.8,1)!important}.fade-slide-y-enter-from,.fade-slide-y-leave-to{opacity:0;transform:translateY(10px)}@keyframes bounce{0%{transform:scale(1) translateY(0)}10%{transform:scale(1.1,.9) translateY(0)}30%{transform:scale(.9,1.1) translateY(-.5em)}50%{transform:scale(1.05,.95) translateY(0)}57%{transform:scale(1) translateY(-.125em)}64%{transform:scale(1) translateY(0)}to{transform:scale(1) translateY(0)}}.feature-header{margin:0 1.75rem}.feature-wrapper{display:flex;flex-wrap:wrap;align-content:stretch;align-items:stretch;justify-content:center}@media print{.feature-wrapper{display:block}}.feature-wrapper:first-child{border-top:1px solid var(--border-color);transition:border-color var(--color-transition)}.feature-item{position:relative;flex-basis:calc(33% - 3rem);margin:.5rem;padding:1rem;border-radius:.5rem;transition:background var(--color-transition),box-shadow var(--color-transition),transform var(--transform-transition)}@media (min-width: 1440px){.feature-item{flex-basis:calc(25% - 3rem)}}@media (max-width: 959px){.feature-item{flex-basis:calc(50% - 3rem)}}@media (max-width: 719px){.feature-item{flex-basis:100%;font-size:.95rem}}@media (max-width: 419px){.feature-item{margin:.5rem 0;font-size:.9rem}}.feature-item.link{cursor:pointer}@media print{.feature-item.link{text-decoration:none}}.feature-item .icon{display:inline-block;width:1.1em;-webkit-margin-end:.5rem;margin-inline-end:.5rem;color:var(--theme-color);font-weight:400;font-size:1.1em}.feature-item:hover{background-color:var(--bg-color-secondary);box-shadow:0 2px 12px 0 var(--card-shadow);transform:scale(1.05)}.feature-item:only-child{flex-basis:100%}.feature-item:first-child:nth-last-child(2),.feature-item:nth-child(2):last-child{flex-basis:calc(50% - 3rem)}@media (max-width: 719px){.feature-item:first-child:nth-last-child(2),.feature-item:nth-child(2):last-child{flex-basis:100%}}.feature-item h3{margin:.25rem 0 .5rem;color:var(--text-color-light);font-weight:700;font-size:1.3rem}@media (max-width: 419px){.feature-item h3{font-size:1.2rem}}.feature-item p{margin:0;color:var(--text-color-lighter);line-height:1.4}.footer-wrapper{position:relative;display:flex;flex-wrap:wrap;align-items:center;justify-content:space-evenly;padding-top:.75rem;padding-bottom:.75rem;-webkit-padding-start:calc(var(--sidebar-space) + 2rem);padding-inline-start:calc(var(--sidebar-space) + 2rem);-webkit-padding-end:2rem;padding-inline-end:2rem;border-top:1px solid var(--border-color);background:var(--bg-color);color:var(--dark-grey);text-align:center;transition:border-top-color var(--color-transition),background var(--color-transition),padding var(--transform-transition)}@media (max-width: 719px){.footer-wrapper{-webkit-padding-start:2rem;padding-inline-start:2rem}}@media (min-width: 1440px){.footer-wrapper{z-index:50;-webkit-padding-start:2rem;padding-inline-start:2rem}}@media print{.footer-wrapper{margin:0!important;padding:0!important}}@media (max-width: 419px){.footer-wrapper{display:block}}.no-sidebar .footer-wrapper,.sidebar-collapsed .footer-wrapper{-webkit-padding-start:2rem;padding-inline-start:2rem}.footer-wrapper .footer{margin:.5rem 1rem;font-size:14px}@media print{.footer-wrapper .footer{display:none}}.footer-wrapper .copyright{margin:6px 0;font-size:13px}.page:not(.not-found)+.footer-wrapper{margin-top:-2rem}@media (min-width: 959px){.hero-info-wrapper{display:flex;align-items:center;justify-content:space-evenly}}.hero-info-wrapper img{display:block;max-width:100%;max-height:18rem;margin:1rem}@media (max-width: 959px){.hero-info-wrapper img{margin:2rem auto}}@media (max-width: 719px){.hero-info-wrapper img{max-height:16rem;margin:1.5rem auto}}@media (max-width: 419px){.hero-info-wrapper img{max-height:14rem}}.hero-info-wrapper img.light{display:block}html[data-theme=dark] .hero-info-wrapper img.light,.hero-info-wrapper img.dark{display:none}html[data-theme=dark] .hero-info-wrapper img.dark{display:block}.hero-info-wrapper h1{margin:.5rem 0;background:linear-gradient(120deg,var(--theme-color-light),var(--theme-color) 30%,#3e71af 100%);-webkit-background-clip:text;background-clip:text;font-weight:700;font-size:3.6rem;line-height:1.5;-webkit-text-fill-color:transparent}@media (max-width: 719px){.hero-info-wrapper h1{margin:0;font-size:2.5rem}}@media (max-width: 959px){.hero-info-wrapper h1{text-align:center}}@media (max-width: 419px){.hero-info-wrapper h1{margin:0 auto;font-size:2rem}}.hero-info-wrapper .description,.hero-info-wrapper .actions{margin:1.8rem 0}@media (max-width: 719px){.hero-info-wrapper .description,.hero-info-wrapper .actions{margin:1.5rem 0}}@media (max-width: 959px){.hero-info-wrapper .description,.hero-info-wrapper .actions{margin:1.5rem auto;text-align:center}}@media (max-width: 419px){.hero-info-wrapper .description,.hero-info-wrapper .actions{margin:1.2rem 0}}.hero-info-wrapper .description{max-width:35rem;color:var(--text-color-bright);font-weight:500;font-size:1.6rem;line-height:1.3}@media (max-width: 719px){.hero-info-wrapper .description{font-size:1.4rem}}@media (max-width: 419px){.hero-info-wrapper .description{font-size:1.2rem}}.hero-info-wrapper .action-button{display:inline-block;overflow:hidden;min-width:4rem;margin:.5rem;padding:.5em 1.5rem;border-radius:2rem;background:var(--bg-color-secondary);color:var(--text-color);font-size:1.2rem;text-align:center;transition:color var(--color-transition),color var(--color-transition),transform var(--transform-transition)}@media (max-width: 719px){.hero-info-wrapper .action-button{padding:.5rem 1rem;font-size:1.1rem}}@media (max-width: 419px){.hero-info-wrapper .action-button{font-size:1rem}}@media print{.hero-info-wrapper .action-button{text-decoration:none}}.hero-info-wrapper .action-button:hover{background:var(--bg-color-tertiary)}.hero-info-wrapper .action-button.primary{border-color:var(--theme-color);background:var(--theme-color);color:var(--white)}.hero-info-wrapper .action-button.primary:hover{border-color:var(--theme-color-light);background:var(--theme-color-light)}.home.project:not(.pure) .hero-info-wrapper .action-button:active{transform:scale(.96)}.home.project{--content-width: var(--home-page-width);display:block;flex:1;padding-top:var(--navbar-height)}.home.project .hero-info-wrapper{max-width:var(--home-page-width);-webkit-margin-start:auto;margin-inline-start:auto;-webkit-margin-end:auto;margin-inline-end:auto;-webkit-padding-start:2.5rem;padding-inline-start:2.5rem;-webkit-padding-end:2.5rem;padding-inline-end:2.5rem}@media (max-width: 959px){.home.project .hero-info-wrapper{-webkit-padding-start:1.5em;padding-inline-start:1.5em;-webkit-padding-end:1.5rem;padding-inline-end:1.5rem}}@media print{.home.project .hero-info-wrapper{max-width:unset}}.home.project .feature-panel{max-width:var(--home-page-width);-webkit-margin-start:auto;margin-inline-start:auto;-webkit-margin-end:auto;margin-inline-end:auto;-webkit-padding-start:1rem;padding-inline-start:1rem;-webkit-padding-end:1rem;padding-inline-end:1rem}@media print{.home.project .feature-panel{max-width:unset}}.home.project .theme-hope-content{padding-bottom:1.5rem}.not-found-hint{padding:2rem}.not-found-hint .error-code{margin:0;font-weight:700;font-size:4rem;line-height:4rem}.not-found-hint .error-title{font-weight:700}.not-found-hint .error-hint{margin:0;padding:12px 0;font-weight:600;font-size:20px;line-height:20px;letter-spacing:2px}.page.not-found{display:flex;flex-direction:column;align-items:center;justify-content:center;box-sizing:border-box;width:100vw;max-width:var(--home-page-width);margin:0 auto;padding:calc(var(--navbar-height) + 1rem) 1rem 1rem!important;text-align:center}.page.not-found .action-button{display:inline-block;box-sizing:border-box;margin:.25rem;padding:.75rem 1rem;border-width:0;border-bottom:1px solid var(--theme-color-dark);border-radius:3rem;background:var(--theme-color);color:var(--white);outline:none;font-size:1rem;transition:background .1s ease}.page.not-found .action-button:hover{background:var(--theme-color-light);cursor:pointer}.page-nav{max-width:var(--content-width, 740px);-webkit-margin-start:auto;margin-inline-start:auto;-webkit-margin-end:auto;margin-inline-end:auto;-webkit-padding-start:2.5rem;padding-inline-start:2.5rem;-webkit-padding-end:2.5rem;padding-inline-end:2.5rem;display:flex;flex-wrap:wrap;min-height:2rem;margin-top:0;padding-top:.5rem;padding-bottom:.5rem;border-top:1px solid var(--border-color);transition:border-top var(--color-transition)}@media (max-width: 959px){.page-nav{-webkit-padding-start:1.5rem;padding-inline-start:1.5rem;-webkit-padding-end:1.5rem;padding-inline-end:1.5rem}}@media print{.page-nav{max-width:unset}}@media print{.page-nav{display:none}}.page-nav .nav-link{display:inline-block;flex-grow:1;margin:.25rem;padding:.25rem .5rem;border:1px solid var(--border-color);border-radius:.25rem}.page-nav .nav-link:hover{background:var(--bg-color-secondary)}.page-nav .nav-link .hint{color:var(--light-grey);font-size:.875rem;line-height:2}.page-nav .nav-link .arrow{display:inline-block;vertical-align:middle;width:1em;height:1em;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='rgba(0,0,0,0.5)' d='M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z'/%3E%3C/svg%3E");line-height:normal;transition:all .3s;font-size:.75rem}html[data-theme=dark] .page-nav .nav-link .arrow{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='rgba(255,255,255,0.5)' d='M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z'/%3E%3C/svg%3E")}.page-nav .nav-link .arrow.down{transform:rotate(180deg)}html[dir=rtl] .page-nav .nav-link .arrow.down{transform:rotate(-180deg)}.page-nav .nav-link .arrow.end{transform:rotate(90deg)}html[dir=rtl] .page-nav .nav-link .arrow.end,.page-nav .nav-link .arrow.start{transform:rotate(-90deg)}html[dir=rtl] .page-nav .nav-link .arrow.start{transform:rotate(90deg)}.page-nav .prev{text-align:start}.page-nav .prev .icon{-webkit-margin-end:.25em;margin-inline-end:.25em}.page-nav .next{text-align:end}.page-nav .next .icon{-webkit-margin-start:.25em;margin-inline-start:.25em}.page-title{max-width:var(--content-width, 740px);-webkit-margin-start:auto;margin-inline-start:auto;-webkit-margin-end:auto;margin-inline-end:auto;-webkit-padding-start:2.5rem;padding-inline-start:2.5rem;-webkit-padding-end:2.5rem;padding-inline-end:2.5rem;position:relative;z-index:1;padding-top:1rem;padding-bottom:0}@media (max-width: 959px){.page-title{-webkit-padding-start:1.5rem;padding-inline-start:1.5rem;-webkit-padding-end:1.5rem;padding-inline-end:1.5rem}}@media print{.page-title{max-width:unset}}@media print{.page-title{-webkit-padding-start:0!important;padding-inline-start:0!important;-webkit-padding-end:0!important;padding-inline-end:0!important}}@media (max-width: 959px){.page-title{padding-top:.5rem}}.page-title h1{margin-top:calc(0px - var(--navbar-height))!important;margin-bottom:1rem;padding-top:var(--navbar-height)!important;font-size:2.2rem}@media (max-width: 959px){.page-title h1{margin-bottom:.5rem}}.page-title h1 .icon{-webkit-margin-end:.25em;margin-inline-end:.25em;color:var(--theme-color);font-size:.9em}.theme-hope-content:not(.custom){padding-top:0!important}.theme-hope-content:not(.custom) h1:first-child,.theme-hope-content:not(.custom) h2:first-child,.theme-hope-content:not(.custom) h3:first-child,.theme-hope-content:not(.custom) h4:first-child,.theme-hope-content:not(.custom) h5:first-child,.theme-hope-content:not(.custom) h6:first-child{margin-top:calc(.5rem - var(--navbar-height))!important;padding-top:var(--navbar-height)!important}.theme-hope-content:not(.custom)>h1:first-child{display:none}.page{display:block;flex-grow:1;padding-bottom:2rem;transition:padding var(--transform-transition)}@media print{.page{min-height:auto!important;margin:0!important;padding:0!important}}.page-cover{-o-object-fit:cover;object-fit:cover;width:calc(100% + 2rem);max-height:25vh;margin-left:-2rem}@media (max-width: 719px){.page-cover{width:100%;margin:0;border-radius:0}}@media (min-width: 1440px){.page-cover{width:calc(100% - 2rem);margin:0 1rem;border-radius:.5rem}}.page-cover .sidebar-collapsed{width:100%;margin-left:0}.skip-link{top:.25rem;left:.25rem;z-index:999;padding:.65rem 1.5rem;border-radius:.5rem;background:var(--bg-color);color:var(--theme-color);box-shadow:var(--card-shadow);font-weight:700;font-size:.9em;text-decoration:none}@media print{.skip-link{display:none}}.skip-link:focus{clip:auto;width:auto;height:auto;-webkit-clip-path:none;clip-path:none}.theme-hope-content pre{overflow:auto;margin:.85rem 0;padding:1rem;border-radius:6px;line-height:1.375}.theme-hope-content pre code{padding:0;border-radius:0;background:transparent!important;color:var(--code-color);font-family:var(--font-family-mono);text-align:left;white-space:pre;word-spacing:normal;word-wrap:normal;word-break:normal;overflow-wrap:unset;-webkit-hyphens:none;hyphens:none;transition:color var(--color-transition);-webkit-font-smoothing:auto;-moz-osx-font-smoothing:auto}@media print{.theme-hope-content pre code{white-space:pre-wrap}}.theme-hope-content .line-number{font-family:var(--font-family-mono)}div[class*=language-]{position:relative;border-radius:6px;background:var(--code-bg-color);transition:background var(--color-transition)}@media (max-width: 419px){.theme-hope-content>div[class*=language-]{margin:.85rem -1.5rem;border-radius:0}}div[class*=language-]:before{content:attr(data-ext);position:absolute;top:.8em;right:1em;z-index:3;color:var(--code-line-color);font-size:.75rem;transition:color var(--color-transition)}div[class*=language-] pre{position:relative;z-index:1}div[class*=language-] .highlight-lines{position:absolute;top:0;left:0;width:100%;padding-top:1rem;line-height:1.375;-webkit-user-select:none;-moz-user-select:none;user-select:none}div[class*=language-] .highlight-line{background:var(--code-highlight-line-color);transition:background var(--color-transition)}div[class*=language-].line-numbers-mode:after{content:"";position:absolute;top:0;left:0;z-index:2;width:var(--line-numbers-width);height:100%;border-right:1px solid var(--code-highlight-line-color);border-radius:6px 0 0 6px;transition:border-color var(--color-transition)}@media (max-width: 419px){div[class*=language-].line-numbers-mode:after{border-radius:0}}@media print{div[class*=language-].line-numbers-mode:after{display:none}}div[class*=language-].line-numbers-mode .highlight-line{position:relative}div[class*=language-].line-numbers-mode .highlight-line:before{content:" ";position:absolute;top:0;left:0;z-index:3;display:block;width:var(--line-numbers-width);height:100%}div[class*=language-].line-numbers-mode pre{vertical-align:middle;margin-left:var(--line-numbers-width);padding-left:.5rem}@media print{div[class*=language-].line-numbers-mode pre{margin-left:0;padding-left:1rem}}div[class*=language-].line-numbers-mode .line-numbers{position:absolute;top:0;left:0;width:var(--line-numbers-width);padding:1rem 0;color:var(--code-line-color);line-height:1.375;counter-reset:line-number;text-align:center;transition:color var(--color-transition);transform:translateY(1px)}@media print{div[class*=language-].line-numbers-mode .line-numbers{display:none}}div[class*=language-].line-numbers-mode .line-number{position:relative;z-index:4;height:1.375em;-webkit-user-select:none;-moz-user-select:none;user-select:none}div[class*=language-].line-numbers-mode .line-number:before{content:counter(line-number);font-size:.85em;counter-increment:line-number}div[class*=language-]:not(.line-numbers-mode) .line-numbers{display:none}:root{--code-color: #D8DEE9;--code-line-color: rgba(216, 222, 233, .67);--code-bg-color: #2e3440;--code-border-color: #38455e;--code-highlight-line-color: #343d4e}div[class*=language-] pre{background:transparent!important}.sr-only{position:absolute;overflow:hidden;clip:rect(0,0,0,0);width:1px;height:1px;margin:-1px;padding:0;border-width:0;white-space:nowrap;-webkit-user-select:none;-moz-user-select:none;user-select:none}@media print{.theme-hope-content{margin:0!important;-webkit-padding-start:0!important;padding-inline-start:0!important;-webkit-padding-end:0!important;padding-inline-end:0!important}}.theme-hope-content.custom{margin:0;padding:0}.theme-hope-content:not(.custom){max-width:var(--content-width, 740px);margin:0 auto;padding:2rem 2.5rem;padding-top:0}@media (max-width: 959px){.theme-hope-content:not(.custom){padding:1.5rem}}@media (max-width: 419px){.theme-hope-content:not(.custom){padding:1rem 1.5rem}}@media print{.theme-hope-content:not(.custom){max-width:unset}}.theme-hope-content:not(.custom)>h1,.theme-hope-content:not(.custom)>h2,.theme-hope-content:not(.custom)>h3,.theme-hope-content:not(.custom)>h4,.theme-hope-content:not(.custom)>h5,.theme-hope-content:not(.custom)>h6{margin-top:calc(.5rem - var(--navbar-height));margin-bottom:.5rem;padding-top:calc(1rem + var(--navbar-height));outline:none}.theme-container.no-navbar .theme-hope-content:not(.custom)>h1,.theme-container.no-navbar .theme-hope-content:not(.custom)>h2,.theme-container.no-navbar .theme-hope-content:not(.custom)>h3,.theme-container.no-navbar .theme-hope-content:not(.custom)>h4,.theme-container.no-navbar .theme-hope-content:not(.custom)>h5,.theme-container.no-navbar .theme-hope-content:not(.custom)>h6{margin-top:1.5rem;padding-top:0}.theme-hope-content:not(.custom)>p,.theme-hope-content:not(.custom)>ul p,.theme-hope-content:not(.custom)>ol p{text-align:justify;overflow-wrap:break-word;-webkit-hyphens:auto;hyphens:auto}@media (max-width: 419px){.theme-hope-content:not(.custom)>p,.theme-hope-content:not(.custom)>ul p,.theme-hope-content:not(.custom)>ol p{text-align:start}}@media print{.theme-hope-content:not(.custom)>p,.theme-hope-content:not(.custom)>ul p,.theme-hope-content:not(.custom)>ol p{text-align:start}}.theme-hope-content a:hover{text-decoration:underline}.theme-hope-content img{max-width:100%}@media (min-width: 1280px){.chart-wrapper::-webkit-scrollbar,.flowchart-wrapper::-webkit-scrollbar,.mermaid-wrapper::-webkit-scrollbar{width:8px;height:8px}.chart-wrapper::-webkit-scrollbar-track-piece,.flowchart-wrapper::-webkit-scrollbar-track-piece,.mermaid-wrapper::-webkit-scrollbar-track-piece{border-radius:8px;background:rgba(0,0,0,.1)}}html[dir=rtl] a.header-anchor{float:right}#docsearch-container{min-width:145.7px!important}@media (max-width: 959px){#docsearch-container{min-width:36px!important}}.DocSearch.DocSearch-Button{margin-left:0}@media (max-width: 959px){.DocSearch.DocSearch-Button{min-width:36px!important}}.DocSearch .DocSearch-Button-Placeholder{display:inline-block;padding:4px 12px 4px 6px;font-size:14px}@media (max-width: 719px){.DocSearch .DocSearch-Button-Placeholder{display:none}}.DocSearch .DocSearch-Search-Icon{width:1.25em;height:1.25em}@media (max-width: 959px){.DocSearch .DocSearch-Button-Keys{display:none}}.DocSearch .DocSearch-Button-Key{background:var(--bg-color);box-shadow:none}@media (prefers-reduced-motion: no-preference){:root{scroll-behavior:smooth}}::-webkit-scrollbar{width:6px;height:6px}::-webkit-scrollbar-track-piece{border-radius:6px;background:rgba(0,0,0,.1)}::-webkit-scrollbar-thumb{border-radius:6px;background:var(--theme-color)}::-webkit-scrollbar-thumb:active{background:var(--theme-color-light)}@media (max-width: 719px){.hide-in-mobile{display:none!important}}@media (max-width: 959px){.hide-in-pad{display:none!important}}.page-author-item{display:inline-block;margin:0 4px;font-weight:400;overflow-wrap:break-word}.page-category-info{flex-wrap:wrap}.page-category-item{display:inline-block;margin:.125em .25em;padding:0 .25em;border-radius:.25em;background:var(--bg-color-secondary);color:var(--text-color-light);font-weight:700;font-size:.75rem;line-height:2;transition:background var(--color-transition),color var(--color-transition)}@media print{.page-category-item{padding:0;font-weight:400}.page-category-item:after{content:", "}.page-category-item:last-of-type:after{content:""}}.page-category-item.clickable>span:hover{color:var(--theme-color);cursor:pointer}.page-category-item.category0{background:#fde5e7;color:#ec2f3e}html[data-theme=dark] .page-category-item.category0{background:#340509;color:#ba111f}.page-category-item.category0:hover{background:#f9bec3}html[data-theme=dark] .page-category-item.category0:hover{background:#53080e}.page-category-item.category1{background:#ffeee8;color:#fb7649}html[data-theme=dark] .page-category-item.category1{background:#441201;color:#f54205}.page-category-item.category1:hover{background:#fed4c6}html[data-theme=dark] .page-category-item.category1:hover{background:#6d1d02}.page-category-item.category2{background:#fef5e7;color:#f5b041}html[data-theme=dark] .page-category-item.category2{background:#3e2703;color:#e08e0b}.page-category-item.category2:hover{background:#fce6c4}html[data-theme=dark] .page-category-item.category2:hover{background:#633f05}.page-category-item.category3{background:#eafaf1;color:#55d98d}html[data-theme=dark] .page-category-item.category3{background:#0c331c;color:#29b866}.page-category-item.category3:hover{background:#caf3db}html[data-theme=dark] .page-category-item.category3:hover{background:#12522d}.page-category-item.category4{background:#e6f9ee;color:#36d278}html[data-theme=dark] .page-category-item.category4{background:#092917;color:#219552}.page-category-item.category4:hover{background:#c0f1d5}html[data-theme=dark] .page-category-item.category4:hover{background:#0f4224}.page-category-item.category5{background:#e1fcfc;color:#16e1e1}html[data-theme=dark] .page-category-item.category5{background:#042929;color:#0e9595}.page-category-item.category5:hover{background:#b4f8f8}html[data-theme=dark] .page-category-item.category5:hover{background:#064242}.page-category-item.category6{background:#e4f0fe;color:#2589f6}html[data-theme=dark] .page-category-item.category6{background:#021b36;color:#0862c3}.page-category-item.category6:hover{background:#bbdafc}html[data-theme=dark] .page-category-item.category6:hover{background:#042c57}.page-category-item.category7{background:#f7f1fd;color:#bb8ced}html[data-theme=dark] .page-category-item.category7{background:#2a0b4b;color:#9851e4}.page-category-item.category7:hover{background:#eadbfa}html[data-theme=dark] .page-category-item.category7:hover{background:#431277}.page-category-item.category8{background:#fdeaf5;color:#ef59ab}html[data-theme=dark] .page-category-item.category8{background:#400626;color:#e81689}.page-category-item.category8:hover{background:#facbe5}html[data-theme=dark] .page-category-item.category8:hover{background:#670a3d}.page-original-info{position:relative;display:inline-block;vertical-align:middle;overflow:hidden;padding:0 .5em;border:.5px solid var(--dark-grey);border-radius:.75em;background:var(--bg-color);font-size:.75em;line-height:1.5}.page-info{display:flex;flex-wrap:wrap;align-content:stretch;align-items:center;justify-content:flex-start;color:var(--dark-grey);font-size:14px}@media print{.page-info{display:flex!important}}.page-info>span{display:flex;align-items:center;max-width:100%;-webkit-margin-end:.5em;margin-inline-end:.5em;line-height:2}@media (min-width: 1440px){.page-info>span{font-size:1.1em}}@media (max-width: 419px){.page-info>span{-webkit-margin-end:.3em;margin-inline-end:.3em;font-size:.875em}}@media print{.page-info>span{display:flex!important}}.page-info .icon{position:relative;display:inline-block;vertical-align:middle;width:1em;height:1em;-webkit-margin-end:.25em;margin-inline-end:.25em}.page-info a{color:inherit}.page-info a:hover,.page-info a:active{color:var(--theme-color)}.page-meta{max-width:var(--content-width, 740px);-webkit-margin-start:auto;margin-inline-start:auto;-webkit-margin-end:auto;margin-inline-end:auto;-webkit-padding-start:2.5rem;padding-inline-start:2.5rem;-webkit-padding-end:2.5rem;padding-inline-end:2.5rem;display:flex;flex-wrap:wrap;justify-content:space-between;overflow:auto;padding-top:.75rem;padding-bottom:.75rem}@media (max-width: 959px){.page-meta{-webkit-padding-start:1.5rem;padding-inline-start:1.5rem;-webkit-padding-end:1.5rem;padding-inline-end:1.5rem}}@media print{.page-meta{max-width:unset}}@media print{.page-meta{margin:0!important;-webkit-padding-start:0!important;padding-inline-start:0!important;-webkit-padding-end:0!important;padding-inline-end:0!important}}@media (max-width: 719px){.page-meta{display:block}}.page-meta .meta-item{flex-grow:1}.page-meta .meta-item .label{font-weight:500}.page-meta .meta-item .label:not(a){color:var(--text-color-lighter)}.page-meta .meta-item .info{color:var(--dark-grey);font-weight:400}.page-meta .git-info{text-align:end}.page-meta .edit-link{margin-top:.25rem;margin-bottom:.25rem;-webkit-margin-end:.5rem;margin-inline-end:.5rem;font-size:14px}@media print{.page-meta .edit-link{display:none}}.page-meta .edit-link .icon{position:relative;bottom:-.125em;width:1em;height:1em;-webkit-margin-end:.25em;margin-inline-end:.25em}.page-meta .update-time,.page-meta .contributors{margin-top:.25rem;margin-bottom:.25rem;font-size:14px}@media (max-width: 719px){.page-meta .update-time,.page-meta .contributors{font-size:13px;text-align:start}}.print-button{border-width:0;background:transparent;cursor:pointer;box-sizing:content-box;width:1rem;height:1rem;padding:.5rem;border-radius:.25em;color:inherit;font-size:1rem;transform:translateY(.25rem)}@media print{.print-button{display:none}}.page-tag-info{flex-wrap:wrap}.page-tag-item{position:relative;display:inline-block;vertical-align:middle;overflow:hidden;min-width:1.5rem;margin:.125rem;padding:.125rem .25rem .125rem .625rem;background:var(--bg-color-secondary);background:linear-gradient(135deg,transparent .75em,var(--bg-color-secondary) 0) top,linear-gradient(45deg,transparent .75em,var(--bg-color-secondary) 0) bottom;background-size:100% 52%!important;background-repeat:no-repeat!important;color:var(--text-color-light);font-weight:700;font-size:.625rem;line-height:1.5;text-align:center;transition:background var(--color-transition),color var(--color-transition)}@media print{.page-tag-item{padding:0;font-weight:400}.page-tag-item:after{content:", "}.page-tag-item:last-of-type:after{content:""}}.page-tag-item.clickable:hover{cursor:pointer}.page-tag-item.tag0{background:#fde5e7;background:linear-gradient(135deg,transparent .75em,#fde5e7 0) top,linear-gradient(45deg,transparent .75em,#fde5e7 0) bottom;color:#ec2f3e}html[data-theme=dark] .page-tag-item.tag0{background:#340509;background:linear-gradient(135deg,transparent .75em,#340509 0) top,linear-gradient(45deg,transparent .75em,#340509 0) bottom;color:#ba111f}.page-tag-item.tag0.clickable:hover{background:#f9bec3;background:linear-gradient(135deg,transparent .75em,#f9bec3 0) top,linear-gradient(45deg,transparent .75em,#f9bec3 0) bottom}html[data-theme=dark] .page-tag-item.tag0.clickable:hover{background:#53080e;background:linear-gradient(135deg,transparent .75em,#53080e 0) top,linear-gradient(45deg,transparent .75em,#53080e 0) bottom}.page-tag-item.tag1{background:#ffeee8;background:linear-gradient(135deg,transparent .75em,#ffeee8 0) top,linear-gradient(45deg,transparent .75em,#ffeee8 0) bottom;color:#fb7649}html[data-theme=dark] .page-tag-item.tag1{background:#441201;background:linear-gradient(135deg,transparent .75em,#441201 0) top,linear-gradient(45deg,transparent .75em,#441201 0) bottom;color:#f54205}.page-tag-item.tag1.clickable:hover{background:#fed4c6;background:linear-gradient(135deg,transparent .75em,#fed4c6 0) top,linear-gradient(45deg,transparent .75em,#fed4c6 0) bottom}html[data-theme=dark] .page-tag-item.tag1.clickable:hover{background:#6d1d02;background:linear-gradient(135deg,transparent .75em,#6d1d02 0) top,linear-gradient(45deg,transparent .75em,#6d1d02 0) bottom}.page-tag-item.tag2{background:#fef5e7;background:linear-gradient(135deg,transparent .75em,#fef5e7 0) top,linear-gradient(45deg,transparent .75em,#fef5e7 0) bottom;color:#f5b041}html[data-theme=dark] .page-tag-item.tag2{background:#3e2703;background:linear-gradient(135deg,transparent .75em,#3e2703 0) top,linear-gradient(45deg,transparent .75em,#3e2703 0) bottom;color:#e08e0b}.page-tag-item.tag2.clickable:hover{background:#fce6c4;background:linear-gradient(135deg,transparent .75em,#fce6c4 0) top,linear-gradient(45deg,transparent .75em,#fce6c4 0) bottom}html[data-theme=dark] .page-tag-item.tag2.clickable:hover{background:#633f05;background:linear-gradient(135deg,transparent .75em,#633f05 0) top,linear-gradient(45deg,transparent .75em,#633f05 0) bottom}.page-tag-item.tag3{background:#eafaf1;background:linear-gradient(135deg,transparent .75em,#eafaf1 0) top,linear-gradient(45deg,transparent .75em,#eafaf1 0) bottom;color:#55d98d}html[data-theme=dark] .page-tag-item.tag3{background:#0c331c;background:linear-gradient(135deg,transparent .75em,#0c331c 0) top,linear-gradient(45deg,transparent .75em,#0c331c 0) bottom;color:#29b866}.page-tag-item.tag3.clickable:hover{background:#caf3db;background:linear-gradient(135deg,transparent .75em,#caf3db 0) top,linear-gradient(45deg,transparent .75em,#caf3db 0) bottom}html[data-theme=dark] .page-tag-item.tag3.clickable:hover{background:#12522d;background:linear-gradient(135deg,transparent .75em,#12522d 0) top,linear-gradient(45deg,transparent .75em,#12522d 0) bottom}.page-tag-item.tag4{background:#e6f9ee;background:linear-gradient(135deg,transparent .75em,#e6f9ee 0) top,linear-gradient(45deg,transparent .75em,#e6f9ee 0) bottom;color:#36d278}html[data-theme=dark] .page-tag-item.tag4{background:#092917;background:linear-gradient(135deg,transparent .75em,#092917 0) top,linear-gradient(45deg,transparent .75em,#092917 0) bottom;color:#219552}.page-tag-item.tag4.clickable:hover{background:#c0f1d5;background:linear-gradient(135deg,transparent .75em,#c0f1d5 0) top,linear-gradient(45deg,transparent .75em,#c0f1d5 0) bottom}html[data-theme=dark] .page-tag-item.tag4.clickable:hover{background:#0f4224;background:linear-gradient(135deg,transparent .75em,#0f4224 0) top,linear-gradient(45deg,transparent .75em,#0f4224 0) bottom}.page-tag-item.tag5{background:#e1fcfc;background:linear-gradient(135deg,transparent .75em,#e1fcfc 0) top,linear-gradient(45deg,transparent .75em,#e1fcfc 0) bottom;color:#16e1e1}html[data-theme=dark] .page-tag-item.tag5{background:#042929;background:linear-gradient(135deg,transparent .75em,#042929 0) top,linear-gradient(45deg,transparent .75em,#042929 0) bottom;color:#0e9595}.page-tag-item.tag5.clickable:hover{background:#b4f8f8;background:linear-gradient(135deg,transparent .75em,#b4f8f8 0) top,linear-gradient(45deg,transparent .75em,#b4f8f8 0) bottom}html[data-theme=dark] .page-tag-item.tag5.clickable:hover{background:#064242;background:linear-gradient(135deg,transparent .75em,#064242 0) top,linear-gradient(45deg,transparent .75em,#064242 0) bottom}.page-tag-item.tag6{background:#e4f0fe;background:linear-gradient(135deg,transparent .75em,#e4f0fe 0) top,linear-gradient(45deg,transparent .75em,#e4f0fe 0) bottom;color:#2589f6}html[data-theme=dark] .page-tag-item.tag6{background:#021b36;background:linear-gradient(135deg,transparent .75em,#021b36 0) top,linear-gradient(45deg,transparent .75em,#021b36 0) bottom;color:#0862c3}.page-tag-item.tag6.clickable:hover{background:#bbdafc;background:linear-gradient(135deg,transparent .75em,#bbdafc 0) top,linear-gradient(45deg,transparent .75em,#bbdafc 0) bottom}html[data-theme=dark] .page-tag-item.tag6.clickable:hover{background:#042c57;background:linear-gradient(135deg,transparent .75em,#042c57 0) top,linear-gradient(45deg,transparent .75em,#042c57 0) bottom}.page-tag-item.tag7{background:#f7f1fd;background:linear-gradient(135deg,transparent .75em,#f7f1fd 0) top,linear-gradient(45deg,transparent .75em,#f7f1fd 0) bottom;color:#bb8ced}html[data-theme=dark] .page-tag-item.tag7{background:#2a0b4b;background:linear-gradient(135deg,transparent .75em,#2a0b4b 0) top,linear-gradient(45deg,transparent .75em,#2a0b4b 0) bottom;color:#9851e4}.page-tag-item.tag7.clickable:hover{background:#eadbfa;background:linear-gradient(135deg,transparent .75em,#eadbfa 0) top,linear-gradient(45deg,transparent .75em,#eadbfa 0) bottom}html[data-theme=dark] .page-tag-item.tag7.clickable:hover{background:#431277;background:linear-gradient(135deg,transparent .75em,#431277 0) top,linear-gradient(45deg,transparent .75em,#431277 0) bottom}.page-tag-item.tag8{background:#fdeaf5;background:linear-gradient(135deg,transparent .75em,#fdeaf5 0) top,linear-gradient(45deg,transparent .75em,#fdeaf5 0) bottom;color:#ef59ab}html[data-theme=dark] .page-tag-item.tag8{background:#400626;background:linear-gradient(135deg,transparent .75em,#400626 0) top,linear-gradient(45deg,transparent .75em,#400626 0) bottom;color:#e81689}.page-tag-item.tag8.clickable:hover{background:#facbe5;background:linear-gradient(135deg,transparent .75em,#facbe5 0) top,linear-gradient(45deg,transparent .75em,#facbe5 0) bottom}html[data-theme=dark] .page-tag-item.tag8.clickable:hover{background:#670a3d;background:linear-gradient(135deg,transparent .75em,#670a3d 0) top,linear-gradient(45deg,transparent .75em,#670a3d 0) bottom}.toc-place-holder{-webkit-margin-start:auto;margin-inline-start:auto;-webkit-margin-end:auto;margin-inline-end:auto;-webkit-padding-start:2.5rem;padding-inline-start:2.5rem;-webkit-padding-end:2.5rem;padding-inline-end:2.5rem;position:sticky;top:calc(var(--navbar-height) + 2rem);z-index:99;max-width:var(--content-width, 740px)}@media (max-width: 959px){.toc-place-holder{-webkit-padding-start:1.5rem;padding-inline-start:1.5rem;-webkit-padding-end:1.5rem;padding-inline-end:1.5rem}}@media print{.toc-place-holder{max-width:unset}}.toc-place-holder+.theme-hope-content:not(.custom){padding-top:0}#toc{position:absolute;left:calc(100% + 1rem);display:none;min-width:10rem;max-width:15rem}@media (min-width: 1440px){.has-toc #toc{display:block}}@media print{#toc{display:none!important}}html[dir=rtl] #toc{right:calc(100% + 1rem);left:unset}#toc .toc-header{margin-bottom:.75rem;-webkit-margin-start:.5rem;margin-inline-start:.5rem;font-weight:600;font-size:.875rem}#toc .toc-wrapper{position:relative;overflow-x:hidden;overflow-y:auto;max-height:75vh;margin:0 .5rem;-webkit-padding-start:8px;padding-inline-start:8px;text-overflow:ellipsis;white-space:nowrap;scroll-behavior:smooth}#toc .toc-wrapper::-webkit-scrollbar-track-piece{background:transparent}#toc .toc-wrapper::-webkit-scrollbar{width:3px}#toc .toc-wrapper::-webkit-scrollbar-thumb:vertical{background:#ddd}html[data-theme=dark] #toc .toc-wrapper::-webkit-scrollbar-thumb:vertical{background:#333}#toc .toc-wrapper:before{content:" ";position:absolute;top:0;bottom:0;left:0;z-index:-1;width:2px;background:var(--border-color)}html[dir=rtl] #toc .toc-wrapper:before{right:0;left:unset}#toc .toc-list{position:relative;margin:0;padding:0}#toc .toc-marker{content:" ";position:absolute;top:0;left:0;z-index:2;width:2px;height:1.7rem;background:var(--theme-color);transition:top var(--vp-tt)}html[dir=rtl] #toc .toc-marker{right:0;left:unset}#toc .toc-link{position:relative;display:block;overflow:hidden;max-width:100%;color:var(--light-grey);line-height:inherit;text-overflow:ellipsis;white-space:nowrap}#toc .toc-link.level2{-webkit-padding-start:0px;padding-inline-start:0px;font-size:14px}#toc .toc-link.level3{-webkit-padding-start:8px;padding-inline-start:8px;font-size:13px}#toc .toc-link.level4{-webkit-padding-start:16px;padding-inline-start:16px;font-size:12px}#toc .toc-link.level5{-webkit-padding-start:24px;padding-inline-start:24px;font-size:11px}#toc .toc-link.level6{-webkit-padding-start:32px;padding-inline-start:32px;font-size:10px}#toc .toc-item{position:relative;box-sizing:border-box;height:1.7rem;padding:0 .5rem;list-style:none;line-height:1.7rem}#toc .toc-item:hover>.toc-link{color:var(--theme-color)}#toc .toc-item.active>.toc-link{color:var(--theme-color);font-weight:700}.dropdown-wrapper{cursor:pointer}.dropdown-wrapper:not(:hover) .arrow{transform:rotate(-180deg)}.dropdown-wrapper .dropdown-title{border-width:0;background:transparent;cursor:pointer;padding:0 .25rem;color:var(--dark-grey);font-weight:500;font-size:inherit;font-family:inherit;line-height:inherit;cursor:inherit}.dropdown-wrapper .dropdown-title:hover{border-color:transparent}.dropdown-wrapper .dropdown-title .icon{-webkit-margin-end:.25em;margin-inline-end:.25em;font-size:1em}.dropdown-wrapper .dropdown-title .arrow{display:inline-block;vertical-align:middle;width:1em;height:1em;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='rgba(0,0,0,0.5)' d='M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z'/%3E%3C/svg%3E");line-height:normal;transition:all .3s;font-size:1.2em}html[data-theme=dark] .dropdown-wrapper .dropdown-title .arrow{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='rgba(255,255,255,0.5)' d='M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z'/%3E%3C/svg%3E")}.dropdown-wrapper .dropdown-title .arrow.down{transform:rotate(180deg)}html[dir=rtl] .dropdown-wrapper .dropdown-title .arrow.down{transform:rotate(-180deg)}.dropdown-wrapper .dropdown-title .arrow.end{transform:rotate(90deg)}html[dir=rtl] .dropdown-wrapper .dropdown-title .arrow.end,.dropdown-wrapper .dropdown-title .arrow.start{transform:rotate(-90deg)}html[dir=rtl] .dropdown-wrapper .dropdown-title .arrow.start{transform:rotate(90deg)}.dropdown-wrapper ul{margin:0;padding:0;list-style-type:none}.dropdown-wrapper .nav-dropdown{position:absolute;top:100%;right:0;overflow-y:auto;box-sizing:border-box;min-width:6rem;max-height:calc(100vh - var(--navbar-height));margin:0;padding:.5rem .75rem;border:1px solid var(--grey14);border-radius:.25rem;background:var(--bg-color);box-shadow:2px 2px 10px var(--card-shadow);text-align:start;white-space:nowrap;opacity:0;visibility:hidden;transition:all .18s ease-out;transform:scale(.8)}html[dir=rtl] .dropdown-wrapper .nav-dropdown{right:unset;left:0}.dropdown-wrapper:hover .nav-dropdown,.dropdown-wrapper.open .nav-dropdown{z-index:2;opacity:1;visibility:visible;transform:scale(1)}.dropdown-wrapper .nav-link{position:relative;display:block;margin-bottom:0;border-bottom:none;color:var(--dark-grey);font-weight:400;font-size:.875rem;line-height:1.7rem;transition:color var(--color-transition)}.dropdown-wrapper .nav-link:hover,.dropdown-wrapper .nav-link.active{color:var(--theme-color)}.dropdown-wrapper .dropdown-subtitle{margin:0;padding:.5rem .25rem 0;color:var(--light-grey);font-weight:600;font-size:.75rem;line-height:2;text-transform:uppercase;transition:color var(--color-transition)}.dropdown-wrapper .dropdown-subitem-wrapper{padding:0 0 .25rem}.dropdown-wrapper .dropdown-item{color:inherit;line-height:1.7rem}.dropdown-wrapper .dropdown-item:last-child .dropdown-subtitle{padding-top:0}.dropdown-wrapper .dropdown-item:last-child .dropdown-subitem-wrapper{padding-bottom:0}.nav-screen-dropdown-title{border-width:0;background:transparent;position:relative;display:flex;align-items:center;width:100%;padding:0;color:var(--dark-grey);font-size:inherit;font-family:inherit;text-align:start;cursor:pointer}.nav-screen-dropdown-title:hover,.nav-screen-dropdown-title.active{color:var(--text-color)}.nav-screen-dropdown-title .title{flex:1}.nav-screen-dropdown-title .arrow{display:inline-block;vertical-align:middle;width:1em;height:1em;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='rgba(0,0,0,0.5)' d='M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z'/%3E%3C/svg%3E");line-height:normal;transition:all .3s}html[data-theme=dark] .nav-screen-dropdown-title .arrow{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='rgba(255,255,255,0.5)' d='M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z'/%3E%3C/svg%3E")}.nav-screen-dropdown-title .arrow.down{transform:rotate(180deg)}html[dir=rtl] .nav-screen-dropdown-title .arrow.down{transform:rotate(-180deg)}.nav-screen-dropdown-title .arrow.end{transform:rotate(90deg)}html[dir=rtl] .nav-screen-dropdown-title .arrow.end,.nav-screen-dropdown-title .arrow.start{transform:rotate(-90deg)}html[dir=rtl] .nav-screen-dropdown-title .arrow.start{transform:rotate(90deg)}.nav-screen-dropdown{overflow:hidden;margin:.5rem 0 0;padding:0;list-style:none;transition:transform .1s ease-out;transform:scaleY(1);transform-origin:top}.nav-screen-dropdown.hide{height:0;margin:0;transform:scaleY(0)}.nav-screen-dropdown .nav-link{position:relative;display:block;-webkit-padding-start:.5rem;padding-inline-start:.5rem;font-weight:400;line-height:2}.nav-screen-dropdown .nav-link:hover,.nav-screen-dropdown .nav-link.active{color:var(--theme-color)}.nav-screen-dropdown .nav-link .icon{font-size:1em}.nav-screen-dropdown .dropdown-item{color:inherit;line-height:1.7rem}.nav-screen-dropdown .dropdown-subtitle{margin:0;-webkit-padding-start:.25rem;padding-inline-start:.25rem;color:var(--light-grey);font-weight:600;font-size:.75rem;line-height:2;text-transform:uppercase;transition:color var(--color-transition)}.nav-screen-dropdown .dropdown-subtitle .nav-link{padding:0}.nav-screen-dropdown .dropdown-subitem-wrapper{margin:0;padding:0;list-style:none}.nav-screen-dropdown .dropdown-subitem{-webkit-padding-start:.5rem;padding-inline-start:.5rem;font-size:.9em}.nav-screen-links{display:none;padding-bottom:.75rem}@media (max-width: 719px){.nav-screen-links{display:block}}.nav-screen-links .navbar-links-item{position:relative;display:block;padding:12px 4px 11px 0;border-bottom:1px solid var(--border-color);font-size:16px;line-height:1.5rem;transition:border-bottom-color var(--color-transition)}.nav-screen-links .nav-link{display:inline-block;width:100%;color:var(--dark-grey);font-weight:400}.nav-screen-links .nav-link:hover{color:var(--text-color)}.nav-screen-links .nav-link.active{color:var(--theme-color)}#nav-screen{position:fixed;top:var(--navbar-height);right:0;bottom:0;left:0;z-index:150;display:none;overflow-y:auto;padding:0 2rem;background:var(--bg-color);transition:background .5s}@media (max-width: 719px){#nav-screen{display:block}}#nav-screen .container{max-width:320px;margin:0 auto;padding:2rem 0 4rem}#nav-screen.fade-enter-active,#nav-screen.fade-leave-active{transition:opacity .25s}#nav-screen.fade-enter-active .container,#nav-screen.fade-leave-active .container{transition:transform .25s ease}#nav-screen.fade-enter-from,#nav-screen.fade-leave-to{opacity:0}#nav-screen.fade-enter-from .container,#nav-screen.fade-leave-to .container{transform:translateY(-8px)}#nav-screen .outlook-wrapper{display:flex;justify-content:space-around}#nav-screen .icon{-webkit-margin-end:.25em;margin-inline-end:.25em}.navbar .logo{vertical-align:top;height:var(--navbar-line-height);-webkit-margin-end:.8rem;margin-inline-end:.8rem}.navbar .logo.light{display:inline-block}.navbar .logo.dark,html[data-theme=dark] .navbar .logo.light{display:none}html[data-theme=dark] .navbar .logo.dark{display:inline-block}.navbar .site-name{position:relative;color:var(--text-color);font-size:1.25rem}@media (max-width: 719px){.navbar .site-name{overflow:hidden;width:calc(100vw - 9.4rem);text-overflow:ellipsis;white-space:nowrap}}.brand:hover .navbar .site-name{color:var(--theme-color)}.navbar .nav-links{display:flex;align-items:center;font-size:.875rem}.navbar .nav-item{position:relative;margin:0 .25rem;line-height:2rem}.navbar .nav-item:first-child{-webkit-margin-start:0;margin-inline-start:0}.navbar .nav-item:last-child{-webkit-margin-end:0;margin-inline-end:0}.navbar .nav-item>.nav-link{color:var(--dark-grey)}.navbar .nav-item>.nav-link:after{content:" ";position:absolute;right:50%;bottom:0;left:50%;height:2px;border-radius:1px;background:var(--theme-color-light);visibility:hidden;transition:left .2s ease-in-out,right .2s ease-in-out}.navbar .nav-item>.nav-link.active{color:var(--theme-color)}.navbar .nav-item>.nav-link:hover:after,.navbar .nav-item>.nav-link.active:after{right:0;left:0;visibility:visible}.navbar{--navbar-line-height: calc( var(--navbar-height) - var(--navbar-vertical-padding) * 2 );position:fixed;top:0;right:0;left:0;z-index:175;display:flex;align-items:center;justify-content:space-between;box-sizing:border-box;height:var(--navbar-height);padding:var(--navbar-vertical-padding) var(--navbar-horizontal-padding);background:var(--navbar-bg-color);box-shadow:0 2px 8px var(--card-shadow);line-height:var(--navbar-line-height);white-space:nowrap;transition:transform ease-in-out .3s,background var(--color-transition),box-shadow var(--color-transition);-webkit-backdrop-filter:saturate(150%) blur(12px);backdrop-filter:saturate(150%) blur(12px)}@media print{.navbar{display:none}}.hide-navbar .navbar.auto-hide{transform:translateY(-100%)}.navbar .nav-link{padding:0 .25rem;color:var(--dark-grey)}.navbar .nav-link.active{color:var(--theme-color)}.navbar .nav-link .icon{-webkit-margin-end:.25em;margin-inline-end:.25em;font-size:1em}.navbar.hide-icon .nav-links .icon{display:none!important}.navbar-start,.navbar-end,.navbar-center{display:flex;flex:1;align-items:center}.navbar-start>*,.navbar-end>*,.navbar-center>*{position:relative;margin:0 .25rem!important}.navbar-start>*:first-child,.navbar-end>*:first-child,.navbar-center>*:first-child{-webkit-margin-start:0!important;margin-inline-start:0!important}.navbar-start>*:last-child,.navbar-end>*:last-child,.navbar-center>*:last-child{-webkit-margin-end:0!important;margin-inline-end:0!important}.navbar-start{justify-content:start}.navbar-center{justify-content:center}.navbar-end{justify-content:end}.navbar .repo-link{display:inline-block;margin:auto;padding:6px;color:var(--dark-grey);line-height:1}.navbar .repo-link:hover,.navbar .repo-link:active{color:var(--theme-color)}.toggle-navbar-button{border-width:0;background:transparent;cursor:pointer;position:relative;display:none;align-items:center;justify-content:center;padding:6px}@media screen and (max-width: 719px){.toggle-navbar-button{display:flex}}.toggle-navbar-button .button-container{position:relative;overflow:hidden;width:16px;height:14px}.toggle-navbar-button .button-top,.toggle-navbar-button .button-middle,.toggle-navbar-button .button-bottom{position:absolute;width:16px;height:2px;background:var(--dark-grey);transition:top .25s,background .5s,transform .25s}.toggle-navbar-button .button-top{top:0;left:0;transform:translate(0)}.toggle-navbar-button .button-middle{top:6px;left:0;transform:translate(8px)}.toggle-navbar-button .button-bottom{top:12px;left:0;transform:translate(4px)}.toggle-navbar-button:hover .button-top{top:0;left:0;transform:translate(4px)}.toggle-navbar-button:hover .button-middle{top:6;left:0;transform:translate(0)}.toggle-navbar-button:hover .button-bottom{top:12px;left:0;transform:translate(8px)}.toggle-navbar-button.is-active .button-top{top:6px;transform:translate(0) rotate(225deg)}.toggle-navbar-button.is-active .button-middle{top:6px;transform:translate(16px)}.toggle-navbar-button.is-active .button-bottom{top:6px;transform:translate(0) rotate(135deg)}.toggle-navbar-button.is-active:hover .button-top,.toggle-navbar-button.is-active:hover .button-middle,.toggle-navbar-button.is-active:hover .button-bottom{background:var(--theme-color);transition:top .25s,background .25s,transform .25s}.toggle-sidebar-button{border-width:0;background:transparent;cursor:pointer;display:none;vertical-align:middle;box-sizing:content-box;width:1rem;height:1rem;padding:.5rem;font:unset;transition:transform .2s ease-in-out}@media screen and (max-width: 719px){.toggle-sidebar-button{display:block;-webkit-padding-end:var(--navbar-mobile-horizontal-padding);padding-inline-end:var(--navbar-mobile-horizontal-padding)}}.toggle-sidebar-button:before,.toggle-sidebar-button:after,.toggle-sidebar-button .icon{display:block;width:100%;height:2px;border-radius:.05em;background:var(--dark-grey);transition:transform .2s ease-in-out}.toggle-sidebar-button:before{content:" ";margin-top:.125em}.sidebar-open .toggle-sidebar-button:before{transform:translateY(.34rem) rotate(135deg)}.toggle-sidebar-button:after{content:" ";margin-bottom:.125em}.sidebar-open .toggle-sidebar-button:after{transform:translateY(-.34rem) rotate(-135deg)}.toggle-sidebar-button .icon{margin:.2em 0}.sidebar-open .toggle-sidebar-button .icon{transform:scale(0)}.appearance-title{display:block;margin:0;padding:0 .25rem;color:var(--light-grey);font-weight:600;font-size:.75rem;line-height:2;transition:color var(--color-transition)}#appearance-switch{border-width:0;background:transparent;vertical-align:middle;padding:6px;color:var(--dark-grey);cursor:pointer;transition:color var(--color-transition)}#appearance-switch:hover{color:var(--theme-color)}#appearance-switch .icon{width:1.25rem;height:1.25rem}.outlook-button{border-width:0;background:transparent;cursor:pointer;position:relative;padding:.375rem;color:var(--dark-grey)}.outlook-button .icon{vertical-align:middle;width:1.25rem;height:1.25rem}.outlook-dropdown{position:absolute;top:100%;right:0;overflow-y:auto;box-sizing:border-box;min-width:100px;margin:0;padding:.5rem .75rem;border:1px solid var(--grey14);border-radius:.25rem;background:var(--bg-color);box-shadow:2px 2px 10px var(--card-shadow);text-align:start;white-space:nowrap;opacity:0;visibility:hidden;transition:all .18s ease-out;transform:scale(.8)}html[dir=rtl] .outlook-dropdown{right:unset;left:0}.outlook-dropdown>*:not(:last-child){padding-bottom:.5rem;border-bottom:1px solid var(--grey14)}.outlook-button:hover .outlook-dropdown,.outlook-button.open .outlook-dropdown{z-index:2;opacity:1;visibility:visible;transform:scale(1)}.theme-color-title{display:block;margin:0;padding:0 .25rem;color:var(--light-grey);font-weight:600;font-size:.75rem;line-height:2;transition:color var(--color-transition)}#theme-color-picker{display:flex;margin:0;padding:0;list-style-type:none;font-size:14px}#theme-color-picker li span{display:inline-block;vertical-align:middle;width:15px;height:15px;margin:0 2px;border-radius:2px}#theme-color-picker li span.theme-color,#theme-color-picker li span.theme-color html[data-theme=dark]{background:#3eaf7c}@media print{.full-screen-wrapper{display:none}}.full-screen-title{display:block;margin:0;padding:0 .25rem;color:var(--light-grey);font-weight:600;font-size:.75rem;line-height:2;transition:color var(--color-transition)}.full-screen,.cancel-full-screen{border-width:0;background:transparent;vertical-align:middle;padding:.375rem;color:var(--dark-grey);cursor:pointer}.full-screen:hover,.cancel-full-screen:hover{color:var(--theme-color)}.full-screen .icon,.cancel-full-screen .icon{width:1.25rem;height:1.25rem}.enter-fullscreen-icon:hover,.cancel-fullscreen-icon{color:var(--theme-color)}.cancel-fullscreen-icon:hover{color:var(--dark-grey)}.sidebar-heading{display:flex;align-items:center;overflow:hidden;box-sizing:border-box;width:calc(100% - 1rem);margin:0;margin-inline:.5rem;padding:.25rem .5rem;border-width:0;border-radius:.375rem;background:transparent;color:var(--text-color);font-size:1.1em;line-height:1.5;-webkit-user-select:none;-moz-user-select:none;user-select:none;transition:color .15s ease;transform:rotate(0)}.sidebar-heading.open{color:inherit}.sidebar-heading.clickable:hover{background:var(--bg-color-secondary)}.sidebar-heading.clickable.exact{border-inline-start-color:var(--theme-color);color:var(--theme-color)}.sidebar-heading.clickable.exact a{color:inherit}.sidebar-heading .icon{-webkit-margin-end:.25em;margin-inline-end:.25em}.sidebar-heading .title{flex:1}.sidebar-heading .arrow{display:inline-block;vertical-align:middle;width:1em;height:1em;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='rgba(0,0,0,0.5)' d='M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z'/%3E%3C/svg%3E");line-height:normal;transition:all .3s;font-size:1.5em}html[data-theme=dark] .sidebar-heading .arrow{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='rgba(255,255,255,0.5)' d='M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z'/%3E%3C/svg%3E")}.sidebar-heading .arrow.down{transform:rotate(180deg)}html[dir=rtl] .sidebar-heading .arrow.down{transform:rotate(-180deg)}.sidebar-heading .arrow.end{transform:rotate(90deg)}html[dir=rtl] .sidebar-heading .arrow.end,.sidebar-heading .arrow.start{transform:rotate(-90deg)}html[dir=rtl] .sidebar-heading .arrow.start{transform:rotate(90deg)}button.sidebar-heading{outline:none;font-weight:inherit;font-family:inherit;line-height:inherit;text-align:start;cursor:pointer}.sidebar-link{display:inline-block;box-sizing:border-box;width:calc(100% - 1rem);margin-inline:.5rem;padding:.25rem .5rem;border-radius:.375rem;color:var(--text-color);font-weight:400;font-size:1em;line-height:1.5}.sidebar-link .icon{-webkit-margin-end:.25em;margin-inline-end:.25em}.sidebar-link:hover{background:var(--bg-color-secondary)}.sidebar-link.active{background:var(--theme-color-mask);color:var(--theme-color);font-weight:500}.sidebar-link.active .icon{color:var(--theme-color)}.sidebar-sub-headers .sidebar-link{padding-top:.25rem;padding-bottom:.25rem;-webkit-border-start:none;border-inline-start:none}.sidebar-sub-headers .sidebar-link.active{background:transparent;font-weight:500}.sidebar-group .sidebar-group{-webkit-padding-start:.75rem;padding-inline-start:.75rem}.sidebar-group .sidebar-group .sidebar-heading{font-size:1em}.sidebar-group:not(.collapsible) .sidebar-heading:not(.clickable){color:inherit;cursor:auto}.sidebar-group .sidebar-link{-webkit-padding-start:1.25rem;padding-inline-start:1.25rem}.sidebar-links,.sidebar-links ul{margin:0;padding:0}.sidebar-links ul.sidebar-sub-headers{-webkit-padding-start:.75rem;padding-inline-start:.75rem;font-size:.95em}@media (min-width: 1440px){.has-toc .sidebar-links ul.sidebar-sub-headers{display:none}}.sidebar-links li{list-style-type:none}.sidebar>.sidebar-links{padding:1.5rem 0}@media (max-width: 719px){.sidebar>.sidebar-links{padding:1rem 0}}.sidebar>.sidebar-links>li>.sidebar-link{font-size:1.1em}.sidebar>.sidebar-links>li:not(:first-child){margin-top:.5rem}.sidebar{position:fixed;top:0;bottom:0;left:0;z-index:1;overflow-y:auto;width:var(--sidebar-width);margin:0;-webkit-padding-start:calc(var(--sidebar-space) - var(--sidebar-width));padding-inline-start:calc(var(--sidebar-space) - var(--sidebar-width));background:var(--sidebar-bg-color);box-shadow:2px 0 8px var(--card-shadow);font-size:.94rem;transition:background var(--color-transition),box-shadow var(--color-transition),padding var(--transform-transition),transform var(--transform-transition);-webkit-backdrop-filter:saturate(150%) blur(12px);backdrop-filter:saturate(150%) blur(12px);scrollbar-color:var(--theme-color) var(--border-color);scrollbar-width:thin}@media (max-width: 959px){.sidebar{font-size:.86em}}@media (max-width: 719px){.sidebar{z-index:125;box-shadow:none;transform:translate(-100%)}html[dir=rtl] .sidebar{transform:translate(100%)}}@media (min-width: 1440px){.sidebar{padding-bottom:3rem;box-shadow:none;font-size:1rem}}@media print{.sidebar{display:none}}html[dir=rtl] .sidebar{right:0;left:unset}.sidebar a{display:inline-block;color:var(--text-color);font-weight:400}.sidebar .icon{-webkit-margin-end:.25em;margin-inline-end:.25em}.sidebar.hide-icon .icon{display:none!important}.sidebar .blogger-info.mobile{display:none}@media (max-width: 719px){.sidebar .blogger-info.mobile{display:block}}.sidebar .blogger-info.mobile+hr{display:none}@media (max-width: 719px){.sidebar .blogger-info.mobile+hr{display:block;margin-top:1rem}}.sidebar-mask{position:fixed;top:0;left:0;z-index:9;width:100vw;height:100vh;background:rgba(0,0,0,.15)}.sidebar-mask.fade-enter-active,.sidebar-mask.fade-leave-active{transition:opacity .25s}.sidebar-mask.fade-enter-from,.sidebar-mask.fade-leave-to{opacity:0}.search-pro-button{border-width:0;background:transparent;display:inline-flex;align-items:center;box-sizing:content-box;height:1.25rem;margin-inline:1rem 0;margin-top:0;margin-bottom:0;padding:.5rem;border:0;border:1px solid var(--vp-bgl);border-radius:1rem;background:var(--vp-bgl);color:var(--vp-c);font-weight:500;cursor:pointer;transition:background var(--vp-ct),color var(--vp-ct)}@media print{.search-pro-button{display:none}}@media (max-width: 959px){.search-pro-button{border-radius:50%}}.search-pro-button:hover{border:1px solid var(--vp-tc);background-color:var(--vp-bglt);color:var(--vp-clt)}.search-pro-button .search-icon{width:1.25rem;height:1.25rem}.search-pro-button .placeholder{margin-inline:.25rem;font-size:1rem}@media (max-width: 959px){.search-pro-button .placeholder{display:none}}.search-pro-button .key-hints{font-size:.75rem}@media (max-width: 959px){.search-pro-button .key-hints{display:none}}.search-pro-button .key-hints .key{display:inline-block;min-width:1em;margin-inline:.125rem;padding:.25rem;border:1px solid var(--vp-brc);border-radius:4px;box-shadow:1px 1px 4px 0 var(--card-shadow);line-height:1;letter-spacing:-.1em;transition:background var(--vp-ct),color var(--vp-ct),border var(--vp-ct) box-shadow var(--vp-ct)}@keyframes search-pro-fade-in{0%{opacity:.2}to{opacity:1}}.search-pro-modal-wrapper{position:fixed;top:0;left:0;z-index:997;display:flex;align-items:center;justify-content:center;overflow:auto;width:100vw;height:100vh;cursor:default}.search-pro-modal-wrapper button{border-width:0;background:transparent;cursor:pointer}.search-pro-modal-wrapper .background{position:fixed;top:0;left:0;z-index:998;width:100vw;height:100vh;animation:.25s search-pro-fade-in;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px)}.search-pro-modal{position:absolute;z-index:999;display:flex;flex-direction:column;width:calc(100% - 6rem);max-width:50em;border-radius:10px;background:var(--vp-bg);box-shadow:2px 2px 10px 0 var(--card-shadow);transition:background var(--vp-ct);animation:.15s pwa-opened}@media (max-width: 1280px){.search-pro-modal{animation:.25s pwa-mobile}}@media (max-width: 719px){.search-pro-modal{width:100vw;max-width:unset;height:100vh}}.search-pro-box{display:flex;margin:1rem}.search-pro-box form{position:relative;display:flex;flex:1}.search-pro-box label{position:absolute;top:calc(50% - .75rem);left:.5rem;color:var(--vp-tc)}html[dir=rtl] .search-pro-box label{right:.5rem;left:unset}.search-pro-box label .search-icon{width:1.5rem;height:1.5rem}.search-pro-box input{flex:1;min-width:0;margin:0;padding-top:.25rem;padding-bottom:.25rem;-webkit-padding-start:2.5rem;padding-inline-start:2.5rem;-webkit-padding-end:1rem;padding-inline-end:1rem;border:0;border:2px solid var(--vp-tc);border-radius:8px;background:var(--vp-bg);color:var(--vp-c);outline:none;font-size:1.25rem;line-height:2.5;-webkit-appearance:none;-moz-appearance:none;appearance:none}.search-pro-box .close-button{border-width:0;background:transparent;cursor:pointer;display:none;-webkit-margin-start:.5rem;margin-inline-start:.5rem;-webkit-margin-end:-.5rem;margin-inline-end:-.5rem;padding:.5rem;color:var(--grey3)}@media (max-width: 719px){.search-pro-box .close-button{display:block}}.search-pro-result{flex-grow:1;overflow-y:auto;min-height:40vh;max-height:calc(80vh - 10rem);padding:0 1rem}@media (max-width: 719px){.search-pro-result{min-height:unset;max-height:unset}}.search-pro-result.loading,.search-pro-result.empty{display:flex;align-items:center;justify-content:center;padding:1.5rem;font-weight:600;font-size:22px;text-align:center}.search-pro-hints{margin-top:1rem;padding:.75rem .5rem;box-shadow:0 -1px 4px 0 var(--card-shadow);line-height:1}.search-pro-hint{display:inline-flex;align-items:center;margin:0 .5rem}.search-pro-hint kbd{margin:0 .5rem;padding:2px;border:1px solid var(--vp-brc);border-radius:4px;box-shadow:1px 1px 4px 0 var(--card-shadow)}.search-pro-hint kbd+kbd{-webkit-margin-start:-.25rem;margin-inline-start:-.25rem}.search-pro-hint svg{display:block;width:15px;height:15px}.search-pro-result{scrollbar-color:var(--vp-tc) var(--vp-brc);scrollbar-width:thin}@media (max-width: 419px){.search-pro-result{font-size:13px}}.search-pro-result::-webkit-scrollbar{width:6px;height:6px}.search-pro-result::-webkit-scrollbar-track-piece{border-radius:6px;background:rgba(0,0,0,.1)}.search-pro-result::-webkit-scrollbar-thumb{border-radius:6px;background:var(--vp-tc)}.search-pro-result::-webkit-scrollbar-thumb:active{background:var(--vp-tcl)}.search-pro-result-list{margin:0;padding:0}.search-pro-result-list-item{display:block;list-style:none}.search-pro-result-title{position:sticky;top:-2px;z-index:10;margin:-4px;margin-bottom:.25rem;padding:4px;background:var(--vp-bg);color:var(--vp-tc);font-weight:600;font-size:.85em;line-height:2rem;text-indent:.5em}.search-pro-result-item.active .search-pro-result-title{color:var(--vp-tc)}.search-pro-result-type{display:block;width:1rem;height:1rem;-webkit-margin-start:-.5rem;margin-inline-start:-.5rem;padding:.5rem;color:var(--vp-tc)}.search-pro-close-icon{box-sizing:content-box;height:1.5rem;padding:0;border-radius:50%;color:var(--vp-tc)}.search-pro-close-icon svg{width:1.5rem;height:1.5rem}.search-pro-close-icon:hover{background:rgba(128,128,128,.3)}.search-pro-result-content{display:flex;flex-grow:1;flex-direction:column;align-items:stretch;justify-content:center;line-height:1.5}.search-pro-result-content .content-header{margin-bottom:.25rem;border-bottom:1px solid var(--vp-brcd);font-size:.9em}.search-pro-result-item{display:flex;align-items:center;margin:.5rem 0;padding:.5rem .75rem;border-radius:.25rem;background:var(--vp-bgl);color:inherit;box-shadow:0 1px 3px 0 var(--card-shadow);font-weight:400;white-space:pre-wrap;word-wrap:break-word}.search-pro-result-item strong{color:var(--vp-tc)}.search-pro-result-item:hover,.search-pro-result-item.active{background-color:var(--vp-tcl);color:var(--white);cursor:pointer}.search-pro-result-item:hover .search-pro-result-type,.search-pro-result-item:hover .search-pro-close-icon,.search-pro-result-item:hover strong,.search-pro-result-item.active .search-pro-result-type,.search-pro-result-item.active .search-pro-close-icon,.search-pro-result-item.active strong{color:var(--white)} diff --git a/assets/testdata.html-32bf797b.js b/assets/testdata.html-32bf797b.js new file mode 100644 index 00000000..857b4f65 --- /dev/null +++ b/assets/testdata.html-32bf797b.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-51b3f914","path":"/docs/user/testdata.html","title":"测试数据格式","lang":"en-US","frontmatter":{"description":"自动模式 您可以直接选择文件(支持多选)上传或将文件拖拽至相应位置上传。 若上传文件为 zip 格式,将会自动进行解压操作。 对于一般的题目,您只需提供 .in 和 .out/.ans 文件,以下是一个例子。 请务必确保文件名中含有数字。形如 sample.in 的文件是不会被自动识别的。 测试数据将被自动识别,并使用 1S 256MB 的限制。 使用...","head":[["meta",{"property":"og:url","content":"https://hydro.js.org/docs/user/testdata.html"}],["meta",{"property":"og:site_name","content":"Hydro"}],["meta",{"property":"og:title","content":"测试数据格式"}],["meta",{"property":"og:description","content":"自动模式 您可以直接选择文件(支持多选)上传或将文件拖拽至相应位置上传。 若上传文件为 zip 格式,将会自动进行解压操作。 对于一般的题目,您只需提供 .in 和 .out/.ans 文件,以下是一个例子。 请务必确保文件名中含有数字。形如 sample.in 的文件是不会被自动识别的。 测试数据将被自动识别,并使用 1S 256MB 的限制。 使用..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-05-12T03:18:30.000Z"}],["meta",{"property":"article:modified_time","content":"2023-05-12T03:18:30.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"测试数据格式\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-05-12T03:18:30.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"自动模式","slug":"自动模式","link":"#自动模式","children":[]},{"level":2,"title":"使用配置文件","slug":"使用配置文件","link":"#使用配置文件","children":[]}],"git":{"createdTime":1631785934000,"updatedTime":1683861510000,"contributors":[{"name":"Macesuted","email":"macesuted@qq.com","commits":2},{"name":"panda","email":"panda_dtdyy@outlook.com","commits":2},{"name":"undefined","email":"i@undefined.moe","commits":2},{"name":"laomai","email":"lmxin@tom.com","commits":1}]},"readingTime":{"minutes":3.3,"words":989},"filePathRelative":"docs/user/testdata.md","localizedDate":"September 16, 2021","autoDesc":true,"excerpt":""}');export{e as data}; diff --git a/assets/testdata.html-4376808f.js b/assets/testdata.html-4376808f.js new file mode 100644 index 00000000..efd04e96 --- /dev/null +++ b/assets/testdata.html-4376808f.js @@ -0,0 +1,104 @@ +import{_ as l}from"./plugin-vue_export-helper-c27b6911.js";import{r as p,o as e,c as o,a as n,b as s,d as c,e as i}from"./app-68b9e0b9.js";const r={},t=i(`

测试数据格式

自动模式

Tips

您可以直接选择文件(支持多选)上传或将文件拖拽至相应位置上传。
若上传文件为 zip 格式,将会自动进行解压操作。

对于一般的题目,您只需提供 .in.out/.ans 文件,以下是一个例子。
请务必确保文件名中含有数字。形如 sample.in 的文件是不会被自动识别的。

喵? tree
+.
+├── a1.in
+├── a1.out
+├── a2.in
+├── a2.out
+├── a3.in
+└── a3.out
+

测试数据将被自动识别,并使用 1S 256MB 的限制。

使用配置文件

Tips

推荐您通过 评测设置 在线编辑题目配置,可以拥有更好的编辑体验。

上传 config.yaml 文件即可,文件格式如下(下方所有样例均为可选项,若无说明则预填写的内容即为默认值):

# 题目类型,可以为 default(比对输出,可以含spj), objective(客观题), interactive(交互题)
+type: default
+
+# 全局时空限制(此处的限制优先级低于测试点的限制)
+time: 1s
+memory: 128m
+
+# 输入输出文件名(例:使用 foo.in 和 foo.out),若使用标准 IO 删除此配置项即可
+filename: foo
+
+# 此部分设置当题目类型为 default 时生效
+# 比较器类型,支持的值有 default(直接比对,忽略行末空格和文件末换行), ccr, cena, hustoj, lemon, qduoj, syzoj, testlib(比较常用)
+checker_type: default
+# 比较器文件(当比较器类型不为 default 时填写)
+# 文件路径(位于压缩包中的路径)
+# 将通过扩展名识别语言,与编译命令处一致。在默认配置下,C++ 扩展名应为 .cc 而非 .cpp
+checker: chk.cc
+
+# 此部分设置当题目类型为interactive时生效
+# 交互器路径(位于压缩包中的路径)
+interactor: interactor.cc
+
+# Extra files 额外文件
+# These files will be copied to the working directory 这些文件将被复制到工作目录。
+# 提示:您无需手动上传 testlib.h。
+user_extra_files:
+  - extra_input.txt
+judge_extra_files:
+  - extra_file.txt
+
+# Test Cases 测试数据列表
+# If neither CASES or SUBTASKS are set(or config.yaml doesn't exist), judge will try to locate them automaticly.
+# 如果 CASES 和 SUBTASKS 都没有设置或 config.yaml 不存在, 系统会自动尝试识别数据点。
+# We support these names for auto mode: 自动识别支持以下命名方式:
+# 1. [name(optional)][number].(in/out/ans)         RegExp: /^([a-zA-Z]*)([0-9]+).in$/
+#   examples: 
+#     - c1.in / c1.out
+#     - 1.in / 1.out
+#     - c1.in / c1.ans
+# 2. input[number].txt / output[number].txt        RegExp: /^(input)([0-9]+).txt$/
+#   - example: input1.txt / input2.txt
+#
+# The CASES option has higher priority than the SUBTASKS option!
+# 在有 CASES 设置项时,不会读取 SUBTASKS 设置项!
+#
+# The CASES option has been deprecated in the new version, please use the more personalized SUBTASKS!
+# CASES 已于新版本中被废弃,请使用个性化程度更高的SUBTASKS!
+# score: 50     # 单个测试点分数
+# time: 1s      # 时间限制
+# memory: 256m  # 内存限制
+# cases:
+#   - input: abc.in
+#     output: def.out
+#   - input: ghi.in
+#     output: jkl.out
+# 或使用Subtask项:
+subtasks:
+  - score: 30
+    type: min # 可选 min/max/sum,分别表示取所有测试点最小值、所有测试点最大值、所有测试点之和
+    time: 1s
+    memory: 64m
+    cases:
+      - time: 0.5s
+        memory: 32m # 可对单个测试点单独设置时间限制和内存限制
+        input: a.in
+        output: a.out
+      - input: b.in
+        output: b.out
+  - score: 70
+    time: 0.5s
+    memory: 32m
+    if: [0] # 可选,传入数组,表示仅在subtask0通过时此subtask才计分
+    cases:
+      - input: c.in
+        output: c.out
+      - input: d.in
+        output: d.out
+
+# 提交语言限制
+# 列举出所有本题允许使用的语言对应的代码(需要和评测机 lang.yaml 内的语言代码相同)
+# 使用语言ID而非名称!对于有子类的选项,请详细至子分类!
+langs:
+  - c
+  - cc
+  - cc.cc11o2
+  - pas
+
+# 时间内存倍率
+# 对某语言设置时间或内存倍率(需要和评测机 lang.yaml 内的语言代码相同)
+# 部分语言默认已存在倍率,请前往控制面板中查看!
+# 使用语言ID而非名称!对于有子类的选项,请详细至子分类!
+time_limit_rate:
+  py.py3: 2
+memory_limit_rate:
+  java: 1.5
+
`,10),E={href:"https://hydro.ac/d/system_test/",target:"_blank",rel:"noopener noreferrer"};function d(F,y){const a=p("ExternalLinkIcon");return e(),o("div",null,[t,n("p",null,[s("可以在 "),n("a",E,[s("此题库"),c(a)]),s(" 中找到各种类型题目的配置示例。")])])}const m=l(r,[["render",d],["__file","testdata.html.vue"]]);export{m as default}; diff --git a/assets/third-party-auth.html-26afa0e7.js b/assets/third-party-auth.html-26afa0e7.js new file mode 100644 index 00000000..f165cd37 --- /dev/null +++ b/assets/third-party-auth.html-26afa0e7.js @@ -0,0 +1 @@ +const t=JSON.parse('{"key":"v-55131a51","path":"/dev/third-party-auth.html","title":"接入第三方账号系统","lang":"en-US","frontmatter":{"description":"Hydro 支持接入第三方的账号系统,并且有以下内置模块可用: @hydrooj/login-with-github; @hydrooj/login-with-google; 对接其他平台 在阅读本节之前,请确保你已阅读 【插件开发】 章节。 以 Github 登录为例:","head":[["meta",{"property":"og:url","content":"https://hydro.js.org/dev/third-party-auth.html"}],["meta",{"property":"og:site_name","content":"Hydro"}],["meta",{"property":"og:title","content":"接入第三方账号系统"}],["meta",{"property":"og:description","content":"Hydro 支持接入第三方的账号系统,并且有以下内置模块可用: @hydrooj/login-with-github; @hydrooj/login-with-google; 对接其他平台 在阅读本节之前,请确保你已阅读 【插件开发】 章节。 以 Github 登录为例:"}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-12-26T15:11:04.000Z"}],["meta",{"property":"article:modified_time","content":"2023-12-26T15:11:04.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"接入第三方账号系统\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-12-26T15:11:04.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"对接其他平台","slug":"对接其他平台","link":"#对接其他平台","children":[]}],"git":{"createdTime":1703603464000,"updatedTime":1703603464000,"contributors":[{"name":"undefined","email":"i@undefined.moe","commits":1}]},"readingTime":{"minutes":1.7,"words":511},"filePathRelative":"dev/third-party-auth.md","localizedDate":"December 26, 2023","autoDesc":true,"excerpt":""}');export{t as data}; diff --git a/assets/third-party-auth.html-7df2a358.js b/assets/third-party-auth.html-7df2a358.js new file mode 100644 index 00000000..eea0ed83 --- /dev/null +++ b/assets/third-party-auth.html-7df2a358.js @@ -0,0 +1,83 @@ +import{_ as s}from"./plugin-vue_export-helper-c27b6911.js";import{o as n,c as a,e as l}from"./app-68b9e0b9.js";const p={},o=l(`

接入第三方账号系统

Hydro 支持接入第三方的账号系统,并且有以下内置模块可用:

  • @hydrooj/login-with-github
  • @hydrooj/login-with-google

对接其他平台

在阅读本节之前,请确保你已阅读 【插件开发】 章节。

以 Github 登录为例:

import {
+    Context, ForbiddenError, Handler, superagent, SystemModel,
+    TokenModel, UserFacingError, ValidationError,
+} from 'hydrooj';
+
+declare module 'hydrooj' {
+    interface SystemKeys {
+        'login-with-github.id': string;
+        'login-with-github.secret': string;
+        'login-with-github.endpoint': string;
+    }
+}
+
+// 当用户点击 【使用 XX 登录】 按钮时,此函数会被执行
+async function get(this: Handler) {
+    // 从系统设置中获取基础设置,并储存状态信息(完成登录逻辑后应该跳转到哪一页)
+    const [appid, [state]] = await Promise.all([
+        SystemModel.get('login-with-github.id'),
+        TokenModel.add(TokenModel.TYPE_OAUTH, 600, { redirect: this.request.referer }),
+    ]);
+    this.response.redirect = \`https://github.com/login/oauth/authorize?client_id=\${appid}&state=\${state}&scope=read:user,user:email\`;
+}
+
+// 当用户在三方系统中完成授权,需要重定向到 /oauth/xxx/callback,这时所有返回的参数作为 callback 的一参数传入。
+async function callback({ state, code }) {
+    // 获取系统设置和之前的状态。
+    const [[appid, secret, endpoint, url], s] = await Promise.all([
+        SystemModel.getMany([
+            'login-with-github.id',
+            'login-with-github.secret',
+            'login-with-github.endpoint',
+            'server.url',
+        ]),
+        TokenModel.get(state, TokenModel.TYPE_OAUTH),
+    ]);
+    if (!s) throw new ValidationError('token');
+    // 使用从 url 中返回的 token 请求第三方的 API,获取用户信息,作为函数返回。
+    // 在 OAuth 协议中,需要使用 state 和 code 换取 access_token 再调用 API,这在不同系统中可能设计不同。
+    // 系统会根据返回的用户信息自动查找已有用户或是创建新用户。
+    const res = await superagent.post(\`\${endpoint || 'https://github.com'}/login/oauth/access_token\`)
+        .send({
+            client_id: appid,
+            client_secret: secret,
+            code,
+            redirect_uri: \`\${url}oauth/github/callback\`,
+            state,
+        })
+        .set('accept', 'application/json');
+    if (res.body.error) {
+        throw new UserFacingError(
+            res.body.error, res.body.error_description, res.body.error_uri,
+        );
+    }
+    const t = res.body.access_token;
+    const userInfo = await superagent.get(\`\${endpoint ? \`\${endpoint}/api\` : 'https://api.github.com'}/user\`)
+        .set('User-Agent', 'Hydro-OAuth')
+        .set('Accept', 'application/vnd.github.v3+json')
+        .set('Authorization', \`token \${t}\`);
+    const ret = {
+        _id: \`\${userInfo.body.id}@github.local\`,
+        email: userInfo.body.email,
+        bio: userInfo.body.bio,
+        // 提供多个用户名,若需创建用户则从前往后尝试,直到用户名可用
+        uname: [userInfo.body.name, userInfo.body.login].filter((i) => i),
+        avatar: \`github:\${userInfo.body.login}\`,
+    };
+    await TokenModel.del(s._id, TokenModel.TYPE_OAUTH);
+    if (!ret.email) throw new ForbiddenError("You don't have a verified email.");
+    return ret;
+}
+
+// 注册此模块。
+export function apply(ctx: Context) {
+    ctx.provideModule('oauth', 'github', {
+        text: 'Login with Github',
+        callback,
+        get,
+    });
+    ctx.i18n.load('zh', {
+        'Login With Github': '使用 Github 登录',
+    });
+}
+
`,7),e=[o];function E(c,r){return n(),a("div",null,e)}const y=s(p,[["render",E],["__file","third-party-auth.html.vue"]]);export{y as default}; diff --git a/assets/typescript.html-82a8a6f2.js b/assets/typescript.html-82a8a6f2.js new file mode 100644 index 00000000..eea590b8 --- /dev/null +++ b/assets/typescript.html-82a8a6f2.js @@ -0,0 +1,122 @@ +import{_ as s}from"./plugin-vue_export-helper-c27b6911.js";import{o as n,c as a,e as l}from"./app-68b9e0b9.js";const p={},o=l(`

使用 TypeScript 编写插件

前置条件:NodeJS>=18
此教程将以编写剪贴板插件为例进行说明。

Step1 初始化项目

使用 hydrooj addon create 快速在 /root/addon 下初始化一个插件或是在一个空文件夹中运行 yarn init 并按照提示填写相关信息。

# 使用 yarn init 的样例
+/workspace/hydro-plugin $ yarn init
+yarn init v1.22.4
+question name (hydro-plugin): @hydrooj/pastebin
+question version (1.0.0): 0.0.1
+question description: HydroOJ的剪贴板组件
+question entry point (index.js): index.ts
+question repository url: https://github.com/hydro-dev/pastebin.git
+question author: undefined <i@undefined.moe>
+question license (MIT): MIT
+question private:
+success Saved package.json
+

Step2 准备编写组件

分析:剪贴板组件需要以下功能:

  • 与数据库交互来存储/检索相应文档。
  • 提供 /paste/create 路由以创建新文档。
  • 提供 /paste/show/:ID 来查看已创建的文档。
  • 根据用户ID进行鉴权,允许将文档设置为私密以防止他人查看。

在路由中定义所有的函数应均为异步函数,支持的函数有:prepare, get, post, post[Operation], cleanup
具体流程如下:

先执行 prepare(args) (如果存在)
+args 为传入的参数集合(包括 QueryString, Body, Path)中的全部参数,
+再执行 prepare(args) (如果存在)
+检查请求类型:
+
+为 GET ?
+  -> 执行 get(args)
+为 POST ?
+  -> 执行 post(args)
+  -> 含有 operation 字段?
+       -> 执行 post[Operation]
+
+执行 cleanup()
+

如果在 this.response.template 指定模板则渲染,否则直接返回 this.response.body 中的内容。

  • 在表单提交时的 operation 字段使用下划线,函数名使用驼峰命名。

<input type="hidden" name="operation" value="confirm_delete"> 对应 postConfirmDelete 函数。

应当提供 apply 函数,并与定义的 Handler 一同挂载到 global.Hydro.handler[模块名] 位置。 apply 函数将在初始化阶段被调用。

Step3 index.ts

// @noErrors
+// @module: esnext
+// @filename: index.ts
+import { definePlugin, Handler, Types, param, db, PRIV, validator, NotFoundError, PermissionError } from 'hydrooj';
+
+const coll = db.collection('paste');
+
+interface Paste {
+    _id: string;
+    owner: number;
+    content: string;
+    isPrivate: boolean;
+}
+
+declare module 'hydrooj' {
+    interface Model {
+        pastebin: typeof pastebinModel;
+    }
+    interface Collections {
+        paste: Paste; // 声明数据表类型
+    }
+}
+
+async function add(userId: number, content: string, isPrivate: boolean): Promise<string> {
+    const pasteId = String.random(16); // Hydro 提供了此方法,创建一个长度为16的随机字符串
+    // 使用 mongodb 为数据库驱动,相关操作参照其文档
+    const result = await coll.insertOne({
+        _id: pasteId,
+        owner: userId,
+        content,
+        isPrivate,
+    });
+    return result.insertedId; // 返回插入的文档ID
+}
+
+async function get(pasteId: string): Promise<Paste> {
+    return await coll.findOne({ _id: pasteId });
+}
+
+// 暴露这些接口,使得 cli 也能够正常调用这些函数;
+const pastebinModel = { add, get };
+global.Hydro.model.pastebin = pastebinModel;
+
+// 创建新路由
+class PasteCreateHandler extends Handler {
+    // Get请求时触发该函数
+    async get() {
+        // 检查用户是否登录,此处为多余(因为底部注册路由时已声明所需权限)
+        // 此方法适用于权限的动态检查
+        // this.checkPriv(PRIV.PRIV_USER_PROFILE);
+        this.response.template = 'paste_create.html'; // 返回此页面
+    }
+
+    // 使用 isContent 检查输入
+    @param('content', Types.String, isContent)
+    @param('private', Types.Boolean)
+    // 从用户提交的表单中取出content和private字段
+    // domainId 为固定传入参数
+    async post(domainId: string, content: string, isPrivate = false) {
+        // 在HTML表单提交的多选框中,选中值为 'on',未选中则为空,需要进行转换
+        const pasteid = await pastebin.add(this.user._id, content, !!isPrivate);
+        // 将用户重定向到创建完成的url
+        this.response.redirect = this.url('paste_show', { id: pasteid });
+        // 相应的,提供了 this.back() 方法用于将用户重定向至前一个地址(通常用于 Ajax 或是部分更新操作)
+    }
+}
+
+class PasteShowHandler extends Handler {
+    @param('id', Types.String)
+    async get(domainId: string, id: string) {
+        const doc = await pastebin.get(id);
+        if (!doc) throw new NotFoundError(id);
+        if (doc.isPrivate && this.user._id !== doc.owner) {
+            throw new PermissionError();
+        }
+        this.response.body = { doc };
+        this.response.template = 'paste_show.html';
+    }
+
+    @param('id', Types.String)
+    async postDelete(domainId: string, id: string) {
+        // 当提交表单并存在 operation 值为 delete 时执行。
+        // 本例中未实现删除功能,仅作为说明。
+    }
+}
+
+// 定义为一个插件
+export default definePlugin({
+    apply(ctx) {
+        // 注册一个名为 paste_create 的路由,匹配 '/paste/create',
+        // 使用PasteCreateHandler处理,访问改路由需要PRIV.PRIV_USER_PROFILE权限
+        // 提示:路由匹配基于 path-to-regexp
+        ctx.Route('paste_create', '/paste/create', PasteCreateHandler, PRIV.PRIV_USER_PROFILE);
+        ctx.Route('paste_show', '/paste/show/:id', PasteShowHandler);
+    }
+});
+

Step4 template

模板采用 nunjucks 语法。放置于 templates/ 文件夹下。
会在请求结束时根据 response.template 的值选择模板,并使用 response.body 的值进行渲染,存入 response.body 中。
response.template 为空或 request.headers['accept'] == 'application/json',则跳过渲染步骤。

Step5 locale

用于提供多国翻译。格式与 Hydro 的 locale 文件夹格式相同。

`,20),e=[o];function c(r,E){return n(),a("div",null,e)}const y=s(p,[["render",c],["__file","typescript.html.vue"]]);export{y as default}; diff --git a/assets/typescript.html-9acb6c36.js b/assets/typescript.html-9acb6c36.js new file mode 100644 index 00000000..1edbe7a6 --- /dev/null +++ b/assets/typescript.html-9acb6c36.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-5ddc85e1","path":"/dev/typescript.html","title":"使用 TypeScript 编写插件","lang":"en-US","frontmatter":{"description":"前置条件:NodeJS>=18 此教程将以编写剪贴板插件为例进行说明。 Step1 初始化项目 使用 hydrooj addon create 快速在 /root/addon 下初始化一个插件或是在一个空文件夹中运行 yarn init 并按照提示填写相关信息。 Step2 准备编写组件 分析:剪贴板组件需要以下功能: 与数据库交互来存储/检索相应文档...","head":[["meta",{"property":"og:url","content":"https://hydro.js.org/dev/typescript.html"}],["meta",{"property":"og:site_name","content":"Hydro"}],["meta",{"property":"og:title","content":"使用 TypeScript 编写插件"}],["meta",{"property":"og:description","content":"前置条件:NodeJS>=18 此教程将以编写剪贴板插件为例进行说明。 Step1 初始化项目 使用 hydrooj addon create 快速在 /root/addon 下初始化一个插件或是在一个空文件夹中运行 yarn init 并按照提示填写相关信息。 Step2 准备编写组件 分析:剪贴板组件需要以下功能: 与数据库交互来存储/检索相应文档..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-02-25T05:29:05.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-25T05:29:05.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"使用 TypeScript 编写插件\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-25T05:29:05.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"Step1 初始化项目","slug":"step1-初始化项目","link":"#step1-初始化项目","children":[]},{"level":2,"title":"Step2 准备编写组件","slug":"step2-准备编写组件","link":"#step2-准备编写组件","children":[]},{"level":2,"title":"Step4 template","slug":"step4-template","link":"#step4-template","children":[]},{"level":2,"title":"Step5 locale","slug":"step5-locale","link":"#step5-locale","children":[]}],"git":{"createdTime":1612251809000,"updatedTime":1677302945000,"contributors":[{"name":"undefined","email":"i@undefined.moe","commits":4},{"name":"Macesuted Kysic","email":"macesuted@foxmail.com","commits":1},{"name":"panda","email":"panda_dtdyy@outlook.com","commits":1},{"name":"无限UCW","email":"45730483+wuxianucw@users.noreply.github.com","commits":1}]},"readingTime":{"minutes":3.46,"words":1039},"filePathRelative":"dev/typescript.md","localizedDate":"February 2, 2021","autoDesc":true,"excerpt":""}');export{e as data}; diff --git a/assets/vjudge.html-22798d18.js b/assets/vjudge.html-22798d18.js new file mode 100644 index 00000000..69e6de65 --- /dev/null +++ b/assets/vjudge.html-22798d18.js @@ -0,0 +1,136 @@ +import{_ as p}from"./plugin-vue_export-helper-c27b6911.js";import{r as o,o as e,c,a as n,b as s,d as r,e as a}from"./app-68b9e0b9.js";const F={},E=a('

Vjudge

Note

此文档已过时,仅作留存使用,请前往 FAQS 查看使用指南。

Codeforces

',3),t=n("br",null,null,-1),i={href:"https://github.com/hydro-dev/Hydro/blob/master/packages/vjudge/src/providers/codeforces.ts",target:"_blank",rel:"noopener noreferrer"},y=a(`

安装插件后创建名为 codeforces 的域,进入数据库 db.domain.updateOne({_id:'codeforces'},{$set:{mount:'codeforces'}});

在 codeforces 的域设置中,将 allowedLangs 如下配置(在新版即在允许提交的语言中选中所有 codeforces 开头的语言):

codeforces,codeforces.43,codeforces.52,codeforces.50,codeforces.54,codeforces.59,codeforces.61,codeforces.65,codeforces.9,codeforces.28,codeforces.32,codeforces.12,codeforces.60,codeforces.36,codeforces.48,codeforces.19,codeforces.3,codeforces.4,codeforces.51,codeforces.13,codeforces.6,codeforces.7,codeforces.31,codeforces.40,codeforces.41,codeforces.67,codeforces.49,codeforces.20,codeforces.34,codeforces.55
+

在 vjudge 表中插入如下条目:

{type:'codeforces', handle:'<codeforces login handle>', password:'<codeforces login password>'}
+

将如下配置添加至 langs 设置末尾:

codeforces:
+  execute: none
+  display: Codeforces
+  domain:
+  - codeforces # Allow domain 'codeforces' to use these languages
+codeforces.43:
+  highlight: cpp astyle-c
+  monaco: cpp
+  display: GNU GCC C11 5.1.0
+  comment: //
+codeforces.52:
+  highlight: cpp astyle-c
+  monaco: cpp
+  display: Clang++17 Diagnostics
+  comment: //
+codeforces.50:
+  highlight: cpp astyle-c
+  monaco: cpp
+  display: GNU G++14 6.4.0
+  comment: //
+codeforces.54:
+  highlight: cpp astyle-c
+  monaco: cpp
+  display: GNU G++17 7.3.0
+  comment: //
+codeforces.59:
+  highlight: cpp astyle-c
+  monaco: cpp
+  display: Microsoft Visual C++ 2017
+  comment: //
+codeforces.61:
+  highlight: cpp astyle-c
+  monaco: cpp
+  display: GNU G++17 9.2.0 (64 bit, msys 2)
+  comment: //
+codeforces.65:
+  highlight: cpp astyle-cs
+  monaco: csharp
+  display: C# 8, .NET Core 3.1
+  comment: //
+codeforces.9:
+  highlight: cpp astyle-cs
+  monaco: csharp
+  display: C# Mono 6.8
+  comment: //
+codeforces.28:
+  highlight: d
+  monaco: plain
+  display: D DMD32 v2.091.0
+  comment: //
+codeforces.32:
+  highlight: go
+  display: Go 1.15.6
+  comment: //
+codeforces.12:
+  highlight: haskell
+  display: Haskell GHC 8.10.1
+  comment: --
+codeforces.60:
+  highlight: java astyle-java
+  monaco: java
+  display: Java 11.0.6
+  comment: //
+codeforces.36:
+  highlight: java astyle-java
+  monaco: java
+  display: Java 1.8.0_241
+  comment: //
+codeforces.48:
+  highlight: kotlin
+  display: Kotlin 1.4.0
+  comment: //
+codeforces.19:
+  highlight: ocaml
+  monaco: plain
+  display: OCaml 4.02.1
+  comment: ['(*','*)']
+codeforces.3:
+  highlight: pascal
+  display: Delphi 7
+  comment: //
+codeforces.4:
+  highlight: pascal
+  display: Free Pascal 3.0.2
+  comment: //
+codeforces.51:
+  highlight: pascal
+  display: PascalABC.NET 3.4.2
+  comment: //
+codeforces.13:
+  highlight: perl
+  display: Perl 5.20.1
+  comment: '#'
+codeforces.6:
+  highlight: php
+  display: PHP 7.2.13
+  comment: //
+codeforces.7:
+  highlight: python
+  display: Python 2.7.18
+  comment: '#'
+codeforces.31:
+  highlight: python
+  display: Python 3.9.1
+  comment: '#'
+codeforces.40:
+  highlight: python
+  display: PyPy 2.7 (7.3.0)
+  comment: '#'
+codeforces.41:
+  highlight: python
+  display: PyPy 3.7 (7.3.0)
+  comment: '#'
+codeforces.67:
+  highlight: ruby
+  display: Ruby 3.0.0
+  comment: '#'
+codeforces.49:
+  highlight: rust
+  display: Rust 1.49.0
+  comment: //
+codeforces.20:
+  highlight: scala
+  display: Scala 2.12.8
+  comment: //
+codeforces.34:
+  highlight: javascript
+  display: JavaScript V8 4.8.0
+  comment: //
+codeforces.55:
+  highlight: javascript
+  display: Node.js 12.6.3
+  comment: //
+

之后再重启 Hydro 即可。

`,8);function B(d,D){const l=o("ExternalLinkIcon");return e(),c("div",null,[E,n("p",null,[s("由于 vjudge 更新了反爬虫机制,Codeforces RemoteJudge 需要一些特殊手段才能正常工作。"),t,s(" 详情请 "),n("a",i,[s("阅读源码"),r(l)])]),y])}const m=p(F,[["render",B],["__file","vjudge.html.vue"]]);export{m as default}; diff --git a/assets/vjudge.html-b94954ed.js b/assets/vjudge.html-b94954ed.js new file mode 100644 index 00000000..167efafd --- /dev/null +++ b/assets/vjudge.html-b94954ed.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-3096c190","path":"/plugins/vjudge.html","title":"Vjudge","lang":"en-US","frontmatter":{"description":"此文档已过时,仅作留存使用,请前往 FAQS 查看使用指南。 Codeforces 由于 vjudge 更新了反爬虫机制,Codeforces RemoteJudge 需要一些特殊手段才能正常工作。 详情请 阅读源码 (https://github.com/hydro-dev/Hydro/blob/master/packages/vjudge/src/...","head":[["meta",{"property":"og:url","content":"https://hydro.js.org/plugins/vjudge.html"}],["meta",{"property":"og:site_name","content":"Hydro"}],["meta",{"property":"og:title","content":"Vjudge"}],["meta",{"property":"og:description","content":"此文档已过时,仅作留存使用,请前往 FAQS 查看使用指南。 Codeforces 由于 vjudge 更新了反爬虫机制,Codeforces RemoteJudge 需要一些特殊手段才能正常工作。 详情请 阅读源码 (https://github.com/hydro-dev/Hydro/blob/master/packages/vjudge/src/..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-05-12T03:18:30.000Z"}],["meta",{"property":"article:modified_time","content":"2023-05-12T03:18:30.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Vjudge\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-05-12T03:18:30.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"Codeforces","slug":"codeforces","link":"#codeforces","children":[]}],"git":{"createdTime":1624333296000,"updatedTime":1683861510000,"contributors":[{"name":"undefined","email":"i@undefined.moe","commits":3},{"name":"panda","email":"panda_dtdyy@outlook.com","commits":2},{"name":"Macesuted","email":"macesuted@qq.com","commits":1}]},"readingTime":{"minutes":1.67,"words":501},"filePathRelative":"plugins/vjudge.md","localizedDate":"June 22, 2021","autoDesc":true,"excerpt":""}');export{e as data}; diff --git a/dev/PERM_PRIV.html b/dev/PERM_PRIV.html new file mode 100644 index 00000000..dddfcd0b --- /dev/null +++ b/dev/PERM_PRIV.html @@ -0,0 +1,40 @@ + + + + + + + + 权限节点 | Hydro + + + + + + +

权限节点


权限节点

Hydro 的权限使用位运算处理。
例:若某用户具有 PRIV_EDIT_SYSTEMPRIV_SET_PERM 权限,应设置为 (1<<0)|(1<<1) (即 3)

可以看 代码open in new window 中关于此部分的内容。

+ + + diff --git a/dev/frontend-modify.html b/dev/frontend-modify.html new file mode 100644 index 00000000..f8fe3233 --- /dev/null +++ b/dev/frontend-modify.html @@ -0,0 +1,40 @@ + + + + + + + + 前端修改 | Hydro + + + + + + + + + + diff --git a/dev/hook.html b/dev/hook.html new file mode 100644 index 00000000..85df2cb4 --- /dev/null +++ b/dev/hook.html @@ -0,0 +1,53 @@ + + + + + + + + 使用 TypeScript 编写插件 | Hydro + + + + + + +

使用 TypeScript 编写插件


使用 TypeScript 编写插件

请注意:在阅读本节之前,请确认您已阅读【使用 TypeScript 编写插件】一节并已完成了插件的创建。

示例

import { Context, Time } from 'hydrooj';
+
+export async function apply(ctx: Context) {
+    // handler 表示路由事件
+    // after 表示在主逻辑完成后运行
+    // RecordDetail 为需要捕获的路由名
+    // get 表示仅捕获 GET 请求
+    ctx.on('handler/after/RecordDetail#get', (h) => {
+        if (h.rdoc._id.getTimestamp() < new Date(Date.now() - Time.day) {
+            h.rdoc.code = '';
+        }
+    });
+}
+
+ + + diff --git a/dev/index.html b/dev/index.html new file mode 100644 index 00000000..5159e820 --- /dev/null +++ b/dev/index.html @@ -0,0 +1,46 @@ + + + + + + + + 开发环境部署 | Hydro + + + + + + +

开发环境部署


开发环境部署

如果您没有过 TypeScript 项目的开发经验,非常不建议自建开发环境。
使用自动脚本安装也可以基于插件系统完成大部分的定制需求(参照左侧【使用 TypeScript 编写插件】章节)。

您可以使用 Gitpodopen in new window 快速打开配置完成的开发环境或是按照下方说明进行手动配置。(由于 Gitpod 的限制,hydrojudge 模块无法正常运行,若需要开发 hydrojudge 相关内容请自行部署)

安装依赖

  • 系统要求:Hydro开发环境目前仅支持 Linux/Unix 系统,如您使用 Windows 请使用 WSL2 。
  • MongoDB:Hydro 需要 MongoDBopen in new window 提供数据库服务。
  • NodeJS:请安装 NodeJS >=18 版本。(若使用 apt 请使用 nodesource 提供的源替代官方源) (推荐使用 nix ,可通过. <(curl https://hydro.ac/nix.sh) 快速安装)
  • yarn:安装 yarn 前请先完成 NodeJS 安装。 npm install -g yarn

尽管这不是必须的,但文档多数区域使用了 npx 工具来调用工作区的程序。如果此命令不存在,你可以在 Hydro 项目文件夹外使用 yarn global add npx 安装它。

安装 Hydro

git clone https://github.com/hydro-dev/Hydro.git /root/Hydro --recursive # 下载至 /root/Hydro 文件夹
+cd /root/Hydro # 进入工作目录
+yarn # 安装依赖包
+yarn build:ui:production # 编译前端
+

插件

开发环境部署完成后默认不启用任何插件。

所有官方插件均随源码仓库下载到安装文件夹的 packages 子文件夹下,可以通过下面的命令启用官方插件(以启用 @hydrooj/ui-default 为例):

npx hydrooj addon add @hydrooj/ui-default
+

对于非官方插件,下载后通过下面的命令启用即可(以启用位置在 /root/addon 下的插件为例):

npx hydrooj addon add /root/addon
+

启动 Hydro

支持如下启动参数:

  • --port=2333 指定启动端口
  • --debug 启用开发模式

使用 yarn debug --port=2333 --watch 启动 Hydro,并在后台运行 yarn build:ui:dev,可以对前端源码进行实时转译,在反复修改时可节省编译时间。启动完成后,您可以在 8000 端口访问到 Hydro 实例,且前端的任何更改将即时生效。(后端热重载可能存在 bug,部分模块修改后可能仍需重启才能生效)
请注意:此功能仅在启用了 @hydrooj/ui-default 插件的情况下才会生效。

首次启动会要求您填写数据库连接信息。请根据您数据库的安装填写(若无密码则留空)
请按照下文说明创建管理员账户即可正常使用。

更新

需要更新的时候进入对应仓库文件夹执行 git pull,然后重新 yarn && yarn build:ui:production 即可。

+ + + diff --git a/dev/third-party-auth.html b/dev/third-party-auth.html new file mode 100644 index 00000000..7a517b06 --- /dev/null +++ b/dev/third-party-auth.html @@ -0,0 +1,122 @@ + + + + + + + + 接入第三方账号系统 | Hydro + + + + + + +

接入第三方账号系统


接入第三方账号系统

Hydro 支持接入第三方的账号系统,并且有以下内置模块可用:

  • @hydrooj/login-with-github
  • @hydrooj/login-with-google

对接其他平台

在阅读本节之前,请确保你已阅读 【插件开发】 章节。

以 Github 登录为例:

import {
+    Context, ForbiddenError, Handler, superagent, SystemModel,
+    TokenModel, UserFacingError, ValidationError,
+} from 'hydrooj';
+
+declare module 'hydrooj' {
+    interface SystemKeys {
+        'login-with-github.id': string;
+        'login-with-github.secret': string;
+        'login-with-github.endpoint': string;
+    }
+}
+
+// 当用户点击 【使用 XX 登录】 按钮时,此函数会被执行
+async function get(this: Handler) {
+    // 从系统设置中获取基础设置,并储存状态信息(完成登录逻辑后应该跳转到哪一页)
+    const [appid, [state]] = await Promise.all([
+        SystemModel.get('login-with-github.id'),
+        TokenModel.add(TokenModel.TYPE_OAUTH, 600, { redirect: this.request.referer }),
+    ]);
+    this.response.redirect = `https://github.com/login/oauth/authorize?client_id=${appid}&state=${state}&scope=read:user,user:email`;
+}
+
+// 当用户在三方系统中完成授权,需要重定向到 /oauth/xxx/callback,这时所有返回的参数作为 callback 的一参数传入。
+async function callback({ state, code }) {
+    // 获取系统设置和之前的状态。
+    const [[appid, secret, endpoint, url], s] = await Promise.all([
+        SystemModel.getMany([
+            'login-with-github.id',
+            'login-with-github.secret',
+            'login-with-github.endpoint',
+            'server.url',
+        ]),
+        TokenModel.get(state, TokenModel.TYPE_OAUTH),
+    ]);
+    if (!s) throw new ValidationError('token');
+    // 使用从 url 中返回的 token 请求第三方的 API,获取用户信息,作为函数返回。
+    // 在 OAuth 协议中,需要使用 state 和 code 换取 access_token 再调用 API,这在不同系统中可能设计不同。
+    // 系统会根据返回的用户信息自动查找已有用户或是创建新用户。
+    const res = await superagent.post(`${endpoint || 'https://github.com'}/login/oauth/access_token`)
+        .send({
+            client_id: appid,
+            client_secret: secret,
+            code,
+            redirect_uri: `${url}oauth/github/callback`,
+            state,
+        })
+        .set('accept', 'application/json');
+    if (res.body.error) {
+        throw new UserFacingError(
+            res.body.error, res.body.error_description, res.body.error_uri,
+        );
+    }
+    const t = res.body.access_token;
+    const userInfo = await superagent.get(`${endpoint ? `${endpoint}/api` : 'https://api.github.com'}/user`)
+        .set('User-Agent', 'Hydro-OAuth')
+        .set('Accept', 'application/vnd.github.v3+json')
+        .set('Authorization', `token ${t}`);
+    const ret = {
+        _id: `${userInfo.body.id}@github.local`,
+        email: userInfo.body.email,
+        bio: userInfo.body.bio,
+        // 提供多个用户名,若需创建用户则从前往后尝试,直到用户名可用
+        uname: [userInfo.body.name, userInfo.body.login].filter((i) => i),
+        avatar: `github:${userInfo.body.login}`,
+    };
+    await TokenModel.del(s._id, TokenModel.TYPE_OAUTH);
+    if (!ret.email) throw new ForbiddenError("You don't have a verified email.");
+    return ret;
+}
+
+// 注册此模块。
+export function apply(ctx: Context) {
+    ctx.provideModule('oauth', 'github', {
+        text: 'Login with Github',
+        callback,
+        get,
+    });
+    ctx.i18n.load('zh', {
+        'Login With Github': '使用 Github 登录',
+    });
+}
+
+ + + diff --git a/dev/typescript.html b/dev/typescript.html new file mode 100644 index 00000000..a324f368 --- /dev/null +++ b/dev/typescript.html @@ -0,0 +1,161 @@ + + + + + + + + 使用 TypeScript 编写插件 | Hydro + + + + + + +

使用 TypeScript 编写插件


使用 TypeScript 编写插件

前置条件:NodeJS>=18
此教程将以编写剪贴板插件为例进行说明。

Step1 初始化项目

使用 hydrooj addon create 快速在 /root/addon 下初始化一个插件或是在一个空文件夹中运行 yarn init 并按照提示填写相关信息。

# 使用 yarn init 的样例
+/workspace/hydro-plugin $ yarn init
+yarn init v1.22.4
+question name (hydro-plugin): @hydrooj/pastebin
+question version (1.0.0): 0.0.1
+question description: HydroOJ的剪贴板组件
+question entry point (index.js): index.ts
+question repository url: https://github.com/hydro-dev/pastebin.git
+question author: undefined <i@undefined.moe>
+question license (MIT): MIT
+question private:
+success Saved package.json
+

Step2 准备编写组件

分析:剪贴板组件需要以下功能:

  • 与数据库交互来存储/检索相应文档。
  • 提供 /paste/create 路由以创建新文档。
  • 提供 /paste/show/:ID 来查看已创建的文档。
  • 根据用户ID进行鉴权,允许将文档设置为私密以防止他人查看。

在路由中定义所有的函数应均为异步函数,支持的函数有:prepare, get, post, post[Operation], cleanup
具体流程如下:

先执行 prepare(args) (如果存在)
+args 为传入的参数集合(包括 QueryString, Body, Path)中的全部参数,
+再执行 prepare(args) (如果存在)
+检查请求类型:
+
+为 GET ?
+  -> 执行 get(args)
+为 POST ?
+  -> 执行 post(args)
+  -> 含有 operation 字段?
+       -> 执行 post[Operation]
+
+执行 cleanup()
+

如果在 this.response.template 指定模板则渲染,否则直接返回 this.response.body 中的内容。

  • 在表单提交时的 operation 字段使用下划线,函数名使用驼峰命名。

<input type="hidden" name="operation" value="confirm_delete"> 对应 postConfirmDelete 函数。

应当提供 apply 函数,并与定义的 Handler 一同挂载到 global.Hydro.handler[模块名] 位置。 apply 函数将在初始化阶段被调用。

Step3 index.ts

// @noErrors
+// @module: esnext
+// @filename: index.ts
+import { definePlugin, Handler, Types, param, db, PRIV, validator, NotFoundError, PermissionError } from 'hydrooj';
+
+const coll = db.collection('paste');
+
+interface Paste {
+    _id: string;
+    owner: number;
+    content: string;
+    isPrivate: boolean;
+}
+
+declare module 'hydrooj' {
+    interface Model {
+        pastebin: typeof pastebinModel;
+    }
+    interface Collections {
+        paste: Paste; // 声明数据表类型
+    }
+}
+
+async function add(userId: number, content: string, isPrivate: boolean): Promise<string> {
+    const pasteId = String.random(16); // Hydro 提供了此方法,创建一个长度为16的随机字符串
+    // 使用 mongodb 为数据库驱动,相关操作参照其文档
+    const result = await coll.insertOne({
+        _id: pasteId,
+        owner: userId,
+        content,
+        isPrivate,
+    });
+    return result.insertedId; // 返回插入的文档ID
+}
+
+async function get(pasteId: string): Promise<Paste> {
+    return await coll.findOne({ _id: pasteId });
+}
+
+// 暴露这些接口,使得 cli 也能够正常调用这些函数;
+const pastebinModel = { add, get };
+global.Hydro.model.pastebin = pastebinModel;
+
+// 创建新路由
+class PasteCreateHandler extends Handler {
+    // Get请求时触发该函数
+    async get() {
+        // 检查用户是否登录,此处为多余(因为底部注册路由时已声明所需权限)
+        // 此方法适用于权限的动态检查
+        // this.checkPriv(PRIV.PRIV_USER_PROFILE);
+        this.response.template = 'paste_create.html'; // 返回此页面
+    }
+
+    // 使用 isContent 检查输入
+    @param('content', Types.String, isContent)
+    @param('private', Types.Boolean)
+    // 从用户提交的表单中取出content和private字段
+    // domainId 为固定传入参数
+    async post(domainId: string, content: string, isPrivate = false) {
+        // 在HTML表单提交的多选框中,选中值为 'on',未选中则为空,需要进行转换
+        const pasteid = await pastebin.add(this.user._id, content, !!isPrivate);
+        // 将用户重定向到创建完成的url
+        this.response.redirect = this.url('paste_show', { id: pasteid });
+        // 相应的,提供了 this.back() 方法用于将用户重定向至前一个地址(通常用于 Ajax 或是部分更新操作)
+    }
+}
+
+class PasteShowHandler extends Handler {
+    @param('id', Types.String)
+    async get(domainId: string, id: string) {
+        const doc = await pastebin.get(id);
+        if (!doc) throw new NotFoundError(id);
+        if (doc.isPrivate && this.user._id !== doc.owner) {
+            throw new PermissionError();
+        }
+        this.response.body = { doc };
+        this.response.template = 'paste_show.html';
+    }
+
+    @param('id', Types.String)
+    async postDelete(domainId: string, id: string) {
+        // 当提交表单并存在 operation 值为 delete 时执行。
+        // 本例中未实现删除功能,仅作为说明。
+    }
+}
+
+// 定义为一个插件
+export default definePlugin({
+    apply(ctx) {
+        // 注册一个名为 paste_create 的路由,匹配 '/paste/create',
+        // 使用PasteCreateHandler处理,访问改路由需要PRIV.PRIV_USER_PROFILE权限
+        // 提示:路由匹配基于 path-to-regexp
+        ctx.Route('paste_create', '/paste/create', PasteCreateHandler, PRIV.PRIV_USER_PROFILE);
+        ctx.Route('paste_show', '/paste/show/:id', PasteShowHandler);
+    }
+});
+

Step4 template

模板采用 nunjucks 语法。放置于 templates/ 文件夹下。
会在请求结束时根据 response.template 的值选择模板,并使用 response.body 的值进行渲染,存入 response.body 中。
response.template 为空或 request.headers['accept'] == 'application/json',则跳过渲染步骤。

Step5 locale

用于提供多国翻译。格式与 Hydro 的 locale 文件夹格式相同。

+ + + diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 00000000..ba3fc0c6 --- /dev/null +++ b/docs/index.html @@ -0,0 +1,44 @@ + + + + + + + + 介绍 | Hydro + + + + + + +

介绍


介绍

为什么使用 Hydro?

  • 安全:使用 cgroup 进行隔离,杜绝卡评测;

  • 高效:Hydro 使用了沙箱复用技术,拥有极高的评测效率;

  • 扩展:Hydro 支持安装额外模块进行扩展;

  • 强大:配合 Judge 模块(或 HydroJudge 独立评测机),可支持 spj,交互题,提交答案题,文件IO 等多种特性;

  • 自定:所有权限节点均可自由设置;

  • 易上手:无需改动源代码,系统设置中预留了大量可自行修改的内容;管理逻辑简洁;

  • 社区:Hydro 正在持续维护中;

  • 如果您正在使用 HustOJ,可以导出题目为 FPS 文件后使用 fps-importer 插件 直接导入 Hydro。

  • 如果您正在使用 QDUOJ, 可以导出题目为 QDUOJ-zip 格式后使用 import-qduoj 插件直接导入 Hydro。

  • 如果您正在使用 Vijos / SYZOJ / HustOJ / UniversalOJ, 可以直接使用 migrate 插件 导入所有数据至 Hydro。

功能对比

Hydro 支持很多其他系统无法支持的题型,可在 https://hydro.ac/d/system_test/p 中查看并免费下载使用样例。(需要登录)
下方对比了 Hydro 与其他主流 OJ 系统的功能。(只进行在不修改源代码情况下的对比)

+:支持
+=:部分支持
+?: 未知
+-:不支持
+
功能HydroHustOJSYZOJ[1]QDUOJVijos
安装一键脚本一键脚本手动搭建dockerdocker
数据库MongoDBMySQLMariaDBPostgresMongoDB
测试数据存储本地/S3 [2]本地本地本地数据库
多评测机+=[3]=[4]=+
测试数据同步按需抓取全量同步全量同步全量同步按需抓取
比赛ACM/OI/IOI/乐多ACM/OIACM/OI/IOIACM/OI/IOIACM/OI
封榜++---
作业功能++--+
修改编译命令/添加语言+=[5]--+
权限系统 [6]+=--+
训练计划(题单)++-[7]-+
团队+ [8]---+
Hack+----
SpecialJudge+ [9]++-=
Subtask+-+--
交互题+-+--
RemoteJudgeCF/SPOJ/UOJ/POJ/LuoguHDU/PKU---
题目导入fps/syzoj/qduoj/hydrofps/qduojsyzojfps/qduoj-

截图

imgimgimgimgimgimgimgimg

现在开始

点击 部署 ,开始部署您的 OJ 吧!


  1. SYZOJ 和 Lyrio (曾用名 syzoj-ng,loj.ac 当前所用系统) 是两套不同的系统,这意味着使用 SYZOJ 无法再导入 loj.ac 的题目,同时 Lyrio 无比赛功能。 ↩︎

  2. S3 指所有兼容 Amazon S3 协议的服务,包括腾讯COS,阿里OSS 等。 ↩︎

  3. 安装配置繁琐,且需要手动在服务器间同步数据。 ↩︎

  4. 需要手动在服务器间同步数据。 ↩︎

  5. 仅能修改部分编译参数,添加语言需要修改源代码。 ↩︎

  6. 此处的权限系统指 除用户/管理员二元化权限之外的 的更细粒度的权限划分。 ↩︎

  7. 部分二次开发版本有此功能。 ↩︎

  8. 通过域功能,允许用户创建域并在域内拥有管理员权限。域之间仅共享账号数据,也可使用域内小组进行权限控制。 ↩︎

  9. 支持所有主流 SPJ 格式。 ↩︎

+ + + diff --git a/docs/install/compiler.html b/docs/install/compiler.html new file mode 100644 index 00000000..607c57ba --- /dev/null +++ b/docs/install/compiler.html @@ -0,0 +1,77 @@ + + + + + + + + 编译器 | Hydro + + + + + + +

编译器


编译器

从 2022/8/12 开始,Hydro 为了避免宿主机环境变化对于评测的影响,对于 此后新安装的实例 默认使用 nix 管理环境。
如果你是在这之前安装的 Hydro,请使用 apt 安装编译器后使用 pm2 restart hydro-sandbox 重启沙箱,并忽略本章节。

以下是 nix 的简要操作说明:

使用 nix-env -iA nixpkgs.编译器名 安装新编译器,后重启沙箱 pm2 restart hydro-sandbox 生效。

可以在 Nixos Searchopen in new window 中搜索你需要的编译器。
以下是常用编译器的示例:

nix-env -iA nixpkgs.busybox nixpkgs.bash nixpkgs.diffutils nixpkgs.unzip # 基础组件,已预装,不建议删除
+nix-env -iA nixpkgs.gcc nixpkgs.fpc # C/C++ 和 Pascal,已预装,不建议删除
+nix-env -iA nixpkgs.ghc # Haskell 
+nix-env -iA nixpkgs.rustc # Rust
+nix-env -iA nixpkgs.python2 # Python2
+nix-env -iA nixpkgs.pythonPackages.numpy # Python2 Numpy 库
+nix-env -iA nixpkgs.python3Minimal
+nix-env -iA nixpkgs.python3Packages.numpy
+nix-env -iA nixpkgs.php # PHP
+nix-env -iA nixpkgs.go # Golang
+nix-env -iA nixpkgs.nodejs # NodeJS
+nix-env -iA nixpkgs.openjdk_headless # Java
+nix-env -iA nixpkgs.ruby # Ruby
+nix-env -iA nixpkgs.mono # C#
+nix-env -iA nixpkgs.julia_17-bin # Julia
+

使用 nix-env -q 查看已安装的列表,后使用 nix-env -e 编译器名 即可删除对应的编译器。
请注意不要误删 Hydro 基础组件,且操作完成后需要重启沙箱 pm2 restart hydro-sandbox 生效。

进阶

如果你需要更加复杂的编译环境配置,我们建议使用编写单独的 nix 文件。

{ 
+  system ? builtins.currentSystem,
+  pkgs ? import <nixpkgs> { system = system; }
+}:
+
+pkgs.buildEnv {
+  name = "hydrojudge-rootfs";
+  paths = with pkgs; [
+    coreutils bash diffutils nix zip unzip gcc
+    # 上方包是评测所需要的,请勿删除,
+    # 在下方列出你所需要的包,查找方式同上文:
+    fpc python3 rustc
+  ];
+  ignoreCollisions = true;
+  pathsToLink = [ "/" ];
+  # 导出一些基本信息和部分编译器所需的 /etc/passwd
+  postBuild = ''
+    mkdir $out/buildInfo
+    echo 'root:x:0:0:root:/root:/bin/bash' >$out/etc/passwd
+    date >$out/buildInfo/timestamp
+  '';
+}
+

复制以上文件,保存为 default.nix ,使用 nix-build 进行构建。
构建后会产生一个 result 文件夹,记住该文件夹所在的路径。
打开 ~/.hydro/mount.yaml 将其中 /root/.nix-profile 替换为编译出的 result 文件夹(切换到新的环境)
之后保存并重启沙箱。

后续若需更改环境配置,仅需要修改 default.nix 文件之后 nix-build 重新构建,再重启沙箱即可生效。
构建过程中的缓存文件可以使用 nix-collect-garbage 进行清理。

更详细的 nix 语言介绍,请参照 Nix Guideopen in new windowNix Manualopen in new window

+ + + diff --git a/docs/install/index.html b/docs/install/index.html new file mode 100644 index 00000000..8a3947a9 --- /dev/null +++ b/docs/install/index.html @@ -0,0 +1,42 @@ + + + + + + + + 部署 Hydro | Hydro + + + + + + +

部署 Hydro


部署 Hydro

这里提供了几套方案帮助您建立自己的站点,请选择适合您的方案并继续。
搭建过程中如果遇到问题欢迎 联系我们 提问。

服务器选择

不同服务商提供的 CPU 主频不同,下方数据仅供参考。
最低服务器配置: CPU: 1核 内存: 2G。(约可允许 100 人使用)
请尽量不要使用突发性能实例或共享型实例,这可能会导致评测时间计量不准确

CentOS 8 已于 2021-12-31 停止支持open in new window,后续不会为安全漏洞发布补丁,建议重装为其他操作系统。

Tips

兼容大部分 Linux 发行版,推荐使用 Debian 12 / Debian 11 / Ubuntu 22.04 (教程多,成功率高,上手简单),不支持 CentOS 及其各种变种:

  • CentOS
  • Alibaba Cloud Linux
  • TencentOS
  • OpenCloudOS

如果你的机器内存较小(<=2GiB),请避免使用 Ubuntu 22.04,它会消耗较多的内存。建议使用 Debian 12 / Debian 11。
如果你有 Linux 运维经验,Hydro 同样支持在 Alpine Linux 上运行,Alpine Linux 系统启动后仅占用 ~100M 内存,是在低配置服务器上运行的更优方案。

Note

虚拟机用户请注意:

  • Hydro 使用的数据库依赖于 CPU 的 avx 指令集以提高运行性能,大部分虚拟机软件默认没有启用 avx 指令集,请参照您使用的虚拟机软件说明。
  • 虚拟机由于非独占 CPU,会导致评测时间计量精度降低。
  • 由于虚拟机本身的数据保存机制,突然断电很容易导致数据库损坏无法读取,请务必定期备份数据库,有条件请购买 UPS 保证供电稳定。

Docker 用户请注意:

  • 使用安装脚本需要设置 USER 环境变量为 root
  • 需要使用 --privileged 参数启动容器,否则评测机无法运行。

部署

Tips

Hydro 需要使用以下端口: 80, 443, 2019, 8888, 5050, 27017,请确保这些端口空闲。
安装和安装后的所有操作均需要在 root 权限下进行!(sudo su
宝塔面板已知出现多次高危漏洞,为防止数据丢失,请不要在生产环境中使用!

运行下面的脚本,等待几分钟即可(建议复制防止敲错):

LANG=zh . <(curl https://hydro.ac/setup.sh)
+

Tips

如果有特殊需求,安装脚本支持一些可选的高级选项,以此方式调用: . <(curl https://hydro.ac/setup.sh) --foo --bar

  • --no-caddy 不配置安装反向代理,只监听8888端口
  • --judge 仅作为独立评测机安装

阿里云/腾讯云/华为云等等用户安装后如果不能访问 请百度搜索 xx云 放行80端口
脚本默认使用的为清华大学镜像。
安装完成后,从 http://服务器ip/ 访问网页端,注册一个账号,之后在终端中使用

hydrooj cli user setSuperAdmin 2
+

将首个注册用户设置为超级管理员。之后刷新页面,您应当能在上方导航栏看到控制面板入口。
进入控制面板,右侧系统设置,验证管理员密码后按需修改配置,注意 Server BaseURL 一项需要填写访问网站用的完整的 URL,以 / 结尾。(重要,务必正确填写,样例:https://hydro.ac/

系统安装后需要题库,可前往 https://hydro.ac/d/tk/p 免费专区进行下载,支持批量导入。 至此,基础功能安装已全部完成,另,如果你的服务部署在内网,且希望外网的用户可以访问,可以百度搜索 “端口映射” 相关教程。

+ + + diff --git a/docs/install/proxy.html b/docs/install/proxy.html new file mode 100644 index 00000000..58ec7d4f --- /dev/null +++ b/docs/install/proxy.html @@ -0,0 +1,61 @@ + + + + + + + + 反向代理 / SSL 配置 | Hydro + + + + + + +

反向代理 / SSL 配置


反向代理 / SSL 配置

2022/10/27 后使用脚本安装的实例已自动配置 Caddy 反向代理,请直接编辑位于 ~/.hydro/Caddyfile 的配置文件!

Note

若使用反向代理,请注意系统设置中的 server.xff 和 server.xhost 设置项需要填写正确(小写),分别对应反向代理所添加的标头名(通常为 x-forwarded-for 和 x-forwarded-host,部分反代工具会使用 x-real-ip 替代 x-forwarded-for)。
server.xhost 设置项配置错误会导致用户无法登录等问题。(CsrfTokenError)
server.xff 设置项配置错误会导致无法记录用户IP。

除一键安装脚本在安装 Caddy 后会自动配置设置项,其他工具请在使用工具前先配置好系统设置!否则将造成用户无法登录、无法记录用户IP等问题。

若您使用 Nginx,请注意配置 WebSocket 协议的反向代理,否则会导致评测状态无法自动刷新,在线 IDE 无法正常使用等问题。

Hydro 支持使用 Caddy, HaProxy 等工具进行反向代理,此处open in new window 提供了一些配置样例。

Hydro 推荐您使用 Caddyopen in new window。以下为样例 Caddyfile。 提示:如果您的服务器位于国内,则需要进行备案后才能使用 80 和 443 端口。

hydro.ac {
+  log {
+    output file /data/access.log {
+      roll_size 1gb
+      roll_keep_for 72h
+    }
+    format json
+  }
+  root * /root/.hydro/static
+  @static {
+    file {
+      try_files {path}
+    }
+  }
+  handle @static {
+    file_server
+  }
+  handle {
+    reverse_proxy http://127.0.0.1:8888
+  }
+}
+
+ + + diff --git a/docs/install/s3.html b/docs/install/s3.html new file mode 100644 index 00000000..60ced292 --- /dev/null +++ b/docs/install/s3.html @@ -0,0 +1,40 @@ + + + + + + + + 存储 | Hydro + + + + + + +

存储


存储

Tips

使用一键安装脚本部署的 Hydro 一般已自动完成存储配置。

文件默认存储于本地的 /data/file/hydro 目录下,切换存储后端时需要手动复制或移动原有文件。
请根据你使用的存储端类型阅读对应教程。(同时欢迎使用其他存储类型的用户向我们提供详细的存储教程)

MinIO

Note

新版本 MinIO 占用较大,如果您为轻量使用,我们不建议使用 MinIO 。旧版本 Hydro 用户大部分可直接切换至 file 模式,由 Hydro 代替读取。

安装 MinIOopen in new window 后进入 控制面板>manage_config。

  • file.type: s3
  • file.endPointhttp://127.0.0.1:9000(即 MinIO 启动时显示的 endPoint)
  • file.accessKey: 参照 MinIO 配置
  • file.secretKey: 参照 MinIO 配置
  • file.buckethydro(MinIO 内部存储桶名称)
  • file.regionus-east-1
  • file.pathStyle: true
  • file.endPointForUser/fs/
  • file.endPointForJudge/fs/

保存后重启,已有文件请自行复制。

腾讯云COS

进入 控制面板>系统设置>存储桶设置。

  • file.type: s3
  • file.endPointhttp://cos.<存储桶地域>.myqcloud.com (或是 https)
  • file.accessKey: 您的腾讯云 API 密钥的 SecretId
  • file.secretKey: 您的腾讯云 API 密钥的 SecretKey
  • file.bucket: <存储桶名称>
  • file.region: Auto
  • file.pathStyle: true
  • file.endPointForUser: 给用户使用的 EndPoint,若填 /fs/ 则表示由服务器转发
  • file.endPointForJudge: 给 judge 使用的 EndPoint,若填 /fs/ 则表示由服务器转发

保存后重启,已有文件请自行复制。

阿里云OSS

// TODO & PRs Welcome

+ + + diff --git a/docs/install/smtp.html b/docs/install/smtp.html new file mode 100644 index 00000000..f7459882 --- /dev/null +++ b/docs/install/smtp.html @@ -0,0 +1,40 @@ + + + + + + + + SMTP | Hydro + + + + + + +

SMTP


SMTP

以 QQ 邮箱为例。

  • SMTP_USER: 12345678@qq.com
  • SMTP_PASS: 提供的 SMTP 密码
  • SMTP_HOST: smtp.qq.com
  • SMTP_PORT: 465/587 (请参照邮件服务商说明)
  • SMTP_SECURE: 是否使用加密 TLS 连接(请参照邮件服务商说明,使用 STARTTLS 的服务商无需勾选)
  • SMTP_FROM: 发送签名(提示:若不清楚请填写邮件地址,填错会导致邮件无法发送)

已知能够完整兼容的服务商有:

  • QQ 邮箱
  • 腾讯企业邮
  • 网易 163 邮箱
  • 飞书域名邮箱
  • Zeptomail
  • Zoho Mail
  • Outlook
  • Gmail

如果使用其他服务商且没有发现问题,欢迎向此列表 Pull Request。

+ + + diff --git a/docs/system/FAQ.html b/docs/system/FAQ.html new file mode 100644 index 00000000..fc2b48a2 --- /dev/null +++ b/docs/system/FAQ.html @@ -0,0 +1,40 @@ + + + + + + + + 常见问题 | Hydro + + + + + + + + + + diff --git a/docs/system/cdn.html b/docs/system/cdn.html new file mode 100644 index 00000000..fbf32b41 --- /dev/null +++ b/docs/system/cdn.html @@ -0,0 +1,40 @@ + + + + + + + + 使用内容分发网络 | Hydro + + + + + + +

使用内容分发网络


使用内容分发网络

如您希望改善 Hydro 的访问质量,在您的服务器带宽较小的情况下,您可以考虑使用内容分发网络,即 CDN ,通常情况下您仅需设置资源 CDN 即可大幅度改善访问质量,关于如何使用内容分发网络和使用中的任何问题请联系各大云厂商。

资源 CDN

创建并配置好资源 CDN ,在控制面板中将 server.cdn 设置项修改为 CDN 域名。(如 https://cdn.hydro.ac/,以 / 结尾)。

全站 CDN

如果您预算充足,可以使用全站 CDN。

Note

全站 CDN 配置较为繁琐,如您没有相关使用经验请仅建立并配置资源 CDN ,配置资源 CDN 在大部分情况下即可大幅度改善访问质量。 因各服务商全站 CDN 配置方法不同,配置过程不同,需要配置的内容较多,以下仅为参考配置且配置补全,如果有任何问题建议先查阅云服务商文档及咨询云服务商工程师。

缓存设置可以参考以下设置:

类型内容缓存行为
全部文件全部文件遵循源站
文件后缀jpg,js,png,css,gif缓存一天

同时设置添加回源HTTP请求头

头部参数头部取值
X-Forward-For参考所使用服务商CDN文档来设置用户来源IP

且您应当修改系统设置中的 server.xff 值为 X-Forwarded-For,该设置是为了能够让系统正确获取到用户的IP地址。

+ + + diff --git a/docs/system/cli.html b/docs/system/cli.html new file mode 100644 index 00000000..15cd7f57 --- /dev/null +++ b/docs/system/cli.html @@ -0,0 +1,71 @@ + + + + + + + + Hydro Cli | Hydro + + + + + + +

Hydro Cli


Hydro Cli

Tips

在使用 cli 之前,请完成数据库配置。
指令中使用 <> 括起来的参数必须给出,用 [] 括起来的参数可以给出,若不给出则按照默认设置。
用户请根据自己的情况替换掉用 <> 或是 [] 包括起来的部分(括号也应替换)

cli 可以帮助用户在控制台下快捷地进行一些操作。
这些命令需要以在终端以 root 用户执行(安装时执行命令的位置)。
下面给出了一些常用的例子。

创建用户

Tips

很少使用。建议通过 控制面板>导入用户 功能代替

hydrooj cli user create <mail> <username> <password> <uid>
+# 该用户的邮箱、用户名和密码
+
+# 如创建邮箱为 hydro@hydro.local,用户名为 Hydro,密码为 hydrohydro ,UID 为 2 的用户:
+# 请确保 UID 为不小于 2 的正整数且未被占用,邮箱和用户名均不重复。
+hydrooj cli user create hydro@hydro.local Hydro hydrohydro 2
+

若一切正常,运行该指令后您会从命令行窗口中看到该用户 uid。

设置全站管理员

hydrooj cli user setSuperAdmin <uid>
+
+# 如设置 uid 为 2 的用户为管理员:
+hydrooj cli user setSuperAdmin 2
+

设置用户权限

hydrooj cli user setPriv <uid> <priv>
+

关于参数 [priv] ,可阅读 此处

更改用户密码

hydrooj cli user setPassword <uid> <password>
+
+# 如将 uid 为 1 的用户的密码改为 hydrohydro:
+hydrooj cli user setPassword 1 hydrohydro
+

创建评测账号

创建一个账号

您需要留意运行此指令返回的数字,表示该用户的 uid,需要填入下面的指令中,然后给予该账号评测权限。

hydrooj cli user setJudge <uid>
+

完成后将配置的用户名及密码写入评测机配置文件,评测机即可连接到网页端。

黑名单相关

用户封禁:

hydrooj cli user setPriv <uid> 0
+

IP/邮箱域名封禁:

# key 格式为 ip::xxx.xxx.xxx.xxx (封禁 IP 访问) 或是 mail::xxx.com (禁止 xxx.com 的邮箱注册)
+hydrooj cli blacklist add <key> [duration] # 将 <key> 拉入黑名单,时长为 [duration] (以月为单位的整数,默认为 12,若 duration=0 则永久封禁)
+hydrooj cli blacklist get <key> # 获取黑名单中有关 <key> 的信息
+hydrooj cli blacklist del <key> # 将 <key> 移出黑名单
+

命令列表

所有于 此文件夹open in new window 下的函数均可用 cli 调用。

这里并没有列出所有可以运行的指令,因为其中很多功能我们更推荐通过 Web 访问。

hydrooj cli user create <mail> <uname> <password> [uid] [regip] [priv]
+# 创建邮箱为 <mail>,用户名为 <uname>,密码为 <password>,ID 为 [uid],注册 ip 为 [regip],权限为 [priv] 的用户
+hydrooj cli user setUname <uid> <unmae> # 将 ID 为 <uid> 的用户的用户名设置为 <uname>
+hydrooj cli user setPriv <uid> <priv> # 将 ID 为 <uid> 的用户的权限设为 <priv>
+hydrooj cli user setPassword <uid> <password> # 将 ID 为 <uid> 的用户的密码设置为 <password>
+hydrooj cli user setEmail <uid> <mail> # 将 ID 为 <uid> 的用户的邮箱设置为 <mail>
+hydrooj cli user setSuperAdmin <uid> # 将 ID 为 <uid> 的用户设为全站管理员
+hydrooj cli problem import <domainId> <file/path> # 将 <file/path> 的Hydro格式题目包导入至 <domainId> 域中
+hydrooj cli problem export <domainId> # 将 <domainId> 域中的所有题目包导出
+hydrooj cli system set <key> <value> # 修改系统设置 <key> 值为 <value>
+
+ + + diff --git a/docs/system/database.html b/docs/system/database.html new file mode 100644 index 00000000..853944a7 --- /dev/null +++ b/docs/system/database.html @@ -0,0 +1,40 @@ + + + + + + + + 数据库备份和恢复 | Hydro + + + + + + +

数据库备份和恢复


数据库备份和恢复

进入数据库

请参考 FAQS 内的数据库连接教程。

快速备份与恢复

为了保证数据安全,请定期备份。

若您使用自动脚本安装,可使用 hydrooj backup 快捷备份数据,备份完成后会在当前目录生成备份压缩包文件,您可使用 hydrooj restore <备份文件路径> 恢复之前备份的数据。

手动备份

可使用 MongoDB 自带的 mongodumpopen in new window 进行数据库备份。并将 /data/file 文件夹备份即可。

对于数据库,请请不要在数据库运行时直接拷贝数据库文件夹。请每次备份后检查生成的备份文件的大小和内容,确保备份成功。
请不要把备份数据和 Hydro 系统放在同一台机器上,这样数据丢失的风险仍然较高。

手动恢复备份

使用 MongoDB 自带的 mongorestoreopen in new window 导入备份的数据库文件,并还原 /data/file 目录文件。
如果只是想不同机器之间迁移部署,只需要在停止 Hydro 和 MongoDB 服务后将相关文件夹(通常为 /data/db/data/file/root/.hydro/config.json )复制即可。

+ + + diff --git a/docs/system/frontend-modify.html b/docs/system/frontend-modify.html new file mode 100644 index 00000000..c7eab056 --- /dev/null +++ b/docs/system/frontend-modify.html @@ -0,0 +1,40 @@ + + + + + + + + 前端修改 | Hydro + + + + + + +

前端修改


前端修改

此指南将教您修改前端文件。

如果您正在使用开发者模式,请直接修改 packages/ui-default/templates 下的文件。

如果您使用安装脚本部署:

请先使用 hydrooj addon create 创建一个本地插件(如果之前没有做过的话)。

修改页面翻译或是添加新语言:

  • 修改翻译:在 zh.yamlopen in new window 内搜索您需要修改的翻译内容,并将 其所在行而非整个文件 修改后添加至 ~/addon/locales/zh.yaml
  • 添加语言:可参照 zh.yamlopen in new window 格式创建一个新文件。欢迎社区参与多国化翻译工作。

修改页面模板:

通常的,在您访问的 url 前加上 view-source:(如 view-source:https://hydro.ac 即可查看页面源代码,在第二行的 <html data-page="xxx">data-page 值即为页面名(首页例外,为 main.html)。 在 默认 templatesopen in new window 中找到对应文件,将文件的全部内容 复制到 ~/addon/templates/ 文件夹下后进行修改即可。

特别的,创建题目时的默认模板位于 partials/problem_default.md,创建训练计划时的默认模板位于 partials/training_default.json,修改方式同上。

以上所有更改均会在重启 Hydro 后生效。

+ + + diff --git a/docs/system/import-user.html b/docs/system/import-user.html new file mode 100644 index 00000000..7d2d9fae --- /dev/null +++ b/docs/system/import-user.html @@ -0,0 +1,43 @@ + + + + + + + + 导入用户 | Hydro + + + + + + +

导入用户


导入用户

目前支持 csv 格式(用 , 分隔)或 Excel 格式(用 TAB 分隔) 导入用户数据, 数据既可以用文本编辑器创建,也可以用 Excel 等软件来辅助创建。

每行最少三列,最多五列,分别为: 邮箱,用户名,密码,显示名,用户信息。(显示名和用户信息为可选)
请使用 UTF-8 编码,否则中文可能会乱码。
如果使用 CSV 格式(逗号分隔),则用户信息列不可用。

foo@undefined.moe	user1	password1
+bar@undefined.moe	user2	password2	temp
+test@undefined.moe	user3	password3	test	{"group":"class1","studentId":"123","school":"Hydro School"}
+

可以在粘贴后点击预览验证复制入的数据的有效性

这将创建三个用户:

  • user1 密码为 password1 , 邮箱 foo@undefined.moe
  • user2 密码为 password2 ,邮箱 bar@undefined.moe,显示名为 temp
  • user3 密码为 password3,邮箱 test@undefined.moe,显示名为 test,学校为 Hydro School,学号为 123,该用户将会被分配至当前域的 class1 小组内;

Note

用户创建后无法删除,请谨慎操作

+ + + diff --git a/docs/system/index.html b/docs/system/index.html new file mode 100644 index 00000000..9582a71e --- /dev/null +++ b/docs/system/index.html @@ -0,0 +1,40 @@ + + + + + + + + System | Hydro + + + + + + + + + + diff --git a/docs/system/maintain.html b/docs/system/maintain.html new file mode 100644 index 00000000..47362cfa --- /dev/null +++ b/docs/system/maintain.html @@ -0,0 +1,54 @@ + + + + + + + + 维护 | Hydro + + + + + + +

维护


维护

PM2

使用一键安装脚本安装的 Hydro 使用 PM2 对进程进行管理。

进程名称

可以通过下面的指令查看当前 PM2 正在管理的所有进程。

pm2 ls
+

一键安装脚本默认会创建下面几个进程:

  • hydrooj: Hydro 主进程
  • hydro-sandbox: Hydro 评测沙箱
  • mongodb: MongoDB 数据库
  • caddy: 反向代理

后文的指令中将用 <name> 替代此处的进程名称,用 <id> 替代进程 ID(进程 ID 可通过 pm2 ls 查看)。(尖括号同样需要替换)

PM2 基本指令

pm2 ls # 查看进程列表
+pm2 start <id> # 启动进程
+pm2 stop <id> # 关闭进程
+pm2 restart <id> # 重启进程
+pm2 del <id> # 删除进程
+pm2 log <id/name> --lines=100 # 查看该进程的后 100 行日志
+pm2 attach <id> # 与进程交互
+pm2 save # 保存对 PM2 进行的修改(在添加、修改、删除进程后需要执行该指令)
+

在部分环境(常见于 lxc 容器或是精简版系统)下,服务器重启后 Hydro 可能不能正常自启动,这时请使用 pm2 resurrect 手动载入进程列表。

如果手动修改进程列表且已经覆盖掉保存的原列表,请使用 pm2 stop all && pm2 del all 清空所有进程之后重新运行安装脚本。原有数据不会丢失。

Hydro 主进程同样支持多进程启动,但在中低端服务器(不超过4核)中没有必要使用多进程启动 Hydro,会降低性能且成倍提高内存占用。

pm2 start hydrooj -i <n> # 以 n 进程启动 Hydro 主进程
+

更新

Hydro 系统会不定期发布更新,可以使用下面的命令获取更新。

无特殊情况请 不要更新PM2 !此操作可能导致进程列表丢失!

yarn global upgrade-interactive --latest # 在交互式界面中选择想要更新的组件
+pm2 restart hydrooj # 更新完后需重启 hydrooj
+

查看已安装版本

cd `yarn global dir` && yarn list --pattern hydrooj
+

清除缓存

yarn cache clean && nix-collect-garbage
+
+ + + diff --git a/docs/user/copy-problem.html b/docs/user/copy-problem.html new file mode 100644 index 00000000..219a0bf2 --- /dev/null +++ b/docs/user/copy-problem.html @@ -0,0 +1,40 @@ + + + + + + + + 复制题目 | Hydro + + + + + + +

复制题目


复制题目

复制题目可以帮助用户将任何有权提交的题目复制到有权创建题目的域中以在比赛/作业/训练计划中使用这些题目。

操作流程

  1. 进入需要复制的题目页面或是题目列表页面。
  2. 点击右侧栏底部的“复制”按钮或是多选题目后点击右侧复制题目按钮。
  3. 在弹出的窗口中输入需要复制到的域的 ID。
  4. 点击“确定”后将自动跳转到复制后的题目连接。

限制

  • 不允许查看/修改复制后的题目的测试数据。
  • 不能复制一个复制来的题目。
  • 部分题目可能不允许复制。这遵循 域设置>编辑域资料 中的管理员设定。
+ + + diff --git a/docs/user/domain.html b/docs/user/domain.html new file mode 100644 index 00000000..55894e4c --- /dev/null +++ b/docs/user/domain.html @@ -0,0 +1,66 @@ + + + + + + + + 域 | Hydro + + + + + + +


简介

域功能类似团队,允许在一套系统中创建多个环境(如不同班级,或是不同功能,等等)
用户可以创建多个域。(需要用户有 PRIV_CREATE_DOMAIN 权限,默认仅开放给管理员账户)。 域间数据完全独立,仅用户信息相通(注册账户后,在该实例的所有域中均有效)。

创建域

登录账号后,在“我的”选项卡中找到“我的域”,并点击“创建域”,填入以下信息:

  • ID: 每个域有一个唯一的 ID,将会在域 URL 中体现。创建后无法修改。
  • 名称: 域的名字,创建后可以更改。
  • 公告: 域主页上显示的公告,创建后可以更改。
  • avatar: 域头像,与用户头像同理,可以使用 gravatar:emailqq:idgithub:nameurl:link 的格式添加。将会在“我的域”界面内显示。

创建域后,您将在此域中拥有管理员权限,可以在域内进行添加题目/创建比赛等操作。

初始化讨论节点

您可以在“管理域”选项卡中点击“初始化讨论节点”按钮初始化讨论节点。

访问控制

未登录用户将默认使用 guest 权限,登录用户将默认使用 default 权限。(所以将登陆用户设为 default 权限后并不会显示在“管理用户”页内,这也表示所有用户默认不会出现在管理列表中)
所以将一个用户的权限设为 default 和将用户移出该域是等价的。

对于不在列表中的用户,点击右上角“添加用户”,在左侧选中用户,右侧选择权限组,再点击“确定”即可。

创建比赛/作业

若您想要创建比赛/作业,您可以在“比赛”或“作业”选项卡中,在页面右侧找到“创建”按钮, 题目一栏支持根据题目ID或是题目名自动筛选。设置完后可点击“创建”按钮创建比赛(描述这类的框不知道写啥就随便填,不能留空)。

Tips

若因为删除作业/比赛内题目导致无法打开,可以通过 /contest/<id>/edit/homework/<id>/edit(即在无法打开的页面页面后加上 /edit)直接访问编辑页并修正。

创建训练

若您想要创建训练,您可以在“训练” 项卡中点击“新建训练计划”,填写以下信息:

  • 标题:该训练的标题;
  • 简介:该训练的简介,会与标题同时显示在列表页面中;
  • 说明:该训练的详细信息;
  • 计划:该训练的具体题目及计划信息,其格式如下:
[
+  {章节详细信息},
+  {章节详细信息},
+  ...
+  {章节详细信息}
+]
+

其中,“章节详细信息”的包含以下部分:

  • _id:章节数字编号;
  • title:章节标题;
  • requireNids:训练此章节之前需要完成的章节数字编号,若无要求则留空,若有多个则使用逗号分隔;
  • pids:此章节中包含的题目的 ID,若有多个则使用逗号分隔。

举例:若要在训练中创建三个章节,章节中分别有 ID 为 1,2,3 的题目。其中章节一、二无前置条件,章节三需要同时完成章节一、二后才能进行,则格式如下:

[
+  {
+    "_id": 1,
+    "title": "入门",
+    "requireNids": [],
+    "pids": [1]
+  },
+  {
+    "_id": 2,
+    "title": "精通",
+    "requireNids": [],
+    "pids": [2]
+  },
+  {
+    "_id": 3,
+    "title": "大师",
+    "requireNids": [1,2],
+    "pids": [3]
+  }
+]
+

Tips

若因为删除训练计划内题目导致训练计划无法打开,可以通过 /training/<id>/edit(即训练计划页面后加上 /edit)直接访问训练计划编辑页并修正配置文件。

+ + + diff --git a/docs/user/index.html b/docs/user/index.html new file mode 100644 index 00000000..2d7f030b --- /dev/null +++ b/docs/user/index.html @@ -0,0 +1,40 @@ + + + + + + + + 用户文档 | Hydro + + + + + + +

用户文档


用户文档

题目难度

Hydro 中题目的难度,根据递交数、通过率以及每个递交的递交时间和评测结果,通过算法计算得出。

  1. 一般地,难度的数值越大,该题目越难。
  2. 新题目的难度可能不准确;在题目获得大量递交之后,难度才会变得较为准确。
  3. 越早递交评测的用户代码的评测结果对题目难度影响越大。
  4. 题目的难度由算法计算得出,有可能出现不准确的结果。

参与比赛

您可以在比赛的详细界面内点击“参与比赛”按钮进行参与。 比赛过程中“成绩表”会根据比赛规则显示排名。 在比赛截止之后,您仍然可以订正其中的题目,但“成绩表”将停止更新。

发布讨论

若您想发布一个讨论,请先进入一个讨论节点,之后点击“创建一个讨论”按钮并填写:

  • 标题;
  • 内容;
  • 是否高亮:若选择后,该贴的左边将有醒目的红色线条(需要“高亮讨论”权限);
  • Pin:该讨论是否置顶(需要“置顶讨论”权限)。

之后点击“创建”按钮进行发布。

认领作业

您可以在作业的详情页面中,点击“认领作业”。
在作业开始之前,您无法查看作业中的题目。
在作业持续时间内,您与他人的做题情况会被实时统计在“成绩表”内。
在作业进入延期阶段后,您仍然可以提交题目,但成绩表内的分数将根据延期扣分规则按百分比折算。
在作业截止之后,您仍然可以订正其中的题目,但“成绩表”将停止更新。

+ + + diff --git a/docs/user/problem-create.html b/docs/user/problem-create.html new file mode 100644 index 00000000..d2721ffa --- /dev/null +++ b/docs/user/problem-create.html @@ -0,0 +1,240 @@ + + + + + + + + Hydro常见题型的制做心得 | Hydro + + + + + + +

Hydro常见题型的制做心得


Hydro常见题型的制做心得

作者: laomai
qq: 29985091
网址: http://82.157.98.222:8888/
日期: 2022/03/16

本文为作者使用hydro时的实验记录,希望对大家有帮助.包括如下内容

零. hydro题目存储格式
一. 制做最简单的oj题
二. 含有自定义头文件的oj题,即函数交互式的题目
三. 半自动对拍的oj题,即不需要录入预期输出的题
四. 完全对拍题,即不需要录入输入数据和输出数据的题
五. 指定输入文件和输出文件
六. 多个子任务
七. 客观题,即制做有标准答案的填空和选择题.

零. hydro题目存储格式

如果想在本地建立好题目,然后批量上传的话. 下面的格式应该对你有帮助
每个题目应自占一个目录,目录名为题目编号比如1 ,2,3,4等等.
每个题目目录下一般有下面的元素:
problem_zh.md 这个文件是就是题目的内容,即题目的描述,是一个markdown格式的文档.
probelm.yaml 文件.这个是题目的配置信息. 比如标题和标签等。
testdata 子目录,对应网站里的测试数据部分里的文件,
里面至少有一个config.yaml文件 用来说明测试的类型.具体内容见后面的例子
如果题目有测试用例,则每个用例至少要提供一个in文件和一个输出文件(但有些测试类型不用,详情见后)
additional_file子目录用来存放给做题者用的额外文件,比如头文件,图片,pdf文档等,在题目的 markdown 文档中可以用下面的格式为这些文件提供下载链接:[提示文字](file://xxx.txt)

下面为手工录入各种题型的步骤,即在网站登录后点创建题目之后的操作.如下图所示 pic1

我们假定题目内容均为下面的markdown文档

# 要求
+
+输入两个整数,输出他们的和
+
+# 样例
+
+```input1
+123 500
+```
+
+```output1
+623
+```
+

一 制做最简单的OJ题目

题目网址: http://82.157.98.222:8888/p/P10000

  1. 新建题目之后编辑题目内容,输入题号和标题,然后点创建按钮。如下图所示.
  2. 此时出现下面的图,点创建文件,文件名为 1.in, 表示用例 1 的输入
  3. 编辑 1.in 的内容为两个整数比如 2 和 3 ,空格分开,如下图所示,然后点确定
  4. 类似办法创建一个 1.out 文件,内容为 5 ,注意数字编号必须和 in 文件一致,创建之后的文件列表和下面类似.

pic11

  1. 这样第一个用例的输入和预期输出就录入完毕,现在可以做本题了
  2. 本题的 AC 代码为:
#include <iostream>
+using namespace std;
+int main(int argc,char* argv[]){
+    int a,b;
+    cin>>a>>b;
+    cout <<(a+b);
+    return 0;
+}
+

二、函数交互型题目

题目网址: http://82.157.98.222:8888/p/P10001
本类型和类型一的区别在于出题者要向做题者提供一个额外的头文件,做题者的主函数里可以包含这个头文件以调用出题者提供的某些函数,或者实现头文件里指定的函数.

  1. 题目内容的录入以及测试数据的录入和类型一样
  2. 本题要额外上传两个文件.分别为 tools.hconfig.yaml ,如下图所示

pic10

tools.h 的内容为

#include<iostream>
+using namespace std;
+
+int add(int x,int y);  //留待做题者实现
+
+int main(int argc,char* argv[]){
+    int a,b;
+    cin>>a>>b;
+    cout << add(a,b);
+    return 0;
+}
+

这个头文件里实现了一个主函数,并且声明了需要做题者实现的函数add,当然,出题者应该在题目要求里写明这个函数的原型以及把tools.h文件上传到附加文件列表中,以方便做题者.
题面里可以用如下格式为用户提供下载链接,中括号内的内容可以自己写,[tools.h](file://tools.h) 如下面所示

pic8

pic9

config.yaml文件的内容为

type: default
+filename: null
+user_extra_files:
+  - tools.h
+

本题的ac代码为

#include "tools.h"
+int add(int x,int y){
+    return x+y;
+}
+

可见本类型的题目,做题者包含给定的头文件后,可以不需要自己实现主函数,只需要专心实现给定的函数即可.

三,半对拍-自己指定评测程序并修改测试输出格式

例题网址:http://82.157.98.222:8888/p/P10002
本题型的特点是不需要手工给出每个用例的预期输出,但是要自己编写一个样本程序,测试时会把用户的输出和样本程序的输出进行对比。

仍以两数求和为例

  1. 题目内容和类型一类似
  2. 测试数据部分只需要提供1.in
  3. 编写一个样本程序 checker.cc,内容如下:
#include "testlib.h"
+int main(int argc, char * argv[]) {
+    registerTestlibCmd(argc, argv);
+    int a = inf.readInt();   // 读取输入流的第一个整数
+    int b = inf.readInt();   // 读取输入流的下一个整数
+    int d = a+b;
+    int c = ouf.readInt();   // 读取输出流的下一个整数
+    if (a+b != c)
+        quitf(_wa, "%d + %d expected %d, found %d", a, b,d,c);   //输出错误的具体信息,便于做题者调试
+    else
+        quitf(_ok, "answer of %d +  %d is %d",a,b,c);
+}
+
  1. config.yaml文件的内容如下:
checker_type: testlib
+checker: checker.cc
+cases:
+  - input: 1.in
+    output: /dev/null # 无输出
+

最终的测试文件列表如下所示:

pic7

当程序有错误时,输出的效果如下

可见这里输出了错误细节,便于做题者调试

本题的ac代码和类型一的一样,内容为

#include <iostream>
+using namespace std;
+int main(int argc,char* argv[]){
+    int a,b;
+    cin>>a>>b;
+    cout <<(a+b);
+    return 0;
+}
+

四. 全自动对拍题

如果不希望自己录入输入数据,而是在每次测试时自动动态生成的话,可以将题目类型设为interactive,并提供一个对拍程序.仍以求和为例
例题网址: http://82.157.98.222:8888/p/P10005

最后测试数据部分的文件列表如下图所示

pic6

  1. checker.cc,内容为:
#include "testlib.h"
+#include <iostream>
+using namespace std;
+
+int main(int argc, char* argv[]) {
+    setName("Interactor A+B");
+    registerInteraction(argc, argv);
+    //自动生成两个随机整数
+    rnd.setSeed(time(NULL));
+    int a = rnd.next(1000);
+    int b = rnd.next(1000);
+    int d = a+b;
+    // 本程序的输出将作为用户程序的输入
+    cout << a << " " << b << endl;
+    int c;
+    // 用户程序的最后输出将作为本程序的输入
+    cin >> c;
+    //对比用户结果和预期结果
+    if (a+b != ans)
+        quitf(_wa, "%d + %d expected %d, found %d", a, b,d,c);   //输出错误的具体信息,便于做题者调试
+    else
+        quitf(_ok, "answer of %d +  %d is %d",a,b,c);
+}
+
  1. config.yaml 文件的内容为:
type: interactive
+interactor: checker.cc
+cases:
+- input: /dev/null # no input and no output, dynamic generated
+  output: /dev/null
+- input: /dev/null # no input and no output, dynamic generated
+  output: /dev/null
+

pic

AC 代码和类型一中的相同

五.文件读写测试

例题网址:http://82.157.98.222:8888/p/P10003
有时希望指定输入和输出文件,此时测试文件 1.in1.out 和类型一类似, 但是要提供config.yaml文件,内容类似于下

file: test
+

则运行时测试环境会自动把每个输入文件复制到test.in中,输出内容和test.out的内容进行对比. ac的代码如下:

#include <fstream>
+using namespace std;
+int main(int argc,char* argv[]){
+    int a,b;
+    ifstream ifs("test.in");
+    ifs>>a>>b;
+    ofstream ofs("test.out");
+    ofs <<(a+b);
+    return 0;
+}
+

六,子任务测试.

例题网址: https://hydro.ac/d/system_test/p/7

  1. 提供好题目和各个子任务的输入、输出文件 建议文件名格式为 data<id>-<数字> id为子任务编号
  2. config.yaml文件的内容参考如下
time: 100ms
+memory: 8m
+subtasks:
+  - score: 20
+    id: 0
+    cases:
+      - input: data1-1.in
+        output: data1-1.ans
+      - input: data1-2.in
+        output: data1-2.ans
+      - input: data1-3.in
+        output: data1-3.ans
+      - input: data1-4.in
+        output: data1-4.ans
+      - input: data1-5.in
+        output: data1-5.ans
+  - score: 20
+    id: 1
+    cases:
+      - input: data2-1.in
+        output: data2-1.ans
+      - input: data2-2.in
+        output: data2-2.ans
+      - input: data2-3.in
+        output: data2-3.ans
+      - input: data2-4.in
+        output: data2-4.ans
+      - input: data2-5.in
+        output: data2-5.ans
+  - score: 20
+    id: 2
+    cases:
+      - input: data3-1.in
+        output: data3-1.ans
+      - input: data3-2.in
+        output: data3-2.ans
+      - input: data3-3.in
+        output: data3-3.ans
+      - input: data3-4.in
+        output: data3-4.ans
+      - input: data3-5.in
+        output: data3-5.ans
+  - score: 20
+    id: 3
+    if: [2]
+    cases:
+      - input: data4-1.in
+        output: data4-1.ans
+      - input: data4-2.in
+        output: data4-2.ans
+      - input: data4-3.in
+        output: data4-3.ans
+      - input: data4-4.in
+        output: data4-4.ans
+      - input: data4-5.in
+        output: data4-5.ans
+  - score: 20
+    id: 4
+    if: [1, 3]
+    cases:
+      - input: data5-1.in
+        output: data5-1.ans
+      - input: data5-2.in
+        output: data5-2.ans
+      - input: data5-3.in
+        output: data5-3.ans
+      - input: data5-4.in
+        output: data5-4.ans
+      - input: data5-5.in
+        output: data5-5.ans
+

可以看出if 用来指定前置子任务.
此外,如果某个子任务没有提供cases部分时,测试时会自动寻找类似于 data<id>-x.indata<id>-x.out 的文件,id为子任务编号
上面的例子故意设计为子任务编号和用例文件中的编号不同,所有每个子任务都需要手工指定对应的cases.

七,客观题制做

注意新版的客观题,格式已经更新。

例题网址:http://82.157.98.222:8888/p/P10004
客观题只需要题面和config.yaml文件. 例子如下:

1. 填空题
+
+1+1 = {{ input(1) }}
+
+2. 选择题
+
+{{ select(2) }}
+- 1+1=2
+- 1+1=3
+- 1+1=4
+
+3. 多选题
+
+{{ multiselect(3) }}
+- A
+- B
+- C
+
+

pic4

上传的 config.yaml 内容为

type: objective # 表明该题为客观题
+answers: # 列举出每一题的正确选项与对应的得分
+  '1': ['2', 50]
+  '2': [['A', 'B'], 30] # 填空题支持多答案,满足其一得分
+  '3': [['A', 'B'], 20] # 多选题答案为数组,有部分分
+
+

题目运行效果如下:

pic3

做完之后点提交,效果如下

pic2

可见评分结果正确.

八.小结

对所有编程题目,题面是必须录入的,如果指定了测试程序时,可以不需要录入输出数据.
如果设置测试方式为interactive,输入数据也不需要手工录入.
想指特殊的测试方式时,一般需要上传一个config.yaml文件,并设置对应字段的值.
对编程题,本文档中用到的字段有

type字段一般为default, 对全自动对拍题,设为interactive

checker_type: testlib checker: checker.cc 用来指定自定义的测试程序,即对拍程序

filename: test用来指定对test.in文件和test.out文件进行读写.

cases:

  • input: 1.in

用来指定测试用例.

更详细的介绍见 https://hydro.js.org/docs/user/testdata/

+ + + diff --git a/docs/user/problem-format.html b/docs/user/problem-format.html new file mode 100644 index 00000000..7c627201 --- /dev/null +++ b/docs/user/problem-format.html @@ -0,0 +1,62 @@ + + + + + + + + Hydro Problem Format | Hydro + + + + + + +

Hydro Problem Format


Hydro Problem Format

为了便于系统间进行数据交换,Hydro 定义了一种基于 zip 的标准格式用于题目传输。压缩包内文件结构如下:

喵? tree
+.
+├── 任意文件名的文件夹
+│   ├── problem.yaml
+│   ├── problem_zh.md
+│   ├── testdata
+│   │   ├── config.yaml
+│   │   ├── a1.in
+│   │   ├── a1.out
+│   │   ├── a2.in
+│   │   ├── a2.out
+│   │   ├── a3.in
+│   │   └── a3.out
+│   └── additional_file
+│       ├── a.png
+│       └── b.pdf
+└── ...
+

其中 problem.yaml 内容如下:

title: 题目名
+tag:
+- 标签1
+- 标签2
+pid: 题号(字母+数字)
+

problem_*.md 中为 markdown 格式的题面,语言代号支持完整形式(如 zh_CN),也支持短形式(如 zh)。若同时存在多个语言的题面,Hydro 将会自动识别并提供切换功能。

testdata 文件夹中存放所有测试数据文件,命名规则和配置文件格式请参照【测试数据格式】章节。

additional_file 中存储附加文件,通常用于存放图片,PDF 等文件。这些文件可以在题面中使用 file://文件名 的路径访问。

+ + + diff --git a/docs/user/problem.html b/docs/user/problem.html new file mode 100644 index 00000000..35490964 --- /dev/null +++ b/docs/user/problem.html @@ -0,0 +1,77 @@ + + + + + + + + 题目 | Hydro + + + + + + +

题目


题目

创建题目

拥有 PERM_CREATE_PROBLEM 的用户均可以新建题目。
请点击题库页面右下角的 创建题目 按钮。

Tips

题目 ID 不能全为数字。若留空则使用自动分配的数字题号。

详见下方题面编辑部分,以及 laomai 编写的说明

导入题目

从 Hydro 导入

上传 Hydro 导出的题目压缩包即可。

如果您的压缩包较大无法上传我们也提供cli导入方法:

hydrooj cli problem import <domainId> <file/path> # 将 <file(压缩文件)/path(解压后的文件夹)> 的Hydro格式题目包导入至 <domainId> 域中。
+

从 SYZOJ 导入

Hydro 提供了一个小工具 loj-downloadopen in new window,可从基于原版 SYZOJ/SYZOJ-NG 搭建的源站下载到符合Hydro格式的题目压缩包。
工具使用方法请前往使用教程查看,自行摸索并确保在网络通畅的环境下使用。

从 FPS 文件导入

见插件 fps-importer

从 QDUOJ 导入

见插件 import-qduoj。

编辑

题面

题面使用 Markdown 语法,并进行了部分扩展。

支持对样例数据分组显示:

```input1
+1 2
+```
+
+```output1
+3
+```

后接的数字为测试点编号,将自动合并,并左右分栏显示。

支持从附加文件引用资源。(您可以先创建题目,上传相关文件后再编辑该题目)

  • 附加文件下载链接: [file](file://input.in)
  • 从附加文件引用一张图片: ![img](file://foo.jpg)
  • 从附加文件引用 pdf 作为题面:@[pdf](file://foo.pdf) (部分情况下若无法使用,请尝试 @[pdf](file://foo.pdf?noDisposition=1)
  • 从附加文件引用 word 文档作为题面: @[doc](file://foo.docx) (依赖 onlyoffice 插件)

题面支持合并表格:

| 1   | 1   | 3   | 4   | 5   |
+| --- | --- | --- | --- | --- |
+| 1   | 1   | 2   | 2   | 6   |
+| 1   | 1   | 2   | 2   | 7   |
+| 1   | 4   | 3   | 5   | 5   |
+

将被渲染为:

img

支持内嵌 HTML:(用来对付部分 Markdown 搞不定的东西)

<span bgcolor="red">foo</span>
+

标签

可点击右侧分类面板快速添加标签,也可以用英文半角逗号分隔多个标签。

文件

您可以在题目右侧“文件”面板上传测试数据和附加文件。(支持拖拽文件至相应位置进行上传)
测试数据格式

客观题

题面

1. 填空题
+
+1+1 = {{ input(1) }}
+
+2. 选择题
+
+{{ select(2) }}
+- 1+1=2
+- 1+1=3
+- 1+1=4
+
+3. 多选题
+
+{{ multiselect(3) }}
+- A
+- B
+- C
+

测试数据

仅需要配置 config.yaml 即可,不需要上传其他文件。

type: objective # 表明该题为客观题
+answers: # 列举出每一题的正确选项与对应的得分
+  '1': ['2', 50] # 填空题/选择题,单答案
+  '2': # 填空题/选择题,多答案,不同答案对应不同分数,注意空格缩进
+    'A': 30 # 也可以使用相同分数,即同时存在多个正确答案
+    'B': 10
+  '3': [['A', 'B'], 20] # 多选题答案为数组,有部分分
+
+ + + diff --git a/docs/user/testdata.html b/docs/user/testdata.html new file mode 100644 index 00000000..7652e70e --- /dev/null +++ b/docs/user/testdata.html @@ -0,0 +1,143 @@ + + + + + + + + 测试数据格式 | Hydro + + + + + + +

测试数据格式


测试数据格式

自动模式

Tips

您可以直接选择文件(支持多选)上传或将文件拖拽至相应位置上传。
若上传文件为 zip 格式,将会自动进行解压操作。

对于一般的题目,您只需提供 .in.out/.ans 文件,以下是一个例子。
请务必确保文件名中含有数字。形如 sample.in 的文件是不会被自动识别的。

喵? tree
+.
+├── a1.in
+├── a1.out
+├── a2.in
+├── a2.out
+├── a3.in
+└── a3.out
+

测试数据将被自动识别,并使用 1S 256MB 的限制。

使用配置文件

Tips

推荐您通过 评测设置 在线编辑题目配置,可以拥有更好的编辑体验。

上传 config.yaml 文件即可,文件格式如下(下方所有样例均为可选项,若无说明则预填写的内容即为默认值):

# 题目类型,可以为 default(比对输出,可以含spj), objective(客观题), interactive(交互题)
+type: default
+
+# 全局时空限制(此处的限制优先级低于测试点的限制)
+time: 1s
+memory: 128m
+
+# 输入输出文件名(例:使用 foo.in 和 foo.out),若使用标准 IO 删除此配置项即可
+filename: foo
+
+# 此部分设置当题目类型为 default 时生效
+# 比较器类型,支持的值有 default(直接比对,忽略行末空格和文件末换行), ccr, cena, hustoj, lemon, qduoj, syzoj, testlib(比较常用)
+checker_type: default
+# 比较器文件(当比较器类型不为 default 时填写)
+# 文件路径(位于压缩包中的路径)
+# 将通过扩展名识别语言,与编译命令处一致。在默认配置下,C++ 扩展名应为 .cc 而非 .cpp
+checker: chk.cc
+
+# 此部分设置当题目类型为interactive时生效
+# 交互器路径(位于压缩包中的路径)
+interactor: interactor.cc
+
+# Extra files 额外文件
+# These files will be copied to the working directory 这些文件将被复制到工作目录。
+# 提示:您无需手动上传 testlib.h。
+user_extra_files:
+  - extra_input.txt
+judge_extra_files:
+  - extra_file.txt
+
+# Test Cases 测试数据列表
+# If neither CASES or SUBTASKS are set(or config.yaml doesn't exist), judge will try to locate them automaticly.
+# 如果 CASES 和 SUBTASKS 都没有设置或 config.yaml 不存在, 系统会自动尝试识别数据点。
+# We support these names for auto mode: 自动识别支持以下命名方式:
+# 1. [name(optional)][number].(in/out/ans)         RegExp: /^([a-zA-Z]*)([0-9]+).in$/
+#   examples: 
+#     - c1.in / c1.out
+#     - 1.in / 1.out
+#     - c1.in / c1.ans
+# 2. input[number].txt / output[number].txt        RegExp: /^(input)([0-9]+).txt$/
+#   - example: input1.txt / input2.txt
+#
+# The CASES option has higher priority than the SUBTASKS option!
+# 在有 CASES 设置项时,不会读取 SUBTASKS 设置项!
+#
+# The CASES option has been deprecated in the new version, please use the more personalized SUBTASKS!
+# CASES 已于新版本中被废弃,请使用个性化程度更高的SUBTASKS!
+# score: 50     # 单个测试点分数
+# time: 1s      # 时间限制
+# memory: 256m  # 内存限制
+# cases:
+#   - input: abc.in
+#     output: def.out
+#   - input: ghi.in
+#     output: jkl.out
+# 或使用Subtask项:
+subtasks:
+  - score: 30
+    type: min # 可选 min/max/sum,分别表示取所有测试点最小值、所有测试点最大值、所有测试点之和
+    time: 1s
+    memory: 64m
+    cases:
+      - time: 0.5s
+        memory: 32m # 可对单个测试点单独设置时间限制和内存限制
+        input: a.in
+        output: a.out
+      - input: b.in
+        output: b.out
+  - score: 70
+    time: 0.5s
+    memory: 32m
+    if: [0] # 可选,传入数组,表示仅在subtask0通过时此subtask才计分
+    cases:
+      - input: c.in
+        output: c.out
+      - input: d.in
+        output: d.out
+
+# 提交语言限制
+# 列举出所有本题允许使用的语言对应的代码(需要和评测机 lang.yaml 内的语言代码相同)
+# 使用语言ID而非名称!对于有子类的选项,请详细至子分类!
+langs:
+  - c
+  - cc
+  - cc.cc11o2
+  - pas
+
+# 时间内存倍率
+# 对某语言设置时间或内存倍率(需要和评测机 lang.yaml 内的语言代码相同)
+# 部分语言默认已存在倍率,请前往控制面板中查看!
+# 使用语言ID而非名称!对于有子类的选项,请详细至子分类!
+time_limit_rate:
+  py.py3: 2
+memory_limit_rate:
+  java: 1.5
+

可以在 此题库open in new window 中找到各种类型题目的配置示例。

+ + + diff --git a/favicon.ico b/favicon.ico new file mode 100644 index 00000000..98d24cb7 Binary files /dev/null and b/favicon.ico differ diff --git a/favicon.png b/favicon.png new file mode 100644 index 00000000..fc4452e8 Binary files /dev/null and b/favicon.png differ diff --git a/index.html b/index.html new file mode 100644 index 00000000..1a7e65dc --- /dev/null +++ b/index.html @@ -0,0 +1,40 @@ + + + + + + + + Hydro + + + + + + +
Hydro

Hydro

高性能在线测评系统

介绍 💡部署指南

安全

使用 cgroup 隔离用户程序

便捷

支持使用脚本一键搭建

强大

提供了比赛 训练 讨论 题解 作业等功能,并可通过安装附加组件进行扩展

快速

沙箱复用,延迟计算,提高运行效率

LICENSEGitHub Workflow Statushydroojnpmnode-currentGitHub contributorsGitHub commit activity

Hydro 是一个高效的信息学在线测评系统。特点:易于部署(且提供安装脚本),轻量,功能强大且易于扩展。

Github 仓库open in new window

欢迎 star 本项目,这是对开发者的鼓励。
项目的开发与维护需要资金,欢迎进行捐助。
Hydro 提供收费的功能定制服务,如您需要可与我们联系。
相关文档若说明的不够详细,请提交 Pull Request 或联系开发组说明。
Bug 和功能建议请在 Issuesopen in new window 提出。

在 Gitpod 打开已配置完成的测试环境open in new window

Hydro Online Judgeopen in new window

联系我们

Email i@undefined.moe
Hydro 用户群:1085853538
Telegram @webpack_exports_undefinedopen in new window

注:Hydro 为开源框架,任何人均能够在遵守协议的情况下使用这套框架。
版权申诉相关问题请联系对应网站管理者,(通常为其 UID=2 的用户),与开发者无关。

开源许可

本项目基于 AGPL v3 开源。
在您部署 Hydro 时,需要保留底部的 Powered by Hydro 字样,其中的 Hydro 字样需指向 hydro.js.org/本仓库/fork 之一的链接。
若您对源码做出修改,同样需要以 AGPL v3 开源,您可以以 Powered by Hydro, Modified by xxx 格式在页脚注明。
此限制对以下模块仍然有效:

  • Hydro 插件;
  • 包括但不限于使用 http 协议与 Hydro 进行交互的组件;

若您需要对这些模块闭源处理,请考虑联系我们以购买许可。
鉴于 Mirai 处的 不和谐事件open in new window 对此项目做如下声明:

  • 项目开源不代表开发者有义务为您提供服务。
  • 在提问前请先阅读《提问的智慧》。
  • 若有必要,开发者有权对您停止任何技术支持。
  • 开发组会 尽可能 保证用户可以进行平滑升级,但无法保证不在新版本引入影响使用的漏洞,且内部实现可能会在不发布任何通知的情况下进行重命名/修改/删除。

如果您对以上条目感到不适,建议您停止使用本项目。

鸣谢

排名不分先后,按照链接字典序。

+ + + diff --git a/plugins/elastic.html b/plugins/elastic.html new file mode 100644 index 00000000..bf535da0 --- /dev/null +++ b/plugins/elastic.html @@ -0,0 +1,40 @@ + + + + + + + + Elastic search | Hydro + + + + + + +

Elastic search


Elastic search

安装 Elasticsearch 后安装 @hydrooj/elastic-search 插件。

进入 HydroOJ 控制面板,在系统设置内正确填写endpoint。

然后在脚本管理中找到重建题目索引,点击运行,参数留空即可。

至此,搜索功能应当可以正常使用。

+ + + diff --git a/plugins/fps-importer.html b/plugins/fps-importer.html new file mode 100644 index 00000000..7816bac0 --- /dev/null +++ b/plugins/fps-importer.html @@ -0,0 +1,40 @@ + + + + + + + + fps-importer | Hydro + + + + + + +

fps-importer


fps-importer

从 fps 文件导入题目

在题库右侧“创建题目”一栏中选择“从 FPS 文件导入”。
在打开的窗口中,您可以上传:

  • fps 格式的 xml 文件
  • zip 文件,其中包含了一个或多个 fps 格式的 xml 文件

由于防止解析 fps 文件消耗大量内存,将拒绝导入超过 64MiB 的文件。
xml 文件需要为 UTF8 编码,否则可能出现中文题面乱码;
若您的文件超过大小限制,可考虑先在本地使用 Easy-Fps-Viewer 等工具进行拆分。

+ + + diff --git a/plugins/geoip.html b/plugins/geoip.html new file mode 100644 index 00000000..f10abaf9 --- /dev/null +++ b/plugins/geoip.html @@ -0,0 +1,40 @@ + + + + + + + + GeoIP | Hydro + + + + + + +

GeoIP


GeoIP

插件需要 MaxMind 的 Geolite2-City.mmdb 支持,在安装插件后需要将mmdb拷贝至插件同一目录下方可启用,如果你不知道这是什么,请勿安装。

+ + + diff --git a/plugins/hydrojudge.html b/plugins/hydrojudge.html new file mode 100644 index 00000000..a18f3b96 --- /dev/null +++ b/plugins/hydrojudge.html @@ -0,0 +1,66 @@ + + + + + + + + hydrojudge | Hydro + + + + + + +

hydrojudge


hydrojudge

Tips

您可以通过一键安装脚本快速安装独立评测机,详情请前往 部署Hydro 查看。

准备

在配置评测机之前,请确认您的站点已经可以访问并正常登录/注册。

您应该预先下载您所要支持的语言的编译器,若您在配置完评测机后 升级/重新安装 了编译器,您需要重新启动沙箱。
关于编译器说明,请参照 编译器 章节。

如果不使用自动脚本,您需要按照如下方式手动安装沙箱服务:
前往 criyle/go-judgeopen in new window 下载 executorserver。 Executorserver 需要在后台以 root 权限运行并监听 127.0.0.1:5050 。 可使用 pm2 进行管理。

安装

作为附加组件

Tips

由于用附加组件安装的评测机与 Hydro 必须在同一台服务器上,每一个 Hydro 实例最多只能有一台评测机由附加组件安装。

在安装 Hydro 的机器上运行下面的指令安装 @hydrooj/hydrojudge

yarn global add @hydrooj/hydrojudge
+hydrooj addon add @hydrooj/hydrojudge
+

重启 Hydro 后 hydrojudge 即可正常运行。

作为独立进程

Tips

该方法可以帮助您在任意服务器上部署评测机。

首先需要创建一个有 PRIV_JUDGE 权限的账户,具体方法参照 此处。(在部署 Hydro 的服务器上运行)

然后在运行评测机的服务器上安装 HydroJudge :

. <(curl https://hydro.ac/setup.sh) --judge
+

创建目录 ~/.config/hydro,在该目录下创建文件 judge.yaml,配置文件格式如下:

hosts:
+  localhost:
+    type: hydro # vj4 用户请在此处填写 vj4
+    server_url: http://localhost/ # Hydro 运行的网址
+    uname: judge # 评测账号用户名
+    password: abc123 # 评测账号密码
+    detail: true # 默认为 true
+

设置完之后,使用下面的指令即可开始运行(可以使用 pm2 管理):

hydrojudge
+

更新

HydroJudge 会发布不定期更新。您可以使用 yarn global upgrade-interactive --latest 来检测并进行更新。

关闭

作为附加组件

在 系统设置>hydrojudge 中有一栏 Disable builtin judge,将它勾上,然后重启 Hydro 即可。

作为独立进程

根据开启的方法关闭即可。

卸载

关闭后运行下面指令即可。

yarn global remove @hydrooj/hydrojudge
+hydrooj addon remove @hydrooj/hydrojudge
+

评测设置

作为附加组件

在 系统设置>hydrojudge 修改对应的参数,然后重启 Hydro 和 hydrojudge 即可。

作为独立进程

如果有需要修改单题测试点数量上限等设置,可以在 ~/.config/hydro/judge.yaml 的末尾添加下列内容:

testcases_max: 100 # 单题最多测试点数量
+total_time_limit: 120 # 单题最大总测试时长
+parallelism: 2 # 单评测机评测进程数量
+# 更多可选配置均可添加在此处,格式与前面的三排类似
+

此处open in new window 的设置均可添加到此处。

修改编译选项/添加新语言支持

对于已安装内置评测机的用户(无论内置评测机是否启动),在 控制面板>系统设置 中修改 judge.langs 配置项即可;对于没有安装内置评测机的用户,需要在 ~/.config/hydro/langs.yaml 中配置。

文件格式参照 此处open in new window

如果您添加了新的语言,您还需要前往 控制面板>系统设置 中修改 Language Highlight ID 与 Monaco language modes。
分别表示选择对应的语言后的高亮设置(基于 PrismJS)和 Monaco 编辑器语法规则设置。

修改完后请重启 Hydro 和 hydrojudge 。

测试数据格式

参照 测试数据格式 配置。

调整沙箱空间大小

Note

如果不调整沙箱的空间大小,当您的评测使用文件 IO 且输入输出文件较大时可能会引发错误。

对于 2022/8/12 前安装的用户:

在服务器上运行下面的代码找到 hydro-sandbox 的运行目录:

pm2 info hydro-sandbox | grep "exec cwd"
+

mount.yamlopen in new window 下载并放置在 sandbox 的运行目录下。然后修改第 64 行和第 68 行的 sizenr_inodes 的大小至您想要的大小,保存后重启 sandbox 即可完成更改。

对于 2022/8/12 后安装的用户:

编辑 /root/.hydro/mount.yaml,修改 size 即可。

C/C++ 彩色编译错误信息

  1. 确认您安装了支持彩色输出的编译器;
  2. 在系统设置中,将 C/C++ 编译命令后加上 -fdiagnostics-color=always

例:

c:
+  compile: /usr/bin/gcc -O2 -Wall -std=c99 -o ${name} foo.c -lm -fdiagnostics-color=always
+

开大程序运行栈空间

2022/8/12 后安装的实例默认已开启无限栈空间,无需手动操作

在很多时候系统默认为程序提供的栈空间并不能满足我们的需求,此时我们需要手动为用户程序提供更大的栈空间。

修改 pm2 中 hydro-sandbox 的启动参数为 ulimit -s unlimited && /usr/bin/hydro-sandbox

pm2 del hydro-sandbox
+pm2 start bash --name hydro-sandbox -- -c "ulimit -s unlimited && hydro-sandbox" 
+

提高测评精度

禁用 CPU 频率缩放与 Intel 睿频加速技术,防止 CPU 频率波动。

禁用内存地址空间随机化,以使得存在内存寻址错误的代码能够得到更多可重复的结果,可以通过在 /etc/sysctl.conf 中添加下面这行并运行 sudo sysctl -p 应用:

kernel.randomize_va_space = 0
+

内存计量不准确

部分 Linux 设备默认使用 cgroup2,而 cgroup2 中移除了精确计量内存消耗的接口。 若要获得更精确的内存计量,推荐启用 cgroup v1 (您可以通过检查 /sys/fs/cgroup/memory/memory.memsw.usage_in_bytes 是否存在来验证是否当前系统是否启用了 cgroup v1 ):

以 Ubuntu 的默认引导器 GRUB 2 为例,编辑 /etc/default/grub: 在其中

GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"
+

后,加入 cgroup_enable=memory swapaccount=1 systemd.unified_cgroup_hierarchy=0 syscall.x32=y,变为:

GRUB_CMDLINE_LINUX_DEFAULT="quiet splash cgroup_enable=memory swapaccount=1 systemd.unified_cgroup_hierarchy=0 syscall.x32=y"
+

运行以下命令更新 GRUB 2 的配置,然后重新启动。

update-grub && reboot
+
+ + + diff --git a/plugins/index.html b/plugins/index.html new file mode 100644 index 00000000..78d1a388 --- /dev/null +++ b/plugins/index.html @@ -0,0 +1,53 @@ + + + + + + + + 插件 | Hydro + + + + + + +

插件


插件

Hydro 支持使用插件扩展自身所支持的功能。

Note

插件对站点的所有内容具有完全的访问权限,请不要启用来历不明的插件。

附加组件列表

Tips

部分斜体字插件需配合额外支持软件,如您只安装插件是无法使用的,详情请前往左侧插件详情查看。

如您为旧版本升级失去博客功能,请直接安装 @hydrooj/blog ,原数据不会丢失。

Hydro 官方目前提供了以下附加组件:

ID描述
@hydrooj/blog博客功能
@hydrooj/fps-importer导入 fps 格式的题目
@hydrooj/geoip显示用户登录地(需要IP库支持)
@hydrooj/hydrojudge评测组件
@hydrooj/import-qduoj导入 QDUOJ 导出的题库
@hydrooj/login-with-github允许用户使用 GitHub 登录
@hydrooj/login-with-google允许用户使用 Google 登录
@hydrooj/migrate从 vijos4/HustOJ/SYZOJ/UniversalOJ 升级
@hydrooj/recaptcha注册时启用 reCAPTCHA 验证码
@hydrooj/ui-defaultHydro 的默认用户界面
@hydrooj/onlyoffice显示 doc/docx 格式题目
@hydrooj/sonic基于 sonic 的题目搜索增强
@hydrooj/elastic-search基于 Elastic 的题目搜索增强
@hydrooj/vjudgeCodeforces/SPOJ/UOJ/POJ/Luogu
@hydrooj/prom-client导出系统状态至 Prometheus

大部分插件的配置均可在安装后于 控制面板>系统设置 中找到。

部分插件若安装后没有正确配置可能会影响系统正常使用!

安装

先全局安装所需模块,再向 hydrooj 注册即可。例:安装 @hydrooj/geoip

yarn global add @hydrooj/geoip
+hydrooj addon add @hydrooj/geoip
+

或者,如果你正在安装一个其他途径获取的插件(自行创建等),请直接使用文件夹 绝对路径: (文件夹路径即为 包含 package.json 的文件夹)

hydrooj addon add /root/xxx
+

请不要将插件与插件嵌套摆放,否则可能会导致一些不可预知的问题。

安装完插件后需要重启 hydrooj 以使插件生效。

查看已注册的插件列表

hydrooj addon list
+

更新

yarn global upgrade-interactive --latest
+

卸载

yarn global remove @hydrooj/geoip
+hydrooj addon remove @hydrooj/geoip
+
+ + + diff --git a/plugins/migrate.html b/plugins/migrate.html new file mode 100644 index 00000000..079e017c --- /dev/null +++ b/plugins/migrate.html @@ -0,0 +1,43 @@ + + + + + + + + migrate | Hydro + + + + + + +

migrate


migrate

从 HUSTOJ 升级

Note

迁移会删除当前 Hydro 的所有数据(含用户账户信息)并移入 HUSTOJ 的数据。
请注意备份相关文件。

请先完成 Hydro 的部署并完成对文件服务的配置(setting_file)。 在迁移数据之前,请先停止正在运行的 HUSTOJ 服务,仅保留其数据库开启。 请注意 Hydro 所在的数据库不应和源 HUSTOJ 数据库相同。

安装插件后,您应当能够在 控制面板>脚本管理 中找到名为 migrateHustoj 的脚本。 其参数格式如下:

{"host":"localhost","port":3306,"name":"jol","username":"","password":"","domainId":"system","contestType":"","dataDir":"","uploadDir":""}
+
  • host: 数据库地址
  • port: 数据库端口
  • name: 数据库名,一般为 jol
  • username&password: 账号密码,若无则填写空字符串
  • domainId: 迁入的域,默认为 system
  • contestType: oi 或者 acm,视情况而定
  • dataDir: HUSTOJ 中 data 文件夹的位置(这里存储着题目数据等关键信息,需要手动处理)
  • uploadDir: HUSTOJ 中 上传文件的位置(这里存储着上传的图片和文件等信息,默认已指定 /home/judge/src/web/upload/ ,如果此路径与您路径相同,请不要填写此项)

当脚本运行完成后,请重启 Hydro 实例,会自动完成之后的升级操作。 迁移后,请使用原 HUSTOJ 的管理员账号登录实例。

从 SYZOJ 升级

SYZOJ 与 HUSTOJ 迁移方法类似,迁移脚本应运行名为 migrateSyzoj 的脚本外,SYZOJ无需 contestType 参数。 其参数格式如下:

{"host":"localhost","port":3306,"name":"syzoj","username":"","password":"","domainId":"system","dataDir":""}
+
  • host: 数据库地址
  • port: 数据库端口
  • name: 数据库名,一般为 syzoj
  • username&password: 账号密码,若无则填写空字符串
  • domainId: 迁入的域,默认为 system
  • dataDir: SYZOJ 中 data 文件夹的位置(这里存储着题目数据等关键信息,需要手动处理)

由于SYZOJ脚本会将原站所有数据迁移,所以运行耗时较长。 当脚本运行完成后,请重启 Hydro 实例,会自动完成之后的升级操作。 迁移后,请使用原 SYZOJ 的管理员账号登录实例。

从 UniversalOJ 升级

UniversalOJ (常称作UOJ社区版)与前两者迁移方法类似,迁移脚本应运行名为 migrateUniversalOJ 的脚本。

由于其升级过程较为麻烦,安装脚本已提供自动升级服务,如您需要可运行安装脚本一键迁移,手动迁移请在开发群中提问。

由于UniversalOJ脚本会将原站所有数据迁移,所以运行耗时较长。 当脚本运行完成后,请重启 Hydro 实例,会自动完成之后的升级操作。 迁移后,请使用原 UniversalOJ 的管理员账号登录实例。

从 Vijos 升级

Note

迁移会删除当前 Hydro 的所有数据(含用户账户信息)并移入 vj4 的数据。
请注意备份相关文件。

请先完成 Hydro 的部署并完成对文件服务的配置(setting_file)。
在迁移数据之前,请先停止正在运行的 vj4 服务,仅保留其数据库开启。
请注意 Hydro 所在的数据库不应和源 vj4 数据库相同。
若您使用 vj4-docker ,可更改 docker-compose.yml 将数据库映射至其他本机端口。

安装插件后,您应当能够在 控制面板>脚本管理 中找到名为 migrateVijos 的脚本。
其参数格式如下:

{"host":"localhost","port":27017,"name":"vj4","username":"","password":""}
+
  • host: 数据库地址
  • port: 数据库端口
  • name: 数据库名
  • username&password: 账号密码,若无则填写空字符串

Tips

vj4-docker 中数据库名为 vj4,无账号密码。

当脚本运行完成后,请重启 Hydro 实例,会自动完成之后的升级操作。 迁移后,请使用原 vj4 的管理员账号登录实例。

Note

若您的 vj4 是由 vj2 或 tyvj 升级而来,在迁移完成后请不要卸载该插件,否则可能导致部分用户无法登录。

+ + + diff --git a/plugins/recaptcha.html b/plugins/recaptcha.html new file mode 100644 index 00000000..b42359a4 --- /dev/null +++ b/plugins/recaptcha.html @@ -0,0 +1,40 @@ + + + + + + + + recaptcha | Hydro + + + + + + +

recaptcha


recaptcha

Tips

我们采用 reCAPTCHA v3 来检验注册者是否是人类,在注册过程中没有看见传统验证码属正常现象。

前往 https://www.google.com/recaptcha/admin/createopen in new window 创建 reCAPTCHA 密钥。
reCAPTCHA 类型请选择“reCAPTCHA 第 3 版”。

创建成功后将客户端密钥和服务端密钥分别填入系统设置 recaptcha 栏下的 keysecret 中,重启 Hydro 后 reCAPTCHA 即可正常工作。

+ + + diff --git a/plugins/sonic.html b/plugins/sonic.html new file mode 100644 index 00000000..51a48c84 --- /dev/null +++ b/plugins/sonic.html @@ -0,0 +1,111 @@ + + + + + + + + Sonic | Hydro + + + + + + +

Sonic


Sonic

安装

安装 sonic-serveropen in new window

使用 root 用户执行如下命令:

nix-env -iA nixpkgs.sonic-server
+

安装 sonic 插件

使用 root 用户执行如下命令:

yarn global add @hydrooj/sonic
+hydrooj addon add @hydrooj/sonic
+

启动

/root/.sonic/config.cfg(没有的自行建立,也可以换成其他的你喜欢的路径)按照以下配置示例写入配置。

配置示例:

# Sonic
+# Fast, lightweight and schema-less search backend
+# Configuration file
+# Example: https://github.com/valeriansaliou/sonic/blob/master/config.cfg
+
+
+[server]
+
+log_level = "error"
+
+
+[channel]
+
+inet = "127.0.0.1:1491" # 默认监听本机
+tcp_timeout = 300
+
+auth_password = "SecretPassword"
+
+[channel.search]
+
+query_limit_default = 10
+query_limit_maximum = 100
+query_alternates_try = 4
+
+suggest_limit_default = 5
+suggest_limit_maximum = 20
+
+
+[store]
+
+[store.kv]
+
+path = "/data/sonic/store/kv/"
+
+retain_word_objects = 1000
+
+[store.kv.pool]
+
+inactive_after = 1800
+
+[store.kv.database]
+
+flush_after = 900
+
+compress = true
+parallelism = 2
+max_files = 100
+max_compactions = 1
+max_flushes = 1
+write_buffer = 16384
+write_ahead_log = true
+
+[store.fst]
+
+path = "/data/sonic/store/fst/"
+
+[store.fst.pool]
+
+inactive_after = 300
+
+[store.fst.graph]
+
+consolidate_after = 180
+
+max_size = 2048
+max_words = 250000
+

执行如下命令:

pm2 start sonic -- -c /root/.sonic/config.cfg
+pm2 save
+

配置

后端地址配置

进入 HydroOJ 控制面板,配置 sonic 后端地址。

如果您直接复制配置示例,那么按照以下内容配置:

  • host: 127.0.0.1
  • port: 1491
  • auth: SecretPassword

修改完成后,重启 HydroOJ。

重启 HydroOJ

执行命令 pm2 restart hydrooj

重建题目索引

进入 HydroOJ 控制面板,在脚本管理中找到重建题目索引,点击运行,参数留空即可。

至此,搜索功能应当可以正常使用。

FAQ

安装后题目搜索不正常

请更新到 HydroOJ 最新版本后,再运行重建题目索引。

+ + + diff --git a/plugins/vjudge.html b/plugins/vjudge.html new file mode 100644 index 00000000..055a0ae6 --- /dev/null +++ b/plugins/vjudge.html @@ -0,0 +1,175 @@ + + + + + + + + Vjudge | Hydro + + + + + + +

Vjudge


Vjudge

Note

此文档已过时,仅作留存使用,请前往 FAQS 查看使用指南。

Codeforces

由于 vjudge 更新了反爬虫机制,Codeforces RemoteJudge 需要一些特殊手段才能正常工作。
详情请 阅读源码open in new window

安装插件后创建名为 codeforces 的域,进入数据库 db.domain.updateOne({_id:'codeforces'},{$set:{mount:'codeforces'}});

在 codeforces 的域设置中,将 allowedLangs 如下配置(在新版即在允许提交的语言中选中所有 codeforces 开头的语言):

codeforces,codeforces.43,codeforces.52,codeforces.50,codeforces.54,codeforces.59,codeforces.61,codeforces.65,codeforces.9,codeforces.28,codeforces.32,codeforces.12,codeforces.60,codeforces.36,codeforces.48,codeforces.19,codeforces.3,codeforces.4,codeforces.51,codeforces.13,codeforces.6,codeforces.7,codeforces.31,codeforces.40,codeforces.41,codeforces.67,codeforces.49,codeforces.20,codeforces.34,codeforces.55
+

在 vjudge 表中插入如下条目:

{type:'codeforces', handle:'<codeforces login handle>', password:'<codeforces login password>'}
+

将如下配置添加至 langs 设置末尾:

codeforces:
+  execute: none
+  display: Codeforces
+  domain:
+  - codeforces # Allow domain 'codeforces' to use these languages
+codeforces.43:
+  highlight: cpp astyle-c
+  monaco: cpp
+  display: GNU GCC C11 5.1.0
+  comment: //
+codeforces.52:
+  highlight: cpp astyle-c
+  monaco: cpp
+  display: Clang++17 Diagnostics
+  comment: //
+codeforces.50:
+  highlight: cpp astyle-c
+  monaco: cpp
+  display: GNU G++14 6.4.0
+  comment: //
+codeforces.54:
+  highlight: cpp astyle-c
+  monaco: cpp
+  display: GNU G++17 7.3.0
+  comment: //
+codeforces.59:
+  highlight: cpp astyle-c
+  monaco: cpp
+  display: Microsoft Visual C++ 2017
+  comment: //
+codeforces.61:
+  highlight: cpp astyle-c
+  monaco: cpp
+  display: GNU G++17 9.2.0 (64 bit, msys 2)
+  comment: //
+codeforces.65:
+  highlight: cpp astyle-cs
+  monaco: csharp
+  display: C# 8, .NET Core 3.1
+  comment: //
+codeforces.9:
+  highlight: cpp astyle-cs
+  monaco: csharp
+  display: C# Mono 6.8
+  comment: //
+codeforces.28:
+  highlight: d
+  monaco: plain
+  display: D DMD32 v2.091.0
+  comment: //
+codeforces.32:
+  highlight: go
+  display: Go 1.15.6
+  comment: //
+codeforces.12:
+  highlight: haskell
+  display: Haskell GHC 8.10.1
+  comment: --
+codeforces.60:
+  highlight: java astyle-java
+  monaco: java
+  display: Java 11.0.6
+  comment: //
+codeforces.36:
+  highlight: java astyle-java
+  monaco: java
+  display: Java 1.8.0_241
+  comment: //
+codeforces.48:
+  highlight: kotlin
+  display: Kotlin 1.4.0
+  comment: //
+codeforces.19:
+  highlight: ocaml
+  monaco: plain
+  display: OCaml 4.02.1
+  comment: ['(*','*)']
+codeforces.3:
+  highlight: pascal
+  display: Delphi 7
+  comment: //
+codeforces.4:
+  highlight: pascal
+  display: Free Pascal 3.0.2
+  comment: //
+codeforces.51:
+  highlight: pascal
+  display: PascalABC.NET 3.4.2
+  comment: //
+codeforces.13:
+  highlight: perl
+  display: Perl 5.20.1
+  comment: '#'
+codeforces.6:
+  highlight: php
+  display: PHP 7.2.13
+  comment: //
+codeforces.7:
+  highlight: python
+  display: Python 2.7.18
+  comment: '#'
+codeforces.31:
+  highlight: python
+  display: Python 3.9.1
+  comment: '#'
+codeforces.40:
+  highlight: python
+  display: PyPy 2.7 (7.3.0)
+  comment: '#'
+codeforces.41:
+  highlight: python
+  display: PyPy 3.7 (7.3.0)
+  comment: '#'
+codeforces.67:
+  highlight: ruby
+  display: Ruby 3.0.0
+  comment: '#'
+codeforces.49:
+  highlight: rust
+  display: Rust 1.49.0
+  comment: //
+codeforces.20:
+  highlight: scala
+  display: Scala 2.12.8
+  comment: //
+codeforces.34:
+  highlight: javascript
+  display: JavaScript V8 4.8.0
+  comment: //
+codeforces.55:
+  highlight: javascript
+  display: Node.js 12.6.3
+  comment: //
+

之后再重启 Hydro 即可。

+ + + diff --git a/robots.txt b/robots.txt new file mode 100644 index 00000000..ab7930f8 --- /dev/null +++ b/robots.txt @@ -0,0 +1,5 @@ + +User-agent:* +Disallow: + +Sitemap: https://hydro.js.org/sitemap.xml diff --git a/search-pro.worker.js b/search-pro.worker.js new file mode 100644 index 00000000..53fa367d --- /dev/null +++ b/search-pro.worker.js @@ -0,0 +1,2 @@ +const g=(o,a)=>{const i=o.toLowerCase(),e=a.toLowerCase(),s=[];let n=0,l=0;const c=(t,p=!1)=>{let r="";l===0?r=t.length>20?`… ${t.slice(-20)}`:t:p?r=t.length+l>100?`${t.slice(0,100-l)}… `:t:r=t.length>20?`${t.slice(0,20)} … ${t.slice(-20)}`:t,r&&s.push(r),l+=r.length,p||(s.push(["strong",a]),l+=a.length,l>=100&&s.push(" …"))};let h=i.indexOf(e,n);if(h===-1)return null;for(;h>=0;){const t=h+e.length;if(c(o.slice(n,h)),n=t,l>100)break;h=i.indexOf(e,n)}return l<100&&c(o.slice(n),!0),s},d=Object.entries,y=Object.keys,f=o=>o.reduce((a,{type:i})=>a+(i==="title"?50:i==="heading"?20:i==="custom"?10:1),0),$=(o,a)=>{var i;const e={};for(const[s,n]of d(a)){const l=((i=a[s.replace(/\/[^\\]*$/,"")])==null?void 0:i.title)||"",c=`${l?`${l} > `:""}${n.title}`,h=g(n.title,o);h&&(e[c]=[...e[c]||[],{type:"title",path:s,display:h}]),n.customFields&&d(n.customFields).forEach(([t,p])=>{p.forEach(r=>{const u=g(r,o);u&&(e[c]=[...e[c]||[],{type:"custom",path:s,index:t,display:u}])})});for(const t of n.contents){const p=g(t.header,o);p&&(e[c]=[...e[c]||[],{type:"heading",path:s+(t.slug?`#${t.slug}`:""),display:p}]);for(const r of t.contents){const u=g(r,o);u&&(e[c]=[...e[c]||[],{type:"content",header:t.header,path:s+(t.slug?`#${t.slug}`:""),display:u}])}}}return y(e).sort((s,n)=>f(e[s])-f(e[n])).map(s=>({title:s,contents:e[s]}))},m=JSON.parse("{\"/\":{\"/\":{\"title\":\"\",\"contents\":[{\"header\":\"\",\"slug\":\"\",\"contents\":[\"Hydro 是一个高效的信息学在线测评系统。特点:易于部署(且提供安装脚本),轻量,功能强大且易于扩展。\",\"Github 仓库\",\"欢迎 star 本项目,这是对开发者的鼓励。 项目的开发与维护需要资金,欢迎进行捐助。 Hydro 提供收费的功能定制服务,如您需要可与我们联系。 相关文档若说明的不够详细,请提交 Pull Request 或联系开发组说明。 Bug 和功能建议请在 Issues 提出。\",\"在 Gitpod 打开已配置完成的测试环境\",\"Hydro Online Judge\"]},{\"header\":\"联系我们\",\"slug\":\"联系我们\",\"contents\":[\"Email i@undefined.moe Hydro 用户群:1085853538 Telegram @webpack_exports_undefined\",\"注:Hydro 为开源框架,任何人均能够在遵守协议的情况下使用这套框架。 版权申诉相关问题请联系对应网站管理者,(通常为其 UID=2 的用户),与开发者无关。\"]},{\"header\":\"开源许可\",\"slug\":\"开源许可\",\"contents\":[\"本项目基于 AGPL v3 开源。 在您部署 Hydro 时,需要保留底部的 Powered by Hydro 字样,其中的 Hydro 字样需指向 hydro.js.org/本仓库/fork 之一的链接。 若您对源码做出修改,同样需要以 AGPL v3 开源,您可以以 Powered by Hydro, Modified by xxx 格式在页脚注明。 此限制对以下模块仍然有效:\",\"Hydro 插件;\",\"包括但不限于使用 http 协议与 Hydro 进行交互的组件;\",\"若您需要对这些模块闭源处理,请考虑联系我们以购买许可。 鉴于 Mirai 处的 不和谐事件 对此项目做如下声明:\",\"项目开源不代表开发者有义务为您提供服务。\",\"在提问前请先阅读《提问的智慧》。\",\"若有必要,开发者有权对您停止任何技术支持。\",\"开发组会 尽可能 保证用户可以进行平滑升级,但无法保证不在新版本引入影响使用的漏洞,且内部实现可能会在不发布任何通知的情况下进行重命名/修改/删除。\",\"如果您对以上条目感到不适,建议您停止使用本项目。\"]},{\"header\":\"鸣谢\",\"slug\":\"鸣谢\",\"contents\":[\"排名不分先后,按照链接字典序。\",\"Github 为 Hydro 提供了代码托管与自动构建。\",\"criyle 提供评测沙箱实现。\",\"Vijos 为 Hydro 提供了UI框架。\"]}]},\"/FAQ/\":{\"title\":\"常见问题集合\",\"contents\":[{\"header\":\"好消息!本页和各大浏览器均达成了合作,使用 Ctrl-F 即可快速搜索关键词!\",\"slug\":\"好消息-本页和各大浏览器均达成了合作-使用-ctrl-f-即可快速搜索关键词\",\"contents\":[]},{\"header\":\"更多教程请点击右上角的常用教程查看。\",\"slug\":\"更多教程请点击右上角的常用教程查看。\",\"contents\":[]},{\"header\":\"用户QQ群 1085853538\",\"slug\":\"用户qq群-1085853538\",\"contents\":[]},{\"header\":\"如何快速上手了解系统功能?\",\"slug\":\"如何快速上手了解系统功能\",\"contents\":[\"参照本文 https://hydro.ac/discuss/6172ceeed850d38c79ae18f9 无服务器快速体验系统功能。 如果你没有二开很多功能的需求,推荐直接使用在线服务。超过两万题的题库可以直接复制使用,无需购置云服务器,无需手动维护,更省心。 如果你有需要绑定自己的域名或是改 Logo 等等自定义需求,也可在管理面板中开通高级功能自助操作。\",\"系统中的用户只有编辑、禁用功能,没有删除功能,这是为了从根源上防止出现“教学事故”,请不要要求增加相关功能,如果认为自己绝不会误操作,请自行开发相关功能。\"]},{\"header\":\"什么是 OJ?\",\"slug\":\"什么是-oj\",\"contents\":[\"现在你所使用的评测系统也仅仅是一个程序,并没有人工智能。因此很多地方需要你来迁就它,如果不这样做,你的答案即使本质上是正确的,由于形式的错误造成系统不能理解,也会导致错误。 系统运行过程如下:\",\"教师在系统中添加题目,并严格定义题目提供输入数据的格式和要求的输出数据格式。\",\"教师根据题目定义的格式向系统中添加若干组测试数据,每组数据都包含输入数据和对应的输出。\",\"学生阅读题目,并根据自己的理解提交程序。\",\"系统编译并运行学生的程序,再将老师事先提供的输入数据“喂”给学生的程序,看它会输出什么。\",\"如果学生程序的输出与老师之前提供的输出完全一致,一字不差,则认为学生的程序是正确的,否则则认为该程序错误。\",\"如果运行过程中出现内存、时间上超出题目限制的情况,则中断程序的运行,并认为答案不正确。\",\"在了解了上面的情况以后,同学们应该理解,如果题目没有要求程序输出“Please Input Two Number”之类的提示信息,那么自行输出这些文字将导致你的程序输出与老师事先告诉系统的输出不能做到“一字不差”,因而将导致系统报答案错误。 如果题目要求每两行输出之间要空一行,结果你没有空,会是格式错误,反之亦然。 也许你会觉得,哦,这系统太烂了,这点东西都不能自动识别;实际上正是这样才能有效训练大家编程的精确性、养成良好的代码习惯。很多程序高手都跟你一样,是从对这个系统吐槽开始学习如何认真仔细的、一丝不苟的进行编程的。 系统为了能用统一的方式运行所有同学的答案,不得不对所有人提交的答案的形式进行限定。 对于学习C、C++语言的同学来说,所有提交给系统的答案必须包含并且只有一个main函数,这个main函数必须返回int类型,并且最好返回0,因为操作系统对非零的返回值认为是运行出错。 编译错误发生时,点击“编译错误”的文字链接可以得到详细解释。\"]},{\"header\":\"Arch Linux 开发模式安装时出现 [ERR_STREAM_PREMATURE_CLOSE]: Premature close 错误\",\"slug\":\"arch-linux-开发模式安装时出现-err-stream-premature-close-premature-close-错误\",\"contents\":[\"删除 .yarnrc.yml 和 .yarn 后再试。\"]},{\"header\":\"为什么我安装完成之后仍然无法访问?\",\"slug\":\"为什么我安装完成之后仍然无法访问\",\"contents\":[\"如果您使用的是 阿里云/腾讯云 等服务商,请确保安全组放行了 80 和 443 端口。\"]},{\"header\":\"为什么我配置完反向代理(caddy/nginx)之后无法登录(出现CsrfTokenError)?\",\"slug\":\"为什么我配置完反向代理-caddy-nginx-之后无法登录-出现csrftokenerror\",\"contents\":[\"反向代理时请确保设置了正确的 Host Header。详细说明\"]},{\"header\":\"怎么备份/还原备份/迁移数据?\",\"slug\":\"怎么备份-还原备份-迁移数据\",\"contents\":[\"hydrooj backuphydrooj restore backup-xxx.zip\",\"百度学习 crontab 的用法后,可以使用 sudo crontab -e 定制自动备份计划。\"]},{\"header\":\"恢复备份时出现 '/data/file/hydro': Directory not empty\",\"slug\":\"恢复备份时出现-data-file-hydro-directory-not-empty\",\"contents\":[\"关闭 minio (pm2 stop minio) 后手动删除 /data/file/hydro 文件夹再重试。\"]},{\"header\":\"更新升级\",\"slug\":\"更新升级\",\"contents\":[\"yarn global upgrade-interactive --latest 然后按空格选中除 pm2 之外的所有包更新,回车确认。 然后 pm2 restart hydrooj 重启服务。 重启后 pm2 logs hydrooj --lines 100 没有看到报错并看到了 Server started 则一切正常。\",\"Hydro 的所有历史版本,都可以无损升级到最新版本。如果老系统更新有疑问,随时加官方群咨询群主。\"]},{\"header\":\"怎么导入题目/创建题目?\",\"slug\":\"怎么导入题目-创建题目\",\"contents\":[\"题目列表右侧有相应入口。\",\"切记:不要导入过多你暂时用不上的题目,正确的方式是每次训练、作业,导入所需的5-10个题目,比赛作业结束后让题目成为训练题库的一部分。这样能保证题库中题号靠前的题目难度依次上升,适合后来的同学自行训练。不要贪图题目数量而忽视其质量。自己看不懂解法的题目,少用、慎用。\"]},{\"header\":\"如何限制未登录用户访问?\",\"slug\":\"如何限制未登录用户访问\",\"contents\":[\"管理域 -> 管理权限 将 Guest 权限组的 查看此域 权限禁用。\"]},{\"header\":\"比赛作业里面的时间是什么含义,OI排名跟普通排名有何区别?\",\"slug\":\"比赛作业里面的时间是什么含义-oi排名跟普通排名有何区别\",\"contents\":[\"时间是指参与人员做出对应题目“花费”的时间: 即:做出题目的时刻 – 比赛开始的时刻 + 惩罚时间 惩罚时间 = 做对之前错误的提交数 * 20分钟。 普通排名按做对的题目数和“花费”的时间进行排名。 OI排名,按得分排名,题目可以按通过的比例进行记分,每题100分。如果希望数据的分值不平均分配,可以使用 config 配置。\"]},{\"header\":\"脚本把 OJ 装在哪里了?\",\"slug\":\"脚本把-oj-装在哪里了\",\"contents\":[\"Hydro 的默认位置可以运行 yarn global dir 得到。(不要直接改代码,更新会覆盖此处的所有修改,请使用插件API) 默认的数据库文件放置在 /data/db,但是不要直接复制文件,而是推荐用 hydrooj backup 进行备份。 测试数据等文件存储于 /data/file。 配置文件位于 /root/.config/hydro 和 /root/.hydro。 对于正在运行中的生产服务器,任何操作前请做好离线备份。 备份文件一定要解压查看内部是否包含全部数据,关注备份的大小(大系统备份应该有上百兆),有条件找虚拟机实测还原是否成功\"]},{\"header\":\"题目的限时和内存限制的精度是怎样的?\",\"slug\":\"题目的限时和内存限制的精度是怎样的\",\"contents\":[\"题目限时允许设定的字面精度是 1ms,但是由于操作系统内核参数的限定,实测的精度通常为4ms。 内存限制的精度是1MB,对于本地native的编译型语言c/c++/pascal/freebasic/clang等是考察程序本身的内存申请空间; 对于虚拟机和脚本语言,则包含了虚拟机本身或解释器本身的内存消耗。\"]},{\"header\":\"我想让 Python 支持 numpy 等等库,怎么办?\",\"slug\":\"我想让-python-支持-numpy-等等库-怎么办\",\"contents\":[\"如果你是 2022/8/12 日前安装,使用 pip3 install numpy 后 pm2 restart hydro-sandbox 否则参照请参照 编译器 章节。\"]},{\"header\":\"使用安装脚本后忘记 MongoDB 的账号密码怎么办?\",\"slug\":\"使用安装脚本后忘记-mongodb-的账号密码怎么办\",\"contents\":[\"看 /root/.hydro/config.json 。\"]},{\"header\":\"如何关闭、打开用户注册?\",\"slug\":\"如何关闭、打开用户注册\",\"contents\":[\"用户注册由 Guest 用户(uid 为 0)的 PRIV_REGISTER_USER 权限控制,默认允许注册。 使用 hydrooj cli user setPriv 0 0 即可关闭注册。 若要重新打开,可使用 hydrooj cli user setPriv 0 8。\",\"变更后,请重启 hydrooj 服务:pm2 restart hydrooj\"]},{\"header\":\"用户名为 Hydro 的用户是干什么的?密码是什么?可以登录么?\",\"slug\":\"用户名为-hydro-的用户是干什么的-密码是什么-可以登录么\",\"contents\":[\"用户名为 Hydro 的用户(uid 为 1)仅用于发送系统消息(与 QQ 中的 10000 类似),无法登录。\"]},{\"header\":\"如何修改网站图标?\",\"slug\":\"如何修改网站图标\",\"contents\":[\"使用 hydrooj addon create 创建一个插件,这会自动创建 /root/addon 目录。 进入 /root/addon/public 目录,将您的站点图标放置于该文件夹下。 您需要将以下文件放在该目录中(适配不同浏览器):\",\"favicon-16x16.png\",\"favicon-32x32.png\",\"favicon-96x96.png\",\"favicon.ico (32x32)\",\"android-chrome-192x192.png\",\"apple-touch-icon-180x180.png\",\"分辨率应尽可能对应,但不强制要求。以上图片将在浏览器标签页图片上显示。 您还需要将以下文件放在该目录:\",\"nav_logo_dark.png\",\"以上图片将在页面左上角 logo 显示。 之后前往系统设置,找到 nav_logo_dark 设置项,改为 /nav_logo_dark.png ,重启 Hydro 即可应用更改。\",\"记得清理浏览器缓存。\"]},{\"header\":\"如何重置数据?\",\"slug\":\"如何重置数据\",\"contents\":[\"Note\",\"此操作会删除所有用户/题目/比赛等数据。请谨慎操作!\",\"将 此脚本 下载到服务器运行。\",\"您可按需更改,显示顺序与配置中的排列顺序相同。\"]},{\"header\":\"评测显示“总时限超过 60s,评测取消”\",\"slug\":\"评测显示-总时限超过-60s-评测取消\",\"contents\":[\"在系统设置中修改 total_time_limit 为允许的单题最大评测时长即可。\"]},{\"header\":\"如何在背景中添加线条特效?\",\"slug\":\"如何在背景中添加线条特效\",\"contents\":[\"在系统设置中找到 footer_extra_html 项,加上如下内容:(写在一行内,不要多加换行)\",\"基于 https://github.com/hustcc/canvas-nest.js ,MIT\",\" \"]},{\"header\":\"使用 Hydro 要花多少钱?\",\"slug\":\"使用-hydro-要花多少钱\",\"contents\":[\"不要钱,我们是 AGPL 的。如果你钱多,可以 给我发个红包。\"]},{\"header\":\"execve: no such file or directory\",\"slug\":\"execve-no-such-file-or-directory\",\"contents\":[\"脚本安装默认只装了一小部分编译器。请参照 编译器 章节安装配置其他编译器。\"]},{\"header\":\"怎么自定义用户标签?\",\"slug\":\"怎么自定义用户标签\",\"contents\":[\"进入 MongoDB,执行下面的操作即可(根据具体情况替换尖括号中的部分):\",\"use hydro db.user.update({\\\"_id\\\": <用户 UID>}, {$set: {\\\"badge\\\": \\\"<标签内容>#<背景颜色(HEX)>#<文字颜色(HEX)>\\\"}}) \"]},{\"header\":\"为什么我无法批量下载多个文件?\",\"slug\":\"为什么我无法批量下载多个文件\",\"contents\":[\"请使用现代浏览器进行操作,并尝试给网站设置 https。 否则请选择逐个下载文件(Ctrl+点击文件名)。\"]},{\"header\":\"为什么我的提交页面没有语言可选?\",\"slug\":\"为什么我的提交页面没有语言可选\",\"contents\":[\"题目 -> 评测设置 -> 允许的语言 域设置 -> 编辑域资料 -> 允许的语言 这两个地方,应该填英文逗号分隔的语言ID,不会填请留空。\"]},{\"header\":\"The 'yarn global' commands have been remove in 2.x - consider using 'yarn dlx' or a third-party plugin instead\",\"slug\":\"the-yarn-global-commands-have-been-remove-in-2-x-consider-using-yarn-dlx-or-a-third-party-plugin-instead\",\"contents\":[\"如果你搞不明白这个问题,请老实用安装脚本,不要折腾开发模式。\"]},{\"header\":\"我是机房用户,大量用户同 IP 操作触发了频率限制,怎么解决?\",\"slug\":\"我是机房用户-大量用户同-ip-操作触发了频率限制-怎么解决\",\"contents\":[\"方案一: 通过在内网架设代理服务器,将内网 ip 发送至服务端。(推荐)\\n方案二: 使用形如 hydrooj cli system set limit.user_login 999 的命令设置新的频率限制(可在错误页面查看具体是触发了哪条限制)\\n方案三: 使用 pm2 start hydrooj -- --benchmark 启动,关闭所有频率限制(不推荐)\"]}]},\"/api/\":{\"title\":\"API\",\"contents\":[{\"header\":\"\",\"slug\":\"\",\"contents\":[\"此处列出部分系统通信协议。\"]}]},\"/api/judge.html\":{\"title\":\"评测端通信协议\",\"contents\":[{\"header\":\"\",\"slug\":\"\",\"contents\":[\"当前版本 v1 。\"]},{\"header\":\"评测端交互流程\",\"slug\":\"评测端交互流程\",\"contents\":[\"GET /judge/files (检查登陆状态是否有效,若无效则跳转登录逻辑,通常每六小时执行一次)\",\"WEBSOCKET /judge/conn (主交互通道)\",\"若登录失效,则进行登录操作。\",\"POST /login {\\\"uname\\\":\\\"USERNAME\\\",\\\"password\\\":\\\"PASSWORD\\\",\\\"rememberme\\\":true} \"]},{\"header\":\"WebSocket 连接建立流程\",\"slug\":\"websocket-连接建立流程\",\"contents\":[\"WEBSOCKET /judge/conn Authorization: Bearer COOKIE_SID \",\"连接建立后,评测端向 Web 汇报当前节点状态(可选) 注:下方信息仅作数据格式展示用,不保证真实有效。\",\"{ \\\"key\\\": \\\"status\\\", \\\"info\\\": { \\\"mid\\\": \\\"MACHINE_ID\\\", \\\"memory\\\": { \\\"total\\\": 25189552128, \\\"free\\\": 660258800, \\\"used\\\": 24529293328, \\\"active\\\": 1558973164, \\\"available\\\": 23636676608, \\\"buffers\\\": 3075653000, \\\"cached\\\": 1000000000, \\\"slab\\\": 1000000000, \\\"buffcache\\\": 1000000000, \\\"swaptotal\\\": 0, \\\"swapused\\\": 0, \\\"swapfree\\\": 0 }, \\\"cpu\\\": { \\\"manufacturer\\\": \\\"Intel\\\", \\\"brand\\\": \\\"Xeon® Platinum 8269CY\\\", \\\"vendor\\\": \\\"Intel\\\", \\\"family\\\": \\\"6\\\", \\\"model\\\": \\\"85\\\", \\\"stepping\\\": \\\"7\\\", \\\"speed\\\": 2.5, \\\"cores\\\": 32, \\\"physicalCores\\\": 32, \\\"processors\\\": 2, \\\"flags\\\": \\\"fpu vme de pse tsc ...\\\", \\\"cache\\\": { \\\"l1d\\\": 32768, \\\"l1i\\\": 32768, \\\"l2\\\": 262144, \\\"l3\\\": 6291456 } }, \\\"load\\\": { \\\"avgLoad\\\": 0.01, \\\"currentLoad\\\": 0.01, \\\"currentLoadUser\\\": 0.01, \\\"currentLoadSystem\\\": 0.01, \\\"currentLoadNice\\\": 0.01, \\\"currentLoadIdle\\\": 0.01, \\\"currentLoadIrq\\\": 0.01 }, \\\"osinfo\\\": { \\\"platform\\\": \\\"linux\\\", \\\"distro\\\": \\\"Ubuntu\\\", \\\"release\\\": \\\"22.04.2 LTS\\\", \\\"codename\\\": \\\"Jammy Jellyfish\\\", \\\"kernel\\\": \\\"5.15.0-84-generic\\\", \\\"arch\\\": \\\"x64\\\", \\\"hostname\\\": \\\"judge\\\", \\\"codepage\\\": \\\"UTF-8\\\", } } } \",\"建立连接后每隔 30s,评测端发送 {\\\"key\\\":\\\"ping\\\"}。\"]},{\"header\":\"语言配置下发\",\"slug\":\"语言配置下发\",\"contents\":[\"在连接建立后,Web 端会向 Judge 分发服务端的语言设置。如果客户端需要进行特殊设置,可忽略此条消息。\"]},{\"header\":\"评测任务推送\",\"slug\":\"评测任务推送\",\"contents\":[\"Web 端会通过 WebSocket 向评测端推送评测任务。\",\"{ \\\"task\\\": { \\\"type\\\": \\\"judge\\\", \\\"_id\\\": \\\"RECORD_ID\\\", \\\"lang\\\": \\\"cc.cc11\\\", \\\"uid\\\": SUBMITTER_UID, \\\"code\\\": \\\"USER_SUBMITTED_CODE\\\", \\\"domainId\\\": \\\"SUBMISSION_DOMAIN_ID\\\", \\\"pid\\\": PROBLEM_ID, \\\"contest\\\": \\\"CONTEST_ID (optional)\\\", \\\"input\\\": \\\"INPUT\\\", \\\"source\\\": \\\"SOURCE_ID\\\", \\\"meta\\\": { \\\"rejudge\\\": false, \\\"problemOwner\\\": OWNER_UID }, \\\"data\\\": [ { \\\"name\\\": \\\"FILE_NAME\\\", \\\"size\\\": SIZE_IN_BYTES, \\\"lastModified\\\": \\\"2023-11-15T08:14:57.535Z\\\", \\\"etag\\\": \\\"ETAG\\\" } ] } } \",\"注1:如果比赛 ID 为 000000000000000000000000 则表示此提交为自测提交,自测提交使用 input 字段值作为程序输入。 注2:source 字段为缓存 ID,同 source 字段的提交使用相同的缓存目录。 注3:source 字段包含且仅包含一个字符 /,建议使用 domainId/pid。 注4:测试数据的 etag 用来识别本地缓存的文件是否与云端一致,可使用 hash 或是修改时间的时间戳。\"]},{\"header\":\"测试数据下载\",\"slug\":\"测试数据下载\",\"contents\":[\"若推送的评测任务中使用了的测试数据缺失,Judge 端会向 Web 请求缺失或是修改的文件。\",\"POST /d/:domainId/judge/files Cookie: sid=COOKIE_SID {\\\"pid\\\":PROBLEM_ID,\\\"files\\\":[\\\"a.in\\\",\\\"a.out\\\"]} \",\"服务端返回如下:\",\"{ \\\"links\\\": { \\\"a.in\\\": \\\"https://cdn.hydro.ac/d/DOMAIN_ID/pid/1/a.in\\\", \\\"a.out\\\": \\\"https://cdn.hydro.ac/d/DOMAIN_ID/pid/1/a.out\\\" } } \"]},{\"header\":\"评测结果上报\",\"slug\":\"评测结果上报\",\"contents\":[\"{ \\\"key\\\": \\\"next/end\\\", \\\"domainId\\\": \\\"DOMAIN_ID\\\", \\\"rid\\\": \\\"RECORD_ID\\\", \\\"message\\\": \\\"JUDGE_MESSAGE\\\", \\\"compilerText\\\": \\\"COMPILER_OUTPUT\\\", \\\"status\\\": STATUS_CODE, \\\"score\\\": SCORE, \\\"time\\\": TIME_IN_MS, \\\"memory\\\": MEMORY_IN_KB, \\\"progress\\\": PROGRESS_PERCENTAGE, \\\"addProgress\\\": PROGRESS_PERCENTAGE, \\\"case\\\": { \\\"id\\\": ID, \\\"subtaskId\\\": SUBTASK_ID, \\\"score\\\": SCORE, \\\"status\\\": STATUS_CODE, \\\"message\\\": \\\"CHECKER_MESSAGE\\\" } } \",\"除 key, domainId, rid 三个字段外,其他字段均为可选。关于 STATUS_CODE 含义请查看 hydro-dev/Hydro/packages/utils/lib/status 。\\n当 key 为 end 时表示评测任务已经完成,结果确定,Web 端可进行 AC 数计量,登记成绩表等操作。\"]}]},\"/dev/PERM_PRIV.html\":{\"title\":\"权限节点\",\"contents\":[{\"header\":\"\",\"slug\":\"\",\"contents\":[\"Hydro 的权限使用位运算处理。 例:若某用户具有 PRIV_EDIT_SYSTEM 与 PRIV_SET_PERM 权限,应设置为 (1<<0)|(1<<1) (即 3)\",\"可以看 代码 中关于此部分的内容。\"]}]},\"/dev/\":{\"title\":\"开发环境部署\",\"contents\":[{\"header\":\"\",\"slug\":\"\",\"contents\":[\"如果您没有过 TypeScript 项目的开发经验,非常不建议自建开发环境。 使用自动脚本安装也可以基于插件系统完成大部分的定制需求(参照左侧【使用 TypeScript 编写插件】章节)。\",\"您可以使用 Gitpod 快速打开配置完成的开发环境或是按照下方说明进行手动配置。(由于 Gitpod 的限制,hydrojudge 模块无法正常运行,若需要开发 hydrojudge 相关内容请自行部署)\"]},{\"header\":\"安装依赖\",\"slug\":\"安装依赖\",\"contents\":[\"系统要求:Hydro开发环境目前仅支持 Linux/Unix 系统,如您使用 Windows 请使用 WSL2 。\",\"MongoDB:Hydro 需要 MongoDB 提供数据库服务。\",\"NodeJS:请安装 NodeJS >=18 版本。(若使用 apt 请使用 nodesource 提供的源替代官方源) (推荐使用 nix ,可通过. <(curl https://hydro.ac/nix.sh) 快速安装)\",\"yarn:安装 yarn 前请先完成 NodeJS 安装。 npm install -g yarn\",\"尽管这不是必须的,但文档多数区域使用了 npx 工具来调用工作区的程序。如果此命令不存在,你可以在 Hydro 项目文件夹外使用 yarn global add npx 安装它。\"]},{\"header\":\"安装 Hydro\",\"slug\":\"安装-hydro\",\"contents\":[\"git clone https://github.com/hydro-dev/Hydro.git /root/Hydro --recursive # 下载至 /root/Hydro 文件夹 cd /root/Hydro # 进入工作目录 yarn # 安装依赖包 yarn build:ui:production # 编译前端 \"]},{\"header\":\"插件\",\"slug\":\"插件\",\"contents\":[\"开发环境部署完成后默认不启用任何插件。\",\"所有官方插件均随源码仓库下载到安装文件夹的 packages 子文件夹下,可以通过下面的命令启用官方插件(以启用 @hydrooj/ui-default 为例):\",\"npx hydrooj addon add @hydrooj/ui-default \",\"对于非官方插件,下载后通过下面的命令启用即可(以启用位置在 /root/addon 下的插件为例):\",\"npx hydrooj addon add /root/addon \"]},{\"header\":\"启动 Hydro\",\"slug\":\"启动-hydro\",\"contents\":[\"支持如下启动参数:\",\"--port=2333 指定启动端口\",\"--debug 启用开发模式\",\"使用 yarn debug --port=2333 --watch 启动 Hydro,并在后台运行 yarn build:ui:dev,可以对前端源码进行实时转译,在反复修改时可节省编译时间。启动完成后,您可以在 8000 端口访问到 Hydro 实例,且前端的任何更改将即时生效。(后端热重载可能存在 bug,部分模块修改后可能仍需重启才能生效) 请注意:此功能仅在启用了 @hydrooj/ui-default 插件的情况下才会生效。\",\"首次启动会要求您填写数据库连接信息。请根据您数据库的安装填写(若无密码则留空) 请按照下文说明创建管理员账户即可正常使用。\"]},{\"header\":\"更新\",\"slug\":\"更新\",\"contents\":[\"需要更新的时候进入对应仓库文件夹执行 git pull,然后重新 yarn && yarn build:ui:production 即可。\"]}]},\"/dev/frontend-modify.html\":{\"title\":\"前端修改\",\"contents\":[{\"header\":\"\",\"slug\":\"\",\"contents\":[\"参考 前端修改。\"]}]},\"/dev/hook.html\":{\"title\":\"使用 TypeScript 编写插件\",\"contents\":[{\"header\":\"\",\"slug\":\"\",\"contents\":[\"请注意:在阅读本节之前,请确认您已阅读【使用 TypeScript 编写插件】一节并已完成了插件的创建。\"]},{\"header\":\"示例\",\"slug\":\"示例\",\"contents\":[\"import { Context, Time } from 'hydrooj'; export async function apply(ctx: Context) { // handler 表示路由事件 // after 表示在主逻辑完成后运行 // RecordDetail 为需要捕获的路由名 // get 表示仅捕获 GET 请求 ctx.on('handler/after/RecordDetail#get', (h) => { if (h.rdoc._id.getTimestamp() < new Date(Date.now() - Time.day) { h.rdoc.code = ''; } }); } \"]}]},\"/dev/third-party-auth.html\":{\"title\":\"接入第三方账号系统\",\"contents\":[{\"header\":\"\",\"slug\":\"\",\"contents\":[\"Hydro 支持接入第三方的账号系统,并且有以下内置模块可用:\",\"@hydrooj/login-with-github\",\"@hydrooj/login-with-google\"]},{\"header\":\"对接其他平台\",\"slug\":\"对接其他平台\",\"contents\":[\"在阅读本节之前,请确保你已阅读 【插件开发】 章节。\",\"以 Github 登录为例:\",\"import { Context, ForbiddenError, Handler, superagent, SystemModel, TokenModel, UserFacingError, ValidationError, } from 'hydrooj'; declare module 'hydrooj' { interface SystemKeys { 'login-with-github.id': string; 'login-with-github.secret': string; 'login-with-github.endpoint': string; } } // 当用户点击 【使用 XX 登录】 按钮时,此函数会被执行 async function get(this: Handler) { // 从系统设置中获取基础设置,并储存状态信息(完成登录逻辑后应该跳转到哪一页) const [appid, [state]] = await Promise.all([ SystemModel.get('login-with-github.id'), TokenModel.add(TokenModel.TYPE_OAUTH, 600, { redirect: this.request.referer }), ]); this.response.redirect = `https://github.com/login/oauth/authorize?client_id=${appid}&state=${state}&scope=read:user,user:email`; } // 当用户在三方系统中完成授权,需要重定向到 /oauth/xxx/callback,这时所有返回的参数作为 callback 的一参数传入。 async function callback({ state, code }) { // 获取系统设置和之前的状态。 const [[appid, secret, endpoint, url], s] = await Promise.all([ SystemModel.getMany([ 'login-with-github.id', 'login-with-github.secret', 'login-with-github.endpoint', 'server.url', ]), TokenModel.get(state, TokenModel.TYPE_OAUTH), ]); if (!s) throw new ValidationError('token'); // 使用从 url 中返回的 token 请求第三方的 API,获取用户信息,作为函数返回。 // 在 OAuth 协议中,需要使用 state 和 code 换取 access_token 再调用 API,这在不同系统中可能设计不同。 // 系统会根据返回的用户信息自动查找已有用户或是创建新用户。 const res = await superagent.post(`${endpoint || 'https://github.com'}/login/oauth/access_token`) .send({ client_id: appid, client_secret: secret, code, redirect_uri: `${url}oauth/github/callback`, state, }) .set('accept', 'application/json'); if (res.body.error) { throw new UserFacingError( res.body.error, res.body.error_description, res.body.error_uri, ); } const t = res.body.access_token; const userInfo = await superagent.get(`${endpoint ? `${endpoint}/api` : 'https://api.github.com'}/user`) .set('User-Agent', 'Hydro-OAuth') .set('Accept', 'application/vnd.github.v3+json') .set('Authorization', `token ${t}`); const ret = { _id: `${userInfo.body.id}@github.local`, email: userInfo.body.email, bio: userInfo.body.bio, // 提供多个用户名,若需创建用户则从前往后尝试,直到用户名可用 uname: [userInfo.body.name, userInfo.body.login].filter((i) => i), avatar: `github:${userInfo.body.login}`, }; await TokenModel.del(s._id, TokenModel.TYPE_OAUTH); if (!ret.email) throw new ForbiddenError(\\\"You don't have a verified email.\\\"); return ret; } // 注册此模块。 export function apply(ctx: Context) { ctx.provideModule('oauth', 'github', { text: 'Login with Github', callback, get, }); ctx.i18n.load('zh', { 'Login With Github': '使用 Github 登录', }); } \"]}]},\"/dev/typescript.html\":{\"title\":\"使用 TypeScript 编写插件\",\"contents\":[{\"header\":\"\",\"slug\":\"\",\"contents\":[\"前置条件:NodeJS>=18 此教程将以编写剪贴板插件为例进行说明。\"]},{\"header\":\"Step1 初始化项目\",\"slug\":\"step1-初始化项目\",\"contents\":[\"使用 hydrooj addon create 快速在 /root/addon 下初始化一个插件或是在一个空文件夹中运行 yarn init 并按照提示填写相关信息。\",\"# 使用 yarn init 的样例 /workspace/hydro-plugin $ yarn init yarn init v1.22.4 question name (hydro-plugin): @hydrooj/pastebin question version (1.0.0): 0.0.1 question description: HydroOJ的剪贴板组件 question entry point (index.js): index.ts question repository url: https://github.com/hydro-dev/pastebin.git question author: undefined question license (MIT): MIT question private: success Saved package.json \"]},{\"header\":\"Step2 准备编写组件\",\"slug\":\"step2-准备编写组件\",\"contents\":[\"分析:剪贴板组件需要以下功能:\",\"与数据库交互来存储/检索相应文档。\",\"提供 /paste/create 路由以创建新文档。\",\"提供 /paste/show/:ID 来查看已创建的文档。\",\"根据用户ID进行鉴权,允许将文档设置为私密以防止他人查看。\",\"在路由中定义所有的函数应均为异步函数,支持的函数有:prepare, get, post, post[Operation], cleanup 具体流程如下:\",\"先执行 prepare(args) (如果存在) args 为传入的参数集合(包括 QueryString, Body, Path)中的全部参数, 再执行 prepare(args) (如果存在) 检查请求类型: 为 GET ? -> 执行 get(args) 为 POST ? -> 执行 post(args) -> 含有 operation 字段? -> 执行 post[Operation] 执行 cleanup() \",\"如果在 this.response.template 指定模板则渲染,否则直接返回 this.response.body 中的内容。\",\"在表单提交时的 operation 字段使用下划线,函数名使用驼峰命名。\",\"如 对应 postConfirmDelete 函数。\",\"应当提供 apply 函数,并与定义的 Handler 一同挂载到 global.Hydro.handler[模块名] 位置。 apply 函数将在初始化阶段被调用。\",\"// @noErrors // @module: esnext // @filename: index.ts import { definePlugin, Handler, Types, param, db, PRIV, validator, NotFoundError, PermissionError } from 'hydrooj'; const coll = db.collection('paste'); interface Paste { _id: string; owner: number; content: string; isPrivate: boolean; } declare module 'hydrooj' { interface Model { pastebin: typeof pastebinModel; } interface Collections { paste: Paste; // 声明数据表类型 } } async function add(userId: number, content: string, isPrivate: boolean): Promise { const pasteId = String.random(16); // Hydro 提供了此方法,创建一个长度为16的随机字符串 // 使用 mongodb 为数据库驱动,相关操作参照其文档 const result = await coll.insertOne({ _id: pasteId, owner: userId, content, isPrivate, }); return result.insertedId; // 返回插入的文档ID } async function get(pasteId: string): Promise { return await coll.findOne({ _id: pasteId }); } // 暴露这些接口,使得 cli 也能够正常调用这些函数; const pastebinModel = { add, get }; global.Hydro.model.pastebin = pastebinModel; // 创建新路由 class PasteCreateHandler extends Handler { // Get请求时触发该函数 async get() { // 检查用户是否登录,此处为多余(因为底部注册路由时已声明所需权限) // 此方法适用于权限的动态检查 // this.checkPriv(PRIV.PRIV_USER_PROFILE); this.response.template = 'paste_create.html'; // 返回此页面 } // 使用 isContent 检查输入 @param('content', Types.String, isContent) @param('private', Types.Boolean) // 从用户提交的表单中取出content和private字段 // domainId 为固定传入参数 async post(domainId: string, content: string, isPrivate = false) { // 在HTML表单提交的多选框中,选中值为 'on',未选中则为空,需要进行转换 const pasteid = await pastebin.add(this.user._id, content, !!isPrivate); // 将用户重定向到创建完成的url this.response.redirect = this.url('paste_show', { id: pasteid }); // 相应的,提供了 this.back() 方法用于将用户重定向至前一个地址(通常用于 Ajax 或是部分更新操作) } } class PasteShowHandler extends Handler { @param('id', Types.String) async get(domainId: string, id: string) { const doc = await pastebin.get(id); if (!doc) throw new NotFoundError(id); if (doc.isPrivate && this.user._id !== doc.owner) { throw new PermissionError(); } this.response.body = { doc }; this.response.template = 'paste_show.html'; } @param('id', Types.String) async postDelete(domainId: string, id: string) { // 当提交表单并存在 operation 值为 delete 时执行。 // 本例中未实现删除功能,仅作为说明。 } } // 定义为一个插件 export default definePlugin({ apply(ctx) { // 注册一个名为 paste_create 的路由,匹配 '/paste/create', // 使用PasteCreateHandler处理,访问改路由需要PRIV.PRIV_USER_PROFILE权限 // 提示:路由匹配基于 path-to-regexp ctx.Route('paste_create', '/paste/create', PasteCreateHandler, PRIV.PRIV_USER_PROFILE); ctx.Route('paste_show', '/paste/show/:id', PasteShowHandler); } }); \"]},{\"header\":\"Step4 template\",\"slug\":\"step4-template\",\"contents\":[\"模板采用 nunjucks 语法。放置于 templates/ 文件夹下。 会在请求结束时根据 response.template 的值选择模板,并使用 response.body 的值进行渲染,存入 response.body 中。 若 response.template 为空或 request.headers['accept'] == 'application/json',则跳过渲染步骤。\"]},{\"header\":\"Step5 locale\",\"slug\":\"step5-locale\",\"contents\":[\"用于提供多国翻译。格式与 Hydro 的 locale 文件夹格式相同。\"]}]},\"/docs/\":{\"title\":\"介绍\",\"contents\":[{\"header\":\"\",\"slug\":\"\",\"contents\":[\"为什么使用 Hydro?\",\"安全:使用 cgroup 进行隔离,杜绝卡评测;\",\"高效:Hydro 使用了沙箱复用技术,拥有极高的评测效率;\",\"扩展:Hydro 支持安装额外模块进行扩展;\",\"强大:配合 Judge 模块(或 HydroJudge 独立评测机),可支持 spj,交互题,提交答案题,文件IO 等多种特性;\",\"自定:所有权限节点均可自由设置;\",\"易上手:无需改动源代码,系统设置中预留了大量可自行修改的内容;管理逻辑简洁;\",\"社区:Hydro 正在持续维护中;\",\"如果您正在使用 HustOJ,可以导出题目为 FPS 文件后使用 fps-importer 插件 直接导入 Hydro。\",\"如果您正在使用 QDUOJ, 可以导出题目为 QDUOJ-zip 格式后使用 import-qduoj 插件直接导入 Hydro。\",\"如果您正在使用 Vijos / SYZOJ / HustOJ / UniversalOJ, 可以直接使用 migrate 插件 导入所有数据至 Hydro。\"]},{\"header\":\"功能对比\",\"slug\":\"功能对比\",\"contents\":[\"Hydro 支持很多其他系统无法支持的题型,可在 https://hydro.ac/d/system_test/p 中查看并免费下载使用样例。(需要登录) 下方对比了 Hydro 与其他主流 OJ 系统的功能。(只进行在不修改源代码情况下的对比)\",\"+:支持 =:部分支持 ?: 未知 -:不支持 \",\"功能\",\"Hydro\",\"HustOJ\",\"SYZOJ[1]\",\"QDUOJ\",\"Vijos\",\"安装\",\"一键脚本\",\"一键脚本\",\"手动搭建\",\"docker\",\"docker\",\"数据库\",\"MongoDB\",\"MySQL\",\"MariaDB\",\"Postgres\",\"MongoDB\",\"测试数据存储\",\"本地/S3 [2]\",\"本地\",\"本地\",\"本地\",\"数据库\",\"多评测机\",\"+\",\"=[3]\",\"=[4]\",\"=\",\"+\",\"测试数据同步\",\"按需抓取\",\"全量同步\",\"全量同步\",\"全量同步\",\"按需抓取\",\"比赛\",\"ACM/OI/IOI/乐多\",\"ACM/OI\",\"ACM/OI/IOI\",\"ACM/OI/IOI\",\"ACM/OI\",\"封榜\",\"+\",\"+\",\"-\",\"-\",\"-\",\"作业功能\",\"+\",\"+\",\"-\",\"-\",\"+\",\"修改编译命令/添加语言\",\"+\",\"=[5]\",\"-\",\"-\",\"+\",\"权限系统 [6]\",\"+\",\"=\",\"-\",\"-\",\"+\",\"训练计划(题单)\",\"+\",\"+\",\"-[7]\",\"-\",\"+\",\"团队\",\"+ [8]\",\"-\",\"-\",\"-\",\"+\",\"Hack\",\"+\",\"-\",\"-\",\"-\",\"-\",\"SpecialJudge\",\"+ [9]\",\"+\",\"+\",\"-\",\"=\",\"Subtask\",\"+\",\"-\",\"+\",\"-\",\"-\",\"交互题\",\"+\",\"-\",\"+\",\"-\",\"-\",\"RemoteJudge\",\"CF/SPOJ/UOJ/POJ/Luogu\",\"HDU/PKU\",\"-\",\"-\",\"-\",\"题目导入\",\"fps/syzoj/qduoj/hydro\",\"fps/qduoj\",\"syzoj\",\"fps/qduoj\",\"-\"]},{\"header\":\"截图\",\"slug\":\"截图\",\"contents\":[]},{\"header\":\"现在开始\",\"slug\":\"现在开始\",\"contents\":[\"点击 部署 ,开始部署您的 OJ 吧!\",\"SYZOJ 和 Lyrio (曾用名 syzoj-ng,loj.ac 当前所用系统) 是两套不同的系统,这意味着使用 SYZOJ 无法再导入 loj.ac 的题目,同时 Lyrio 无比赛功能。 ↩︎\",\"S3 指所有兼容 Amazon S3 协议的服务,包括腾讯COS,阿里OSS 等。 ↩︎\",\"安装配置繁琐,且需要手动在服务器间同步数据。 ↩︎\",\"需要手动在服务器间同步数据。 ↩︎\",\"仅能修改部分编译参数,添加语言需要修改源代码。 ↩︎\",\"此处的权限系统指 除用户/管理员二元化权限之外的 的更细粒度的权限划分。 ↩︎\",\"部分二次开发版本有此功能。 ↩︎\",\"通过域功能,允许用户创建域并在域内拥有管理员权限。域之间仅共享账号数据,也可使用域内小组进行权限控制。 ↩︎\",\"支持所有主流 SPJ 格式。 ↩︎\"]}]},\"/plugins/\":{\"title\":\"插件\",\"contents\":[{\"header\":\"\",\"slug\":\"\",\"contents\":[\"Hydro 支持使用插件扩展自身所支持的功能。\",\"Note\",\"插件对站点的所有内容具有完全的访问权限,请不要启用来历不明的插件。\"]},{\"header\":\"附加组件列表\",\"slug\":\"附加组件列表\",\"contents\":[\"Tips\",\"部分斜体字插件需配合额外支持软件,如您只安装插件是无法使用的,详情请前往左侧插件详情查看。\",\"如您为旧版本升级失去博客功能,请直接安装 @hydrooj/blog ,原数据不会丢失。\",\"Hydro 官方目前提供了以下附加组件:\",\"ID\",\"描述\",\"@hydrooj/blog\",\"博客功能\",\"@hydrooj/fps-importer\",\"导入 fps 格式的题目\",\"@hydrooj/geoip\",\"显示用户登录地(需要IP库支持)\",\"@hydrooj/hydrojudge\",\"评测组件\",\"@hydrooj/import-qduoj\",\"导入 QDUOJ 导出的题库\",\"@hydrooj/login-with-github\",\"允许用户使用 GitHub 登录\",\"@hydrooj/login-with-google\",\"允许用户使用 Google 登录\",\"@hydrooj/migrate\",\"从 vijos4/HustOJ/SYZOJ/UniversalOJ 升级\",\"@hydrooj/recaptcha\",\"注册时启用 reCAPTCHA 验证码\",\"@hydrooj/ui-default\",\"Hydro 的默认用户界面\",\"@hydrooj/onlyoffice\",\"显示 doc/docx 格式题目\",\"@hydrooj/sonic\",\"基于 sonic 的题目搜索增强\",\"@hydrooj/elastic-search\",\"基于 Elastic 的题目搜索增强\",\"@hydrooj/vjudge\",\"Codeforces/SPOJ/UOJ/POJ/Luogu\",\"@hydrooj/prom-client\",\"导出系统状态至 Prometheus\",\"大部分插件的配置均可在安装后于 控制面板>系统设置 中找到。\",\"部分插件若安装后没有正确配置可能会影响系统正常使用!\"]},{\"header\":\"安装\",\"slug\":\"安装\",\"contents\":[\"先全局安装所需模块,再向 hydrooj 注册即可。例:安装 @hydrooj/geoip\",\"yarn global add @hydrooj/geoip hydrooj addon add @hydrooj/geoip \",\"或者,如果你正在安装一个其他途径获取的插件(自行创建等),请直接使用文件夹 绝对路径: (文件夹路径即为 包含 package.json 的文件夹)\",\"hydrooj addon add /root/xxx \",\"请不要将插件与插件嵌套摆放,否则可能会导致一些不可预知的问题。\",\"安装完插件后需要重启 hydrooj 以使插件生效。\"]},{\"header\":\"查看已注册的插件列表\",\"slug\":\"查看已注册的插件列表\",\"contents\":[\"hydrooj addon list \"]},{\"header\":\"更新\",\"slug\":\"更新\",\"contents\":[\"yarn global upgrade-interactive --latest \"]},{\"header\":\"卸载\",\"slug\":\"卸载\",\"contents\":[\"yarn global remove @hydrooj/geoip hydrooj addon remove @hydrooj/geoip \"]}]},\"/plugins/elastic.html\":{\"title\":\"Elastic search\",\"contents\":[{\"header\":\"\",\"slug\":\"\",\"contents\":[\"安装 Elasticsearch 后安装 @hydrooj/elastic-search 插件。\",\"进入 HydroOJ 控制面板,在系统设置内正确填写endpoint。\",\"然后在脚本管理中找到重建题目索引,点击运行,参数留空即可。\",\"至此,搜索功能应当可以正常使用。\"]}]},\"/plugins/fps-importer.html\":{\"title\":\"fps-importer\",\"contents\":[{\"header\":\"从 fps 文件导入题目\",\"slug\":\"从-fps-文件导入题目\",\"contents\":[\"在题库右侧“创建题目”一栏中选择“从 FPS 文件导入”。 在打开的窗口中,您可以上传:\",\"fps 格式的 xml 文件\",\"zip 文件,其中包含了一个或多个 fps 格式的 xml 文件\",\"由于防止解析 fps 文件消耗大量内存,将拒绝导入超过 64MiB 的文件。\\nxml 文件需要为 UTF8 编码,否则可能出现中文题面乱码;\\n若您的文件超过大小限制,可考虑先在本地使用 Easy-Fps-Viewer 等工具进行拆分。\"]}]},\"/plugins/geoip.html\":{\"title\":\"GeoIP\",\"contents\":[{\"header\":\"\",\"slug\":\"\",\"contents\":[\"插件需要 MaxMind 的 Geolite2-City.mmdb 支持,在安装插件后需要将mmdb拷贝至插件同一目录下方可启用,如果你不知道这是什么,请勿安装。\"]}]},\"/plugins/hydrojudge.html\":{\"title\":\"hydrojudge\",\"contents\":[{\"header\":\"\",\"slug\":\"\",\"contents\":[\"Tips\",\"您可以通过一键安装脚本快速安装独立评测机,详情请前往 部署Hydro 查看。\"]},{\"header\":\"准备\",\"slug\":\"准备\",\"contents\":[\"在配置评测机之前,请确认您的站点已经可以访问并正常登录/注册。\",\"您应该预先下载您所要支持的语言的编译器,若您在配置完评测机后 升级/重新安装 了编译器,您需要重新启动沙箱。 关于编译器说明,请参照 编译器 章节。\",\"如果不使用自动脚本,您需要按照如下方式手动安装沙箱服务: 前往 criyle/go-judge 下载 executorserver。 Executorserver 需要在后台以 root 权限运行并监听 127.0.0.1:5050 。 可使用 pm2 进行管理。\"]},{\"header\":\"安装\",\"slug\":\"安装\",\"contents\":[]},{\"header\":\"作为附加组件\",\"slug\":\"作为附加组件\",\"contents\":[\"Tips\",\"由于用附加组件安装的评测机与 Hydro 必须在同一台服务器上,每一个 Hydro 实例最多只能有一台评测机由附加组件安装。\",\"在安装 Hydro 的机器上运行下面的指令安装 @hydrooj/hydrojudge:\",\"yarn global add @hydrooj/hydrojudge hydrooj addon add @hydrooj/hydrojudge \",\"重启 Hydro 后 hydrojudge 即可正常运行。\"]},{\"header\":\"作为独立进程\",\"slug\":\"作为独立进程\",\"contents\":[\"Tips\",\"该方法可以帮助您在任意服务器上部署评测机。\",\"首先需要创建一个有 PRIV_JUDGE 权限的账户,具体方法参照 此处。(在部署 Hydro 的服务器上运行)\",\"然后在运行评测机的服务器上安装 HydroJudge :\",\". <(curl https://hydro.ac/setup.sh) --judge \",\"创建目录 ~/.config/hydro,在该目录下创建文件 judge.yaml,配置文件格式如下:\",\"hosts: localhost: type: hydro # vj4 用户请在此处填写 vj4 server_url: http://localhost/ # Hydro 运行的网址 uname: judge # 评测账号用户名 password: abc123 # 评测账号密码 detail: true # 默认为 true \",\"设置完之后,使用下面的指令即可开始运行(可以使用 pm2 管理):\",\"hydrojudge \"]},{\"header\":\"更新\",\"slug\":\"更新\",\"contents\":[\"HydroJudge 会发布不定期更新。您可以使用 yarn global upgrade-interactive --latest 来检测并进行更新。\"]},{\"header\":\"关闭\",\"slug\":\"关闭\",\"contents\":[]},{\"header\":\"作为附加组件\",\"slug\":\"作为附加组件-1\",\"contents\":[\"在 系统设置>hydrojudge 中有一栏 Disable builtin judge,将它勾上,然后重启 Hydro 即可。\"]},{\"header\":\"作为独立进程\",\"slug\":\"作为独立进程-1\",\"contents\":[\"根据开启的方法关闭即可。\"]},{\"header\":\"卸载\",\"slug\":\"卸载\",\"contents\":[\"关闭后运行下面指令即可。\",\"yarn global remove @hydrooj/hydrojudge hydrooj addon remove @hydrooj/hydrojudge \"]},{\"header\":\"评测设置\",\"slug\":\"评测设置\",\"contents\":[]},{\"header\":\"作为附加组件\",\"slug\":\"作为附加组件-2\",\"contents\":[\"在 系统设置>hydrojudge 修改对应的参数,然后重启 Hydro 和 hydrojudge 即可。\"]},{\"header\":\"作为独立进程\",\"slug\":\"作为独立进程-2\",\"contents\":[\"如果有需要修改单题测试点数量上限等设置,可以在 ~/.config/hydro/judge.yaml 的末尾添加下列内容:\",\"testcases_max: 100 # 单题最多测试点数量 total_time_limit: 120 # 单题最大总测试时长 parallelism: 2 # 单评测机评测进程数量 # 更多可选配置均可添加在此处,格式与前面的三排类似 \",\"在 此处 的设置均可添加到此处。\"]},{\"header\":\"修改编译选项/添加新语言支持\",\"slug\":\"修改编译选项-添加新语言支持\",\"contents\":[\"对于已安装内置评测机的用户(无论内置评测机是否启动),在 控制面板>系统设置 中修改 judge.langs 配置项即可;对于没有安装内置评测机的用户,需要在 ~/.config/hydro/langs.yaml 中配置。\",\"文件格式参照 此处 。\",\"如果您添加了新的语言,您还需要前往 控制面板>系统设置 中修改 Language Highlight ID 与 Monaco language modes。 分别表示选择对应的语言后的高亮设置(基于 PrismJS)和 Monaco 编辑器语法规则设置。\",\"修改完后请重启 Hydro 和 hydrojudge 。\"]},{\"header\":\"测试数据格式\",\"slug\":\"测试数据格式\",\"contents\":[\"参照 测试数据格式 配置。\"]},{\"header\":\"调整沙箱空间大小\",\"slug\":\"调整沙箱空间大小\",\"contents\":[\"Note\",\"如果不调整沙箱的空间大小,当您的评测使用文件 IO 且输入输出文件较大时可能会引发错误。\",\"对于 2022/8/12 前安装的用户:\",\"在服务器上运行下面的代码找到 hydro-sandbox 的运行目录:\",\"pm2 info hydro-sandbox | grep \\\"exec cwd\\\" \",\"将 mount.yaml 下载并放置在 sandbox 的运行目录下。然后修改第 64 行和第 68 行的 size 和 nr_inodes 的大小至您想要的大小,保存后重启 sandbox 即可完成更改。\",\"对于 2022/8/12 后安装的用户:\",\"编辑 /root/.hydro/mount.yaml,修改 size 即可。\"]},{\"header\":\"C/C++ 彩色编译错误信息\",\"slug\":\"c-c-彩色编译错误信息\",\"contents\":[\"确认您安装了支持彩色输出的编译器;\",\"在系统设置中,将 C/C++ 编译命令后加上 -fdiagnostics-color=always\",\"例:\",\"c: compile: /usr/bin/gcc -O2 -Wall -std=c99 -o ${name} foo.c -lm -fdiagnostics-color=always \"]},{\"header\":\"开大程序运行栈空间\",\"slug\":\"开大程序运行栈空间\",\"contents\":[\"2022/8/12 后安装的实例默认已开启无限栈空间,无需手动操作\",\"在很多时候系统默认为程序提供的栈空间并不能满足我们的需求,此时我们需要手动为用户程序提供更大的栈空间。\",\"修改 pm2 中 hydro-sandbox 的启动参数为 ulimit -s unlimited && /usr/bin/hydro-sandbox :\",\"pm2 del hydro-sandbox pm2 start bash --name hydro-sandbox -- -c \\\"ulimit -s unlimited && hydro-sandbox\\\" \"]},{\"header\":\"提高测评精度\",\"slug\":\"提高测评精度\",\"contents\":[\"禁用 CPU 频率缩放与 Intel 睿频加速技术,防止 CPU 频率波动。\",\"禁用内存地址空间随机化,以使得存在内存寻址错误的代码能够得到更多可重复的结果,可以通过在 /etc/sysctl.conf 中添加下面这行并运行 sudo sysctl -p 应用:\",\"kernel.randomize_va_space = 0 \"]},{\"header\":\"内存计量不准确\",\"slug\":\"内存计量不准确\",\"contents\":[\"部分 Linux 设备默认使用 cgroup2,而 cgroup2 中移除了精确计量内存消耗的接口。 若要获得更精确的内存计量,推荐启用 cgroup v1 (您可以通过检查 /sys/fs/cgroup/memory/memory.memsw.usage_in_bytes 是否存在来验证是否当前系统是否启用了 cgroup v1 ):\",\"以 Ubuntu 的默认引导器 GRUB 2 为例,编辑 /etc/default/grub: 在其中\",\"GRUB_CMDLINE_LINUX_DEFAULT=\\\"quiet splash\\\" \",\"后,加入 cgroup_enable=memory swapaccount=1 systemd.unified_cgroup_hierarchy=0 syscall.x32=y,变为:\",\"GRUB_CMDLINE_LINUX_DEFAULT=\\\"quiet splash cgroup_enable=memory swapaccount=1 systemd.unified_cgroup_hierarchy=0 syscall.x32=y\\\" \",\"运行以下命令更新 GRUB 2 的配置,然后重新启动。\",\"update-grub && reboot \"]}]},\"/plugins/migrate.html\":{\"title\":\"migrate\",\"contents\":[{\"header\":\"从 HUSTOJ 升级\",\"slug\":\"从-hustoj-升级\",\"contents\":[\"Note\",\"迁移会删除当前 Hydro 的所有数据(含用户账户信息)并移入 HUSTOJ 的数据。 请注意备份相关文件。\",\"请先完成 Hydro 的部署并完成对文件服务的配置(setting_file)。 在迁移数据之前,请先停止正在运行的 HUSTOJ 服务,仅保留其数据库开启。 请注意 Hydro 所在的数据库不应和源 HUSTOJ 数据库相同。\",\"安装插件后,您应当能够在 控制面板>脚本管理 中找到名为 migrateHustoj 的脚本。 其参数格式如下:\",\"{\\\"host\\\":\\\"localhost\\\",\\\"port\\\":3306,\\\"name\\\":\\\"jol\\\",\\\"username\\\":\\\"\\\",\\\"password\\\":\\\"\\\",\\\"domainId\\\":\\\"system\\\",\\\"contestType\\\":\\\"\\\",\\\"dataDir\\\":\\\"\\\",\\\"uploadDir\\\":\\\"\\\"} \",\"host: 数据库地址\",\"port: 数据库端口\",\"name: 数据库名,一般为 jol\",\"username&password: 账号密码,若无则填写空字符串\",\"domainId: 迁入的域,默认为 system\",\"contestType: oi 或者 acm,视情况而定\",\"dataDir: HUSTOJ 中 data 文件夹的位置(这里存储着题目数据等关键信息,需要手动处理)\",\"uploadDir: HUSTOJ 中 上传文件的位置(这里存储着上传的图片和文件等信息,默认已指定 /home/judge/src/web/upload/ ,如果此路径与您路径相同,请不要填写此项)\",\"当脚本运行完成后,请重启 Hydro 实例,会自动完成之后的升级操作。 迁移后,请使用原 HUSTOJ 的管理员账号登录实例。\"]},{\"header\":\"从 SYZOJ 升级\",\"slug\":\"从-syzoj-升级\",\"contents\":[\"SYZOJ 与 HUSTOJ 迁移方法类似,迁移脚本应运行名为 migrateSyzoj 的脚本外,SYZOJ无需 contestType 参数。 其参数格式如下:\",\"{\\\"host\\\":\\\"localhost\\\",\\\"port\\\":3306,\\\"name\\\":\\\"syzoj\\\",\\\"username\\\":\\\"\\\",\\\"password\\\":\\\"\\\",\\\"domainId\\\":\\\"system\\\",\\\"dataDir\\\":\\\"\\\"} \",\"host: 数据库地址\",\"port: 数据库端口\",\"name: 数据库名,一般为 syzoj\",\"username&password: 账号密码,若无则填写空字符串\",\"domainId: 迁入的域,默认为 system\",\"dataDir: SYZOJ 中 data 文件夹的位置(这里存储着题目数据等关键信息,需要手动处理)\",\"由于SYZOJ脚本会将原站所有数据迁移,所以运行耗时较长。 当脚本运行完成后,请重启 Hydro 实例,会自动完成之后的升级操作。 迁移后,请使用原 SYZOJ 的管理员账号登录实例。\"]},{\"header\":\"从 UniversalOJ 升级\",\"slug\":\"从-universaloj-升级\",\"contents\":[\"UniversalOJ (常称作UOJ社区版)与前两者迁移方法类似,迁移脚本应运行名为 migrateUniversalOJ 的脚本。\",\"由于其升级过程较为麻烦,安装脚本已提供自动升级服务,如您需要可运行安装脚本一键迁移,手动迁移请在开发群中提问。\",\"由于UniversalOJ脚本会将原站所有数据迁移,所以运行耗时较长。 当脚本运行完成后,请重启 Hydro 实例,会自动完成之后的升级操作。 迁移后,请使用原 UniversalOJ 的管理员账号登录实例。\"]},{\"header\":\"从 Vijos 升级\",\"slug\":\"从-vijos-升级\",\"contents\":[\"Note\",\"迁移会删除当前 Hydro 的所有数据(含用户账户信息)并移入 vj4 的数据。 请注意备份相关文件。\",\"请先完成 Hydro 的部署并完成对文件服务的配置(setting_file)。 在迁移数据之前,请先停止正在运行的 vj4 服务,仅保留其数据库开启。 请注意 Hydro 所在的数据库不应和源 vj4 数据库相同。 若您使用 vj4-docker ,可更改 docker-compose.yml 将数据库映射至其他本机端口。\",\"安装插件后,您应当能够在 控制面板>脚本管理 中找到名为 migrateVijos 的脚本。 其参数格式如下:\",\"{\\\"host\\\":\\\"localhost\\\",\\\"port\\\":27017,\\\"name\\\":\\\"vj4\\\",\\\"username\\\":\\\"\\\",\\\"password\\\":\\\"\\\"} \",\"host: 数据库地址\",\"port: 数据库端口\",\"name: 数据库名\",\"username&password: 账号密码,若无则填写空字符串\",\"Tips\",\"vj4-docker 中数据库名为 vj4,无账号密码。\",\"当脚本运行完成后,请重启 Hydro 实例,会自动完成之后的升级操作。 迁移后,请使用原 vj4 的管理员账号登录实例。\",\"Note\",\"若您的 vj4 是由 vj2 或 tyvj 升级而来,在迁移完成后请不要卸载该插件,否则可能导致部分用户无法登录。\"]}]},\"/plugins/recaptcha.html\":{\"title\":\"recaptcha\",\"contents\":[{\"header\":\"\",\"slug\":\"\",\"contents\":[\"Tips\",\"我们采用 reCAPTCHA v3 来检验注册者是否是人类,在注册过程中没有看见传统验证码属正常现象。\",\"前往 https://www.google.com/recaptcha/admin/create 创建 reCAPTCHA 密钥。 reCAPTCHA 类型请选择“reCAPTCHA 第 3 版”。\",\"创建成功后将客户端密钥和服务端密钥分别填入系统设置 recaptcha 栏下的 key 和 secret 中,重启 Hydro 后 reCAPTCHA 即可正常工作。\"]}]},\"/plugins/sonic.html\":{\"title\":\"Sonic\",\"contents\":[{\"header\":\"安装\",\"slug\":\"安装\",\"contents\":[]},{\"header\":\"安装 sonic-server\",\"slug\":\"安装-sonic-server\",\"contents\":[\"使用 root 用户执行如下命令:\",\"nix-env -iA nixpkgs.sonic-server \"]},{\"header\":\"安装 sonic 插件\",\"slug\":\"安装-sonic-插件\",\"contents\":[\"使用 root 用户执行如下命令:\",\"yarn global add @hydrooj/sonic hydrooj addon add @hydrooj/sonic \"]},{\"header\":\"启动\",\"slug\":\"启动\",\"contents\":[\"在 /root/.sonic/config.cfg(没有的自行建立,也可以换成其他的你喜欢的路径)按照以下配置示例写入配置。\",\"配置示例:\",\"# Sonic # Fast, lightweight and schema-less search backend # Configuration file # Example: https://github.com/valeriansaliou/sonic/blob/master/config.cfg [server] log_level = \\\"error\\\" [channel] inet = \\\"127.0.0.1:1491\\\" # 默认监听本机 tcp_timeout = 300 auth_password = \\\"SecretPassword\\\" [channel.search] query_limit_default = 10 query_limit_maximum = 100 query_alternates_try = 4 suggest_limit_default = 5 suggest_limit_maximum = 20 [store] [store.kv] path = \\\"/data/sonic/store/kv/\\\" retain_word_objects = 1000 [store.kv.pool] inactive_after = 1800 [store.kv.database] flush_after = 900 compress = true parallelism = 2 max_files = 100 max_compactions = 1 max_flushes = 1 write_buffer = 16384 write_ahead_log = true [store.fst] path = \\\"/data/sonic/store/fst/\\\" [store.fst.pool] inactive_after = 300 [store.fst.graph] consolidate_after = 180 max_size = 2048 max_words = 250000 \",\"执行如下命令:\",\"pm2 start sonic -- -c /root/.sonic/config.cfg pm2 save \"]},{\"header\":\"配置\",\"slug\":\"配置\",\"contents\":[]},{\"header\":\"后端地址配置\",\"slug\":\"后端地址配置\",\"contents\":[\"进入 HydroOJ 控制面板,配置 sonic 后端地址。\",\"如果您直接复制配置示例,那么按照以下内容配置:\",\"host: 127.0.0.1\",\"port: 1491\",\"auth: SecretPassword\",\"修改完成后,重启 HydroOJ。\"]},{\"header\":\"重启 HydroOJ\",\"slug\":\"重启-hydrooj\",\"contents\":[\"执行命令 pm2 restart hydrooj。\"]},{\"header\":\"重建题目索引\",\"slug\":\"重建题目索引\",\"contents\":[\"进入 HydroOJ 控制面板,在脚本管理中找到重建题目索引,点击运行,参数留空即可。\",\"至此,搜索功能应当可以正常使用。\"]},{\"header\":\"FAQ\",\"slug\":\"faq\",\"contents\":[]},{\"header\":\"安装后题目搜索不正常\",\"slug\":\"安装后题目搜索不正常\",\"contents\":[\"请更新到 HydroOJ 最新版本后,再运行重建题目索引。\"]}]},\"/plugins/vjudge.html\":{\"title\":\"Vjudge\",\"contents\":[{\"header\":\"\",\"slug\":\"\",\"contents\":[\"Note\",\"此文档已过时,仅作留存使用,请前往 FAQS 查看使用指南。\"]},{\"header\":\"Codeforces\",\"slug\":\"codeforces\",\"contents\":[\"由于 vjudge 更新了反爬虫机制,Codeforces RemoteJudge 需要一些特殊手段才能正常工作。 详情请 阅读源码\",\"安装插件后创建名为 codeforces 的域,进入数据库 db.domain.updateOne({_id:'codeforces'},{$set:{mount:'codeforces'}});\",\"在 codeforces 的域设置中,将 allowedLangs 如下配置(在新版即在允许提交的语言中选中所有 codeforces 开头的语言):\",\"codeforces,codeforces.43,codeforces.52,codeforces.50,codeforces.54,codeforces.59,codeforces.61,codeforces.65,codeforces.9,codeforces.28,codeforces.32,codeforces.12,codeforces.60,codeforces.36,codeforces.48,codeforces.19,codeforces.3,codeforces.4,codeforces.51,codeforces.13,codeforces.6,codeforces.7,codeforces.31,codeforces.40,codeforces.41,codeforces.67,codeforces.49,codeforces.20,codeforces.34,codeforces.55 \",\"在 vjudge 表中插入如下条目:\",\"{type:'codeforces', handle:'', password:''} \",\"将如下配置添加至 langs 设置末尾:\",\"codeforces: execute: none display: Codeforces domain: - codeforces # Allow domain 'codeforces' to use these languages codeforces.43: highlight: cpp astyle-c monaco: cpp display: GNU GCC C11 5.1.0 comment: // codeforces.52: highlight: cpp astyle-c monaco: cpp display: Clang++17 Diagnostics comment: // codeforces.50: highlight: cpp astyle-c monaco: cpp display: GNU G++14 6.4.0 comment: // codeforces.54: highlight: cpp astyle-c monaco: cpp display: GNU G++17 7.3.0 comment: // codeforces.59: highlight: cpp astyle-c monaco: cpp display: Microsoft Visual C++ 2017 comment: // codeforces.61: highlight: cpp astyle-c monaco: cpp display: GNU G++17 9.2.0 (64 bit, msys 2) comment: // codeforces.65: highlight: cpp astyle-cs monaco: csharp display: C# 8, .NET Core 3.1 comment: // codeforces.9: highlight: cpp astyle-cs monaco: csharp display: C# Mono 6.8 comment: // codeforces.28: highlight: d monaco: plain display: D DMD32 v2.091.0 comment: // codeforces.32: highlight: go display: Go 1.15.6 comment: // codeforces.12: highlight: haskell display: Haskell GHC 8.10.1 comment: -- codeforces.60: highlight: java astyle-java monaco: java display: Java 11.0.6 comment: // codeforces.36: highlight: java astyle-java monaco: java display: Java 1.8.0_241 comment: // codeforces.48: highlight: kotlin display: Kotlin 1.4.0 comment: // codeforces.19: highlight: ocaml monaco: plain display: OCaml 4.02.1 comment: ['(*','*)'] codeforces.3: highlight: pascal display: Delphi 7 comment: // codeforces.4: highlight: pascal display: Free Pascal 3.0.2 comment: // codeforces.51: highlight: pascal display: PascalABC.NET 3.4.2 comment: // codeforces.13: highlight: perl display: Perl 5.20.1 comment: '#' codeforces.6: highlight: php display: PHP 7.2.13 comment: // codeforces.7: highlight: python display: Python 2.7.18 comment: '#' codeforces.31: highlight: python display: Python 3.9.1 comment: '#' codeforces.40: highlight: python display: PyPy 2.7 (7.3.0) comment: '#' codeforces.41: highlight: python display: PyPy 3.7 (7.3.0) comment: '#' codeforces.67: highlight: ruby display: Ruby 3.0.0 comment: '#' codeforces.49: highlight: rust display: Rust 1.49.0 comment: // codeforces.20: highlight: scala display: Scala 2.12.8 comment: // codeforces.34: highlight: javascript display: JavaScript V8 4.8.0 comment: // codeforces.55: highlight: javascript display: Node.js 12.6.3 comment: // \",\"之后再重启 Hydro 即可。\"]}]},\"/docs/install/\":{\"title\":\"部署 Hydro\",\"contents\":[{\"header\":\"\",\"slug\":\"\",\"contents\":[\"这里提供了几套方案帮助您建立自己的站点,请选择适合您的方案并继续。 搭建过程中如果遇到问题欢迎 联系我们 提问。\"]},{\"header\":\"服务器选择\",\"slug\":\"服务器选择\",\"contents\":[\"不同服务商提供的 CPU 主频不同,下方数据仅供参考。 最低服务器配置: CPU: 1核 内存: 2G。(约可允许 100 人使用)请尽量不要使用突发性能实例或共享型实例,这可能会导致评测时间计量不准确\",\"CentOS 8 已于 2021-12-31 停止支持,后续不会为安全漏洞发布补丁,建议重装为其他操作系统。\",\"Tips\",\"兼容大部分 Linux 发行版,推荐使用 Debian 12 / Debian 11 / Ubuntu 22.04 (教程多,成功率高,上手简单),不支持 CentOS 及其各种变种:\",\"CentOS\",\"Alibaba Cloud Linux\",\"TencentOS\",\"OpenCloudOS\",\"如果你的机器内存较小(<=2GiB),请避免使用 Ubuntu 22.04,它会消耗较多的内存。建议使用 Debian 12 / Debian 11。 如果你有 Linux 运维经验,Hydro 同样支持在 Alpine Linux 上运行,Alpine Linux 系统启动后仅占用 ~100M 内存,是在低配置服务器上运行的更优方案。\",\"Note\",\"虚拟机用户请注意:\",\"Hydro 使用的数据库依赖于 CPU 的 avx 指令集以提高运行性能,大部分虚拟机软件默认没有启用 avx 指令集,请参照您使用的虚拟机软件说明。\",\"虚拟机由于非独占 CPU,会导致评测时间计量精度降低。\",\"由于虚拟机本身的数据保存机制,突然断电很容易导致数据库损坏无法读取,请务必定期备份数据库,有条件请购买 UPS 保证供电稳定。\",\"Docker 用户请注意:\",\"使用安装脚本需要设置 USER 环境变量为 root。\",\"需要使用 --privileged 参数启动容器,否则评测机无法运行。\"]},{\"header\":\"部署\",\"slug\":\"部署\",\"contents\":[\"Tips\",\"Hydro 需要使用以下端口: 80, 443, 2019, 8888, 5050, 27017,请确保这些端口空闲。安装和安装后的所有操作均需要在 root 权限下进行!(sudo su)。 宝塔面板已知出现多次高危漏洞,为防止数据丢失,请不要在生产环境中使用!\",\"运行下面的脚本,等待几分钟即可(建议复制防止敲错):\",\"LANG=zh . <(curl https://hydro.ac/setup.sh) \",\"Tips\",\"如果有特殊需求,安装脚本支持一些可选的高级选项,以此方式调用: . <(curl https://hydro.ac/setup.sh) --foo --bar\",\"--no-caddy 不配置安装反向代理,只监听8888端口\",\"--judge 仅作为独立评测机安装\",\"阿里云/腾讯云/华为云等等用户安装后如果不能访问 请百度搜索 xx云 放行80端口 脚本默认使用的为清华大学镜像。 安装完成后,从 http://服务器ip/ 访问网页端,注册一个账号,之后在终端中使用\",\"hydrooj cli user setSuperAdmin 2 \",\"将首个注册用户设置为超级管理员。之后刷新页面,您应当能在上方导航栏看到控制面板入口。 进入控制面板,右侧系统设置,验证管理员密码后按需修改配置,注意 Server BaseURL 一项需要填写访问网站用的完整的 URL,以 / 结尾。(重要,务必正确填写,样例:https://hydro.ac/)\",\"系统安装后需要题库,可前往 https://hydro.ac/d/tk/p 免费专区进行下载,支持批量导入。\\n至此,基础功能安装已全部完成,另,如果你的服务部署在内网,且希望外网的用户可以访问,可以百度搜索 “端口映射” 相关教程。\"]}]},\"/docs/install/compiler.html\":{\"title\":\"编译器\",\"contents\":[{\"header\":\"\",\"slug\":\"\",\"contents\":[\"从 2022/8/12 开始,Hydro 为了避免宿主机环境变化对于评测的影响,对于 此后新安装的实例 默认使用 nix 管理环境。 如果你是在这之前安装的 Hydro,请使用 apt 安装编译器后使用 pm2 restart hydro-sandbox 重启沙箱,并忽略本章节。\",\"以下是 nix 的简要操作说明:\",\"使用 nix-env -iA nixpkgs.编译器名 安装新编译器,后重启沙箱 pm2 restart hydro-sandbox 生效。\",\"可以在 Nixos Search 中搜索你需要的编译器。 以下是常用编译器的示例:\",\"nix-env -iA nixpkgs.busybox nixpkgs.bash nixpkgs.diffutils nixpkgs.unzip # 基础组件,已预装,不建议删除 nix-env -iA nixpkgs.gcc nixpkgs.fpc # C/C++ 和 Pascal,已预装,不建议删除 nix-env -iA nixpkgs.ghc # Haskell nix-env -iA nixpkgs.rustc # Rust nix-env -iA nixpkgs.python2 # Python2 nix-env -iA nixpkgs.pythonPackages.numpy # Python2 Numpy 库 nix-env -iA nixpkgs.python3Minimal nix-env -iA nixpkgs.python3Packages.numpy nix-env -iA nixpkgs.php # PHP nix-env -iA nixpkgs.go # Golang nix-env -iA nixpkgs.nodejs # NodeJS nix-env -iA nixpkgs.openjdk_headless # Java nix-env -iA nixpkgs.ruby # Ruby nix-env -iA nixpkgs.mono # C# nix-env -iA nixpkgs.julia_17-bin # Julia \",\"使用 nix-env -q 查看已安装的列表,后使用 nix-env -e 编译器名 即可删除对应的编译器。 请注意不要误删 Hydro 基础组件,且操作完成后需要重启沙箱 pm2 restart hydro-sandbox 生效。\"]},{\"header\":\"进阶\",\"slug\":\"进阶\",\"contents\":[\"如果你需要更加复杂的编译环境配置,我们建议使用编写单独的 nix 文件。\",\"{ system ? builtins.currentSystem, pkgs ? import { system = system; } }: pkgs.buildEnv { name = \\\"hydrojudge-rootfs\\\"; paths = with pkgs; [ coreutils bash diffutils nix zip unzip gcc # 上方包是评测所需要的,请勿删除, # 在下方列出你所需要的包,查找方式同上文: fpc python3 rustc ]; ignoreCollisions = true; pathsToLink = [ \\\"/\\\" ]; # 导出一些基本信息和部分编译器所需的 /etc/passwd postBuild = '' mkdir $out/buildInfo echo 'root:x:0:0:root:/root:/bin/bash' >$out/etc/passwd date >$out/buildInfo/timestamp ''; } \",\"复制以上文件,保存为 default.nix ,使用 nix-build 进行构建。 构建后会产生一个 result 文件夹,记住该文件夹所在的路径。 打开 ~/.hydro/mount.yaml 将其中 /root/.nix-profile 替换为编译出的 result 文件夹(切换到新的环境) 之后保存并重启沙箱。\",\"后续若需更改环境配置,仅需要修改 default.nix 文件之后 nix-build 重新构建,再重启沙箱即可生效。 构建过程中的缓存文件可以使用 nix-collect-garbage 进行清理。\",\"更详细的 nix 语言介绍,请参照 Nix Guide 和\\nNix Manual。\"]}]},\"/docs/install/proxy.html\":{\"title\":\"反向代理 / SSL 配置\",\"contents\":[{\"header\":\"2022/10/27 后使用脚本安装的实例已自动配置 Caddy 反向代理,请直接编辑位于 ~/.hydro/Caddyfile 的配置文件!\",\"slug\":\"_2022-10-27-后使用脚本安装的实例已自动配置-caddy-反向代理-请直接编辑位于-hydro-caddyfile-的配置文件\",\"contents\":[\"Note\",\"若使用反向代理,请注意系统设置中的 server.xff 和 server.xhost 设置项需要填写正确(小写),分别对应反向代理所添加的标头名(通常为 x-forwarded-for 和 x-forwarded-host,部分反代工具会使用 x-real-ip 替代 x-forwarded-for)。 server.xhost 设置项配置错误会导致用户无法登录等问题。(CsrfTokenError) server.xff 设置项配置错误会导致无法记录用户IP。\",\"除一键安装脚本在安装 Caddy 后会自动配置设置项,其他工具请在使用工具前先配置好系统设置!否则将造成用户无法登录、无法记录用户IP等问题。\",\"若您使用 Nginx,请注意配置 WebSocket 协议的反向代理,否则会导致评测状态无法自动刷新,在线 IDE 无法正常使用等问题。\",\"Hydro 支持使用 Caddy, HaProxy 等工具进行反向代理,此处 提供了一些配置样例。\",\"Hydro 推荐您使用 Caddy。以下为样例 Caddyfile。 提示:如果您的服务器位于国内,则需要进行备案后才能使用 80 和 443 端口。\",\"hydro.ac { log { output file /data/access.log { roll_size 1gb roll_keep_for 72h } format json } root * /root/.hydro/static @static { file { try_files {path} } } handle @static { file_server } handle { reverse_proxy http://127.0.0.1:8888 } } \"]}]},\"/docs/install/s3.html\":{\"title\":\"存储\",\"contents\":[{\"header\":\"\",\"slug\":\"\",\"contents\":[\"Tips\",\"使用一键安装脚本部署的 Hydro 一般已自动完成存储配置。\",\"文件默认存储于本地的 /data/file/hydro 目录下,切换存储后端时需要手动复制或移动原有文件。 请根据你使用的存储端类型阅读对应教程。(同时欢迎使用其他存储类型的用户向我们提供详细的存储教程)\",\"MinIO\",\"Note\",\"新版本 MinIO 占用较大,如果您为轻量使用,我们不建议使用 MinIO 。旧版本 Hydro 用户大部分可直接切换至 file 模式,由 Hydro 代替读取。\",\"安装 MinIO 后进入 控制面板>manage_config。\",\"file.type: s3\",\"file.endPoint: http://127.0.0.1:9000(即 MinIO 启动时显示的 endPoint)\",\"file.accessKey: 参照 MinIO 配置\",\"file.secretKey: 参照 MinIO 配置\",\"file.bucket: hydro(MinIO 内部存储桶名称)\",\"file.region: us-east-1\",\"file.pathStyle: true\",\"file.endPointForUser: /fs/\",\"file.endPointForJudge: /fs/\",\"保存后重启,已有文件请自行复制。\",\"腾讯云COS\",\"进入 控制面板>系统设置>存储桶设置。\",\"file.type: s3\",\"file.endPoint: http://cos.<存储桶地域>.myqcloud.com (或是 https)\",\"file.accessKey: 您的腾讯云 API 密钥的 SecretId\",\"file.secretKey: 您的腾讯云 API 密钥的 SecretKey\",\"file.bucket: <存储桶名称>\",\"file.region: Auto\",\"file.pathStyle: true\",\"file.endPointForUser: 给用户使用的 EndPoint,若填 /fs/ 则表示由服务器转发\",\"file.endPointForJudge: 给 judge 使用的 EndPoint,若填 /fs/ 则表示由服务器转发\",\"保存后重启,已有文件请自行复制。\",\"阿里云OSS\",\"// TODO & PRs Welcome\"]}]},\"/docs/install/smtp.html\":{\"title\":\"SMTP\",\"contents\":[{\"header\":\"\",\"slug\":\"\",\"contents\":[\"以 QQ 邮箱为例。\",\"SMTP_USER: 12345678@qq.com\",\"SMTP_PASS: 提供的 SMTP 密码\",\"SMTP_HOST: smtp.qq.com\",\"SMTP_PORT: 465/587 (请参照邮件服务商说明)\",\"SMTP_SECURE: 是否使用加密 TLS 连接(请参照邮件服务商说明,使用 STARTTLS 的服务商无需勾选)\",\"SMTP_FROM: 发送签名(提示:若不清楚请填写邮件地址,填错会导致邮件无法发送)\",\"已知能够完整兼容的服务商有:\",\"QQ 邮箱\",\"腾讯企业邮\",\"网易 163 邮箱\",\"飞书域名邮箱\",\"Zeptomail\",\"Zoho Mail\",\"Outlook\",\"Gmail\",\"如果使用其他服务商且没有发现问题,欢迎向此列表 Pull Request。\"]}]},\"/docs/system/FAQ.html\":{\"title\":\"常见问题\",\"contents\":[{\"header\":\"\",\"slug\":\"\",\"contents\":[\"已移动至 此处\"]}]},\"/docs/system/cdn.html\":{\"title\":\"使用内容分发网络\",\"contents\":[{\"header\":\"\",\"slug\":\"\",\"contents\":[\"如您希望改善 Hydro 的访问质量,在您的服务器带宽较小的情况下,您可以考虑使用内容分发网络,即 CDN ,通常情况下您仅需设置资源 CDN 即可大幅度改善访问质量,关于如何使用内容分发网络和使用中的任何问题请联系各大云厂商。\"]},{\"header\":\"资源 CDN\",\"slug\":\"资源-cdn\",\"contents\":[\"创建并配置好资源 CDN ,在控制面板中将 server.cdn 设置项修改为 CDN 域名。(如 https://cdn.hydro.ac/,以 / 结尾)。\"]},{\"header\":\"全站 CDN\",\"slug\":\"全站-cdn\",\"contents\":[\"如果您预算充足,可以使用全站 CDN。\",\"Note\",\"全站 CDN 配置较为繁琐,如您没有相关使用经验请仅建立并配置资源 CDN ,配置资源 CDN 在大部分情况下即可大幅度改善访问质量。 因各服务商全站 CDN 配置方法不同,配置过程不同,需要配置的内容较多,以下仅为参考配置且配置补全,如果有任何问题建议先查阅云服务商文档及咨询云服务商工程师。\",\"缓存设置可以参考以下设置:\",\"类型\",\"内容\",\"缓存行为\",\"全部文件\",\"全部文件\",\"遵循源站\",\"文件后缀\",\"jpg,js,png,css,gif\",\"缓存一天\",\"同时设置添加回源HTTP请求头\",\"头部参数\",\"头部取值\",\"X-Forward-For\",\"参考所使用服务商CDN文档来设置用户来源IP\",\"且您应当修改系统设置中的 server.xff 值为 X-Forwarded-For,该设置是为了能够让系统正确获取到用户的IP地址。\"]}]},\"/docs/system/cli.html\":{\"title\":\"Hydro Cli\",\"contents\":[{\"header\":\"\",\"slug\":\"\",\"contents\":[\"Tips\",\"在使用 cli 之前,请完成数据库配置。 指令中使用 <> 括起来的参数必须给出,用 [] 括起来的参数可以给出,若不给出则按照默认设置。用户请根据自己的情况替换掉用 <> 或是 [] 包括起来的部分(括号也应替换)\",\"cli 可以帮助用户在控制台下快捷地进行一些操作。 这些命令需要以在终端以 root 用户执行(安装时执行命令的位置)。 下面给出了一些常用的例子。\"]},{\"header\":\"创建用户\",\"slug\":\"创建用户\",\"contents\":[\"Tips\",\"很少使用。建议通过 控制面板>导入用户 功能代替\",\"hydrooj cli user create # 该用户的邮箱、用户名和密码 # 如创建邮箱为 hydro@hydro.local,用户名为 Hydro,密码为 hydrohydro ,UID 为 2 的用户: # 请确保 UID 为不小于 2 的正整数且未被占用,邮箱和用户名均不重复。 hydrooj cli user create hydro@hydro.local Hydro hydrohydro 2 \",\"若一切正常,运行该指令后您会从命令行窗口中看到该用户 uid。\"]},{\"header\":\"设置全站管理员\",\"slug\":\"设置全站管理员\",\"contents\":[\"hydrooj cli user setSuperAdmin # 如设置 uid 为 2 的用户为管理员: hydrooj cli user setSuperAdmin 2 \"]},{\"header\":\"设置用户权限\",\"slug\":\"设置用户权限\",\"contents\":[\"hydrooj cli user setPriv \",\"关于参数 [priv] ,可阅读 此处。\"]},{\"header\":\"更改用户密码\",\"slug\":\"更改用户密码\",\"contents\":[\"hydrooj cli user setPassword # 如将 uid 为 1 的用户的密码改为 hydrohydro: hydrooj cli user setPassword 1 hydrohydro \"]},{\"header\":\"创建评测账号\",\"slug\":\"创建评测账号\",\"contents\":[\"先 创建一个账号。\",\"您需要留意运行此指令返回的数字,表示该用户的 uid,需要填入下面的指令中,然后给予该账号评测权限。\",\"hydrooj cli user setJudge \",\"完成后将配置的用户名及密码写入评测机配置文件,评测机即可连接到网页端。\"]},{\"header\":\"黑名单相关\",\"slug\":\"黑名单相关\",\"contents\":[\"用户封禁:\",\"hydrooj cli user setPriv 0 \",\"IP/邮箱域名封禁:\",\"# key 格式为 ip::xxx.xxx.xxx.xxx (封禁 IP 访问) 或是 mail::xxx.com (禁止 xxx.com 的邮箱注册) hydrooj cli blacklist add [duration] # 将 拉入黑名单,时长为 [duration] (以月为单位的整数,默认为 12,若 duration=0 则永久封禁) hydrooj cli blacklist get # 获取黑名单中有关 的信息 hydrooj cli blacklist del # 将 移出黑名单 \"]},{\"header\":\"命令列表\",\"slug\":\"命令列表\",\"contents\":[\"所有于 此文件夹 下的函数均可用 cli 调用。\",\"这里并没有列出所有可以运行的指令,因为其中很多功能我们更推荐通过 Web 访问。\",\"hydrooj cli user create [uid] [regip] [priv] # 创建邮箱为 ,用户名为 ,密码为 ,ID 为 [uid],注册 ip 为 [regip],权限为 [priv] 的用户 hydrooj cli user setUname # 将 ID 为 的用户的用户名设置为 hydrooj cli user setPriv # 将 ID 为 的用户的权限设为 hydrooj cli user setPassword # 将 ID 为 的用户的密码设置为 hydrooj cli user setEmail # 将 ID 为 的用户的邮箱设置为 hydrooj cli user setSuperAdmin # 将 ID 为 的用户设为全站管理员 hydrooj cli problem import # 将 的Hydro格式题目包导入至 域中 hydrooj cli problem export # 将 域中的所有题目包导出 hydrooj cli system set # 修改系统设置 值为 \"]}]},\"/docs/system/database.html\":{\"title\":\"数据库备份和恢复\",\"contents\":[{\"header\":\"进入数据库\",\"slug\":\"进入数据库\",\"contents\":[\"请参考 FAQS 内的数据库连接教程。\"]},{\"header\":\"快速备份与恢复\",\"slug\":\"快速备份与恢复\",\"contents\":[\"为了保证数据安全,请定期备份。\",\"若您使用自动脚本安装,可使用 hydrooj backup 快捷备份数据,备份完成后会在当前目录生成备份压缩包文件,您可使用 hydrooj restore <备份文件路径> 恢复之前备份的数据。\"]},{\"header\":\"手动备份\",\"slug\":\"手动备份\",\"contents\":[\"可使用 MongoDB 自带的 mongodump 进行数据库备份。并将 /data/file 文件夹备份即可。\",\"对于数据库,请请不要在数据库运行时直接拷贝数据库文件夹。请每次备份后检查生成的备份文件的大小和内容,确保备份成功。 请不要把备份数据和 Hydro 系统放在同一台机器上,这样数据丢失的风险仍然较高。\"]},{\"header\":\"手动恢复备份\",\"slug\":\"手动恢复备份\",\"contents\":[\"使用 MongoDB 自带的 mongorestore 导入备份的数据库文件,并还原 /data/file 目录文件。\\n如果只是想不同机器之间迁移部署,只需要在停止 Hydro 和 MongoDB 服务后将相关文件夹(通常为 /data/db 与 /data/file 与 /root/.hydro/config.json )复制即可。\"]}]},\"/docs/system/frontend-modify.html\":{\"title\":\"前端修改\",\"contents\":[{\"header\":\"\",\"slug\":\"\",\"contents\":[\"此指南将教您修改前端文件。\",\"如果您正在使用开发者模式,请直接修改 packages/ui-default/templates 下的文件。\",\"如果您使用安装脚本部署:\",\"请先使用 hydrooj addon create 创建一个本地插件(如果之前没有做过的话)。\"]},{\"header\":\"修改页面翻译或是添加新语言:\",\"slug\":\"修改页面翻译或是添加新语言\",\"contents\":[\"修改翻译:在 zh.yaml 内搜索您需要修改的翻译内容,并将 其所在行而非整个文件 修改后添加至 ~/addon/locales/zh.yaml 。\",\"添加语言:可参照 zh.yaml 格式创建一个新文件。欢迎社区参与多国化翻译工作。\"]},{\"header\":\"修改页面模板:\",\"slug\":\"修改页面模板\",\"contents\":[\"通常的,在您访问的 url 前加上 view-source:(如 view-source:https://hydro.ac 即可查看页面源代码,在第二行的 中 data-page 值即为页面名(首页例外,为 main.html)。 在 默认 templates 中找到对应文件,将文件的全部内容 复制到 ~/addon/templates/ 文件夹下后进行修改即可。\",\"特别的,创建题目时的默认模板位于 partials/problem_default.md,创建训练计划时的默认模板位于 partials/training_default.json,修改方式同上。\",\"以上所有更改均会在重启 Hydro 后生效。\"]}]},\"/docs/system/import-user.html\":{\"title\":\"导入用户\",\"contents\":[{\"header\":\"\",\"slug\":\"\",\"contents\":[\"目前支持 csv 格式(用 , 分隔)或 Excel 格式(用 TAB 分隔) 导入用户数据, 数据既可以用文本编辑器创建,也可以用 Excel 等软件来辅助创建。\",\"每行最少三列,最多五列,分别为: 邮箱,用户名,密码,显示名,用户信息。(显示名和用户信息为可选) 请使用 UTF-8 编码,否则中文可能会乱码。 如果使用 CSV 格式(逗号分隔),则用户信息列不可用。\",\"foo@undefined.moe user1 password1 bar@undefined.moe user2 password2 temp test@undefined.moe user3 password3 test {\\\"group\\\":\\\"class1\\\",\\\"studentId\\\":\\\"123\\\",\\\"school\\\":\\\"Hydro School\\\"} \",\"可以在粘贴后点击预览验证复制入的数据的有效性\",\"这将创建三个用户:\",\"user1 密码为 password1 , 邮箱 foo@undefined.moe;\",\"user2 密码为 password2 ,邮箱 bar@undefined.moe,显示名为 temp;\",\"user3 密码为 password3,邮箱 test@undefined.moe,显示名为 test,学校为 Hydro School,学号为 123,该用户将会被分配至当前域的 class1 小组内;\",\"Note\",\"用户创建后无法删除,请谨慎操作\"]}]},\"/docs/system/maintain.html\":{\"title\":\"维护\",\"contents\":[{\"header\":\"PM2\",\"slug\":\"pm2\",\"contents\":[\"使用一键安装脚本安装的 Hydro 使用 PM2 对进程进行管理。\"]},{\"header\":\"进程名称\",\"slug\":\"进程名称\",\"contents\":[\"可以通过下面的指令查看当前 PM2 正在管理的所有进程。\",\"pm2 ls \",\"一键安装脚本默认会创建下面几个进程:\",\"hydrooj: Hydro 主进程\",\"hydro-sandbox: Hydro 评测沙箱\",\"mongodb: MongoDB 数据库\",\"caddy: 反向代理\",\"后文的指令中将用 替代此处的进程名称,用 替代进程 ID(进程 ID 可通过 pm2 ls 查看)。(尖括号同样需要替换)\"]},{\"header\":\"PM2 基本指令\",\"slug\":\"pm2-基本指令\",\"contents\":[\"pm2 ls # 查看进程列表 pm2 start # 启动进程 pm2 stop # 关闭进程 pm2 restart # 重启进程 pm2 del # 删除进程 pm2 log --lines=100 # 查看该进程的后 100 行日志 pm2 attach # 与进程交互 pm2 save # 保存对 PM2 进行的修改(在添加、修改、删除进程后需要执行该指令) \",\"在部分环境(常见于 lxc 容器或是精简版系统)下,服务器重启后 Hydro 可能不能正常自启动,这时请使用 pm2 resurrect 手动载入进程列表。\",\"如果手动修改进程列表且已经覆盖掉保存的原列表,请使用 pm2 stop all && pm2 del all 清空所有进程之后重新运行安装脚本。原有数据不会丢失。\",\"Hydro 主进程同样支持多进程启动,但在中低端服务器(不超过4核)中没有必要使用多进程启动 Hydro,会降低性能且成倍提高内存占用。\",\"pm2 start hydrooj -i # 以 n 进程启动 Hydro 主进程 \"]},{\"header\":\"更新\",\"slug\":\"更新\",\"contents\":[\"Hydro 系统会不定期发布更新,可以使用下面的命令获取更新。\",\"无特殊情况请 不要更新PM2 !此操作可能导致进程列表丢失!\",\"yarn global upgrade-interactive --latest # 在交互式界面中选择想要更新的组件 pm2 restart hydrooj # 更新完后需重启 hydrooj \"]},{\"header\":\"查看已安装版本\",\"slug\":\"查看已安装版本\",\"contents\":[\"cd `yarn global dir` && yarn list --pattern hydrooj \"]},{\"header\":\"清除缓存\",\"slug\":\"清除缓存\",\"contents\":[\"yarn cache clean && nix-collect-garbage \"]}]},\"/docs/user/\":{\"title\":\"用户文档\",\"contents\":[{\"header\":\"题目难度\",\"slug\":\"题目难度\",\"contents\":[\"Hydro 中题目的难度,根据递交数、通过率以及每个递交的递交时间和评测结果,通过算法计算得出。\",\"一般地,难度的数值越大,该题目越难。\",\"新题目的难度可能不准确;在题目获得大量递交之后,难度才会变得较为准确。\",\"越早递交评测的用户代码的评测结果对题目难度影响越大。\",\"题目的难度由算法计算得出,有可能出现不准确的结果。\"]},{\"header\":\"参与比赛\",\"slug\":\"参与比赛\",\"contents\":[\"您可以在比赛的详细界面内点击“参与比赛”按钮进行参与。 比赛过程中“成绩表”会根据比赛规则显示排名。 在比赛截止之后,您仍然可以订正其中的题目,但“成绩表”将停止更新。\"]},{\"header\":\"发布讨论\",\"slug\":\"发布讨论\",\"contents\":[\"若您想发布一个讨论,请先进入一个讨论节点,之后点击“创建一个讨论”按钮并填写:\",\"标题;\",\"内容;\",\"是否高亮:若选择后,该贴的左边将有醒目的红色线条(需要“高亮讨论”权限);\",\"Pin:该讨论是否置顶(需要“置顶讨论”权限)。\",\"之后点击“创建”按钮进行发布。\"]},{\"header\":\"认领作业\",\"slug\":\"认领作业\",\"contents\":[\"您可以在作业的详情页面中,点击“认领作业”。\\n在作业开始之前,您无法查看作业中的题目。\\n在作业持续时间内,您与他人的做题情况会被实时统计在“成绩表”内。\\n在作业进入延期阶段后,您仍然可以提交题目,但成绩表内的分数将根据延期扣分规则按百分比折算。\\n在作业截止之后,您仍然可以订正其中的题目,但“成绩表”将停止更新。\"]}]},\"/docs/user/copy-problem.html\":{\"title\":\"复制题目\",\"contents\":[{\"header\":\"\",\"slug\":\"\",\"contents\":[\"复制题目可以帮助用户将任何有权提交的题目复制到有权创建题目的域中以在比赛/作业/训练计划中使用这些题目。\"]},{\"header\":\"操作流程\",\"slug\":\"操作流程\",\"contents\":[\"进入需要复制的题目页面或是题目列表页面。\",\"点击右侧栏底部的“复制”按钮或是多选题目后点击右侧复制题目按钮。\",\"在弹出的窗口中输入需要复制到的域的 ID。\",\"点击“确定”后将自动跳转到复制后的题目连接。\"]},{\"header\":\"限制\",\"slug\":\"限制\",\"contents\":[\"不允许查看/修改复制后的题目的测试数据。\",\"不能复制一个复制来的题目。\",\"部分题目可能不允许复制。这遵循 域设置>编辑域资料 中的管理员设定。\"]}]},\"/docs/user/domain.html\":{\"title\":\"域\",\"contents\":[{\"header\":\"简介\",\"slug\":\"简介\",\"contents\":[\"域功能类似团队,允许在一套系统中创建多个环境(如不同班级,或是不同功能,等等) 用户可以创建多个域。(需要用户有 PRIV_CREATE_DOMAIN 权限,默认仅开放给管理员账户)。 域间数据完全独立,仅用户信息相通(注册账户后,在该实例的所有域中均有效)。\"]},{\"header\":\"创建域\",\"slug\":\"创建域\",\"contents\":[\"登录账号后,在“我的”选项卡中找到“我的域”,并点击“创建域”,填入以下信息:\",\"ID: 每个域有一个唯一的 ID,将会在域 URL 中体现。创建后无法修改。\",\"名称: 域的名字,创建后可以更改。\",\"公告: 域主页上显示的公告,创建后可以更改。\",\"avatar: 域头像,与用户头像同理,可以使用 gravatar:email 或 qq:id 或 github:name 或 url:link 的格式添加。将会在“我的域”界面内显示。\",\"创建域后,您将在此域中拥有管理员权限,可以在域内进行添加题目/创建比赛等操作。\"]},{\"header\":\"初始化讨论节点\",\"slug\":\"初始化讨论节点\",\"contents\":[\"您可以在“管理域”选项卡中点击“初始化讨论节点”按钮初始化讨论节点。\"]},{\"header\":\"访问控制\",\"slug\":\"访问控制\",\"contents\":[\"未登录用户将默认使用 guest 权限,登录用户将默认使用 default 权限。(所以将登陆用户设为 default 权限后并不会显示在“管理用户”页内,这也表示所有用户默认不会出现在管理列表中) 所以将一个用户的权限设为 default 和将用户移出该域是等价的。\",\"对于不在列表中的用户,点击右上角“添加用户”,在左侧选中用户,右侧选择权限组,再点击“确定”即可。\"]},{\"header\":\"创建比赛/作业\",\"slug\":\"创建比赛-作业\",\"contents\":[\"若您想要创建比赛/作业,您可以在“比赛”或“作业”选项卡中,在页面右侧找到“创建”按钮, 题目一栏支持根据题目ID或是题目名自动筛选。设置完后可点击“创建”按钮创建比赛(描述这类的框不知道写啥就随便填,不能留空)。\",\"Tips\",\"若因为删除作业/比赛内题目导致无法打开,可以通过 /contest//edit 或 /homework//edit(即在无法打开的页面页面后加上 /edit)直接访问编辑页并修正。\"]},{\"header\":\"创建训练\",\"slug\":\"创建训练\",\"contents\":[\"若您想要创建训练,您可以在“训练” 项卡中点击“新建训练计划”,填写以下信息:\",\"标题:该训练的标题;\",\"简介:该训练的简介,会与标题同时显示在列表页面中;\",\"说明:该训练的详细信息;\",\"计划:该训练的具体题目及计划信息,其格式如下:\",\"[ {章节详细信息}, {章节详细信息}, ... {章节详细信息} ] \",\"其中,“章节详细信息”的包含以下部分:\",\"_id:章节数字编号;\",\"title:章节标题;\",\"requireNids:训练此章节之前需要完成的章节数字编号,若无要求则留空,若有多个则使用逗号分隔;\",\"pids:此章节中包含的题目的 ID,若有多个则使用逗号分隔。\",\"举例:若要在训练中创建三个章节,章节中分别有 ID 为 1,2,3 的题目。其中章节一、二无前置条件,章节三需要同时完成章节一、二后才能进行,则格式如下:\",\"[ { \\\"_id\\\": 1, \\\"title\\\": \\\"入门\\\", \\\"requireNids\\\": [], \\\"pids\\\": [1] }, { \\\"_id\\\": 2, \\\"title\\\": \\\"精通\\\", \\\"requireNids\\\": [], \\\"pids\\\": [2] }, { \\\"_id\\\": 3, \\\"title\\\": \\\"大师\\\", \\\"requireNids\\\": [1,2], \\\"pids\\\": [3] } ] \",\"Tips\",\"若因为删除训练计划内题目导致训练计划无法打开,可以通过 /training//edit(即训练计划页面后加上 /edit)直接访问训练计划编辑页并修正配置文件。\"]}]},\"/docs/user/problem-create.html\":{\"title\":\"Hydro常见题型的制做心得\",\"contents\":[{\"header\":\"\",\"slug\":\"\",\"contents\":[\"作者: laomai qq: 29985091 网址: http://82.157.98.222:8888/ 日期: 2022/03/16\",\"本文为作者使用hydro时的实验记录,希望对大家有帮助.包括如下内容\",\"零. hydro题目存储格式 一. 制做最简单的oj题 二. 含有自定义头文件的oj题,即函数交互式的题目 三. 半自动对拍的oj题,即不需要录入预期输出的题 四. 完全对拍题,即不需要录入输入数据和输出数据的题 五. 指定输入文件和输出文件 六. 多个子任务 七. 客观题,即制做有标准答案的填空和选择题.\"]},{\"header\":\"零. hydro题目存储格式\",\"slug\":\"零-hydro题目存储格式\",\"contents\":[\"如果想在本地建立好题目,然后批量上传的话. 下面的格式应该对你有帮助 每个题目应自占一个目录,目录名为题目编号比如1 ,2,3,4等等. 每个题目目录下一般有下面的元素:problem_zh.md 这个文件是就是题目的内容,即题目的描述,是一个markdown格式的文档.probelm.yaml 文件.这个是题目的配置信息. 比如标题和标签等。 testdata 子目录,对应网站里的测试数据部分里的文件, 里面至少有一个config.yaml文件 用来说明测试的类型.具体内容见后面的例子 如果题目有测试用例,则每个用例至少要提供一个in文件和一个输出文件(但有些测试类型不用,详情见后) additional_file子目录用来存放给做题者用的额外文件,比如头文件,图片,pdf文档等,在题目的 markdown 文档中可以用下面的格式为这些文件提供下载链接:[提示文字](file://xxx.txt)\",\"下面为手工录入各种题型的步骤,即在网站登录后点创建题目之后的操作.如下图所示 \",\"我们假定题目内容均为下面的markdown文档\",\"# 要求 输入两个整数,输出他们的和 # 样例 ```input1 123 500 ``` ```output1 623 ``` \"]},{\"header\":\"一 制做最简单的OJ题目\",\"slug\":\"一-制做最简单的oj题目\",\"contents\":[\"题目网址: http://82.157.98.222:8888/p/P10000\",\"新建题目之后编辑题目内容,输入题号和标题,然后点创建按钮。如下图所示.\",\"此时出现下面的图,点创建文件,文件名为 1.in, 表示用例 1 的输入\",\"编辑 1.in 的内容为两个整数比如 2 和 3 ,空格分开,如下图所示,然后点确定\",\"类似办法创建一个 1.out 文件,内容为 5 ,注意数字编号必须和 in 文件一致,创建之后的文件列表和下面类似.\",\"这样第一个用例的输入和预期输出就录入完毕,现在可以做本题了\",\"本题的 AC 代码为:\",\"#include using namespace std; int main(int argc,char* argv[]){ int a,b; cin>>a>>b; cout <<(a+b); return 0; } \"]},{\"header\":\"二、函数交互型题目\",\"slug\":\"二、函数交互型题目\",\"contents\":[\"题目网址: http://82.157.98.222:8888/p/P10001 本类型和类型一的区别在于出题者要向做题者提供一个额外的头文件,做题者的主函数里可以包含这个头文件以调用出题者提供的某些函数,或者实现头文件里指定的函数.\",\"题目内容的录入以及测试数据的录入和类型一样\",\"本题要额外上传两个文件.分别为 tools.h 和 config.yaml ,如下图所示\",\"tools.h 的内容为\",\"#include using namespace std; int add(int x,int y); //留待做题者实现 int main(int argc,char* argv[]){ int a,b; cin>>a>>b; cout << add(a,b); return 0; } \",\"这个头文件里实现了一个主函数,并且声明了需要做题者实现的函数add,当然,出题者应该在题目要求里写明这个函数的原型以及把tools.h文件上传到附加文件列表中,以方便做题者. 题面里可以用如下格式为用户提供下载链接,中括号内的内容可以自己写,[tools.h](file://tools.h) 如下面所示\",\"config.yaml文件的内容为\",\"type: default filename: null user_extra_files: - tools.h \",\"本题的ac代码为\",\"#include \\\"tools.h\\\" int add(int x,int y){ return x+y; } \",\"可见本类型的题目,做题者包含给定的头文件后,可以不需要自己实现主函数,只需要专心实现给定的函数即可.\"]},{\"header\":\"三,半对拍-自己指定评测程序并修改测试输出格式\",\"slug\":\"三-半对拍-自己指定评测程序并修改测试输出格式\",\"contents\":[\"例题网址:http://82.157.98.222:8888/p/P10002 本题型的特点是不需要手工给出每个用例的预期输出,但是要自己编写一个样本程序,测试时会把用户的输出和样本程序的输出进行对比。\",\"仍以两数求和为例\",\"题目内容和类型一类似\",\"测试数据部分只需要提供1.in\",\"编写一个样本程序 checker.cc,内容如下:\",\"#include \\\"testlib.h\\\" int main(int argc, char * argv[]) { registerTestlibCmd(argc, argv); int a = inf.readInt(); // 读取输入流的第一个整数 int b = inf.readInt(); // 读取输入流的下一个整数 int d = a+b; int c = ouf.readInt(); // 读取输出流的下一个整数 if (a+b != c) quitf(_wa, \\\"%d + %d expected %d, found %d\\\", a, b,d,c); //输出错误的具体信息,便于做题者调试 else quitf(_ok, \\\"answer of %d + %d is %d\\\",a,b,c); } \",\"config.yaml文件的内容如下:\",\"checker_type: testlib checker: checker.cc cases: - input: 1.in output: /dev/null # 无输出 \",\"最终的测试文件列表如下所示:\",\"当程序有错误时,输出的效果如下\",\"可见这里输出了错误细节,便于做题者调试\",\"本题的ac代码和类型一的一样,内容为\",\"#include using namespace std; int main(int argc,char* argv[]){ int a,b; cin>>a>>b; cout <<(a+b); return 0; } \",\"如果不希望自己录入输入数据,而是在每次测试时自动动态生成的话,可以将题目类型设为interactive,并提供一个对拍程序.仍以求和为例 例题网址: http://82.157.98.222:8888/p/P10005\",\"最后测试数据部分的文件列表如下图所示\",\"checker.cc,内容为:\",\"#include \\\"testlib.h\\\" #include using namespace std; int main(int argc, char* argv[]) { setName(\\\"Interactor A+B\\\"); registerInteraction(argc, argv); //自动生成两个随机整数 rnd.setSeed(time(NULL)); int a = rnd.next(1000); int b = rnd.next(1000); int d = a+b; // 本程序的输出将作为用户程序的输入 cout << a << \\\" \\\" << b << endl; int c; // 用户程序的最后输出将作为本程序的输入 cin >> c; //对比用户结果和预期结果 if (a+b != ans) quitf(_wa, \\\"%d + %d expected %d, found %d\\\", a, b,d,c); //输出错误的具体信息,便于做题者调试 else quitf(_ok, \\\"answer of %d + %d is %d\\\",a,b,c); } \",\"config.yaml 文件的内容为:\",\"type: interactive interactor: checker.cc cases: - input: /dev/null # no input and no output, dynamic generated output: /dev/null - input: /dev/null # no input and no output, dynamic generated output: /dev/null \",\"AC 代码和类型一中的相同\"]},{\"header\":\"五.文件读写测试\",\"slug\":\"五-文件读写测试\",\"contents\":[\"例题网址:http://82.157.98.222:8888/p/P10003 有时希望指定输入和输出文件,此时测试文件 1.in 和 1.out 和类型一类似, 但是要提供config.yaml文件,内容类似于下\",\"file: test \",\"则运行时测试环境会自动把每个输入文件复制到test.in中,输出内容和test.out的内容进行对比. ac的代码如下:\",\"#include using namespace std; int main(int argc,char* argv[]){ int a,b; ifstream ifs(\\\"test.in\\\"); ifs>>a>>b; ofstream ofs(\\\"test.out\\\"); ofs <<(a+b); return 0; } \"]},{\"header\":\"六,子任务测试.\",\"slug\":\"六-子任务测试\",\"contents\":[\"例题网址: https://hydro.ac/d/system_test/p/7\",\"提供好题目和各个子任务的输入、输出文件 建议文件名格式为 data-<数字> id为子任务编号\",\"config.yaml文件的内容参考如下\",\"time: 100ms memory: 8m subtasks: - score: 20 id: 0 cases: - input: data1-1.in output: data1-1.ans - input: data1-2.in output: data1-2.ans - input: data1-3.in output: data1-3.ans - input: data1-4.in output: data1-4.ans - input: data1-5.in output: data1-5.ans - score: 20 id: 1 cases: - input: data2-1.in output: data2-1.ans - input: data2-2.in output: data2-2.ans - input: data2-3.in output: data2-3.ans - input: data2-4.in output: data2-4.ans - input: data2-5.in output: data2-5.ans - score: 20 id: 2 cases: - input: data3-1.in output: data3-1.ans - input: data3-2.in output: data3-2.ans - input: data3-3.in output: data3-3.ans - input: data3-4.in output: data3-4.ans - input: data3-5.in output: data3-5.ans - score: 20 id: 3 if: [2] cases: - input: data4-1.in output: data4-1.ans - input: data4-2.in output: data4-2.ans - input: data4-3.in output: data4-3.ans - input: data4-4.in output: data4-4.ans - input: data4-5.in output: data4-5.ans - score: 20 id: 4 if: [1, 3] cases: - input: data5-1.in output: data5-1.ans - input: data5-2.in output: data5-2.ans - input: data5-3.in output: data5-3.ans - input: data5-4.in output: data5-4.ans - input: data5-5.in output: data5-5.ans \",\"可以看出if 用来指定前置子任务. 此外,如果某个子任务没有提供cases部分时,测试时会自动寻找类似于 data-x.in 和data-x.out 的文件,id为子任务编号 上面的例子故意设计为子任务编号和用例文件中的编号不同,所有每个子任务都需要手工指定对应的cases.\"]},{\"header\":\"七,客观题制做\",\"slug\":\"七-客观题制做\",\"contents\":[\"注意新版的客观题,格式已经更新。\",\"例题网址:http://82.157.98.222:8888/p/P10004 客观题只需要题面和config.yaml文件. 例子如下:\",\"1. 填空题 1+1 = {{ input(1) }} 2. 选择题 {{ select(2) }} - 1+1=2 - 1+1=3 - 1+1=4 3. 多选题 {{ multiselect(3) }} - A - B - C \",\"上传的 config.yaml 内容为\",\"type: objective # 表明该题为客观题 answers: # 列举出每一题的正确选项与对应的得分 '1': ['2', 50] '2': [['A', 'B'], 30] # 填空题支持多答案,满足其一得分 '3': [['A', 'B'], 20] # 多选题答案为数组,有部分分 \",\"题目运行效果如下:\",\"做完之后点提交,效果如下\",\"可见评分结果正确.\"]},{\"header\":\"八.小结\",\"slug\":\"八-小结\",\"contents\":[\"对所有编程题目,题面是必须录入的,如果指定了测试程序时,可以不需要录入输出数据. 如果设置测试方式为interactive,输入数据也不需要手工录入. 想指特殊的测试方式时,一般需要上传一个config.yaml文件,并设置对应字段的值. 对编程题,本文档中用到的字段有\",\"type字段一般为default, 对全自动对拍题,设为interactive\",\"checker_type: testlib checker: checker.cc 用来指定自定义的测试程序,即对拍程序\",\"filename: test用来指定对test.in文件和test.out文件进行读写.\",\"cases:\",\"input: 1.in\",\"用来指定测试用例.\",\"更详细的介绍见\\nhttps://hydro.js.org/docs/user/testdata/\"]}]},\"/docs/user/problem-format.html\":{\"title\":\"Hydro Problem Format\",\"contents\":[{\"header\":\"\",\"slug\":\"\",\"contents\":[\"为了便于系统间进行数据交换,Hydro 定义了一种基于 zip 的标准格式用于题目传输。压缩包内文件结构如下:\",\"喵? tree . ├── 任意文件名的文件夹 │ ├── problem.yaml │ ├── problem_zh.md │ ├── testdata │ │ ├── config.yaml │ │ ├── a1.in │ │ ├── a1.out │ │ ├── a2.in │ │ ├── a2.out │ │ ├── a3.in │ │ └── a3.out │ └── additional_file │ ├── a.png │ └── b.pdf └── ... \",\"其中 problem.yaml 内容如下:\",\"title: 题目名 tag: - 标签1 - 标签2 pid: 题号(字母+数字) \",\"problem_*.md 中为 markdown 格式的题面,语言代号支持完整形式(如 zh_CN),也支持短形式(如 zh)。若同时存在多个语言的题面,Hydro 将会自动识别并提供切换功能。\",\"testdata 文件夹中存放所有测试数据文件,命名规则和配置文件格式请参照【测试数据格式】章节。\",\"additional_file 中存储附加文件,通常用于存放图片,PDF 等文件。这些文件可以在题面中使用 file://文件名 的路径访问。\"]}]},\"/docs/user/problem.html\":{\"title\":\"题目\",\"contents\":[{\"header\":\"创建题目\",\"slug\":\"创建题目\",\"contents\":[\"拥有 PERM_CREATE_PROBLEM 的用户均可以新建题目。 请点击题库页面右下角的 创建题目 按钮。\",\"Tips\",\"题目 ID 不能全为数字。若留空则使用自动分配的数字题号。\",\"详见下方题面编辑部分,以及 laomai 编写的说明\"]},{\"header\":\"导入题目\",\"slug\":\"导入题目\",\"contents\":[]},{\"header\":\"从 Hydro 导入\",\"slug\":\"从-hydro-导入\",\"contents\":[\"上传 Hydro 导出的题目压缩包即可。\",\"如果您的压缩包较大无法上传我们也提供cli导入方法:\",\"hydrooj cli problem import # 将 的Hydro格式题目包导入至 域中。 \"]},{\"header\":\"从 SYZOJ 导入\",\"slug\":\"从-syzoj-导入\",\"contents\":[\"Hydro 提供了一个小工具 loj-download,可从基于原版 SYZOJ/SYZOJ-NG 搭建的源站下载到符合Hydro格式的题目压缩包。 工具使用方法请前往使用教程查看,自行摸索并确保在网络通畅的环境下使用。\"]},{\"header\":\"从 FPS 文件导入\",\"slug\":\"从-fps-文件导入\",\"contents\":[\"见插件 fps-importer。\"]},{\"header\":\"从 QDUOJ 导入\",\"slug\":\"从-qduoj-导入\",\"contents\":[\"见插件 import-qduoj。\"]},{\"header\":\"编辑\",\"slug\":\"编辑\",\"contents\":[]},{\"header\":\"题面\",\"slug\":\"题面\",\"contents\":[\"题面使用 Markdown 语法,并进行了部分扩展。\",\"支持对样例数据分组显示:\",\"```input1 1 2 ``` ```output1 3 ```\",\"后接的数字为测试点编号,将自动合并,并左右分栏显示。\",\"支持从附加文件引用资源。(您可以先创建题目,上传相关文件后再编辑该题目)\",\"附加文件下载链接: [file](file://input.in)\",\"从附加文件引用一张图片: ![img](file://foo.jpg)\",\"从附加文件引用 pdf 作为题面:@[pdf](file://foo.pdf) (部分情况下若无法使用,请尝试 @[pdf](file://foo.pdf?noDisposition=1) )\",\"从附加文件引用 word 文档作为题面: @[doc](file://foo.docx) (依赖 onlyoffice 插件)\",\"题面支持合并表格:\",\"| 1 | 1 | 3 | 4 | 5 | | --- | --- | --- | --- | --- | | 1 | 1 | 2 | 2 | 6 | | 1 | 1 | 2 | 2 | 7 | | 1 | 4 | 3 | 5 | 5 | \",\"将被渲染为:\",\"支持内嵌 HTML:(用来对付部分 Markdown 搞不定的东西)\",\"foo \"]},{\"header\":\"标签\",\"slug\":\"标签\",\"contents\":[\"可点击右侧分类面板快速添加标签,也可以用英文半角逗号分隔多个标签。\"]},{\"header\":\"文件\",\"slug\":\"文件\",\"contents\":[\"您可以在题目右侧“文件”面板上传测试数据和附加文件。(支持拖拽文件至相应位置进行上传)测试数据格式。\"]},{\"header\":\"客观题\",\"slug\":\"客观题\",\"contents\":[]},{\"header\":\"题面\",\"slug\":\"题面-1\",\"contents\":[\"1. 填空题 1+1 = {{ input(1) }} 2. 选择题 {{ select(2) }} - 1+1=2 - 1+1=3 - 1+1=4 3. 多选题 {{ multiselect(3) }} - A - B - C \"]},{\"header\":\"测试数据\",\"slug\":\"测试数据\",\"contents\":[\"仅需要配置 config.yaml 即可,不需要上传其他文件。\",\"type: objective # 表明该题为客观题 answers: # 列举出每一题的正确选项与对应的得分 '1': ['2', 50] # 填空题/选择题,单答案 '2': # 填空题/选择题,多答案,不同答案对应不同分数,注意空格缩进 'A': 30 # 也可以使用相同分数,即同时存在多个正确答案 'B': 10 '3': [['A', 'B'], 20] # 多选题答案为数组,有部分分 \"]}]},\"/docs/user/testdata.html\":{\"title\":\"测试数据格式\",\"contents\":[{\"header\":\"自动模式\",\"slug\":\"自动模式\",\"contents\":[\"Tips\",\"您可以直接选择文件(支持多选)上传或将文件拖拽至相应位置上传。 若上传文件为 zip 格式,将会自动进行解压操作。\",\"对于一般的题目,您只需提供 .in 和 .out/.ans 文件,以下是一个例子。 请务必确保文件名中含有数字。形如 sample.in 的文件是不会被自动识别的。\",\"喵? tree . ├── a1.in ├── a1.out ├── a2.in ├── a2.out ├── a3.in └── a3.out \",\"测试数据将被自动识别,并使用 1S 256MB 的限制。\"]},{\"header\":\"使用配置文件\",\"slug\":\"使用配置文件\",\"contents\":[\"Tips\",\"推荐您通过 评测设置 在线编辑题目配置,可以拥有更好的编辑体验。\",\"上传 config.yaml 文件即可,文件格式如下(下方所有样例均为可选项,若无说明则预填写的内容即为默认值):\",\"# 题目类型,可以为 default(比对输出,可以含spj), objective(客观题), interactive(交互题) type: default # 全局时空限制(此处的限制优先级低于测试点的限制) time: 1s memory: 128m # 输入输出文件名(例:使用 foo.in 和 foo.out),若使用标准 IO 删除此配置项即可 filename: foo # 此部分设置当题目类型为 default 时生效 # 比较器类型,支持的值有 default(直接比对,忽略行末空格和文件末换行), ccr, cena, hustoj, lemon, qduoj, syzoj, testlib(比较常用) checker_type: default # 比较器文件(当比较器类型不为 default 时填写) # 文件路径(位于压缩包中的路径) # 将通过扩展名识别语言,与编译命令处一致。在默认配置下,C++ 扩展名应为 .cc 而非 .cpp checker: chk.cc # 此部分设置当题目类型为interactive时生效 # 交互器路径(位于压缩包中的路径) interactor: interactor.cc # Extra files 额外文件 # These files will be copied to the working directory 这些文件将被复制到工作目录。 # 提示:您无需手动上传 testlib.h。 user_extra_files: - extra_input.txt judge_extra_files: - extra_file.txt # Test Cases 测试数据列表 # If neither CASES or SUBTASKS are set(or config.yaml doesn't exist), judge will try to locate them automaticly. # 如果 CASES 和 SUBTASKS 都没有设置或 config.yaml 不存在, 系统会自动尝试识别数据点。 # We support these names for auto mode: 自动识别支持以下命名方式: # 1. [name(optional)][number].(in/out/ans) RegExp: /^([a-zA-Z]*)([0-9]+).in$/ # examples: # - c1.in / c1.out # - 1.in / 1.out # - c1.in / c1.ans # 2. input[number].txt / output[number].txt RegExp: /^(input)([0-9]+).txt$/ # - example: input1.txt / input2.txt # # The CASES option has higher priority than the SUBTASKS option! # 在有 CASES 设置项时,不会读取 SUBTASKS 设置项! # # The CASES option has been deprecated in the new version, please use the more personalized SUBTASKS! # CASES 已于新版本中被废弃,请使用个性化程度更高的SUBTASKS! # score: 50 # 单个测试点分数 # time: 1s # 时间限制 # memory: 256m # 内存限制 # cases: # - input: abc.in # output: def.out # - input: ghi.in # output: jkl.out # 或使用Subtask项: subtasks: - score: 30 type: min # 可选 min/max/sum,分别表示取所有测试点最小值、所有测试点最大值、所有测试点之和 time: 1s memory: 64m cases: - time: 0.5s memory: 32m # 可对单个测试点单独设置时间限制和内存限制 input: a.in output: a.out - input: b.in output: b.out - score: 70 time: 0.5s memory: 32m if: [0] # 可选,传入数组,表示仅在subtask0通过时此subtask才计分 cases: - input: c.in output: c.out - input: d.in output: d.out # 提交语言限制 # 列举出所有本题允许使用的语言对应的代码(需要和评测机 lang.yaml 内的语言代码相同) # 使用语言ID而非名称!对于有子类的选项,请详细至子分类! langs: - c - cc - cc.cc11o2 - pas # 时间内存倍率 # 对某语言设置时间或内存倍率(需要和评测机 lang.yaml 内的语言代码相同) # 部分语言默认已存在倍率,请前往控制面板中查看! # 使用语言ID而非名称!对于有子类的选项,请详细至子分类! time_limit_rate: py.py3: 2 memory_limit_rate: java: 1.5 \",\"可以在 此题库 中找到各种类型题目的配置示例。\"]}]},\"/docs/system/\":{\"title\":\"System\",\"contents\":[]}}}");self.onmessage=({data:o})=>{self.postMessage($(o.query,m[o.routeLocale]))}; +//# sourceMappingURL=original.js.map diff --git a/sitemap.xml b/sitemap.xml new file mode 100644 index 00000000..b44cdf2e --- /dev/null +++ b/sitemap.xml @@ -0,0 +1,3 @@ + + +https://hydro.js.org/2023-05-19T14:49:26.000Zdailyhttps://hydro.js.org/FAQ/2023-02-25T05:29:05.000Zdailyhttps://hydro.js.org/api/2023-11-22T01:11:53.000Zdailyhttps://hydro.js.org/api/judge.html2023-11-23T03:00:48.000Zdailyhttps://hydro.js.org/dev/PERM_PRIV.html2022-12-09T10:31:58.000Zdailyhttps://hydro.js.org/dev/2023-06-06T04:14:26.000Zdailyhttps://hydro.js.org/dev/frontend-modify.html2021-08-13T04:13:21.000Zdailyhttps://hydro.js.org/dev/hook.html2023-05-19T14:49:26.000Zdailyhttps://hydro.js.org/dev/third-party-auth.html2023-12-26T15:11:04.000Zdailyhttps://hydro.js.org/dev/typescript.html2023-02-25T05:29:05.000Zdailyhttps://hydro.js.org/docs/2023-06-21T14:07:07.000Zdailyhttps://hydro.js.org/plugins/2023-05-12T03:18:30.000Zdailyhttps://hydro.js.org/plugins/elastic.html2023-05-12T03:18:30.000Zdailyhttps://hydro.js.org/plugins/fps-importer.html2022-12-09T10:31:58.000Zdailyhttps://hydro.js.org/plugins/geoip.html2023-02-25T05:29:05.000Zdailyhttps://hydro.js.org/plugins/hydrojudge.html2023-08-01T09:24:40.000Zdailyhttps://hydro.js.org/plugins/migrate.html2023-05-12T03:18:30.000Zdailyhttps://hydro.js.org/plugins/recaptcha.html2021-04-20T05:10:12.000Zdailyhttps://hydro.js.org/plugins/sonic.html2023-02-25T05:29:05.000Zdailyhttps://hydro.js.org/plugins/vjudge.html2023-05-12T03:18:30.000Zdailyhttps://hydro.js.org/docs/install/2023-11-30T07:45:11.000Zdailyhttps://hydro.js.org/docs/install/compiler.html2023-02-26T07:44:01.000Zdailyhttps://hydro.js.org/docs/install/proxy.html2023-08-23T08:55:42.000Zdailyhttps://hydro.js.org/docs/install/s3.html2023-05-12T03:32:53.000Zdailyhttps://hydro.js.org/docs/install/smtp.html2022-12-09T10:31:58.000Zdailyhttps://hydro.js.org/docs/system/FAQ.html2022-03-14T10:46:41.000Zdailyhttps://hydro.js.org/docs/system/cdn.html2023-05-17T15:15:27.000Zdailyhttps://hydro.js.org/docs/system/cli.html2023-05-12T03:18:30.000Zdailyhttps://hydro.js.org/docs/system/database.html2023-11-06T08:41:11.000Zdailyhttps://hydro.js.org/docs/system/frontend-modify.html2022-02-25T15:35:42.000Zdailyhttps://hydro.js.org/docs/system/import-user.html2022-12-29T09:30:13.000Zdailyhttps://hydro.js.org/docs/system/maintain.html2023-08-24T08:31:37.000Zdailyhttps://hydro.js.org/docs/user/2021-05-08T17:02:49.000Zdailyhttps://hydro.js.org/docs/user/copy-problem.html2022-02-25T15:35:42.000Zdailyhttps://hydro.js.org/docs/user/domain.html2023-03-20T01:53:27.000Zdailyhttps://hydro.js.org/docs/user/problem-create.html2022-11-08T15:43:33.000Zdailyhttps://hydro.js.org/docs/user/problem-format.html2023-05-19T14:49:26.000Zdailyhttps://hydro.js.org/docs/user/problem.html2023-05-12T03:18:30.000Zdailyhttps://hydro.js.org/docs/user/testdata.html2023-05-12T03:18:30.000Zdaily \ No newline at end of file diff --git a/sitemap.xsl b/sitemap.xsl new file mode 100644 index 00000000..8ad0f233 --- /dev/null +++ b/sitemap.xsl @@ -0,0 +1,152 @@ + + + + + + + XML Sitemap + + + + +

XML Sitemap

+
+ + + + + + + + + + + + + + + + + + + + + + +
URLs list
+ + PriorityChange FrequencyLast Updated Time
+ + + + + + + + + + + + + 0.5 + + + + + + + + + - + + + + +
+
+ + + +
+
diff --git a/twoslash.css b/twoslash.css new file mode 100644 index 00000000..5e64a0eb --- /dev/null +++ b/twoslash.css @@ -0,0 +1,336 @@ +pre { + position: relative; +} + +pre.shiki { + overflow-x: auto; +} + +pre.shiki:hover .dim { + opacity: 1; +} + +pre.shiki div.dim { + opacity: 0.5; +} + +pre.shiki div.dim, +pre.shiki div.highlight { + margin: 0; + padding: 0; +} + +pre.shiki div.highlight { + opacity: 1; + background-color: #f1f8ff; +} + +pre.shiki div.line { + min-height: 1rem; +} + +/** Don't show the language identifiers */ +pre.shiki .language-id { + display: none; +} + +/* Visually differentiates twoslash code samples */ +pre.twoslash { + border-color: #719af4; +} + +/** When you mouse over the pre, show the underlines */ +pre.twoslash:hover data-lsp { + border-color: #747474; +} + +/** The tooltip-like which provides the LSP response */ +pre.twoslash data-lsp::before { + content: attr(lsp); + position: absolute; + pointer-events: none; + transform: translate(0, 1rem); + + opacity: 0; + + background-color: #3f3f3f; + color: #fff; + max-width: 500px; + text-align: left; + padding: 5px 8px; + border-radius: 2px; + font-family: "JetBrains Mono", Menlo, Monaco, Consolas, Courier New, + monospace; + font-size: 14px; + white-space: normal; + z-index: 999; + + transition: opacity 0.1s ease; +} + +pre.twoslash data-lsp:hover::before { + opacity: 90%; +} + +/* Respect no animations */ +@media (prefers-reduced-motion: reduce) { + pre.twoslash data-lsp::before { + transition: none; + } +} + +pre .code-title { + display: none; +} + +/* The try button */ +pre .code-container > a { + position: absolute; + right: 8px; + bottom: 8px; + border-radius: 4px; + border: 1px solid #719af4; + padding: 0 8px; + color: #719af4; + text-decoration: none; + opacity: 0; + transition: opacity var(--t-color); +} + +/* Respect no animations */ +@media (prefers-reduced-motion: reduce) { + pre .code-container > a { + transition: none; + } +} + +pre .code-container > a:hover { + color: white; + background-color: #719af4; +} + +pre .code-container:hover a { + opacity: 1; +} + +pre code { + font-family: "JetBrains Mono", Menlo, Monaco, Consolas, Courier New, + monospace; + white-space: pre; + -webkit-overflow-scrolling: touch; +} + +pre code a { + text-decoration: none; +} + +pre data-err { + /* Extracted from VS Code */ + background: url("data:image/svg+xml,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%206%203'%20enable-background%3D'new%200%200%206%203'%20height%3D'3'%20width%3D'6'%3E%3Cg%20fill%3D'%23c94824'%3E%3Cpolygon%20points%3D'5.5%2C0%202.5%2C3%201.1%2C3%204.1%2C0'%2F%3E%3Cpolygon%20points%3D'4%2C0%206%2C2%206%2C0.6%205.4%2C0'%2F%3E%3Cpolygon%20points%3D'0%2C2%201%2C3%202.4%2C3%200%2C0.6'%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E") + repeat-x bottom left; + padding-bottom: 3px; +} + +pre .query { + margin-bottom: 10px; + color: #137998; + display: inline-block; +} + +/* In order to have the 'popped out' style design and to not break the layout + /* we need to place a fake and un-selectable copy of the error which _isn't_ broken out + /* behind the actual error message. + /* This sections keeps both of those two in in sync */ + +pre .error, +pre .error-behind { + margin-left: -14px; + margin-top: 8px; + margin-bottom: 4px; + padding: 6px; + padding-left: 14px; + width: calc(100% - 20px); + white-space: pre-wrap; + display: block; +} + +pre .error { + position: absolute; + background-color: #fee; + border-left: 2px solid #bf1818; + /* Give the space to the error code */ + display: flex; + align-items: center; + color: black; +} + +pre .error .code { + display: none; +} + +pre .error-behind { + user-select: none; + visibility: transparent; + color: #fee; +} + +/* Queries */ +pre .arrow { + /* Transparent background */ + background-color: #eee; + position: relative; + top: -7px; + margin-left: 0.1rem; + /* Edges */ + border-left: 1px solid #eee; + border-top: 1px solid #eee; + transform: translateY(25%) rotate(45deg); + /* Size */ + height: 8px; + width: 8px; +} + +pre .popover { + margin-bottom: 10px; + background-color: #eee; + display: inline-block; + padding: 0 0.5rem 0.3rem; + margin-top: 10px; + border-radius: 3px; +} + +/* Completion */ +pre .inline-completions ul.dropdown { + display: inline-block; + position: absolute; + width: 240px; + background-color: gainsboro; + color: grey; + padding-top: 4px; + font-family: var(--code-font); + font-size: 0.8rem; + margin: 0; + padding: 0; + border-left: 4px solid #4b9edd; +} + +pre .inline-completions ul.dropdown::before { + background-color: #4b9edd; + width: 2px; + position: absolute; + top: -1.2rem; + left: -3px; + content: " "; +} + +pre .inline-completions ul.dropdown li { + overflow-x: hidden; + padding-left: 4px; + margin-bottom: 4px; +} + +pre .inline-completions ul.dropdown li.deprecated { + text-decoration: line-through; +} + +pre .inline-completions ul.dropdown li span.result-found { + color: #4b9edd; +} + +pre .inline-completions ul.dropdown li span.result { + width: 500px; + color: black; + display: inline-block; +} + +.dark-theme .markdown pre { + background-color: #d8d8d8; + border-color: #ddd; + filter: invert(98%) hue-rotate(180deg); +} + +data-lsp { + /* Ensures there's no 1px jump when the hover happens */ + border-bottom: 1px dotted transparent; + /* Fades in unobtrusively */ + transition: border-color var(--t-color); +} + +/* Respect no animations */ +@media (prefers-reduced-motion: reduce) { + data-lsp { + transition: none; + } +} + +/** Annotations support, providing a tool for meta commentary */ +.tag-container { + position: relative; +} + +.tag-container .twoslash-annotation { + position: absolute; + font-family: "JetBrains Mono", Menlo, Monaco, Consolas, Courier New, + monospace; + right: -10px; + /** Default annotation text to 200px */ + width: 500px; + color: #187abf; + background-color: #fcf3d9 bb; +} + +.tag-container .twoslash-annotation p { + text-align: left; + font-size: 0.8rem; + line-height: 0.9rem; +} + +.tag-container .twoslash-annotation svg { + float: left; + margin-left: -44px; +} + +.tag-container .twoslash-annotation.left { + right: auto; + left: -200px; +} + +.tag-container .twoslash-annotation.left svg { + float: right; + margin-right: -5px; +} + +/** Support for showing console log/warn/errors inline */ +pre .logger { + display: flex; + align-items: center; + color: black; + padding: 6px; + padding-left: 8px; + width: calc(100% - 19px); + white-space: pre-wrap; +} + +pre .logger svg { + margin-right: 9px; +} + +pre .logger.error-log { + background-color: #fee; + border-left: 2px solid #bf1818; +} + +pre .logger.warn-log { + background-color: #ffe; + border-left: 2px solid #eae662; +} + +pre .logger.log-log { + background-color: #e9e9e9; + border-left: 2px solid #ababab; +} + +pre .logger.log-log svg { + margin-left: 6px; + margin-right: 9px; +} \ No newline at end of file