feat: add card rotation, customer lookup, and concurrent eligibility checks

Add encrypted card pool management, persisted card and outbound rotation, and per-card decline cooldowns. Improve customer and redemption-code lookup, recovery controls, and filtering; rebuild frontend assets and refresh mock screenshots.

Give read-only eligibility checks four independent slots so payment processing no longer blocks them. Cover concurrency, slot cleanup, card rotation, and lookup behavior with tests.
This commit is contained in:
mizorewww committed 2026-10-04 11:44:38 +08:00
1 parent 92f09423c3
commit 83ac3f00ae
47 files changed
+3033 -501

No files matched your search

+9 -5
View File
@@ -37,7 +37,7 @@ npm run preview
部署前请先准备好以下四样东西,配置向导会逐项询问:
1. **X 登录 Cookie**(`auth_token` 和 `ct0`):在浏览器登录 x.com 后,按 F12 打开开发者工具 → Application(应用)→ Cookies → `https://x.com`,复制这两项的值。这是系统以你的 X 账号身份发起赠送的凭据。
2. **一张用于付款的银行卡**:卡号、有效期、CVC,以及发卡行登记的持卡人姓名、账单邮箱和账单国家(两位代码,如 `BD`)。请只填真实信息。
2. **用于付款的银行卡(一张或多张)**:卡号、有效期、CVC,以及发卡行登记的持卡人姓名、账单邮箱和账单国家(两位代码,如 `BD`)。多张卡会在服务端加密保存并随机轮换,新卡可复用同一账单资料。请只填真实信息。
3. **代理(可选)**:服务器能直接访问 x.com 就选「直连」;否则准备一个代理节点。支持 sing-box 的任意 outbound 类型(anytls、socks、http、shadowsocks、vmess、vless、trojan 等),也可以直接粘贴完整 sing-box 配置。
4. **Stripe 公钥**:X 结账页面使用的 `pk_live_` 开头公钥。使用默认 X Premium 目录时向导会说明;它与商户、商品、价格一起保存在「目录」配置中,也可以完全自定义。
@@ -65,7 +65,7 @@ go build -tags with_quic,with_utls -o bin/xgift-web ./cmd/xgift-web
1. **密码文件** — 自动生成一个随机密码用于加密保管库,保存在你指定的路径(默认 `sqlite/vault-password`,仅本人可读)。**请务必备份这个文件,丢失后所有加密数据无法恢复。**
2. **X 凭据** — 粘贴第一步准备的两个 Cookie。
3. **支付卡** — 输入卡信息和账单信息(卡号会自动校验)。
3. **支付卡** — 输入卡信息和账单信息(卡号会自动校验)。想启用多卡轮换,向导完成后用 `xgift cards add` 追加更多卡,缺少的账单字段会自动继承。
4. **代理** — 选直连、按提示填 AnyTLS 节点,或粘贴 sing-box 配置;保存前会实际启动验证配置是否有效。
5. **Stripe 公钥** — 粘贴 `pk_live_` 公钥。
6. **商品目录** — 直接回车使用 X Premium 默认目录(3/6 个月套餐),或自定义商户、币种和套餐。
@@ -123,11 +123,15 @@ curl https://你的域名/healthz # {"ok":true,...} 即成功
更新配置用 `put`(从标准输入读取新值):
```sh
echo '新的ct0等JSON' | ./bin/xgift put --name cookies # 还有 card / proxy / api-auth
./bin/xgift cards list # 查看卡池和当前轮换组合(只显示尾号)
echo '{"number":"...","exp_month":"05","exp_year":"2031","cvc":"123"}' | ./bin/xgift cards add
echo '新的ct0等JSON' | ./bin/xgift put --name cookies # 还有 card / cards / proxy / api-auth
echo 'pk_live_新公钥' | ./bin/xgift put --name stripe-key
echo '{"merchant":"acct_...","currency":"bdt","plans":[...]}' | ./bin/xgift put --name catalog
```
付款卡按「卡 × 节点」组合随机轮换:每 3 个连续订单使用同一组合;任意订单被拒后立即换组合,被拒的那张卡进入 30 分钟冷却(其他卡继续轮换),补单也走同一逻辑。支付方明确 `do_not_try_again` 时该卡永久封锁直到显式解除。`cards add` 追加或更新(同卡号替换),`cards remove --last4 1234` 移除,`cards rotate` 立即结束当前组合,`cards unblock` 清除冷却与永久封锁。
## 常见问题
**密码文件丢了怎么办?** 无法恢复。加密数据全部作废,需要删除 `vault.db` 后重新运行 `xgift setup`。请把它和数据库一起备份。
@@ -136,7 +140,7 @@ echo '{"merchant":"acct_...","currency":"bdt","plans":[...]}' | ./bin/xgift put
**想暂停充值?** 把 `site.env` 里 `XGIFT_PAYMENTS_ENABLED` 改为 `false` 并重启服务。用户兑换会被婉拒,兑换码不消耗。
**付款被拒怎么办?** 明确拒付会显示失败说明并阻止重复提交,不再显示自动核实。网页和 CLI 在同一个 `checkout.lock` 下执行付款,提交间隔至少 30 秒,重启仍保留间隔。普通拒付只标记该订单失败,不因连续次数暂停全站;支付端明确返回 `do_not_try_again` 时保留停止重试保护。处理付款方式后,管理员可执行 `xgift resume-payments`(指定生产环境的 `--db` 和 `--password-file`)解除普通旧暂停(不能解除支付方明确禁止重试的暂停);该命令不付款,也不会修改 `XGIFT_PAYMENTS_ENABLED`。手动完成原账单后,可查询原订单以核对成功状态。
**付款被拒怎么办?** 明确拒付会显示失败说明并阻止重复提交,不再显示自动核实。网页和 CLI 在同一个 `checkout.lock` 下执行付款,提交间隔至少 30 秒,重启仍保留间隔。付款按「卡 × 节点」组合随机轮换,每 3 个连续订单使用同一组合;普通拒付会立即结束当前组合,被拒那张卡进入 30 分钟冷却(其他卡继续轮换,可用卡不足时自动回退),下一次提交(含补单)自动换到新的卡和节点,不因连续次数暂停全站。支付端明确返回 `do_not_try_again` 时只封锁被拒的那张卡;仅当所有卡都被永久封锁时才暂停全站,可用 `xgift cards unblock` 显式解除(不能通过补单确认框解除)。该命令不付款,也不会修改 `XGIFT_PAYMENTS_ENABLED`。手动完成原账单后,可查询原订单以核对成功状态。
**付款结果不明怎么办?** 系统宁可标记「待核实」也不会重复扣款。用户用原兑换码点「重新检查并继续兑换」即可自动核对,确认成功后自动补上状态。
@@ -150,7 +154,7 @@ echo '{"merchant":"acct_...","currency":"bdt","plans":[...]}' | ./bin/xgift put
### 管理员手动补单
登录 `/admin`,使用「预览并补单」查看所有 `review` 订单、每笔金额和当前默认卡尾号,勾选确认后点击「确认付款并启动补单」。此操作会发起真实付款,独立于公开充值入口的 `XGIFT_PAYMENTS_ENABLED` 开关;预览、状态查询、部署或服务重启均不会启动付款。预览有效期为 10 分钟,卡配置或订单内容发生变化时必须重新预览。
登录 `/admin`,使用「预览并补单」查看所有 `review` 订单、每笔金额和当前轮换卡尾号,勾选确认后点击「确认付款并启动补单」。补单与普通付款共用同一套卡 × 节点轮换逻辑:被拒订单会换到新组合,同一批次的后续订单继续沿用新组合。此操作会发起真实付款,独立于公开充值入口的 `XGIFT_PAYMENTS_ENABLED` 开关;预览、状态查询、部署或服务重启均不会启动付款。预览有效期为 10 分钟,卡池配置或订单内容发生变化时必须重新预览。
补单在服务器后台串行执行,订单之间至少等待 30 秒,并保留全局付款间隔。每批每单最多尝试一次;已付款只同步结果,未知付款结果、银行验证、禁止重试指令和不匹配的账单不会重付。有效会话会复用并重新核验商户、客户、套餐、金额及未收款/未授权金额证据。旧会话失效时,管理员必须确认已核对原订单未扣款;系统还要求原始明确拒付、对应的失败查询记录,以及再次通过的账号资格和价格检查,才会归档旧订单并生成新链接。未知付款结果、禁止重试指令不会因该确认而放行。每个原会话最多允许 3 次人工重试。普通拒付不再累计触发全站暂停;支付方明确禁止重试的暂停不能从此按钮解除。
+114 -28
View File
@@ -34,12 +34,13 @@ func run() error {
// Permit the requested `xgift username --pay` spelling as well as global flags.
args := os.Args[1:]
command := ""
sub := ""
rest := []string{}
for i := 0; i < len(args); i++ {
a := args[i]
if strings.HasPrefix(a, "-") {
rest = append(rest, a)
if a == "--db" || a == "--password-file" || a == "--profile" || a == "--port" || a == "--name" || a == "--months" {
if a == "--db" || a == "--password-file" || a == "--profile" || a == "--port" || a == "--name" || a == "--months" || a == "--last4" {
i++
if i >= len(args) {
return errors.New("missing flag value")
@@ -48,6 +49,8 @@ func run() error {
}
} else if command == "" {
command = a
} else if command == "cards" && sub == "" {
sub = a
} else {
return errors.New("unexpected argument")
}
@@ -67,12 +70,13 @@ func run() error {
profile := f.String("profile", "Default", "Chrome directory name")
port := f.Int("port", 0, "local proxy port; default automatic (proxy command: 18791)")
months := f.Int("months", 6, "gift duration in months; must match a plan in the catalog record")
last4 := f.String("last4", "", "card tail for cards remove")
retire := f.Bool("retire-canceled", false, "archive an inactive, canceled, unpaid order after read-only verification")
inspect := f.Bool("inspect", false, "read the existing Stripe order status without paying")
pay := f.Bool("pay", false, "pay only at the exact catalog plan total")
name := f.String("name", "", "secret name for put")
f.Usage = func() {
fmt.Fprintln(f.Output(), "Usage: xgift <setup|init|status|billing|import-chrome|put|proxy|check|check-payment-outbounds|resume-payments|username> [flags]\nsetup is the interactive first-time wizard; init reads a JSON object from stdin; put reads one JSON value from stdin (stripe-key: the raw pk_live_ key; catalog: merchant/plan catalog JSON; payment-outbounds: an outbound array). check-payment-outbounds probes public endpoints without paying.")
fmt.Fprintln(f.Output(), "Usage: xgift <setup|init|status|billing|cards|import-chrome|put|proxy|check|check-payment-outbounds|resume-payments|username> [flags]\nsetup is the interactive first-time wizard; init reads a JSON object from stdin; put reads one JSON value from stdin (stripe-key: the raw pk_live_ key; catalog: merchant/plan catalog JSON; payment-outbounds: an outbound array; cards: a card array). cards list|add|remove|unblock|rotate manages the encrypted payment card pool. check-payment-outbounds probes public endpoints without paying.")
f.PrintDefaults()
}
if err := f.Parse(rest); err != nil {
@@ -146,6 +150,8 @@ func run() error {
}
defer v.Close()
switch command {
case "cards":
return runCards(v, sub, *last4)
case "check-payment-outbounds":
failed := false
enc := json.NewEncoder(os.Stdout)
@@ -177,39 +183,18 @@ func run() error {
fmt.Println("Automatic payment pause cleared; payment spacing remains enforced.")
return nil
case "billing":
raw, e := v.Get("card")
if e != nil {
return e
}
defer clear(raw)
var c map[string]any
if e = json.Unmarshal(raw, &c); e != nil {
return e
}
var fields map[string]string
if e = json.NewDecoder(io.LimitReader(os.Stdin, 65536)).Decode(&fields); e != nil {
if e := json.NewDecoder(io.LimitReader(os.Stdin, 65536)).Decode(&fields); e != nil {
return errors.New("billing expects a JSON object on stdin")
}
for n, value := range fields {
switch n {
case "billing_name", "email", "billing_country", "billing_postal_code", "billing_address_line1", "billing_address_line2", "billing_city", "billing_state":
c[n] = value
default:
return errors.New("unsupported billing field")
}
}
raw, e = json.Marshal(c)
n, e := checkout.UpdateCardBilling(v, fields)
if e != nil {
return e
}
defer clear(raw)
if e = v.Put("card", raw); e != nil {
return e
}
fmt.Println("Billing information saved in encrypted SQLite")
fmt.Printf("Billing information saved in encrypted SQLite for %d card(s)\n", n)
return nil
case "status":
for _, n := range []string{"cookies", "card", "proxy"} {
for _, n := range []string{"cookies", "proxy"} {
b, e := v.Get(n)
if e != nil {
return fmt.Errorf("record %s is missing; run setup or put --name %s", n, n)
@@ -220,6 +205,20 @@ func run() error {
clear(b)
fmt.Printf("%s: encrypted record verified\n", n)
}
status, e := checkout.CardsStatus(v)
if e != nil {
return e
}
usable := 0
for _, card := range status {
if card.Usable {
usable++
}
}
if usable == 0 {
return checkout.ErrNoUsableCard
}
fmt.Printf("cards: %d encrypted record(s), %d usable\n", len(status), usable)
raw, e := v.Get("api-auth")
if e != nil {
return errors.New("record api-auth is missing; fix with put --name api-auth")
@@ -285,6 +284,18 @@ func run() error {
return errors.New("stdin must be valid JSON")
}
return v.Put(*name, b)
case "cards":
b, e := io.ReadAll(io.LimitReader(os.Stdin, 1024*1024))
if e != nil {
return e
}
defer clear(b)
n, e := checkout.SetCardRecords(v, b)
if e != nil {
return e
}
fmt.Printf("Card set replaced: %d validated cards\n", n)
return nil
case "stripe-key":
b, e := io.ReadAll(io.LimitReader(os.Stdin, 4096))
if e != nil {
@@ -307,7 +318,7 @@ func run() error {
}
return v.Put(*name, b)
default:
return errors.New("--name must be proxy, payment-outbounds, card, cookies, api-auth, stripe-key or catalog")
return errors.New("--name must be proxy, payment-outbounds, card, cards, cookies, api-auth, stripe-key or catalog")
}
}
if command != "proxy" && command != "check" && !regexp.MustCompile(`^@?[A-Za-z0-9_]{1,15}$`).MatchString(command) {
@@ -375,3 +386,78 @@ func run() error {
}
return e
}
func runCards(v *vault.Vault, sub, last4 string) error {
switch sub {
case "", "list":
status, err := checkout.CardsStatus(v)
if err != nil {
return err
}
rotation, err := checkout.PaymentRotationStatus(v)
if err != nil {
return err
}
fmt.Printf("卡池:%d 张(每 %d 个连续订单使用同一卡+节点组合;被拒后立即轮换)\n", rotation.Cards, rotation.BatchSize)
for i, s := range status {
line := fmt.Sprintf(" %d) 尾号 %s", i+1, s.Last4)
if s.Usable {
line += " 可用"
} else {
line += " 不可用:" + s.Problem
}
if s.Blocked != "" {
if s.CoolingSeconds > 0 {
line += fmt.Sprintf("(被拒冷却:%s,剩 %d 分钟)", s.Blocked, (s.CoolingSeconds+59)/60)
} else {
line += "(已封锁:" + s.Blocked + ")"
}
}
fmt.Println(line)
}
if rotation.CardLast4 == "" {
fmt.Println("当前轮换组合:未开始(下一笔付款时随机选择)")
} else {
node := rotation.Node
if node == "" {
node = "direct"
}
fmt.Printf("当前轮换组合:尾号 %s × %s(已用 %d/%d)\n", rotation.CardLast4, node, rotation.Used, rotation.BatchSize)
}
return nil
case "add":
b, err := io.ReadAll(io.LimitReader(os.Stdin, 1<<20))
if err != nil {
return err
}
defer clear(b)
total, err := checkout.AddCardRecords(v, b)
if err != nil {
return err
}
fmt.Printf("卡池已保存:共 %d 张。缺少的账单字段已从现有卡继承。\n", total)
return nil
case "remove":
remaining, err := checkout.RemoveCardRecord(v, last4)
if err != nil {
return err
}
fmt.Printf("已移除尾号 %s;卡池剩余 %d 张\n", last4, remaining)
return nil
case "unblock":
cleared, err := checkout.UnblockPaymentCards(v)
if err != nil {
return err
}
fmt.Printf("已解除 %d 张卡的封锁;若仍有可用卡,付款保护暂停已同步解除\n", cleared)
return nil
case "rotate":
if err := checkout.ResetPaymentRotation(v); err != nil {
return err
}
fmt.Println("已结束当前轮换批次;下一笔付款将随机选择新的卡+节点组合")
return nil
default:
return errors.New("cards expects list, add, remove --last4 XXXX, unblock or rotate")
}
}
+14 -3
View File
@@ -75,14 +75,25 @@ PY
包含 selector、urltest 等分组的订阅须先移除这些元素,仅保留独立代理节点。运行程序不自动拉取订阅,避免未经核验的订阅更新改变付款路径。
## 节点选择和订单绑定
## 卡池轮换、节点选择和订单绑定
付款卡保存在加密的 `cards` 数组(兼容旧的单张 `card` 记录),Stripe 付款按「卡 × 节点」组合随机轮换:
- 每 3 个连续付款订单使用同一组合(不按客户,按提交顺序)。第 4 个订单重新随机选择卡和可用节点;同一张卡不会连续被选为相邻组合(可用卡足够时)。
- 任一订单被银行拒付后,当前组合立即作废;下一次提交(包括管理员补单)自动换到另一张卡和一个可用节点。被拒的那张卡进入 30 分钟冷却,期间不再参与轮换;其他卡不够用时会自动回退重新启用。普通拒付不再因累计次数暂停全站,也不影响其他组合。
- 只有支付方明确返回 `do_not_try_again` 时才永久封锁对应那张卡;其余卡继续轮换,全部卡都被永久封锁才暂停全站,可用 `xgift cards unblock` 显式解除(同时清除拒绝冷却)。
- 旧单卡时代的已拒订单没有卡指纹记录,首次补单会按旧 `card` 记录给对应卡补上冷却,避免用旧卡反复重试。
- 补单与普通付款共用同一套轮换逻辑;已被拒订单不会重复使用原卡重试,而未提交付款的订单重复尝试会继续沿用已绑定的组合,不重复占用轮换名额。
- 卡池变化(增删卡)会形成新的集合指纹,自动重置支付保护状态和后台补单预览;仅轮换不会改变指纹。CLI 用 `xgift cards list|add|remove|unblock|rotate` 管理。
节点选择与旧版一致:
- 新绑定订单首次进入 Stripe 流程时,从未冷却的池内节点随机选择,`direct` 与代理均可参与。若有不同 `server` 的节点,会避开上一新订单的服务器;如果全部同服务器,则尽量避开上一节点。
- 一次批量补单中的不同客户分别选择。随机选择不保证各节点次数相等;不同协议节点也可能共享同一公网 IP。
- 选择发生在第一个 Stripe 请求前,所以“仅生成链接”中的 Stripe 核验也可能建立节点绑定。
- `stripe-route:<recipient_id>` 保存加密的节点配置快照、节点指纹和时间,正常情况下持续沿用。节点因连接故障进入冷却后,可原子归档到 `stripe-route-history:*` 并切换到可用出口。后台显示 `direct` 或 `node-` 加指纹前 12 位,完整凭据不返回网页。
- `stripe-route:<recipient_id>` 保存加密的节点配置快照、节点指纹、卡指纹和时间,正常情况下持续沿用。节点因连接故障进入冷却后,可原子归档到 `stripe-route-history:*` 并切换到可用出口;卡指纹保持不变。后台显示 `direct` 或 `node-` 加指纹前 12 位,完整凭据不返回网页。
- 以前没有节点绑定的待处理订单,在功能启用后首次访问 Stripe 时建立绑定。绑定不代表已付款。
- 明确银行卡拒付不会自动换节点重付。金额校验、幂等、付款间隔和支付方禁止重试指令继续生效;普通拒付不再因累计两次而触发全站暂停。
- 明确银行卡拒付不会在同一个组合上重复扣款。金额校验、幂等、付款间隔和支付方禁止重试指令继续生效。
## 网络重试与 6 小时冷却
Binary file not shown.

Before

Width:  |  Height:  |  Size: 215 KiB

After

Width:  |  Height:  |  Size: 238 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 214 KiB

After

Width:  |  Height:  |  Size: 238 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 93 KiB

+72 -2
View File
@@ -121,6 +121,49 @@ createServer(async (req, res) => {
return;
}
if (req.method !== "POST") {
if (req.method === "GET" && url.pathname === "/api/admin/recovery") {
json(200, {
batch: null,
network: { mode: "direct", nodes: 1 },
summary: {
review: codes.filter((code) => code.status === "review").length,
processing: codes.filter((code) => code.status === "processing")
.length,
},
});
return;
}
if (req.method === "GET" && url.pathname === "/api/admin/customer") {
const key = url.searchParams.get("id") || "";
const user = (url.searchParams.get("username") || "")
.replace(/^@/, "")
.toLowerCase();
const found = codes.find(
(code) =>
(key && code.id === key) || (user && code.username === user),
);
if (!found) {
json(404, { message: "没有找到对应的订单,请核对后重试。" });
return;
}
json(200, {
order: {
id: found.id,
username: found.username,
hint: found.hint,
months: found.months,
status: found.status,
message: found.message,
batch: found.batch,
},
code: plaintext.get(found.id) || "",
checkout_url: "",
previous_checkout_url: "",
can_recover: false,
replacement_count: 0,
});
return;
}
if (req.method === "GET" && url.pathname === "/api/admin/stats") {
const daily = [];
for (let offset = 29; offset >= 0; offset--) {
@@ -174,8 +217,11 @@ createServer(async (req, res) => {
}
}
const body = JSON.parse(raw);
if (
url.pathname === "/api/admin/folders" ||
if (url.pathname.startsWith("/api/admin/recovery/")) {
json(503, { message: "本地模拟预览不提供补单操作。" });
return;
}
if (url.pathname === "/api/admin/folders" ||
url.pathname === "/api/admin/folders/rename"
) {
const name = typeof body.name === "string" ? body.name.trim() : "";
@@ -304,6 +350,30 @@ createServer(async (req, res) => {
});
return;
}
if (url.pathname === "/api/admin/lookup") {
const full =
typeof body.code === "string" ? body.code.trim().toUpperCase() : "";
if (!/^XG-[A-F0-9]{48}$/.test(full)) {
json(400, { message: "请填写 XG- 开头、后接 48 位字符的完整兑换码。" });
return;
}
// Fixed demo hit so a found result can be previewed without generating.
if (full === "XG-" + "5".repeat(48)) {
json(200, { ...codes[2], progress: 100, updated: now });
return;
}
const entry = [...plaintext.entries()].find(
([, value]) => value === full,
);
const found = entry && codes.find((code) => code.id === entry[0]);
json(
found ? 200 : 404,
found
? { ...found, updated: found.created, progress: 0 }
: { message: "没有找到这个兑换码,请核对后重试。" },
);
return;
}
if (url.pathname === "/api/admin/codes/copy") {
const code = plaintext.get(body.id);
json(
+8 -1
View File
@@ -1,4 +1,4 @@
import { useState } from "react";
import { useEffect, useState } from "react";
import { Alert, Box, Button, Stack, Typography } from "@mui/material";
import ContentCopyRounded from "@mui/icons-material/ContentCopyRounded";
import CheckRounded from "@mui/icons-material/CheckRounded";
@@ -6,6 +6,12 @@ import CheckRounded from "@mui/icons-material/CheckRounded";
export function CopyableCodes({ codes }: { codes: string[] }) {
const [copied, setCopied] = useState<number | "all" | null>(null);
const [error, setError] = useState(false);
// The ✓ marks a recent copy; clear it so a later visit does not read as fresh.
useEffect(() => {
if (copied === null) return;
const timer = setTimeout(() => setCopied(null), 5000);
return () => clearTimeout(timer);
}, [copied]);
async function copy(index: number | "all") {
try {
await navigator.clipboard.writeText(
@@ -43,6 +49,7 @@ export function CopyableCodes({ codes }: { codes: string[] }) {
<Box
component="ul"
aria-label="新生成的兑换码"
tabIndex={0}
sx={{
m: 0,
p: 0,
+44 -27
View File
@@ -13,6 +13,8 @@ import {
Typography,
} from "@mui/material";
import { adminApi } from "./adminApi";
import { codeStatus } from "./codeStatus";
import PersonSearchRounded from "@mui/icons-material/PersonSearchRounded";
type Detail = {
order: {
@@ -81,9 +83,9 @@ export function CustomerPanel({
async function copy() {
try {
await navigator.clipboard.writeText(detail?.code || "");
setNotice("完整卡密已复制。");
setNotice("完整兑换码已复制。");
} catch {
setNotice("复制失败,请选中下方完整卡密手动复制。");
setNotice("复制失败,请选中下方完整兑换码手动复制。");
}
}
function prepare(mode: "links" | "pay") {
@@ -94,10 +96,22 @@ export function CustomerPanel({
}
return (
<>
<Paper variant="outlined" sx={{ p: { xs: 2, sm: 3 }, mb: 3 }}>
<Typography variant="h2" sx={{ fontSize: 21 }}>
按客户查卡密 / 单独补单
</Typography>
<Paper
variant="outlined"
component="section"
aria-labelledby="customer-panel-title"
sx={{ p: { xs: 2, sm: 3 }, height: "100%" }}
>
<Stack direction="row" spacing={1} alignItems="center">
<PersonSearchRounded color="primary" aria-hidden="true" />
<Typography
id="customer-panel-title"
variant="h2"
sx={{ fontSize: 21 }}
>
按客户查询
</Typography>
</Stack>
<Box
component="form"
onSubmit={(e) => {
@@ -115,6 +129,7 @@ export function CustomerPanel({
size="small"
fullWidth
autoComplete="off"
slotProps={{ htmlInput: { maxLength: 16, spellCheck: false } }}
/>
<Button
type="submit"
@@ -127,7 +142,7 @@ export function CustomerPanel({
</Stack>
</Box>
<Typography variant="body2" color="text.secondary" sx={{ mt: 1 }}>
直接查看客户对应的完整卡密和付款链接,无需按批次翻页。
直接查看客户对应的完整兑换码和付款链接,无需按批次翻页。
</Typography>
</Paper>
<Dialog
@@ -136,34 +151,35 @@ export function CustomerPanel({
fullWidth
maxWidth="sm"
aria-labelledby="customer-title"
aria-describedby="customer-dialog-description"
>
<DialogTitle id="customer-title">
{detail ? `@${detail.order.username} 的订单` : "客户订单详情"}
{detail
? detail.order.username
? `@${detail.order.username} 的订单`
: "兑换码详情"
: error
? "查询结果"
: "客户订单详情"}
</DialogTitle>
<DialogContent>
<DialogContent id="customer-dialog-description">
{busy && <Typography>正在读取订单…</Typography>}
{error && <Alert severity="error">{error}</Alert>}
{error && <Alert severity="error" role="alert">{error}</Alert>}
{detail && (
<Stack spacing={2}>
<Typography>
{detail.order.months} 个月 · {detail.order.batch || "未分类"} ·{" "}
{(
{
review: "待处理",
succeeded: "已完成",
processing: "处理中",
active: "未使用",
revoked: "已停用",
} as Record<string, string>
)[detail.order.status] || detail.order.status}
</Typography>
<Typography variant="body2" color="text.secondary">
{detail.order.message}
{codeStatus[detail.order.status]?.label || detail.order.status}
</Typography>
{detail.order.message && (
<Typography variant="body2" color="text.secondary">
{detail.order.message}
</Typography>
)}
{detail.code ? (
<>
<TextField
label="客户对应的完整卡密"
label="客户对应的完整兑换码"
multiline
value={detail.code}
slotProps={{ input: { readOnly: true } }}
@@ -175,15 +191,16 @@ export function CustomerPanel({
}}
/>
<Button variant="outlined" onClick={() => void copy()}>
复制完整卡密
复制完整兑换码
</Button>
</>
) : (
<Alert severity="info">
此历史卡密仅保存了校验值,无法还原。仍可按此客户订单单独补单。
此历史兑换码仅保存了校验值,无法还原完整内容。
{detail.can_recover && "仍可按此客户订单单独补单。"}
</Alert>
)}
{notice && <Alert severity="info">{notice}</Alert>}
{notice && <Alert severity="info" role="status">{notice}</Alert>}
{detail.checkout_url && (
<>
<TextField
@@ -210,7 +227,7 @@ export function CustomerPanel({
)}
{detail.can_recover && (
<Alert severity="info">
“仅生成链接”不会付款;“单独补单”会先展示这一笔订单,确认后才尝试付款。
「仅生成补单链接」不会付款;「单独补单」会先展示这一笔订单,确认后才尝试付款。
</Alert>
)}
</Stack>
+169
View File
@@ -0,0 +1,169 @@
import { useRef, useState } from "react";
import {
Alert,
Box,
Button,
CircularProgress,
InputAdornment,
Paper,
Stack,
TextField,
Typography,
} from "@mui/material";
import FactCheckRounded from "@mui/icons-material/FactCheckRounded";
import { request } from "./shared";
// Standalone eligibility probe next to the redemption card: a visitor can
// verify an X account before involving any redemption code. Advisory only.
export function EligibilityCard() {
const [username, setUsername] = useState("");
const [checking, setChecking] = useState(false);
const [invalid, setInvalid] = useState(false);
const [result, setResult] = useState<{
severity: "success" | "warning" | "info";
message: string;
} | null>(null);
const field = useRef<HTMLInputElement>(null);
const root = useRef<HTMLDivElement>(null);
const alertRef = useRef<HTMLDivElement>(null);
const cleanUser = username.trim().replace(/^@/, "").toLowerCase();
const userValid = /^[a-z0-9_]{1,15}$/.test(cleanUser);
async function run() {
setInvalid(!userValid);
if (!userValid || checking) {
if (!userValid) field.current?.focus();
return;
}
// 检测期间输入框与按钮禁用,焦点会跌落;完成后泊放到结果提示。
const refocus = root.current?.contains(document.activeElement) ?? false;
setChecking(true);
setResult(null);
try {
const { ok, data } = await request<{
eligible?: boolean;
message?: string;
}>("/api/check", { username: cleanUser }, AbortSignal.timeout(45000));
if (ok && typeof data.eligible === "boolean") {
setResult(
data.eligible
? { severity: "success", message: "该账号当前可以接收赠送。" }
: {
severity: "warning",
message: `该账号当前无法接收赠送:${data.message || "原因未知。"}`,
},
);
} else {
setResult({
severity: "info",
message: data.message || "暂时无法检测,请稍后再试。",
});
}
} catch {
setResult({ severity: "info", message: "暂时无法检测,请稍后再试。" });
} finally {
setChecking(false);
// 仅当焦点确已跌落 body 时泊放;用户等待期间移走焦点不抢夺。
if (refocus)
requestAnimationFrame(() => {
if (document.activeElement === document.body)
alertRef.current?.focus();
});
}
}
return (
<Paper
ref={root}
variant="outlined"
component="section"
aria-labelledby="eligibility-title"
sx={{
p: { xs: 2.5, sm: 4 },
borderRadius: "28px",
display: "flex",
flexDirection: "column",
}}
>
<Stack direction="row" spacing={1.5} alignItems="center" sx={{ mb: 1 }}>
<FactCheckRounded color="primary" aria-hidden="true" />
<Typography id="eligibility-title" component="h2" variant="h3">
检测赠送资格
</Typography>
</Stack>
<Typography variant="body2" color="text.secondary" sx={{ mb: 3 }}>
兑换前先确认 X 账号当前能否接收 Premium 赠送。检测不消耗兑换码。
</Typography>
<Stack
component="form"
spacing={2.5}
noValidate
sx={{ flexGrow: 1 }}
onSubmit={(event) => {
event.preventDefault();
void run();
}}
>
<TextField
label="X 用户名"
value={username}
onChange={(event) => {
setUsername(event.target.value);
setResult(null);
if (invalid) setInvalid(false);
}}
disabled={checking}
autoComplete="off"
placeholder="your_username"
error={invalid}
helperText={
invalid
? "请输入 1–15 位英文字母、数字或下划线,不是显示名称。"
: "填写 @ 后的用户名。"
}
slotProps={{
htmlInput: {
maxLength: 16,
spellCheck: false,
autoCapitalize: "none",
ref: field,
},
input: {
startAdornment: (
<InputAdornment position="start">@</InputAdornment>
),
},
}}
/>
<Button
type="submit"
variant="outlined"
size="large"
disabled={checking}
startIcon={
checking ? (
<CircularProgress size={18} aria-hidden="true" />
) : undefined
}
>
{checking ? "正在检测…" : "开始检测"}
</Button>
{result && (
<Alert
ref={alertRef}
tabIndex={-1}
severity={result.severity}
role="status"
aria-live="polite"
>
{result.message}
</Alert>
)}
<Box sx={{ flexGrow: 1 }} aria-hidden="true" />
<Typography variant="caption" color="text.secondary" component="p">
结果仅供参考,提交兑换时系统会向 X 再次核实。
</Typography>
</Stack>
</Paper>
);
}
+30 -28
View File
@@ -152,7 +152,7 @@ function conditionLabel(token: Extract<Token, { kind: "condition" }>): string {
const op = token.negate ? "≠" : ":";
switch (token.field) {
case "folder":
return token.value === "-"
return token.value === "-" && !token.literal
? `批次${op}未分类`
: `批次${op}${token.value}`;
case "status":
@@ -160,7 +160,7 @@ function conditionLabel(token: Extract<Token, { kind: "condition" }>): string {
case "months":
return `时长${op}${token.value} 个月`;
case "username":
return token.value === "-"
return token.value === "-" && !token.literal
? `账号${op}未绑定`
: `账号${op}${token.value}`;
}
@@ -183,8 +183,15 @@ function tokenLabel(token: Token): string {
}
}
function quoteValue(name: string) {
return /[\s()":=!≠]/.test(name) ? `"${name}"` : name;
function quoteValue(name: string, literal = false) {
// 批次名/账号可含任意字符;保留字、引号与反斜杠特殊处理,保证序列化结果
// 可被 tokenizer 还原。哨兵值 "-"(未分类/未绑定)保持裸写;仅当名称本身
// 就叫 "-" 时才加引号(literal,与 parse 的哨兵分支互逆)。
if (/^(and|or|not|非|&&|\|\|)$/i.test(name) || (name === "-" && literal))
return `"${name}"`;
return /[\s()":=!≠\\:()!="“”]/.test(name)
? `"${name.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/["“”]/g, "\\$&")}"`
: name;
}
function serializeTokens(tokens: Token[]): string {
@@ -196,8 +203,8 @@ function serializeTokens(tokens: Token[]): string {
case "condition": {
const op = token.negate ? "!=" : ":";
text =
token.field === "folder"
? `folder${op}${quoteValue(token.value)}`
token.field === "folder" || token.field === "username"
? `${token.field}${op}${quoteValue(token.value, token.literal)}`
: `${token.field}${op}${token.value}`;
break;
}
@@ -297,7 +304,10 @@ export function FilterBar({
}: Props) {
const [tokens, setTokens] = useState<Token[]>([]);
const [mode, setMode] = useState<"palette" | "text">("palette");
const [announce, setAnnounce] = useState("");
// seq 递增保证相同文案重复播报时 live region 仍会重建触发朗读。
const [announce, setAnnounce] = useState({ seq: 0, text: "" });
const speak = (text: string) =>
setAnnounce((current) => ({ seq: current.seq + 1, text }));
const [desyncWarning, setDesyncWarning] = useState("");
const [username, setUsername] = useState("");
const canvasRef = useRef<HTMLDivElement>(null);
@@ -312,7 +322,7 @@ export function FilterBar({
// 文本无法解析:恢复为调色板内容并提示,保证画布与表达式永不脱节。
const note = "无法解析文本表达式,已恢复为调色板中的条件。";
setDesyncWarning(note);
setAnnounce(note);
speak(note);
onChange(serializeTokens(tokens));
}
// tokens 刻意不作为依赖:只在 value / mode 变化时同步。
@@ -328,7 +338,7 @@ export function FilterBar({
useEffect(() => {
if (applySeq > lastApplySeq.current) {
lastApplySeq.current = applySeq;
setAnnounce(
speak(
resultCount == null
? "筛选已应用"
: `筛选已应用,共 ${resultCount} 条结果`,
@@ -340,14 +350,14 @@ export function FilterBar({
lastNoticeSeq.current = clearNotice.seq;
note = clearNotice.text;
}
setAnnounce(note);
speak(note);
}
wasApplied.current = applied;
}, [applied, applySeq, resultCount, clearNotice]);
function commit(next: Token[], note: string) {
setTokens(next);
setAnnounce(note);
speak(note);
setDesyncWarning("");
onChange(serializeTokens(next));
// 激活的调色板按钮可能在提交后被禁用,导致焦点跌回 <body>;
@@ -402,17 +412,6 @@ export function FilterBar({
commit(next, `已切换为 ${tokenLabel(updated)}`);
}
// 条件 chip:Enter/Space(与点击一致)切换 = / ≠。
function conditionChipKeyDown(index: number) {
return (event: KeyboardEvent) => {
if (disabled) return;
if (event.key === "Enter" || event.key === " ") {
event.preventDefault();
toggleNegate(index);
}
};
}
// 其他词元 chip 暴露 role="button",Enter/Space 与 Delete/Backspace 一样触发删除。
function chipKeyDown(index: number) {
return (event: KeyboardEvent) => {
@@ -493,7 +492,7 @@ export function FilterBar({
sx={{ mb: 0.5, flexWrap: "wrap", rowGap: 0.5 }}
>
<FilterAltOutlined color="primary" sx={{ flexShrink: 0 }} />
<Typography variant="h3" sx={{ whiteSpace: "nowrap", flexShrink: 0 }}>
<Typography variant="h2" sx={{ whiteSpace: "nowrap", flexShrink: 0, fontSize: 21 }}>
高级筛选
</Typography>
{applied && (
@@ -511,7 +510,6 @@ export function FilterBar({
variant="text"
size="small"
startIcon={mode === "palette" ? <CodeOutlined /> : <PaletteOutlined />}
aria-pressed={mode === "text"}
aria-label={
mode === "palette" ? "切换到文本模式" : "切换到调色板模式"
}
@@ -567,7 +565,7 @@ export function FilterBar({
event.preventDefault();
if (!applyDisabled) onApply();
// 表达式无效时 Enter 不再静默,播报当前不可应用的原因。
else if (invalidReason) setAnnounce(invalidReason);
else if (invalidReason) speak(invalidReason);
}
}}
sx={(theme) => ({
@@ -617,7 +615,6 @@ export function FilterBar({
aria-label={`${tokenLabel(token)},按 Enter 或点击切换 = / ≠,按 Delete 或 Backspace 删除`}
onClick={disabled ? undefined : () => toggleNegate(index)}
onDelete={disabled ? undefined : () => removeAt(index)}
onKeyDown={conditionChipKeyDown(index)}
sx={[
chipSizeSx,
conditionTint(tokenTone(token)),
@@ -727,6 +724,8 @@ export function FilterBar({
field: "folder",
value: folder.name,
negate: false,
// 批次名恰为哨兵值 "-" 时保持字法语义。
literal: folder.name === "-" ? true : undefined,
})
}
ariaLabel={`添加批次条件 ${folder.name}`}
@@ -805,7 +804,9 @@ export function FilterBar({
onKeyDown={(event) => {
if (event.key === "Enter") {
event.preventDefault();
addUsername();
if (username.trim() && !usernameValid)
speak("账号名需为字母、数字或下划线。");
else addUsername();
}
}}
slotProps={{
@@ -984,11 +985,12 @@ export function FilterBar({
</Stack>
<Box
component="span"
key={announce.seq}
role="status"
aria-live="polite"
sx={visuallyHidden}
>
{announce}
{announce.text}
</Box>
</Paper>
);
+11 -9
View File
@@ -22,17 +22,15 @@ type Props = {
stats?: AdminStats;
filter: string;
disabled: boolean;
muted?: boolean;
onSelect: (id: string) => void;
onBusyChange: (value: boolean) => void;
onChanged: (deleted?: string) => Promise<void>;
onChanged: () => Promise<void>;
};
export function FolderPanel({
folders,
stats,
filter,
disabled,
muted = false,
onSelect,
onBusyChange,
onChanged,
@@ -84,12 +82,10 @@ export function FolderPanel({
useFlexGap
gap={1}
sx={{
height: 80,
minHeight: 80,
overflowX: "auto",
alignItems: "center",
pb: 1,
opacity: muted ? 0.55 : 1,
transition: "opacity 160ms ease",
}}
role="region"
aria-label="批次文件夹,可横向滚动"
@@ -164,28 +160,34 @@ export function FolderPanel({
fullWidth
maxWidth="xs"
aria-labelledby="batch-rename-title"
aria-describedby="batch-rename-content"
>
<Box
component="form"
noValidate
onSubmit={(e) => {
e.preventDefault();
void save();
}}
>
<DialogTitle id="batch-rename-title">重命名批次</DialogTitle>
<DialogContent>
<DialogContent id="batch-rename-content">
<TextField
autoFocus
label="批次名称"
value={name}
onChange={(e) => setName(e.target.value)}
onChange={(e) => {
setName(e.target.value);
if (error) setError("");
}}
disabled={pending}
required
error={!!error}
sx={{ mt: 1 }}
helperText="该批次内的兑换码会同步更新名称"
/>
{error && (
<Alert severity="error" sx={{ mt: 2 }}>
<Alert severity="error" role="alert" sx={{ mt: 2 }}>
{error}
</Alert>
)}
+281
View File
@@ -0,0 +1,281 @@
import { useEffect, useRef, useState } from "react";
import {
Alert,
Box,
Button,
Chip,
CircularProgress,
Paper,
Stack,
TextField,
Typography,
} from "@mui/material";
import ManageSearchRounded from "@mui/icons-material/ManageSearchRounded";
import { adminApi, formatTime, type AdminCode } from "./adminApi";
import { codeStatus } from "./codeStatus";
// Direct lookup by full redemption code: status, batch and recipient without
// paging through folders. Actions delegate to the parent's existing flows.
export function LookupPanel({
disabled,
refreshSignal,
onCopy,
onViewCustomer,
onRevoke,
}: {
disabled: boolean;
refreshSignal: number;
onCopy: (code: AdminCode) => void;
onViewCustomer: (id: string) => void;
onRevoke: (code: AdminCode) => void;
}) {
const [input, setInput] = useState("");
const [busy, setBusy] = useState(false);
const [invalid, setInvalid] = useState(false);
const [error, setError] = useState("");
const [result, setResult] = useState<AdminCode | null>(null);
const queried = useRef("");
const sequence = useRef(0);
const field = useRef<HTMLInputElement>(null);
const clean = input.replace(/\s+/g, "").toUpperCase();
const valid = /^XG-[A-F0-9]{48}$/.test(clean);
async function run(code: string) {
const seq = ++sequence.current;
setBusy(true);
setError("");
try {
const data = await adminApi<AdminCode>("/api/admin/lookup", { code });
if (seq === sequence.current) {
setResult(data);
queried.current = code;
}
} catch (e) {
if (seq === sequence.current) {
setResult(null);
setError((e as Error).message);
}
} finally {
if (seq === sequence.current) setBusy(false);
}
}
function submit() {
setInvalid(!valid);
if (!valid || busy || disabled) {
if (!valid) field.current?.focus();
return;
}
void run(clean);
}
// Keep a visible result in sync after mutations (revoke, move, folder ops).
// Only while the shown result still matches the input: once the admin edits
// the field, the old result is gone and must not reappear.
useEffect(() => {
if (refreshSignal > 0 && result && queried.current === clean)
void run(queried.current);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [refreshSignal]);
const rows = result
? [
["接收账号", result.username ? `@${result.username}` : "—"],
["批次", result.batch || "未分类"],
[
"生成时间",
formatTime(result.created),
],
...(result.status === "processing" || result.status === "review"
? [["订单进度", `${Math.min(100, Math.max(0, result.progress ?? 0))}%`]]
: []),
]
: [];
return (
<Paper
variant="outlined"
component="section"
aria-labelledby="lookup-title"
sx={{ p: { xs: 2, sm: 3 }, height: "100%" }}
>
<Stack direction="row" spacing={1} alignItems="center">
<ManageSearchRounded color="primary" aria-hidden="true" />
<Typography id="lookup-title" variant="h2" sx={{ fontSize: 21 }}>
按兑换码查询
</Typography>
</Stack>
<Box
component="form"
noValidate
onSubmit={(event) => {
event.preventDefault();
submit();
}}
sx={{ mt: 2 }}
>
<Stack direction={{ xs: "column", sm: "row" }} spacing={1}>
<TextField
label="完整兑换码"
placeholder="XG-…"
value={input}
onChange={(event) => {
// 编辑即作废在途响应:旧结果不得在输入变化后重新出现。
sequence.current++;
setInput(event.target.value);
setResult(null);
setError("");
if (invalid) setInvalid(false);
}}
size="small"
fullWidth
autoComplete="off"
error={invalid}
helperText={
invalid
? "请输入 XG- 开头、后接 48 位十六进制字符(0-9、A-F)的完整兑换码。"
: " "
}
slotProps={{
htmlInput: { maxLength: 80, spellCheck: false, ref: field },
input: { sx: { fontFamily: "monospace", fontSize: 16 } },
}}
/>
<Button
type="submit"
variant="outlined"
disabled={busy || disabled || !input.trim()}
startIcon={
busy ? <CircularProgress size={16} aria-hidden="true" /> : undefined
}
sx={{ whiteSpace: "nowrap", alignSelf: { sm: "flex-start" } }}
>
{busy ? "正在查询…" : "查询兑换码"}
</Button>
</Stack>
</Box>
<Typography variant="body2" color="text.secondary">
粘贴客户提供的完整兑换码,直接查看状态、批次和接收账号,无需按批次翻页。
</Typography>
{error && (
<Alert severity="error" role="alert" sx={{ mt: 2 }}>
{error}
</Alert>
)}
<Box aria-live="polite">
{result && (
<Box
sx={{
mt: 2,
p: 2,
border: 1,
borderColor: "divider",
borderRadius: 2,
bgcolor: "background.default",
}}
>
<Stack
direction="row"
spacing={1}
alignItems="center"
flexWrap="wrap"
useFlexGap
>
<Chip
size="small"
variant="outlined"
color={codeStatus[result.status]?.color ?? "default"}
label={codeStatus[result.status]?.label ?? result.status}
/>
<Typography variant="body2" fontWeight={600}>
{result.months} 个月
</Typography>
<Typography
variant="body2"
color="text.secondary"
sx={{ fontFamily: "monospace" }}
>
尾号 …{result.hint}
</Typography>
</Stack>
<Box
component="dl"
sx={{
display: "grid",
gridTemplateColumns: "auto 1fr",
columnGap: 2,
rowGap: 0.5,
m: 0,
mt: 1.5,
}}
>
{rows.map(([label, value]) => (
<Box component="div" key={label} sx={{ display: "contents" }}>
<Typography
component="dt"
variant="body2"
color="text.secondary"
sx={{ whiteSpace: "nowrap" }}
>
{label}
</Typography>
<Typography
component="dd"
variant="body2"
sx={{ m: 0, overflowWrap: "anywhere" }}
>
{value}
</Typography>
</Box>
))}
</Box>
{result.message && (
<Typography
variant="body2"
color="text.secondary"
sx={{ mt: 1, overflowWrap: "anywhere" }}
>
{result.message}
</Typography>
)}
<Stack
direction="row"
spacing={1}
flexWrap="wrap"
useFlexGap
sx={{ mt: 1.5 }}
>
<Button
size="small"
variant="outlined"
disabled={disabled}
onClick={() => onViewCustomer(result.id)}
>
查看兑换码 / 补单
</Button>
{result.copyable && (
<Button
size="small"
variant="outlined"
disabled={disabled}
onClick={() => onCopy(result)}
>
复制完整兑换码
</Button>
)}
{result.status === "active" && (
<Button
size="small"
variant="outlined"
color="error"
disabled={disabled}
onClick={() => onRevoke(result)}
>
停用
</Button>
)}
</Stack>
</Box>
)}
</Box>
</Paper>
);
}
+32 -17
View File
@@ -24,7 +24,7 @@ import {
Typography,
} from "@mui/material";
import ExpandMoreRounded from "@mui/icons-material/ExpandMoreRounded";
import { adminApi } from "./adminApi";
import { adminApi, formatTime } from "./adminApi";
import type { RecoverySelection } from "./CustomerPanel";
type Item = {
@@ -47,6 +47,7 @@ type Batch = {
created: number;
updated?: number;
last4: string;
cards?: number;
paused: boolean;
message: string;
items: Item[];
@@ -83,13 +84,13 @@ function resultSummary(items: Item[]) {
return [`共 ${items.length} 笔`, ...parts.filter(([, n]) => n > 0).map(([label, n]) => `${label} ${n} 笔`)].join(" · ");
}
function taskTime(seconds?: number) {
return seconds ? new Date(seconds * 1000).toLocaleString("zh-CN", { hour12: false }) : "时间未记录";
return seconds ? formatTime(seconds) : "时间未记录";
}
function BatchDetails({ batch }: { batch: Batch }) {
return <>
<Stack direction="row" flexWrap="wrap" gap={1} alignItems="center">
<Chip size="small" label={labels[batch.state] || batch.state} />
<Typography variant="body2">{batch.mode === "links" ? "仅生成链接" : `付款卡尾号 ${batch.last4}`} · {resultSummary(batch.items)}</Typography>
<Typography variant="body2">{batch.mode === "links" ? "仅生成补单链接" : batch.cards && batch.cards > 1 ? `付款卡 ${batch.cards} 张随机轮换(当前尾号 ${batch.last4})` : `付款卡尾号 ${batch.last4}`} · {resultSummary(batch.items)}</Typography>
</Stack>
<Typography variant="caption" color="text.secondary" display="block" sx={{ mt: 1 }}>
创建于 {taskTime(batch.created)} · 更新于 {taskTime(batch.updated || batch.created)}
@@ -123,7 +124,7 @@ function Orders({ items }: { items: Item[] }) {
fontWeight={600}
sx={{ overflowWrap: "anywhere" }}
>
@{item.username} · 卡密尾号 {item.hint}
@{item.username} · 兑换码尾号 {item.hint}
</Typography>
{item.payment_node && (
<Typography variant="caption">付款节点 {item.payment_node}</Typography>
@@ -157,6 +158,9 @@ function Orders({ items }: { items: Item[] }) {
))}
</Stack>
<TableContainer
tabIndex={0}
role="region"
aria-label="补单订单清单,可滚动查看"
sx={{ maxHeight: 380, display: { xs: "none", sm: "block" } }}
>
<Table size="small" stickyHeader aria-label="补单订单清单">
@@ -173,7 +177,7 @@ function Orders({ items }: { items: Item[] }) {
<TableCell sx={{ verticalAlign: "top", minWidth: 140 }}>
<Typography variant="body2">@{item.username}</Typography>
<Typography variant="caption" display="block">
卡密尾号 {item.hint}
兑换码尾号 {item.hint}
{item.payment_node && ` · 付款节点 ${item.payment_node}`}
</Typography>
<Typography variant="caption" color="text.secondary">
@@ -232,6 +236,8 @@ export function RecoveryPanel({
const linksOnly = batch?.mode === "links";
const mutating = useRef(false);
const sequence = useRef(0);
// 上一个补单操作在途时到达的 selection 先暂存,完成后补发,避免"点了没反应"。
const pendingSelection = useRef<RecoverySelection | null>(null);
const active = batch?.state === "running" || batch?.state === "stopping";
const pending =
batch?.items.filter((item) => item.state === "pending").length || 0;
@@ -264,7 +270,10 @@ export function RecoveryPanel({
};
}, []);
useEffect(() => {
if (selection) void act("preview", selection);
if (selection) {
if (mutating.current) pendingSelection.current = selection;
else void act("preview", selection);
}
}, [selection]);
async function act(
action: "preview" | "start" | "stop",
@@ -303,6 +312,11 @@ export function RecoveryPanel({
mutating.current = false;
sequence.current++;
setBusy(false);
const queued = pendingSelection.current;
if (queued) {
pendingSelection.current = null;
void act("preview", queued);
}
}
}
return (
@@ -341,7 +355,7 @@ export function RecoveryPanel({
disabled={busy || active}
onClick={() => void act("preview", { mode: "links" })}
>
仅生成链接
仅生成补单链接
</Button>
<Button
variant="contained"
@@ -363,20 +377,20 @@ export function RecoveryPanel({
</Stack>
</Stack>
{error && !open && (
<Alert severity="error" sx={{ mt: 2 }}>
<Alert severity="error" role="alert" sx={{ mt: 2 }}>
{error}
</Alert>
)}
{statusError && <Alert severity="error" sx={{ mt: 2 }}>当前状态读取失败:{statusError}</Alert>}
<Box sx={{ mt: 2 }} aria-live="polite">
<Typography variant="body2" fontWeight={600}>
{statusError && <Alert severity="error" role="alert" sx={{ mt: 2 }}>当前状态读取失败:{statusError}</Alert>}
<Box sx={{ mt: 2 }}>
<Typography variant="body2" fontWeight={600} aria-live="polite">
{statusError ? "当前状态暂不可用" : active ? "当前有补单任务运行中" : summary ? "当前没有运行中的补单任务" : "正在读取当前状态…"}
</Typography>
{summary && <Typography variant="body2" color="text.secondary" sx={{ mt: 0.5 }}>
当前订单:待核实 {summary.review} 笔 · 充值处理中 {summary.processing} 笔
</Typography>}
</Box>
{batch && active && (
{batch && active && !statusError && (
<Box sx={{ mt: 2 }}>
<BatchDetails batch={batch} />
</Box>
@@ -393,7 +407,7 @@ export function RecoveryPanel({
</Typography>
</Box>
</AccordionSummary>
<AccordionDetails>
<AccordionDetails id="recovery-history-content">
<Typography variant="body2" color="text.secondary" sx={{ mb: 1.5 }}>
以下为这次任务保存的处理结果。当前订单数量显示在上方;刷新页面不会重新执行此任务。
</Typography>
@@ -417,13 +431,14 @@ export function RecoveryPanel({
},
}}
aria-labelledby="recovery-title"
aria-describedby="recovery-dialog-description"
>
<DialogTitle id="recovery-title">
{linksOnly ? "确认生成补单链接(不付款)" : "确认手动补单"}
</DialogTitle>
<DialogContent>
<DialogContent id="recovery-dialog-description">
{error && (
<Alert severity="error" sx={{ mb: 2 }}>
<Alert severity="error" role="alert" sx={{ mb: 2 }}>
{error}
</Alert>
)}
@@ -432,7 +447,7 @@ export function RecoveryPanel({
"只生成或更新付款链接,不提交银行卡付款;核验并处理"
) : (
<>
使用银行卡尾号 <strong>{batch?.last4}</strong>,核验并处理
{batch?.cards && batch.cards > 1 ? <>使用 <strong>{batch.cards}</strong> 张银行卡随机轮换(当前尾号 <strong>{batch?.last4}</strong>)</> : <>使用银行卡尾号 <strong>{batch?.last4}</strong></>},核验并处理
</>
)}{" "}
<strong>{pending}</strong> 笔订单,账单总额{" "}
@@ -478,7 +493,7 @@ export function RecoveryPanel({
}
label={
linksOnly
? "我已核对客户和套餐,确认仅生成链接,不付款。"
? "我已核对客户和套餐,确认仅生成补单链接,不付款。"
: "我已核对客户、套餐、账单金额和银行卡,确认启动本批次付款。"
}
/>
+15 -10
View File
@@ -18,10 +18,10 @@ import { stats as fetchStats, type AdminStatsDetail } from "./adminApi";
const visuallyHidden = {
position: "absolute",
width: 1,
height: 1,
width: "1px",
height: "1px",
p: 0,
m: -1,
m: "-1px",
overflow: "hidden",
clip: "rect(0 0 0 0)",
whiteSpace: "nowrap",
@@ -241,7 +241,8 @@ export function StatsPanel({ refreshSignal }: { refreshSignal: number }) {
1,
...(data?.review_stages ?? []).map((stage) => stage.count),
);
const remainder = theme.vars.palette.primary.light;
// Neutral track color that stays calm on dark surfaces (primary.light does not).
const remainder = theme.vars.palette.divider;
return (
<Paper variant="outlined" sx={{ mb: 3, overflow: "hidden" }}>
<Button
@@ -282,8 +283,12 @@ export function StatsPanel({ refreshSignal }: { refreshSignal: number }) {
aria-label="统计概览"
sx={{ px: { xs: 2.5, sm: 3 }, pb: 3, pt: 1 }}
>
{/* 折叠按钮内的标题是 span,补一个隐藏的 h2 让小节 h3 有父级。 */}
<Typography variant="h2" sx={visuallyHidden}>
统计概览
</Typography>
{loading && (
<Stack spacing={2} aria-label="正在加载统计数据">
<Stack spacing={2} role="status" aria-label="正在加载统计数据">
<Box
sx={{
display: "grid",
@@ -302,7 +307,7 @@ export function StatsPanel({ refreshSignal }: { refreshSignal: number }) {
</Stack>
)}
{!loading && error && (
<Alert severity="error">
<Alert severity="error" role="alert">
{error}
{data && " 以下保留上次加载的数据。"}
<Button onClick={() => void load()}>重新加载</Button>
@@ -336,9 +341,9 @@ export function StatsPanel({ refreshSignal }: { refreshSignal: number }) {
value={String(data.codes.succeeded)}
hint={`成功率 ${successRate}`}
/>
<StatCard label="待处理" value={String(data.codes.processing)} />
<StatCard label="待审核" value={String(data.codes.review)} />
<StatCard label="已撤销" value={String(data.codes.revoked)} />
<StatCard label="处理中" value={String(data.codes.processing)} />
<StatCard label="待核实" value={String(data.codes.review)} />
<StatCard label="已停用" value={String(data.codes.revoked)} />
</Box>
{data.daily.length > 0 && (
<Box component="section" aria-labelledby="stats-daily-title">
@@ -445,7 +450,7 @@ export function StatsPanel({ refreshSignal }: { refreshSignal: number }) {
{data.review_stages.length > 0 && (
<Box component="section" aria-labelledby="stats-stages-title">
<Typography id="stats-stages-title" variant="h3" sx={{ mb: 1.5 }}>
待审核阶段分布
待核实阶段分布
</Typography>
<Stack spacing={1.5}>
{[...data.review_stages]
+102 -62
View File
@@ -36,26 +36,23 @@ import ConfirmationNumberOutlined from "@mui/icons-material/ConfirmationNumberOu
import { mount, Shell } from "./shared";
import { AppearanceMenu } from "./AppearanceMenu";
import { CopyableCodes } from "./CopyableCodes";
import { adminApi as api, type AdminStats, type Folder } from "./adminApi";
import {
adminApi as api,
formatTime,
type AdminCode,
type AdminStats,
type Folder,
} from "./adminApi";
import { codeStatus as statuses } from "./codeStatus";
import { FolderPanel } from "./FolderPanel";
import { FilterBar } from "./FilterBar";
import { parseFilter } from "./filter";
import { CustomerPanel, type RecoverySelection } from "./CustomerPanel";
import { LookupPanel } from "./LookupPanel";
import { RecoveryPanel } from "./RecoveryPanel";
import { StatsPanel } from "./StatsPanel";
type Code = {
copyable: boolean;
folder: string;
id: string;
hint: string;
batch: string;
months: number;
status: string;
username: string;
message: string;
created: number;
};
type Code = AdminCode;
type Listing = {
folder: string;
folders: Folder[];
@@ -72,16 +69,6 @@ type Generated = {
folder: string;
};
type Confirmation = { kind: "revoke"; code: Code } | null;
const statuses: Record<
string,
{ label: string; color: "default" | "primary" | "success" | "warning" }
> = {
active: { label: "可使用", color: "primary" },
processing: { label: "处理中", color: "primary" },
succeeded: { label: "已完成", color: "success" },
review: { label: "待核实", color: "warning" },
revoked: { label: "已停用", color: "default" },
};
function Admin() {
const [customerSelection, setCustomerSelection] = useState<{
id: string;
@@ -97,6 +84,8 @@ function Admin() {
const [count, setCount] = useState("10");
const [batch, setBatch] = useState("");
const [copyNotice, setCopyNotice] = useState("");
// 连续复制时重置 Snackbar 的自动隐藏计时,避免第二条提示一闪而过。
const [copySeq, setCopySeq] = useState(0);
const copying = useRef(false);
const [selectedIDs, setSelectedIDs] = useState<string[]>([]);
const [moveOpen, setMoveOpen] = useState(false);
@@ -121,7 +110,7 @@ function Admin() {
const [confirmation, setConfirmation] = useState<Confirmation>(null);
const [batchError, setBatchError] = useState(false);
const [countError, setCountError] = useState(false);
const [focusTarget, setFocusTarget] = useState<"form" | "list" | null>(null);
const [focusTarget, setFocusTarget] = useState<"list" | null>(null);
const [statsSignal, setStatsSignal] = useState(0);
const listSequence = useRef(0);
const mutation = useRef(false);
@@ -131,6 +120,8 @@ function Admin() {
const refresh = useCallback(
async (page: number, folder = filterRef.current) => {
const sequence = ++listSequence.current;
// 跨页翻页保留选择;只有切换批次时才清空(筛选模式的进出单独管理)。
const switchingFolder = folder !== filterRef.current;
setLoading(true);
setListError("");
try {
@@ -140,7 +131,7 @@ function Admin() {
if (sequence === listSequence.current) {
setListing(data);
filterRef.current = data.folder;
setSelectedIDs([]);
if (switchingFolder) setSelectedIDs([]);
// The panel fetches on mount; only nudge it for later refreshes.
if (sequence > 1) setStatsSignal((value) => value + 1);
}
@@ -160,7 +151,7 @@ function Admin() {
// Filter mode: parse the expression, fetch every page client-side, then
// evaluate the predicate locally. Shares listSequence with refresh() so
// overlapping loads from either mode cancel each other.
const applyFilter = useCallback(async (source: string) => {
const applyFilter = useCallback(async (source: string, keepPage = false) => {
let match: (code: Code) => boolean;
try {
match = parseFilter(source);
@@ -185,7 +176,7 @@ function Admin() {
setAllCodes(codes);
setActiveFilter({ source, match });
setApplySeq((value) => value + 1);
setFilterPage(0);
if (!keepPage) setFilterPage(0);
setSelectedIDs([]);
} catch (error) {
if (sequence === listSequence.current)
@@ -202,12 +193,18 @@ function Admin() {
setFilterError("");
setFilterPage(0);
setSelectedIDs([]);
if (reload) void refresh(0);
if (reload) void refresh(0, "");
}
// After any mutation, reload the current view and keep stats/lookup panels
// in sync (applyFilter does not touch statsSignal on its own; refresh does).
function reloadCurrent() {
if (activeFilter) void applyFilter(activeFilter.source);
else void refresh(listing?.page ?? 0);
if (activeFilter) {
void applyFilter(activeFilter.source, true);
setStatsSignal((value) => value + 1);
} else {
void refresh(listing?.page ?? 0);
}
}
useEffect(() => {
@@ -215,7 +212,6 @@ function Admin() {
// Restore to a surviving control after the dialog's exit transition.
const timer = setTimeout(() => {
if (focusTarget === "list") refreshButton.current?.focus();
else form.current?.querySelector<HTMLElement>("[role=combobox]")?.focus();
setFocusTarget(null);
}, 250);
return () => clearTimeout(timer);
@@ -224,6 +220,7 @@ function Admin() {
async function copyRow(code: Code) {
if (!code.copyable) {
setCopyNotice("历史兑换码未保存完整内容,请使用原先下载的 TXT。");
setCopySeq((value) => value + 1);
return;
}
if (copying.current) return;
@@ -248,6 +245,7 @@ function Admin() {
} catch {
setCopyNotice("复制失败,请检查剪贴板权限或稍后重试。");
} finally {
setCopySeq((value) => value + 1);
copying.current = false;
}
}
@@ -290,6 +288,7 @@ function Admin() {
try {
await api("/api/admin/revoke", { id: confirmation.code.id });
setNotice({ text: "兑换码已停用。", error: false });
setSelectedIDs([]);
setFocusTarget("list");
setConfirmation(null);
reloadCurrent();
@@ -315,6 +314,7 @@ function Admin() {
text: `已移动 ${selectedIDs.length} 枚兑换码。`,
error: false,
});
setSelectedIDs([]);
setMoveOpen(false);
setFocusTarget("list");
reloadCurrent();
@@ -351,6 +351,8 @@ function Admin() {
const visibleCodes = matched
? matched.slice(safeFilterPage * 100, safeFilterPage * 100 + 100)
: (listing?.codes ?? []);
const pageIDs = visibleCodes.map((code) => code.id);
const pageSelected = pageIDs.filter((id) => selectedIDs.includes(id));
return (
<Shell admin>
@@ -387,12 +389,32 @@ function Admin() {
<AppearanceMenu />
</Stack>
</Stack>
<CustomerPanel
selected={customerSelection}
onPrepare={(id, mode) =>
setRecoverySelection({ id, mode, seq: Date.now() })
}
/>
<Box
sx={{
display: "grid",
gridTemplateColumns: {
xs: "1fr",
md: "minmax(0, 1fr) minmax(0, 1fr)",
},
gap: 3,
mb: 3,
alignItems: "stretch",
}}
>
<CustomerPanel
selected={customerSelection}
onPrepare={(id, mode) =>
setRecoverySelection({ id, mode, seq: Date.now() })
}
/>
<LookupPanel
disabled={busy || loading}
refreshSignal={statsSignal}
onCopy={(code) => void copyRow(code)}
onViewCustomer={(id) => setCustomerSelection({ id, seq: Date.now() })}
onRevoke={(code) => setConfirmation({ kind: "revoke", code })}
/>
</Box>
<RecoveryPanel selection={recoverySelection} />
<StatsPanel refreshSignal={statsSignal} />
<FolderPanel
@@ -400,7 +422,6 @@ function Admin() {
stats={listing?.stats}
filter={listing?.folder ?? ""}
disabled={busy || loading}
muted={!!activeFilter}
onSelect={(folder) => {
// Clicking a folder chip while the expression filter is active
// exits filter mode and returns to normal folder filtering.
@@ -425,8 +446,7 @@ function Admin() {
mutation.current = value;
setBusy(value);
}}
onChanged={async (deleted) => {
if (deleted === filterRef.current) filterRef.current = "";
onChanged={async () => {
if (activeFilter) reloadCurrent();
else await refresh(0);
}}
@@ -519,7 +539,10 @@ function Admin() {
type="number"
required
value={count}
onChange={(event) => setCount(event.target.value)}
onChange={(event) => {
setCount(event.target.value);
if (countError) setCountError(false);
}}
disabled={busy}
error={countError}
helperText={
@@ -531,7 +554,10 @@ function Admin() {
label="批次名称(可选)"
placeholder="例如:十月赠礼"
value={batch}
onChange={(event) => setBatch(event.target.value)}
onChange={(event) => {
setBatch(event.target.value);
if (batchError) setBatchError(false);
}}
disabled={busy}
error={batchError}
helperText={
@@ -556,6 +582,8 @@ function Admin() {
<Alert
severity={notice.error ? "error" : "success"}
role="status"
closeText="关闭"
onClose={notice.error ? undefined : () => setNotice(null)}
sx={{ mb: 3 }}
>
{notice.text}
@@ -637,7 +665,7 @@ function Admin() {
</Stack>
{loading && <LinearProgress aria-label="正在加载兑换码" />}
{listError && (
<Alert severity="error" sx={{ m: 2 }}>
<Alert severity="error" role="alert" sx={{ m: 2 }}>
{listError}
{(listing || allCodes) && " 以下保留上次加载的数据。"}
<Button onClick={() => reloadCurrent()}>重新加载</Button>
@@ -693,18 +721,17 @@ function Admin() {
busy || loading || !!listError || !visibleCodes.length
}
checked={
!!visibleCodes.length &&
selectedIDs.length === visibleCodes.length
!!pageIDs.length && pageSelected.length === pageIDs.length
}
indeterminate={
selectedIDs.length > 0 &&
selectedIDs.length < visibleCodes.length
pageSelected.length > 0 &&
pageSelected.length < pageIDs.length
}
onChange={(event) =>
setSelectedIDs(
setSelectedIDs((ids) =>
event.target.checked
? visibleCodes.map((code) => code.id)
: [],
? [...new Set([...ids, ...pageIDs])]
: ids.filter((id) => !pageIDs.includes(id)),
)
}
/>
@@ -806,14 +833,10 @@ function Admin() {
</TableCell>
<TableCell>
<Typography variant="body2" sx={{ whiteSpace: "nowrap" }}>
{new Date(code.created * 1000).toLocaleDateString(
"zh-CN",
)}
{formatTime(code.created).slice(0, 10)}
</Typography>
<Typography variant="caption" color="text.secondary">
{new Date(code.created * 1000).toLocaleTimeString(
"zh-CN",
)}
{formatTime(code.created).slice(11)}
</Typography>
</TableCell>
<TableCell onClick={(e) => e.stopPropagation()}>
@@ -825,8 +848,9 @@ function Admin() {
onClick={() =>
setCustomerSelection({ id: code.id, seq: Date.now() })
}
sx={{ whiteSpace: "nowrap", flexShrink: 0 }}
>
查看卡密 / 补单
查看兑换码 / 补单
</Button>
<Tooltip
describeChild
@@ -955,9 +979,16 @@ function Admin() {
) : (
<>
<Typography variant="body2" color="text.secondary">
{listing?.folder
? `第 ${listing.page + 1} 页`
: `共 ${listing?.stats.total ?? 0} 条 · 第 ${(listing?.page ?? 0) + 1} / ${Math.max(1, Math.ceil((listing?.stats.total ?? 0) / 100))} 页`}
{(() => {
const total = listing?.folder
? listing.folder === "unfiled"
? (listing?.stats.unfiled ?? 0)
: (listing?.folders.find(
(folder) => folder.id === listing.folder,
)?.count ?? 0)
: (listing?.stats.total ?? 0);
return `共 ${total} 条 · 第 ${(listing?.page ?? 0) + 1} / ${Math.max(1, Math.ceil(total / 100))} 页`;
})()}
</Typography>
<Stack direction="row" spacing={1}>
<Button
@@ -988,6 +1019,7 @@ function Admin() {
fullWidth
maxWidth="xs"
aria-labelledby="move-dialog-title"
aria-describedby="move-dialog-description"
>
<DialogTitle id="move-dialog-title">
移动 {selectedIDs.length} 枚兑换码
@@ -999,6 +1031,10 @@ function Admin() {
value={moveTarget}
disabled={busy}
onChange={(event) => setMoveTarget(event.target.value)}
slotProps={{
select: { displayEmpty: true },
inputLabel: { shrink: true },
}}
sx={{ mt: 1 }}
>
<MenuItem value="">未分类</MenuItem>
@@ -1012,7 +1048,7 @@ function Admin() {
</MenuItem>
))}
</TextField>
<DialogContentText sx={{ mt: 2 }}>
<DialogContentText id="move-dialog-description" sx={{ mt: 2 }}>
只修改归属分类,不改变兑换码、账号和订单状态。
</DialogContentText>
</DialogContent>
@@ -1035,13 +1071,15 @@ function Admin() {
onClose={() => {
if (!busy) setConfirmation(null);
}}
role="alertdialog"
aria-labelledby="admin-dialog-title"
aria-describedby="admin-dialog-description"
maxWidth="xs"
fullWidth
>
<DialogTitle id="admin-dialog-title">停用这枚兑换码?</DialogTitle>
<DialogContent>
<DialogContentText>
<DialogContentText id="admin-dialog-description">
{`尾号 ${confirmation?.code.hint ?? ""} 的兑换码将无法使用。此操作不可撤销。`}
</DialogContentText>
</DialogContent>
@@ -1064,10 +1102,12 @@ function Admin() {
</DialogActions>
</Dialog>
<Snackbar
key={copySeq}
open={!!copyNotice}
autoHideDuration={4000}
onClose={() => setCopyNotice("")}
message={copyNotice}
slotProps={{ content: { role: "status" } }}
/>
</Shell>
);
+20
View File
@@ -24,3 +24,23 @@ export type AdminStatsDetail = {
export function stats() {
return adminApi<AdminStatsDetail>("/api/admin/stats");
}
export type AdminCode = {
copyable: boolean;
folder: string;
id: string;
hint: string;
batch: string;
months: number;
status: string;
username: string;
message: string;
created: number;
updated?: number;
progress?: number;
};
// 全站统一的时间呈现:YYYY-MM-DD HH:mm:ss(与统计表日期风格一致)。
export function formatTime(seconds: number): string {
const d = new Date(seconds * 1000);
const p = (n: number) => String(n).padStart(2, "0");
return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}:${p(d.getSeconds())}`;
}
+92 -96
View File
@@ -6,7 +6,6 @@ import {
Alert,
Box,
Button,
CircularProgress,
Dialog,
DialogActions,
DialogContent,
@@ -26,11 +25,11 @@ import {
import ArrowForwardRounded from "@mui/icons-material/ArrowForwardRounded";
import ArrowOutwardRounded from "@mui/icons-material/ArrowOutwardRounded";
import ExpandMoreRounded from "@mui/icons-material/ExpandMoreRounded";
import FactCheckRounded from "@mui/icons-material/FactCheckRounded";
import ShieldOutlined from "@mui/icons-material/ShieldOutlined";
import HistoryRounded from "@mui/icons-material/HistoryRounded";
import { mount, request, Shell } from "./shared";
import { AppearanceMenu } from "./AppearanceMenu";
import { EligibilityCard } from "./EligibilityCard";
type Result = {
status?: string;
@@ -60,19 +59,18 @@ function App() {
const [locked, setLocked] = useState(false);
const [exhausted, setExhausted] = useState(false);
const [validation, setValidation] = useState(false);
const [checking, setChecking] = useState(false);
const [checkResult, setCheckResult] = useState<{
severity: "success" | "warning" | "info";
message: string;
} | null>(null);
// 本次会话的进度来自「兑换」还是「查询」,驱动进度区标题与区域命名。
const fromRedeem = useRef(false);
const timer = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);
const controller = useRef<AbortController | null>(null);
const inFlight = useRef(false);
const progressPanel = useRef<HTMLDivElement>(null);
const progressHeading = useRef<HTMLParagraphElement>(null);
const resultAlert = useRef<HTMLDivElement>(null);
const form = useRef<HTMLFormElement>(null);
const current = useRef<Input>({ code: "", username: "" });
const attempt = useRef(0);
const cleanCode = code.trim().toUpperCase();
const cleanCode = code.replace(/\s+/g, "").toUpperCase();
const cleanUser = username.trim().replace(/^@/, "").toLowerCase();
const codeValid = /^XG-[A-F0-9]{48}$/.test(cleanCode);
const userValid = /^[a-z0-9_]{1,15}$/.test(cleanUser);
@@ -126,6 +124,10 @@ function App() {
}
function apply(ok: boolean, data: Result) {
if (data.status === "paused") setService("paused");
// If focus sits in the progress panel and this update unmounts it
// (terminal states), hand focus to the result alert instead of <body>.
const refocus =
progressPanel.current?.contains(document.activeElement) ?? false;
setResult({
...data,
message:
@@ -141,9 +143,11 @@ function App() {
? "error"
: data.status === "succeeded"
? "success"
: data.status === "review" || data.status === "revoked"
? "warning"
: "info",
: data.status === "revoked"
? "error"
: data.status === "review"
? "warning"
: "info",
);
if (data.payment_declined) {
setProgress(null);
@@ -162,6 +166,11 @@ function App() {
setProgress(null);
if (ok && data.status === "active") setLocked(false);
}
if (refocus)
requestAnimationFrame(() => {
if (!progressPanel.current?.contains(document.activeElement))
resultAlert.current?.focus();
});
}
async function send(path: string) {
controller.current = new AbortController();
@@ -214,7 +223,7 @@ function App() {
}
return form.current!.reportValidity();
}
function start() {
function start(keepProgress = false) {
if (inFlight.current) return false;
clearTimeout(timer.current);
current.current = { code: cleanCode, username: cleanUser };
@@ -223,13 +232,18 @@ function App() {
setBusy(true);
setExhausted(false);
setSeverity("info");
setProgress(5);
// 继续查询保留已显示的进度,避免进度条倒退(apply 维持单调不降)。
if (!keepProgress) setProgress(5);
scroll();
// The submit/query buttons disable themselves; park focus on the progress
// heading so keyboard and screen-reader users are not dropped to <body>.
requestAnimationFrame(() => progressHeading.current?.focus());
return true;
}
async function redeem() {
setConfirmation(false);
if (service !== "enabled" || result?.payment_declined) return;
fromRedeem.current = true;
if (!start()) return;
setResult({ status: "processing", message: "正在核实 X 账号和赠送资格…" });
try {
@@ -252,53 +266,37 @@ function App() {
}
function edit(field: "code" | "username", value: string) {
if (field === "code") setCode(value);
else {
setUsername(value);
setCheckResult(null);
}
else setUsername(value);
// 与已提交的键值对比较(同一套清洗规则):只在真正变化时解锁并清空
// 结果;空白位置等外观编辑保留当前展示(锁定也继续生效)。
const differs =
field === "code"
? value.replace(/\s+/g, "").toUpperCase() !== current.current.code
: value.trim().replace(/^@/, "").toLowerCase() !==
current.current.username;
if (!differs) return;
if (locked) setLocked(false);
setResult(null);
setProgress(null);
setExhausted(false);
// A lost response stays query-only until the server returns a known state.
}
// Advisory only: the result never blocks or alters the redemption flow.
async function runCheck() {
if (checking || busy || !userValid) return;
setChecking(true);
setCheckResult(null);
try {
const { ok, data } = await request<{
eligible?: boolean;
message?: string;
}>("/api/check", { username: cleanUser }, AbortSignal.timeout(45000));
if (ok && typeof data.eligible === "boolean") {
setCheckResult(
data.eligible
? { severity: "success", message: "该账号当前可以接收赠送。" }
: {
severity: "warning",
message: `该账号当前无法接收赠送:${data.message || "原因未知。"}`,
},
);
} else {
setCheckResult({
severity: "info",
message: data.message || "暂时无法检测,请稍后再试。",
});
}
} catch {
setCheckResult({ severity: "info", message: "暂时无法检测,请稍后再试。" });
} finally {
setChecking(false);
}
}
return (
<Shell>
<Paper
variant="outlined"
sx={{ p: { xs: 2.5, sm: 4 }, borderRadius: "28px" }}
<Shell maxWidth="md">
<Box
sx={{
display: "grid",
gridTemplateColumns: {
xs: "1fr",
md: "minmax(0, 7fr) minmax(0, 5fr)",
},
gap: 3,
}}
>
<Paper
variant="outlined"
sx={{ p: { xs: 2.5, sm: 4 }, borderRadius: "28px" }}
>
<Stack
direction="row"
alignItems="center"
@@ -329,7 +327,7 @@ function App() {
ref={form}
onSubmit={(event) => {
event.preventDefault();
if (service === "enabled" && !result?.payment_declined && valid() && !locked && !busy)
if (service === "enabled" && !result?.payment_declined && result?.status !== "revoked" && valid() && !locked && !busy)
setConfirmation(true);
}}
noValidate
@@ -348,12 +346,13 @@ function App() {
error={validation && !codeValid}
helperText={
validation && !codeValid
? "请输入 XG- 开头、后接 48 位字母或数字的完整兑换码。"
? "请输入 XG- 开头、后接 48 位十六进制字符(0-9、A-F)的完整兑换码。"
: "请保留兑换码,后续查询仍需使用。"
}
slotProps={{
htmlInput: { maxLength: 80, spellCheck: false },
input: { sx: { fontFamily: "monospace", fontSize: 14 } },
input: { sx: { fontFamily: "monospace", fontSize: 16 } },
inputLabel: { shrink: true },
}}
/>
<TextField
@@ -383,44 +382,23 @@ function App() {
},
}}
/>
<Box>
<Button
variant="text"
size="small"
disabled={!userValid || busy || checking}
onClick={() => void runCheck()}
startIcon={
checking ? (
<CircularProgress size={16} aria-hidden="true" />
) : (
<FactCheckRounded />
)
}
>
{checking ? "正在检测…" : "检测可否接收赠送"}
</Button>
{checkResult && (
<Alert
severity={checkResult.severity}
role="status"
aria-live="polite"
sx={{ mt: 1 }}
>
{checkResult.message}
</Alert>
)}
</Box>
<Button
type="submit"
variant="contained"
size="large"
disabled={busy || locked || service !== "enabled" || result?.payment_declined}
disabled={busy || locked || service !== "enabled" || result?.payment_declined || result?.status === "revoked"}
endIcon={<ArrowForwardRounded />}
>
{service === "paused"
{service === "loading"
? "正在检查服务状态…"
: service === "unknown"
? "服务状态未知,请稍后再试"
: service === "paused"
? "充值已暂停"
: result?.payment_declined
? "付款被拒,请联系管理员"
: result?.status === "revoked"
? "兑换码已停用"
: busy
? "正在处理,请稍候"
: locked
@@ -435,6 +413,7 @@ function App() {
disabled={busy}
startIcon={<HistoryRounded />}
onClick={() => {
fromRedeem.current = false;
if (valid() && start()) {
setResult({ message: "正在查询原订单,不会再次扣款…" });
void query();
@@ -449,7 +428,7 @@ function App() {
{progress !== null && (
<Box
component="section"
aria-label="兑换进度"
aria-labelledby="progress-heading"
sx={{
mt: 3,
p: 2,
@@ -463,10 +442,16 @@ function App() {
spacing={1}
sx={{ mb: 1.5 }}
>
<Typography variant="body2" fontWeight={600}>
<Typography
ref={progressHeading}
id="progress-heading"
tabIndex={-1}
variant="body2"
fontWeight={600}
>
{result?.status === "succeeded"
? "兑换完成"
: busy
: fromRedeem.current
? "兑换进度"
: "原订单进度"}
</Typography>
@@ -477,7 +462,7 @@ function App() {
<LinearProgress
variant="determinate"
value={progress}
aria-label="兑换阶段进度"
aria-label="流程阶段进度"
color={result?.status === "succeeded" ? "success" : "primary"}
sx={{ height: 6, borderRadius: 3 }}
/>
@@ -510,12 +495,18 @@ function App() {
component="p"
sx={{ mt: 2 }}
>
百分比表示流程阶段,不是预计耗时。请勿重复提交。
{result?.status === "succeeded"
? "百分比表示流程阶段,不是预计耗时。请保留兑换码备查。"
: result?.status === "review"
? "百分比表示流程阶段,不是预计耗时。"
: "百分比表示流程阶段,不是预计耗时。请勿重复提交。"}
</Typography>
</Box>
)}
{result && (
<Alert
ref={resultAlert}
tabIndex={-1}
severity={severity}
role="status"
aria-live="polite"
@@ -532,7 +523,8 @@ function App() {
sx={{ mt: 2 }}
onClick={() => {
// Resume status polling only; never re-submits the redemption.
if (valid() && start()) {
fromRedeem.current = false;
if (valid() && start(true)) {
setResult({
status: result.status,
message: "正在继续查询原订单,不会再次扣款…",
@@ -546,9 +538,10 @@ function App() {
)}
{result?.status === "succeeded" && (
<Button
href="https://x.com/"
href="https://x.com/i/premium"
target="_blank"
rel="noopener noreferrer"
variant="contained"
endIcon={<ArrowOutwardRounded />}
fullWidth
sx={{ mt: 2 }}
@@ -566,6 +559,8 @@ function App() {
</Typography>
</Stack>
</Paper>
<EligibilityCard />
</Box>
<Box component="section" aria-labelledby="faq-title" sx={{ mt: 4 }}>
<Typography id="faq-title" variant="h3" component="h2" sx={{ mb: 1 }}>
常见问题
@@ -577,7 +572,7 @@ function App() {
],
[
"账号暂时无法接收赠送怎么办?",
"X 会根据账号情况决定是否允许接收 Premium 赠送。兑换前可先点击用户名旁的「检测可否接收赠送」确认当前资格。首次建单前资格未通过,兑换码不会使用;已有待核实订单时,请使用原兑换码和账号重新检查,符合条件且尚未付款时会继续兑换。",
"X 会根据账号情况决定是否允许接收 Premium 赠送。兑换前可先用本页的「检测赠送资格」确认账号当前状态。首次建单前资格未通过,兑换码不会使用;已有待核实订单时,请使用原兑换码和账号重新检查,符合条件且尚未付款时会继续兑换。",
],
[
"等待较久或关闭页面后,如何查询?",
@@ -602,7 +597,7 @@ function App() {
>
<Typography fontWeight={500}>{title}</Typography>
</AccordionSummary>
<AccordionDetails sx={{ px: 0, pb: 3 }}>
<AccordionDetails id={`faq-content-${index}`} sx={{ px: 0, pb: 3 }}>
<Typography variant="body2" color="text.secondary">
{text}
</Typography>
@@ -640,6 +635,7 @@ function App() {
open={confirmation}
onClose={() => setConfirmation(false)}
aria-labelledby="redeem-dialog-title"
aria-describedby="redeem-dialog-description"
fullWidth
maxWidth="xs"
>
@@ -649,7 +645,7 @@ function App() {
: "确认接收 Premium 的账号"}
</DialogTitle>
<DialogContent>
<DialogContentText>
<DialogContentText id="redeem-dialog-description">
接收账号为 <strong>@{cleanUser}</strong>。
{result?.status === "review"
? "将重新核对账号资格和原订单;符合条件且尚未付款时继续付款,已提交过付款的订单只核实结果。"
@@ -665,7 +661,7 @@ function App() {
disabled={service !== "enabled"}
onClick={() => void redeem()}
>
确认兑换
{result?.status === "review" ? "继续兑换" : "确认兑换"}
</Button>
</DialogActions>
</Dialog>
+10
View File
@@ -0,0 +1,10 @@
export const codeStatus: Record<
string,
{ label: string; color: "default" | "primary" | "success" | "warning" }
> = {
active: { label: "可使用", color: "primary" },
processing: { label: "处理中", color: "primary" },
succeeded: { label: "已完成", color: "success" },
review: { label: "待核实", color: "warning" },
revoked: { label: "已停用", color: "default" },
};
+86 -19
View File
@@ -31,13 +31,42 @@ type Token =
function tokenize(src: string): Token[] {
// 中文输入法容错:全角括号、冒号、引号、叹号、等号统一归一为半角。
src = src
.replace(/(/g, "(")
.replace(/)/g, ")")
.replace(/:/g, ":")
.replace(/!/g, "!")
.replace(/=/g, "=")
.replace(/["“”]/g, '"');
// 引号内的字面内容保持原样(批次名可能本身含全角标点)。
let normalized = "";
let inString = false;
let escaped = false;
for (const raw of src) {
if (inString) {
if (escaped) {
normalized += raw;
escaped = false;
continue;
}
if (raw === "\\") {
normalized += raw;
escaped = true;
continue;
}
// 未转义的全角引号在字符串内视为闭合(中文输入法自动配对场景);
// 名称字面的全角引号由 quoteValue 转义为 \” 绕过。
if (raw === '"' || /["“”]/.test(raw)) {
normalized += '"';
inString = false;
continue;
}
normalized += raw;
continue;
}
const char = /["“”]/.test(raw) ? '"' : raw;
if (char === '"') inString = true;
normalized += char
.replace(/(/g, "(")
.replace(/)/g, ")")
.replace(/:/g, ":")
.replace(/!/g, "!")
.replace(/=/g, "=");
}
src = normalized;
const tokens: Token[] = [];
let index = 0;
while (index < src.length) {
@@ -82,10 +111,22 @@ function tokenize(src: string): Token[] {
continue;
}
if (char === '"') {
const end = src.indexOf('"', index + 1);
if (end === -1)
throw new Error("引号不匹配:批次名称的英文双引号没有闭合。");
tokens.push({ kind: "string", text: src.slice(index + 1, end) });
// 支持 \" 与 \\ 转义,与 quoteValue 的序列化互逆。
let end = index + 1;
let text = "";
for (;;) {
if (end >= src.length)
throw new Error("引号不匹配:批次名称的英文双引号没有闭合。");
if (src[end] === "\\" && end + 1 < src.length) {
text += src[end + 1];
end += 2;
continue;
}
if (src[end] === '"') break;
text += src[end];
end++;
}
tokens.push({ kind: "string", text });
index = end + 1;
continue;
}
@@ -108,11 +149,13 @@ type Node =
| { type: "or"; left: Node; right: Node }
| { type: "and"; left: Node; right: Node }
| { type: "not"; operand: Node }
| { type: "condition"; field: Field; value: string; negate: boolean };
// literal: 值来自引号串,哨兵值("-")按字面名称处理。
| { type: "condition"; field: Field; value: string; negate: boolean; literal?: boolean };
// 调色板模式使用的扁平词元,按表达式中的出现顺序记录。
// condition.literal: 值来自引号串(序列化时保持引号,哨兵 "-" 按字面名称处理)。
export type ExpressionToken =
| { kind: "condition"; field: Field; value: string; negate: boolean }
| { kind: "condition"; field: Field; value: string; negate: boolean; literal?: boolean }
| { kind: "not" }
| { kind: "and" }
| { kind: "or" }
@@ -193,8 +236,16 @@ function parse(src: string): { root: Node; flat: ExpressionToken[] } {
throw new Error(`「${field.text}」后缺少 : 或 !=。`);
next();
const value = peek();
if (!value || (value.kind !== "word" && value.kind !== "string"))
if (!value || (value.kind !== "word" && value.kind !== "string")) {
if (
value &&
(value.kind === "and" || value.kind === "or" || value.kind === "not")
)
throw new Error(
`「${field.text}:」后遇到逻辑运算符;如果名称本身含 and / or / not / 非,请用英文引号包裹,如 ${field.text}:"非"。`,
);
throw new Error(`「${field.text}:」后缺少值。`);
}
next();
let normalized = value.text;
if (name === "status") {
@@ -214,14 +265,30 @@ function parse(src: string): { root: Node; flat: ExpressionToken[] } {
} else if (!value.text) {
throw new Error("「username:」后需要账号名;未绑定请使用 username:-。");
}
flat.push({ kind: "condition", field: name, value: normalized, negate });
return { type: "condition", field: name, value: normalized, negate };
flat.push({
kind: "condition",
field: name,
value: normalized,
negate,
literal: value.kind === "string",
});
return {
type: "condition",
field: name,
value: normalized,
negate,
literal: value.kind === "string",
};
}
const root = parseExpr();
if (position < tokens.length) {
const rest = tokens[position];
if (rest.kind === "rparen") throw new Error("括号不匹配:多余的右括号。");
if (rest.kind === "colon" || rest.kind === "eq" || rest.kind === "neq")
throw new Error(
'值中包含 : 或 = 等特殊字符;请用英文引号包裹名称,如 folder:"国庆:活动"。',
);
if (rest.kind === "lparen")
throw new Error("「(」前缺少逻辑运算符(and / or)。");
if (rest.kind === "word" || rest.kind === "string") {
@@ -259,7 +326,7 @@ export function parseFilter(src: string): (code: CodeRow) => boolean {
break;
case "folder":
matched =
node.value === "-"
node.value === "-" && !node.literal
? !code.batch
: code.batch.toLowerCase() === node.value.toLowerCase();
break;
@@ -268,7 +335,7 @@ export function parseFilter(src: string): (code: CodeRow) => boolean {
break;
case "username":
matched =
node.value === "-"
node.value === "-" && !node.literal
? !code.username
: (code.username ?? "").toLowerCase() ===
node.value.toLowerCase();
@@ -287,4 +354,4 @@ export function parseExpressionTokens(src: string): ExpressionToken[] {
}
export const FILTER_HINT =
"条件:folder:批次名、status:状态、months:时长、username:账号;逻辑:and、or、not、括号;!= 取反;folder:- 未分类、username:- 未绑定。";
"条件:folder:批次名、status:状态、months:时长、username:账号;逻辑:and、or、not、括号;!= 取反;folder:- 未分类、username:- 未绑定;名称含空格、冒号或保留字时用英文引号包裹,如 folder:\"and\"。";
+43 -11
View File
@@ -46,17 +46,21 @@ class ErrorBoundary extends Component<
return { failed: true };
}
render() {
if (this.state.failed)
if (this.state.failed) {
const admin = window.location.pathname.startsWith("/admin");
return (
<Container sx={{ py: 8 }}>
<Alert severity="error">
页面暂时无法显示。若已提交兑换,请保留兑换码,重新打开页面后查询原订单;不要重复兑换。
{admin
? "管理页暂时无法显示。进行中的兑换不受影响,请重新打开后继续核实。"
: "页面暂时无法显示。若已提交兑换,请保留兑换码,重新打开页面后查询原订单;不要重复兑换。"}
</Alert>
<Button href="/" sx={{ mt: 2 }}>
重新打开兑换页
<Button href={admin ? "/admin" : "/"} sx={{ mt: 2 }}>
{admin ? "重新打开管理页" : "重新打开兑换页"}
</Button>
</Container>
);
}
return this.props.children;
}
}
@@ -84,18 +88,45 @@ export function mount(node: ReactNode) {
export function Shell({
admin = false,
maxWidth,
children,
}: {
admin?: boolean;
maxWidth?: "xs" | "sm" | "md" | "lg";
children: ReactNode;
}) {
return (
<Container
id="main"
component="main"
maxWidth={admin ? "lg" : "sm"}
sx={{ py: { xs: 3, sm: 6 } }}
>
<>
<Link
href="#main"
sx={{
position: "absolute",
left: 16,
top: -64,
zIndex: (theme) => theme.zIndex.tooltip,
px: 2,
py: 1,
borderRadius: 1,
bgcolor: "background.paper",
color: "text.primary",
fontWeight: 600,
transition: "top 160ms ease",
"&:focus-visible": { top: 16 },
"@media (prefers-reduced-motion: reduce)": { transition: "none" },
}}
>
跳转到主要内容
</Link>
<Container
id="main"
component="main"
tabIndex={-1}
maxWidth={maxWidth ?? (admin ? "lg" : "sm")}
sx={{
py: { xs: 3, sm: 6 },
"&:focus-visible": { outline: "none" },
}}
>
{children}
<Box
component="footer"
@@ -144,6 +175,7 @@ export function Shell({
GitHub
</Link>
</Box>
</Container>
</Container>
</>
);
}
+648
View File
@@ -0,0 +1,648 @@
package checkout
import (
"crypto/sha256"
"database/sql"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"regexp"
"sort"
"strconv"
"strings"
"time"
"xgift/internal/vault"
)
// Cards are stored as an encrypted JSON array under "cards". A single legacy
// "card" record keeps working for vaults that never added another card.
const (
cardsRecord = "cards"
legacyCardKey = "card"
cardBlockRecord = "payment-card-blocks"
)
// paymentCardCooldown is how long a declined card stays out of rotation while
// other cards are available. A provider no-retry instruction blocks it until an
// operator explicitly unblocks it.
const paymentCardCooldown = 30 * time.Minute
var ErrNoUsableCard = errors.New("no usable payment card is available; every configured card may be blocked or cooling down")
var (
cardNumberPattern = regexp.MustCompile(`^[0-9]{12,19}$`)
cardMonthPattern = regexp.MustCompile(`^(0[1-9]|1[0-2])$`)
cardYearPattern = regexp.MustCompile(`^[0-9]{4}$`)
cardCVCPattern = regexp.MustCompile(`^[0-9]{3,4}$`)
cardCountry = regexp.MustCompile(`^[A-Z]{2}$`)
)
// validateCard is the structural and expiry check every payment card must pass.
func validateCard(c card) error {
if !cardNumberPattern.MatchString(c.Number) || !cardMonthPattern.MatchString(c.Month) || !cardYearPattern.MatchString(c.Year) || !cardCVCPattern.MatchString(c.CVC) || strings.TrimSpace(c.Name) == "" || !strings.Contains(c.Email, "@") {
return errors.New("card, cardholder name or email is incomplete")
}
sum := 0
for i, n := range c.Number {
d := int(n - '0')
if (len(c.Number)-i)%2 == 0 {
d *= 2
if d > 9 {
d -= 9
}
}
sum += d
}
if sum%10 != 0 {
return errors.New("card number checksum is invalid")
}
year, _ := strconv.Atoi(c.Year)
month, _ := strconv.Atoi(c.Month)
if !time.Now().Before(time.Date(year, time.Month(month)+1, 1, 0, 0, 0, 0, time.UTC)) {
return errors.New("card has expired")
}
if c.Country == "" {
return errors.New("Stripe requires a billing address; supply the card billing country and applicable address fields")
}
if !cardCountry.MatchString(c.Country) {
return errors.New("invalid supplied billing country")
}
return nil
}
// cardFingerprint identifies one card without ever exposing its number.
func cardFingerprint(c card) string {
sum := sha256.Sum256([]byte(c.Number + ":" + c.Month + ":" + c.Year))
return hex.EncodeToString(sum[:])
}
// cardSetFingerprint covers the whole configured set so a changed set resets
// circuit state and invalidates admin recovery previews, while rotation across
// the same set stays stable.
func cardSetFingerprint(cards []card) string {
parts := make([]string, 0, len(cards))
for _, c := range cards {
parts = append(parts, cardFingerprint(c))
}
sort.Strings(parts)
sum := sha256.Sum256([]byte(strings.Join(parts, "\n")))
return hex.EncodeToString(sum[:])
}
func cardTail(c card) string {
if len(c.Number) < 4 {
return "****"
}
return c.Number[len(c.Number)-4:]
}
// readCards prefers the multi-card record and falls back to the legacy single
// card so existing vaults keep paying without a migration step.
func readCards(v *vault.Vault) ([]card, error) {
raw, err := v.Get(cardsRecord)
if err == nil {
defer clear(raw)
var cards []card
if json.Unmarshal(raw, &cards) != nil || len(cards) == 0 {
return nil, errors.New("invalid card set record")
}
return cards, nil
}
if !errors.Is(err, sql.ErrNoRows) {
return nil, err
}
raw, err = v.Get(legacyCardKey)
if err != nil {
return nil, err
}
defer clear(raw)
var c card
if json.Unmarshal(raw, &c) != nil {
return nil, errors.New("invalid card record")
}
return []card{c}, nil
}
// readCard keeps the legacy single-card helper working: it returns the first
// card of the configured set, fully validated.
func readCard(v *vault.Vault) (card, error) {
cards, err := readCards(v)
if err != nil {
return card{}, err
}
c := cards[0]
if err = validateCard(c); err != nil {
return c, err
}
return c, nil
}
// legacyCardFingerprint was used while the historic single card was assumed to
// be the one that declined old orders; multi-card rotation now tracks real
// decline evidence instead.
// readCardsOptional behaves like readCards but reports an unconfigured card
// set as empty, which lets `cards add` create the first record.
func readCardsOptional(v *vault.Vault) ([]card, error) {
cards, err := readCards(v)
if errors.Is(err, sql.ErrNoRows) {
return nil, nil
}
return cards, err
}
func usableCards(cards []card) []card {
usable := make([]card, 0, len(cards))
for _, c := range cards {
if validateCard(c) == nil {
usable = append(usable, c)
}
}
return usable
}
func cardByFingerprint(cards []card, fingerprint string) (card, bool) {
for _, c := range cards {
if cardFingerprint(c) == fingerprint {
return c, true
}
}
return card{}, false
}
type cardBlock struct {
Reason string `json:"reason"`
BlockedAt int64 `json:"blocked_at"`
Until int64 `json:"until,omitempty"`
}
func readCardBlocks(v *vault.Vault) (map[string]cardBlock, error) {
blocks := map[string]cardBlock{}
raw, err := v.Get(cardBlockRecord)
if errors.Is(err, sql.ErrNoRows) {
return blocks, nil
}
if err != nil {
return nil, err
}
defer clear(raw)
if json.Unmarshal(raw, &blocks) != nil {
return nil, errors.New("invalid card block record")
}
return blocks, nil
}
func saveCardBlocks(v *vault.Vault, blocks map[string]cardBlock) error {
b, err := json.Marshal(blocks)
if err != nil {
return err
}
defer clear(b)
return v.Put(cardBlockRecord, b)
}
const cardUsageRecord = "payment-card-last-used"
func readCardUsage(v *vault.Vault) (map[string]int64, error) {
usage := map[string]int64{}
raw, err := v.Get(cardUsageRecord)
if errors.Is(err, sql.ErrNoRows) {
return usage, nil
}
if err != nil {
return nil, err
}
defer clear(raw)
if json.Unmarshal(raw, &usage) != nil {
return nil, errors.New("invalid card usage record")
}
return usage, nil
}
// touchCardUsageLocked records when a card was handed to a payment attempt.
// Caller must hold paymentRouteMu.
func touchCardUsageLocked(v *vault.Vault, fingerprint string) error {
if fingerprint == "" {
return nil
}
usage, err := readCardUsage(v)
if err != nil {
return err
}
usage[fingerprint] = time.Now().UnixNano()
b, err := json.Marshal(usage)
if err != nil {
return err
}
defer clear(b)
return v.Put(cardUsageRecord, b)
}
// paymentCardBlocked reports whether a card is currently out of rotation,
// either permanently blocked or inside its post-decline cooldown.
func paymentCardBlocked(v *vault.Vault, fingerprint string) (bool, error) {
blocks, err := readCardBlocks(v)
if err != nil {
return false, err
}
block, blocked := blocks[fingerprint]
if !blocked {
return false, nil
}
return block.Until == 0 || block.Until > time.Now().Unix(), nil
}
// blockPaymentCard excludes one card from rotation until an operator unblocks
// it or changes the card set. Caller must not hold paymentRouteMu.
func blockPaymentCard(v *vault.Vault, fingerprint, reason string) error {
if fingerprint == "" {
return nil
}
paymentRouteMu.Lock()
defer paymentRouteMu.Unlock()
blocks, err := readCardBlocks(v)
if err != nil {
return err
}
blocks[fingerprint] = cardBlock{Reason: reason, BlockedAt: time.Now().Unix()}
return saveCardBlocks(v, blocks)
}
// coolPaymentCard keeps a declined card out of rotation for the cooldown while
// leaving any permanent provider block in place. Caller must not hold
// paymentRouteMu.
func coolPaymentCard(v *vault.Vault, fingerprint, reason string) error {
if fingerprint == "" {
return nil
}
paymentRouteMu.Lock()
defer paymentRouteMu.Unlock()
return coolPaymentCardLocked(v, fingerprint, reason)
}
func coolPaymentCardLocked(v *vault.Vault, fingerprint, reason string) error {
if fingerprint == "" {
return nil
}
blocks, err := readCardBlocks(v)
if err != nil {
return err
}
if existing, ok := blocks[fingerprint]; ok && existing.Until == 0 {
return nil
}
blocks[fingerprint] = cardBlock{Reason: reason, BlockedAt: time.Now().Unix(), Until: time.Now().Add(paymentCardCooldown).Unix()}
return saveCardBlocks(v, blocks)
}
// UnblockPaymentCards clears every durable card block. It is an explicit
// operator action; the recovery batch confirmation never calls it. When the
// provider no-retry instruction paused the site and a usable card remains, the
// pause is lifted together with the block.
func UnblockPaymentCards(v *vault.Vault) (int, error) {
paymentRouteMu.Lock()
defer paymentRouteMu.Unlock()
blocks, err := readCardBlocks(v)
if err != nil {
return 0, err
}
if len(blocks) > 0 {
if err = v.Put(cardBlockRecord, []byte("{}")); err != nil {
return 0, err
}
}
state, err := readPaymentControl(v)
if err != nil {
return 0, err
}
if state.Paused && state.Reason == "do_not_try_again" {
usable, e := hasUsableCard(v)
if e != nil {
return 0, e
}
if usable {
state.Paused = false
state.Reason = ""
state.ConsecutiveDeclines = 0
if err = savePaymentControl(v, state); err != nil {
return 0, err
}
}
}
return len(blocks), nil
}
// hasUsableCard reports whether any configured card is not permanently
// blocked. Cooling cards count as usable because they return automatically.
func hasUsableCard(v *vault.Vault) (bool, error) {
cards, err := readCards(v)
if err != nil {
return false, nil
}
blocks, err := readCardBlocks(v)
if err != nil {
return false, err
}
for _, c := range cards {
if validateCard(c) != nil {
continue
}
if block, blocked := blocks[cardFingerprint(c)]; !blocked || (block.Until != 0 && block.Until <= time.Now().Unix()) {
return true, nil
}
}
return false, nil
}
// CardStatus is a number-free view of one configured card for the CLI.
type CardStatus struct {
Last4 string `json:"last4"`
Usable bool `json:"usable"`
Problem string `json:"problem,omitempty"`
Blocked string `json:"blocked,omitempty"`
CoolingSeconds int64 `json:"cooling_seconds,omitempty"`
}
func CardsStatus(v *vault.Vault) ([]CardStatus, error) {
cards, err := readCards(v)
if err != nil {
return nil, err
}
blocks, err := readCardBlocks(v)
if err != nil {
return nil, err
}
status := make([]CardStatus, 0, len(cards))
for _, c := range cards {
entry := CardStatus{Last4: cardTail(c), Usable: true}
if problem := validateCard(c); problem != nil {
entry.Usable = false
entry.Problem = problem.Error()
}
if block, ok := blocks[cardFingerprint(c)]; ok {
entry.Blocked = block.Reason
if remaining := block.Until - time.Now().Unix(); block.Until > 0 && remaining > 0 {
entry.CoolingSeconds = remaining
}
}
status = append(status, entry)
}
return status, nil
}
// AddCardRecords appends cards from a JSON object or array. Missing billing
// fields are inherited from an existing card because cardholders normally keep
// one billing profile. Duplicate numbers replace the existing entry.
func AddCardRecords(v *vault.Vault, raw []byte) (int, error) {
incoming, err := decodeCardInput(raw)
if err != nil {
return 0, err
}
cards, err := readCardsOptional(v)
if err != nil {
return 0, err
}
return mergeCards(v, cards, incoming, true)
}
// SetCardRecords replaces the whole card set with a validated JSON array.
func SetCardRecords(v *vault.Vault, raw []byte) (int, error) {
incoming, err := decodeCardInput(raw)
if err != nil {
return 0, err
}
return mergeCards(v, nil, incoming, false)
}
func decodeCardInput(raw []byte) ([]card, error) {
trimmed := strings.TrimSpace(string(raw))
if trimmed == "" {
return nil, errors.New("stdin must contain a card object or a JSON array of cards")
}
var many []card
if strings.HasPrefix(trimmed, "[") {
if json.Unmarshal(raw, &many) != nil {
return nil, errors.New("stdin must be a valid JSON array of cards")
}
} else {
var one card
if json.Unmarshal(raw, &one) != nil {
return nil, errors.New("stdin must be a valid card object")
}
many = []card{one}
}
if len(many) == 0 {
return nil, errors.New("no cards supplied")
}
return many, nil
}
func mergeCards(v *vault.Vault, existing, incoming []card, inherit bool) (int, error) {
base := card{}
for _, c := range existing {
if validateCard(c) == nil {
base = c
break
}
}
merged := append([]card{}, existing...)
for _, c := range incoming {
if inherit {
c = inheritBilling(c, base)
}
if err := validateCard(c); err != nil {
return 0, fmt.Errorf("card ending %s: %w", cardTail(c), err)
}
replaced := false
for i := range merged {
if merged[i].Number == c.Number {
merged[i] = c
replaced = true
break
}
}
if !replaced {
merged = append(merged, c)
}
}
if len(merged) == 0 {
return 0, errors.New("card set would be empty")
}
b, err := json.Marshal(merged)
if err != nil {
return 0, err
}
defer clear(b)
if err = v.Put(cardsRecord, b); err != nil {
return 0, err
}
return len(merged), nil
}
func inheritBilling(c card, base card) card {
for _, field := range []struct {
value *string
base string
}{
{&c.Name, base.Name},
{&c.Email, base.Email},
{&c.Country, base.Country},
{&c.Postal, base.Postal},
{&c.Line1, base.Line1},
{&c.Line2, base.Line2},
{&c.City, base.City},
{&c.State, base.State},
} {
if strings.TrimSpace(*field.value) == "" {
*field.value = field.base
}
}
return c
}
// RemoveCardRecord deletes the card ending in the given last four digits.
func RemoveCardRecord(v *vault.Vault, last4 string) (int, error) {
if !regexp.MustCompile(`^[0-9]{4}$`).MatchString(last4) {
return 0, errors.New("--last4 must be exactly four digits")
}
cards, err := readCards(v)
if err != nil {
return 0, err
}
matches := 0
kept := make([]card, 0, len(cards))
for _, c := range cards {
if cardTail(c) == last4 {
matches++
continue
}
kept = append(kept, c)
}
if matches == 0 {
return 0, fmt.Errorf("no configured card ends with %s", last4)
}
if matches > 1 {
return 0, errors.New("more than one configured card ends with those digits; remove it from the JSON set instead")
}
if len(kept) == 0 {
return 0, errors.New("refusing to remove the last payment card")
}
b, err := json.Marshal(kept)
if err != nil {
return 0, err
}
defer clear(b)
if err = v.Put(cardsRecord, b); err != nil {
return 0, err
}
return len(kept), nil
}
// UpdateCardBilling applies billing fields to every configured card.
func UpdateCardBilling(v *vault.Vault, fields map[string]string) (int, error) {
allowed := map[string]bool{"billing_name": true, "email": true, "billing_country": true, "billing_postal_code": true, "billing_address_line1": true, "billing_address_line2": true, "billing_city": true, "billing_state": true}
for name := range fields {
if !allowed[name] {
return 0, errors.New("unsupported billing field")
}
}
cards, err := readCards(v)
if err != nil {
return 0, err
}
updated := make([]card, 0, len(cards))
for _, c := range cards {
raw, err := json.Marshal(c)
if err != nil {
return 0, err
}
defer clear(raw)
var record map[string]any
if json.Unmarshal(raw, &record) != nil {
return 0, errors.New("invalid card record")
}
for name, value := range fields {
record[name] = value
}
out, err := json.Marshal(record)
if err != nil {
return 0, err
}
defer clear(out)
var next card
if json.Unmarshal(out, &next) != nil {
return 0, errors.New("invalid card record after billing update")
}
if err = validateCard(next); err != nil {
return 0, fmt.Errorf("card ending %s: %w", cardTail(next), err)
}
updated = append(updated, next)
}
b, err := json.Marshal(updated)
if err != nil {
return 0, err
}
defer clear(b)
if _, err = v.Get(cardsRecord); err == nil {
return len(updated), v.Put(cardsRecord, b)
} else if !errors.Is(err, sql.ErrNoRows) {
return 0, err
}
return len(updated), v.Put(legacyCardKey, b)
}
// RotationInfo is a number-free view of the running card+node batch for the CLI.
type RotationInfo struct {
BatchSize int `json:"batch_size"`
Used int `json:"used"`
CardLast4 string `json:"card_last4,omitempty"`
Node string `json:"node,omitempty"`
Cards int `json:"cards"`
Usable int `json:"usable"`
Blocked []string `json:"blocked,omitempty"`
Cooling []string `json:"cooling,omitempty"`
}
func PaymentRotationStatus(v *vault.Vault) (RotationInfo, error) {
cards, err := readCards(v)
if err != nil {
return RotationInfo{}, err
}
blocks, err := readCardBlocks(v)
if err != nil {
return RotationInfo{}, err
}
info := RotationInfo{BatchSize: PaymentBatchSize, Cards: len(cards)}
for _, c := range cards {
if validateCard(c) == nil {
info.Usable++
}
if block, ok := blocks[cardFingerprint(c)]; ok {
if block.Until > time.Now().Unix() {
info.Cooling = append(info.Cooling, fmt.Sprintf("%s (%s)", cardTail(c), block.Reason))
} else if block.Until == 0 {
info.Blocked = append(info.Blocked, cardTail(c)+" ("+block.Reason+")")
}
}
}
rotation, err := readPaymentRotation(v)
if err != nil {
return RotationInfo{}, err
}
if rotation == nil {
return info, nil
}
info.Used = rotation.Used
if c, ok := cardByFingerprint(cards, rotation.CardFingerprint); ok {
info.CardLast4 = cardTail(c)
}
if len(rotation.Outbound) > 0 {
if routeGroup(rotation.Outbound) == "direct" {
info.Node = "direct"
} else {
info.Node = "node-" + rotation.NodeID[:12]
}
}
return info, nil
}
+154
View File
@@ -0,0 +1,154 @@
package checkout
import (
"strings"
"testing"
)
const (
testCardOne = `{"number":"4242424242424242","exp_month":"12","exp_year":"2099","cvc":"123","billing_name":"Test Holder","email":"holder@example.invalid","billing_country":"US"}`
testCardTwo = `{"number":"4000056655665556","exp_month":"11","exp_year":"2099","cvc":"456","billing_name":"Test Holder","email":"holder@example.invalid","billing_country":"US"}`
testCardThree = `{"number":"5555555555554444","exp_month":"10","exp_year":"2099","cvc":"789","billing_name":"Test Holder","email":"holder@example.invalid","billing_country":"US"}`
)
func TestReadCardsPrefersSetAndFallsBackToLegacy(t *testing.T) {
v := controlFixture(t)
if err := v.Put("card", []byte(testCardOne)); err != nil {
t.Fatal(err)
}
cards, err := readCards(v)
if err != nil || len(cards) != 1 || cards[0].Number != "4242424242424242" {
t.Fatalf("legacy fallback failed: %+v %v", cards, err)
}
if n, err := AddCardRecords(v, []byte(testCardTwo)); err != nil || n != 2 {
t.Fatalf("add failed: %d %v", n, err)
}
if n, err := AddCardRecords(v, []byte("["+testCardThree+"]")); err != nil || n != 3 {
t.Fatalf("append failed: %d %v", n, err)
}
cards, err = readCards(v)
if err != nil || len(cards) != 3 {
t.Fatalf("set not preferred: %+v %v", cards, err)
}
if cards[1].Name != "Test Holder" || cards[1].Country != "US" {
t.Fatal("billing was not inherited")
}
// Re-adding an existing number replaces it instead of duplicating.
if n, err := AddCardRecords(v, []byte(strings.Replace(testCardTwo, `"456"`, `"999"`, 1))); err != nil || n != 3 {
t.Fatalf("duplicate replacement failed: %d %v", n, err)
}
cards, _ = readCards(v)
if cards[1].CVC != "999" {
t.Fatal("duplicate card was not updated")
}
}
func TestCardValidationAndExpiryAreEnforced(t *testing.T) {
v := controlFixture(t)
if _, err := AddCardRecords(v, []byte(`{"number":"4242424242424243","exp_month":"12","exp_year":"2099","cvc":"123","billing_name":"N","email":"a@b.invalid","billing_country":"US"}`)); err == nil {
t.Fatal("bad checksum accepted")
}
if _, err := AddCardRecords(v, []byte(`{"number":"4242424242424242","exp_month":"01","exp_year":"2000","cvc":"123","billing_name":"N","email":"a@b.invalid","billing_country":"US"}`)); err == nil {
t.Fatal("expired card accepted")
}
if _, err := AddCardRecords(v, []byte(testCardOne)); err != nil {
t.Fatal(err)
}
// A second card without billing inherits the first profile.
if _, err := AddCardRecords(v, []byte(`{"number":"4000056655665556","exp_month":"11","exp_year":"2099","cvc":"456"}`)); err != nil {
t.Fatal(err)
}
status, err := CardsStatus(v)
if err != nil || len(status) != 2 || !status[0].Usable || !status[1].Usable {
t.Fatalf("status=%+v err=%v", status, err)
}
if _, err = RemoveCardRecord(v, "5556"); err != nil {
t.Fatal(err)
}
if _, err = RemoveCardRecord(v, "4242"); err == nil {
t.Fatal("removing the last card was allowed")
}
}
func TestSetCardRecordsReplacesAndRejectsEmpty(t *testing.T) {
v := controlFixture(t)
if _, err := v.Get(cardsRecord); err == nil {
t.Fatal("unexpected card set fixture")
}
if _, err := SetCardRecords(v, []byte(`[]`)); err == nil {
t.Fatal("empty set accepted")
}
if n, err := SetCardRecords(v, []byte("["+testCardOne+","+testCardTwo+"]")); err != nil || n != 2 {
t.Fatalf("set failed: %d %v", n, err)
}
rotation, err := PaymentRotationStatus(v)
if err != nil || rotation.Cards != 2 || rotation.Usable != 2 || rotation.BatchSize != PaymentBatchSize {
t.Fatalf("status=%+v err=%v", rotation, err)
}
}
func TestCardSetFingerprintTracksMembershipNotOrder(t *testing.T) {
v := controlFixture(t)
if _, err := SetCardRecords(v, []byte("["+testCardOne+","+testCardTwo+"]")); err != nil {
t.Fatal(err)
}
before, err := paymentCardFingerprint(v)
if err != nil {
t.Fatal(err)
}
if _, err = SetCardRecords(v, []byte("["+testCardTwo+","+testCardOne+"]")); err != nil {
t.Fatal(err)
}
after, _ := paymentCardFingerprint(v)
if before != after {
t.Fatal("set fingerprint changed when only order changed")
}
if _, err = AddCardRecords(v, []byte(testCardThree)); err != nil {
t.Fatal(err)
}
changed, _ := paymentCardFingerprint(v)
if changed == before {
t.Fatal("set fingerprint did not change after adding a card")
}
}
func TestBlockedCardsAreSkippedUntilExplicitlyUnblocked(t *testing.T) {
v := controlFixture(t)
if _, err := SetCardRecords(v, []byte("["+testCardOne+","+testCardTwo+","+testCardThree+"]")); err != nil {
t.Fatal(err)
}
cards, _ := readCards(v)
first := cardFingerprint(cards[0])
second := cardFingerprint(cards[1])
if err := blockPaymentCard(v, first, "do_not_try_again"); err != nil {
t.Fatal(err)
}
if err := blockPaymentCard(v, second, "do_not_try_again"); err != nil {
t.Fatal(err)
}
if usable, err := hasUsableCard(v); err != nil || !usable {
t.Fatal("third card should remain usable")
}
pair, _, err := choosePaymentPair(v, cards, nil, "", "")
if err != nil {
t.Fatal(err)
}
if cardFingerprint(pair) != cardFingerprint(cards[2]) {
t.Fatal("blocked card was selected")
}
if err := blockPaymentCard(v, cardFingerprint(cards[2]), "do_not_try_again"); err != nil {
t.Fatal(err)
}
if usable, _ := hasUsableCard(v); usable {
t.Fatal("all cards blocked but still reported usable")
}
if _, _, err := choosePaymentPair(v, cards, nil, "", ""); err != ErrNoUsableCard {
t.Fatalf("err=%v", err)
}
if cleared, err := UnblockPaymentCards(v); err != nil || cleared != 3 {
t.Fatalf("cleared=%d err=%v", cleared, err)
}
if usable, _ := hasUsableCard(v); !usable {
t.Fatal("unblock did not restore rotation")
}
}
+13 -2
View File
@@ -21,6 +21,7 @@ type Record struct {
CreationAttempts int `json:"creation_attempts,omitempty"`
PreflightSaved bool `json:"preflight_saved,omitempty"`
PaymentMethod string `json:"payment_method,omitempty"`
CardFingerprint string `json:"card_fingerprint,omitempty"`
ConfirmParameters string `json:"confirm_parameters,omitempty"`
ConfirmKey string `json:"confirm_key,omitempty"`
SubmittedAt int64 `json:"submitted_at,omitempty"`
@@ -180,7 +181,11 @@ func run(ctx context.Context, v *vault.Vault, user, expectedRecipient string, pa
return &r, e
}
}
s, e := newStripe(ctx, v, r.RecipientID)
paymentFlow := paymentRead
if pay {
paymentFlow = paymentPay
}
s, e := newStripe(ctx, v, r.RecipientID, paymentFlow)
if e != nil {
return &r, e
}
@@ -203,13 +208,19 @@ func run(ctx context.Context, v *vault.Vault, user, expectedRecipient string, pa
if !pay {
return &r, nil
}
c, e := readCard(v)
c, e := s.paymentCard()
if e != nil {
return &r, e
}
r.CardFingerprint = cardFingerprint(c)
progress(ctx, 70, "正在准备付款,请勿重复提交…")
method, e := s.tokenize(ctx, &r, c)
if e != nil {
if cardTokenizationRejected(e) {
// The card itself was rejected before any submit: end the batch so the
// next attempt rotates to another card instead of retrying this one.
_ = markPaymentDecline(v, r.RecipientID)
}
return &r, e
}
// Refresh after card creation; confirmation also pins the expected amount server-side.
+1 -1
View File
@@ -56,7 +56,7 @@ func inspect(ctx context.Context, v *vault.Vault, user string, port, months int,
if !sessionURL(r.URL, r.SessionID) {
return errors.New("untrusted recorded checkout")
}
s, e := newStripe(ctx, v, r.RecipientID)
s, e := newStripe(ctx, v, r.RecipientID, paymentRead)
if e != nil {
return e
}
+24 -8
View File
@@ -12,14 +12,24 @@ import (
"xgift/internal/vault"
)
// CardSummary exposes only a display suffix and an opaque configuration binding.
func CardSummary(v *vault.Vault) (last4, binding string, err error) {
c, err := readCard(v)
// CardSummary exposes only a display suffix, the configured card count and an
// opaque set binding. Rotation inside the same set does not change the binding.
func CardSummary(v *vault.Vault) (last4 string, count int, binding string, err error) {
cards, err := readCards(v)
if err != nil {
return "", "", err
return "", 0, "", err
}
binding, err = paymentCardFingerprint(v)
return c.Number[len(c.Number)-4:], binding, err
usable := usableCards(cards)
if len(usable) == 0 {
return "", len(cards), "", ErrNoUsableCard
}
display := usable[0]
if rotation, e := readPaymentRotation(v); e == nil && rotation != nil && rotation.CardFingerprint != "" {
if c, ok := cardByFingerprint(cards, rotation.CardFingerprint); ok && validateCard(c) == nil {
display = c
}
}
return cardTail(display), len(cards), cardSetFingerprint(cards), nil
}
// ManualRetryBlocked deliberately treats bank instructions as a stop condition.
@@ -145,7 +155,7 @@ func ManualRecoverForRecipient(ctx context.Context, v *vault.Vault, user, recipi
if err = verifySubmission(v, &r, plan); err != nil {
return &r, err
}
s, err := newStripe(ctx, v, r.RecipientID)
s, err := newStripe(ctx, v, r.RecipientID, paymentRetry)
if err != nil {
return &r, err
}
@@ -204,14 +214,18 @@ func manualRecoverDeclined(ctx context.Context, v *vault.Vault, r *Record, s *st
if err = v.Put(fmt.Sprintf("manual-previous:%s:%d", r.SessionID, next.RecoveryAttempts), old); err != nil {
return r, err
}
c, err := readCard(v)
c, err := s.paymentCard()
if err != nil {
return r, err
}
method, err := s.tokenize(ctx, &next, c)
if err != nil {
if cardTokenizationRejected(err) {
_ = markPaymentDecline(v, r.RecipientID)
}
return r, err
}
next.CardFingerprint = cardFingerprint(c)
page, proof, err := s.manualPreflight(ctx, r, plan)
if err != nil {
return r, err
@@ -261,6 +275,8 @@ func ManualRecoveryErrorMessage(err error) string {
return replacementMessage(err)
case errors.Is(err, ErrPaymentPaused):
return "银行卡付款保护已暂停,未继续提交。"
case errors.Is(err, ErrNoUsableCard):
return "没有可用的付款卡(可能全部在冷却或被封锁),未提交补单付款;请用 cards list 查看卡池状态。"
case strings.Contains(text, "checkout_not_active_session"):
return "原账单已失效,未提交补单付款;需要单独核实。"
case strings.Contains(text, "unpaid"), strings.Contains(text, "payment intent"), strings.Contains(text, "payment_intent"):
+37 -8
View File
@@ -2,9 +2,7 @@ package checkout
import (
"context"
"crypto/sha256"
"database/sql"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
@@ -53,12 +51,11 @@ func readPaymentControl(v *vault.Vault) (paymentControl, error) {
return state, nil
}
func paymentCardFingerprint(v *vault.Vault) (string, error) {
c, err := readCard(v)
cards, err := readCards(v)
if err != nil {
return "", err
}
digest := sha256.Sum256([]byte(c.Number + ":" + c.Month + ":" + c.Year))
return hex.EncodeToString(digest[:]), nil
return cardSetFingerprint(cards), nil
}
func savePaymentControl(v *vault.Vault, state paymentControl) error {
b, err := json.Marshal(state)
@@ -138,17 +135,49 @@ func paymentOutcome(v *vault.Vault, r *Record) error {
} else if IsPaymentDeclined(r) {
state.ConsecutiveDeclines++
state.Outcome = "declined"
// The declined order keeps its evidence; the running card+node batch is
// expired so the next attempt rotates to another pair.
if err = markPaymentDecline(v, r.RecipientID); err != nil {
return err
}
// Ordinary card declines stay local to the failed order. Only an explicit
// provider instruction pauses this card globally.
// provider no-retry instruction blocks that one card; with other cards
// configured the site keeps paying through the remaining rotation and
// pauses only when there is nothing left to try.
if r.LastError != nil && r.LastError.AdviceCode == "do_not_try_again" {
state.Paused = true
state.Reason = "do_not_try_again"
fingerprint := declinedCardFingerprint(v, r.RecipientID)
if fingerprint == "" {
state.Paused = true
state.Reason = "do_not_try_again"
} else {
if err = blockPaymentCard(v, fingerprint, "do_not_try_again"); err != nil {
return err
}
remaining, e := hasUsableCard(v)
if e != nil {
return e
}
if !remaining {
state.Paused = true
state.Reason = "do_not_try_again"
}
}
}
} else {
return nil
}
return savePaymentControl(v, state)
}
// declinedCardFingerprint resolves the card bound to a declined order without
// selecting, rotating or contacting any node.
func declinedCardFingerprint(v *vault.Vault, recipient string) string {
route, err := readPaymentRoute(v, recipient)
if err != nil || route.Card == "" {
return ""
}
return route.Card
}
func IsPaymentDeclined(r *Record) bool {
return r != nil && r.Status != "succeeded" && r.Status != "requires_action" && (r.Status == "declined" || r.LastError != nil && r.LastError.HTTP == 402 && r.LastError.Type == "card_error")
}
+1 -1
View File
@@ -211,7 +211,7 @@ func TestNoAvailableExitAndCanceledRequestDoNotReplay(t *testing.T) {
raw := `[{"type":"direct","tag":"direct"}]`
v.Put("payment-outbounds", []byte(raw))
v.Put("stripe-key", []byte("pk_live_Test"))
s, e := newStripe(context.Background(), v, "1234")
s, e := newStripe(context.Background(), v, "1234", paymentRead)
if e != nil {
t.Fatal(e)
}
+396
View File
@@ -0,0 +1,396 @@
package checkout
import (
"crypto/rand"
"database/sql"
"encoding/json"
"errors"
"math/big"
"regexp"
"time"
"xgift/internal/proxy"
"xgift/internal/vault"
)
// PaymentBatchSize is how many consecutive payment attempts share one card+node
// pair. A decline ends the batch immediately and the next attempt rotates.
const PaymentBatchSize = 3
const paymentRotationRecord = "payment-rotation"
type paymentRotation struct {
CardFingerprint string `json:"card_fingerprint,omitempty"`
NodeID string `json:"node_id,omitempty"`
Outbound json.RawMessage `json:"outbound,omitempty"`
Used int `json:"used"`
UpdatedAt int64 `json:"updated_at"`
}
func readPaymentRotation(v *vault.Vault) (*paymentRotation, error) {
raw, err := v.Get(paymentRotationRecord)
if errors.Is(err, sql.ErrNoRows) {
return nil, nil
}
if err != nil {
return nil, err
}
defer clear(raw)
var r paymentRotation
if json.Unmarshal(raw, &r) != nil || r.Used < 0 || r.Used > PaymentBatchSize {
return nil, errors.New("invalid payment rotation record")
}
if len(r.Outbound) > 0 {
if _, err = proxy.ParseOutboundPool(append(append([]byte{'['}, r.Outbound...), ']')); err != nil {
return nil, errors.New("invalid payment rotation outbound")
}
if r.NodeID != outboundID(r.Outbound) {
return nil, errors.New("payment rotation node does not match its snapshot")
}
}
return &r, nil
}
func savePaymentRotation(v *vault.Vault, r *paymentRotation) error {
r.UpdatedAt = time.Now().Unix()
b, err := json.Marshal(r)
if err != nil {
return err
}
defer clear(b)
return v.Put(paymentRotationRecord, b)
}
// ResetPaymentRotation expires the running batch so the next payment attempt
// selects a fresh card+node pair.
func ResetPaymentRotation(v *vault.Vault) error {
paymentRouteMu.Lock()
defer paymentRouteMu.Unlock()
rotation, err := readPaymentRotation(v)
if err != nil {
return err
}
if rotation == nil {
rotation = &paymentRotation{}
}
rotation.Used = PaymentBatchSize
return savePaymentRotation(v, rotation)
}
// choosePaymentPair picks one random usable card and one random available node.
// Cards that are blocked or cooling are skipped; keepCard pins the running
// batch to its card; forbidden replaces the given node when possible.
func choosePaymentPair(v *vault.Vault, cards []card, nodes []json.RawMessage, keepCard, forbidden string) (card, json.RawMessage, error) {
blocks, err := readCardBlocks(v)
if err != nil {
return card{}, nil, err
}
usable := make([]card, 0, len(cards))
for _, c := range cards {
if validateCard(c) != nil {
continue
}
if _, blocked := blocks[cardFingerprint(c)]; blocked {
continue
}
usable = append(usable, c)
}
if len(usable) == 0 {
return card{}, nil, ErrNoUsableCard
}
pickable := usable
if keepCard != "" {
for _, c := range usable {
if cardFingerprint(c) == keepCard {
pickable = []card{c}
break
}
}
}
// New batches prefer the usable card that has gone unused the longest, so a
// two-card set alternates instead of streaking by chance.
if keepCard == "" {
usage, err := readCardUsage(v)
if err != nil {
return card{}, nil, err
}
oldest := int64(-1)
preferred := make([]card, 0, len(pickable))
for _, c := range pickable {
used := usage[cardFingerprint(c)]
if oldest < 0 || used < oldest {
oldest = used
preferred = append(preferred[:0], c)
} else if used == oldest {
preferred = append(preferred, c)
}
}
pickable = preferred
}
cardIndex, err := rand.Int(rand.Reader, big.NewInt(int64(len(pickable))))
if err != nil {
return card{}, nil, errors.New("cannot choose payment card")
}
chosen := pickable[cardIndex.Int64()]
if len(nodes) == 0 {
return chosen, json.RawMessage(`{"type":"direct","tag":"direct"}`), nil
}
available, err := availablePaymentNodes(v, nodes)
if err != nil {
return card{}, nil, err
}
if len(available) == 0 {
return card{}, nil, ErrPaymentNodesCooling
}
choices := available
if last, e := v.Get("stripe-route:last-node"); e == nil && len(last) > 0 {
lastGroup := ""
for _, node := range nodes {
if outboundID(node) == string(last) {
lastGroup = routeGroup(node)
break
}
}
clear(last)
if lastGroup != "" {
filtered := make([]json.RawMessage, 0, len(choices))
for _, node := range choices {
if routeGroup(node) != lastGroup {
filtered = append(filtered, node)
}
}
if len(filtered) > 0 {
choices = filtered
}
}
}
if len(choices) > 1 && forbidden != "" {
filtered := make([]json.RawMessage, 0, len(choices))
for _, node := range choices {
if outboundID(node) != forbidden {
filtered = append(filtered, node)
}
}
if len(filtered) > 0 {
choices = filtered
}
}
nodeIndex, err := rand.Int(rand.Reader, big.NewInt(int64(len(choices))))
if err != nil {
return card{}, nil, errors.New("cannot choose payment node")
}
return chosen, choices[nodeIndex.Int64()], nil
}
func paymentNodes(v *vault.Vault) ([]json.RawMessage, error) {
raw, err := v.Get("payment-outbounds")
if errors.Is(err, sql.ErrNoRows) {
return nil, nil
}
if err != nil {
return nil, err
}
defer clear(raw)
return proxy.ParseOutboundPool(raw)
}
// continueOrRotate returns the pair the next payment attempt should use. A
// running batch of fewer than PaymentBatchSize attempts keeps its card; a new
// batch prefers a different node.
func continueOrRotate(v *vault.Vault, cards []card, nodes []json.RawMessage, rotation *paymentRotation, continueBatch bool, forbidden string) (card, json.RawMessage, int, error) {
if continueBatch && rotation != nil && rotation.Used < PaymentBatchSize && rotation.CardFingerprint != "" {
c, ok := cardByFingerprint(cards, rotation.CardFingerprint)
if ok && validateCard(c) == nil {
if blocked, e := paymentCardBlocked(v, rotation.CardFingerprint); e != nil {
return card{}, nil, 0, e
} else if !blocked {
if len(rotation.Outbound) == 0 {
return c, json.RawMessage(`{"type":"direct","tag":"direct"}`), rotation.Used + 1, nil
}
until, e := nodeCoolingUntil(v, rotation.Outbound)
if e != nil {
return card{}, nil, 0, e
}
if until <= time.Now().Unix() {
return c, rotation.Outbound, rotation.Used + 1, nil
}
next, node, e := choosePaymentPair(v, cards, nodes, rotation.CardFingerprint, rotation.NodeID)
if e != nil {
return card{}, nil, 0, e
}
return next, node, rotation.Used + 1, nil
}
}
}
chosen, node, err := choosePaymentPair(v, cards, nodes, "", forbidden)
if err != nil {
return card{}, nil, 0, err
}
return chosen, node, 1, nil
}
// assignPaymentRoute pins the card+node pair a payment submission must use and
// records it on the order. rotate forces a fresh pair (used after a decline).
// Read-only Stripe calls keep using selectPaymentRoute and never rotate cards.
func assignPaymentRoute(v *vault.Vault, recipient string, rotate bool) (*paymentRoute, card, error) {
if !regexp.MustCompile(`^[0-9]{1,32}$`).MatchString(recipient) {
return nil, card{}, errors.New("payment route requires a bound recipient")
}
paymentRouteMu.Lock()
defer paymentRouteMu.Unlock()
cards, err := readCards(v)
if err != nil {
return nil, card{}, err
}
rotation, err := readPaymentRotation(v)
if err != nil {
return nil, card{}, err
}
nodes, err := paymentNodes(v)
if err != nil {
return nil, card{}, err
}
route, routeErr := readPaymentRoute(v, recipient)
if routeErr != nil && !errors.Is(routeErr, sql.ErrNoRows) {
return nil, card{}, routeErr
}
var bound card
boundOK := false
if routeErr == nil && route.Card != "" {
if c, ok := cardByFingerprint(cards, route.Card); ok && validateCard(c) == nil {
blocked, e := paymentCardBlocked(v, route.Card)
if e != nil {
return nil, card{}, e
}
if !blocked {
bound, boundOK = c, true
}
}
}
if routeErr == nil && !rotate && boundOK {
// The order keeps its pinned pair; only a durable transport cooldown may
// move the node, and the card always stays with the order.
until, e := nodeCoolingUntil(v, route.Outbound)
if e != nil {
return nil, card{}, e
}
if until > time.Now().Unix() {
next, e := rotateCoolingRouteLocked(v, route)
if e != nil {
return nil, card{}, e
}
return next, bound, nil
}
return route, bound, nil
}
// A fresh pair is needed: first attempt, a route with no usable card, or an
// explicit rotation after a decline. A retry keeps the rejected card out of
// rotation for the cooldown.
forbidden := ""
if routeErr == nil {
forbidden = route.NodeID
}
if rotate && routeErr == nil && route.Card != "" {
if _, ok := cardByFingerprint(cards, route.Card); ok {
if err = coolPaymentCardLocked(v, route.Card, "declined"); err != nil {
return nil, card{}, err
}
}
}
continueBatch := !rotate
chosen, node, used, err := continueOrRotate(v, cards, nodes, rotation, continueBatch, forbidden)
if err != nil {
return nil, card{}, err
}
fingerprint := cardFingerprint(chosen)
next := &paymentRoute{Recipient: recipient, NodeID: outboundID(node), Outbound: node, Card: fingerprint, SelectedAt: time.Now().Unix()}
b, err := json.Marshal(next)
if err != nil {
return nil, card{}, err
}
defer clear(b)
if routeErr == nil {
expected, e := v.Get("stripe-route:" + recipient)
if e != nil {
return nil, card{}, e
}
defer clear(expected)
archive := "stripe-route-history:" + recipient + ":" + time.Now().Format("20060102T150405.000000000")
if e = v.ReplaceArchived("stripe-route:"+recipient, archive, expected, expected, b); e != nil {
return nil, card{}, e
}
} else {
inserted, e := v.PutIfAbsent("stripe-route:"+recipient, b)
if e != nil {
return nil, card{}, e
}
if !inserted {
// Another process bound this order first; keep that binding.
current, e := readPaymentRoute(v, recipient)
if e != nil {
return nil, card{}, e
}
c, ok := cardByFingerprint(cards, current.Card)
if !ok {
usable := usableCards(cards)
if len(usable) == 0 {
return nil, card{}, ErrNoUsableCard
}
c = usable[0]
}
return current, c, nil
}
}
if rotation == nil {
rotation = &paymentRotation{}
}
rotation.CardFingerprint = fingerprint
rotation.NodeID = next.NodeID
rotation.Outbound = append(json.RawMessage(nil), node...)
rotation.Used = used
if err = savePaymentRotation(v, rotation); err != nil {
return nil, card{}, err
}
if err = touchCardUsageLocked(v, fingerprint); err != nil {
return nil, card{}, err
}
if err = v.Put("stripe-route:last-node", []byte(next.NodeID)); err != nil {
return nil, card{}, err
}
return next, chosen, nil
}
// markPaymentDecline ends the running batch and keeps the declined card out of
// rotation for the cooldown while other cards remain available.
func markPaymentDecline(v *vault.Vault, recipient string) error {
if recipient == "" {
return nil
}
paymentRouteMu.Lock()
defer paymentRouteMu.Unlock()
rotation, err := readPaymentRotation(v)
if err != nil {
return err
}
if rotation == nil {
rotation = &paymentRotation{}
}
if route, e := readPaymentRoute(v, recipient); e == nil && route.Card != "" {
if err = coolPaymentCardLocked(v, route.Card, "declined"); err != nil {
return err
}
}
rotation.Used = PaymentBatchSize
return savePaymentRotation(v, rotation)
}
// cardTokenizationRejected reports whether a failed card submission was
// rejected by the provider because of the card itself rather than by a
// transport or API problem. A rejected card is rotated away immediately.
func cardTokenizationRejected(err error) bool {
var se *stripeError
return errors.As(err, &se) && se.Type == "card_error"
}
+276
View File
@@ -0,0 +1,276 @@
package checkout
import (
"fmt"
"strings"
"testing"
"time"
"xgift/internal/vault"
)
// rotationSetup builds a vault with the given card records and the standard
// two-server node pool used by the route tests.
func rotationSetup(t *testing.T, cards ...string) *vault.Vault {
t.Helper()
v := controlFixture(t)
if err := v.Put("payment-outbounds", []byte(twoPaymentNodes)); err != nil {
t.Fatal(err)
}
if _, err := SetCardRecords(v, []byte("["+strings.Join(cards, ",")+"]")); err != nil {
t.Fatal(err)
}
return v
}
func assignPair(t *testing.T, v *vault.Vault, recipient string, rotate bool) (string, string) {
t.Helper()
route, card, err := assignPaymentRoute(v, recipient, rotate)
if err != nil {
t.Fatal(err)
}
return route.NodeID, cardFingerprint(card)
}
func TestThreeConsecutiveOrdersShareOnePair(t *testing.T) {
v := rotationSetup(t, testCardOne, testCardTwo, testCardThree)
firstNode, firstCard := assignPair(t, v, "101", false)
secondNode, secondCard := assignPair(t, v, "102", false)
thirdNode, thirdCard := assignPair(t, v, "103", false)
if firstNode != secondNode || secondNode != thirdNode || firstCard != secondCard || secondCard != thirdCard {
t.Fatalf("first three orders did not share one pair: %s/%s %s/%s %s/%s", firstNode, firstCard, secondNode, secondCard, thirdNode, thirdCard)
}
rotation, err := readPaymentRotation(v)
if err != nil || rotation.Used != PaymentBatchSize {
t.Fatalf("rotation=%+v err=%v", rotation, err)
}
fourthNode, _ := assignPair(t, v, "104", false)
if fourthNode == thirdNode {
t.Fatal("fourth order did not rotate to another pair")
}
rotation, _ = readPaymentRotation(v)
if rotation.Used != 1 {
t.Fatalf("new batch did not restart the counter: %+v", rotation)
}
}
func TestDeclineEndsBatchAndNextRotationAvoidsCard(t *testing.T) {
v := rotationSetup(t, testCardOne, testCardTwo, testCardThree)
node, card := assignPair(t, v, "201", false)
if err := markPaymentDecline(v, "201"); err != nil {
t.Fatal(err)
}
rotation, err := readPaymentRotation(v)
if err != nil || rotation.Used != PaymentBatchSize {
t.Fatalf("decline was not recorded as a batch end: %+v %v", rotation, err)
}
if blocked, _ := paymentCardBlocked(v, card); !blocked {
t.Fatal("declined card was not cooled down")
}
nextNode, nextCard := assignPair(t, v, "202", false)
if nextCard == card {
t.Fatal("next order reused the declined card")
}
if nextNode == node {
t.Fatal("next order reused the declined node")
}
if _, err := readPaymentRotation(v); err != nil {
t.Fatal(err)
}
}
func TestRetryAfterDeclineRotatesPair(t *testing.T) {
v := rotationSetup(t, testCardOne, testCardTwo, testCardThree)
node, card := assignPair(t, v, "301", false)
next, nextCard, err := assignPaymentRoute(v, "301", true)
if err != nil {
t.Fatal(err)
}
if next.NodeID == node {
t.Fatal("retry kept the rejected node")
}
if cardFingerprint(nextCard) == card {
t.Fatal("retry reused the rejected card")
}
if next.Card != cardFingerprint(nextCard) {
t.Fatal("retry route did not persist its card binding")
}
}
func TestRepeatAttemptKeepsBoundPairWithoutConsumingTwice(t *testing.T) {
v := rotationSetup(t, testCardOne, testCardTwo, testCardThree)
node, card := assignPair(t, v, "401", false)
again, againCard, err := assignPaymentRoute(v, "401", false)
if err != nil {
t.Fatal(err)
}
if again.NodeID != node || cardFingerprint(againCard) != card {
t.Fatal("repeat attempt did not keep its bound pair")
}
rotation, _ := readPaymentRotation(v)
if rotation.Used != 1 {
t.Fatalf("repeat attempt consumed another batch slot: %+v", rotation)
}
}
func TestLegacyRouteAdoptsRunningBatchCard(t *testing.T) {
v := rotationSetup(t, testCardOne, testCardTwo, testCardThree)
if _, err := selectPaymentRoute(v, "501"); err != nil {
t.Fatal(err)
}
_, batchCard := assignPair(t, v, "502", false)
next, card, err := assignPaymentRoute(v, "501", false)
if err != nil {
t.Fatal(err)
}
if cardFingerprint(card) != batchCard {
t.Fatal("legacy route did not adopt the running batch card")
}
if next.Card != batchCard {
t.Fatal("card binding was not persisted on the legacy route")
}
rotation, _ := readPaymentRotation(v)
if rotation.Used != 2 {
t.Fatalf("legacy binding did not consume a batch slot: %+v", rotation)
}
}
func TestCoolingBatchNodeMovesWithoutChangingCard(t *testing.T) {
v := rotationSetup(t, testCardOne, testCardTwo, testCardThree)
nodeID, card := assignPair(t, v, "601", false)
rotation, err := readPaymentRotation(v)
if err != nil {
t.Fatal(err)
}
if err = coolPaymentNode(v, rotation.Outbound); err != nil {
t.Fatal(err)
}
nextNode, nextCard := assignPair(t, v, "602", false)
if nextNode == nodeID {
t.Fatal("cooling node was kept for the running batch")
}
if nextCard != card {
t.Fatal("card changed during transport-failure node failover")
}
if rotation, _ = readPaymentRotation(v); rotation.Used != 2 {
t.Fatalf("node failover did not consume exactly one slot: %+v", rotation)
}
}
func TestEmptyPoolKeepsCardRotationOnDirect(t *testing.T) {
v := controlFixture(t)
if _, err := SetCardRecords(v, []byte("["+testCardOne+","+testCardTwo+"]")); err != nil {
t.Fatal(err)
}
route, card, err := assignPaymentRoute(v, "701", false)
if err != nil {
t.Fatal(err)
}
if routeGroup(route.Outbound) != "direct" || route.Card != cardFingerprint(card) {
t.Fatalf("route=%+v", route)
}
}
func TestDoNotTryAgainBlocksOneCardWithoutGlobalPause(t *testing.T) {
v := rotationSetup(t, testCardOne, testCardTwo, testCardThree)
route, _, err := assignPaymentRoute(v, "801", false)
if err != nil {
t.Fatal(err)
}
declined := route.Card
r := &Record{RecipientID: route.Recipient, SessionID: "cs_live_RotationOne", Status: "declined", LastError: &stripeError{HTTP: 402, Type: "card_error", AdviceCode: "do_not_try_again"}}
if err = savePaymentControl(v, paymentControl{LastSession: r.SessionID}); err != nil {
t.Fatal(err)
}
if err = paymentOutcome(v, r); err != nil {
t.Fatal(err)
}
if paused, _ := PaymentPaused(v); paused {
t.Fatal("one blocked card paused rotation while two usable cards remain")
}
if blocked, _ := paymentCardBlocked(v, declined); !blocked {
t.Fatal("declined card was not blocked")
}
cards, _ := readCards(v)
for _, c := range cards {
if cardFingerprint(c) != declined {
if err = blockPaymentCard(v, cardFingerprint(c), "do_not_try_again"); err != nil {
t.Fatal(err)
}
}
}
second := &Record{RecipientID: route.Recipient, SessionID: "cs_live_RotationTwo", Status: "declined", LastError: &stripeError{HTTP: 402, Type: "card_error", AdviceCode: "do_not_try_again"}}
if err = savePaymentControl(v, paymentControl{LastSession: second.SessionID}); err != nil {
t.Fatal(err)
}
if err = paymentOutcome(v, second); err != nil {
t.Fatal(err)
}
if paused, _ := PaymentPaused(v); !paused {
t.Fatal("all cards blocked but the site stayed open")
}
if cleared, err := UnblockPaymentCards(v); err != nil || cleared != 3 {
t.Fatalf("cleared=%d err=%v", cleared, err)
}
if paused, _ := PaymentPaused(v); paused {
t.Fatal("explicit unblock did not lift the provider pause")
}
if usable, _ := hasUsableCard(v); !usable {
t.Fatal("unblock did not restore rotation")
}
}
func TestCoolingCardReturnsAfterCooldown(t *testing.T) {
v := rotationSetup(t, testCardOne, testCardTwo, testCardThree)
cards, _ := readCards(v)
first := cardFingerprint(cards[0])
if err := coolPaymentCard(v, first, "declined"); err != nil {
t.Fatal(err)
}
if blocked, _ := paymentCardBlocked(v, first); !blocked {
t.Fatal("cooled card still selectable")
}
blocks, _ := readCardBlocks(v)
entry := blocks[first]
entry.Until = time.Now().Add(-time.Second).Unix()
blocks[first] = entry
if err := saveCardBlocks(v, blocks); err != nil {
t.Fatal(err)
}
if blocked, _ := paymentCardBlocked(v, first); blocked {
t.Fatal("expired cooldown kept the card out of rotation")
}
if usable, _ := hasUsableCard(v); !usable {
t.Fatal("expired cooldown broke the usable card set")
}
}
func TestTwoCardRotationAlternatesBatches(t *testing.T) {
v := rotationSetup(t, testCardOne, testCardTwo)
var batches []string
for order := 0; order < 6; order++ {
_, card := assignPair(t, v, fmt.Sprintf("81%d", order), false)
batches = append(batches, card)
}
if batches[0] != batches[1] || batches[1] != batches[2] {
t.Fatalf("first batch was not consistent: %v", batches)
}
if batches[3] != batches[4] || batches[4] != batches[5] {
t.Fatalf("second batch was not consistent: %v", batches)
}
if batches[0] == batches[3] {
t.Fatalf("two-card batch selection did not alternate: %v", batches)
}
// A forced rotation (declined retry) must also alternate the card.
_, first, err := assignPaymentRoute(v, "82", true)
if err != nil {
t.Fatal(err)
}
_, second, err := assignPaymentRoute(v, "83", true)
if err != nil {
t.Fatal(err)
}
if cardFingerprint(first) == cardFingerprint(second) {
t.Fatal("consecutive forced rotations reused the same card")
}
}
+5 -1
View File
@@ -21,6 +21,7 @@ type paymentRoute struct {
Recipient string `json:"recipient"`
NodeID string `json:"node_id"`
Outbound json.RawMessage `json:"outbound"`
Card string `json:"card,omitempty"`
SelectedAt int64 `json:"selected_at"`
}
@@ -75,6 +76,9 @@ func readPaymentRoute(v *vault.Vault, recipient string) (*paymentRoute, error) {
if json.Unmarshal(raw, &route) != nil || route.Recipient != recipient || route.SelectedAt <= 0 || len(route.Outbound) == 0 || route.NodeID != outboundID(route.Outbound) {
return nil, errors.New("saved payment route is invalid; refusing to select another node")
}
if route.Card != "" && !regexp.MustCompile(`^[0-9a-f]{64}$`).MatchString(route.Card) {
return nil, errors.New("saved payment route card binding is invalid")
}
if _, err = proxy.ParseOutboundPool(append(append([]byte{'['}, route.Outbound...), ']')); err != nil {
return nil, errors.New("saved payment outbound is invalid")
}
@@ -229,7 +233,7 @@ func rotateCoolingRouteLocked(v *vault.Vault, old *paymentRoute) (*paymentRoute,
if err != nil {
return nil, err
}
next := &paymentRoute{Recipient: old.Recipient, NodeID: outboundID(node), Outbound: node, SelectedAt: time.Now().Unix()}
next := &paymentRoute{Recipient: old.Recipient, NodeID: outboundID(node), Outbound: node, Card: old.Card, SelectedAt: time.Now().Unix()}
b, err := json.Marshal(next)
if err != nil {
return nil, err
+2 -2
View File
@@ -124,7 +124,7 @@ func TestStripePoolUsesPinnedProxyAndDoesNotFallback(t *testing.T) {
v := controlFixture(t)
v.Put("payment-outbounds", nodes)
v.Put("stripe-key", []byte("pk_live_Test"))
s, err := newStripe(context.Background(), v, "1234")
s, err := newStripe(context.Background(), v, "1234", paymentRead)
if err != nil {
t.Fatal(err)
}
@@ -147,7 +147,7 @@ func TestStripePoolUsesPinnedProxyAndDoesNotFallback(t *testing.T) {
pinned, _ := v.Get("stripe-route:1234")
upstream.Close()
v.Put("payment-outbounds", []byte(`[]`))
s, err = newStripe(context.Background(), v, "1234")
s, err = newStripe(context.Background(), v, "1234", paymentRead)
if err != nil {
t.Fatal(err)
}
+1 -1
View File
@@ -42,7 +42,7 @@ func Reconcile(ctx context.Context, v *vault.Vault, recipient string, port int)
if err = verifySubmission(v, &r, plan); err != nil {
return &r, err
}
s, err := newStripe(ctx, v, r.RecipientID)
s, err := newStripe(ctx, v, r.RecipientID, paymentRead)
if err != nil {
return &r, err
}
+1 -1
View File
@@ -59,7 +59,7 @@ func PrepareRecoveryLinkForRecipient(ctx context.Context, v *vault.Vault, user,
if !sessionURL(r.URL, r.SessionID) {
return &r, errors.New("untrusted original checkout")
}
s, err := newStripe(ctx, v, r.RecipientID)
s, err := newStripe(ctx, v, r.RecipientID, paymentRead)
if err != nil {
return &r, err
}
+51 -48
View File
@@ -25,8 +25,21 @@ type stripeClient struct {
vault *vault.Vault
closeRoute func()
route *paymentRoute
card card
hasCard bool
openRoute func(context.Context, json.RawMessage) (*http.Client, func(), error)
}
// paymentMode separates read-only Stripe traffic from payment submissions so a
// card+node pair is consumed exactly when a card is about to be tokenized.
type paymentMode int
const (
paymentRead paymentMode = iota
paymentPay
paymentRetry
)
type stripeError struct {
Code, Type string
Message, Param, RequestID string
@@ -59,7 +72,7 @@ type stripeAPIError struct {
Intent *stripeIntentEvidence `json:"payment_intent"`
}
func newStripe(ctx context.Context, v *vault.Vault, recipient string) (*stripeClient, error) {
func newStripe(ctx context.Context, v *vault.Vault, recipient string, mode paymentMode) (*stripeClient, error) {
key, e := v.Get("stripe-key")
if e != nil {
return nil, e
@@ -68,9 +81,21 @@ func newStripe(ctx context.Context, v *vault.Vault, recipient string) (*stripeCl
if !regexp.MustCompile(`^pk_live_[A-Za-z0-9]+$`).Match(key) {
return nil, errors.New("invalid Stripe merchant publishable key")
}
route, e := selectPaymentRoute(v, recipient)
if e != nil {
return nil, e
var route *paymentRoute
var bound card
switch mode {
case paymentPay:
if route, bound, e = assignPaymentRoute(v, recipient, false); e != nil {
return nil, e
}
case paymentRetry:
if route, bound, e = assignPaymentRoute(v, recipient, true); e != nil {
return nil, e
}
default:
if route, e = selectPaymentRoute(v, recipient); e != nil {
return nil, e
}
}
// Missing/empty pool is direct; an assigned order never silently falls back.
client := &http.Client{Transport: &http.Transport{Proxy: nil, TLSHandshakeTimeout: 15 * time.Second}, Timeout: 35 * time.Second}
@@ -83,7 +108,20 @@ func newStripe(ctx context.Context, v *vault.Vault, recipient string) (*stripeCl
}
}
client.CheckRedirect = func(*http.Request, []*http.Request) error { return errStripeRedirect }
return &stripeClient{http: client, key: string(key), vault: v, closeRoute: closeRoute, route: route, openRoute: proxy.OpenOutbound}, nil
s := &stripeClient{http: client, key: string(key), vault: v, closeRoute: closeRoute, route: route, openRoute: proxy.OpenOutbound}
if mode != paymentRead {
s.card, s.hasCard = bound, true
}
return s, nil
}
// paymentCard returns the card bound to this payment attempt. Legacy callers
// and fixtures fall back to the first configured card.
func (s *stripeClient) paymentCard() (card, error) {
if s.hasCard {
return s.card, nil
}
return readCard(s.vault)
}
func (s *stripeClient) close() {
if s.closeRoute != nil {
@@ -354,50 +392,15 @@ type card struct {
State string `json:"billing_state"`
}
func readCard(v *vault.Vault) (card, error) {
raw, e := v.Get("card")
if e != nil {
return card{}, e
}
defer clear(raw)
var c card
if json.Unmarshal(raw, &c) != nil {
return c, errors.New("invalid card record")
}
if !regexp.MustCompile(`^[0-9]{12,19}$`).MatchString(c.Number) || !regexp.MustCompile(`^(0[1-9]|1[0-2])$`).MatchString(c.Month) || !regexp.MustCompile(`^[0-9]{4}$`).MatchString(c.Year) || !regexp.MustCompile(`^[0-9]{3,4}$`).MatchString(c.CVC) || strings.TrimSpace(c.Name) == "" || !strings.Contains(c.Email, "@") {
return c, errors.New("card, cardholder name or email is incomplete")
}
sum := 0
for i, n := range c.Number {
d := int(n - '0')
if (len(c.Number)-i)%2 == 0 {
d *= 2
if d > 9 {
d -= 9
}
}
sum += d
}
if sum%10 != 0 {
return c, errors.New("card number checksum is invalid")
}
year, _ := strconv.Atoi(c.Year)
month, _ := strconv.Atoi(c.Month)
if !time.Now().Before(time.Date(year, time.Month(month)+1, 1, 0, 0, 0, 0, time.UTC)) {
return c, errors.New("card has expired")
}
if c.Country == "" {
return c, errors.New("Stripe requires a billing address; supply the card billing country and applicable address fields")
}
if !regexp.MustCompile(`^[A-Z]{2}$`).MatchString(c.Country) {
return c, errors.New("invalid supplied billing country")
}
return c, nil
}
func CheckPaymentConfiguration(v *vault.Vault) error {
_, err := readCard(v)
return err
cards, err := readCards(v)
if err != nil {
return err
}
if len(usableCards(cards)) == 0 {
return ErrNoUsableCard
}
return nil
}
func (s *stripeClient) tokenize(ctx context.Context, r *Record, c card) (string, error) {
form := url.Values{"type": {"card"}, "card[number]": {c.Number}, "card[exp_month]": {c.Month}, "card[exp_year]": {c.Year}, "card[cvc]": {c.CVC}, "billing_details[name]": {c.Name}, "billing_details[email]": {c.Email}}
+1 -1
View File
@@ -34,7 +34,7 @@ func TestStripeDirectAndXProxyStaySeparate(t *testing.T) {
t.Fatal(err)
}
}
s, err := newStripe(context.Background(), v, "1234")
s, err := newStripe(context.Background(), v, "1234", paymentRead)
if err != nil {
t.Fatal(err)
}
+1 -1
View File
@@ -29,7 +29,7 @@
/>
<title>XGift · 兑换码管理</title>
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<script type="module" src="/admin.js?v=b962140d448c"></script>
<script type="module" src="/admin.js?v=00ddc63a3139"></script>
</head>
<body>
<div id="root"></div>
+52 -52
View File
@@ -1,16 +1,16 @@
var _A=Object.create;var Kx=Object.defineProperty;var zA=Object.getOwnPropertyDescriptor;var jA=Object.getOwnPropertyNames;var BA=Object.getPrototypeOf,UA=Object.prototype.hasOwnProperty;var Vo=(e,t)=>()=>{try{return t||e((t={exports:{}}).exports,t),t.exports}catch(o){throw t=0,o}};var LA=(e,t,o,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of jA(t))!UA.call(e,n)&&n!==o&&Kx(e,n,{get:()=>t[n],enumerable:!(r=zA(t,n))||r.enumerable});return e};var C=(e,t,o)=>(o=e!=null?_A(BA(e)):{},LA(t||!e||!e.__esModule?Kx(o,"default",{value:e,enumerable:!0}):o,e));var s1=Vo(we=>{"use strict";var bg=Symbol.for("react.transitional.element"),IA=Symbol.for("react.portal"),HA=Symbol.for("react.fragment"),$A=Symbol.for("react.strict_mode"),VA=Symbol.for("react.profiler"),FA=Symbol.for("react.consumer"),qA=Symbol.for("react.context"),GA=Symbol.for("react.forward_ref"),YA=Symbol.for("react.suspense"),KA=Symbol.for("react.memo"),Jx=Symbol.for("react.lazy"),WA=Symbol.for("react.activity"),XA=Symbol.for("react.view_transition"),Wx=Symbol.iterator;function QA(e){return e===null||typeof e!="object"?null:(e=Wx&&e[Wx]||e["@@iterator"],typeof e=="function"?e:null)}var e1={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},t1=Object.assign,o1={};function pl(e,t,o){this.props=e,this.context=t,this.refs=o1,this.updater=o||e1}pl.prototype.isReactComponent={};pl.prototype.setState=function(e,t){if(typeof e!="object"&&typeof e!="function"&&e!=null)throw Error("takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,t,"setState")};pl.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")};function r1(){}r1.prototype=pl.prototype;function vg(e,t,o){this.props=e,this.context=t,this.refs=o1,this.updater=o||e1}var xg=vg.prototype=new r1;xg.constructor=vg;t1(xg,pl.prototype);xg.isPureReactComponent=!0;var Xx=Array.isArray;function Tg(){}var yt={H:null,A:null,T:null,S:null},n1=Object.prototype.hasOwnProperty;function Pg(e,t,o){var r=o.ref;return{$$typeof:bg,type:e,key:t,ref:r!==void 0?r:null,props:o}}function ZA(e,t){return Pg(e.type,t,e.props)}function Sg(e){return typeof e=="object"&&e!==null&&e.$$typeof===bg}function JA(e){var t={"=":"=0",":":"=2"};return"$"+e.replace(/[=:]/g,function(o){return t[o]})}var Qx=/\/+/g;function gg(e,t){return typeof e=="object"&&e!==null&&e.key!=null?JA(""+e.key):t.toString(36)}function e3(e){switch(e.status){case"fulfilled":return e.value;case"rejected":throw e.reason;default:switch(typeof e.status=="string"?e.then(Tg,Tg):(e.status="pending",e.then(function(t){e.status==="pending"&&(e.status="fulfilled",e.value=t)},function(t){e.status==="pending"&&(e.status="rejected",e.reason=t)})),e.status){case"fulfilled":return e.value;case"rejected":throw e.reason}}throw e}function ll(e,t,o,r,n){var a=typeof e;(a==="undefined"||a==="boolean")&&(e=null);var i=!1;if(e===null)i=!0;else switch(a){case"bigint":case"string":case"number":i=!0;break;case"object":switch(e.$$typeof){case bg:case IA:i=!0;break;case Jx:return i=e._init,ll(i(e._payload),t,o,r,n)}}if(i)return n=n(e),i=r===""?"."+gg(e,0):r,Xx(n)?(o="",i!=null&&(o=i.replace(Qx,"$&/")+"/"),ll(n,t,o,"",function(p){return p})):n!=null&&(Sg(n)&&(n=ZA(n,o+(n.key==null||e&&e.key===n.key?"":(""+n.key).replace(Qx,"$&/")+"/")+i)),t.push(n)),1;i=0;var s=r===""?".":r+":";if(Xx(e))for(var l=0;l<e.length;l++)r=e[l],a=s+gg(r,l),i+=ll(r,t,o,a,n);else if(l=QA(e),typeof l=="function")for(e=l.call(e),l=0;!(r=e.next()).done;)r=r.value,a=s+gg(r,l++),i+=ll(r,t,o,a,n);else if(a==="object"){if(typeof e.then=="function")return ll(e3(e),t,o,r,n);throw t=String(e),Error("Objects are not valid as a React child (found: "+(t==="[object Object]"?"object with keys {"+Object.keys(e).join(", ")+"}":t)+"). If you meant to render a collection of children, use an array instead.")}return i}function Jf(e,t,o){if(e==null)return e;var r=[],n=0;return ll(e,r,"","",function(a){return t.call(o,a,n++)}),r}function t3(e){if(e._status===-1){var t=e._result,o=t();o.then(function(r){(e._status===0||e._status===-1)&&(e._status=1,e._result=r,o.status===void 0&&(o.status="fulfilled",o.value=r))},function(r){(e._status===0||e._status===-1)&&(e._status=2,e._result=r,o.status===void 0&&(o.status="rejected",o.reason=r))}),e._status===-1&&(e._status=0,e._result=o)}if(e._status===1)return e._result.default;throw e._result}var Zx=typeof reportError=="function"?reportError:function(e){if(typeof window=="object"&&typeof window.ErrorEvent=="function"){var t=new window.ErrorEvent("error",{bubbles:!0,cancelable:!0,message:typeof e=="object"&&e!==null&&typeof e.message=="string"?String(e.message):String(e),error:e});if(!window.dispatchEvent(t))return}else if(typeof process=="object"&&typeof process.emit=="function"){process.emit("uncaughtException",e);return}console.error(e)};function a1(e){var t=yt.T,o={};o.types=t!==null?t.types:nullLine truncated
var V3=Object.create;var t1=Object.defineProperty;var F3=Object.getOwnPropertyDescriptor;var q3=Object.getOwnPropertyNames;var G3=Object.getPrototypeOf,Y3=Object.prototype.hasOwnProperty;var Yo=(e,t)=>()=>{try{return t||e((t={exports:{}}).exports,t),t.exports}catch(o){throw t=0,o}};var W3=(e,t,o,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of q3(t))!Y3.call(e,n)&&n!==o&&t1(e,n,{get:()=>t[n],enumerable:!(r=F3(t,n))||r.enumerable});return e};var C=(e,t,o)=>(o=e!=null?V3(G3(e)):{},W3(t||!e||!e.__esModule?t1(o,"default",{value:e,enumerable:!0}):o,e));var m1=Yo(Ne=>{"use strict";var Rg=Symbol.for("react.transitional.element"),K3=Symbol.for("react.portal"),X3=Symbol.for("react.fragment"),Q3=Symbol.for("react.strict_mode"),Z3=Symbol.for("react.profiler"),J3=Symbol.for("react.consumer"),eA=Symbol.for("react.context"),tA=Symbol.for("react.forward_ref"),oA=Symbol.for("react.suspense"),rA=Symbol.for("react.memo"),i1=Symbol.for("react.lazy"),nA=Symbol.for("react.activity"),aA=Symbol.for("react.view_transition"),o1=Symbol.iterator;function iA(e){return e===null||typeof e!="object"?null:(e=o1&&e[o1]||e["@@iterator"],typeof e=="function"?e:null)}var s1={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},l1=Object.assign,p1={};function gl(e,t,o){this.props=e,this.context=t,this.refs=p1,this.updater=o||s1}gl.prototype.isReactComponent={};gl.prototype.setState=function(e,t){if(typeof e!="object"&&typeof e!="function"&&e!=null)throw Error("takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,t,"setState")};gl.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")};function c1(){}c1.prototype=gl.prototype;function Og(e,t,o){this.props=e,this.context=t,this.refs=p1,this.updater=o||s1}var wg=Og.prototype=new c1;wg.constructor=Og;l1(wg,gl.prototype);wg.isPureReactComponent=!0;var r1=Array.isArray;function Eg(){}var bt={H:null,A:null,T:null,S:null},u1=Object.prototype.hasOwnProperty;function Ng(e,t,o){var r=o.ref;return{$$typeof:Rg,type:e,key:t,ref:r!==void 0?r:null,props:o}}function sA(e,t){return Ng(e.type,t,e.props)}function Mg(e){return typeof e=="object"&&e!==null&&e.$$typeof===Rg}function lA(e){var t={"=":"=0",":":"=2"};return"$"+e.replace(/[=:]/g,function(o){return t[o]})}var n1=/\/+/g;function Cg(e,t){return typeof e=="object"&&e!==null&&e.key!=null?lA(""+e.key):t.toString(36)}function pA(e){switch(e.status){case"fulfilled":return e.value;case"rejected":throw e.reason;default:switch(typeof e.status=="string"?e.then(Eg,Eg):(e.status="pending",e.then(function(t){e.status==="pending"&&(e.status="fulfilled",e.value=t)},function(t){e.status==="pending"&&(e.status="rejected",e.reason=t)})),e.status){case"fulfilled":return e.value;case"rejected":throw e.reason}}throw e}function hl(e,t,o,r,n){var a=typeof e;(a==="undefined"||a==="boolean")&&(e=null);var i=!1;if(e===null)i=!0;else switch(a){case"bigint":case"string":case"number":i=!0;break;case"object":switch(e.$$typeof){case Rg:case K3:i=!0;break;case i1:return i=e._init,hl(i(e._payload),t,o,r,n)}}if(i)return n=n(e),i=r===""?"."+Cg(e,0):r,r1(n)?(o="",i!=null&&(o=i.replace(n1,"$&/")+"/"),hl(n,t,o,"",function(p){return p})):n!=null&&(Mg(n)&&(n=sA(n,o+(n.key==null||e&&e.key===n.key?"":(""+n.key).replace(n1,"$&/")+"/")+i)),t.push(n)),1;i=0;var s=r===""?".":r+":";if(r1(e))for(var l=0;l<e.length;l++)r=e[l],a=s+Cg(r,l),i+=hl(r,t,o,a,n);else if(l=iA(e),typeof l=="function")for(e=l.call(e),l=0;!(r=e.next()).done;)r=r.value,a=s+Cg(r,l++),i+=hl(r,t,o,a,n);else if(a==="object"){if(typeof e.then=="function")return hl(pA(e),t,o,r,n);throw t=String(e),Error("Objects are not valid as a React child (found: "+(t==="[object Object]"?"object with keys {"+Object.keys(e).join(", ")+"}":t)+"). If you meant to render a collection of children, use an array instead.")}return i}function sd(e,t,o){if(e==null)return e;var r=[],n=0;return hl(e,r,"","",function(a){return t.call(o,a,n++)}),r}function cA(e){if(e._status===-1){var t=e._result,o=t();o.then(function(r){(e._status===0||e._status===-1)&&(e._status=1,e._result=r,o.status===void 0&&(o.status="fulfilled",o.value=r))},function(r){(e._status===0||e._status===-1)&&(e._status=2,e._result=r,o.status===void 0&&(o.status="rejected",o.reason=r))}),e._status===-1&&(e._status=0,e._result=o)}if(e._status===1)return e._result.default;throw e._result}var a1=typeof reportError=="function"?reportError:function(e){if(typeof window=="object"&&typeof window.ErrorEvent=="function"){var t=new window.ErrorEvent("error",{bubbles:!0,cancelable:!0,message:typeof e=="object"&&e!==null&&typeof e.message=="string"?String(e.message):String(e),error:e});if(!window.dispatchEvent(t))return}else if(typeof process=="object"&&typeof process.emit=="function"){process.emit("uncaughtException",e);return}console.error(e)};function f1(e){var t=bt.T,o={};o.types=t!==null?t.types:nullLine truncated
at`)?" (<anonymous>)":-1<o.stack.indexOf("@")?"@unknown:0:0":""}return`
`+Zb+e+Z2}var Jb=!1;function ev(e,t){if(!e||Jb)return"";Jb=!0;var o=Error.prepareStackTrace;Error.prepareStackTrace=void 0;try{var r={DetermineComponentFrameRoot:function(){try{if(t){var m=function(){throw Error()};if(Object.defineProperty(m.prototype,"props",{set:function(){throw Error()}}),typeof Reflect=="object"&&Reflect.construct){try{Reflect.construct(m,[])}catch(g){var f=g}Reflect.construct(e,[],m)}else{try{m.call()}catch(g){f=g}m=!1;try{var u=Object.getOwnPropertyDescriptor(e.prototype,"props");Object.defineProperty(e.prototype,"props",{configurable:!0,set:function(){throw Error()}}),m=!0,new e}finally{m&&(u!==void 0?Object.defineProperty(e.prototype,"props",u):delete e.prototype.props)}}}else{try{throw Error()}catch(g){f=g}(m=e())&&typeof m.catch=="function"&&m.catch(function(){})}}catch(g){if(g&&f&&typeof g.stack=="string")return[g.stack,f.stack]}return[null,null]}};r.DetermineComponentFrameRoot.displayName="DetermineComponentFrameRoot";var n=Object.getOwnPropertyDescriptor(r.DetermineComponentFrameRoot,"name");n&&n.configurable&&Object.defineProperty(r.DetermineComponentFrameRoot,"name",{value:"DetermineComponentFrameRoot"});var a=r.DetermineComponentFrameRoot(),i=a[0],s=a[1];if(i&&s){var l=i.split(`
`+av+e+aO}var iv=!1;function sv(e,t){if(!e||iv)return"";iv=!0;var o=Error.prepareStackTrace;Error.prepareStackTrace=void 0;try{var r={DetermineComponentFrameRoot:function(){try{if(t){var d=function(){throw Error()};if(Object.defineProperty(d.prototype,"props",{set:function(){throw Error()}}),typeof Reflect=="object"&&Reflect.construct){try{Reflect.construct(d,[])}catch(g){var f=g}Reflect.construct(e,[],d)}else{try{d.call()}catch(g){f=g}d=!1;try{var u=Object.getOwnPropertyDescriptor(e.prototype,"props");Object.defineProperty(e.prototype,"props",{configurable:!0,set:function(){throw Error()}}),d=!0,new e}finally{d&&(u!==void 0?Object.defineProperty(e.prototype,"props",u):delete e.prototype.props)}}}else{try{throw Error()}catch(g){f=g}(d=e())&&typeof d.catch=="function"&&d.catch(function(){})}}catch(g){if(g&&f&&typeof g.stack=="string")return[g.stack,f.stack]}return[null,null]}};r.DetermineComponentFrameRoot.displayName="DetermineComponentFrameRoot";var n=Object.getOwnPropertyDescriptor(r.DetermineComponentFrameRoot,"name");n&&n.configurable&&Object.defineProperty(r.DetermineComponentFrameRoot,"name",{value:"DetermineComponentFrameRoot"});var a=r.DetermineComponentFrameRoot(),i=a[0],s=a[1];if(i&&s){var l=i.split(`
`),p=s.split(`
`);for(n=r=0;r<l.length&&!l[r].includes("DetermineComponentFrameRoot");)r++;for(;n<p.length&&!p[n].includes("DetermineComponentFrameRoot");)n++;if(r===l.length||n===p.length)for(r=l.length-1,n=p.length-1;1<=r&&0<=n&&l[r]!==p[n];)n--;for(;1<=r&&0<=n;r--,n--)if(l[r]!==p[n]){if(r!==1||n!==1)do if(r--,n--,0>n||l[r]!==p[n]){var c=`
`+l[r].replace(" at new "," at ");return e.displayName&&c.includes("<anonymous>")&&(c=c.replace("<anonymous>",e.displayName)),c}while(1<=r&&0<=n);break}}}finally{Jb=!1,Error.prepareStackTrace=o}return(o=e?e.displayName||e.name:"")?xi(o):""}function gU(e,t){switch(e.tag){case 26:case 27:case 5:return xi(e.type);case 16:return xi("Lazy");case 13:return e.child!==t&&t!==null?xi("Suspense Fallback"):xi("Suspense");case 19:return xi("SuspenseList");case 0:case 15:return ev(e.type,!1);case 11:return ev(e.type.render,!1);case 1:return ev(e.type,!0);case 31:return xi("Activity");case 30:return xi("ViewTransition");default:return""}}function J2(e){try{var t="",o=null;do t+=gU(e,o),o=e,e=e.return;while(e);return t}catch(r){return`
`+l[r].replace(" at new "," at ");return e.displayName&&c.includes("<anonymous>")&&(c=c.replace("<anonymous>",e.displayName)),c}while(1<=r&&0<=n);break}}}finally{iv=!1,Error.prepareStackTrace=o}return(o=e?e.displayName||e.name:"")?Oi(o):""}function RU(e,t){switch(e.tag){case 26:case 27:case 5:return Oi(e.type);case 16:return Oi("Lazy");case 13:return e.child!==t&&t!==null?Oi("Suspense Fallback"):Oi("Suspense");case 19:return Oi("SuspenseList");case 0:case 15:return sv(e.type,!1);case 11:return sv(e.type.render,!1);case 1:return sv(e.type,!0);case 31:return Oi("Activity");case 30:return Oi("ViewTransition");default:return""}}function iO(e){try{var t="",o=null;do t+=RU(e,o),o=e,e=e.return;while(e);return t}catch(r){return`
Error generating stack: `+r.message+`
`+r.stack}}var Lv=Object.prototype.hasOwnProperty,$0=no.unstable_scheduleCallback,tv=no.unstable_cancelCallback,TU=no.unstable_shouldYield,bU=no.unstable_requestPaint,jr=no.unstable_now,vU=no.unstable_getCurrentPriorityLevel,Hw=no.unstable_ImmediatePriority,$w=no.unstable_UserBlockingPriority,vh=no.unstable_NormalPriority,xU=no.unstable_LowPriority,Vw=no.unstable_IdlePriority,PU=no.log,SU=no.unstable_setDisableYieldValue,If=null,Br=null;function Ri(e){if(typeof PU=="function"&&SU(e),Br&&typeof Br.setStrictMode=="function")try{Br.setStrictMode(If,e)}catch{}}var Ur=Math.clz32?Math.clz32:RU,CU=Math.log,EU=Math.LN2;function RU(e){return e>>>=0,e===0?32:31-(CU(e)/EU|0)|0}var Dy=256,ky=262144,_y=4194304;function Ls(e){var t=e&42;if(t!==0)return t;switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return e&-e;case 262144:case 524288:case 1048576:case 2097152:return e&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return e&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return e}}function Gh(e,t,o){var r=e.pendingLanes;if(r===0)return 0;var n=0,a=e.suspendedLanes,i=e.pingedLanes;e=e.warmLanes;var s=r&134217727;return s!==0?(r=s&~a,r!==0?n=Ls(r):(i&=s,i!==0?n=Ls(i):o||(o=s&~e,o!==0&&(n=Ls(o))))):(s=r&~a,s!==0?n=Ls(s):i!==0?n=Ls(i):o||(o=r&~e,o!==0&&(n=Ls(o)))),n===0?0:t!==0&&t!==n&&(t&a)===0&&(a=n&-n,o=t&-t,a>=o||a===32&&(o&4194048)!==0)?t:n}function Hf(e,t){return(e.pendingLanes&~(e.suspendedLanes&~e.pingedLanes)&t)===0}function Fw(e,t){(t&8)!==0&&(t|=t&32);var o=e.entangledLanes;if(o!==0)for(e=e.entanglements,o&=t;0<o;){var r=31-Ur(o),n=1<<r;t|=e[r],o&=~n}return t}function OU(e,t){switch(e){case 1:case 2:case 4:case 8:case 64:return t+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function qw(){var e=_y;return _y<<=1,(_y&62914560)===0&&(_y=4194304),e}function ov(e){for(var t=[],o=0;31>o;o++)t.push(e);return t}function $f(e,t){e.pendingLanes|=t,t!==268435456&&(e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0)}function wU(e,t,o,r,n,a){var i=e.pendingLanes;e.pendingLanes=o,e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0,e.expiredLanes&=o,e.entangledLanes&=o,e.errorRecoveryDisabledLanes&=o,e.shellSuspendCounter=0;var s=e.entanglements,l=e.expirationTimes,p=e.hiddenUpdates;for(o=i&~o;0<o;){var c=31-Ur(o),m=1<<c;s[c]=0,l[c]=-1;var f=p[c];if(f!==null)for(p[c]=null,c=0;c<f.length;c++){var u=f[c];u!==null&&(u.lane&=-536870913)}o&=~m}r!==0&&Gw(e,r,0),a!==0&&n===0&&e.tag!==0&&(e.suspendedLanes|=a&~(i&~t))}function Gw(e,t,o){e.pendingLanes|=t,e.suspendedLanes&=~t;var r=31-Ur(t);e.entangledLanes|=t,e.entanglements[r]=e.entanglements[r]|1073741824|o&261930}function Yw(e,t){var o=e.entangledLanes|=t;for(e=e.entanglements;o;){var r=31-Ur(o),n=1<<r;n&t|e[r]&t&&(e[r]|=t),o&=~n}}function Kw(e,t){var o=t&-t;return o=(o&42)!==0?1:V0(o),(o&(e.suspendedLanes|t))!==0?0:o}function V0(e){switch(e){case 2:e=1;break;case 8:e=4;break;case 32:e=16;break;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:case 4194304:case 8388608:case 16777216:case 33554432:e=128;break;case 268435456:e=134217728;break;default:e=0}return e}function F0(e){return e&=-e,2<e?8<e?(e&134217727)!==0?32:268435456:8:2}function Ww(){var e=Je.p;return e!==0?e:(e=window.event,e===void 0?32:MM(e.type))}function eO(e,t){var o=Je.p;try{return Je.p=e,t()}finally{Je.p=o}}var Wa=Math.random().toString(36).slice(2),Oo="__reactFiber$"+Wa,gr="__reactProps$"+Wa,yc="__reactContainer$"+Wa,tO="__reactEvents$"+Wa,NU="__reactListeners$"+Wa,MU="__reactHandles$"+Wa,oO="__reactResources$"+Wa,Vf="__reactMarker$"+Wa,xh="__reactLoad$"+Wa;function Yh(e){delete e[Oo],delete e[gr],delete e[NU],delete e[MU]}function $s(e){var t;if(t=e[Oo])return t;for(var o=e.parentNode;o;){if(t=o[yc]||o[Oo]){if(o=t.alternate,t.child!==null||o!==null&&o.child!==null)for(e=bw(e);e!==null;){if(o=e[Oo])return o;e=bw(e)}return t}e=o,o=e.parentNode}return null}function hc(e){if(e=e[Oo]||e[yc]){var t=e.tag;if(t===5||t===6||t===13||t===31||t===26||t===27||t===3)return e}return null}function sf(e){var t=e.tag;if(t===5||t===26||t===27||t===6)return e.stateNode;throw Error(V(33))}function Gp(e){var t=e[oO];return t||(t=e[oO]={hoistableStyles:new Map,hoistableScripts:new Map}),t}function yo(e){e[Vf]=!0}function Xw(e){e[xh]=void 0}var Qw=new Set,Zw={};function nl(e,t){rc(e,t),rc(e+"Capt Line truncated
`).replace(y8,"")}function sM(e,t){return t=pw(t),pw(e)===t}function it(e,t,o,r,n,a){switch(o){case"children":if(typeof r=="string")t==="body"||t==="textarea"&&r===""||nc(e,r);else if(typeof r=="number"||typeof r=="bigint")t!=="body"&&nc(e,""+r);else return;break;case"className":zy(e,"class",r);break;case"tabIndex":zy(e,"tabindex",r);break;case"dir":case"role":case"viewBox":case"width":case"height":zy(e,o,r);break;case"style":nN(e,r,a);return;case"data":if(t!=="object"){zy(e,"data",r);break}case"src":case"href":if(r===""&&(t!=="a"||o!=="href")){e.removeAttribute(o);break}if(r==null||typeof r=="function"||typeof r=="symbol"||typeof r=="boolean"){e.removeAttribute(o);break}r=Jy(r),e.setAttribute(o,r);break;case"action":case"formAction":if(typeof r=="function"){e.setAttribute(o,"javascript:throw new Error('A React form was unexpectedly submitted. If you called form.submit() manually, consider using form.requestSubmit() instead. If you\\'re trying to use event.stopPropagation() in a submit event handler, consider also calling event.preventDefault().')");break}else typeof a=="function"&&(o==="formAction"?(t!=="input"&&it(e,t,"name",n.name,n,null),it(e,t,"formEncType",n.formEncType,n,null),it(e,t,"formMethod",n.formMethod,n,null),it(e,t,"formTarget",n.formTarget,n,null)):(it(e,t,"encType",n.encType,n,null),it(e,t,"method",n.method,n,null),it(e,t,"target",n.target,n,null)));if(r==null||typeof r=="symbol"||typeof r=="boolean"){e.removeAttribute(o);break}r=Jy(r),e.setAttribute(o,r);break;case"onClick":r!=null&&(e.onclick=ra);return;case"onScroll":r!=null&&Ie("scroll",e);return;case"onScrollEnd":r!=null&&Ie("scrollend",e);return;case"dangerouslySetInnerHTML":if(r!=null){if(typeof r!="object"||!("__html"in r))throw Error(V(61));if(o=r.__html,o!=null){if(n.children!=null)throw Error(V(60));a?.__html!==o&&(e.innerHTML=o)}}break;case"multiple":e.multiple=r&&typeof r!="function"&&typeof r!="symbol";break;case"muted":e.muted=r&&typeof r!="function"&&typeof r!="symbol";break;case"suppressContentEditableWarning":case"suppressHydrationWarning":case"defaultValue":case"defaultChecked":case"innerHTML":case"ref":break;case"autoFocus":break;case"xlinkHref":if(r==null||typeof r=="function"||typeof r=="boolean"||typeof r=="symbol"){e.removeAttribute("xlink:href");break}o=Jy(r),e.setAttributeNS("http://www.w3.org/1999/xlink","xlink:href",o);break;case"contentEditable":case"spellCheck":case"draggable":case"value":case"autoReverse":case"externalResourcesRequired":case"focusable":case"preserveAlpha":r!=null&&typeof r!="function"&&typeof r!="symbol"?e.setAttribute(o,r):e.removeAttribute(o);break;case"inert":case"allowFullScreen":case"async":case"autoPlay":case"controls":case"credentialless":case"default":case"defer":case"disabled":case"disablePictureInPicture":case"disableRemotePlayback":case"formNoValidate":case"hidden":case"loop":case"noModule":case"noValidate":case"open":case"playsInline":case"readOnly":case"required":case"reversed":case"scoped":case"seamless":case"itemScope":r&&typeof r!="function"&&typeof r!="symbol"?e.setAttribute(o,""):e.removeAttribute(o);break;case"capture":case"download":r===!0?e.setAttribute(o,""):r!==!1&&r!=null&&typeof r!="function"&&typeof r!="symbol"?e.setAttribute(o,r):e.removeAttribute(o);break;case"cols":case"rows":case"size":case"span":r!=null&&typeof r!="function"&&typeof r!="symbol"&&!isNaN(r)&&1<=r?e.setAttribute(o,r):e.removeAttribute(o);break;case"rowSpan":case"start":r==null||typeof r=="function"||typeof r=="symbol"||isNaN(r)?e.removeAttribute(o):e.setAttribute(o,r);break;case"popover":Ie("beforetoggle",e),Ie("toggle",e),Zy(e,"popover",r);break;case"xlinkActuate":Ba(e,"http://www.w3.org/1999/xlink","xlink:actuate",r);break;case"xlinkArcrole":Ba(e,"http://www.w3.org/1999/xlink","xlink:arcrole",r);break;case"xlinkRole":Ba(e,"http://www.w3.org/1999/xlink","xlink:role",r);break;case"xlinkShow":Ba(e,"http://www.w3.org/1999/xlink","xlink:show",r);break;case"xlinkTitle":Ba(e,"http://www.w3.org/1999/xlink","xlink:title",r);break;case"xlinkType":Ba(e,"http://www.w3.org/1999/xlink","xlink:type",r);break;case"xmlBase":Ba(e,"http://www.w3.org/XML/1998/namespace","xml:base",r);break;case"xmlLang":Ba(e,"http://www.w3.org/XML/1998/namespace","xml:lang",r);break;case"xmlSpace":Ba(e,"http://www.w3.org/XML/1998/namespace","xml:space",r);break;case"is":Zy(e,"is",r);break;case"innerText":case"textContent":return;default:if(!(2<o.length)||o[0]!=="o"&&o[0]!=="O"||o[1]!=="n"&&o[1]!=="N")o=jU.get(o)||o,Zy(e,o,r);else return}Qe=!0}function N0(e,t,o,r,n,a){switch(o){case"style":nN(e,r,a);return;case"dangerouslySetInnerHTML":if(r!=null){if(typeof r!="object"||!("__html"in r))throw Error(V(61));if(o=r.__html,o!=null){if(n.children!=null)throw Error(V(60));a?.__html!==o&&(e.innerHTML=o)}}break;case"children":if(typeof r=="string")nc(e,r);else if(typeof r=="number"||typeof r=="bigint")nc(e,""+r);else return;break;case"onScroll":r!=null&&Ie("scroll",e);return;case"onScrollEnd":r!=null&&Ie("scrollend",e);return;case"onClick":r Line truncated
`)),(MP!==void 0?dD:uD)(m,s,l,p,c)}}var xF=Xg();function mD(e,t=Number.MIN_SAFE_INTEGER,o=Number.MAX_SAFE_INTEGER){return Math.max(t,Math.min(e,o))}var Qg=mD;function Jg(e,t=0,o=1){return Qg(e,t,o)}function yD(e){e=e.slice(1);let t=new RegExp(`.{1,${e.length>=6?2:1}}`,"g"),o=e.match(t);return o&&o[0].length===1&&(o=o.map(r=>r+r)),o?`rgb${o.length===4?"a":""}(${o.map((r,n)=>n<3?parseInt(r,16):Math.round(parseInt(r,16)/255*1e3)/1e3).join(", ")})`:""}function oi(e){if(e.type)return e;if(e.charAt(0)==="#")return oi(yD(e));let t=e.indexOf("("),o=e.substring(0,t);if(!["rgb","rgba","hsl","hsla","color"].includes(o))throw new Error(io(9,e));let r=e.substring(t+1,e.length-1),n;if(o==="color"){if(r=r.split(" "),n=r.shift(),r.length===4&&r[3].charAt(0)==="/"&&(r[3]=r[3].slice(1)),!["srgb","display-p3","a98-rgb","prophoto-rgb","rec-2020"].includes(n))throw new Error(io(10,n))}else r=r.split(",");return r=r.map(a=>parseFloat(a)),{type:o,values:r,colorSpace:n}}var hD=e=>{let t=oi(e);return t.values.slice(0,3).map((o,r)=>t.type.includes("hsl")&&r!==0?`${o}%`:o).join(" ")},Al=(e,t)=>{try{return hD(e)}catch{return e}};function Hd(e){let{type:t,colorSpace:o}=e,{values:r}=e;return t.includes("rgb")?r=r.map((n,a)=>a<3?parseInt(n,10):n):t.includes("hsl")&&(r[1]=`${r[1]}%`,r[2]=`${r[2]}%`),t.includes("color")?r=`${o} ${r.join(" ")}`:r=`${r.join(", ")}`,`${t}(${r})`}function eT(e){e=oi(e);let{values:t}=e,o=t[0],r=t[1]/100,n=t[2]/100,a=r*Math.min(n,1-n),i=(p,c=(p+o/30)%12)=>n-a*Math.max(Math.min(c-3,9-c,1),-1),s="rgb",l=[Math.round(i(0)*255),Math.round(i(8)*255),Math.round(i(4)*255)];return e.type==="hsla"&&(s+="a",l.push(t[3])),Hd({type:s,values:l})}function Zg(e){e=oi(e);let t=e.type==="hsl"||e.type==="hsla"?oi(eT(e)).values:e.values;return t=t.map(o=>(e.type!=="color"&&(o/=255),o<=.03928?o/12.92:((o+.055)/1.055)**2.4)),Number((.2126*t[0]+.7152*t[1]+.0722*t[2]).toFixed(3))}function AP(e,t){let o=Zg(e),r=Zg(t);return(Math.max(o,r)+.05)/(Math.min(o,r)+.05)}function ri(e,t){return e=oi(e),t=Jg(t),(e.type==="rgb"||e.type==="hsl")&&(e.type+="a"),e.type==="color"?e.values[3]=`/${t}`:e.values[3]=t,Hd(e)}function ni(e,t,o){try{return ri(e,t)}catch{return e}}function Dl(e,t){if(e=oi(e),t=Jg(t),e.type.includes("hsl"))e.values[2]*=1-t;else if(e.type.includes("rgb")||e.type.includes("color"))for(let o=0;o<3;o+=1)e.values[o]*=1-t;return Hd(e)}function et(e,t,o){try{return Dl(e,t)}catch{return e}}function kl(e,t){if(e=oi(e),t=Jg(t),e.type.includes("hsl"))e.values[2]+=(100-e.values[2])*t;else if(e.type.includes("rgb"))for(let o=0;o<3;o+=1)e.values[o]+=(255-e.values[o])*t;else if(e.type.includes("color"))for(let o=0;o<3;o+=1)e.values[o]+=(1-e.values[o])*t;return Hd(e)}function tt(e,t,o){try{return kl(e,t)}catch{return e}}function $d(e,t=.15){return Zg(e)>.5?Dl(e,t):kl(e,t)}function Vc(e,t,o){try{return $d(e,t)}catch{return e}}var GP=C(I(),1);var _P=C(I(),1);var DP=C(I(),1),gD=DP.createContext(null),Vd=gD;var tT=C(I(),1);function ga(){return tT.useContext(Vd)}var TD=typeof Symbol=="function"&&Symbol.for,kP=TD?Symbol.for("mui.nested"):"__THEME_NESTED__";var zP=C(U(),1);function bD(e,t){return typeof t=="function"?t(e):{...e,...t}}function vD(e){let{children:t,theme:o}=e,r=ga(),n=_P.useMemo(()=>{let a=r===null?{...o}:bD(r,o);return a!=null&&(a[kP]=r!==null),a},[o,r]);return(0,zP.jsx)(Vd.Provider,{value:n,children:t})}var Fd=vD;var qd=C(I(),1);var jP=C(U(),1),BP=qd.createContext();function xD({value:e,...t}){return(0,jP.jsx)(BP.Provider,{value:e??!0,...t})}var ai=()=>qd.useContext(BP)??!1,UP=xD;var Gd=C(I(),1);var LP=C(U(),1),IP=Gd.createContext(void 0);function PD({value:e,children:t}){return(0,LP.jsx)(IP.Provider,{value:e,children:t})}function SD(e){let{theme:t,name:o,props:r}=e;if(!t||!t.components||!t.components[o])return r;let n=t.components[o];return n.defaultProps?qn(n.defaultProps,r,t.components.mergeClassNameAndStyle):!n.styleOverrides&&!n.variants?qn(n,r,t.components.mergeClassNameAndStyle):r}function oT({props:e,name:t}){let o=Gd.useContext(IP);return SD({props:e,name:t,theme:{components:o}})}var Yd=PD;var Fc=C(I(),1),HP=0;function CD(e){let[t,o]=Fc.useState(e),r=e||t;return Fc.useEffect(()=>{t==null&&(HP+=1,o(`mui-${HP}`))},[t]),r}var ED={...Fc},$P=ED.useId;function Yr(e){if($P!==void 0){let t=$P();return e??t}return CD(e)}var VP=C(U(),1);function rT(e){let t=ya(),o=Yr()||"",{modularCssLayers:r}=e,n="mui.global, mui.components, mui.theme, mui.custom, mui.sx";return!r||t!==null?n="":typeof r=="string"?n=r.replace(/mui(?!\.)/g,n):n=`@layer ${n};`,Gt(()=>{let a=document.querySelector("head");if(!a)return;let i=a.firstChild;if(n){if(i&&i.hasAttribute?.("data-mui-layer-order")&&i.getAttribute("data-mui-layer-order")===o)return;let s=document.createElement("style");s.setAttribute("data-mui-layer-order",o),s.textContent=n,a.prepend(s)}else a.querySelector(`style[data-mui-layer-order="${o}"]`)?.remove()},[n,o]),n?(0,VP.jsx)(Rl,{styles:n}):null}var _l=C(U(),1),FP={};function qP(e,t,o,r=!1){return GP.useMemo(()=>{let n=e&&t[e]||t;if(typeof o=="f Line truncated
${s}.classList.add('${f}'.replace('%s', colorScheme));`}let m=c.match(/\[([^[\]]+)\]/);if(m){let[f,u]=m[1].split("=");u||(p+=`${s}.removeAttribute('${f}'.replace('%s', light));
`+r.stack}}var Gv=Object.prototype.hasOwnProperty,K0=co.unstable_scheduleCallback,lv=co.unstable_cancelCallback,OU=co.unstable_shouldYield,wU=co.unstable_requestPaint,jr=co.unstable_now,NU=co.unstable_getCurrentPriorityLevel,Ww=co.unstable_ImmediatePriority,Kw=co.unstable_UserBlockingPriority,wh=co.unstable_NormalPriority,MU=co.unstable_LowPriority,Xw=co.unstable_IdlePriority,AU=co.log,kU=co.unstable_setDisableYieldValue,Yf=null,Br=null;function ki(e){if(typeof AU=="function"&&kU(e),Br&&typeof Br.setStrictMode=="function")try{Br.setStrictMode(Yf,e)}catch{}}var Ur=Math.clz32?Math.clz32:zU,DU=Math.log,_U=Math.LN2;function zU(e){return e>>>=0,e===0?32:31-(DU(e)/_U|0)|0}var Iy=256,$y=262144,Hy=4194304;function Gs(e){var t=e&42;if(t!==0)return t;switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return e&-e;case 262144:case 524288:case 1048576:case 2097152:return e&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return e&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return e}}function eg(e,t,o){var r=e.pendingLanes;if(r===0)return 0;var n=0,a=e.suspendedLanes,i=e.pingedLanes;e=e.warmLanes;var s=r&134217727;return s!==0?(r=s&~a,r!==0?n=Gs(r):(i&=s,i!==0?n=Gs(i):o||(o=s&~e,o!==0&&(n=Gs(o))))):(s=r&~a,s!==0?n=Gs(s):i!==0?n=Gs(i):o||(o=r&~e,o!==0&&(n=Gs(o)))),n===0?0:t!==0&&t!==n&&(t&a)===0&&(a=n&-n,o=t&-t,a>=o||a===32&&(o&4194048)!==0)?t:n}function Wf(e,t){return(e.pendingLanes&~(e.suspendedLanes&~e.pingedLanes)&t)===0}function Qw(e,t){(t&8)!==0&&(t|=t&32);var o=e.entangledLanes;if(o!==0)for(e=e.entanglements,o&=t;0<o;){var r=31-Ur(o),n=1<<r;t|=e[r],o&=~n}return t}function jU(e,t){switch(e){case 1:case 2:case 4:case 8:case 64:return t+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function Zw(){var e=Hy;return Hy<<=1,(Hy&62914560)===0&&(Hy=4194304),e}function pv(e){for(var t=[],o=0;31>o;o++)t.push(e);return t}function Kf(e,t){e.pendingLanes|=t,t!==268435456&&(e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0)}function BU(e,t,o,r,n,a){var i=e.pendingLanes;e.pendingLanes=o,e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0,e.expiredLanes&=o,e.entangledLanes&=o,e.errorRecoveryDisabledLanes&=o,e.shellSuspendCounter=0;var s=e.entanglements,l=e.expirationTimes,p=e.hiddenUpdates;for(o=i&~o;0<o;){var c=31-Ur(o),d=1<<c;s[c]=0,l[c]=-1;var f=p[c];if(f!==null)for(p[c]=null,c=0;c<f.length;c++){var u=f[c];u!==null&&(u.lane&=-536870913)}o&=~d}r!==0&&Jw(e,r,0),a!==0&&n===0&&e.tag!==0&&(e.suspendedLanes|=a&~(i&~t))}function Jw(e,t,o){e.pendingLanes|=t,e.suspendedLanes&=~t;var r=31-Ur(t);e.entangledLanes|=t,e.entanglements[r]=e.entanglements[r]|1073741824|o&261930}function e5(e,t){var o=e.entangledLanes|=t;for(e=e.entanglements;o;){var r=31-Ur(o),n=1<<r;n&t|e[r]&t&&(e[r]|=t),o&=~n}}function t5(e,t){var o=t&-t;return o=(o&42)!==0?1:X0(o),(o&(e.suspendedLanes|t))!==0?0:o}function X0(e){switch(e){case 2:e=1;break;case 8:e=4;break;case 32:e=16;break;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:case 4194304:case 8388608:case 16777216:case 33554432:e=128;break;case 268435456:e=134217728;break;default:e=0}return e}function Q0(e){return e&=-e,2<e?8<e?(e&134217727)!==0?32:268435456:8:2}function o5(){var e=Qe.p;return e!==0?e:(e=window.event,e===void 0?32:BM(e.type))}function sO(e,t){var o=Qe.p;try{return Qe.p=e,t()}finally{Qe.p=o}}var Ja=Math.random().toString(36).slice(2),Do="__reactFiber$"+Ja,vr="__reactProps$"+Ja,Cc="__reactContainer$"+Ja,lO="__reactEvents$"+Ja,UU="__reactListeners$"+Ja,LU="__reactHandles$"+Ja,pO="__reactResources$"+Ja,Xf="__reactMarker$"+Ja,Nh="__reactLoad$"+Ja;function tg(e){delete e[Do],delete e[vr],delete e[UU],delete e[LU]}function Ks(e){var t;if(t=e[Do])return t;for(var o=e.parentNode;o;){if(t=o[Cc]||o[Do]){if(o=t.alternate,t.child!==null||o!==null&&o.child!==null)for(e=Rw(e);e!==null;){if(o=e[Do])return o;e=Rw(e)}return t}e=o,o=e.parentNode}return null}function Ec(e){if(e=e[Do]||e[Cc]){var t=e.tag;if(t===5||t===6||t===13||t===31||t===26||t===27||t===3)return e}return null}function mf(e){var t=e.tag;if(t===5||t===26||t===27||t===6)return e.stateNode;throw Error(F(33))}function tc(e){var t=e[pO];return t||(t=e[pO]={hoistableStyles:new Map,hoistableScripts:new Map}),t}function xo(e){e[Xf]=!0}function r5(e){e[Nh]=void 0}var n5=new Set,a5={};function ul(e,t){fc(e,t),fc(e+"Capt Line truncated
`).replace(CL,"")}function mM(e,t){return t=hw(t),hw(e)===t}function it(e,t,o,r,n,a){switch(o){case"children":if(typeof r=="string")t==="body"||t==="textarea"&&r===""||dc(e,r);else if(typeof r=="number"||typeof r=="bigint")t!=="body"&&dc(e,""+r);else return;break;case"className":Vy(e,"class",r);break;case"tabIndex":Vy(e,"tabindex",r);break;case"dir":case"role":case"viewBox":case"width":case"height":Vy(e,o,r);break;case"style":u5(e,r,a);return;case"data":if(t!=="object"){Vy(e,"data",r);break}case"src":case"href":if(r===""&&(t!=="a"||o!=="href")){e.removeAttribute(o);break}if(r==null||typeof r=="function"||typeof r=="symbol"||typeof r=="boolean"){e.removeAttribute(o);break}r=sh(r),e.setAttribute(o,r);break;case"action":case"formAction":if(typeof r=="function"){e.setAttribute(o,"javascript:throw new Error('A React form was unexpectedly submitted. If you called form.submit() manually, consider using form.requestSubmit() instead. If you\\'re trying to use event.stopPropagation() in a submit event handler, consider also calling event.preventDefault().')");break}else typeof a=="function"&&(o==="formAction"?(t!=="input"&&it(e,t,"name",n.name,n,null),it(e,t,"formEncType",n.formEncType,n,null),it(e,t,"formMethod",n.formMethod,n,null),it(e,t,"formTarget",n.formTarget,n,null)):(it(e,t,"encType",n.encType,n,null),it(e,t,"method",n.method,n,null),it(e,t,"target",n.target,n,null)));if(r==null||typeof r=="symbol"||typeof r=="boolean"){e.removeAttribute(o);break}r=sh(r),e.setAttribute(o,r);break;case"onClick":r!=null&&(e.onclick=ia);return;case"onScroll":r!=null&&Ie("scroll",e);return;case"onScrollEnd":r!=null&&Ie("scrollend",e);return;case"dangerouslySetInnerHTML":if(r!=null){if(typeof r!="object"||!("__html"in r))throw Error(F(61));if(o=r.__html,o!=null){if(n.children!=null)throw Error(F(60));a?.__html!==o&&(e.innerHTML=o)}}break;case"multiple":e.multiple=r&&typeof r!="function"&&typeof r!="symbol";break;case"muted":e.muted=r&&typeof r!="function"&&typeof r!="symbol";break;case"suppressContentEditableWarning":case"suppressHydrationWarning":case"defaultValue":case"defaultChecked":case"innerHTML":case"ref":break;case"autoFocus":break;case"xlinkHref":if(r==null||typeof r=="function"||typeof r=="boolean"||typeof r=="symbol"){e.removeAttribute("xlink:href");break}o=sh(r),e.setAttributeNS("http://www.w3.org/1999/xlink","xlink:href",o);break;case"contentEditable":case"spellCheck":case"draggable":case"value":case"autoReverse":case"externalResourcesRequired":case"focusable":case"preserveAlpha":r!=null&&typeof r!="function"&&typeof r!="symbol"?e.setAttribute(o,r):e.removeAttribute(o);break;case"inert":case"allowFullScreen":case"async":case"autoPlay":case"controls":case"credentialless":case"default":case"defer":case"disabled":case"disablePictureInPicture":case"disableRemotePlayback":case"formNoValidate":case"hidden":case"loop":case"noModule":case"noValidate":case"open":case"playsInline":case"readOnly":case"required":case"reversed":case"scoped":case"seamless":case"itemScope":r&&typeof r!="function"&&typeof r!="symbol"?e.setAttribute(o,""):e.removeAttribute(o);break;case"capture":case"download":r===!0?e.setAttribute(o,""):r!==!1&&r!=null&&typeof r!="function"&&typeof r!="symbol"?e.setAttribute(o,r):e.removeAttribute(o);break;case"cols":case"rows":case"size":case"span":r!=null&&typeof r!="function"&&typeof r!="symbol"&&!isNaN(r)&&1<=r?e.setAttribute(o,r):e.removeAttribute(o);break;case"rowSpan":case"start":r==null||typeof r=="function"||typeof r=="symbol"||isNaN(r)?e.removeAttribute(o):e.setAttribute(o,r);break;case"popover":Ie("beforetoggle",e),Ie("toggle",e),ih(e,"popover",r);break;case"xlinkActuate":$a(e,"http://www.w3.org/1999/xlink","xlink:actuate",r);break;case"xlinkArcrole":$a(e,"http://www.w3.org/1999/xlink","xlink:arcrole",r);break;case"xlinkRole":$a(e,"http://www.w3.org/1999/xlink","xlink:role",r);break;case"xlinkShow":$a(e,"http://www.w3.org/1999/xlink","xlink:show",r);break;case"xlinkTitle":$a(e,"http://www.w3.org/1999/xlink","xlink:title",r);break;case"xlinkType":$a(e,"http://www.w3.org/1999/xlink","xlink:type",r);break;case"xmlBase":$a(e,"http://www.w3.org/XML/1998/namespace","xml:base",r);break;case"xmlLang":$a(e,"http://www.w3.org/XML/1998/namespace","xml:lang",r);break;case"xmlSpace":$a(e,"http://www.w3.org/XML/1998/namespace","xml:space",r);break;case"is":ih(e,"is",r);break;case"innerText":case"textContent":return;default:if(!(2<o.length)||o[0]!=="o"&&o[0]!=="O"||o[1]!=="n"&&o[1]!=="N")o=qU.get(o)||o,ih(e,o,r);else return}Ke=!0}function j0(e,t,o,r,n,a){switch(o){case"style":u5(e,r,a);return;case"dangerouslySetInnerHTML":if(r!=null){if(typeof r!="object"||!("__html"in r))throw Error(F(61));if(o=r.__html,o!=null){if(n.children!=null)throw Error(F(60));a?.__html!==o&&(e.innerHTML=o)}}break;case"children":if(typeof r=="string")dc(e,r);else if(typeof r=="number"||typeof r=="bigint")dc(e,""+r);else return;break;case"onScroll":r!=null&&Ie("scroll",e);return;case"onScrollEnd":r!=null&&Ie("scrollend",e);return;case"onClick":r Line truncated
`)),(BP!==void 0?Pk:vk)(d,s,l,p,c)}}var NF=rT();function Sk(e,t=Number.MIN_SAFE_INTEGER,o=Number.MAX_SAFE_INTEGER){return Math.max(t,Math.min(e,o))}var nT=Sk;function iT(e,t=0,o=1){return nT(e,t,o)}function Ck(e){e=e.slice(1);let t=new RegExp(`.{1,${e.length>=6?2:1}}`,"g"),o=e.match(t);return o&&o[0].length===1&&(o=o.map(r=>r+r)),o?`rgb${o.length===4?"a":""}(${o.map((r,n)=>n<3?parseInt(r,16):Math.round(parseInt(r,16)/255*1e3)/1e3).join(", ")})`:""}function si(e){if(e.type)return e;if(e.charAt(0)==="#")return si(Ck(e));let t=e.indexOf("("),o=e.substring(0,t);if(!["rgb","rgba","hsl","hsla","color"].includes(o))throw new Error(uo(9,e));let r=e.substring(t+1,e.length-1),n;if(o==="color"){if(r=r.split(" "),n=r.shift(),r.length===4&&r[3].charAt(0)==="/"&&(r[3]=r[3].slice(1)),!["srgb","display-p3","a98-rgb","prophoto-rgb","rec-2020"].includes(n))throw new Error(uo(10,n))}else r=r.split(",");return r=r.map(a=>parseFloat(a)),{type:o,values:r,colorSpace:n}}var Ek=e=>{let t=si(e);return t.values.slice(0,3).map((o,r)=>t.type.includes("hsl")&&r!==0?`${o}%`:o).join(" ")},Ll=(e,t)=>{try{return Ek(e)}catch{return e}};function Kd(e){let{type:t,colorSpace:o}=e,{values:r}=e;return t.includes("rgb")?r=r.map((n,a)=>a<3?parseInt(n,10):n):t.includes("hsl")&&(r[1]=`${r[1]}%`,r[2]=`${r[2]}%`),t.includes("color")?r=`${o} ${r.join(" ")}`:r=`${r.join(", ")}`,`${t}(${r})`}function sT(e){e=si(e);let{values:t}=e,o=t[0],r=t[1]/100,n=t[2]/100,a=r*Math.min(n,1-n),i=(p,c=(p+o/30)%12)=>n-a*Math.max(Math.min(c-3,9-c,1),-1),s="rgb",l=[Math.round(i(0)*255),Math.round(i(8)*255),Math.round(i(4)*255)];return e.type==="hsla"&&(s+="a",l.push(t[3])),Kd({type:s,values:l})}function aT(e){e=si(e);let t=e.type==="hsl"||e.type==="hsla"?si(sT(e)).values:e.values;return t=t.map(o=>(e.type!=="color"&&(o/=255),o<=.03928?o/12.92:((o+.055)/1.055)**2.4)),Number((.2126*t[0]+.7152*t[1]+.0722*t[2]).toFixed(3))}function UP(e,t){let o=aT(e),r=aT(t);return(Math.max(o,r)+.05)/(Math.min(o,r)+.05)}function li(e,t){return e=si(e),t=iT(t),(e.type==="rgb"||e.type==="hsl")&&(e.type+="a"),e.type==="color"?e.values[3]=`/${t}`:e.values[3]=t,Kd(e)}function pi(e,t,o){try{return li(e,t)}catch{return e}}function Il(e,t){if(e=si(e),t=iT(t),e.type.includes("hsl"))e.values[2]*=1-t;else if(e.type.includes("rgb")||e.type.includes("color"))for(let o=0;o<3;o+=1)e.values[o]*=1-t;return Kd(e)}function Je(e,t,o){try{return Il(e,t)}catch{return e}}function $l(e,t){if(e=si(e),t=iT(t),e.type.includes("hsl"))e.values[2]+=(100-e.values[2])*t;else if(e.type.includes("rgb"))for(let o=0;o<3;o+=1)e.values[o]+=(255-e.values[o])*t;else if(e.type.includes("color"))for(let o=0;o<3;o+=1)e.values[o]+=(1-e.values[o])*t;return Kd(e)}function et(e,t,o){try{return $l(e,t)}catch{return e}}function Xd(e,t=.15){return aT(e)>.5?Il(e,t):$l(e,t)}function Zc(e,t,o){try{return Xd(e,t)}catch{return e}}var JP=C(I(),1);var $P=C(I(),1);var LP=C(I(),1),Rk=LP.createContext(null),Qd=Rk;var lT=C(I(),1);function xa(){return lT.useContext(Qd)}var Ok=typeof Symbol=="function"&&Symbol.for,IP=Ok?Symbol.for("mui.nested"):"__THEME_NESTED__";var HP=C(z(),1);function wk(e,t){return typeof t=="function"?t(e):{...e,...t}}function Nk(e){let{children:t,theme:o}=e,r=xa(),n=$P.useMemo(()=>{let a=r===null?{...o}:wk(r,o);return a!=null&&(a[IP]=r!==null),a},[o,r]);return(0,HP.jsx)(Qd.Provider,{value:n,children:t})}var Zd=Nk;var Jd=C(I(),1);var VP=C(z(),1),FP=Jd.createContext();function Mk({value:e,...t}){return(0,VP.jsx)(FP.Provider,{value:e??!0,...t})}var ci=()=>Jd.useContext(FP)??!1,qP=Mk;var em=C(I(),1);var GP=C(z(),1),YP=em.createContext(void 0);function Ak({value:e,children:t}){return(0,GP.jsx)(YP.Provider,{value:e,children:t})}function kk(e){let{theme:t,name:o,props:r}=e;if(!t||!t.components||!t.components[o])return r;let n=t.components[o];return n.defaultProps?Wn(n.defaultProps,r,t.components.mergeClassNameAndStyle):!n.styleOverrides&&!n.variants?Wn(n,r,t.components.mergeClassNameAndStyle):r}function pT({props:e,name:t}){let o=em.useContext(YP);return kk({props:e,name:t,theme:{components:o}})}var tm=Ak;var Jc=C(I(),1),WP=0;function Dk(e){let[t,o]=Jc.useState(e),r=e||t;return Jc.useEffect(()=>{t==null&&(WP+=1,o(`mui-${WP}`))},[t]),r}var _k={...Jc},KP=_k.useId;function Wr(e){if(KP!==void 0){let t=KP();return e??t}return Dk(e)}var XP=C(z(),1);function cT(e){let t=ba(),o=Wr()||"",{modularCssLayers:r}=e,n="mui.global, mui.components, mui.theme, mui.custom, mui.sx";return!r||t!==null?n="":typeof r=="string"?n=r.replace(/mui(?!\.)/g,n):n=`@layer ${n};`,Xt(()=>{let a=document.querySelector("head");if(!a)return;let i=a.firstChild;if(n){if(i&&i.hasAttribute?.("data-mui-layer-order")&&i.getAttribute("data-mui-layer-order")===o)return;let s=document.createElement("style");s.setAttribute("data-mui-layer-order",o),s.textContent=n,a.prepend(s)}else a.querySelector(`style[data-mui-layer-order="${o}"]`)?.remove()},[n,o]),n?(0,XP.jsx)(_l,{styles:n}):null}var Hl=C(z(),1),QP={};function ZP(e,t,o,r=!1){return JP.useMemo(()=>{let n=e&&t[e]||t;if(typeof o=="f Line truncated
${s}.classList.add('${f}'.replace('%s', colorScheme));`}let d=c.match(/\[([^[\]]+)\]/);if(d){let[f,u]=d[1].split("=");u||(p+=`${s}.removeAttribute('${f}'.replace('%s', light));
${s}.removeAttribute('${f}'.replace('%s', dark));`),p+=`
${s}.setAttribute('${f}'.replace('%s', colorScheme), ${u?`${u}.replace('%s', colorScheme)`:'""'});`}else c!==".%s"&&(p+=`${s}.setAttribute('${c}', colorScheme);`);return(0,KP.jsx)("script",{suppressHydrationWarning:!0,nonce:typeof window>"u"?l:"",dangerouslySetInnerHTML:{__html:`(function() {
${s}.setAttribute('${f}'.replace('%s', colorScheme), ${u?`${u}.replace('%s', colorScheme)`:'""'});`}else c!==".%s"&&(p+=`${s}.setAttribute('${c}', colorScheme);`);return(0,tS.jsx)("script",{suppressHydrationWarning:!0,nonce:typeof window>"u"?l:"",dangerouslySetInnerHTML:{__html:`(function() {
try {
let colorScheme = '';
const mode = localStorage.getItem('${n}') || '${t}';
@@ -34,15 +34,15 @@ try {
if (colorScheme) {
${p}
}
} catch(e){}})();`}},"mui-color-scheme-init")}var xo=C(I(),1);function wD(){}var ND=({key:e,storageWindow:t})=>(!t&&typeof window<"u"&&(t=window),{get(o){if(typeof window>"u")return;if(!t)return o;let r;try{r=t.localStorage.getItem(e)}catch{}return r||o},set:o=>{if(t)try{t.localStorage.setItem(e,o)}catch{}},subscribe:o=>{if(!t)return wD;let r=n=>{let a=n.newValue;n.key===e&&o(a)};return t.addEventListener("storage",r),()=>{t.removeEventListener("storage",r)}}}),WP=ND;function aT(){}function XP(e){if(typeof window<"u"&&typeof window.matchMedia=="function"&&e==="system")return window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"}function QP(e,t){if(e.mode==="light"||e.mode==="system"&&e.systemMode==="light")return t("light");if(e.mode==="dark"||e.mode==="system"&&e.systemMode==="dark")return t("dark")}function MD(e){return QP(e,t=>{if(t==="light")return e.lightColorScheme;if(t==="dark")return e.darkColorScheme})}function iT(e){let{defaultMode:t="light",defaultLightColorScheme:o,defaultDarkColorScheme:r,supportedColorSchemes:n=[],modeStorageKey:a=qc,colorSchemeStorageKey:i=Gc,storageWindow:s=typeof window>"u"?void 0:window,storageManager:l=WP,noSsr:p=!1}=e,c=n.join(","),m=n.length>1,f=xo.useMemo(()=>l?.({key:a,storageWindow:s}),[l,a,s]),u=xo.useMemo(()=>l?.({key:`${i}-light`,storageWindow:s}),[l,i,s]),g=xo.useMemo(()=>l?.({key:`${i}-dark`,storageWindow:s}),[l,i,s]),[v,x]=xo.useState(()=>{let R=f?.get(t)||t,w=u?.get(o)||o,O=g?.get(r)||r;return{mode:R,systemMode:XP(R),lightColorScheme:w,darkColorScheme:O}}),[d,y]=xo.useState(p||!m);xo.useEffect(()=>{y(!0)},[]);let h=MD(v),T=xo.useCallback(R=>{x(w=>{if(R===w.mode)return w;let O=R??t;return f?.set(O),{...w,mode:O,systemMode:XP(O)}})},[f,t]),P=xo.useCallback(R=>{R?typeof R=="string"?R&&!c.includes(R)?console.error(`\`${R}\` does not exist in \`theme.colorSchemes\`.`):x(w=>{let O={...w};return QP(w,N=>{N==="light"&&(u?.set(R),O.lightColorScheme=R),N==="dark"&&(g?.set(R),O.darkColorScheme=R)}),O}):x(w=>{let O={...w},N=R.light===null?o:R.light,b=R.dark===null?r:R.dark;return N&&(c.includes(N)?(O.lightColorScheme=N,u?.set(N)):console.error(`\`${N}\` does not exist in \`theme.colorSchemes\`.`)),b&&(c.includes(b)?(O.darkColorScheme=b,g?.set(b)):console.error(`\`${b}\` does not exist in \`theme.colorSchemes\`.`)),O}):x(w=>(u?.set(o),g?.set(r),{...w,lightColorScheme:o,darkColorScheme:r}))},[c,u,g,o,r]),S=xo.useCallback(R=>{v.mode==="system"&&x(w=>{let O=R?.matches?"dark":"light";return w.systemMode===O?w:{...w,systemMode:O}})},[v.mode]),E=xo.useRef(S);return E.current=S,xo.useEffect(()=>{if(typeof window.matchMedia!="function"||!m)return;let R=(...O)=>E.current(...O),w=window.matchMedia("(prefers-color-scheme: dark)");return w.addListener(R),R(w),()=>{w.removeListener(R)}},[m]),xo.useEffect(()=>{if(m){let R=f?.subscribe(N=>{(!N||["light","dark","system"].includes(N))&&T(N||t)})||aT,w=u?.subscribe(N=>{(!N||c.match(N))&&P({light:N})})||aT,O=g?.subscribe(N=>{(!N||c.match(N))&&P({dark:N})})||aT;return()=>{R(),w(),O()}}},[P,T,c,t,s,m,f,u,g]),{...v,mode:d?v.mode:void 0,systemMode:d?v.systemMode:void 0,colorScheme:d?h:void 0,setMode:T,setColorScheme:P}}var jl=C(U(),1),AD="*{-webkit-transition:none!important;-moz-transition:none!important;-o-transition:none!important;-ms-transition:none!important;transition:none!important}";function Wd(e){let{themeId:t,theme:o={},modeStorageKey:r=qc,colorSchemeStorageKey:n=Gc,disableTransitionOnChange:a=!1,defaultColorScheme:i,resolveTheme:s}=e,l={allColorSchemes:[],colorScheme:void 0,darkColorScheme:void 0,lightColorScheme:void 0,mode:void 0,setColorScheme:()=>{},setMode:()=>{},systemMode:void 0},p=Po.createContext(void 0),c=()=>Po.useContext(p)||l,m={},f={};function u(d){let{children:y,theme:h,modeStorageKey:T=r,colorSchemeStorageKey:P=n,disableTransitionOnChange:S=a,storageManager:E,storageWindow:R=typeof window>"u"?void 0:window,documentNode:w=typeof document>"u"?void 0:document,colorSchemeNode:O=typeof document>"u"?void 0:document.documentElement,disableNestedContext:N=!1,disableStyleSheetGeneration:b=!1,defaultMode:M="system",forceThemeRerender:A=!1,noSsr:_}=d,k=Po.useRef(!1),W=ga(),re=Po.useContext(p),F=!!re&&!N,me=Po.useMemo(()=>h||(typeof o=="function"?o():o),[h]),ie=me[t],ue=ie||me,{colorSchemes:ne=m,components:Ee=f,cssVarPrefix:le}=ue,oe=Object.keys(ne).filter(Ye=>!!ne[Ye]).join(","),ye=Po.useMemo(()=>oe.split(","),[oe]),ge=typeof i=="string"?i:i.light,Te=typeof i=="string"?i:i.dark,se=ne[ge]&&ne[Te]?M:ne[ue.defaultColorScheme]?.palette?.mode||ue.palette?.mode,{mode:de,setMode:be,systemMode:$,lightColorScheme:z,darkColorScheme:xe,colorScheme:Oe,setColorScheme:Pe}=iT({supportedColorSchemes:ye,defaultLightColorScheme:ge,defaultDarkColorScheme:Te,modeStorageKey:T,colorSchemeStorageKey:P,defaultMode:se,storageManager:E,storageWindow:R,noSsr:_}),ke=de,qe=Oe;F&&(ke=re.mode,qe=re.colorScheme);let $e=qe||ue.defaultColorScheme;ue.vars&&!A&&($e=ue.defaultColorScheme);let Ne=Po.useMemo(()=>{let Ye=ue.generateThemeVars?.()||ue.Line truncated
} catch(e){}})();`}},"mui-color-scheme-init")}var Oo=C(I(),1);function Bk(){}var Uk=({key:e,storageWindow:t})=>(!t&&typeof window<"u"&&(t=window),{get(o){if(typeof window>"u")return;if(!t)return o;let r;try{r=t.localStorage.getItem(e)}catch{}return r||o},set:o=>{if(t)try{t.localStorage.setItem(e,o)}catch{}},subscribe:o=>{if(!t)return Bk;let r=n=>{let a=n.newValue;n.key===e&&o(a)};return t.addEventListener("storage",r),()=>{t.removeEventListener("storage",r)}}}),oS=Uk;function fT(){}function rS(e){if(typeof window<"u"&&typeof window.matchMedia=="function"&&e==="system")return window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"}function nS(e,t){if(e.mode==="light"||e.mode==="system"&&e.systemMode==="light")return t("light");if(e.mode==="dark"||e.mode==="system"&&e.systemMode==="dark")return t("dark")}function Lk(e){return nS(e,t=>{if(t==="light")return e.lightColorScheme;if(t==="dark")return e.darkColorScheme})}function dT(e){let{defaultMode:t="light",defaultLightColorScheme:o,defaultDarkColorScheme:r,supportedColorSchemes:n=[],modeStorageKey:a=eu,colorSchemeStorageKey:i=tu,storageWindow:s=typeof window>"u"?void 0:window,storageManager:l=oS,noSsr:p=!1}=e,c=n.join(","),d=n.length>1,f=Oo.useMemo(()=>l?.({key:a,storageWindow:s}),[l,a,s]),u=Oo.useMemo(()=>l?.({key:`${i}-light`,storageWindow:s}),[l,i,s]),g=Oo.useMemo(()=>l?.({key:`${i}-dark`,storageWindow:s}),[l,i,s]),[x,v]=Oo.useState(()=>{let R=f?.get(t)||t,w=u?.get(o)||o,O=g?.get(r)||r;return{mode:R,systemMode:rS(R),lightColorScheme:w,darkColorScheme:O}}),[m,y]=Oo.useState(p||!d);Oo.useEffect(()=>{y(!0)},[]);let h=Lk(x),T=Oo.useCallback(R=>{v(w=>{if(R===w.mode)return w;let O=R??t;return f?.set(O),{...w,mode:O,systemMode:rS(O)}})},[f,t]),P=Oo.useCallback(R=>{R?typeof R=="string"?R&&!c.includes(R)?console.error(`\`${R}\` does not exist in \`theme.colorSchemes\`.`):v(w=>{let O={...w};return nS(w,A=>{A==="light"&&(u?.set(R),O.lightColorScheme=R),A==="dark"&&(g?.set(R),O.darkColorScheme=R)}),O}):v(w=>{let O={...w},A=R.light===null?o:R.light,b=R.dark===null?r:R.dark;return A&&(c.includes(A)?(O.lightColorScheme=A,u?.set(A)):console.error(`\`${A}\` does not exist in \`theme.colorSchemes\`.`)),b&&(c.includes(b)?(O.darkColorScheme=b,g?.set(b)):console.error(`\`${b}\` does not exist in \`theme.colorSchemes\`.`)),O}):v(w=>(u?.set(o),g?.set(r),{...w,lightColorScheme:o,darkColorScheme:r}))},[c,u,g,o,r]),S=Oo.useCallback(R=>{x.mode==="system"&&v(w=>{let O=R?.matches?"dark":"light";return w.systemMode===O?w:{...w,systemMode:O}})},[x.mode]),E=Oo.useRef(S);return E.current=S,Oo.useEffect(()=>{if(typeof window.matchMedia!="function"||!d)return;let R=(...O)=>E.current(...O),w=window.matchMedia("(prefers-color-scheme: dark)");return w.addListener(R),R(w),()=>{w.removeListener(R)}},[d]),Oo.useEffect(()=>{if(d){let R=f?.subscribe(A=>{(!A||["light","dark","system"].includes(A))&&T(A||t)})||fT,w=u?.subscribe(A=>{(!A||c.match(A))&&P({light:A})})||fT,O=g?.subscribe(A=>{(!A||c.match(A))&&P({dark:A})})||fT;return()=>{R(),w(),O()}}},[P,T,c,t,s,d,f,u,g]),{...x,mode:m?x.mode:void 0,systemMode:m?x.systemMode:void 0,colorScheme:m?h:void 0,setMode:T,setColorScheme:P}}var Fl=C(z(),1),Ik="*{-webkit-transition:none!important;-moz-transition:none!important;-o-transition:none!important;-ms-transition:none!important;transition:none!important}";function rm(e){let{themeId:t,theme:o={},modeStorageKey:r=eu,colorSchemeStorageKey:n=tu,disableTransitionOnChange:a=!1,defaultColorScheme:i,resolveTheme:s}=e,l={allColorSchemes:[],colorScheme:void 0,darkColorScheme:void 0,lightColorScheme:void 0,mode:void 0,setColorScheme:()=>{},setMode:()=>{},systemMode:void 0},p=wo.createContext(void 0),c=()=>wo.useContext(p)||l,d={},f={};function u(m){let{children:y,theme:h,modeStorageKey:T=r,colorSchemeStorageKey:P=n,disableTransitionOnChange:S=a,storageManager:E,storageWindow:R=typeof window>"u"?void 0:window,documentNode:w=typeof document>"u"?void 0:document,colorSchemeNode:O=typeof document>"u"?void 0:document.documentElement,disableNestedContext:A=!1,disableStyleSheetGeneration:b=!1,defaultMode:N="system",forceThemeRerender:M=!1,noSsr:_}=m,D=wo.useRef(!1),K=xa(),ee=wo.useContext(p),q=!!ee&&!A,ye=wo.useMemo(()=>h||(typeof o=="function"?o():o),[h]),se=ye[t],ce=se||ye,{colorSchemes:oe=d,components:Ce=f,cssVarPrefix:pe}=ce,re=Object.keys(oe).filter(Ge=>!!oe[Ge]).join(","),Te=wo.useMemo(()=>re.split(","),[re]),he=typeof i=="string"?i:i.light,Ee=typeof i=="string"?i:i.dark,le=oe[he]&&oe[Ee]?N:oe[ce.defaultColorScheme]?.palette?.mode||ce.palette?.mode,{mode:fe,setMode:ge,systemMode:$,lightColorScheme:U,darkColorScheme:Pe,colorScheme:Me,setColorScheme:Se}=dT({supportedColorSchemes:Te,defaultLightColorScheme:he,defaultDarkColorScheme:Ee,modeStorageKey:T,colorSchemeStorageKey:P,defaultMode:le,storageManager:E,storageWindow:R,noSsr:_}),Oe=fe,Ve=Me;q&&(Oe=ee.mode,Ve=ee.colorScheme);let Ze=Ve||ce.defaultColorScheme;ce.vars&&!M&&(Ze=ce.defaultColorScheme);let Fe=wo.useMemo(()=>{let Ge=ce.generateThemeVars?.()||ce.Line truncated
const theme = ${JSON.stringify(t,null,2)};
theme.breakpoints = createBreakpoints(theme.breakpoints || {});
theme.transitions = createTransitions(theme.transitions || {});
export default theme;`}function fS(e){return typeof e=="number"?`${(e*100).toFixed(0)}%`:`calc((${e}) * 100%)`}var nk=e=>{if(!Number.isNaN(+e))return+e;let t=e.match(/\d*\.?\d+/g);if(!t)return 0;let o=0;for(let r=0;r<t.length;r+=1)o+=+t[r];return o};function ak(e){Object.assign(e,{alpha(t,o){let r=this||e;return r.colorSpace?`oklch(from ${t} l c h / ${typeof o=="string"?`calc(${o})`:o})`:r.vars?`rgba(${t.replace(/var\(--([^,\s)]+)(?:,[^)]+)?\)+/g,"var(--$1Channel)")} / ${typeof o=="string"?`calc(${o})`:o})`:ri(t,nk(o))},lighten(t,o){let r=this||e;return r.colorSpace?`color-mix(in ${r.colorSpace}, ${t}, #fff ${fS(o)})`:kl(t,o)},darken(t,o){let r=this||e;return r.colorSpace?`color-mix(in ${r.colorSpace}, ${t}, #000 ${fS(o)})`:Dl(t,o)}})}function ik(e={},...t){let{breakpoints:o,mixins:r={},spacing:n,palette:a={},transitions:i={},typography:s={},shape:l,colorSpace:p,...c}=e;if(e.vars&&e.generateThemeVars===void 0)throw new Error(io(20));let m=ls({...a,colorSpace:p}),f=bn(e),u=Xe(f,{mixins:cT(f.breakpoints,r),palette:m,shadows:pS.slice(),typography:Kc(m,s),transitions:fT(i),zIndex:{...uS}});return u=Xe(u,c),u=t.reduce((g,v)=>Xe(g,v),u),u.unstable_sxConfig={...Tn,...c?.unstable_sxConfig},u.unstable_sx=function(v){return lr({sx:v,theme:this})},u.toRuntimeSource=om,ak(u),u}var Wc=ik;function Ul(e){let t;return e<1?t=5.11916*e**2:t=4.5*Math.log(e+1)+2,Math.round(t*10)/1e3}var sk=[...Array(25)].map((e,t)=>{if(t===0)return"none";let o=Ul(t);return`linear-gradient(rgba(255 255 255 / ${o}), rgba(255 255 255 / ${o}))`});function dT(e){return{inputPlaceholder:e==="dark"?.5:.42,inputUnderline:e==="dark"?.7:.42,switchTrackDisabled:e==="dark"?.2:.12,switchTrack:e==="dark"?.3:.38}}function mT(e){return e==="dark"?sk:[]}function yT(e){let{palette:t={mode:"light"},opacity:o,overlays:r,colorSpace:n,...a}=e,i=ls({...t,colorSpace:n});return{palette:i,opacity:{...dT(i.mode),...o},overlays:r||mT(i.mode),...a}}function hT(e){return!!e[0].match(/(cssVarPrefix|colorSchemeSelector|modularCssLayers|rootSelector|typography|mixins|breakpoints|direction|transitions)/)||!!e[0].match(/sxConfig$/)||e[0]==="palette"&&!!e[1]?.match(/(mode|contrastThreshold|tonalOffset)/)}var lk=e=>[...[...Array(25)].map((t,o)=>`--${e?`${e}-`:""}overlays-${o}`),`--${e?`${e}-`:""}palette-AppBar-darkBg`,`--${e?`${e}-`:""}palette-AppBar-darkColor`],dS=lk;var mS=e=>(t,o)=>{let r=e.rootSelector||":root",n=e.colorSchemeSelector,a=n;if(n==="class"&&(a=".%s"),n==="data"&&(a="[data-%s]"),n?.startsWith("data-")&&!n.includes("%s")&&(a=`[${n}="%s"]`),e.defaultColorScheme===t){if(t==="dark"){let i={};return dS(e.cssVarPrefix).forEach(s=>{i[s]=o[s],delete o[s]}),a==="media"?{[r]:o,"@media (prefers-color-scheme: dark)":{[r]:i}}:a?{[a.replace("%s",t)]:i,[`${r}, ${a.replace("%s",t)}`]:o}:{[r]:{...o,...i}}}if(a&&a!=="media")return`${r}, ${a.replace("%s",String(t))}`}else if(t){if(a==="media")return{[`@media (prefers-color-scheme: ${String(t)})`]:{[r]:o}};if(a)return a.replace("%s",String(t))}return r};function pk(e,t){t.forEach(o=>{e[o]||(e[o]={})})}function H(e,t,o){!e[t]&&o&&(e[t]=o)}function Xc(e){return typeof e!="string"||!e.startsWith("hsl")?e:eT(e)}function Ta(e,t){`${t}Channel`in e||(e[`${t}Channel`]=Al(Xc(e[t]),`MUI: Can't create \`palette.${t}Channel\` because \`palette.${t}\` is not one of these formats: #nnn, #nnnnnn, rgb(), rgba(), hsl(), hsla(), color().
To suppress this warning, you need to explicitly provide the \`palette.${t}Channel\` as a string (in rgb format, for example "12 12 12") or undefined if you want to remove the channel token.`))}function ck(e){return typeof e=="number"?`${e}px`:typeof e=="string"||typeof e=="function"||Array.isArray(e)?e:"8px"}var Gn=e=>{try{return e()}catch{}},uk=(e="mui")=>Xd(e);function gT(e,t,o,r,n){if(!o)return;o=o===!0?{}:o;let a=n==="dark"?"dark":"light";if(!r){t[n]=yT({...o,palette:{mode:a,...o?.palette},colorSpace:e});return}let{palette:i,...s}=Wc({...r,palette:{mode:a,...o?.palette},colorSpace:e});return t[n]={...o,palette:i,opacity:{...dT(a),...o?.opacity},overlays:o?.overlays||mT(a)},s}function TT(e={},...t){let{colorSchemes:o={light:!0},defaultColorScheme:r,disableCssColorScheme:n=!1,cssVarPrefix:a="mui",nativeColor:i=!1,shouldSkipGeneratingVar:s=hT,colorSchemeSelector:l=o.light&&o.dark?"media":void 0,rootSelector:p=":root",...c}=e,m=Object.keys(o)[0],f=r||(o.light&&m!=="light"?"light":m),u=uk(a),{[f]:g,light:v,dark:x,...d}=o,y={...d},h=g;if((f==="dark"&&!("dark"in o)||f==="light"&&!("light"in o))&&(h=!0),!h)throw new Error(io(21,f));let T;i&&(T="oklch");let P=gT(T,y,h,c,f);v&&!y.light&&gT(T,y,v,void 0,"light"),x&&!y.dark&&gT(T,y,x,void 0,"dark");let S={defaultColorScheme:f,...P,cssVarPrefix:a,colorSchemeSelector:l,rootSelector:p,getCssVar:u,colorSchemes:y,font:{...tm(P.typography),...P.font},spacing:ck(c.spacing)};Object.keys(S.colorSchemes).forEach(N=>{let b=S.colorSchemes[N].palette,M=_=>{let k=_.split("-"),W=k[1],re=k[2];return u(_,b[W][re])};b.mode==="light"&&(H(b.common,"background","#fff"),H(b.common,"onBackground","#000")),b.mode==="dark"&&(H(b.common,"background","#000"),H(b.common,"onBackground","#fff"));function A(_,k,W){if(T){let re;return _===ni&&(re=`transparent ${((1-W)*100).toFixed(0)}%`),_===et&&(re=`#000 ${(W*100).toFixed(0)}%`),_===tt&&(re=`#fff ${(W*100).toFixed(0)}%`),`color-mix(in ${T}, ${k}, ${re})`}return _(k,W)}if(pk(b,["Alert","AppBar","Avatar","Button","Chip","FilledInput","LinearProgress","Skeleton","Slider","SnackbarContent","SpeedDialAction","StepConnector","StepContent","Switch","TableCell","Tooltip"]),b.mode==="light"){H(b.Alert,"errorColor",A(et,i?u("palette-error-light"):b.error.light,.6)),H(b.Alert,"infoColor",A(et,i?u("palette-info-light"):b.info.light,.6)),H(b.Alert,"successColor",A(et,i?u("palette-success-light"):b.success.light,.6)),H(b.Alert,"warningColor",A(et,i?u("palette-warning-light"):b.warning.light,.6)),H(b.Alert,"errorFilledBg",M("palette-error-main")),H(b.Alert,"infoFilledBg",M("palette-info-main")),H(b.Alert,"successFilledBg",M("palette-success-main")),H(b.Alert,"warningFilledBg",M("palette-warning-main")),H(b.Alert,"errorFilledColor",Gn(()=>b.getContrastText(b.error.main))),H(b.Alert,"infoFilledColor",Gn(()=>b.getContrastText(b.info.main))),H(b.Alert,"successFilledColor",Gn(()=>b.getContrastText(b.success.main))),H(b.Alert,"warningFilledColor",Gn(()=>b.getContrastText(b.warning.main))),H(b.Alert,"errorStandardBg",A(tt,i?u("palette-error-light"):b.error.light,.9)),H(b.Alert,"infoStandardBg",A(tt,i?u("palette-info-light"):b.info.light,.9)),H(b.Alert,"successStandardBg",A(tt,i?u("palette-success-light"):b.success.light,.9)),H(b.Alert,"warningStandardBg",A(tt,i?u("palette-warning-light"):b.warning.light,.9)),H(b.Alert,"errorIconColor",M("palette-error-main")),H(b.Alert,"infoIconColor",M("palette-info-main")),H(b.Alert,"successIconColor",M("palette-success-main")),H(b.Alert,"warningIconColor",M("palette-warning-main")),H(b.AppBar,"defaultBg",M("palette-grey-100")),H(b.Avatar,"defaultBg",M("palette-grey-400")),H(b.Button,"inheritContainedBg",M("palette-grey-300")),H(b.Button,"inheritContainedHoverBg",M("palette-grey-A100")),H(b.Chip,"defaultBorder",M("palette-grey-400")),H(b.Chip,"defaultAvatarColor",M("palette-grey-700")),H(b.Chip,"defaultIconColor",M("palette-grey-700")),H(b.FilledInput,"bg","rgba(0, 0, 0, 0.06)"),H(b.FilledInput,"hoverBg","rgba(0, 0, 0, 0.09)"),H(b.FilledInput,"disabledBg","rgba(0, 0, 0, 0.12)"),H(b.LinearProgress,"primaryBg",A(tt,i?u("palette-primary-main"):b.primary.main,.62)),H(b.LinearProgress,"secondaryBg",A(tt,i?u("palette-secondary-main"):b.secondary.main,.62)),H(b.LinearProgress,"errorBg",A(tt,i?u("palette-error-main"):b.error.main,.62)),H(b.LinearProgress,"infoBg",A(tt,i?u("palette-info-main"):b.info.main,.62)),H(b.LinearProgress,"successBg",A(tt,i?u("palette-success-main"):b.success.main,.62)),H(b.LinearProgress,"warningBg",A(tt,i?u("palette-warning-light"):b.warning.main,.62)),H(b.Skeleton,"bg",T?A(ni,i?u("palette-text-primary"):b.text.primary,.11):`rgba(${M("palette-text-primaryChannel")} / 0.11)`),H(b.Slider,"primaryTrack",A(tt,i?u("palette-primary-main"):b.primary.main,.62)),H(b.Slider,"secondaryTrack",A(tt,i?u("palette-secondary-main"):b.secondary.main,.62)),H(b.Slider,"errorTrack",A(tt,i?u("palette-error-main"):b.error.main,.62)),H(b.Slider,"infoTrack",A(tt,i?u("palette-info-main"):b.info.main,.62)),H(b.Slider,"successTrack",A(tt,iLine truncated
export default theme;`}function bS(e){return typeof e=="number"?`${(e*100).toFixed(0)}%`:`calc((${e}) * 100%)`}var dD=e=>{if(!Number.isNaN(+e))return+e;let t=e.match(/\d*\.?\d+/g);if(!t)return 0;let o=0;for(let r=0;r<t.length;r+=1)o+=+t[r];return o};function mD(e){Object.assign(e,{alpha(t,o){let r=this||e;return r.colorSpace?`oklch(from ${t} l c h / ${typeof o=="string"?`calc(${o})`:o})`:r.vars?`rgba(${t.replace(/var\(--([^,\s)]+)(?:,[^)]+)?\)+/g,"var(--$1Channel)")} / ${typeof o=="string"?`calc(${o})`:o})`:li(t,dD(o))},lighten(t,o){let r=this||e;return r.colorSpace?`color-mix(in ${r.colorSpace}, ${t}, #fff ${bS(o)})`:$l(t,o)},darken(t,o){let r=this||e;return r.colorSpace?`color-mix(in ${r.colorSpace}, ${t}, #000 ${bS(o)})`:Il(t,o)}})}function yD(e={},...t){let{breakpoints:o,mixins:r={},spacing:n,palette:a={},transitions:i={},typography:s={},shape:l,colorSpace:p,...c}=e;if(e.vars&&e.generateThemeVars===void 0)throw new Error(uo(20));let d=ys({...a,colorSpace:p}),f=vn(e),u=We(f,{mixins:gT(f.breakpoints,r),palette:d,shadows:hS.slice(),typography:ru(d,s),transitions:bT(i),zIndex:{...TS}});return u=We(u,c),u=t.reduce((g,x)=>We(g,x),u),u.unstable_sxConfig={...bn,...c?.unstable_sxConfig},u.unstable_sx=function(x){return ur({sx:x,theme:this})},u.toRuntimeSource=cm,mD(u),u}var nu=yD;function Gl(e){let t;return e<1?t=5.11916*e**2:t=4.5*Math.log(e+1)+2,Math.round(t*10)/1e3}var hD=[...Array(25)].map((e,t)=>{if(t===0)return"none";let o=Gl(t);return`linear-gradient(rgba(255 255 255 / ${o}), rgba(255 255 255 / ${o}))`});function vT(e){return{inputPlaceholder:e==="dark"?.5:.42,inputUnderline:e==="dark"?.7:.42,switchTrackDisabled:e==="dark"?.2:.12,switchTrack:e==="dark"?.3:.38}}function xT(e){return e==="dark"?hD:[]}function PT(e){let{palette:t={mode:"light"},opacity:o,overlays:r,colorSpace:n,...a}=e,i=ys({...t,colorSpace:n});return{palette:i,opacity:{...vT(i.mode),...o},overlays:r||xT(i.mode),...a}}function ST(e){return!!e[0].match(/(cssVarPrefix|colorSchemeSelector|modularCssLayers|rootSelector|typography|mixins|breakpoints|direction|transitions)/)||!!e[0].match(/sxConfig$/)||e[0]==="palette"&&!!e[1]?.match(/(mode|contrastThreshold|tonalOffset)/)}var gD=e=>[...[...Array(25)].map((t,o)=>`--${e?`${e}-`:""}overlays-${o}`),`--${e?`${e}-`:""}palette-AppBar-darkBg`,`--${e?`${e}-`:""}palette-AppBar-darkColor`],vS=gD;var xS=e=>(t,o)=>{let r=e.rootSelector||":root",n=e.colorSchemeSelector,a=n;if(n==="class"&&(a=".%s"),n==="data"&&(a="[data-%s]"),n?.startsWith("data-")&&!n.includes("%s")&&(a=`[${n}="%s"]`),e.defaultColorScheme===t){if(t==="dark"){let i={};return vS(e.cssVarPrefix).forEach(s=>{i[s]=o[s],delete o[s]}),a==="media"?{[r]:o,"@media (prefers-color-scheme: dark)":{[r]:i}}:a?{[a.replace("%s",t)]:i,[`${r}, ${a.replace("%s",t)}`]:o}:{[r]:{...o,...i}}}if(a&&a!=="media")return`${r}, ${a.replace("%s",String(t))}`}else if(t){if(a==="media")return{[`@media (prefers-color-scheme: ${String(t)})`]:{[r]:o}};if(a)return a.replace("%s",String(t))}return r};function TD(e,t){t.forEach(o=>{e[o]||(e[o]={})})}function H(e,t,o){!e[t]&&o&&(e[t]=o)}function au(e){return typeof e!="string"||!e.startsWith("hsl")?e:sT(e)}function Pa(e,t){`${t}Channel`in e||(e[`${t}Channel`]=Ll(au(e[t]),`MUI: Can't create \`palette.${t}Channel\` because \`palette.${t}\` is not one of these formats: #nnn, #nnnnnn, rgb(), rgba(), hsl(), hsla(), color().
To suppress this warning, you need to explicitly provide the \`palette.${t}Channel\` as a string (in rgb format, for example "12 12 12") or undefined if you want to remove the channel token.`))}function bD(e){return typeof e=="number"?`${e}px`:typeof e=="string"||typeof e=="function"||Array.isArray(e)?e:"8px"}var Kn=e=>{try{return e()}catch{}},vD=(e="mui")=>nm(e);function CT(e,t,o,r,n){if(!o)return;o=o===!0?{}:o;let a=n==="dark"?"dark":"light";if(!r){t[n]=PT({...o,palette:{mode:a,...o?.palette},colorSpace:e});return}let{palette:i,...s}=nu({...r,palette:{mode:a,...o?.palette},colorSpace:e});return t[n]={...o,palette:i,opacity:{...vT(a),...o?.opacity},overlays:o?.overlays||xT(a)},s}function ET(e={},...t){let{colorSchemes:o={light:!0},defaultColorScheme:r,disableCssColorScheme:n=!1,cssVarPrefix:a="mui",nativeColor:i=!1,shouldSkipGeneratingVar:s=ST,colorSchemeSelector:l=o.light&&o.dark?"media":void 0,rootSelector:p=":root",...c}=e,d=Object.keys(o)[0],f=r||(o.light&&d!=="light"?"light":d),u=vD(a),{[f]:g,light:x,dark:v,...m}=o,y={...m},h=g;if((f==="dark"&&!("dark"in o)||f==="light"&&!("light"in o))&&(h=!0),!h)throw new Error(uo(21,f));let T;i&&(T="oklch");let P=CT(T,y,h,c,f);x&&!y.light&&CT(T,y,x,void 0,"light"),v&&!y.dark&&CT(T,y,v,void 0,"dark");let S={defaultColorScheme:f,...P,cssVarPrefix:a,colorSchemeSelector:l,rootSelector:p,getCssVar:u,colorSchemes:y,font:{...pm(P.typography),...P.font},spacing:bD(c.spacing)};Object.keys(S.colorSchemes).forEach(A=>{let b=S.colorSchemes[A].palette,N=_=>{let D=_.split("-"),K=D[1],ee=D[2];return u(_,b[K][ee])};b.mode==="light"&&(H(b.common,"background","#fff"),H(b.common,"onBackground","#000")),b.mode==="dark"&&(H(b.common,"background","#000"),H(b.common,"onBackground","#fff"));function M(_,D,K){if(T){let ee;return _===pi&&(ee=`transparent ${((1-K)*100).toFixed(0)}%`),_===Je&&(ee=`#000 ${(K*100).toFixed(0)}%`),_===et&&(ee=`#fff ${(K*100).toFixed(0)}%`),`color-mix(in ${T}, ${D}, ${ee})`}return _(D,K)}if(TD(b,["Alert","AppBar","Avatar","Button","Chip","FilledInput","LinearProgress","Skeleton","Slider","SnackbarContent","SpeedDialAction","StepConnector","StepContent","Switch","TableCell","Tooltip"]),b.mode==="light"){H(b.Alert,"errorColor",M(Je,i?u("palette-error-light"):b.error.light,.6)),H(b.Alert,"infoColor",M(Je,i?u("palette-info-light"):b.info.light,.6)),H(b.Alert,"successColor",M(Je,i?u("palette-success-light"):b.success.light,.6)),H(b.Alert,"warningColor",M(Je,i?u("palette-warning-light"):b.warning.light,.6)),H(b.Alert,"errorFilledBg",N("palette-error-main")),H(b.Alert,"infoFilledBg",N("palette-info-main")),H(b.Alert,"successFilledBg",N("palette-success-main")),H(b.Alert,"warningFilledBg",N("palette-warning-main")),H(b.Alert,"errorFilledColor",Kn(()=>b.getContrastText(b.error.main))),H(b.Alert,"infoFilledColor",Kn(()=>b.getContrastText(b.info.main))),H(b.Alert,"successFilledColor",Kn(()=>b.getContrastText(b.success.main))),H(b.Alert,"warningFilledColor",Kn(()=>b.getContrastText(b.warning.main))),H(b.Alert,"errorStandardBg",M(et,i?u("palette-error-light"):b.error.light,.9)),H(b.Alert,"infoStandardBg",M(et,i?u("palette-info-light"):b.info.light,.9)),H(b.Alert,"successStandardBg",M(et,i?u("palette-success-light"):b.success.light,.9)),H(b.Alert,"warningStandardBg",M(et,i?u("palette-warning-light"):b.warning.light,.9)),H(b.Alert,"errorIconColor",N("palette-error-main")),H(b.Alert,"infoIconColor",N("palette-info-main")),H(b.Alert,"successIconColor",N("palette-success-main")),H(b.Alert,"warningIconColor",N("palette-warning-main")),H(b.AppBar,"defaultBg",N("palette-grey-100")),H(b.Avatar,"defaultBg",N("palette-grey-400")),H(b.Button,"inheritContainedBg",N("palette-grey-300")),H(b.Button,"inheritContainedHoverBg",N("palette-grey-A100")),H(b.Chip,"defaultBorder",N("palette-grey-400")),H(b.Chip,"defaultAvatarColor",N("palette-grey-700")),H(b.Chip,"defaultIconColor",N("palette-grey-700")),H(b.FilledInput,"bg","rgba(0, 0, 0, 0.06)"),H(b.FilledInput,"hoverBg","rgba(0, 0, 0, 0.09)"),H(b.FilledInput,"disabledBg","rgba(0, 0, 0, 0.12)"),H(b.LinearProgress,"primaryBg",M(et,i?u("palette-primary-main"):b.primary.main,.62)),H(b.LinearProgress,"secondaryBg",M(et,i?u("palette-secondary-main"):b.secondary.main,.62)),H(b.LinearProgress,"errorBg",M(et,i?u("palette-error-main"):b.error.main,.62)),H(b.LinearProgress,"infoBg",M(et,i?u("palette-info-main"):b.info.main,.62)),H(b.LinearProgress,"successBg",M(et,i?u("palette-success-main"):b.success.main,.62)),H(b.LinearProgress,"warningBg",M(et,i?u("palette-warning-light"):b.warning.main,.62)),H(b.Skeleton,"bg",T?M(pi,i?u("palette-text-primary"):b.text.primary,.11):`rgba(${N("palette-text-primaryChannel")} / 0.11)`),H(b.Slider,"primaryTrack",M(et,i?u("palette-primary-main"):b.primary.main,.62)),H(b.Slider,"secondaryTrack",M(et,i?u("palette-secondary-main"):b.secondary.main,.62)),H(b.Slider,"errorTrack",M(et,i?u("palette-error-main"):b.error.main,.62)),H(b.Slider,"infoTrack",M(et,i?u("palette-info-main"):b.info.main,.62)),H(b.Slider,"successTrack",M(et,iLine truncated
0% {
transform: scale(0);
opacity: 0.1;
@@ -52,7 +52,7 @@ To suppress this warning, you need to explicitly provide the \`palette.${t}Chann
transform: scale(1);
opacity: 0.3;
}
`,p_=vo`
`,T_=Ro`
0% {
opacity: 1;
}
@@ -60,7 +60,7 @@ To suppress this warning, you need to explicitly provide the \`palette.${t}Chann
100% {
opacity: 0;
}
`,c_=vo`
`,b_=Ro`
0% {
transform: scale(1);
}
@@ -72,23 +72,23 @@ To suppress this warning, you need to explicitly provide the \`palette.${t}Chann
100% {
transform: scale(1);
}
`,u_=D("span",{name:"MuiTouchRipple",slot:"Root"})({overflow:"hidden",pointerEvents:"none",position:"absolute",zIndex:0,top:0,right:0,bottom:0,left:0,borderRadius:"inherit"}),f_=D(WS,{name:"MuiTouchRipple",slot:"Ripple"})`
`,v_=k("span",{name:"MuiTouchRipple",slot:"Root"})({overflow:"hidden",pointerEvents:"none",position:"absolute",zIndex:0,top:0,right:0,bottom:0,left:0,borderRadius:"inherit"}),x_=k(oC,{name:"MuiTouchRipple",slot:"Ripple"})`
opacity: 0;
position: absolute;
&.${Rr.rippleVisible} {
&.${Or.rippleVisible} {
opacity: 0.3;
transform: scale(1);
animation-name: ${l_};
animation-duration: ${kT}ms;
animation-name: ${g_};
animation-duration: ${IT}ms;
animation-timing-function: ${({theme:e})=>e.transitions.easing.easeInOut};
}
&.${Rr.ripplePulsate} {
&.${Or.ripplePulsate} {
animation-duration: ${({theme:e})=>e.transitions.duration.shorter}ms;
}
& .${Rr.child} {
& .${Or.child} {
opacity: 1;
display: block;
width: 100%;
@@ -97,25 +97,25 @@ To suppress this warning, you need to explicitly provide the \`palette.${t}Chann
background-color: currentColor;
}
& .${Rr.childLeaving} {
& .${Or.childLeaving} {
opacity: 0;
animation-name: ${p_};
animation-duration: ${kT}ms;
animation-name: ${T_};
animation-duration: ${IT}ms;
animation-timing-function: ${({theme:e})=>e.transitions.easing.easeInOut};
}
& .${Rr.childPulsate} {
& .${Or.childPulsate} {
position: absolute;
/* @noflip */
left: 0px;
top: 0;
animation-name: ${c_};
animation-name: ${b_};
animation-duration: 2500ms;
animation-timing-function: ${({theme:e})=>e.transitions.easing.easeInOut};
animation-iteration-count: infinite;
animation-delay: 200ms;
}
`,d_=Jt.forwardRef(function(t,o){let r=X({props:t,name:"MuiTouchRipple"}),{center:n=!1,classes:a={},className:i,...s}=r,[l,p]=Jt.useState([]),c=Jt.useRef(0),m=Jt.useRef(null);Jt.useEffect(()=>{m.current&&(m.current(),m.current=null)},[l]);let f=Jt.useRef(!1),u=Ko(),g=Jt.useRef(null),v=Jt.useRef(null),x=Jt.useCallback(T=>{let{pulsate:P,rippleX:S,rippleY:E,rippleSize:R,cb:w}=T;p(O=>[...O,(0,Rm.jsx)(f_,{classes:{ripple:L(a.ripple,Rr.ripple),rippleVisible:L(a.rippleVisible,Rr.rippleVisible),ripplePulsate:L(a.ripplePulsate,Rr.ripplePulsate),child:L(a.child,Rr.child),childLeaving:L(a.childLeaving,Rr.childLeaving),childPulsate:L(a.childPulsate,Rr.childPulsate)},timeout:kT,pulsate:P,rippleX:S,rippleY:E,rippleSize:R},c.current)]),c.current+=1,m.current=w},[a]),d=Jt.useCallback((T={},P={},S=()=>{})=>{let{pulsate:E=!1,center:R=n||P.pulsate,fakeElement:w=!1}=P;if(T?.type==="mousedown"&&f.current){f.current=!1;return}T?.type==="touchstart"&&(f.current=!0);let O=w?null:v.current,N=O?O.getBoundingClientRect():{width:0,height:0,left:0,top:0},b,M,A;if(R||T===void 0||T.clientX===0&&T.clientY===0||!T.clientX&&!T.touches)b=Math.round(N.width/2),M=Math.round(N.height/2);else{let{clientX:_,clientY:k}=T.touches&&T.touches.length>0?T.touches[0]:T;b=Math.round(_-N.left),M=Math.round(k-N.top)}if(R)A=Math.sqrt((2*N.width**2+N.height**2)/3),A%2===0&&(A+=1);else{let _=Math.max(Math.abs((O?O.clientWidth:0)-b),b)*2+2,k=Math.max(Math.abs((O?O.clientHeight:0)-M),M)*2+2;A=Math.sqrt(_**2+k**2)}T?.touches?g.current===null&&(g.current=()=>{x({pulsate:E,rippleX:b,rippleY:M,rippleSize:A,cb:S})},u.start(s_,()=>{g.current&&(g.current(),g.current=null)})):x({pulsate:E,rippleX:b,rippleY:M,rippleSize:A,cb:S})},[n,x,u]),y=Jt.useCallback(()=>{d({},{pulsate:!0})},[d]),h=Jt.useCallback((T,P)=>{if(u.clear(),T?.type==="touchend"&&g.current){g.current(),g.current=null,u.start(0,()=>{h(T,P)});return}g.current=null,p(S=>S.length>0?S.slice(1):S),m.current=P},[u]);return Jt.useImperativeHandle(o,()=>({pulsate:y,start:d,stop:h}),[y,d,h]),(0,Rm.jsx)(u_,{className:L(Rr.root,a.root,i),ref:v,...s,children:(0,Rm.jsx)(wT,{component:null,exit:!0,children:l})})}),XS=d_;function QS(e){return q("MuiButtonBase",e)}var m_=G("MuiButtonBase",["root","disabled","focusVisible"]),ZS=m_;var Om=C(U(),1),y_=e=>{let{disabled:t,focusVisible:o,focusVisibleClassName:r,classes:n}=e,i=Y({root:["root",t&&"disabled",o&&"focusVisible"]},QS,n);return o&&r&&(i.root+=` ${r}`),i},h_=D("button",{name:"MuiButtonBase",slot:"Root"})({display:"inline-flex",alignItems:"center",justifyContent:"center",position:"relative",boxSizing:"border-box",WebkitTapHighlightColor:"transparent",backgroundColor:"transparent",outline:0,border:0,margin:0,borderRadius:0,padding:0,cursor:"pointer",userSelect:"none",verticalAlign:"middle",MozAppearance:"none",WebkitAppearance:"none",textDecoration:"none",color:"inherit","&::-moz-focus-inner":{borderStyle:"none"},[`&.${ZS.disabled}`]:{pointerEvents:"none",cursor:"default"},"@media print":{colorAdjust:"exact"}}),g_=Kn.forwardRef(function(t,o){let r=X({props:t,name:"MuiButtonBase"}),{action:n,centerRipple:a=!1,children:i,className:s,component:l="button",disabled:p=!1,disableRipple:c=!1,disableTouchRipple:m=!1,focusRipple:f=!1,focusVisibleClassName:u,LinkComponent:g="a",onBlur:v,onClick:x,onContextMenu:d,onDragLeave:y,onFocus:h,onFocusVisible:T,onKeyDown:P,onKeyUp:S,onMouseDown:E,onMouseLeave:R,onMouseUp:w,onTouchEnd:O,onTouchMove:N,onTouchStart:b,tabIndex:M=0,TouchRippleProps:A,touchRippleRef:_,type:k,...W}=r,re=Kn.useRef(null),F=Cm(),me=St(F.ref,_),[ie,ue]=Kn.useState(!1);p&&ie&&ue(!1),Kn.useImperativeHandle(n,()=>({focusVisible:()=>{ue(!0),re.current.focus()}}),[]);let ne=F.shouldMount&&!c&&!p;Kn.useEffect(()=>{ie&&f&&!c&&F.pulsate()},[c,f,ie,F]);let Ee=Ca(F,"start",E,m),le=Ca(F,"stop",d,m),oe=Ca(F,"stop",y,m),ye=Ca(F,"stop",w,m),ge=Ca(F,"stop",pe=>{ie&&pe.preventDefault(),R&&R(pe)},m),Te=Ca(F,"start",b,m),se=Ca(F,"stop",O,m),de=Ca(F,"stop",N,m),be=Ca(F,"stop",pe=>{vn(pe.target)||ue(!1),v&&v(pe)},!1),$=ii(pe=>{re.current||(re.current=pe.currentTarget),vn(pe.target)&&(ue(!0),T&&T(pe)),h&&h(pe)}),z=()=>{let pe=re.current;return pe?pe.tagName==="BUTTON"?!1:!(pe.tagName==="A"&&pe.href):l&&l!=="button"},xe=ii(pe=>{f&&!pe.repeat&&ie&&pe.key===" "&&F.stop(pe,()=>{F.start(pe)}),pe.target===pe.currentTarget&&z()&&pe.key===" "&&pe.preventDefault(),P&&P(pe),pe.target===pe.currentTarget&&z()&&pe.key==="Enter"&&!p&&(pe.preventDefault(),x&&x(pe))}),Oe=ii(pe=>{f&&pe.key===" "&&ie&&!pe.defaultPrevented&&F.stop(pe,()=>{F.pulsate(pe)}),S&&S(pe),x&&pe.target===pe.currentTarget&&z()&&pe.key===" "&&!pe.defaultPrevented&&!p&&x(pe)}),Pe=l;Pe==="button"&&(W.href||W.to)&&(Pe=g);let ke={};if(Pe==="button"){let pe=!!W.formAction;ke.type=k===void 0&&!pe?"button":k,ke.disabled=p}else!W.href&&!W.to&&(ke.role="button"),p&&(ke["aria-disabled"]=p);let qe=St(o,re),$e={...r,centerRipple:a,component:l,disabled:p,disableRipple:c,disableTouchRipple:m,focusRipple:f,tabIndex:M,focusVisible:ie},Ne=y_($e);return Line truncated
`,P_=ao.forwardRef(function(t,o){let r=Q({props:t,name:"MuiTouchRipple"}),{center:n=!1,classes:a={},className:i,...s}=r,[l,p]=ao.useState([]),c=ao.useRef(0),d=ao.useRef(null);ao.useEffect(()=>{d.current&&(d.current(),d.current=null)},[l]);let f=ao.useRef(!1),u=Zo(),g=ao.useRef(null),x=ao.useRef(null),v=ao.useCallback(T=>{let{pulsate:P,rippleX:S,rippleY:E,rippleSize:R,cb:w}=T;p(O=>[...O,(0,_m.jsx)(x_,{classes:{ripple:L(a.ripple,Or.ripple),rippleVisible:L(a.rippleVisible,Or.rippleVisible),ripplePulsate:L(a.ripplePulsate,Or.ripplePulsate),child:L(a.child,Or.child),childLeaving:L(a.childLeaving,Or.childLeaving),childPulsate:L(a.childPulsate,Or.childPulsate)},timeout:IT,pulsate:P,rippleX:S,rippleY:E,rippleSize:R},c.current)]),c.current+=1,d.current=w},[a]),m=ao.useCallback((T={},P={},S=()=>{})=>{let{pulsate:E=!1,center:R=n||P.pulsate,fakeElement:w=!1}=P;if(T?.type==="mousedown"&&f.current){f.current=!1;return}T?.type==="touchstart"&&(f.current=!0);let O=w?null:x.current,A=O?O.getBoundingClientRect():{width:0,height:0,left:0,top:0},b,N,M;if(R||T===void 0||T.clientX===0&&T.clientY===0||!T.clientX&&!T.touches)b=Math.round(A.width/2),N=Math.round(A.height/2);else{let{clientX:_,clientY:D}=T.touches&&T.touches.length>0?T.touches[0]:T;b=Math.round(_-A.left),N=Math.round(D-A.top)}if(R)M=Math.sqrt((2*A.width**2+A.height**2)/3),M%2===0&&(M+=1);else{let _=Math.max(Math.abs((O?O.clientWidth:0)-b),b)*2+2,D=Math.max(Math.abs((O?O.clientHeight:0)-N),N)*2+2;M=Math.sqrt(_**2+D**2)}T?.touches?g.current===null&&(g.current=()=>{v({pulsate:E,rippleX:b,rippleY:N,rippleSize:M,cb:S})},u.start(h_,()=>{g.current&&(g.current(),g.current=null)})):v({pulsate:E,rippleX:b,rippleY:N,rippleSize:M,cb:S})},[n,v,u]),y=ao.useCallback(()=>{m({},{pulsate:!0})},[m]),h=ao.useCallback((T,P)=>{if(u.clear(),T?.type==="touchend"&&g.current){g.current(),g.current=null,u.start(0,()=>{h(T,P)});return}g.current=null,p(S=>S.length>0?S.slice(1):S),d.current=P},[u]);return ao.useImperativeHandle(o,()=>({pulsate:y,start:m,stop:h}),[y,m,h]),(0,_m.jsx)(v_,{className:L(Or.root,a.root,i),ref:x,...s,children:(0,_m.jsx)(zT,{component:null,exit:!0,children:l})})}),rC=P_;function nC(e){return G("MuiButtonBase",e)}var S_=Y("MuiButtonBase",["root","disabled","focusVisible"]),aC=S_;var zm=C(z(),1),C_=e=>{let{disabled:t,focusVisible:o,focusVisibleClassName:r,classes:n}=e,i=W({root:["root",t&&"disabled",o&&"focusVisible"]},nC,n);return o&&r&&(i.root+=` ${r}`),i},E_=k("button",{name:"MuiButtonBase",slot:"Root"})({display:"inline-flex",alignItems:"center",justifyContent:"center",position:"relative",boxSizing:"border-box",WebkitTapHighlightColor:"transparent",backgroundColor:"transparent",outline:0,border:0,margin:0,borderRadius:0,padding:0,cursor:"pointer",userSelect:"none",verticalAlign:"middle",MozAppearance:"none",WebkitAppearance:"none",textDecoration:"none",color:"inherit","&::-moz-focus-inner":{borderStyle:"none"},[`&.${aC.disabled}`]:{pointerEvents:"none",cursor:"default"},"@media print":{colorAdjust:"exact"}}),R_=Qn.forwardRef(function(t,o){let r=Q({props:t,name:"MuiButtonBase"}),{action:n,centerRipple:a=!1,children:i,className:s,component:l="button",disabled:p=!1,disableRipple:c=!1,disableTouchRipple:d=!1,focusRipple:f=!1,focusVisibleClassName:u,LinkComponent:g="a",onBlur:x,onClick:v,onContextMenu:m,onDragLeave:y,onFocus:h,onFocusVisible:T,onKeyDown:P,onKeyUp:S,onMouseDown:E,onMouseLeave:R,onMouseUp:w,onTouchEnd:O,onTouchMove:A,onTouchStart:b,tabIndex:N=0,TouchRippleProps:M,touchRippleRef:_,type:D,...K}=r,ee=Qn.useRef(null),q=km(),ye=Et(q.ref,_),[se,ce]=Qn.useState(!1);p&&se&&ce(!1),Qn.useImperativeHandle(n,()=>({focusVisible:()=>{ce(!0),ee.current.focus()}}),[]);let oe=q.shouldMount&&!c&&!p;Qn.useEffect(()=>{se&&f&&!c&&q.pulsate()},[c,f,se,q]);let Ce=wa(q,"start",E,d),pe=wa(q,"stop",m,d),re=wa(q,"stop",y,d),Te=wa(q,"stop",w,d),he=wa(q,"stop",ae=>{se&&ae.preventDefault(),R&&R(ae)},d),Ee=wa(q,"start",b,d),le=wa(q,"stop",O,d),fe=wa(q,"stop",A,d),ge=wa(q,"stop",ae=>{xn(ae.target)||ce(!1),x&&x(ae)},!1),$=ui(ae=>{ee.current||(ee.current=ae.currentTarget),xn(ae.target)&&(ce(!0),T&&T(ae)),h&&h(ae)}),U=()=>{let ae=ee.current;return ae?ae.tagName==="BUTTON"?!1:!(ae.tagName==="A"&&ae.href):l&&l!=="button"},Pe=ui(ae=>{f&&!ae.repeat&&se&&ae.key===" "&&q.stop(ae,()=>{q.start(ae)}),ae.target===ae.currentTarget&&U()&&ae.key===" "&&ae.preventDefault(),P&&P(ae),ae.target===ae.currentTarget&&U()&&ae.key==="Enter"&&!p&&(ae.preventDefault(),v&&v(ae))}),Me=ui(ae=>{f&&ae.key===" "&&se&&!ae.defaultPrevented&&q.stop(ae,()=>{q.pulsate(ae)}),S&&S(ae),v&&ae.target===ae.currentTarget&&U()&&ae.key===" "&&!ae.defaultPrevented&&!p&&v(ae)}),Se=l;Se==="button"&&(K.href||K.to)&&(Se=g);let Oe={};if(Se==="button"){let ae=!!K.formAction;Oe.type=D===void 0&&!ae?"button":D,Oe.disabled=p}else!K.href&&!K.to&&(Oe.role="button"),p&&(Oe["aria-disabled"]=p);let Ve=Et(o,ee),Ze={...r,centerRipple:a,component:l,disabled:p,disableRipple:c,disableTouchRipple:d,focusRipple:f,tabIndex:N,focusVisible:se},Fe=C_(Ze);return Line truncated
0% {
transform: rotate(0deg);
}
@@ -123,7 +123,7 @@ To suppress this warning, you need to explicitly provide the \`palette.${t}Chann
100% {
transform: rotate(360deg);
}
`,jT=vo`
`,VT=Ro`
0% {
stroke-dasharray: 1px, 200px;
stroke-dashoffset: 0;
@@ -138,13 +138,13 @@ To suppress this warning, you need to explicitly provide the \`palette.${t}Chann
stroke-dasharray: 1px, 200px;
stroke-dashoffset: -126px;
}
`,O_=typeof zT!="string"?ir`
animation: ${zT} 1.4s linear infinite;
`:null,w_=typeof jT!="string"?ir`
animation: ${jT} 1.4s ease-in-out infinite;
`:null,N_=e=>{let{classes:t,variant:o,color:r,disableShrink:n}=e,a={root:["root",o,`color${j(r)}`],svg:["svg"],track:["track"],circle:["circle",`circle${j(o)}`,n&&"circleDisableShrink"]};return Y(a,tC,t)},M_=D("span",{name:"MuiCircularProgress",slot:"Root",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.root,t[o.variant],t[`color${j(o.color)}`]]}})(Z(({theme:e})=>({display:"inline-block",variants:[{props:{variant:"determinate"},style:{transition:e.transitions.create("transform")}},{props:{variant:"indeterminate"},style:O_||{animation:`${zT} 1.4s linear infinite`}},...Object.entries(e.palette).filter(Be()).map(([t])=>({props:{color:t},style:{color:(e.vars||e).palette[t].main}}))]}))),A_=D("svg",{name:"MuiCircularProgress",slot:"Svg"})({display:"block"}),D_=D("circle",{name:"MuiCircularProgress",slot:"Circle",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.circle,t[`circle${j(o.variant)}`],o.disableShrink&&t.circleDisableShrink]}})(Z(({theme:e})=>({stroke:"currentColor",variants:[{props:{variant:"determinate"},style:{transition:e.transitions.create("stroke-dashoffset")}},{props:{variant:"indeterminate"},style:{strokeDasharray:"80px, 200px",strokeDashoffset:0}},{props:({ownerState:t})=>t.variant==="indeterminate"&&!t.disableShrink,style:w_||{animation:`${jT} 1.4s ease-in-out infinite`}}]}))),k_=D("circle",{name:"MuiCircularProgress",slot:"Track"})(Z(({theme:e})=>({stroke:"currentColor",opacity:(e.vars||e).palette.action.activatedOpacity}))),__=oC.forwardRef(function(t,o){let r=X({props:t,name:"MuiCircularProgress"}),{className:n,color:a="primary",disableShrink:i=!1,enableTrackSlot:s=!1,size:l=40,style:p,thickness:c=3.6,value:m=0,variant:f="indeterminate",...u}=r,g={...r,color:a,disableShrink:i,size:l,thickness:c,value:m,variant:f,enableTrackSlot:s},v=N_(g),x={},d={},y={};if(f==="determinate"){let h=2*Math.PI*((xn-c)/2);x.strokeDasharray=h.toFixed(3),y["aria-valuenow"]=Math.round(m),x.strokeDashoffset=`${((100-m)/100*h).toFixed(3)}px`,d.transform="rotate(-90deg)"}return(0,Ql.jsx)(M_,{className:L(v.root,n),style:{width:l,height:l,...d,...p},ownerState:g,ref:o,role:"progressbar",...y,...u,children:(0,Ql.jsxs)(A_,{className:v.svg,ownerState:g,viewBox:`${xn/2} ${xn/2} ${xn} ${xn}`,children:[s?(0,Ql.jsx)(k_,{className:v.track,ownerState:g,cx:xn,cy:xn,r:(xn-c)/2,fill:"none",strokeWidth:c,"aria-hidden":"true"}):null,(0,Ql.jsx)(D_,{className:v.circle,style:x,ownerState:g,cx:xn,cy:xn,r:(xn-c)/2,fill:"none",strokeWidth:c})]})})}),fu=__;function rC(e){return q("MuiIconButton",e)}var z_=G("MuiIconButton",["root","disabled","colorInherit","colorPrimary","colorSecondary","colorError","colorInfo","colorSuccess","colorWarning","edgeStart","edgeEnd","sizeSmall","sizeMedium","sizeLarge","loading","loadingIndicator","loadingWrapper"]),BT=z_;var Zl=C(U(),1),j_=e=>{let{classes:t,disabled:o,color:r,edge:n,size:a,loading:i}=e,s={root:["root",i&&"loading",o&&"disabled",r!=="default"&&`color${j(r)}`,n&&`edge${j(n)}`,`size${j(a)}`],loadingIndicator:["loadingIndicator"],loadingWrapper:["loadingWrapper"]};return Y(s,rC,t)},B_=D(pr,{name:"MuiIconButton",slot:"Root",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.root,o.loading&&t.loading,o.color!=="default"&&t[`color${j(o.color)}`],o.edge&&t[`edge${j(o.edge)}`],t[`size${j(o.size)}`]]}})(Z(({theme:e})=>({textAlign:"center",flex:"0 0 auto",fontSize:e.typography.pxToRem(24),padding:8,borderRadius:"50%",color:(e.vars||e).palette.action.active,transition:e.transitions.create("background-color",{duration:e.transitions.duration.shortest}),variants:[{props:t=>!t.disableRipple,style:{"--IconButton-hoverBg":e.alpha((e.vars||e).palette.action.active,(e.vars||e).palette.action.hoverOpacity),"&:hover":{backgroundColor:"var(--IconButton-hoverBg)","@media (hover: none)":{backgroundColor:"transparent"}}}},{props:{edge:"start"},style:{marginLeft:-12}},{props:{edge:"start",size:"small"},style:{marginLeft:-3}},{props:{edge:"end"},style:{marginRight:-12}},{props:{edge:"end",size:"small"},style:{marginRight:-3}}]})),Z(({theme:e})=>({variants:[{props:{color:"inherit"},style:{color:"inherit"}},...Object.entries(e.palette).filter(Be()).map(([t])=>({props:{color:t},style:{color:(e.vars||e).palette[t].main}})),...Object.entries(e.palette).filter(Be()).map(([t])=>({props:{color:t},style:{"--IconButton-hoverBg":e.alpha((e.vars||e).palette[t].main,(e.vars||e).palette.action.hoverOpacity)}})),{props:{size:"small"},style:{padding:5,fontSize:e.typography.pxToRem(18)}},{props:{size:"large"},style:{padding:12,fontSize:e.typography.pxToRem(28)}}],[`&.${BT.disabled}`]:{backgroundColor:"transparent",color:(e.vars||e).palette.action.disabled},[`&.${BT.loading}`]:{color:"transparent"}}))),U_=D("span",{name:"MuiIconButton",slot:"LoadingIndicator"})(({theme:e})=>({display:"none",position:"absolute",visibility:"visible",top:"50%",left:"50%",transform:"translate(-50%, -50%)",color:(e.vars||e).palette.action.disabled,variants:[{props:{loading:!0},style:{display:"flex"}}]})),L_=Mm.forwardRef(function(t,o){ Line truncated
`&&(T.value+=" ");let E=S.boxSizing,R=Im(S.paddingBottom)+Im(S.paddingTop),w=Im(S.borderBottomWidth)+Im(S.borderTopWidth),O=T.scrollHeight;T.value="x";let N=T.scrollHeight,b=O;a&&(b=Math.max(Number(a)*N,b)),n&&(b=Math.min(Number(n)*N,b)),b=Math.max(b,N);let M=b+(E==="border-box"?R+w:0),A=Math.abs(b-O)<=1;return{outerHeightStyle:M,overflowing:A}},[n,a,t.placeholder]),v=Er(()=>{let h=c.current,T=g();if(!h||!T||QC(T))return!1;let P=T.outerHeightStyle;return f.current!=null&&f.current!==P}),x=Mr.useCallback(()=>{let h=c.current,T=g();if(!h||!T||QC(T))return;let P=T.outerHeightStyle;f.current!==P&&(f.current=P,h.style.height=`${P}px`),h.style.overflow=T.overflowing?"hidden":""},[g]),d=Mr.useRef(-1);return Gt(()=>{let h=Il(x),T=c?.current;if(!T)return;let P=Kr(T);P.addEventListener("resize",h);let S;return typeof ResizeObserver<"u"&&(S=new ResizeObserver(()=>{v()&&(S.unobserve(T),cancelAnimationFrame(d.current),x(),d.current=requestAnimationFrame(()=>{S.observe(T)}))}),S.observe(T)),()=>{h.clear(),cancelAnimationFrame(d.current),P.removeEventListener("resize",h),S&&S.disconnect()}},[g,x,v]),Gt(()=>{x()}),(0,Pu.jsxs)(Mr.Fragment,{children:[(0,Pu.jsx)("textarea",{value:s,onChange:h=>{p||x();let T=h.target,P=T.value.length,S=T.value.endsWith(`
`),E=T.selectionStart===P;S&&E&&T.setSelectionRange(P,P),r&&r(h)},ref:m,rows:a,style:i,...l}),(0,Pu.jsx)("textarea",{"aria-hidden":!0,className:t.className,readOnly:!0,ref:u,tabIndex:-1,style:{...Yz.shadow,...i,paddingTop:0,paddingBottom:0}})]})}),JT=Wz;function Xo({props:e,states:t,muiFormControl:o}){return t.reduce((r,n)=>(r[n]=e[n],o&&typeof e[n]>"u"&&(r[n]=o[n]),r),{})}var ZC=C(I(),1),Xz=ZC.createContext(void 0),np=Xz;var JC=C(I(),1);function uo(){return JC.useContext(np)}function Hm(e){let t=e.activeElement;for(;t?.shadowRoot?.activeElement!=null;)t=t.shadowRoot.activeElement;return t}var Na=Hm;function eE(e){return e!=null&&!(Array.isArray(e)&&e.length===0)}function Os(e,t=!1){return e&&(eE(e.value)&&e.value!==""||t&&eE(e.defaultValue)&&e.defaultValue!=="")}function tE(e){return e.startAdornment}function oE(e){return q("MuiInputBase",e)}var Qz=G("MuiInputBase",["root","formControl","focused","disabled","adornedStart","adornedEnd","error","sizeSmall","multiline","colorSecondary","fullWidth","hiddenLabel","readOnly","input","inputSizeSmall","inputMultiline","inputTypeSearch","inputAdornedStart","inputAdornedEnd","inputHiddenLabel"]),En=Qz;var ws=C(U(),1),rE,eb="mui-auto-fill",$m="mui-auto-fill-cancel",Ns=(e,t)=>{let{ownerState:o}=e;return[t.root,o.formControl&&t.formControl,o.startAdornment&&t.adornedStart,o.endAdornment&&t.adornedEnd,o.error&&t.error,o.size==="small"&&t.sizeSmall,o.multiline&&t.multiline,o.color&&t[`color${j(o.color)}`],o.fullWidth&&t.fullWidth,o.hiddenLabel&&t.hiddenLabel]},Ms=(e,t)=>{let{ownerState:o}=e;return[t.input,o.size==="small"&&t.inputSizeSmall,o.multiline&&t.inputMultiline,o.type==="search"&&t.inputTypeSearch,o.startAdornment&&t.inputAdornedStart,o.endAdornment&&t.inputAdornedEnd,o.hiddenLabel&&t.inputHiddenLabel]},Zz=e=>{let{classes:t,color:o,disabled:r,error:n,endAdornment:a,focused:i,formControl:s,fullWidth:l,hiddenLabel:p,multiline:c,readOnly:m,size:f,startAdornment:u,type:g}=e,v={root:["root",`color${j(o)}`,r&&"disabled",n&&"error",l&&"fullWidth",i&&"focused",s&&"formControl",f&&f!=="medium"&&`size${j(f)}`,c&&"multiline",u&&"adornedStart",a&&"adornedEnd",p&&"hiddenLabel",m&&"readOnly"],input:["input",r&&"disabled",g==="search"&&"inputTypeSearch",c&&"inputMultiline",f==="small"&&"inputSizeSmall",p&&"inputHiddenLabel",u&&"inputAdornedStart",a&&"inputAdornedEnd",m&&"readOnly"]};return Y(v,oE,t)},As=D("div",{name:"MuiInputBase",slot:"Root",overridesResolver:Ns})(Z(({theme:e})=>({...e.typography.body1,color:(e.vars||e).palette.text.primary,lineHeight:"1.4375em",boxSizing:"border-box",position:"relative",cursor:"text",display:"inline-flex",alignItems:"center",[`&.${En.disabled}`]:{color:(e.vars||e).palette.text.disabled,cursor:"default"},variants:[{props:({ownerState:t})=>t.multiline,style:{padding:"4px 0 5px"}},{props:({ownerState:t,size:o})=>t.multiline&&o==="small",style:{paddingTop:1}},{props:({ownerState:t})=>t.fullWidth,style:{width:"100%"}}]}))),Ds=D("input",{name:"MuiInputBase",slot:"Input",overridesResolver:Ms})(Z(({theme:e})=>{let t=e.palette.mode==="light",o={color:"currentColor",...e.vars?{opacity:e.vars.opacity.inputPlaceholder}:{opacity:t?.42:.5},transition:e.transitions.create("opacity",{duration:e.transitions.duration.shorter})},r={opacity:"0 !important"},n=e.vars?{opacity:e.vars.opacity.inputPlaceholder}:{opacity:t?.42:.5};return{font:"inherit",letterSpacing:"inherit",color:"currentColor",padding:"4px 0 5px",border:0,boxSizing:"content-box",background:"none",height:"1.4375em",margin:0,WebkitTapHighlightColor:"transparent",display:"block",minWidth:0,width:"100%","&::-webkit-input-placeholder":o,"&::-moz-placeholder":o,"&::-ms-input-placeholder":o,"&:focus":{outline:0},"&:invalid":{boxShadow:"none"},"&::-webkit-search-decoration":{WebkitAppearance:"none"},[`label[data-shrink=false] + .${En.formControl} &`]:{"&::-webkit-input-placeholder":r,"&::-moz-placeholder":r,"&::-ms-input-placeholder":r,"&:focus::-webkit-input-placeholder":n,"&:focus::-moz-placeholder":n,"&:focus::-ms-input-placeholder":n},[`&.${En.disabled}`]:{opacity:1,WebkitTextFillColor:(e.vars||e).palette.text.disabled},variants:[{props:({ownerState:a})=>!a.disableInjectingGlobalStyles,style:{animationName:$m,animationDuration:"10ms","&:-webkit-autofill":{animationDuration:"5000s",animationName:eb}}},{props:{size:"small"},style:{paddingTop:1}},{props:({ownerState:a})=>a.multiline,style:{height:"auto",resize:"none",padding:0,paddingTop:0}},{props:{type:"search"},style:{MozAppearance:"textfield"}}]}})),nE=Jc({[`@keyframes ${eb}`]:{from:{animationName:eb}},[`@keyframes ${$m}`]:{from:{animationName:$m}}}),Jz=Uo.forwardRef(function(t,o){let r=X({props:t,name:"MuiInputBase"}),{"aria-describedby":n,autoComplete:a,autoFocus:i,className:s,color:l,components:p={},componentsProps:c={},defaultValue:m,disabled:f,disableInjectingGlobalStyles:u,endAdornment:g,error:v,fullWidth:x=!1,id:d,inputComponent:y="input",inputProps:h={},inputRef:T,margin:P,maxRows:S,minRows:E,multiline:R=!1,name:w,onBlur:O,onChange:N,onClick Line truncated
`,j_=typeof HT!="string"?pr`
animation: ${HT} 1.4s linear infinite;
`:null,B_=typeof VT!="string"?pr`
animation: ${VT} 1.4s ease-in-out infinite;
`:null,U_=e=>{let{classes:t,variant:o,color:r,disableShrink:n}=e,a={root:["root",o,`color${B(r)}`],svg:["svg"],track:["track"],circle:["circle",`circle${B(o)}`,n&&"circleDisableShrink"]};return W(a,lC,t)},L_=k("span",{name:"MuiCircularProgress",slot:"Root",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.root,t[o.variant],t[`color${B(o.color)}`]]}})(J(({theme:e})=>({display:"inline-block",variants:[{props:{variant:"determinate"},style:{transition:e.transitions.create("transform")}},{props:{variant:"indeterminate"},style:j_||{animation:`${HT} 1.4s linear infinite`}},...Object.entries(e.palette).filter(Ue()).map(([t])=>({props:{color:t},style:{color:(e.vars||e).palette[t].main}}))]}))),I_=k("svg",{name:"MuiCircularProgress",slot:"Svg"})({display:"block"}),$_=k("circle",{name:"MuiCircularProgress",slot:"Circle",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.circle,t[`circle${B(o.variant)}`],o.disableShrink&&t.circleDisableShrink]}})(J(({theme:e})=>({stroke:"currentColor",variants:[{props:{variant:"determinate"},style:{transition:e.transitions.create("stroke-dashoffset")}},{props:{variant:"indeterminate"},style:{strokeDasharray:"80px, 200px",strokeDashoffset:0}},{props:({ownerState:t})=>t.variant==="indeterminate"&&!t.disableShrink,style:B_||{animation:`${VT} 1.4s ease-in-out infinite`}}]}))),H_=k("circle",{name:"MuiCircularProgress",slot:"Track"})(J(({theme:e})=>({stroke:"currentColor",opacity:(e.vars||e).palette.action.activatedOpacity}))),V_=pC.forwardRef(function(t,o){let r=Q({props:t,name:"MuiCircularProgress"}),{className:n,color:a="primary",disableShrink:i=!1,enableTrackSlot:s=!1,size:l=40,style:p,thickness:c=3.6,value:d=0,variant:f="indeterminate",...u}=r,g={...r,color:a,disableShrink:i,size:l,thickness:c,value:d,variant:f,enableTrackSlot:s},x=U_(g),v={},m={},y={};if(f==="determinate"){let h=2*Math.PI*((Pn-c)/2);v.strokeDasharray=h.toFixed(3),y["aria-valuenow"]=Math.round(d),v.strokeDashoffset=`${((100-d)/100*h).toFixed(3)}px`,m.transform="rotate(-90deg)"}return(0,ap.jsx)(L_,{className:L(x.root,n),style:{width:l,height:l,...m,...p},ownerState:g,ref:o,role:"progressbar",...y,...u,children:(0,ap.jsxs)(I_,{className:x.svg,ownerState:g,viewBox:`${Pn/2} ${Pn/2} ${Pn} ${Pn}`,children:[s?(0,ap.jsx)(H_,{className:x.track,ownerState:g,cx:Pn,cy:Pn,r:(Pn-c)/2,fill:"none",strokeWidth:c,"aria-hidden":"true"}):null,(0,ap.jsx)($_,{className:x.circle,style:v,ownerState:g,cx:Pn,cy:Pn,r:(Pn-c)/2,fill:"none",strokeWidth:c})]})})}),yi=V_;function cC(e){return G("MuiIconButton",e)}var F_=Y("MuiIconButton",["root","disabled","colorInherit","colorPrimary","colorSecondary","colorError","colorInfo","colorSuccess","colorWarning","edgeStart","edgeEnd","sizeSmall","sizeMedium","sizeLarge","loading","loadingIndicator","loadingWrapper"]),FT=F_;var ip=C(z(),1),q_=e=>{let{classes:t,disabled:o,color:r,edge:n,size:a,loading:i}=e,s={root:["root",i&&"loading",o&&"disabled",r!=="default"&&`color${B(r)}`,n&&`edge${B(n)}`,`size${B(a)}`],loadingIndicator:["loadingIndicator"],loadingWrapper:["loadingWrapper"]};return W(s,cC,t)},G_=k(fr,{name:"MuiIconButton",slot:"Root",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.root,o.loading&&t.loading,o.color!=="default"&&t[`color${B(o.color)}`],o.edge&&t[`edge${B(o.edge)}`],t[`size${B(o.size)}`]]}})(J(({theme:e})=>({textAlign:"center",flex:"0 0 auto",fontSize:e.typography.pxToRem(24),padding:8,borderRadius:"50%",color:(e.vars||e).palette.action.active,transition:e.transitions.create("background-color",{duration:e.transitions.duration.shortest}),variants:[{props:t=>!t.disableRipple,style:{"--IconButton-hoverBg":e.alpha((e.vars||e).palette.action.active,(e.vars||e).palette.action.hoverOpacity),"&:hover":{backgroundColor:"var(--IconButton-hoverBg)","@media (hover: none)":{backgroundColor:"transparent"}}}},{props:{edge:"start"},style:{marginLeft:-12}},{props:{edge:"start",size:"small"},style:{marginLeft:-3}},{props:{edge:"end"},style:{marginRight:-12}},{props:{edge:"end",size:"small"},style:{marginRight:-3}}]})),J(({theme:e})=>({variants:[{props:{color:"inherit"},style:{color:"inherit"}},...Object.entries(e.palette).filter(Ue()).map(([t])=>({props:{color:t},style:{color:(e.vars||e).palette[t].main}})),...Object.entries(e.palette).filter(Ue()).map(([t])=>({props:{color:t},style:{"--IconButton-hoverBg":e.alpha((e.vars||e).palette[t].main,(e.vars||e).palette.action.hoverOpacity)}})),{props:{size:"small"},style:{padding:5,fontSize:e.typography.pxToRem(18)}},{props:{size:"large"},style:{padding:12,fontSize:e.typography.pxToRem(28)}}],[`&.${FT.disabled}`]:{backgroundColor:"transparent",color:(e.vars||e).palette.action.disabled},[`&.${FT.loading}`]:{color:"transparent"}}))),Y_=k("span",{name:"MuiIconButton",slot:"LoadingIndicator"})(({theme:e})=>({display:"none",position:"absolute",visibility:"visible",top:"50%",left:"50%",transform:"translate(-50%, -50%)",color:(e.vars||e).palette.action.disabled,variants:[{props:{loading:!0},style:{display:"flex"}}]})),W_=Um.forwardRef(function(t,o){ Line truncated
`&&(T.value+=" ");let E=S.boxSizing,R=Wm(S.paddingBottom)+Wm(S.paddingTop),w=Wm(S.borderBottomWidth)+Wm(S.borderTopWidth),O=T.scrollHeight;T.value="x";let A=T.scrollHeight,b=O;a&&(b=Math.max(Number(a)*A,b)),n&&(b=Math.min(Number(n)*A,b)),b=Math.max(b,A);let N=b+(E==="border-box"?R+w:0),M=Math.abs(b-O)<=1;return{outerHeightStyle:N,overflowing:M}},[n,a,t.placeholder]),x=Rr(()=>{let h=c.current,T=g();if(!h||!T||nE(T))return!1;let P=T.outerHeightStyle;return f.current!=null&&f.current!==P}),v=Mr.useCallback(()=>{let h=c.current,T=g();if(!h||!T||nE(T))return;let P=T.outerHeightStyle;f.current!==P&&(f.current=P,h.style.height=`${P}px`),h.style.overflow=T.overflowing?"hidden":""},[g]),m=Mr.useRef(-1);return Xt(()=>{let h=Wl(v),T=c?.current;if(!T)return;let P=Kr(T);P.addEventListener("resize",h);let S;return typeof ResizeObserver<"u"&&(S=new ResizeObserver(()=>{x()&&(S.unobserve(T),cancelAnimationFrame(m.current),v(),m.current=requestAnimationFrame(()=>{S.observe(T)}))}),S.observe(T)),()=>{h.clear(),cancelAnimationFrame(m.current),P.removeEventListener("resize",h),S&&S.disconnect()}},[g,v,x]),Xt(()=>{v()}),(0,Mu.jsxs)(Mr.Fragment,{children:[(0,Mu.jsx)("textarea",{value:s,onChange:h=>{p||v();let T=h.target,P=T.value.length,S=T.value.endsWith(`
`),E=T.selectionStart===P;S&&E&&T.setSelectionRange(P,P),r&&r(h)},ref:d,rows:a,style:i,...l}),(0,Mu.jsx)("textarea",{"aria-hidden":!0,className:t.className,readOnly:!0,ref:u,tabIndex:-1,style:{...o6.shadow,...i,paddingTop:0,paddingBottom:0}})]})}),ib=n6;function tr({props:e,states:t,muiFormControl:o}){return t.reduce((r,n)=>(r[n]=e[n],o&&typeof e[n]>"u"&&(r[n]=o[n]),r),{})}var aE=C(I(),1),a6=aE.createContext(void 0),fp=a6;var iE=C(I(),1);function go(){return iE.useContext(fp)}function Km(e){let t=e.activeElement;for(;t?.shadowRoot?.activeElement!=null;)t=t.shadowRoot.activeElement;return t}var Da=Km;function sE(e){return e!=null&&!(Array.isArray(e)&&e.length===0)}function _s(e,t=!1){return e&&(sE(e.value)&&e.value!==""||t&&sE(e.defaultValue)&&e.defaultValue!=="")}function lE(e){return e.startAdornment}function pE(e){return G("MuiInputBase",e)}var i6=Y("MuiInputBase",["root","formControl","focused","disabled","adornedStart","adornedEnd","error","sizeSmall","multiline","colorSecondary","fullWidth","hiddenLabel","readOnly","input","inputSizeSmall","inputMultiline","inputTypeSearch","inputAdornedStart","inputAdornedEnd","inputHiddenLabel"]),Rn=i6;var zs=C(z(),1),cE,sb="mui-auto-fill",Xm="mui-auto-fill-cancel",js=(e,t)=>{let{ownerState:o}=e;return[t.root,o.formControl&&t.formControl,o.startAdornment&&t.adornedStart,o.endAdornment&&t.adornedEnd,o.error&&t.error,o.size==="small"&&t.sizeSmall,o.multiline&&t.multiline,o.color&&t[`color${B(o.color)}`],o.fullWidth&&t.fullWidth,o.hiddenLabel&&t.hiddenLabel]},Bs=(e,t)=>{let{ownerState:o}=e;return[t.input,o.size==="small"&&t.inputSizeSmall,o.multiline&&t.inputMultiline,o.type==="search"&&t.inputTypeSearch,o.startAdornment&&t.inputAdornedStart,o.endAdornment&&t.inputAdornedEnd,o.hiddenLabel&&t.inputHiddenLabel]},s6=e=>{let{classes:t,color:o,disabled:r,error:n,endAdornment:a,focused:i,formControl:s,fullWidth:l,hiddenLabel:p,multiline:c,readOnly:d,size:f,startAdornment:u,type:g}=e,x={root:["root",`color${B(o)}`,r&&"disabled",n&&"error",l&&"fullWidth",i&&"focused",s&&"formControl",f&&f!=="medium"&&`size${B(f)}`,c&&"multiline",u&&"adornedStart",a&&"adornedEnd",p&&"hiddenLabel",d&&"readOnly"],input:["input",r&&"disabled",g==="search"&&"inputTypeSearch",c&&"inputMultiline",f==="small"&&"inputSizeSmall",p&&"inputHiddenLabel",u&&"inputAdornedStart",a&&"inputAdornedEnd",d&&"readOnly"]};return W(x,pE,t)},Us=k("div",{name:"MuiInputBase",slot:"Root",overridesResolver:js})(J(({theme:e})=>({...e.typography.body1,color:(e.vars||e).palette.text.primary,lineHeight:"1.4375em",boxSizing:"border-box",position:"relative",cursor:"text",display:"inline-flex",alignItems:"center",[`&.${Rn.disabled}`]:{color:(e.vars||e).palette.text.disabled,cursor:"default"},variants:[{props:({ownerState:t})=>t.multiline,style:{padding:"4px 0 5px"}},{props:({ownerState:t,size:o})=>t.multiline&&o==="small",style:{paddingTop:1}},{props:({ownerState:t})=>t.fullWidth,style:{width:"100%"}}]}))),Ls=k("input",{name:"MuiInputBase",slot:"Input",overridesResolver:Bs})(J(({theme:e})=>{let t=e.palette.mode==="light",o={color:"currentColor",...e.vars?{opacity:e.vars.opacity.inputPlaceholder}:{opacity:t?.42:.5},transition:e.transitions.create("opacity",{duration:e.transitions.duration.shorter})},r={opacity:"0 !important"},n=e.vars?{opacity:e.vars.opacity.inputPlaceholder}:{opacity:t?.42:.5};return{font:"inherit",letterSpacing:"inherit",color:"currentColor",padding:"4px 0 5px",border:0,boxSizing:"content-box",background:"none",height:"1.4375em",margin:0,WebkitTapHighlightColor:"transparent",display:"block",minWidth:0,width:"100%","&::-webkit-input-placeholder":o,"&::-moz-placeholder":o,"&::-ms-input-placeholder":o,"&:focus":{outline:0},"&:invalid":{boxShadow:"none"},"&::-webkit-search-decoration":{WebkitAppearance:"none"},[`label[data-shrink=false] + .${Rn.formControl} &`]:{"&::-webkit-input-placeholder":r,"&::-moz-placeholder":r,"&::-ms-input-placeholder":r,"&:focus::-webkit-input-placeholder":n,"&:focus::-moz-placeholder":n,"&:focus::-ms-input-placeholder":n},[`&.${Rn.disabled}`]:{opacity:1,WebkitTextFillColor:(e.vars||e).palette.text.disabled},variants:[{props:({ownerState:a})=>!a.disableInjectingGlobalStyles,style:{animationName:Xm,animationDuration:"10ms","&:-webkit-autofill":{animationDuration:"5000s",animationName:sb}}},{props:{size:"small"},style:{paddingTop:1}},{props:({ownerState:a})=>a.multiline,style:{height:"auto",resize:"none",padding:0,paddingTop:0}},{props:{type:"search"},style:{MozAppearance:"textfield"}}]}})),uE=lu({[`@keyframes ${sb}`]:{from:{animationName:sb}},[`@keyframes ${Xm}`]:{from:{animationName:Xm}}}),l6=Vo.forwardRef(function(t,o){let r=Q({props:t,name:"MuiInputBase"}),{"aria-describedby":n,autoComplete:a,autoFocus:i,className:s,color:l,components:p={},componentsProps:c={},defaultValue:d,disabled:f,disableInjectingGlobalStyles:u,endAdornment:g,error:x,fullWidth:v=!1,id:m,inputComponent:y="input",inputProps:h={},inputRef:T,margin:P,maxRows:S,minRows:E,multiline:R=!1,name:w,onBlur:O,onChange:A,onClick Line truncated
0% {
left: -35%;
right: 100%;
@@ -159,9 +159,9 @@ To suppress this warning, you need to explicitly provide the \`palette.${t}Chann
left: 100%;
right: -90%;
}
`,J6=typeof gb!="string"?ir`
animation: ${gb} 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite;
`:null,Tb=vo`
`,lB=typeof Cb!="string"?pr`
animation: ${Cb} 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite;
`:null,Eb=Ro`
0% {
left: -200%;
right: 100%;
@@ -176,9 +176,9 @@ To suppress this warning, you need to explicitly provide the \`palette.${t}Chann
left: 107%;
right: -8%;
}
`,eB=typeof Tb!="string"?ir`
animation: ${Tb} 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) 1.15s infinite;
`:null,bb=vo`
`,pB=typeof Eb!="string"?pr`
animation: ${Eb} 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) 1.15s infinite;
`:null,Rb=Ro`
0% {
opacity: 1;
background-position: 0 -23px;
@@ -193,9 +193,9 @@ To suppress this warning, you need to explicitly provide the \`palette.${t}Chann
opacity: 1;
background-position: -200px -23px;
}
`,tB=typeof bb!="string"?ir`
animation: ${bb} 3s infinite linear;
`:null,oB=e=>{let{classes:t,variant:o,color:r}=e,n={root:["root",`color${j(r)}`,o],dashed:["dashed",`dashedColor${j(r)}`],bar1:["bar","bar1",`barColor${j(r)}`,(o==="indeterminate"||o==="query")&&"bar1Indeterminate",o==="determinate"&&"bar1Determinate",o==="buffer"&&"bar1Buffer"],bar2:["bar","bar2",o!=="buffer"&&`barColor${j(r)}`,o==="buffer"&&`color${j(r)}`,(o==="indeterminate"||o==="query")&&"bar2Indeterminate",o==="buffer"&&"bar2Buffer"]};return Y(n,gR,t)},vb=(e,t)=>e.vars?e.vars.palette.LinearProgress[`${t}Bg`]:e.palette.mode==="light"?e.lighten(e.palette[t].main,.62):e.darken(e.palette[t].main,.5),rB=D("span",{name:"MuiLinearProgress",slot:"Root",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.root,t[`color${j(o.color)}`],t[o.variant]]}})(Z(({theme:e})=>({position:"relative",overflow:"hidden",display:"block",height:4,zIndex:0,"@media print":{colorAdjust:"exact"},variants:[...Object.entries(e.palette).filter(Be()).map(([t])=>({props:{color:t},style:{backgroundColor:vb(e,t)}})),{props:({ownerState:t})=>t.color==="inherit"&&t.variant!=="buffer",style:{"&::before":{content:'""',position:"absolute",left:0,top:0,right:0,bottom:0,backgroundColor:"currentColor",opacity:.3}}},{props:{variant:"buffer"},style:{backgroundColor:"transparent"}},{props:{variant:"query"},style:{transform:"rotate(180deg)"}}]}))),nB=D("span",{name:"MuiLinearProgress",slot:"Dashed",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.dashed,t[`dashedColor${j(o.color)}`]]}})(Z(({theme:e})=>({position:"absolute",marginTop:0,height:"100%",width:"100%",backgroundSize:"10px 10px",backgroundPosition:"0 -23px",variants:[{props:{color:"inherit"},style:{opacity:.3,backgroundImage:"radial-gradient(currentColor 0%, currentColor 16%, transparent 42%)"}},...Object.entries(e.palette).filter(Be()).map(([t])=>{let o=vb(e,t);return{props:{color:t},style:{backgroundImage:`radial-gradient(${o} 0%, ${o} 16%, transparent 42%)`}}})]})),tB||{animation:`${bb} 3s infinite linear`}),aB=D("span",{name:"MuiLinearProgress",slot:"Bar1",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.bar,t.bar1,t[`barColor${j(o.color)}`],(o.variant==="indeterminate"||o.variant==="query")&&t.bar1Indeterminate,o.variant==="determinate"&&t.bar1Determinate,o.variant==="buffer"&&t.bar1Buffer]}})(Z(({theme:e})=>({width:"100%",position:"absolute",left:0,bottom:0,top:0,transition:"transform 0.2s linear",transformOrigin:"left",variants:[{props:{color:"inherit"},style:{backgroundColor:"currentColor"}},...Object.entries(e.palette).filter(Be()).map(([t])=>({props:{color:t},style:{backgroundColor:(e.vars||e).palette[t].main}})),{props:{variant:"determinate"},style:{transition:`transform .${hb}s linear`}},{props:{variant:"buffer"},style:{zIndex:1,transition:`transform .${hb}s linear`}},{props:({ownerState:t})=>t.variant==="indeterminate"||t.variant==="query",style:{width:"auto"}},{props:({ownerState:t})=>t.variant==="indeterminate"||t.variant==="query",style:J6||{animation:`${gb} 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite`}}]}))),iB=D("span",{name:"MuiLinearProgress",slot:"Bar2",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.bar,t.bar2,t[`barColor${j(o.color)}`],(o.variant==="indeterminate"||o.variant==="query")&&t.bar2Indeterminate,o.variant==="buffer"&&t.bar2Buffer]}})(Z(({theme:e})=>({width:"100%",position:"absolute",left:0,bottom:0,top:0,transition:"transform 0.2s linear",transformOrigin:"left",variants:[...Object.entries(e.palette).filter(Be()).map(([t])=>({props:{color:t},style:{"--LinearProgressBar2-barColor":(e.vars||e).palette[t].main}})),{props:({ownerState:t})=>t.variant!=="buffer"&&t.color!=="inherit",style:{backgroundColor:"var(--LinearProgressBar2-barColor, currentColor)"}},{props:({ownerState:t})=>t.variant!=="buffer"&&t.color==="inherit",style:{backgroundColor:"currentColor"}},{props:{color:"inherit"},style:{opacity:.3}},...Object.entries(e.palette).filter(Be()).map(([t])=>({props:{color:t,variant:"buffer"},style:{backgroundColor:vb(e,t),transition:`transform .${hb}s linear`}})),{props:({ownerState:t})=>t.variant==="indeterminate"||t.variant==="query",style:{width:"auto"}},{props:({ownerState:t})=>t.variant==="indeterminate"||t.variant==="query",style:eB||{animation:`${Tb} 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) 1.15s infinite`}}]}))),sB=TR.forwardRef(function(t,o){let r=X({props:t,name:"MuiLinearProgress"}),{className:n,color:a="primary",value:i,valueBuffer:s,variant:l="indeterminate",...p}=r,c={...r,color:a,variant:l},m=oB(c),f=ai(),u={},g={bar1:{},bar2:{}};if((l==="determinate"||l==="buffer")&&i!==void 0){u["aria-valuenow"]=Math.round(i),u["aria-valuemin"]=0,u["aria-valuemax"]=100;let v=i-100;f&&(v=-v),g.bar1.transform=`translateX(${v}%)`}if(l==="buffer"&&s!==void 0){let v=(s||0)-100;f&&(v=-v),g.bar2.transform=`translateX(${v}%)`}return(0,hp.jsxs)(rB,{className:L(m.root,n),ownerState:c,role:"progressbar",...u,ref:o,...p,children:[l==="buffer"?(0,hp.jsx)(nB,{className:m.dashed,ownerState:c}):null,(0,hp.jsx)(aB,{className:m.bar1,ownerState:c Line truncated
`,cB=typeof Rb!="string"?pr`
animation: ${Rb} 3s infinite linear;
`:null,uB=e=>{let{classes:t,variant:o,color:r}=e,n={root:["root",`color${B(r)}`,o],dashed:["dashed",`dashedColor${B(r)}`],bar1:["bar","bar1",`barColor${B(r)}`,(o==="indeterminate"||o==="query")&&"bar1Indeterminate",o==="determinate"&&"bar1Determinate",o==="buffer"&&"bar1Buffer"],bar2:["bar","bar2",o!=="buffer"&&`barColor${B(r)}`,o==="buffer"&&`color${B(r)}`,(o==="indeterminate"||o==="query")&&"bar2Indeterminate",o==="buffer"&&"bar2Buffer"]};return W(n,CR,t)},Ob=(e,t)=>e.vars?e.vars.palette.LinearProgress[`${t}Bg`]:e.palette.mode==="light"?e.lighten(e.palette[t].main,.62):e.darken(e.palette[t].main,.5),fB=k("span",{name:"MuiLinearProgress",slot:"Root",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.root,t[`color${B(o.color)}`],t[o.variant]]}})(J(({theme:e})=>({position:"relative",overflow:"hidden",display:"block",height:4,zIndex:0,"@media print":{colorAdjust:"exact"},variants:[...Object.entries(e.palette).filter(Ue()).map(([t])=>({props:{color:t},style:{backgroundColor:Ob(e,t)}})),{props:({ownerState:t})=>t.color==="inherit"&&t.variant!=="buffer",style:{"&::before":{content:'""',position:"absolute",left:0,top:0,right:0,bottom:0,backgroundColor:"currentColor",opacity:.3}}},{props:{variant:"buffer"},style:{backgroundColor:"transparent"}},{props:{variant:"query"},style:{transform:"rotate(180deg)"}}]}))),dB=k("span",{name:"MuiLinearProgress",slot:"Dashed",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.dashed,t[`dashedColor${B(o.color)}`]]}})(J(({theme:e})=>({position:"absolute",marginTop:0,height:"100%",width:"100%",backgroundSize:"10px 10px",backgroundPosition:"0 -23px",variants:[{props:{color:"inherit"},style:{opacity:.3,backgroundImage:"radial-gradient(currentColor 0%, currentColor 16%, transparent 42%)"}},...Object.entries(e.palette).filter(Ue()).map(([t])=>{let o=Ob(e,t);return{props:{color:t},style:{backgroundImage:`radial-gradient(${o} 0%, ${o} 16%, transparent 42%)`}}})]})),cB||{animation:`${Rb} 3s infinite linear`}),mB=k("span",{name:"MuiLinearProgress",slot:"Bar1",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.bar,t.bar1,t[`barColor${B(o.color)}`],(o.variant==="indeterminate"||o.variant==="query")&&t.bar1Indeterminate,o.variant==="determinate"&&t.bar1Determinate,o.variant==="buffer"&&t.bar1Buffer]}})(J(({theme:e})=>({width:"100%",position:"absolute",left:0,bottom:0,top:0,transition:"transform 0.2s linear",transformOrigin:"left",variants:[{props:{color:"inherit"},style:{backgroundColor:"currentColor"}},...Object.entries(e.palette).filter(Ue()).map(([t])=>({props:{color:t},style:{backgroundColor:(e.vars||e).palette[t].main}})),{props:{variant:"determinate"},style:{transition:`transform .${Sb}s linear`}},{props:{variant:"buffer"},style:{zIndex:1,transition:`transform .${Sb}s linear`}},{props:({ownerState:t})=>t.variant==="indeterminate"||t.variant==="query",style:{width:"auto"}},{props:({ownerState:t})=>t.variant==="indeterminate"||t.variant==="query",style:lB||{animation:`${Cb} 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite`}}]}))),yB=k("span",{name:"MuiLinearProgress",slot:"Bar2",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.bar,t.bar2,t[`barColor${B(o.color)}`],(o.variant==="indeterminate"||o.variant==="query")&&t.bar2Indeterminate,o.variant==="buffer"&&t.bar2Buffer]}})(J(({theme:e})=>({width:"100%",position:"absolute",left:0,bottom:0,top:0,transition:"transform 0.2s linear",transformOrigin:"left",variants:[...Object.entries(e.palette).filter(Ue()).map(([t])=>({props:{color:t},style:{"--LinearProgressBar2-barColor":(e.vars||e).palette[t].main}})),{props:({ownerState:t})=>t.variant!=="buffer"&&t.color!=="inherit",style:{backgroundColor:"var(--LinearProgressBar2-barColor, currentColor)"}},{props:({ownerState:t})=>t.variant!=="buffer"&&t.color==="inherit",style:{backgroundColor:"currentColor"}},{props:{color:"inherit"},style:{opacity:.3}},...Object.entries(e.palette).filter(Ue()).map(([t])=>({props:{color:t,variant:"buffer"},style:{backgroundColor:Ob(e,t),transition:`transform .${Sb}s linear`}})),{props:({ownerState:t})=>t.variant==="indeterminate"||t.variant==="query",style:{width:"auto"}},{props:({ownerState:t})=>t.variant==="indeterminate"||t.variant==="query",style:pB||{animation:`${Eb} 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) 1.15s infinite`}}]}))),hB=ER.forwardRef(function(t,o){let r=Q({props:t,name:"MuiLinearProgress"}),{className:n,color:a="primary",value:i,valueBuffer:s,variant:l="indeterminate",...p}=r,c={...r,color:a,variant:l},d=uB(c),f=ci(),u={},g={bar1:{},bar2:{}};if((l==="determinate"||l==="buffer")&&i!==void 0){u["aria-valuenow"]=Math.round(i),u["aria-valuemin"]=0,u["aria-valuemax"]=100;let x=i-100;f&&(x=-x),g.bar1.transform=`translateX(${x}%)`}if(l==="buffer"&&s!==void 0){let x=(s||0)-100;f&&(x=-x),g.bar2.transform=`translateX(${x}%)`}return(0,Cp.jsxs)(fB,{className:L(d.root,n),ownerState:c,role:"progressbar",...u,ref:o,...p,children:[l==="buffer"?(0,Cp.jsx)(dB,{className:d.dashed,ownerState:c}):null,(0,Cp.jsx)(mB,{className:d.bar1,ownerState:c Line truncated
0% {
opacity: 1;
}
@@ -207,7 +207,7 @@ To suppress this warning, you need to explicitly provide the \`palette.${t}Chann
100% {
opacity: 1;
}
`,jb=vo`
`,Vb=Ro`
0% {
transform: translateX(-100%);
}
@@ -220,22 +220,22 @@ To suppress this warning, you need to explicitly provide the \`palette.${t}Chann
100% {
transform: translateX(100%);
}
`,u9=typeof zb!="string"?ir`
animation: ${zb} 2s ease-in-out 0.5s infinite;
`:null,f9=typeof jb!="string"?ir`
`,v9=typeof Hb!="string"?pr`
animation: ${Hb} 2s ease-in-out 0.5s infinite;
`:null,x9=typeof Vb!="string"?pr`
&::after {
animation: ${jb} 2s linear 0.5s infinite;
animation: ${Vb} 2s linear 0.5s infinite;
}
`:null,d9=D("span",{name:"MuiSkeleton",slot:"Root",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.root,t[o.variant],o.animation!==!1&&t[o.animation],o.hasChildren&&t.withChildren,o.hasChildren&&!o.width&&t.fitContent,o.hasChildren&&!o.height&&t.heightAuto]}})(Z(({theme:e})=>{let t=bT(e.shape.borderRadius)||"px",o=vT(e.shape.borderRadius);return{display:"block",backgroundColor:e.vars?e.vars.palette.Skeleton.bg:e.alpha(e.palette.text.primary,e.palette.mode==="light"?.11:.13),height:"1.2em",variants:[{props:{variant:"text"},style:{marginTop:0,marginBottom:0,height:"auto",transformOrigin:"0 55%",transform:"scale(1, 0.60)",borderRadius:`${o}${t}/${Math.round(o/.6*10)/10}${t}`,"&:empty:before":{content:'"\\00a0"'}}},{props:{variant:"circular"},style:{borderRadius:"50%"}},{props:{variant:"rounded"},style:{borderRadius:(e.vars||e).shape.borderRadius}},{props:({ownerState:r})=>r.hasChildren,style:{"& > *":{visibility:"hidden"}}},{props:({ownerState:r})=>r.hasChildren&&!r.width,style:{maxWidth:"fit-content"}},{props:({ownerState:r})=>r.hasChildren&&!r.height,style:{height:"auto"}},{props:{animation:"pulse"},style:u9||{animation:`${zb} 2s ease-in-out 0.5s infinite`}},{props:{animation:"wave"},style:{position:"relative",overflow:"hidden",WebkitMaskImage:"-webkit-radial-gradient(white, black)","&::after":{background:`linear-gradient(
`:null,P9=k("span",{name:"MuiSkeleton",slot:"Root",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.root,t[o.variant],o.animation!==!1&&t[o.animation],o.hasChildren&&t.withChildren,o.hasChildren&&!o.width&&t.fitContent,o.hasChildren&&!o.height&&t.heightAuto]}})(J(({theme:e})=>{let t=RT(e.shape.borderRadius)||"px",o=OT(e.shape.borderRadius);return{display:"block",backgroundColor:e.vars?e.vars.palette.Skeleton.bg:e.alpha(e.palette.text.primary,e.palette.mode==="light"?.11:.13),height:"1.2em",variants:[{props:{variant:"text"},style:{marginTop:0,marginBottom:0,height:"auto",transformOrigin:"0 55%",transform:"scale(1, 0.60)",borderRadius:`${o}${t}/${Math.round(o/.6*10)/10}${t}`,"&:empty:before":{content:'"\\00a0"'}}},{props:{variant:"circular"},style:{borderRadius:"50%"}},{props:{variant:"rounded"},style:{borderRadius:(e.vars||e).shape.borderRadius}},{props:({ownerState:r})=>r.hasChildren,style:{"& > *":{visibility:"hidden"}}},{props:({ownerState:r})=>r.hasChildren&&!r.width,style:{maxWidth:"fit-content"}},{props:({ownerState:r})=>r.hasChildren&&!r.height,style:{height:"auto"}},{props:{animation:"pulse"},style:v9||{animation:`${Hb} 2s ease-in-out 0.5s infinite`}},{props:{animation:"wave"},style:{position:"relative",overflow:"hidden",WebkitMaskImage:"-webkit-radial-gradient(white, black)","&::after":{background:`linear-gradient(
90deg,
transparent,
${(e.vars||e).palette.action.hover},
transparent
)`,content:'""',position:"absolute",transform:"translateX(-100%)",bottom:0,left:0,right:0,top:0}}},{props:{animation:"wave"},style:f9||{"&::after":{animation:`${jb} 2s linear 0.5s infinite`}}}]}})),m9=KR.forwardRef(function(t,o){let r=X({props:t,name:"MuiSkeleton"}),{animation:n="pulse",className:a,component:i="span",height:s,style:l,variant:p="text",width:c,...m}=r,f={...r,animation:n,component:i,variant:p,hasChildren:!!m.children},u=c9(f);return(0,WR.jsx)(d9,{as:i,ref:o,className:L(u.root,a),ownerState:f,...m,style:{width:c,height:s,...l}})}),Fu=m9;var xy=C(I(),1);var xp=C(I(),1);function y9(e={}){let{autoHideDuration:t=null,disableWindowBlurListener:o=!1,onClose:r,open:n,resumeHideDuration:a}=e,i=Ko();xp.useEffect(()=>{if(!n)return;function d(y){y.defaultPrevented||y.key==="Escape"&&r?.(y,"escapeKeyDown")}return document.addEventListener("keydown",d),()=>{document.removeEventListener("keydown",d)}},[n,r]);let s=Er((d,y)=>{r?.(d,y)}),l=Er(d=>{!r||d==null||i.start(d,()=>{s(null,"timeout")})});xp.useEffect(()=>(n&&l(t),i.clear),[n,t,l,i]);let p=d=>{r?.(d,"clickaway")},c=i.clear,m=xp.useCallback(()=>{t!=null&&l(a??t*.5)},[t,a,l]),f=d=>y=>{let h=d.onBlur;h?.(y),m()},u=d=>y=>{let h=d.onFocus;h?.(y),c()},g=d=>y=>{let h=d.onMouseEnter;h?.(y),c()},v=d=>y=>{let h=d.onMouseLeave;h?.(y),m()};return xp.useEffect(()=>{if(!o&&n)return window.addEventListener("focus",m),window.addEventListener("blur",c),()=>{window.removeEventListener("focus",m),window.removeEventListener("blur",c)}},[o,n,m,c]),{getRootProps:(d={})=>{let y={...pi(e),...pi(d)};return{role:"presentation",...d,...y,onBlur:f(y),onFocus:u(y),onMouseEnter:g(y),onMouseLeave:v(y)}},onClickAway:p}}var XR=y9;var ZR=C(I(),1);function QR(e){return q("MuiSnackbarContent",e)}var vbe=G("MuiSnackbarContent",["root","message","action"]);var qu=C(U(),1),h9=e=>{let{classes:t}=e;return Y({root:["root"],action:["action"],message:["message"]},QR,t)},g9=D(xt,{name:"MuiSnackbarContent",slot:"Root"})(Z(({theme:e})=>{let t=e.palette.mode==="light"?.8:.98;return{...e.typography.body2,color:e.vars?e.vars.palette.SnackbarContent.color:e.palette.getContrastText($d(e.palette.background.default,t)),backgroundColor:e.vars?e.vars.palette.SnackbarContent.bg:$d(e.palette.background.default,t),display:"flex",alignItems:"center",flexWrap:"wrap",padding:"6px 16px",flexGrow:1,[e.breakpoints.up("sm")]:{flexGrow:"initial",minWidth:288}}})),T9=D("div",{name:"MuiSnackbarContent",slot:"Message"})({padding:"8px 0"}),b9=D("div",{name:"MuiSnackbarContent",slot:"Action"})({display:"flex",alignItems:"center",marginLeft:"auto",paddingLeft:16,marginRight:-8}),v9=ZR.forwardRef(function(t,o){let r=X({props:t,name:"MuiSnackbarContent"}),{action:n,className:a,message:i,role:s="alert",...l}=r,p=r,c=h9(p);return(0,qu.jsxs)(g9,{role:s,elevation:6,className:L(c.root,a),ownerState:p,ref:o,...l,children:[(0,qu.jsx)(T9,{className:c.message,ownerState:p,children:i}),n?(0,qu.jsx)(b9,{className:c.action,ownerState:p,children:n}):null]})}),Bb=v9;function JR(e){return q("MuiSnackbar",e)}var jbe=G("MuiSnackbar",["root","anchorOriginTopCenter","anchorOriginBottomCenter","anchorOriginTopRight","anchorOriginBottomRight","anchorOriginTopLeft","anchorOriginBottomLeft"]);var Gu=C(U(),1),x9=e=>{let{classes:t,anchorOrigin:o}=e,r={root:["root",`anchorOrigin${j(o.vertical)}${j(o.horizontal)}`]};return Y(r,JR,t)},P9=D("div",{name:"MuiSnackbar",slot:"Root",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.root,t[`anchorOrigin${j(o.anchorOrigin.vertical)}${j(o.anchorOrigin.horizontal)}`]]}})(Z(({theme:e})=>({zIndex:(e.vars||e).zIndex.snackbar,position:"fixed",display:"flex",left:8,right:8,justifyContent:"center",alignItems:"center",variants:[{props:({ownerState:t})=>t.anchorOrigin.vertical==="top",style:{top:8,[e.breakpoints.up("sm")]:{top:24}}},{props:({ownerState:t})=>t.anchorOrigin.vertical!=="top",style:{bottom:8,[e.breakpoints.up("sm")]:{bottom:24}}},{props:({ownerState:t})=>t.anchorOrigin.horizontal==="left",style:{justifyContent:"flex-start",[e.breakpoints.up("sm")]:{left:24,right:"auto"}}},{props:({ownerState:t})=>t.anchorOrigin.horizontal==="right",style:{justifyContent:"flex-end",[e.breakpoints.up("sm")]:{right:24,left:"auto"}}},{props:({ownerState:t})=>t.anchorOrigin.horizontal==="center",style:{[e.breakpoints.up("sm")]:{left:"50%",right:"auto",transform:"translateX(-50%)"}}}]}))),S9=xy.forwardRef(function(t,o){let r=X({props:t,name:"MuiSnackbar"}),n=Dt(),a={enter:n.transitions.duration.enteringScreen,exit:n.transitions.duration.leavingScreen},{action:i,anchorOrigin:{vertical:s,horizontal:l}={vertical:"bottom",horizontal:"left"},autoHideDuration:p=null,children:c,className:m,ClickAwayListenerProps:f,ContentProps:u,disableWindowBlurListener:g=!1,message:v,onBlur:x,onClose:d,onFocus:y,onMouseEnter:h,onMouseLeave:T,open:P,resumeHideDuration:S,slots:E={},slotProps:R={},TransitionComponent:w,transitionDuration:O=a,TransitionProps:{onEnter:N,onExited:b,...M}={},...A}=r,_={...r,anchorOrigin:{vertical:s,horizon Line truncated
${e.palette.mode==="light"?e.lighten(e.alpha(e.palette.divider,1),.88):e.darken(e.alpha(e.palette.divider,1),.68)}`,textAlign:"left",padding:16,variants:[{props:{variant:"head"},style:{color:(e.vars||e).palette.text.primary,lineHeight:e.typography.pxToRem(24),fontWeight:e.typography.fontWeightMedium}},{props:{variant:"body"},style:{color:(e.vars||e).palette.text.primary}},{props:{variant:"footer"},style:{color:(e.vars||e).palette.text.secondary,lineHeight:e.typography.pxToRem(21),fontSize:e.typography.pxToRem(12)}},{props:{size:"small"},style:{padding:"6px 16px",[`&.${c2.paddingCheckbox}`]:{width:24,padding:"0 12px 0 16px","& > *":{padding:0}}}},{props:{padding:"checkbox"},style:{width:48,padding:"0 0 0 4px"}},{props:{padding:"none"},style:{padding:0}},{props:{align:"left"},style:{textAlign:"left"}},{props:{align:"center"},style:{textAlign:"center"}},{props:{align:"right"},style:{textAlign:"right",flexDirection:"row-reverse"}},{props:{align:"justify"},style:{textAlign:"justify"}},{props:({ownerState:t})=>t.stickyHeader,style:{position:"sticky",top:0,zIndex:2,backgroundColor:(e.vars||e).palette.background.default}}]}))),F9=Ku.forwardRef(function(t,o){let r=X({props:t,name:"MuiTableCell"}),{align:n="inherit",className:a,component:i,padding:s,scope:l,size:p,sortDirection:c,variant:m,...f}=r,u=Ku.useContext(Ey),g=Ku.useContext(Ti),v=g&&g.variant==="head",x;i?x=i:x=v?"th":"td";let d=l;x==="td"?d=void 0:!d&&v&&(d="col");let y=m||g&&g.variant,h={...r,align:n,component:x,padding:s||(u&&u.padding?u.padding:"normal"),size:p||(u&&u.size?u.size:"medium"),sortDirection:c,stickyHeader:y==="head"&&u&&u.stickyHeader,variant:y},T=$9(h),P=null;return c&&(P=c==="asc"?"ascending":"descending"),(0,u2.jsx)(V9,{as:x,ref:o,className:L(T.root,a),"aria-sort":P,scope:d,ownerState:h,...f})}),Kt=F9;var d2=C(I(),1);function f2(e){return q("MuiTableContainer",e)}var E0e=G("MuiTableContainer",["root"]);var m2=C(U(),1),q9=e=>{let{classes:t}=e;return Y({root:["root"]},f2,t)},G9=D("div",{name:"MuiTableContainer",slot:"Root"})({width:"100%",overflowX:"auto"}),Y9=d2.forwardRef(function(t,o){let r=X({props:t,name:"MuiTableContainer"}),{className:n,component:a="div",...i}=r,s={...r,component:a},l=q9(s);return(0,m2.jsx)(G9,{ref:o,as:a,className:L(l.root,n),ownerState:s,...i})}),Cp=Y9;var g2=C(I(),1);function y2(e){return q("MuiTableHead",e)}var U0e=G("MuiTableHead",["root"]);var Ib=C(U(),1),K9=e=>{let{classes:t}=e;return Y({root:["root"]},y2,t)},W9=D("thead",{name:"MuiTableHead",slot:"Root"})({display:"table-header-group"}),X9={variant:"head"},h2="thead",Q9=g2.forwardRef(function(t,o){let r=X({props:t,name:"MuiTableHead"}),{className:n,component:a=h2,...i}=r,s={...r,component:a},l=K9(s);return(0,Ib.jsx)(Ti.Provider,{value:X9,children:(0,Ib.jsx)(W9,{as:a,className:L(l.root,n),ref:o,role:a===h2?null:"rowgroup",ownerState:s,...i})})}),Ep=Q9;var Oy=C(I(),1);function T2(e){return q("MuiTableRow",e)}var Z9=G("MuiTableRow",["root","selected","hover","head","footer"]),Hb=Z9;var v2=C(U(),1),J9=e=>{let{classes:t,selected:o,hover:r,head:n,footer:a}=e;return Y({root:["root",o&&"selected",r&&"hover",n&&"head",a&&"footer"]},T2,t)},eU=D("tr",{name:"MuiTableRow",slot:"Root",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.root,o.head&&t.head,o.footer&&t.footer]}})(Z(({theme:e})=>({color:"inherit",display:"table-row",verticalAlign:"middle",outline:0,[`&.${Hb.hover}:hover`]:{backgroundColor:(e.vars||e).palette.action.hover},[`&.${Hb.selected}`]:{backgroundColor:e.alpha((e.vars||e).palette.primary.main,(e.vars||e).palette.action.selectedOpacity),"&:hover":{backgroundColor:e.alpha((e.vars||e).palette.primary.main,`${(e.vars||e).palette.action.selectedOpacity} + ${(e.vars||e).palette.action.hoverOpacity}`)}}}))),b2="tr",tU=Oy.forwardRef(function(t,o){let r=X({props:t,name:"MuiTableRow"}),{className:n,component:a=b2,hover:i=!1,selected:s=!1,...l}=r,p=Oy.useContext(Ti),c={...r,component:a,hover:i,selected:s,head:p&&p.variant==="head",footer:p&&p.variant==="footer"},m=J9(c);return(0,v2.jsx)(eU,{as:a,ref:o,className:L(m.root,n),role:a===b2?null:"row",ownerState:c,...l})}),za=tU;var P2=C(I(),1);function x2(e){return q("MuiTextField",e)}var fxe=G("MuiTextField",["root"]);var js=C(U(),1),oU={standard:_u,filled:Du,outlined:$u},rU=e=>{let{classes:t}=e;return Y({root:["root"]},x2,t)},nU=D(lb,{name:"MuiTextField",slot:"Root"})({}),aU=P2.forwardRef(function(t,o){let r=X({props:t,name:"MuiTextField"}),{autoComplete:n,autoFocus:a=!1,children:i,className:s,color:l="primary",defaultValue:p,disabled:c=!1,error:m=!1,FormHelperTextProps:f,fullWidth:u=!1,helperText:g,id:v,InputLabelProps:x,inputProps:d,InputProps:y,inputRef:h,label:T,maxRows:P,minRows:S,multiline:E=!1,name:R,onBlur:w,onChange:O,onFocus:N,placeholder:b,required:M=!1,rows:A,select:_=!1,SelectProps:k,slots:W={},slotProps:re={},type:F,value:me,variant:ie="outlined",...ue}=r,ne={...r,autoFocus:a,color:l,disabled:c,error:m,fullWidth:u,multiline:E,required:M,select:_,variant:ie},Ee=rU(ne),le=Yr(v),oe=g&&le?`${le}-heLine truncated
`):e[i]),o(i),n(!1)}catch{o(null),n(!0)}}return(0,tr.jsxs)(he,{sx:{my:2},children:[(0,tr.jsxs)(Ce,{direction:"row",alignItems:"center",justifyContent:"space-between",spacing:1,sx:{mb:1},children:[(0,tr.jsx)(K,{variant:"body2",color:"text.secondary",children:"\u70B9\u51FB\u5355\u679A\u5151\u6362\u7801\u5373\u53EF\u590D\u5236"}),(0,tr.jsx)(Se,{size:"small",color:"secondary",startIcon:(0,tr.jsx)($x,{}),onClick:()=>{a("all")},sx:{px:1.5,flexShrink:0},children:"\u590D\u5236\u5168\u90E8"})]}),(0,tr.jsx)(he,{component:"ul","aria-label":"\u65B0\u751F\u6210\u7684\u5151\u6362\u7801",sx:{m:0,p:0,listStyle:"none",maxHeight:300,overflowY:"auto",border:1,borderColor:"divider",borderRadius:2},children:e.map((i,s)=>(0,tr.jsx)(he,{component:"li",children:(0,tr.jsx)(Se,{fullWidth:!0,"aria-label":`\u590D\u5236\u7B2C ${s+1} \u679A\u5151\u6362\u7801`,onClick:()=>{a(s)},endIcon:t===s?(0,tr.jsx)(eA,{}):(0,tr.jsx)($x,{}),sx:{py:1.5,px:2,borderRadius:0,justifyContent:"space-between",textAlign:"left",borderBottom:s<e.length-1?1:0,borderColor:"divider",color:"text.primary",gap:1},children:(0,tr.jsx)(he,{component:"code",sx:{fontFamily:"monospace",fontSize:".8125rem",overflowWrap:"anywhere",userSelect:"text"},children:i})})},i))}),t!==null&&(0,tr.jsx)(K,{role:"status",variant:"body2",color:"success.main",sx:{mt:1},children:t==="all"?`\u5DF2\u590D\u5236\u5168\u90E8 ${e.length} \u679A\u5151\u6362\u7801\u3002`:`\u5DF2\u590D\u5236\u7B2C ${t+1} \u679A\u5151\u6362\u7801\u3002`}),r&&(0,tr.jsx)(gt,{severity:"warning",sx:{mt:1},children:"\u6D4F\u89C8\u5668\u672A\u5141\u8BB8\u8BBF\u95EE\u526A\u8D34\u677F\u3002\u8BF7\u9009\u4E2D\u5151\u6362\u7801\u624B\u52A8\u590D\u5236\uFF0C\u6216\u4F7F\u7528\u4E0B\u65B9\u300C\u4E0B\u8F7D TXT\u300D\u3002"})]})}async function or(e,t){let{ok:o,data:r}=await $M(e,t);if(!o)throw new Error(r.message||"\u8BF7\u6C42\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002");return r}function oA(){return or("/api/admin/stats")}var Zf=C(I(),1);var rA=C(U(),1),nA=ce((0,rA.jsx)("path",{d:"m9.17 6 2 2H20v10H4V6zM10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8z"}),"FolderOutlined");var aA=C(U(),1),iA=ce((0,aA.jsx)("path",{d:"m14.06 9.02.92.92L5.92 19H5v-.92zM17.66 3c-.25 0-.51.1-.7.29l-1.83 1.83 3.75 3.75 1.83-1.83c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.2-.2-.45-.29-.71-.29m-3.6 3.19L3 17.25V21h3.75L17.81 9.94z"}),"EditOutlined");var Ot=C(U(),1);function sA({folders:e,stats:t,filter:o,disabled:r,muted:n=!1,onSelect:a,onBusyChange:i,onChanged:s}){let[l,p]=(0,Zf.useState)(null),[c,m]=(0,Zf.useState)(""),[f,u]=(0,Zf.useState)(""),[g,v]=(0,Zf.useState)(!1);async function x(){if(!(!l||g)){if(!c.trim()||new TextEncoder().encode(c.trim()).length>120){u("\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A\uFF0C\u6700\u591A 120 \u5B57\u8282\u3002");return}v(!0),i(!0);try{await or("/api/admin/folders/rename",{id:l.id,name:c.trim()}),await s(),p(null)}catch(d){u(d.message)}finally{v(!1),i(!1)}}}return(0,Ot.jsxs)(he,{sx:{mb:3},children:[(0,Ot.jsxs)(Ce,{direction:"row",justifyContent:"space-between",alignItems:"baseline",sx:{mb:1.5},children:[(0,Ot.jsx)(K,{variant:"h2",children:"\u6279\u6B21"}),(0,Ot.jsxs)(K,{variant:"body2",color:"text.secondary",children:[t?.total??"\u2014"," \u679A\u5151\u6362\u7801"]})]}),(0,Ot.jsx)(K,{variant:"body2",color:"text.secondary",sx:{mb:2},children:"\u70B9\u51FB\u6279\u6B21\u6587\u4EF6\u5939\u67E5\u770B\u5151\u6362\u7801\uFF0C\u5DE6\u53F3\u6ED1\u52A8\u53EF\u67E5\u770B\u5168\u90E8\u6279\u6B21\u3002"}),(0,Ot.jsx)(Ce,{direction:"row",useFlexGap:!0,gap:1,sx:{height:80,overflowX:"auto",alignItems:"center",pb:1,opacity:n?.55:1,transition:"opacity 160ms ease"},role:"region","aria-label":"\u6279\u6B21\u6587\u4EF6\u5939\uFF0C\u53EF\u6A2A\u5411\u6EDA\u52A8",tabIndex:0,children:[{id:"",name:"\u5168\u90E8\u5151\u6362\u7801",count:t?.total??0},...t?.unfiled?[{id:"unfiled",name:"\u672A\u5206\u7C7B",count:t.unfiled}]:[],...e].map(d=>(0,Ot.jsxs)(he,{sx:{display:"flex",border:1,borderColor:o===d.id?"primary.main":"divider",borderRadius:2,bgcolor:o===d.id?"action.selected":"background.paper",maxWidth:"100%",flexShrink:0},children:[(0,Ot.jsxs)(Se,{disabled:r,"aria-pressed":o===d.id,startIcon:(0,Ot.jsx)(nA,{}),onClick:()=>a(d.id),sx:{px:2,py:1.5,justifyContent:"flex-start",textAlign:"left",overflowWrap:"anywhere",minWidth:0},children:[d.name," \xB7 ",d.count]}),d.id&&d.id!=="unfiled"&&(0,Ot.jsx)(kn,{describeChild:!0,title:`\u91CD\u547D\u540D\u6279\u6B21\uFF1A${d.name}`,children:(0,Ot.jsx)("span",{children:(0,Ot.jsx)(Xr,{"aria-label":`\u91CD\u547D\u540D\u6279\u6B21\uFF1A${d.name}`,disabled:r,onClick:()=>{p(d),m(d.name),u("")},sx:{m:.5,border:1,borderColor:"divider",width:44,height:44},children:(0,Ot.jsx)(iA,{fontSize:"small"})})})})]},d.id))}),(0,Ot.jsx)(Nn,{open:!!l,onClose:()=>!g&&p(null),fullWidth:!0,maxWidth:"xs","aria-labelledby":"batch-rename-title",children:(0,Ot.jsxs)(he,{component:"form",onSubmit:d=>{d.preventDefault(),x()},children:[(0,Ot.jsx)(Dn,{id:"batch-rename-title",children:"\u91CD\u547D\u540D Line truncated
)`,content:'""',position:"absolute",transform:"translateX(-100%)",bottom:0,left:0,right:0,top:0}}},{props:{animation:"wave"},style:x9||{"&::after":{animation:`${Vb} 2s linear 0.5s infinite`}}}]}})),S9=t2.forwardRef(function(t,o){let r=Q({props:t,name:"MuiSkeleton"}),{animation:n="pulse",className:a,component:i="span",height:s,style:l,variant:p="text",width:c,...d}=r,f={...r,animation:n,component:i,variant:p,hasChildren:!!d.children},u=b9(f);return(0,o2.jsx)(P9,{as:i,ref:o,className:L(u.root,a),ownerState:f,...d,style:{width:c,height:s,...l}})}),Qu=S9;var Ny=C(I(),1);var Mp=C(I(),1);function C9(e={}){let{autoHideDuration:t=null,disableWindowBlurListener:o=!1,onClose:r,open:n,resumeHideDuration:a}=e,i=Zo();Mp.useEffect(()=>{if(!n)return;function m(y){y.defaultPrevented||y.key==="Escape"&&r?.(y,"escapeKeyDown")}return document.addEventListener("keydown",m),()=>{document.removeEventListener("keydown",m)}},[n,r]);let s=Rr((m,y)=>{r?.(m,y)}),l=Rr(m=>{!r||m==null||i.start(m,()=>{s(null,"timeout")})});Mp.useEffect(()=>(n&&l(t),i.clear),[n,t,l,i]);let p=m=>{r?.(m,"clickaway")},c=i.clear,d=Mp.useCallback(()=>{t!=null&&l(a??t*.5)},[t,a,l]),f=m=>y=>{let h=m.onBlur;h?.(y),d()},u=m=>y=>{let h=m.onFocus;h?.(y),c()},g=m=>y=>{let h=m.onMouseEnter;h?.(y),c()},x=m=>y=>{let h=m.onMouseLeave;h?.(y),d()};return Mp.useEffect(()=>{if(!o&&n)return window.addEventListener("focus",d),window.addEventListener("blur",c),()=>{window.removeEventListener("focus",d),window.removeEventListener("blur",c)}},[o,n,d,c]),{getRootProps:(m={})=>{let y={...mi(e),...mi(m)};return{role:"presentation",...m,...y,onBlur:f(y),onFocus:u(y),onMouseEnter:g(y),onMouseLeave:x(y)}},onClickAway:p}}var r2=C9;var a2=C(I(),1);function n2(e){return G("MuiSnackbarContent",e)}var wbe=Y("MuiSnackbarContent",["root","message","action"]);var Zu=C(z(),1),E9=e=>{let{classes:t}=e;return W({root:["root"],action:["action"],message:["message"]},n2,t)},R9=k(dt,{name:"MuiSnackbarContent",slot:"Root"})(J(({theme:e})=>{let t=e.palette.mode==="light"?.8:.98;return{...e.typography.body2,color:e.vars?e.vars.palette.SnackbarContent.color:e.palette.getContrastText(Xd(e.palette.background.default,t)),backgroundColor:e.vars?e.vars.palette.SnackbarContent.bg:Xd(e.palette.background.default,t),display:"flex",alignItems:"center",flexWrap:"wrap",padding:"6px 16px",flexGrow:1,[e.breakpoints.up("sm")]:{flexGrow:"initial",minWidth:288}}})),O9=k("div",{name:"MuiSnackbarContent",slot:"Message"})({padding:"8px 0"}),w9=k("div",{name:"MuiSnackbarContent",slot:"Action"})({display:"flex",alignItems:"center",marginLeft:"auto",paddingLeft:16,marginRight:-8}),N9=a2.forwardRef(function(t,o){let r=Q({props:t,name:"MuiSnackbarContent"}),{action:n,className:a,message:i,role:s="alert",...l}=r,p=r,c=E9(p);return(0,Zu.jsxs)(R9,{role:s,elevation:6,className:L(c.root,a),ownerState:p,ref:o,...l,children:[(0,Zu.jsx)(O9,{className:c.message,ownerState:p,children:i}),n?(0,Zu.jsx)(w9,{className:c.action,ownerState:p,children:n}):null]})}),Fb=N9;function i2(e){return G("MuiSnackbar",e)}var Fbe=Y("MuiSnackbar",["root","anchorOriginTopCenter","anchorOriginBottomCenter","anchorOriginTopRight","anchorOriginBottomRight","anchorOriginTopLeft","anchorOriginBottomLeft"]);var Ju=C(z(),1),M9=e=>{let{classes:t,anchorOrigin:o}=e,r={root:["root",`anchorOrigin${B(o.vertical)}${B(o.horizontal)}`]};return W(r,i2,t)},A9=k("div",{name:"MuiSnackbar",slot:"Root",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.root,t[`anchorOrigin${B(o.anchorOrigin.vertical)}${B(o.anchorOrigin.horizontal)}`]]}})(J(({theme:e})=>({zIndex:(e.vars||e).zIndex.snackbar,position:"fixed",display:"flex",left:8,right:8,justifyContent:"center",alignItems:"center",variants:[{props:({ownerState:t})=>t.anchorOrigin.vertical==="top",style:{top:8,[e.breakpoints.up("sm")]:{top:24}}},{props:({ownerState:t})=>t.anchorOrigin.vertical!=="top",style:{bottom:8,[e.breakpoints.up("sm")]:{bottom:24}}},{props:({ownerState:t})=>t.anchorOrigin.horizontal==="left",style:{justifyContent:"flex-start",[e.breakpoints.up("sm")]:{left:24,right:"auto"}}},{props:({ownerState:t})=>t.anchorOrigin.horizontal==="right",style:{justifyContent:"flex-end",[e.breakpoints.up("sm")]:{right:24,left:"auto"}}},{props:({ownerState:t})=>t.anchorOrigin.horizontal==="center",style:{[e.breakpoints.up("sm")]:{left:"50%",right:"auto",transform:"translateX(-50%)"}}}]}))),k9=Ny.forwardRef(function(t,o){let r=Q({props:t,name:"MuiSnackbar"}),n=jt(),a={enter:n.transitions.duration.enteringScreen,exit:n.transitions.duration.leavingScreen},{action:i,anchorOrigin:{vertical:s,horizontal:l}={vertical:"bottom",horizontal:"left"},autoHideDuration:p=null,children:c,className:d,ClickAwayListenerProps:f,ContentProps:u,disableWindowBlurListener:g=!1,message:x,onBlur:v,onClose:m,onFocus:y,onMouseEnter:h,onMouseLeave:T,open:P,resumeHideDuration:S,slots:E={},slotProps:R={},TransitionComponent:w,transitionDuration:O=a,TransitionProps:{onEnter:A,onExited:b,...N}={},...M}=r,_={...r,anchorOrigin:{vertical:s,horizon Line truncated
${e.palette.mode==="light"?e.lighten(e.alpha(e.palette.divider,1),.88):e.darken(e.alpha(e.palette.divider,1),.68)}`,textAlign:"left",padding:16,variants:[{props:{variant:"head"},style:{color:(e.vars||e).palette.text.primary,lineHeight:e.typography.pxToRem(24),fontWeight:e.typography.fontWeightMedium}},{props:{variant:"body"},style:{color:(e.vars||e).palette.text.primary}},{props:{variant:"footer"},style:{color:(e.vars||e).palette.text.secondary,lineHeight:e.typography.pxToRem(21),fontSize:e.typography.pxToRem(12)}},{props:{size:"small"},style:{padding:"6px 16px",[`&.${g2.paddingCheckbox}`]:{width:24,padding:"0 12px 0 16px","& > *":{padding:0}}}},{props:{padding:"checkbox"},style:{width:48,padding:"0 0 0 4px"}},{props:{padding:"none"},style:{padding:0}},{props:{align:"left"},style:{textAlign:"left"}},{props:{align:"center"},style:{textAlign:"center"}},{props:{align:"right"},style:{textAlign:"right",flexDirection:"row-reverse"}},{props:{align:"justify"},style:{textAlign:"justify"}},{props:({ownerState:t})=>t.stickyHeader,style:{position:"sticky",top:0,zIndex:2,backgroundColor:(e.vars||e).palette.background.default}}]}))),J9=tf.forwardRef(function(t,o){let r=Q({props:t,name:"MuiTableCell"}),{align:n="inherit",className:a,component:i,padding:s,scope:l,size:p,sortDirection:c,variant:d,...f}=r,u=tf.useContext(Dy),g=tf.useContext(Ci),x=g&&g.variant==="head",v;i?v=i:v=x?"th":"td";let m=l;v==="td"?m=void 0:!m&&x&&(m="col");let y=d||g&&g.variant,h={...r,align:n,component:v,padding:s||(u&&u.padding?u.padding:"normal"),size:p||(u&&u.size?u.size:"medium"),sortDirection:c,stickyHeader:y==="head"&&u&&u.stickyHeader,variant:y},T=Q9(h),P=null;return c&&(P=c==="asc"?"ascending":"descending"),(0,T2.jsx)(Z9,{as:v,ref:o,className:L(T.root,a),"aria-sort":P,scope:m,ownerState:h,...f})}),Zt=J9;var v2=C(I(),1);function b2(e){return G("MuiTableContainer",e)}var D0e=Y("MuiTableContainer",["root"]);var x2=C(z(),1),eU=e=>{let{classes:t}=e;return W({root:["root"]},b2,t)},tU=k("div",{name:"MuiTableContainer",slot:"Root"})({width:"100%",overflowX:"auto"}),oU=v2.forwardRef(function(t,o){let r=Q({props:t,name:"MuiTableContainer"}),{className:n,component:a="div",...i}=r,s={...r,component:a},l=eU(s);return(0,x2.jsx)(tU,{ref:o,as:a,className:L(l.root,n),ownerState:s,...i})}),Dp=oU;var C2=C(I(),1);function P2(e){return G("MuiTableHead",e)}var G0e=Y("MuiTableHead",["root"]);var Yb=C(z(),1),rU=e=>{let{classes:t}=e;return W({root:["root"]},P2,t)},nU=k("thead",{name:"MuiTableHead",slot:"Root"})({display:"table-header-group"}),aU={variant:"head"},S2="thead",iU=C2.forwardRef(function(t,o){let r=Q({props:t,name:"MuiTableHead"}),{className:n,component:a=S2,...i}=r,s={...r,component:a},l=rU(s);return(0,Yb.jsx)(Ci.Provider,{value:aU,children:(0,Yb.jsx)(nU,{as:a,className:L(l.root,n),ref:o,role:a===S2?null:"rowgroup",ownerState:s,...i})})}),_p=iU;var zy=C(I(),1);function E2(e){return G("MuiTableRow",e)}var sU=Y("MuiTableRow",["root","selected","hover","head","footer"]),Wb=sU;var O2=C(z(),1),lU=e=>{let{classes:t,selected:o,hover:r,head:n,footer:a}=e;return W({root:["root",o&&"selected",r&&"hover",n&&"head",a&&"footer"]},E2,t)},pU=k("tr",{name:"MuiTableRow",slot:"Root",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.root,o.head&&t.head,o.footer&&t.footer]}})(J(({theme:e})=>({color:"inherit",display:"table-row",verticalAlign:"middle",outline:0,[`&.${Wb.hover}:hover`]:{backgroundColor:(e.vars||e).palette.action.hover},[`&.${Wb.selected}`]:{backgroundColor:e.alpha((e.vars||e).palette.primary.main,(e.vars||e).palette.action.selectedOpacity),"&:hover":{backgroundColor:e.alpha((e.vars||e).palette.primary.main,`${(e.vars||e).palette.action.selectedOpacity} + ${(e.vars||e).palette.action.hoverOpacity}`)}}}))),R2="tr",cU=zy.forwardRef(function(t,o){let r=Q({props:t,name:"MuiTableRow"}),{className:n,component:a=R2,hover:i=!1,selected:s=!1,...l}=r,p=zy.useContext(Ci),c={...r,component:a,hover:i,selected:s,head:p&&p.variant==="head",footer:p&&p.variant==="footer"},d=lU(c);return(0,O2.jsx)(pU,{as:a,ref:o,className:L(d.root,n),role:a===R2?null:"row",ownerState:c,...l})}),La=cU;var N2=C(I(),1);function w2(e){return G("MuiTextField",e)}var vxe=Y("MuiTextField",["root"]);var Vs=C(z(),1),uU={standard:Hu,filled:Iu,outlined:Ku},fU=e=>{let{classes:t}=e;return W({root:["root"]},w2,t)},dU=k(yb,{name:"MuiTextField",slot:"Root"})({}),mU=N2.forwardRef(function(t,o){let r=Q({props:t,name:"MuiTextField"}),{autoComplete:n,autoFocus:a=!1,children:i,className:s,color:l="primary",defaultValue:p,disabled:c=!1,error:d=!1,FormHelperTextProps:f,fullWidth:u=!1,helperText:g,id:x,InputLabelProps:v,inputProps:m,InputProps:y,inputRef:h,label:T,maxRows:P,minRows:S,multiline:E=!1,name:R,onBlur:w,onChange:O,onFocus:A,placeholder:b,required:N=!1,rows:M,select:_=!1,SelectProps:D,slots:K={},slotProps:ee={},type:q,value:ye,variant:se="outlined",...ce}=r,oe={...r,autoFocus:a,color:l,disabled:c,error:d,fullWidth:u,multiline:E,required:N,select:_,variant:se},Ce=fU(oe),pe=Wr(x),re=g&&pe?`${pe}-heLine truncated
`):e[i]),o(i),n(!1)}catch{o(null),n(!0)}}return(0,ir.jsxs)(ue,{sx:{my:2},children:[(0,ir.jsxs)(ve,{direction:"row",alignItems:"center",justifyContent:"space-between",spacing:1,sx:{mb:1},children:[(0,ir.jsx)(V,{variant:"body2",color:"text.secondary",children:"\u70B9\u51FB\u5355\u679A\u5151\u6362\u7801\u5373\u53EF\u590D\u5236"}),(0,ir.jsx)(be,{size:"small",color:"secondary",startIcon:(0,ir.jsx)(Kx,{}),onClick:()=>{a("all")},sx:{px:1.5,flexShrink:0},children:"\u590D\u5236\u5168\u90E8"})]}),(0,ir.jsx)(ue,{component:"ul","aria-label":"\u65B0\u751F\u6210\u7684\u5151\u6362\u7801",tabIndex:0,sx:{m:0,p:0,listStyle:"none",maxHeight:300,overflowY:"auto",border:1,borderColor:"divider",borderRadius:2},children:e.map((i,s)=>(0,ir.jsx)(ue,{component:"li",children:(0,ir.jsx)(be,{fullWidth:!0,"aria-label":`\u590D\u5236\u7B2C ${s+1} \u679A\u5151\u6362\u7801`,onClick:()=>{a(s)},endIcon:t===s?(0,ir.jsx)(s3,{}):(0,ir.jsx)(Kx,{}),sx:{py:1.5,px:2,borderRadius:0,justifyContent:"space-between",textAlign:"left",borderBottom:s<e.length-1?1:0,borderColor:"divider",color:"text.primary",gap:1},children:(0,ir.jsx)(ue,{component:"code",sx:{fontFamily:"monospace",fontSize:".8125rem",overflowWrap:"anywhere",userSelect:"text"},children:i})})},i))}),t!==null&&(0,ir.jsx)(V,{role:"status",variant:"body2",color:"success.main",sx:{mt:1},children:t==="all"?`\u5DF2\u590D\u5236\u5168\u90E8 ${e.length} \u679A\u5151\u6362\u7801\u3002`:`\u5DF2\u590D\u5236\u7B2C ${t+1} \u679A\u5151\u6362\u7801\u3002`}),r&&(0,ir.jsx)(pt,{severity:"warning",sx:{mt:1},children:"\u6D4F\u89C8\u5668\u672A\u5141\u8BB8\u8BBF\u95EE\u526A\u8D34\u677F\u3002\u8BF7\u9009\u4E2D\u5151\u6362\u7801\u624B\u52A8\u590D\u5236\uFF0C\u6216\u4F7F\u7528\u4E0B\u65B9\u300C\u4E0B\u8F7D TXT\u300D\u3002"})]})}async function Lo(e,t){let{ok:o,data:r}=await KM(e,t);if(!o)throw new Error(r.message||"\u8BF7\u6C42\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002");return r}function p3(){return Lo("/api/admin/stats")}function yl(e){let t=new Date(e*1e3),o=r=>String(r).padStart(2,"0");return`${t.getFullYear()}-${o(t.getMonth()+1)}-${o(t.getDate())} ${o(t.getHours())}:${o(t.getMinutes())}:${o(t.getSeconds())}`}var ts={active:{label:"\u53EF\u4F7F\u7528",color:"primary"},processing:{label:"\u5904\u7406\u4E2D",color:"primary"},succeeded:{label:"\u5DF2\u5B8C\u6210",color:"success"},review:{label:"\u5F85\u6838\u5B9E",color:"warning"},revoked:{label:"\u5DF2\u505C\u7528",color:"default"}};var id=C(I(),1);var c3=C(z(),1),u3=ie((0,c3.jsx)("path",{d:"m9.17 6 2 2H20v10H4V6zM10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8z"}),"FolderOutlined");var f3=C(z(),1),d3=ie((0,f3.jsx)("path",{d:"m14.06 9.02.92.92L5.92 19H5v-.92zM17.66 3c-.25 0-.51.1-.7.29l-1.83 1.83 3.75 3.75 1.83-1.83c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.2-.2-.45-.29-.71-.29m-3.6 3.19L3 17.25V21h3.75L17.81 9.94z"}),"EditOutlined");var Nt=C(z(),1);function m3({folders:e,stats:t,filter:o,disabled:r,onSelect:n,onBusyChange:a,onChanged:i}){let[s,l]=(0,id.useState)(null),[p,c]=(0,id.useState)(""),[d,f]=(0,id.useState)(""),[u,g]=(0,id.useState)(!1);async function x(){if(!(!s||u)){if(!p.trim()||new TextEncoder().encode(p.trim()).length>120){f("\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A\uFF0C\u6700\u591A 120 \u5B57\u8282\u3002");return}g(!0),a(!0);try{await Lo("/api/admin/folders/rename",{id:s.id,name:p.trim()}),await i(),l(null)}catch(v){f(v.message)}finally{g(!1),a(!1)}}}return(0,Nt.jsxs)(ue,{sx:{mb:3},children:[(0,Nt.jsxs)(ve,{direction:"row",justifyContent:"space-between",alignItems:"baseline",sx:{mb:1.5},children:[(0,Nt.jsx)(V,{variant:"h2",children:"\u6279\u6B21"}),(0,Nt.jsxs)(V,{variant:"body2",color:"text.secondary",children:[t?.total??"\u2014"," \u679A\u5151\u6362\u7801"]})]}),(0,Nt.jsx)(V,{variant:"body2",color:"text.secondary",sx:{mb:2},children:"\u70B9\u51FB\u6279\u6B21\u6587\u4EF6\u5939\u67E5\u770B\u5151\u6362\u7801\uFF0C\u5DE6\u53F3\u6ED1\u52A8\u53EF\u67E5\u770B\u5168\u90E8\u6279\u6B21\u3002"}),(0,Nt.jsx)(ve,{direction:"row",useFlexGap:!0,gap:1,sx:{minHeight:80,overflowX:"auto",alignItems:"center",pb:1},role:"region","aria-label":"\u6279\u6B21\u6587\u4EF6\u5939\uFF0C\u53EF\u6A2A\u5411\u6EDA\u52A8",tabIndex:0,children:[{id:"",name:"\u5168\u90E8\u5151\u6362\u7801",count:t?.total??0},...t?.unfiled?[{id:"unfiled",name:"\u672A\u5206\u7C7B",count:t.unfiled}]:[],...e].map(v=>(0,Nt.jsxs)(ue,{sx:{display:"flex",border:1,borderColor:o===v.id?"primary.main":"divider",borderRadius:2,bgcolor:o===v.id?"action.selected":"background.paper",maxWidth:"100%",flexShrink:0},children:[(0,Nt.jsxs)(be,{disabled:r,"aria-pressed":o===v.id,startIcon:(0,Nt.jsx)(u3,{}),onClick:()=>n(v.id),sx:{px:2,py:1.5,justifyContent:"flex-start",textAlign:"left",overflowWrap:"anywhere",minWidth:0},children:[v.name," \xB7 ",v.count]}),v.id&&v.id!=="unfiled"&&(0,Nt.jsx)(_n,{describeChild:!0,title:`\u91CD\u547D\u540D\u6279\u6B21\uFF1A${v.name}`,children:(0,Nt.jsx)("span",{children:(0,Nt.jsx)(Qr,{"aria-label":`\u91CD\u547D\u540D\u6279\u6B21\uFF1A${v.name}`,disabled: Line truncated
`)+`
`],{type:"text/plain;charset=utf-8"})),te=document.createElement("a");te.href=Q,te.download=`xgift-${oe.months}mo-${Date.now()}.txt`,te.click(),setTimeout(()=>URL.revokeObjectURL(Q),1e3)}let To=k&&re?re.filter(k.match):null,$r=To?.length??0,mn=Math.max(1,Math.ceil($r/100)),br=Math.min(me,mn-1),nr=To?To.slice(br*100,br*100+100):n?.codes??[];return(0,B.jsxs)(FM,{admin:!0,children:[(0,B.jsxs)(Ce,{direction:{xs:"column",sm:"row"},justifyContent:"space-between",alignItems:{xs:"start",sm:"center"},spacing:2,sx:{mb:4},children:[(0,B.jsxs)(he,{children:[(0,B.jsx)(K,{variant:"h1",sx:{fontSize:{xs:30,sm:36},mt:.5},children:"\u5151\u6362\u7801\u7BA1\u7406"}),(0,B.jsx)(K,{color:"text.secondary",sx:{mt:1},children:"\u751F\u6210\u5151\u6362\u7801\u3001\u67E5\u770B\u5151\u6362\u72B6\u6001\u548C\u7BA1\u7406\u6279\u6B21\u3002"})]}),(0,B.jsxs)(Ce,{direction:"row",alignItems:"center",spacing:1,children:[(0,B.jsx)(Nr,{variant:"outlined",color:n?.payments_enabled?"success":"default",label:n?n.payments_enabled?"\u5145\u503C\u5DF2\u5F00\u653E":"\u7528\u6237\u5145\u503C\u5165\u53E3\u5DF2\u6682\u505C":"\u6B63\u5728\u83B7\u53D6\u670D\u52A1\u72B6\u6001"}),(0,B.jsx)(QM,{})]})]}),(0,B.jsx)(PA,{selected:e,onPrepare:(Q,te)=>r({id:Q,mode:te,seq:Date.now()})}),(0,B.jsx)(OA,{selection:o}),(0,B.jsx)(MA,{refreshSignal:ke}),(0,B.jsx)(sA,{folders:n?.folders??[],stats:n?.stats,filter:n?.folder??"",disabled:c||i,muted:!!k,onSelect:Q=>{if(k){je(!1);let te=Q==="unfiled"?"\u672A\u5206\u7C7B":Q?n?.folders.find(ve=>ve.id===Q)?.name??"":"";te&&le(ve=>({seq:ve.seq+1,text:`\u7B5B\u9009\u5DF2\u6E05\u9664\uFF0C\u5DF2\u663E\u793A\u6279\u6B21\uFF1A${te}`}))}Bt(0,Q)},onBusyChange:Q=>{Ne.current=Q,m(Q)},onChanged:async Q=>{Q===N.current&&(N.current=""),k?Ke():await Bt(0)}}),k&&(0,B.jsx)(K,{variant:"body2",color:"text.secondary",sx:{mt:-1.5,mb:3},children:"\u8868\u8FBE\u5F0F\u7B5B\u9009\u751F\u6548\u4E2D\uFF0C\u70B9\u51FB\u6279\u6B21\u6587\u4EF6\u5939\u53EF\u6E05\u9664\u7B5B\u9009\u5E76\u67E5\u770B\u8BE5\u6279\u6B21\u3002"}),(0,B.jsx)(xA,{value:b,onChange:Q=>{M(Q),A&&_("")},onApply:()=>{b.trim()&&Ye(b.trim())},onClear:()=>je(),applied:!!k,error:A,disabled:c||i,folders:n?.folders??[],appliedSource:k?.source??"",resultCount:k?$r:void 0,applySeq:ue,clearNotice:Ee}),(0,B.jsxs)(xt,{variant:"outlined",sx:{p:{xs:2.5,sm:3},mb:3},children:[(0,B.jsxs)(Ce,{direction:"row",spacing:1,alignItems:"center",sx:{mb:1},children:[(0,B.jsx)(Vb,{color:"primary"}),(0,B.jsx)(K,{variant:"h2",children:"\u751F\u6210\u5151\u6362\u7801"})]}),(0,B.jsx)(K,{variant:"body2",color:"text.secondary",sx:{mb:3},children:"\u6BCF\u6279\u6700\u591A 500 \u679A\u3002\u540C\u540D\u6279\u6B21\u81EA\u52A8\u5F52\u5165\u540C\u4E00\u4E2A\u6587\u4EF6\u5939\u3002"}),(0,B.jsx)(he,{component:"form",ref:pe,noValidate:!0,onSubmit:Q=>{Q.preventDefault();let te=new TextEncoder().encode(x.trim()).length>120,ve=!Number.isInteger(Number(g))||Number(g)<1||Number(g)>500;$(te),xe(ve),!(te||ve||!pe.current.reportValidity()||c)&&rr()},children:(0,B.jsxs)(he,{sx:{display:"grid",gridTemplateColumns:{xs:"1fr",sm:"1fr 1fr",md:"1fr 1fr 2fr"},gap:2,alignItems:"start"},children:[(0,B.jsxs)(Io,{select:!0,label:"\u5957\u9910\u65F6\u957F",value:f,onChange:Q=>u(Number(Q.target.value)),disabled:c,helperText:"\u7ED1\u5B9A\u540E\u4E0D\u53EF\u66F4\u6539",children:[(0,B.jsx)(_a,{value:3,children:"3 \u4E2A\u6708 Premium"}),(0,B.jsx)(_a,{value:6,children:"6 \u4E2A\u6708 Premium"})]}),(0,B.jsx)(Io,{label:"\u751F\u6210\u6570\u91CF",type:"number",required:!0,value:g,onChange:Q=>v(Q.target.value),disabled:c,error:z,helperText:z?"\u8BF7\u8F93\u5165 1\u2013500 \u4E4B\u95F4\u7684\u6574\u6570":"\u6BCF\u6279 1\u2013500 \u679A",slotProps:{htmlInput:{min:1,max:500,step:1}}}),(0,B.jsx)(Io,{label:"\u6279\u6B21\u540D\u79F0\uFF08\u53EF\u9009\uFF09",placeholder:"\u4F8B\u5982\uFF1A\u5341\u6708\u8D60\u793C",value:x,onChange:Q=>d(Q.target.value),disabled:c,error:be,helperText:be?"\u6279\u6B21\u540D\u79F0\u4E0D\u80FD\u8D85\u8FC7 120 \u5B57\u8282\uFF08\u7EA6 40 \u4E2A\u6C49\u5B57\uFF09":"\u6279\u6B21\u540D\u79F0\u5C31\u662F\u6587\u4EF6\u5939\u540D\u79F0\uFF0C\u7559\u7A7A\u81EA\u52A8\u547D\u540D"}),(0,B.jsx)(Se,{type:"submit",variant:"contained",startIcon:(0,B.jsx)(M2,{}),disabled:c||i||!!l,sx:{gridColumn:{sm:"1 / -1"},justifySelf:{sm:"end"}},children:c?"\u6B63\u5728\u5904\u7406\u2026":"\u751F\u6210\u5151\u6362\u7801"})]})})]}),ge&&(0,B.jsx)(gt,{severity:ge.error?"error":"success",role:"status",sx:{mb:3},children:ge.text}),oe&&(0,B.jsxs)(xt,{ref:ao,variant:"outlined",sx:{p:3,mb:3,borderColor:"primary.main"},children:[(0,B.jsx)(K,{variant:"h2",children:"\u672C\u6279\u5151\u6362\u7801"}),(0,B.jsxs)(K,{variant:"body2",color:"text.secondary",sx:{my:1,overflowWrap:"anywhere"},children:[oe.batch," \xB7 ",oe.codes.length," \u679A \xB7 ",oe.months," ","\u4E2A\u6708"]}),(0,B.jsx)(tA,{codes:oe.codes},oe.codes[0]),(0,B.jsxs)(Ce,{direction:{xs:"column",sm:"row"},spacing:1.5,children:[(0,B.jsx)(Se,{variant:"contained",startIcon:(0,B.jsx)(D2,{}),onClick:Ut,children:"\u4E0B\u8F Line truncated
`],{type:"text/plain;charset=utf-8"})),je=document.createElement("a");je.href=X,je.download=`xgift-${he.months}mo-${Date.now()}.txt`,je.click(),setTimeout(()=>URL.revokeObjectURL(X),1e3)}let lr=ee&&ye?ye.filter(ee.match):null,ma=lr?.length??0,Fn=Math.max(1,Math.ceil(ma/100)),Vr=Math.min(ce,Fn-1),de=lr?lr.slice(Vr*100,Vr*100+100):n?.codes??[],ze=de.map(X=>X.id),Mt=ze.filter(X=>E.includes(X));return(0,j.jsxs)(QM,{admin:!0,children:[(0,j.jsxs)(ve,{direction:{xs:"column",sm:"row"},justifyContent:"space-between",alignItems:{xs:"start",sm:"center"},spacing:2,sx:{mb:4},children:[(0,j.jsxs)(ue,{children:[(0,j.jsx)(V,{variant:"h1",sx:{fontSize:{xs:30,sm:36},mt:.5},children:"\u5151\u6362\u7801\u7BA1\u7406"}),(0,j.jsx)(V,{color:"text.secondary",sx:{mt:1},children:"\u751F\u6210\u5151\u6362\u7801\u3001\u67E5\u770B\u5151\u6362\u72B6\u6001\u548C\u7BA1\u7406\u6279\u6B21\u3002"})]}),(0,j.jsxs)(ve,{direction:"row",alignItems:"center",spacing:1,children:[(0,j.jsx)(er,{variant:"outlined",color:n?.payments_enabled?"success":"default",label:n?n.payments_enabled?"\u5145\u503C\u5DF2\u5F00\u653E":"\u7528\u6237\u5145\u503C\u5165\u53E3\u5DF2\u6682\u505C":"\u6B63\u5728\u83B7\u53D6\u670D\u52A1\u72B6\u6001"}),(0,j.jsx)(n3,{})]})]}),(0,j.jsxs)(ue,{sx:{display:"grid",gridTemplateColumns:{xs:"1fr",md:"minmax(0, 1fr) minmax(0, 1fr)"},gap:3,mb:3,alignItems:"stretch"},children:[(0,j.jsx)(M3,{selected:e,onPrepare:(X,je)=>r({id:X,mode:je,seq:Date.now()})}),(0,j.jsx)(D3,{disabled:c||i,refreshSignal:Ze,onCopy:X=>{we(X)},onViewCustomer:X=>t({id:X,seq:Date.now()}),onRevoke:X=>$({kind:"revoke",code:X})})]}),(0,j.jsx)(U3,{selection:o}),(0,j.jsx)(H3,{refreshSignal:Ze}),(0,j.jsx)(m3,{folders:n?.folders??[],stats:n?.stats,filter:n?.folder??"",disabled:c||i,onSelect:X=>{if(ee){ot(!1);let je=X==="unfiled"?"\u672A\u5206\u7C7B":X?n?.folders.find(At=>At.id===X)?.name??"":"";je&&Te(At=>({seq:At.seq+1,text:`\u7B5B\u9009\u5DF2\u6E05\u9664\uFF0C\u5DF2\u663E\u793A\u6279\u6B21\uFF1A${je}`}))}Ae(0,X)},onBusyChange:X=>{gt.current=X,d(X)},onChanged:async()=>{ee?oo():await Ae(0)}}),ee&&(0,j.jsx)(V,{variant:"body2",color:"text.secondary",sx:{mt:-1.5,mb:3},children:"\u8868\u8FBE\u5F0F\u7B5B\u9009\u751F\u6548\u4E2D\uFF0C\u70B9\u51FB\u6279\u6B21\u6587\u4EF6\u5939\u53EF\u6E05\u9664\u7B5B\u9009\u5E76\u67E5\u770B\u8BE5\u6279\u6B21\u3002"}),(0,j.jsx)(w3,{value:M,onChange:X=>{_(X),D&&K("")},onApply:()=>{M.trim()&&lt(M.trim())},onClear:()=>ot(),applied:!!ee,error:D,disabled:c||i,folders:n?.folders??[],appliedSource:ee?.source??"",resultCount:ee?ma:void 0,applySeq:Ce,clearNotice:re}),(0,j.jsxs)(dt,{variant:"outlined",sx:{p:{xs:2.5,sm:3},mb:3},children:[(0,j.jsxs)(ve,{direction:"row",spacing:1,alignItems:"center",sx:{mb:1},children:[(0,j.jsx)(Xb,{color:"primary"}),(0,j.jsx)(V,{variant:"h2",children:"\u751F\u6210\u5151\u6362\u7801"})]}),(0,j.jsx)(V,{variant:"body2",color:"text.secondary",sx:{mb:3},children:"\u6BCF\u6279\u6700\u591A 500 \u679A\u3002\u540C\u540D\u6279\u6B21\u81EA\u52A8\u5F52\u5165\u540C\u4E00\u4E2A\u6587\u4EF6\u5939\u3002"}),(0,j.jsx)(ue,{component:"form",ref:Tt,noValidate:!0,onSubmit:X=>{X.preventDefault();let je=new TextEncoder().encode(v.trim()).length>120,At=!Number.isInteger(Number(g))||Number(g)<1||Number(g)>500;Pe(je),Se(At),!(je||At||!Tt.current.reportValidity()||c)&&Co()},children:(0,j.jsxs)(ue,{sx:{display:"grid",gridTemplateColumns:{xs:"1fr",sm:"1fr 1fr",md:"1fr 1fr 2fr"},gap:2,alignItems:"start"},children:[(0,j.jsxs)(To,{select:!0,label:"\u5957\u9910\u65F6\u957F",value:f,onChange:X=>u(Number(X.target.value)),disabled:c,helperText:"\u7ED1\u5B9A\u540E\u4E0D\u53EF\u66F4\u6539",children:[(0,j.jsx)(Ua,{value:3,children:"3 \u4E2A\u6708 Premium"}),(0,j.jsx)(Ua,{value:6,children:"6 \u4E2A\u6708 Premium"})]}),(0,j.jsx)(To,{label:"\u751F\u6210\u6570\u91CF",type:"number",required:!0,value:g,onChange:X=>{x(X.target.value),Me&&Se(!1)},disabled:c,error:Me,helperText:Me?"\u8BF7\u8F93\u5165 1\u2013500 \u4E4B\u95F4\u7684\u6574\u6570":"\u6BCF\u6279 1\u2013500 \u679A",slotProps:{htmlInput:{min:1,max:500,step:1}}}),(0,j.jsx)(To,{label:"\u6279\u6B21\u540D\u79F0\uFF08\u53EF\u9009\uFF09",placeholder:"\u4F8B\u5982\uFF1A\u5341\u6708\u8D60\u793C",value:v,onChange:X=>{m(X.target.value),U&&Pe(!1)},disabled:c,error:U,helperText:U?"\u6279\u6B21\u540D\u79F0\u4E0D\u80FD\u8D85\u8FC7 120 \u5B57\u8282\uFF08\u7EA6 40 \u4E2A\u6C49\u5B57\uFF09":"\u6279\u6B21\u540D\u79F0\u5C31\u662F\u6587\u4EF6\u5939\u540D\u79F0\uFF0C\u7559\u7A7A\u81EA\u52A8\u547D\u540D"}),(0,j.jsx)(be,{type:"submit",variant:"contained",startIcon:(0,j.jsx)(B2,{}),disabled:c||i||!!l,sx:{gridColumn:{sm:"1 / -1"},justifySelf:{sm:"end"}},children:c?"\u6B63\u5728\u5904\u7406\u2026":"\u751F\u6210\u5151\u6362\u7801"})]})})]}),le&&(0,j.jsx)(pt,{severity:le.error?"error":"success",role:"status",closeText:"\u5173\u95ED",onClose:le.error?void 0:()=>fe(null),sx:{mb:3},children:le.text}),he&&(0,j.jsxs)(dt,{ref:sr,variant:"outlined",sx:{p:3,mb:3,borderColor:"primary.main"},children:[(0,j.jsx)(V,{variant:"h2",children:"\u672C\u6279\u5151\uLine truncated
/*! Bundled license information:
react/cjs/react.production.js:
Binary file not shown.
+40 -40
View File
@@ -1,15 +1,15 @@
var IN=Object.create;var Lb=Object.defineProperty;var VN=Object.getOwnPropertyDescriptor;var HN=Object.getOwnPropertyNames;var FN=Object.getPrototypeOf,$N=Object.prototype.hasOwnProperty;var ro=(e,t)=>()=>{try{return t||e((t={exports:{}}).exports,t),t.exports}catch(o){throw t=0,o}};var qN=(e,t,o,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of HN(t))!$N.call(e,n)&&n!==o&&Lb(e,n,{get:()=>t[n],enumerable:!(r=VN(t,n))||r.enumerable});return e};var C=(e,t,o)=>(o=e!=null?IN(FN(e)):{},qN(t||!e||!e.__esModule?Lb(o,"default",{value:e,enumerable:!0}):o,e));var Zb=ro(ae=>{"use strict";var Ey=Symbol.for("react.transitional.element"),GN=Symbol.for("react.portal"),YN=Symbol.for("react.fragment"),XN=Symbol.for("react.strict_mode"),KN=Symbol.for("react.profiler"),QN=Symbol.for("react.consumer"),ZN=Symbol.for("react.context"),WN=Symbol.for("react.forward_ref"),JN=Symbol.for("react.suspense"),e5=Symbol.for("react.memo"),Fb=Symbol.for("react.lazy"),t5=Symbol.for("react.activity"),o5=Symbol.for("react.view_transition"),kb=Symbol.iterator;function r5(e){return e===null||typeof e!="object"?null:(e=kb&&e[kb]||e["@@iterator"],typeof e=="function"?e:null)}var $b={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},qb=Object.assign,Gb={};function Xi(e,t,o){this.props=e,this.context=t,this.refs=Gb,this.updater=o||$b}Xi.prototype.isReactComponent={};Xi.prototype.setState=function(e,t){if(typeof e!="object"&&typeof e!="function"&&e!=null)throw Error("takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,t,"setState")};Xi.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")};function Yb(){}Yb.prototype=Xi.prototype;function Ry(e,t,o){this.props=e,this.context=t,this.refs=Gb,this.updater=o||$b}var Oy=Ry.prototype=new Yb;Oy.constructor=Ry;qb(Oy,Xi.prototype);Oy.isPureReactComponent=!0;var Ib=Array.isArray;function Cy(){}var Ye={H:null,A:null,T:null,S:null},Xb=Object.prototype.hasOwnProperty;function Ny(e,t,o){var r=o.ref;return{$$typeof:Ey,type:e,key:t,ref:r!==void 0?r:null,props:o}}function n5(e,t){return Ny(e.type,t,e.props)}function wy(e){return typeof e=="object"&&e!==null&&e.$$typeof===Ey}function a5(e){var t={"=":"=0",":":"=2"};return"$"+e.replace(/[=:]/g,function(o){return t[o]})}var Vb=/\/+/g;function Py(e,t){return typeof e=="object"&&e!==null&&e.key!=null?a5(""+e.key):t.toString(36)}function i5(e){switch(e.status){case"fulfilled":return e.value;case"rejected":throw e.reason;default:switch(typeof e.status=="string"?e.then(Cy,Cy):(e.status="pending",e.then(function(t){e.status==="pending"&&(e.status="fulfilled",e.value=t)},function(t){e.status==="pending"&&(e.status="rejected",e.reason=t)})),e.status){case"fulfilled":return e.value;case"rejected":throw e.reason}}throw e}function Yi(e,t,o,r,n){var a=typeof e;(a==="undefined"||a==="boolean")&&(e=null);var i=!1;if(e===null)i=!0;else switch(a){case"bigint":case"string":case"number":i=!0;break;case"object":switch(e.$$typeof){case Ey:case GN:i=!0;break;case Fb:return i=e._init,Yi(i(e._payload),t,o,r,n)}}if(i)return n=n(e),i=r===""?"."+Py(e,0):r,Ib(n)?(o="",i!=null&&(o=i.replace(Vb,"$&/")+"/"),Yi(n,t,o,"",function(p){return p})):n!=null&&(wy(n)&&(n=n5(n,o+(n.key==null||e&&e.key===n.key?"":(""+n.key).replace(Vb,"$&/")+"/")+i)),t.push(n)),1;i=0;var s=r===""?".":r+":";if(Ib(e))for(var l=0;l<e.length;l++)r=e[l],a=s+Py(r,l),i+=Yi(r,t,o,a,n);else if(l=r5(e),typeof l=="function")for(e=l.call(e),l=0;!(r=e.next()).done;)r=r.value,a=s+Py(r,l++),i+=Yi(r,t,o,a,n);else if(a==="object"){if(typeof e.then=="function")return Yi(i5(e),t,o,r,n);throw t=String(e),Error("Objects are not valid as a React child (found: "+(t==="[object Object]"?"object with keys {"+Object.keys(e).join(", ")+"}":t)+"). If you meant to render a collection of children, use an array instead.")}return i}function mc(e,t,o){if(e==null)return e;var r=[],n=0;return Yi(e,r,"","",function(a){return t.call(o,a,n++)}),r}function s5(e){if(e._status===-1){var t=e._result,o=t();o.then(function(r){(e._status===0||e._status===-1)&&(e._status=1,e._result=r,o.status===void 0&&(o.status="fulfilled",o.value=r))},function(r){(e._status===0||e._status===-1)&&(e._status=2,e._result=r,o.status===void 0&&(o.status="rejected",o.reason=r))}),e._status===-1&&(e._status=0,e._result=o)}if(e._status===1)return e._result.default;throw e._result}var Hb=typeof reportError=="function"?reportError:function(e){if(typeof window=="object"&&typeof window.ErrorEvent=="function"){var t=new window.ErrorEvent("error",{bubbles:!0,cancelable:!0,message:typeof e=="object"&&e!==null&&typeof e.message=="string"?String(e.message):String(e),error:e});if(!window.dispatchEvent(t))return}else if(typeof process=="object"&&typeof process.emit=="function"){process.emit("uncaughtException",e);return}console.error(e)};function Kb(e){var t=Ye.T,o={};o.types=t!==null?t.types:nullLine truncated
var FN=Object.create;var Ib=Object.defineProperty;var $N=Object.getOwnPropertyDescriptor;var qN=Object.getOwnPropertyNames;var GN=Object.getPrototypeOf,YN=Object.prototype.hasOwnProperty;var ro=(e,t)=>()=>{try{return t||e((t={exports:{}}).exports,t),t.exports}catch(o){throw t=0,o}};var XN=(e,t,o,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of qN(t))!YN.call(e,n)&&n!==o&&Ib(e,n,{get:()=>t[n],enumerable:!(r=$N(t,n))||r.enumerable});return e};var C=(e,t,o)=>(o=e!=null?FN(GN(e)):{},XN(t||!e||!e.__esModule?Ib(o,"default",{value:e,enumerable:!0}):o,e));var Jb=ro(ae=>{"use strict";var Oy=Symbol.for("react.transitional.element"),KN=Symbol.for("react.portal"),QN=Symbol.for("react.fragment"),ZN=Symbol.for("react.strict_mode"),WN=Symbol.for("react.profiler"),JN=Symbol.for("react.consumer"),e5=Symbol.for("react.context"),t5=Symbol.for("react.forward_ref"),o5=Symbol.for("react.suspense"),r5=Symbol.for("react.memo"),qb=Symbol.for("react.lazy"),n5=Symbol.for("react.activity"),a5=Symbol.for("react.view_transition"),Vb=Symbol.iterator;function i5(e){return e===null||typeof e!="object"?null:(e=Vb&&e[Vb]||e["@@iterator"],typeof e=="function"?e:null)}var Gb={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},Yb=Object.assign,Xb={};function Zi(e,t,o){this.props=e,this.context=t,this.refs=Xb,this.updater=o||Gb}Zi.prototype.isReactComponent={};Zi.prototype.setState=function(e,t){if(typeof e!="object"&&typeof e!="function"&&e!=null)throw Error("takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,t,"setState")};Zi.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")};function Kb(){}Kb.prototype=Zi.prototype;function Ny(e,t,o){this.props=e,this.context=t,this.refs=Xb,this.updater=o||Gb}var wy=Ny.prototype=new Kb;wy.constructor=Ny;Yb(wy,Zi.prototype);wy.isPureReactComponent=!0;var Hb=Array.isArray;function Ry(){}var Ke={H:null,A:null,T:null,S:null},Qb=Object.prototype.hasOwnProperty;function Ay(e,t,o){var r=o.ref;return{$$typeof:Oy,type:e,key:t,ref:r!==void 0?r:null,props:o}}function s5(e,t){return Ay(e.type,t,e.props)}function My(e){return typeof e=="object"&&e!==null&&e.$$typeof===Oy}function l5(e){var t={"=":"=0",":":"=2"};return"$"+e.replace(/[=:]/g,function(o){return t[o]})}var Fb=/\/+/g;function Ey(e,t){return typeof e=="object"&&e!==null&&e.key!=null?l5(""+e.key):t.toString(36)}function p5(e){switch(e.status){case"fulfilled":return e.value;case"rejected":throw e.reason;default:switch(typeof e.status=="string"?e.then(Ry,Ry):(e.status="pending",e.then(function(t){e.status==="pending"&&(e.status="fulfilled",e.value=t)},function(t){e.status==="pending"&&(e.status="rejected",e.reason=t)})),e.status){case"fulfilled":return e.value;case"rejected":throw e.reason}}throw e}function Qi(e,t,o,r,n){var a=typeof e;(a==="undefined"||a==="boolean")&&(e=null);var i=!1;if(e===null)i=!0;else switch(a){case"bigint":case"string":case"number":i=!0;break;case"object":switch(e.$$typeof){case Oy:case KN:i=!0;break;case qb:return i=e._init,Qi(i(e._payload),t,o,r,n)}}if(i)return n=n(e),i=r===""?"."+Ey(e,0):r,Hb(n)?(o="",i!=null&&(o=i.replace(Fb,"$&/")+"/"),Qi(n,t,o,"",function(p){return p})):n!=null&&(My(n)&&(n=s5(n,o+(n.key==null||e&&e.key===n.key?"":(""+n.key).replace(Fb,"$&/")+"/")+i)),t.push(n)),1;i=0;var s=r===""?".":r+":";if(Hb(e))for(var l=0;l<e.length;l++)r=e[l],a=s+Ey(r,l),i+=Qi(r,t,o,a,n);else if(l=i5(e),typeof l=="function")for(e=l.call(e),l=0;!(r=e.next()).done;)r=r.value,a=s+Ey(r,l++),i+=Qi(r,t,o,a,n);else if(a==="object"){if(typeof e.then=="function")return Qi(p5(e),t,o,r,n);throw t=String(e),Error("Objects are not valid as a React child (found: "+(t==="[object Object]"?"object with keys {"+Object.keys(e).join(", ")+"}":t)+"). If you meant to render a collection of children, use an array instead.")}return i}function Tc(e,t,o){if(e==null)return e;var r=[],n=0;return Qi(e,r,"","",function(a){return t.call(o,a,n++)}),r}function u5(e){if(e._status===-1){var t=e._result,o=t();o.then(function(r){(e._status===0||e._status===-1)&&(e._status=1,e._result=r,o.status===void 0&&(o.status="fulfilled",o.value=r))},function(r){(e._status===0||e._status===-1)&&(e._status=2,e._result=r,o.status===void 0&&(o.status="rejected",o.reason=r))}),e._status===-1&&(e._status=0,e._result=o)}if(e._status===1)return e._result.default;throw e._result}var $b=typeof reportError=="function"?reportError:function(e){if(typeof window=="object"&&typeof window.ErrorEvent=="function"){var t=new window.ErrorEvent("error",{bubbles:!0,cancelable:!0,message:typeof e=="object"&&e!==null&&typeof e.message=="string"?String(e.message):String(e),error:e});if(!window.dispatchEvent(t))return}else if(typeof process=="object"&&typeof process.emit=="function"){process.emit("uncaughtException",e);return}console.error(e)};function Zb(e){var t=Ke.T,o={};o.types=t!==null?t.types:nullLine truncated
at`)?" (<anonymous>)":-1<o.stack.indexOf("@")?"@unknown:0:0":""}return`
`+Gg+e+IC}var Yg=!1;function Xg(e,t){if(!e||Yg)return"";Yg=!0;var o=Error.prepareStackTrace;Error.prepareStackTrace=void 0;try{var r={DetermineComponentFrameRoot:function(){try{if(t){var d=function(){throw Error()};if(Object.defineProperty(d.prototype,"props",{set:function(){throw Error()}}),typeof Reflect=="object"&&Reflect.construct){try{Reflect.construct(d,[])}catch(b){var c=b}Reflect.construct(e,[],d)}else{try{d.call()}catch(b){c=b}d=!1;try{var u=Object.getOwnPropertyDescriptor(e.prototype,"props");Object.defineProperty(e.prototype,"props",{configurable:!0,set:function(){throw Error()}}),d=!0,new e}finally{d&&(u!==void 0?Object.defineProperty(e.prototype,"props",u):delete e.prototype.props)}}}else{try{throw Error()}catch(b){c=b}(d=e())&&typeof d.catch=="function"&&d.catch(function(){})}}catch(b){if(b&&c&&typeof b.stack=="string")return[b.stack,c.stack]}return[null,null]}};r.DetermineComponentFrameRoot.displayName="DetermineComponentFrameRoot";var n=Object.getOwnPropertyDescriptor(r.DetermineComponentFrameRoot,"name");n&&n.configurable&&Object.defineProperty(r.DetermineComponentFrameRoot,"name",{value:"DetermineComponentFrameRoot"});var a=r.DetermineComponentFrameRoot(),i=a[0],s=a[1];if(i&&s){var l=i.split(`
`+Xg+e+IC}var Kg=!1;function Qg(e,t){if(!e||Kg)return"";Kg=!0;var o=Error.prepareStackTrace;Error.prepareStackTrace=void 0;try{var r={DetermineComponentFrameRoot:function(){try{if(t){var d=function(){throw Error()};if(Object.defineProperty(d.prototype,"props",{set:function(){throw Error()}}),typeof Reflect=="object"&&Reflect.construct){try{Reflect.construct(d,[])}catch(b){var c=b}Reflect.construct(e,[],d)}else{try{d.call()}catch(b){c=b}d=!1;try{var u=Object.getOwnPropertyDescriptor(e.prototype,"props");Object.defineProperty(e.prototype,"props",{configurable:!0,set:function(){throw Error()}}),d=!0,new e}finally{d&&(u!==void 0?Object.defineProperty(e.prototype,"props",u):delete e.prototype.props)}}}else{try{throw Error()}catch(b){c=b}(d=e())&&typeof d.catch=="function"&&d.catch(function(){})}}catch(b){if(b&&c&&typeof b.stack=="string")return[b.stack,c.stack]}return[null,null]}};r.DetermineComponentFrameRoot.displayName="DetermineComponentFrameRoot";var n=Object.getOwnPropertyDescriptor(r.DetermineComponentFrameRoot,"name");n&&n.configurable&&Object.defineProperty(r.DetermineComponentFrameRoot,"name",{value:"DetermineComponentFrameRoot"});var a=r.DetermineComponentFrameRoot(),i=a[0],s=a[1];if(i&&s){var l=i.split(`
`),p=s.split(`
`);for(n=r=0;r<l.length&&!l[r].includes("DetermineComponentFrameRoot");)r++;for(;n<p.length&&!p[n].includes("DetermineComponentFrameRoot");)n++;if(r===l.length||n===p.length)for(r=l.length-1,n=p.length-1;1<=r&&0<=n&&l[r]!==p[n];)n--;for(;1<=r&&0<=n;r--,n--)if(l[r]!==p[n]){if(r!==1||n!==1)do if(r--,n--,0>n||l[r]!==p[n]){var f=`
`+l[r].replace(" at new "," at ");return e.displayName&&f.includes("<anonymous>")&&(f=f.replace("<anonymous>",e.displayName)),f}while(1<=r&&0<=n);break}}}finally{Yg=!1,Error.prepareStackTrace=o}return(o=e?e.displayName||e.name:"")?pa(o):""}function Qz(e,t){switch(e.tag){case 26:case 27:case 5:return pa(e.type);case 16:return pa("Lazy");case 13:return e.child!==t&&t!==null?pa("Suspense Fallback"):pa("Suspense");case 19:return pa("SuspenseList");case 0:case 15:return Xg(e.type,!1);case 11:return Xg(e.type.render,!1);case 1:return Xg(e.type,!0);case 31:return pa("Activity");case 30:return pa("ViewTransition");default:return""}}function VC(e){try{var t="",o=null;do t+=Qz(e,o),o=e,e=e.return;while(e);return t}catch(r){return`
`+l[r].replace(" at new "," at ");return e.displayName&&f.includes("<anonymous>")&&(f=f.replace("<anonymous>",e.displayName)),f}while(1<=r&&0<=n);break}}}finally{Kg=!1,Error.prepareStackTrace=o}return(o=e?e.displayName||e.name:"")?fa(o):""}function Jz(e,t){switch(e.tag){case 26:case 27:case 5:return fa(e.type);case 16:return fa("Lazy");case 13:return e.child!==t&&t!==null?fa("Suspense Fallback"):fa("Suspense");case 19:return fa("SuspenseList");case 0:case 15:return Qg(e.type,!1);case 11:return Qg(e.type.render,!1);case 1:return Qg(e.type,!0);case 31:return fa("Activity");case 30:return fa("ViewTransition");default:return""}}function VC(e){try{var t="",o=null;do t+=Jz(e,o),o=e,e=e.return;while(e);return t}catch(r){return`
Error generating stack: `+r.message+`
`+r.stack}}var DT=Object.prototype.hasOwnProperty,U0=Rt.unstable_scheduleCallback,Kg=Rt.unstable_cancelCallback,Zz=Rt.unstable_shouldYield,Wz=Rt.unstable_requestPaint,Fo=Rt.unstable_now,Jz=Rt.unstable_getCurrentPriorityLevel,wR=Rt.unstable_ImmediatePriority,AR=Rt.unstable_UserBlockingPriority,Om=Rt.unstable_NormalPriority,e6=Rt.unstable_LowPriority,MR=Rt.unstable_IdlePriority,t6=Rt.log,o6=Rt.unstable_setDisableYieldValue,tc=null,$o=null;function ma(e){if(typeof t6=="function"&&o6(e),$o&&typeof $o.setStrictMode=="function")try{$o.setStrictMode(tc,e)}catch{}}var qo=Math.clz32?Math.clz32:a6,r6=Math.log,n6=Math.LN2;function a6(e){return e>>>=0,e===0?32:31-(r6(e)/n6|0)|0}var kd=256,Id=262144,Vd=4194304;function xi(e){var t=e&42;if(t!==0)return t;switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return e&-e;case 262144:case 524288:case 1048576:case 2097152:return e&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return e&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return e}}function Jm(e,t,o){var r=e.pendingLanes;if(r===0)return 0;var n=0,a=e.suspendedLanes,i=e.pingedLanes;e=e.warmLanes;var s=r&134217727;return s!==0?(r=s&~a,r!==0?n=xi(r):(i&=s,i!==0?n=xi(i):o||(o=s&~e,o!==0&&(n=xi(o))))):(s=r&~a,s!==0?n=xi(s):i!==0?n=xi(i):o||(o=r&~e,o!==0&&(n=xi(o)))),n===0?0:t!==0&&t!==n&&(t&a)===0&&(a=n&-n,o=t&-t,a>=o||a===32&&(o&4194048)!==0)?t:n}function oc(e,t){return(e.pendingLanes&~(e.suspendedLanes&~e.pingedLanes)&t)===0}function _R(e,t){(t&8)!==0&&(t|=t&32);var o=e.entangledLanes;if(o!==0)for(e=e.entanglements,o&=t;0<o;){var r=31-qo(o),n=1<<r;t|=e[r],o&=~n}return t}function i6(e,t){switch(e){case 1:case 2:case 4:case 8:case 64:return t+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function DR(){var e=Vd;return Vd<<=1,(Vd&62914560)===0&&(Vd=4194304),e}function Qg(e){for(var t=[],o=0;31>o;o++)t.push(e);return t}function rc(e,t){e.pendingLanes|=t,t!==268435456&&(e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0)}function s6(e,t,o,r,n,a){var i=e.pendingLanes;e.pendingLanes=o,e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0,e.expiredLanes&=o,e.entangledLanes&=o,e.errorRecoveryDisabledLanes&=o,e.shellSuspendCounter=0;var s=e.entanglements,l=e.expirationTimes,p=e.hiddenUpdates;for(o=i&~o;0<o;){var f=31-qo(o),d=1<<f;s[f]=0,l[f]=-1;var c=p[f];if(c!==null)for(p[f]=null,f=0;f<c.length;f++){var u=c[f];u!==null&&(u.lane&=-536870913)}o&=~d}r!==0&&zR(e,r,0),a!==0&&n===0&&e.tag!==0&&(e.suspendedLanes|=a&~(i&~t))}function zR(e,t,o){e.pendingLanes|=t,e.suspendedLanes&=~t;var r=31-qo(t);e.entangledLanes|=t,e.entanglements[r]=e.entanglements[r]|1073741824|o&261930}function jR(e,t){var o=e.entangledLanes|=t;for(e=e.entanglements;o;){var r=31-qo(o),n=1<<r;n&t|e[r]&t&&(e[r]|=t),o&=~n}}function UR(e,t){var o=t&-t;return o=(o&42)!==0?1:B0(o),(o&(e.suspendedLanes|t))!==0?0:o}function B0(e){switch(e){case 2:e=1;break;case 8:e=4;break;case 32:e=16;break;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:case 4194304:case 8388608:case 16777216:case 33554432:e=128;break;case 268435456:e=134217728;break;default:e=0}return e}function L0(e){return e&=-e,2<e?8<e?(e&134217727)!==0?32:268435456:8:2}function BR(){var e=Re.p;return e!==0?e:(e=window.event,e===void 0?32:TN(e.type))}function HC(e,t){var o=Re.p;try{return Re.p=e,t()}finally{Re.p=o}}var jn=Math.random().toString(36).slice(2),Ft="__reactFiber$"+jn,Oo="__reactProps$"+jn,kl="__reactContainer$"+jn,FC="__reactEvents$"+jn,l6="__reactListeners$"+jn,p6="__reactHandles$"+jn,$C="__reactResources$"+jn,nc="__reactMarker$"+jn,Nm="__reactLoad$"+jn;function ey(e){delete e[Ft],delete e[Oo],delete e[l6],delete e[p6]}function Ci(e){var t;if(t=e[Ft])return t;for(var o=e.parentNode;o;){if(t=o[kl]||o[Ft]){if(o=t.alternate,t.child!==null||o!==null&&o.child!==null)for(e=sR(e);e!==null;){if(o=e[Ft])return o;e=sR(e)}return t}e=o,o=e.parentNode}return null}function Il(e){if(e=e[Ft]||e[kl]){var t=e.tag;if(t===5||t===6||t===13||t===31||t===26||t===27||t===3)return e}return null}function Su(e){var t=e.tag;if(t===5||t===26||t===27||t===6)return e.stateNode;throw Error(z(33))}function hl(e){var t=e[$C];return t||(t=e[$C]={hoistableStyles:new Map,hoistableScripts:new Map}),t}function _t(e){e[nc]=!0}function LR(e){e[Nm]=void 0}var kR=new Set,IR={};function Ii(e,t){Ol(e,t),Ol(e+"Capt Line truncated
`).replace(Xj,"")}function K2(e,t){return t=ZE(t),ZE(e)===t}function ke(e,t,o,r,n,a){switch(o){case"children":if(typeof r=="string")t==="body"||t==="textarea"&&r===""||Nl(e,r);else if(typeof r=="number"||typeof r=="bigint")t!=="body"&&Nl(e,""+r);else return;break;case"className":Hd(e,"class",r);break;case"tabIndex":Hd(e,"tabindex",r);break;case"dir":case"role":case"viewBox":case"width":case"height":Hd(e,o,r);break;case"style":GR(e,r,a);return;case"data":if(t!=="object"){Hd(e,"data",r);break}case"src":case"href":if(r===""&&(t!=="a"||o!=="href")){e.removeAttribute(o);break}if(r==null||typeof r=="function"||typeof r=="symbol"||typeof r=="boolean"){e.removeAttribute(o);break}r=im(r),e.setAttribute(o,r);break;case"action":case"formAction":if(typeof r=="function"){e.setAttribute(o,"javascript:throw new Error('A React form was unexpectedly submitted. If you called form.submit() manually, consider using form.requestSubmit() instead. If you\\'re trying to use event.stopPropagation() in a submit event handler, consider also calling event.preventDefault().')");break}else typeof a=="function"&&(o==="formAction"?(t!=="input"&&ke(e,t,"name",n.name,n,null),ke(e,t,"formEncType",n.formEncType,n,null),ke(e,t,"formMethod",n.formMethod,n,null),ke(e,t,"formTarget",n.formTarget,n,null)):(ke(e,t,"encType",n.encType,n,null),ke(e,t,"method",n.method,n,null),ke(e,t,"target",n.target,n,null)));if(r==null||typeof r=="symbol"||typeof r=="boolean"){e.removeAttribute(o);break}r=im(r),e.setAttribute(o,r);break;case"onClick":r!=null&&(e.onclick=Yr);return;case"onScroll":r!=null&&me("scroll",e);return;case"onScrollEnd":r!=null&&me("scrollend",e);return;case"dangerouslySetInnerHTML":if(r!=null){if(typeof r!="object"||!("__html"in r))throw Error(z(61));if(o=r.__html,o!=null){if(n.children!=null)throw Error(z(60));a?.__html!==o&&(e.innerHTML=o)}}break;case"multiple":e.multiple=r&&typeof r!="function"&&typeof r!="symbol";break;case"muted":e.muted=r&&typeof r!="function"&&typeof r!="symbol";break;case"suppressContentEditableWarning":case"suppressHydrationWarning":case"defaultValue":case"defaultChecked":case"innerHTML":case"ref":break;case"autoFocus":break;case"xlinkHref":if(r==null||typeof r=="function"||typeof r=="boolean"||typeof r=="symbol"){e.removeAttribute("xlink:href");break}o=im(r),e.setAttributeNS("http://www.w3.org/1999/xlink","xlink:href",o);break;case"contentEditable":case"spellCheck":case"draggable":case"value":case"autoReverse":case"externalResourcesRequired":case"focusable":case"preserveAlpha":r!=null&&typeof r!="function"&&typeof r!="symbol"?e.setAttribute(o,r):e.removeAttribute(o);break;case"inert":case"allowFullScreen":case"async":case"autoPlay":case"controls":case"credentialless":case"default":case"defer":case"disabled":case"disablePictureInPicture":case"disableRemotePlayback":case"formNoValidate":case"hidden":case"loop":case"noModule":case"noValidate":case"open":case"playsInline":case"readOnly":case"required":case"reversed":case"scoped":case"seamless":case"itemScope":r&&typeof r!="function"&&typeof r!="symbol"?e.setAttribute(o,""):e.removeAttribute(o);break;case"capture":case"download":r===!0?e.setAttribute(o,""):r!==!1&&r!=null&&typeof r!="function"&&typeof r!="symbol"?e.setAttribute(o,r):e.removeAttribute(o);break;case"cols":case"rows":case"size":case"span":r!=null&&typeof r!="function"&&typeof r!="symbol"&&!isNaN(r)&&1<=r?e.setAttribute(o,r):e.removeAttribute(o);break;case"rowSpan":case"start":r==null||typeof r=="function"||typeof r=="symbol"||isNaN(r)?e.removeAttribute(o):e.setAttribute(o,r);break;case"popover":me("beforetoggle",e),me("toggle",e),am(e,"popover",r);break;case"xlinkActuate":Pn(e,"http://www.w3.org/1999/xlink","xlink:actuate",r);break;case"xlinkArcrole":Pn(e,"http://www.w3.org/1999/xlink","xlink:arcrole",r);break;case"xlinkRole":Pn(e,"http://www.w3.org/1999/xlink","xlink:role",r);break;case"xlinkShow":Pn(e,"http://www.w3.org/1999/xlink","xlink:show",r);break;case"xlinkTitle":Pn(e,"http://www.w3.org/1999/xlink","xlink:title",r);break;case"xlinkType":Pn(e,"http://www.w3.org/1999/xlink","xlink:type",r);break;case"xmlBase":Pn(e,"http://www.w3.org/XML/1998/namespace","xml:base",r);break;case"xmlLang":Pn(e,"http://www.w3.org/XML/1998/namespace","xml:lang",r);break;case"xmlSpace":Pn(e,"http://www.w3.org/XML/1998/namespace","xml:space",r);break;case"is":am(e,"is",r);break;case"innerText":case"textContent":return;default:if(!(2<o.length)||o[0]!=="o"&&o[0]!=="O"||o[1]!=="n"&&o[1]!=="N")o=y6.get(o)||o,am(e,o,r);else return}Ce=!0}function P0(e,t,o,r,n,a){switch(o){case"style":GR(e,r,a);return;case"dangerouslySetInnerHTML":if(r!=null){if(typeof r!="object"||!("__html"in r))throw Error(z(61));if(o=r.__html,o!=null){if(n.children!=null)throw Error(z(60));a?.__html!==o&&(e.innerHTML=o)}}break;case"children":if(typeof r=="string")Nl(e,r);else if(typeof r=="number"||typeof r=="bigint")Nl(e,""+r);else return;break;case"onScroll":r!=null&&me("scroll",e);return;case"onScrollEnd":r!=null&&me("scrollend",e);return;case"onClick":r Line truncated
`+r.stack}}var jT=Object.prototype.hasOwnProperty,L0=Ot.unstable_scheduleCallback,Zg=Ot.unstable_cancelCallback,e6=Ot.unstable_shouldYield,t6=Ot.unstable_requestPaint,$o=Ot.unstable_now,o6=Ot.unstable_getCurrentPriorityLevel,wR=Ot.unstable_ImmediatePriority,AR=Ot.unstable_UserBlockingPriority,Am=Ot.unstable_NormalPriority,r6=Ot.unstable_LowPriority,MR=Ot.unstable_IdlePriority,n6=Ot.log,a6=Ot.unstable_setDisableYieldValue,nc=null,qo=null;function ga(e){if(typeof n6=="function"&&a6(e),qo&&typeof qo.setStrictMode=="function")try{qo.setStrictMode(nc,e)}catch{}}var Go=Math.clz32?Math.clz32:l6,i6=Math.log,s6=Math.LN2;function l6(e){return e>>>=0,e===0?32:31-(i6(e)/s6|0)|0}var Hd=256,Fd=262144,$d=4194304;function Ci(e){var t=e&42;if(t!==0)return t;switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return e&-e;case 262144:case 524288:case 1048576:case 2097152:return e&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return e&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return e}}function oy(e,t,o){var r=e.pendingLanes;if(r===0)return 0;var n=0,a=e.suspendedLanes,i=e.pingedLanes;e=e.warmLanes;var s=r&134217727;return s!==0?(r=s&~a,r!==0?n=Ci(r):(i&=s,i!==0?n=Ci(i):o||(o=s&~e,o!==0&&(n=Ci(o))))):(s=r&~a,s!==0?n=Ci(s):i!==0?n=Ci(i):o||(o=r&~e,o!==0&&(n=Ci(o)))),n===0?0:t!==0&&t!==n&&(t&a)===0&&(a=n&-n,o=t&-t,a>=o||a===32&&(o&4194048)!==0)?t:n}function ac(e,t){return(e.pendingLanes&~(e.suspendedLanes&~e.pingedLanes)&t)===0}function _R(e,t){(t&8)!==0&&(t|=t&32);var o=e.entangledLanes;if(o!==0)for(e=e.entanglements,o&=t;0<o;){var r=31-Go(o),n=1<<r;t|=e[r],o&=~n}return t}function p6(e,t){switch(e){case 1:case 2:case 4:case 8:case 64:return t+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function DR(){var e=$d;return $d<<=1,($d&62914560)===0&&($d=4194304),e}function Wg(e){for(var t=[],o=0;31>o;o++)t.push(e);return t}function ic(e,t){e.pendingLanes|=t,t!==268435456&&(e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0)}function u6(e,t,o,r,n,a){var i=e.pendingLanes;e.pendingLanes=o,e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0,e.expiredLanes&=o,e.entangledLanes&=o,e.errorRecoveryDisabledLanes&=o,e.shellSuspendCounter=0;var s=e.entanglements,l=e.expirationTimes,p=e.hiddenUpdates;for(o=i&~o;0<o;){var f=31-Go(o),d=1<<f;s[f]=0,l[f]=-1;var c=p[f];if(c!==null)for(p[f]=null,f=0;f<c.length;f++){var u=c[f];u!==null&&(u.lane&=-536870913)}o&=~d}r!==0&&zR(e,r,0),a!==0&&n===0&&e.tag!==0&&(e.suspendedLanes|=a&~(i&~t))}function zR(e,t,o){e.pendingLanes|=t,e.suspendedLanes&=~t;var r=31-Go(t);e.entangledLanes|=t,e.entanglements[r]=e.entanglements[r]|1073741824|o&261930}function jR(e,t){var o=e.entangledLanes|=t;for(e=e.entanglements;o;){var r=31-Go(o),n=1<<r;n&t|e[r]&t&&(e[r]|=t),o&=~n}}function UR(e,t){var o=t&-t;return o=(o&42)!==0?1:k0(o),(o&(e.suspendedLanes|t))!==0?0:o}function k0(e){switch(e){case 2:e=1;break;case 8:e=4;break;case 32:e=16;break;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:case 4194304:case 8388608:case 16777216:case 33554432:e=128;break;case 268435456:e=134217728;break;default:e=0}return e}function I0(e){return e&=-e,2<e?8<e?(e&134217727)!==0?32:268435456:8:2}function BR(){var e=Oe.p;return e!==0?e:(e=window.event,e===void 0?32:TN(e.type))}function HC(e,t){var o=Oe.p;try{return Oe.p=e,t()}finally{Oe.p=o}}var Bn=Math.random().toString(36).slice(2),$t="__reactFiber$"+Bn,Ao="__reactProps$"+Bn,$l="__reactContainer$"+Bn,FC="__reactEvents$"+Bn,c6="__reactListeners$"+Bn,f6="__reactHandles$"+Bn,$C="__reactResources$"+Bn,sc="__reactMarker$"+Bn,Mm="__reactLoad$"+Bn;function ry(e){delete e[$t],delete e[Ao],delete e[c6],delete e[f6]}function Oi(e){var t;if(t=e[$t])return t;for(var o=e.parentNode;o;){if(t=o[$l]||o[$t]){if(o=t.alternate,t.child!==null||o!==null&&o.child!==null)for(e=sR(e);e!==null;){if(o=e[$t])return o;e=sR(e)}return t}e=o,o=e.parentNode}return null}function ql(e){if(e=e[$t]||e[$l]){var t=e.tag;if(t===5||t===6||t===13||t===31||t===26||t===27||t===3)return e}return null}function Eu(e){var t=e.tag;if(t===5||t===26||t===27||t===6)return e.stateNode;throw Error(z(33))}function xl(e){var t=e[$C];return t||(t=e[$C]={hoistableStyles:new Map,hoistableScripts:new Map}),t}function Dt(e){e[sc]=!0}function LR(e){e[Mm]=void 0}var kR=new Set,IR={};function Fi(e,t){_l(e,t),_l(e+"Capt Line truncated
`).replace(Zj,"")}function KO(e,t){return t=ZE(t),ZE(e)===t}function ke(e,t,o,r,n,a){switch(o){case"children":if(typeof r=="string")t==="body"||t==="textarea"&&r===""||Dl(e,r);else if(typeof r=="number"||typeof r=="bigint")t!=="body"&&Dl(e,""+r);else return;break;case"className":qd(e,"class",r);break;case"tabIndex":qd(e,"tabindex",r);break;case"dir":case"role":case"viewBox":case"width":case"height":qd(e,o,r);break;case"style":GR(e,r,a);return;case"data":if(t!=="object"){qd(e,"data",r);break}case"src":case"href":if(r===""&&(t!=="a"||o!=="href")){e.removeAttribute(o);break}if(r==null||typeof r=="function"||typeof r=="symbol"||typeof r=="boolean"){e.removeAttribute(o);break}r=pm(r),e.setAttribute(o,r);break;case"action":case"formAction":if(typeof r=="function"){e.setAttribute(o,"javascript:throw new Error('A React form was unexpectedly submitted. If you called form.submit() manually, consider using form.requestSubmit() instead. If you\\'re trying to use event.stopPropagation() in a submit event handler, consider also calling event.preventDefault().')");break}else typeof a=="function"&&(o==="formAction"?(t!=="input"&&ke(e,t,"name",n.name,n,null),ke(e,t,"formEncType",n.formEncType,n,null),ke(e,t,"formMethod",n.formMethod,n,null),ke(e,t,"formTarget",n.formTarget,n,null)):(ke(e,t,"encType",n.encType,n,null),ke(e,t,"method",n.method,n,null),ke(e,t,"target",n.target,n,null)));if(r==null||typeof r=="symbol"||typeof r=="boolean"){e.removeAttribute(o);break}r=pm(r),e.setAttribute(o,r);break;case"onClick":r!=null&&(e.onclick=Qr);return;case"onScroll":r!=null&&fe("scroll",e);return;case"onScrollEnd":r!=null&&fe("scrollend",e);return;case"dangerouslySetInnerHTML":if(r!=null){if(typeof r!="object"||!("__html"in r))throw Error(z(61));if(o=r.__html,o!=null){if(n.children!=null)throw Error(z(60));a?.__html!==o&&(e.innerHTML=o)}}break;case"multiple":e.multiple=r&&typeof r!="function"&&typeof r!="symbol";break;case"muted":e.muted=r&&typeof r!="function"&&typeof r!="symbol";break;case"suppressContentEditableWarning":case"suppressHydrationWarning":case"defaultValue":case"defaultChecked":case"innerHTML":case"ref":break;case"autoFocus":break;case"xlinkHref":if(r==null||typeof r=="function"||typeof r=="boolean"||typeof r=="symbol"){e.removeAttribute("xlink:href");break}o=pm(r),e.setAttributeNS("http://www.w3.org/1999/xlink","xlink:href",o);break;case"contentEditable":case"spellCheck":case"draggable":case"value":case"autoReverse":case"externalResourcesRequired":case"focusable":case"preserveAlpha":r!=null&&typeof r!="function"&&typeof r!="symbol"?e.setAttribute(o,r):e.removeAttribute(o);break;case"inert":case"allowFullScreen":case"async":case"autoPlay":case"controls":case"credentialless":case"default":case"defer":case"disabled":case"disablePictureInPicture":case"disableRemotePlayback":case"formNoValidate":case"hidden":case"loop":case"noModule":case"noValidate":case"open":case"playsInline":case"readOnly":case"required":case"reversed":case"scoped":case"seamless":case"itemScope":r&&typeof r!="function"&&typeof r!="symbol"?e.setAttribute(o,""):e.removeAttribute(o);break;case"capture":case"download":r===!0?e.setAttribute(o,""):r!==!1&&r!=null&&typeof r!="function"&&typeof r!="symbol"?e.setAttribute(o,r):e.removeAttribute(o);break;case"cols":case"rows":case"size":case"span":r!=null&&typeof r!="function"&&typeof r!="symbol"&&!isNaN(r)&&1<=r?e.setAttribute(o,r):e.removeAttribute(o);break;case"rowSpan":case"start":r==null||typeof r=="function"||typeof r=="symbol"||isNaN(r)?e.removeAttribute(o):e.setAttribute(o,r);break;case"popover":fe("beforetoggle",e),fe("toggle",e),lm(e,"popover",r);break;case"xlinkActuate":En(e,"http://www.w3.org/1999/xlink","xlink:actuate",r);break;case"xlinkArcrole":En(e,"http://www.w3.org/1999/xlink","xlink:arcrole",r);break;case"xlinkRole":En(e,"http://www.w3.org/1999/xlink","xlink:role",r);break;case"xlinkShow":En(e,"http://www.w3.org/1999/xlink","xlink:show",r);break;case"xlinkTitle":En(e,"http://www.w3.org/1999/xlink","xlink:title",r);break;case"xlinkType":En(e,"http://www.w3.org/1999/xlink","xlink:type",r);break;case"xmlBase":En(e,"http://www.w3.org/XML/1998/namespace","xml:base",r);break;case"xmlLang":En(e,"http://www.w3.org/XML/1998/namespace","xml:lang",r);break;case"xmlSpace":En(e,"http://www.w3.org/XML/1998/namespace","xml:space",r);break;case"is":lm(e,"is",r);break;case"innerText":case"textContent":return;default:if(!(2<o.length)||o[0]!=="o"&&o[0]!=="O"||o[1]!=="n"&&o[1]!=="N")o=T6.get(o)||o,lm(e,o,r);else return}Pe=!0}function E0(e,t,o,r,n,a){switch(o){case"style":GR(e,r,a);return;case"dangerouslySetInnerHTML":if(r!=null){if(typeof r!="object"||!("__html"in r))throw Error(z(61));if(o=r.__html,o!=null){if(n.children!=null)throw Error(z(60));a?.__html!==o&&(e.innerHTML=o)}}break;case"children":if(typeof r=="string")Dl(e,r);else if(typeof r=="number"||typeof r=="bigint")Dl(e,""+r);else return;break;case"onScroll":r!=null&&fe("scroll",e);return;case"onScrollEnd":r!=null&&fe("scrollend",e);return;case"onClick":r Line truncated
${s}.classList.add('${c}'.replace('%s', colorScheme));`}let d=f.match(/\[([^[\]]+)\]/);if(d){let[c,u]=d[1].split("=");u||(p+=`${s}.removeAttribute('${c}'.replace('%s', light));
${s}.removeAttribute('${c}'.replace('%s', dark));`),p+=`
${s}.setAttribute('${c}'.replace('%s', colorScheme), ${u?`${u}.replace('%s', colorScheme)`:'""'});`}else f!==".%s"&&(p+=`${s}.setAttribute('${f}', colorScheme);`);return(0,Bx.jsx)("script",{suppressHydrationWarning:!0,nonce:typeof window>"u"?l:"",dangerouslySetInnerHTML:{__html:`(function() {
${s}.setAttribute('${c}'.replace('%s', colorScheme), ${u?`${u}.replace('%s', colorScheme)`:'""'});`}else f!==".%s"&&(p+=`${s}.setAttribute('${f}', colorScheme);`);return(0,kx.jsx)("script",{suppressHydrationWarning:!0,nonce:typeof window>"u"?l:"",dangerouslySetInnerHTML:{__html:`(function() {
try {
let colorScheme = '';
const mode = localStorage.getItem('${n}') || '${t}';
@@ -33,15 +33,15 @@ try {
if (colorScheme) {
${p}
}
} catch(e){}})();`}},"mui-color-scheme-init")}var Lt=C(L(),1);function _w(){}var Dw=({key:e,storageWindow:t})=>(!t&&typeof window<"u"&&(t=window),{get(o){if(typeof window>"u")return;if(!t)return o;let r;try{r=t.localStorage.getItem(e)}catch{}return r||o},set:o=>{if(t)try{t.localStorage.setItem(e,o)}catch{}},subscribe:o=>{if(!t)return _w;let r=n=>{let a=n.newValue;n.key===e&&o(a)};return t.addEventListener("storage",r),()=>{t.removeEventListener("storage",r)}}}),Lx=Dw;function ch(){}function kx(e){if(typeof window<"u"&&typeof window.matchMedia=="function"&&e==="system")return window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"}function Ix(e,t){if(e.mode==="light"||e.mode==="system"&&e.systemMode==="light")return t("light");if(e.mode==="dark"||e.mode==="system"&&e.systemMode==="dark")return t("dark")}function zw(e){return Ix(e,t=>{if(t==="light")return e.lightColorScheme;if(t==="dark")return e.darkColorScheme})}function fh(e){let{defaultMode:t="light",defaultLightColorScheme:o,defaultDarkColorScheme:r,supportedColorSchemes:n=[],modeStorageKey:a=fp,colorSchemeStorageKey:i=dp,storageWindow:s=typeof window>"u"?void 0:window,storageManager:l=Lx,noSsr:p=!1}=e,f=n.join(","),d=n.length>1,c=Lt.useMemo(()=>l?.({key:a,storageWindow:s}),[l,a,s]),u=Lt.useMemo(()=>l?.({key:`${i}-light`,storageWindow:s}),[l,i,s]),b=Lt.useMemo(()=>l?.({key:`${i}-dark`,storageWindow:s}),[l,i,s]),[v,x]=Lt.useState(()=>{let R=c?.get(t)||t,N=u?.get(o)||o,O=b?.get(r)||r;return{mode:R,systemMode:kx(R),lightColorScheme:N,darkColorScheme:O}}),[m,h]=Lt.useState(p||!d);Lt.useEffect(()=>{h(!0)},[]);let y=zw(v),g=Lt.useCallback(R=>{x(N=>{if(R===N.mode)return N;let O=R??t;return c?.set(O),{...N,mode:O,systemMode:kx(O)}})},[c,t]),S=Lt.useCallback(R=>{R?typeof R=="string"?R&&!f.includes(R)?console.error(`\`${R}\` does not exist in \`theme.colorSchemes\`.`):x(N=>{let O={...N};return Ix(N,D=>{D==="light"&&(u?.set(R),O.lightColorScheme=R),D==="dark"&&(b?.set(R),O.darkColorScheme=R)}),O}):x(N=>{let O={...N},D=R.light===null?o:R.light,T=R.dark===null?r:R.dark;return D&&(f.includes(D)?(O.lightColorScheme=D,u?.set(D)):console.error(`\`${D}\` does not exist in \`theme.colorSchemes\`.`)),T&&(f.includes(T)?(O.darkColorScheme=T,b?.set(T)):console.error(`\`${T}\` does not exist in \`theme.colorSchemes\`.`)),O}):x(N=>(u?.set(o),b?.set(r),{...N,lightColorScheme:o,darkColorScheme:r}))},[f,u,b,o,r]),P=Lt.useCallback(R=>{v.mode==="system"&&x(N=>{let O=R?.matches?"dark":"light";return N.systemMode===O?N:{...N,systemMode:O}})},[v.mode]),E=Lt.useRef(P);return E.current=P,Lt.useEffect(()=>{if(typeof window.matchMedia!="function"||!d)return;let R=(...O)=>E.current(...O),N=window.matchMedia("(prefers-color-scheme: dark)");return N.addListener(R),R(N),()=>{N.removeListener(R)}},[d]),Lt.useEffect(()=>{if(d){let R=c?.subscribe(D=>{(!D||["light","dark","system"].includes(D))&&g(D||t)})||ch,N=u?.subscribe(D=>{(!D||f.match(D))&&S({light:D})})||ch,O=b?.subscribe(D=>{(!D||f.match(D))&&S({dark:D})})||ch;return()=>{R(),N(),O()}}},[S,g,f,t,s,d,c,u,b]),{...v,mode:m?v.mode:void 0,systemMode:m?v.systemMode:void 0,colorScheme:m?y:void 0,setMode:g,setColorScheme:S}}var vs=C(I(),1),jw="*{-webkit-transition:none!important;-moz-transition:none!important;-o-transition:none!important;-ms-transition:none!important;transition:none!important}";function cf(e){let{themeId:t,theme:o={},modeStorageKey:r=fp,colorSchemeStorageKey:n=dp,disableTransitionOnChange:a=!1,defaultColorScheme:i,resolveTheme:s}=e,l={allColorSchemes:[],colorScheme:void 0,darkColorScheme:void 0,lightColorScheme:void 0,mode:void 0,setColorScheme:()=>{},setMode:()=>{},systemMode:void 0},p=kt.createContext(void 0),f=()=>kt.useContext(p)||l,d={},c={};function u(m){let{children:h,theme:y,modeStorageKey:g=r,colorSchemeStorageKey:S=n,disableTransitionOnChange:P=a,storageManager:E,storageWindow:R=typeof window>"u"?void 0:window,documentNode:N=typeof document>"u"?void 0:document,colorSchemeNode:O=typeof document>"u"?void 0:document.documentElement,disableNestedContext:D=!1,disableStyleSheetGeneration:T=!1,defaultMode:A="system",forceThemeRerender:M=!1,noSsr:U}=m,k=kt.useRef(!1),Y=sn(),Z=kt.useContext(p),X=!!Z&&!D,Te=kt.useMemo(()=>y||(typeof o=="function"?o():o),[y]),te=Te[t],ie=te||Te,{colorSchemes:ne=d,components:Je=c,cssVarPrefix:Oe}=ie,ze=Object.keys(ne).filter(nt=>!!ne[nt]).join(","),fe=kt.useMemo(()=>ze.split(","),[ze]),ot=typeof i=="string"?i:i.light,de=typeof i=="string"?i:i.dark,oe=ne[ot]&&ne[de]?A:ne[ie.defaultColorScheme]?.palette?.mode||ie.palette?.mode,{mode:le,setMode:be,systemMode:ee,lightColorScheme:B,darkColorScheme:se,colorScheme:xe,setColorScheme:he}=fh({supportedColorSchemes:fe,defaultLightColorScheme:ot,defaultDarkColorScheme:de,modeStorageKey:g,colorSchemeStorageKey:S,defaultMode:oe,storageManager:E,storageWindow:R,noSsr:U}),Ne=le,et=xe;X&&(Ne=Z.mode,et=Z.colorScheme);let Qt=et||ie.defaultColorScheme;ie.vars&&!M&&(Qt=ie.defaultColorScheme);let rt=kt.useMemo(()=>{let nt=ie.generateThemeVars?.()||ie.varLine truncated
} catch(e){}})();`}},"mui-color-scheme-init")}var kt=C(B(),1);function jw(){}var Uw=({key:e,storageWindow:t})=>(!t&&typeof window<"u"&&(t=window),{get(o){if(typeof window>"u")return;if(!t)return o;let r;try{r=t.localStorage.getItem(e)}catch{}return r||o},set:o=>{if(t)try{t.localStorage.setItem(e,o)}catch{}},subscribe:o=>{if(!t)return jw;let r=n=>{let a=n.newValue;n.key===e&&o(a)};return t.addEventListener("storage",r),()=>{t.removeEventListener("storage",r)}}}),Ix=Uw;function dh(){}function Vx(e){if(typeof window<"u"&&typeof window.matchMedia=="function"&&e==="system")return window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"}function Hx(e,t){if(e.mode==="light"||e.mode==="system"&&e.systemMode==="light")return t("light");if(e.mode==="dark"||e.mode==="system"&&e.systemMode==="dark")return t("dark")}function Bw(e){return Hx(e,t=>{if(t==="light")return e.lightColorScheme;if(t==="dark")return e.darkColorScheme})}function mh(e){let{defaultMode:t="light",defaultLightColorScheme:o,defaultDarkColorScheme:r,supportedColorSchemes:n=[],modeStorageKey:a=gp,colorSchemeStorageKey:i=Tp,storageWindow:s=typeof window>"u"?void 0:window,storageManager:l=Ix,noSsr:p=!1}=e,f=n.join(","),d=n.length>1,c=kt.useMemo(()=>l?.({key:a,storageWindow:s}),[l,a,s]),u=kt.useMemo(()=>l?.({key:`${i}-light`,storageWindow:s}),[l,i,s]),b=kt.useMemo(()=>l?.({key:`${i}-dark`,storageWindow:s}),[l,i,s]),[v,x]=kt.useState(()=>{let R=c?.get(t)||t,N=u?.get(o)||o,O=b?.get(r)||r;return{mode:R,systemMode:Vx(R),lightColorScheme:N,darkColorScheme:O}}),[m,h]=kt.useState(p||!d);kt.useEffect(()=>{h(!0)},[]);let y=Bw(v),g=kt.useCallback(R=>{x(N=>{if(R===N.mode)return N;let O=R??t;return c?.set(O),{...N,mode:O,systemMode:Vx(O)}})},[c,t]),S=kt.useCallback(R=>{R?typeof R=="string"?R&&!f.includes(R)?console.error(`\`${R}\` does not exist in \`theme.colorSchemes\`.`):x(N=>{let O={...N};return Hx(N,D=>{D==="light"&&(u?.set(R),O.lightColorScheme=R),D==="dark"&&(b?.set(R),O.darkColorScheme=R)}),O}):x(N=>{let O={...N},D=R.light===null?o:R.light,T=R.dark===null?r:R.dark;return D&&(f.includes(D)?(O.lightColorScheme=D,u?.set(D)):console.error(`\`${D}\` does not exist in \`theme.colorSchemes\`.`)),T&&(f.includes(T)?(O.darkColorScheme=T,b?.set(T)):console.error(`\`${T}\` does not exist in \`theme.colorSchemes\`.`)),O}):x(N=>(u?.set(o),b?.set(r),{...N,lightColorScheme:o,darkColorScheme:r}))},[f,u,b,o,r]),P=kt.useCallback(R=>{v.mode==="system"&&x(N=>{let O=R?.matches?"dark":"light";return N.systemMode===O?N:{...N,systemMode:O}})},[v.mode]),E=kt.useRef(P);return E.current=P,kt.useEffect(()=>{if(typeof window.matchMedia!="function"||!d)return;let R=(...O)=>E.current(...O),N=window.matchMedia("(prefers-color-scheme: dark)");return N.addListener(R),R(N),()=>{N.removeListener(R)}},[d]),kt.useEffect(()=>{if(d){let R=c?.subscribe(D=>{(!D||["light","dark","system"].includes(D))&&g(D||t)})||dh,N=u?.subscribe(D=>{(!D||f.match(D))&&S({light:D})})||dh,O=b?.subscribe(D=>{(!D||f.match(D))&&S({dark:D})})||dh;return()=>{R(),N(),O()}}},[S,g,f,t,s,d,c,u,b]),{...v,mode:m?v.mode:void 0,systemMode:m?v.systemMode:void 0,colorScheme:m?y:void 0,setMode:g,setColorScheme:S}}var Ps=C(k(),1),Lw="*{-webkit-transition:none!important;-moz-transition:none!important;-o-transition:none!important;-ms-transition:none!important;transition:none!important}";function yf(e){let{themeId:t,theme:o={},modeStorageKey:r=gp,colorSchemeStorageKey:n=Tp,disableTransitionOnChange:a=!1,defaultColorScheme:i,resolveTheme:s}=e,l={allColorSchemes:[],colorScheme:void 0,darkColorScheme:void 0,lightColorScheme:void 0,mode:void 0,setColorScheme:()=>{},setMode:()=>{},systemMode:void 0},p=It.createContext(void 0),f=()=>It.useContext(p)||l,d={},c={};function u(m){let{children:h,theme:y,modeStorageKey:g=r,colorSchemeStorageKey:S=n,disableTransitionOnChange:P=a,storageManager:E,storageWindow:R=typeof window>"u"?void 0:window,documentNode:N=typeof document>"u"?void 0:document,colorSchemeNode:O=typeof document>"u"?void 0:document.documentElement,disableNestedContext:D=!1,disableStyleSheetGeneration:T=!1,defaultMode:A="system",forceThemeRerender:M=!1,noSsr:U}=m,L=It.useRef(!1),G=un(),J=It.useContext(p),K=!!J&&!D,he=It.useMemo(()=>y||(typeof o=="function"?o():o),[y]),re=he[t],se=re||he,{colorSchemes:ie=d,components:Xe=c,cssVarPrefix:Ne}=se,Ce=Object.keys(ie).filter(nt=>!!ie[nt]).join(","),me=It.useMemo(()=>Ce.split(","),[Ce]),ot=typeof i=="string"?i:i.light,ge=typeof i=="string"?i:i.dark,oe=ie[ot]&&ie[ge]?A:ie[se.defaultColorScheme]?.palette?.mode||se.palette?.mode,{mode:X,setMode:Q,systemMode:Ee,lightColorScheme:Y,darkColorScheme:ce,colorScheme:we,setColorScheme:Te}=mh({supportedColorSchemes:me,defaultLightColorScheme:ot,defaultDarkColorScheme:ge,modeStorageKey:g,colorSchemeStorageKey:S,defaultMode:oe,storageManager:E,storageWindow:R,noSsr:U}),Ae=X,et=we;K&&(Ae=J.mode,et=J.colorScheme);let Qt=et||se.defaultColorScheme;se.vars&&!M&&(Qt=se.defaultColorScheme);let rt=It.useMemo(()=>{let nt=se.generateThemeVars?.()||se.vars,HLine truncated
const theme = ${JSON.stringify(t,null,2)};
theme.breakpoints = createBreakpoints(theme.breakpoints || {});
theme.transitions = createTransitions(theme.transitions || {});
export default theme;`}function t1(e){return typeof e=="number"?`${(e*100).toFixed(0)}%`:`calc((${e}) * 100%)`}var lA=e=>{if(!Number.isNaN(+e))return+e;let t=e.match(/\d*\.?\d+/g);if(!t)return 0;let o=0;for(let r=0;r<t.length;r+=1)o+=+t[r];return o};function pA(e){Object.assign(e,{alpha(t,o){let r=this||e;return r.colorSpace?`oklch(from ${t} l c h / ${typeof o=="string"?`calc(${o})`:o})`:r.vars?`rgba(${t.replace(/var\(--([^,\s)]+)(?:,[^)]+)?\)+/g,"var(--$1Channel)")} / ${typeof o=="string"?`calc(${o})`:o})`:$n(t,lA(o))},lighten(t,o){let r=this||e;return r.colorSpace?`color-mix(in ${r.colorSpace}, ${t}, #fff ${t1(o)})`:gs(t,o)},darken(t,o){let r=this||e;return r.colorSpace?`color-mix(in ${r.colorSpace}, ${t}, #000 ${t1(o)})`:hs(t,o)}})}function uA(e={},...t){let{breakpoints:o,mixins:r={},spacing:n,palette:a={},transitions:i={},typography:s={},shape:l,colorSpace:p,...f}=e;if(e.vars&&e.generateThemeVars===void 0)throw new Error(Ot(20));let d=Za({...a,colorSpace:p}),c=vr(e),u=Pe(c,{mixins:hh(c.breakpoints,r),palette:d,shadows:Wx.slice(),typography:yp(d,s),transitions:Th(i),zIndex:{...e1}});return u=Pe(u,f),u=t.reduce((b,v)=>Pe(b,v),u),u.unstable_sxConfig={...br,...f?.unstable_sxConfig},u.unstable_sx=function(v){return To({sx:v,theme:this})},u.toRuntimeSource=Tf,pA(u),u}var hp=uA;function Ss(e){let t;return e<1?t=5.11916*e**2:t=4.5*Math.log(e+1)+2,Math.round(t*10)/1e3}var cA=[...Array(25)].map((e,t)=>{if(t===0)return"none";let o=Ss(t);return`linear-gradient(rgba(255 255 255 / ${o}), rgba(255 255 255 / ${o}))`});function bh(e){return{inputPlaceholder:e==="dark"?.5:.42,inputUnderline:e==="dark"?.7:.42,switchTrackDisabled:e==="dark"?.2:.12,switchTrack:e==="dark"?.3:.38}}function vh(e){return e==="dark"?cA:[]}function xh(e){let{palette:t={mode:"light"},opacity:o,overlays:r,colorSpace:n,...a}=e,i=Za({...t,colorSpace:n});return{palette:i,opacity:{...bh(i.mode),...o},overlays:r||vh(i.mode),...a}}function Sh(e){return!!e[0].match(/(cssVarPrefix|colorSchemeSelector|modularCssLayers|rootSelector|typography|mixins|breakpoints|direction|transitions)/)||!!e[0].match(/sxConfig$/)||e[0]==="palette"&&!!e[1]?.match(/(mode|contrastThreshold|tonalOffset)/)}var fA=e=>[...[...Array(25)].map((t,o)=>`--${e?`${e}-`:""}overlays-${o}`),`--${e?`${e}-`:""}palette-AppBar-darkBg`,`--${e?`${e}-`:""}palette-AppBar-darkColor`],o1=fA;var r1=e=>(t,o)=>{let r=e.rootSelector||":root",n=e.colorSchemeSelector,a=n;if(n==="class"&&(a=".%s"),n==="data"&&(a="[data-%s]"),n?.startsWith("data-")&&!n.includes("%s")&&(a=`[${n}="%s"]`),e.defaultColorScheme===t){if(t==="dark"){let i={};return o1(e.cssVarPrefix).forEach(s=>{i[s]=o[s],delete o[s]}),a==="media"?{[r]:o,"@media (prefers-color-scheme: dark)":{[r]:i}}:a?{[a.replace("%s",t)]:i,[`${r}, ${a.replace("%s",t)}`]:o}:{[r]:{...o,...i}}}if(a&&a!=="media")return`${r}, ${a.replace("%s",String(t))}`}else if(t){if(a==="media")return{[`@media (prefers-color-scheme: ${String(t)})`]:{[r]:o}};if(a)return a.replace("%s",String(t))}return r};function dA(e,t){t.forEach(o=>{e[o]||(e[o]={})})}function _(e,t,o){!e[t]&&o&&(e[t]=o)}function gp(e){return typeof e!="string"||!e.startsWith("hsl")?e:ih(e)}function ln(e,t){`${t}Channel`in e||(e[`${t}Channel`]=ys(gp(e[t]),`MUI: Can't create \`palette.${t}Channel\` because \`palette.${t}\` is not one of these formats: #nnn, #nnnnnn, rgb(), rgba(), hsl(), hsla(), color().
To suppress this warning, you need to explicitly provide the \`palette.${t}Channel\` as a string (in rgb format, for example "12 12 12") or undefined if you want to remove the channel token.`))}function mA(e){return typeof e=="number"?`${e}px`:typeof e=="string"||typeof e=="function"||Array.isArray(e)?e:"8px"}var jr=e=>{try{return e()}catch{}},yA=(e="mui")=>ff(e);function Ph(e,t,o,r,n){if(!o)return;o=o===!0?{}:o;let a=n==="dark"?"dark":"light";if(!r){t[n]=xh({...o,palette:{mode:a,...o?.palette},colorSpace:e});return}let{palette:i,...s}=hp({...r,palette:{mode:a,...o?.palette},colorSpace:e});return t[n]={...o,palette:i,opacity:{...bh(a),...o?.opacity},overlays:o?.overlays||vh(a)},s}function Ch(e={},...t){let{colorSchemes:o={light:!0},defaultColorScheme:r,disableCssColorScheme:n=!1,cssVarPrefix:a="mui",nativeColor:i=!1,shouldSkipGeneratingVar:s=Sh,colorSchemeSelector:l=o.light&&o.dark?"media":void 0,rootSelector:p=":root",...f}=e,d=Object.keys(o)[0],c=r||(o.light&&d!=="light"?"light":d),u=yA(a),{[c]:b,light:v,dark:x,...m}=o,h={...m},y=b;if((c==="dark"&&!("dark"in o)||c==="light"&&!("light"in o))&&(y=!0),!y)throw new Error(Ot(21,c));let g;i&&(g="oklch");let S=Ph(g,h,y,f,c);v&&!h.light&&Ph(g,h,v,void 0,"light"),x&&!h.dark&&Ph(g,h,x,void 0,"dark");let P={defaultColorScheme:c,...S,cssVarPrefix:a,colorSchemeSelector:l,rootSelector:p,getCssVar:u,colorSchemes:h,font:{...gf(S.typography),...S.font},spacing:mA(f.spacing)};Object.keys(P.colorSchemes).forEach(D=>{let T=P.colorSchemes[D].palette,A=U=>{let k=U.split("-"),Y=k[1],Z=k[2];return u(U,T[Y][Z])};T.mode==="light"&&(_(T.common,"background","#fff"),_(T.common,"onBackground","#000")),T.mode==="dark"&&(_(T.common,"background","#000"),_(T.common,"onBackground","#fff"));function M(U,k,Y){if(g){let Z;return U===qn&&(Z=`transparent ${((1-Y)*100).toFixed(0)}%`),U===Ae&&(Z=`#000 ${(Y*100).toFixed(0)}%`),U===Me&&(Z=`#fff ${(Y*100).toFixed(0)}%`),`color-mix(in ${g}, ${k}, ${Z})`}return U(k,Y)}if(dA(T,["Alert","AppBar","Avatar","Button","Chip","FilledInput","LinearProgress","Skeleton","Slider","SnackbarContent","SpeedDialAction","StepConnector","StepContent","Switch","TableCell","Tooltip"]),T.mode==="light"){_(T.Alert,"errorColor",M(Ae,i?u("palette-error-light"):T.error.light,.6)),_(T.Alert,"infoColor",M(Ae,i?u("palette-info-light"):T.info.light,.6)),_(T.Alert,"successColor",M(Ae,i?u("palette-success-light"):T.success.light,.6)),_(T.Alert,"warningColor",M(Ae,i?u("palette-warning-light"):T.warning.light,.6)),_(T.Alert,"errorFilledBg",A("palette-error-main")),_(T.Alert,"infoFilledBg",A("palette-info-main")),_(T.Alert,"successFilledBg",A("palette-success-main")),_(T.Alert,"warningFilledBg",A("palette-warning-main")),_(T.Alert,"errorFilledColor",jr(()=>T.getContrastText(T.error.main))),_(T.Alert,"infoFilledColor",jr(()=>T.getContrastText(T.info.main))),_(T.Alert,"successFilledColor",jr(()=>T.getContrastText(T.success.main))),_(T.Alert,"warningFilledColor",jr(()=>T.getContrastText(T.warning.main))),_(T.Alert,"errorStandardBg",M(Me,i?u("palette-error-light"):T.error.light,.9)),_(T.Alert,"infoStandardBg",M(Me,i?u("palette-info-light"):T.info.light,.9)),_(T.Alert,"successStandardBg",M(Me,i?u("palette-success-light"):T.success.light,.9)),_(T.Alert,"warningStandardBg",M(Me,i?u("palette-warning-light"):T.warning.light,.9)),_(T.Alert,"errorIconColor",A("palette-error-main")),_(T.Alert,"infoIconColor",A("palette-info-main")),_(T.Alert,"successIconColor",A("palette-success-main")),_(T.Alert,"warningIconColor",A("palette-warning-main")),_(T.AppBar,"defaultBg",A("palette-grey-100")),_(T.Avatar,"defaultBg",A("palette-grey-400")),_(T.Button,"inheritContainedBg",A("palette-grey-300")),_(T.Button,"inheritContainedHoverBg",A("palette-grey-A100")),_(T.Chip,"defaultBorder",A("palette-grey-400")),_(T.Chip,"defaultAvatarColor",A("palette-grey-700")),_(T.Chip,"defaultIconColor",A("palette-grey-700")),_(T.FilledInput,"bg","rgba(0, 0, 0, 0.06)"),_(T.FilledInput,"hoverBg","rgba(0, 0, 0, 0.09)"),_(T.FilledInput,"disabledBg","rgba(0, 0, 0, 0.12)"),_(T.LinearProgress,"primaryBg",M(Me,i?u("palette-primary-main"):T.primary.main,.62)),_(T.LinearProgress,"secondaryBg",M(Me,i?u("palette-secondary-main"):T.secondary.main,.62)),_(T.LinearProgress,"errorBg",M(Me,i?u("palette-error-main"):T.error.main,.62)),_(T.LinearProgress,"infoBg",M(Me,i?u("palette-info-main"):T.info.main,.62)),_(T.LinearProgress,"successBg",M(Me,i?u("palette-success-main"):T.success.main,.62)),_(T.LinearProgress,"warningBg",M(Me,i?u("palette-warning-light"):T.warning.main,.62)),_(T.Skeleton,"bg",g?M(qn,i?u("palette-text-primary"):T.text.primary,.11):`rgba(${A("palette-text-primaryChannel")} / 0.11)`),_(T.Slider,"primaryTrack",M(Me,i?u("palette-primary-main"):T.primary.main,.62)),_(T.Slider,"secondaryTrack",M(Me,i?u("palette-secondary-main"):T.secondary.main,.62)),_(T.Slider,"errorTrack",M(Me,i?u("palette-error-main"):T.error.main,.62)),_(T.Slider,"infoTrack",M(Me,i?u("palette-info-main"):T.info.main,.62)),_(T.Slider,"successTrack",M(Me,i?u("palLine truncated
export default theme;`}function r1(e){return typeof e=="number"?`${(e*100).toFixed(0)}%`:`calc((${e}) * 100%)`}var cA=e=>{if(!Number.isNaN(+e))return+e;let t=e.match(/\d*\.?\d+/g);if(!t)return 0;let o=0;for(let r=0;r<t.length;r+=1)o+=+t[r];return o};function fA(e){Object.assign(e,{alpha(t,o){let r=this||e;return r.colorSpace?`oklch(from ${t} l c h / ${typeof o=="string"?`calc(${o})`:o})`:r.vars?`rgba(${t.replace(/var\(--([^,\s)]+)(?:,[^)]+)?\)+/g,"var(--$1Channel)")} / ${typeof o=="string"?`calc(${o})`:o})`:Yn(t,cA(o))},lighten(t,o){let r=this||e;return r.colorSpace?`color-mix(in ${r.colorSpace}, ${t}, #fff ${r1(o)})`:vs(t,o)},darken(t,o){let r=this||e;return r.colorSpace?`color-mix(in ${r.colorSpace}, ${t}, #000 ${r1(o)})`:bs(t,o)}})}function dA(e={},...t){let{breakpoints:o,mixins:r={},spacing:n,palette:a={},transitions:i={},typography:s={},shape:l,colorSpace:p,...f}=e;if(e.vars&&e.generateThemeVars===void 0)throw new Error(Nt(20));let d=ei({...a,colorSpace:p}),c=Sr(e),u=Se(c,{mixins:Th(c.breakpoints,r),palette:d,shadows:e1.slice(),typography:vp(d,s),transitions:vh(i),zIndex:{...o1}});return u=Se(u,f),u=t.reduce((b,v)=>Se(b,v),u),u.unstable_sxConfig={...xr,...f?.unstable_sxConfig},u.unstable_sx=function(v){return vo({sx:v,theme:this})},u.toRuntimeSource=Sf,fA(u),u}var xp=dA;function Es(e){let t;return e<1?t=5.11916*e**2:t=4.5*Math.log(e+1)+2,Math.round(t*10)/1e3}var mA=[...Array(25)].map((e,t)=>{if(t===0)return"none";let o=Es(t);return`linear-gradient(rgba(255 255 255 / ${o}), rgba(255 255 255 / ${o}))`});function xh(e){return{inputPlaceholder:e==="dark"?.5:.42,inputUnderline:e==="dark"?.7:.42,switchTrackDisabled:e==="dark"?.2:.12,switchTrack:e==="dark"?.3:.38}}function Sh(e){return e==="dark"?mA:[]}function Ph(e){let{palette:t={mode:"light"},opacity:o,overlays:r,colorSpace:n,...a}=e,i=ei({...t,colorSpace:n});return{palette:i,opacity:{...xh(i.mode),...o},overlays:r||Sh(i.mode),...a}}function Ch(e){return!!e[0].match(/(cssVarPrefix|colorSchemeSelector|modularCssLayers|rootSelector|typography|mixins|breakpoints|direction|transitions)/)||!!e[0].match(/sxConfig$/)||e[0]==="palette"&&!!e[1]?.match(/(mode|contrastThreshold|tonalOffset)/)}var yA=e=>[...[...Array(25)].map((t,o)=>`--${e?`${e}-`:""}overlays-${o}`),`--${e?`${e}-`:""}palette-AppBar-darkBg`,`--${e?`${e}-`:""}palette-AppBar-darkColor`],n1=yA;var a1=e=>(t,o)=>{let r=e.rootSelector||":root",n=e.colorSchemeSelector,a=n;if(n==="class"&&(a=".%s"),n==="data"&&(a="[data-%s]"),n?.startsWith("data-")&&!n.includes("%s")&&(a=`[${n}="%s"]`),e.defaultColorScheme===t){if(t==="dark"){let i={};return n1(e.cssVarPrefix).forEach(s=>{i[s]=o[s],delete o[s]}),a==="media"?{[r]:o,"@media (prefers-color-scheme: dark)":{[r]:i}}:a?{[a.replace("%s",t)]:i,[`${r}, ${a.replace("%s",t)}`]:o}:{[r]:{...o,...i}}}if(a&&a!=="media")return`${r}, ${a.replace("%s",String(t))}`}else if(t){if(a==="media")return{[`@media (prefers-color-scheme: ${String(t)})`]:{[r]:o}};if(a)return a.replace("%s",String(t))}return r};function hA(e,t){t.forEach(o=>{e[o]||(e[o]={})})}function _(e,t,o){!e[t]&&o&&(e[t]=o)}function Sp(e){return typeof e!="string"||!e.startsWith("hsl")?e:lh(e)}function cn(e,t){`${t}Channel`in e||(e[`${t}Channel`]=Ts(Sp(e[t]),`MUI: Can't create \`palette.${t}Channel\` because \`palette.${t}\` is not one of these formats: #nnn, #nnnnnn, rgb(), rgba(), hsl(), hsla(), color().
To suppress this warning, you need to explicitly provide the \`palette.${t}Channel\` as a string (in rgb format, for example "12 12 12") or undefined if you want to remove the channel token.`))}function gA(e){return typeof e=="number"?`${e}px`:typeof e=="string"||typeof e=="function"||Array.isArray(e)?e:"8px"}var Br=e=>{try{return e()}catch{}},TA=(e="mui")=>hf(e);function Eh(e,t,o,r,n){if(!o)return;o=o===!0?{}:o;let a=n==="dark"?"dark":"light";if(!r){t[n]=Ph({...o,palette:{mode:a,...o?.palette},colorSpace:e});return}let{palette:i,...s}=xp({...r,palette:{mode:a,...o?.palette},colorSpace:e});return t[n]={...o,palette:i,opacity:{...xh(a),...o?.opacity},overlays:o?.overlays||Sh(a)},s}function Rh(e={},...t){let{colorSchemes:o={light:!0},defaultColorScheme:r,disableCssColorScheme:n=!1,cssVarPrefix:a="mui",nativeColor:i=!1,shouldSkipGeneratingVar:s=Ch,colorSchemeSelector:l=o.light&&o.dark?"media":void 0,rootSelector:p=":root",...f}=e,d=Object.keys(o)[0],c=r||(o.light&&d!=="light"?"light":d),u=TA(a),{[c]:b,light:v,dark:x,...m}=o,h={...m},y=b;if((c==="dark"&&!("dark"in o)||c==="light"&&!("light"in o))&&(y=!0),!y)throw new Error(Nt(21,c));let g;i&&(g="oklch");let S=Eh(g,h,y,f,c);v&&!h.light&&Eh(g,h,v,void 0,"light"),x&&!h.dark&&Eh(g,h,x,void 0,"dark");let P={defaultColorScheme:c,...S,cssVarPrefix:a,colorSchemeSelector:l,rootSelector:p,getCssVar:u,colorSchemes:h,font:{...xf(S.typography),...S.font},spacing:gA(f.spacing)};Object.keys(P.colorSchemes).forEach(D=>{let T=P.colorSchemes[D].palette,A=U=>{let L=U.split("-"),G=L[1],J=L[2];return u(U,T[G][J])};T.mode==="light"&&(_(T.common,"background","#fff"),_(T.common,"onBackground","#000")),T.mode==="dark"&&(_(T.common,"background","#000"),_(T.common,"onBackground","#fff"));function M(U,L,G){if(g){let J;return U===Xn&&(J=`transparent ${((1-G)*100).toFixed(0)}%`),U===_e&&(J=`#000 ${(G*100).toFixed(0)}%`),U===De&&(J=`#fff ${(G*100).toFixed(0)}%`),`color-mix(in ${g}, ${L}, ${J})`}return U(L,G)}if(hA(T,["Alert","AppBar","Avatar","Button","Chip","FilledInput","LinearProgress","Skeleton","Slider","SnackbarContent","SpeedDialAction","StepConnector","StepContent","Switch","TableCell","Tooltip"]),T.mode==="light"){_(T.Alert,"errorColor",M(_e,i?u("palette-error-light"):T.error.light,.6)),_(T.Alert,"infoColor",M(_e,i?u("palette-info-light"):T.info.light,.6)),_(T.Alert,"successColor",M(_e,i?u("palette-success-light"):T.success.light,.6)),_(T.Alert,"warningColor",M(_e,i?u("palette-warning-light"):T.warning.light,.6)),_(T.Alert,"errorFilledBg",A("palette-error-main")),_(T.Alert,"infoFilledBg",A("palette-info-main")),_(T.Alert,"successFilledBg",A("palette-success-main")),_(T.Alert,"warningFilledBg",A("palette-warning-main")),_(T.Alert,"errorFilledColor",Br(()=>T.getContrastText(T.error.main))),_(T.Alert,"infoFilledColor",Br(()=>T.getContrastText(T.info.main))),_(T.Alert,"successFilledColor",Br(()=>T.getContrastText(T.success.main))),_(T.Alert,"warningFilledColor",Br(()=>T.getContrastText(T.warning.main))),_(T.Alert,"errorStandardBg",M(De,i?u("palette-error-light"):T.error.light,.9)),_(T.Alert,"infoStandardBg",M(De,i?u("palette-info-light"):T.info.light,.9)),_(T.Alert,"successStandardBg",M(De,i?u("palette-success-light"):T.success.light,.9)),_(T.Alert,"warningStandardBg",M(De,i?u("palette-warning-light"):T.warning.light,.9)),_(T.Alert,"errorIconColor",A("palette-error-main")),_(T.Alert,"infoIconColor",A("palette-info-main")),_(T.Alert,"successIconColor",A("palette-success-main")),_(T.Alert,"warningIconColor",A("palette-warning-main")),_(T.AppBar,"defaultBg",A("palette-grey-100")),_(T.Avatar,"defaultBg",A("palette-grey-400")),_(T.Button,"inheritContainedBg",A("palette-grey-300")),_(T.Button,"inheritContainedHoverBg",A("palette-grey-A100")),_(T.Chip,"defaultBorder",A("palette-grey-400")),_(T.Chip,"defaultAvatarColor",A("palette-grey-700")),_(T.Chip,"defaultIconColor",A("palette-grey-700")),_(T.FilledInput,"bg","rgba(0, 0, 0, 0.06)"),_(T.FilledInput,"hoverBg","rgba(0, 0, 0, 0.09)"),_(T.FilledInput,"disabledBg","rgba(0, 0, 0, 0.12)"),_(T.LinearProgress,"primaryBg",M(De,i?u("palette-primary-main"):T.primary.main,.62)),_(T.LinearProgress,"secondaryBg",M(De,i?u("palette-secondary-main"):T.secondary.main,.62)),_(T.LinearProgress,"errorBg",M(De,i?u("palette-error-main"):T.error.main,.62)),_(T.LinearProgress,"infoBg",M(De,i?u("palette-info-main"):T.info.main,.62)),_(T.LinearProgress,"successBg",M(De,i?u("palette-success-main"):T.success.main,.62)),_(T.LinearProgress,"warningBg",M(De,i?u("palette-warning-light"):T.warning.main,.62)),_(T.Skeleton,"bg",g?M(Xn,i?u("palette-text-primary"):T.text.primary,.11):`rgba(${A("palette-text-primaryChannel")} / 0.11)`),_(T.Slider,"primaryTrack",M(De,i?u("palette-primary-main"):T.primary.main,.62)),_(T.Slider,"secondaryTrack",M(De,i?u("palette-secondary-main"):T.secondary.main,.62)),_(T.Slider,"errorTrack",M(De,i?u("palette-error-main"):T.error.main,.62)),_(T.Slider,"infoTrack",M(De,i?u("palette-info-main"):T.info.main,.62)),_(T.Slider,"successTrack",M(De,i?u("palLine truncated
0% {
transform: scale(0);
opacity: 0.1;
@@ -51,7 +51,7 @@ To suppress this warning, you need to explicitly provide the \`palette.${t}Chann
transform: scale(1);
opacity: 0.3;
}
`,dM=ho`
`,hM=To`
0% {
opacity: 1;
}
@@ -59,7 +59,7 @@ To suppress this warning, you need to explicitly provide the \`palette.${t}Chann
100% {
opacity: 0;
}
`,mM=ho`
`,gM=To`
0% {
transform: scale(1);
}
@@ -71,23 +71,23 @@ To suppress this warning, you need to explicitly provide the \`palette.${t}Chann
100% {
transform: scale(1);
}
`,yM=w("span",{name:"MuiTouchRipple",slot:"Root"})({overflow:"hidden",pointerEvents:"none",position:"absolute",zIndex:0,top:0,right:0,bottom:0,left:0,borderRadius:"inherit"}),hM=w(L1,{name:"MuiTouchRipple",slot:"Ripple"})`
`,TM=w("span",{name:"MuiTouchRipple",slot:"Root"})({overflow:"hidden",pointerEvents:"none",position:"absolute",zIndex:0,top:0,right:0,bottom:0,left:0,borderRadius:"inherit"}),bM=w(I1,{name:"MuiTouchRipple",slot:"Ripple"})`
opacity: 0;
position: absolute;
&.${Do.rippleVisible} {
&.${jo.rippleVisible} {
opacity: 0.3;
transform: scale(1);
animation-name: ${fM};
animation-duration: ${kh}ms;
animation-name: ${yM};
animation-duration: ${Vh}ms;
animation-timing-function: ${({theme:e})=>e.transitions.easing.easeInOut};
}
&.${Do.ripplePulsate} {
&.${jo.ripplePulsate} {
animation-duration: ${({theme:e})=>e.transitions.duration.shorter}ms;
}
& .${Do.child} {
& .${jo.child} {
opacity: 1;
display: block;
width: 100%;
@@ -96,25 +96,25 @@ To suppress this warning, you need to explicitly provide the \`palette.${t}Chann
background-color: currentColor;
}
& .${Do.childLeaving} {
& .${jo.childLeaving} {
opacity: 0;
animation-name: ${dM};
animation-duration: ${kh}ms;
animation-name: ${hM};
animation-duration: ${Vh}ms;
animation-timing-function: ${({theme:e})=>e.transitions.easing.easeInOut};
}
& .${Do.childPulsate} {
& .${jo.childPulsate} {
position: absolute;
/* @noflip */
left: 0px;
top: 0;
animation-name: ${mM};
animation-name: ${gM};
animation-duration: 2500ms;
animation-timing-function: ${({theme:e})=>e.transitions.easing.easeInOut};
animation-iteration-count: infinite;
animation-delay: 200ms;
}
`,gM=Pt.forwardRef(function(t,o){let r=F({props:t,name:"MuiTouchRipple"}),{center:n=!1,classes:a={},className:i,...s}=r,[l,p]=Pt.useState([]),f=Pt.useRef(0),d=Pt.useRef(null);Pt.useEffect(()=>{d.current&&(d.current(),d.current=null)},[l]);let c=Pt.useRef(!1),u=Xn(),b=Pt.useRef(null),v=Pt.useRef(null),x=Pt.useCallback(g=>{let{pulsate:S,rippleX:P,rippleY:E,rippleSize:R,cb:N}=g;p(O=>[...O,(0,Hf.jsx)(hM,{classes:{ripple:j(a.ripple,Do.ripple),rippleVisible:j(a.rippleVisible,Do.rippleVisible),ripplePulsate:j(a.ripplePulsate,Do.ripplePulsate),child:j(a.child,Do.child),childLeaving:j(a.childLeaving,Do.childLeaving),childPulsate:j(a.childPulsate,Do.childPulsate)},timeout:kh,pulsate:S,rippleX:P,rippleY:E,rippleSize:R},f.current)]),f.current+=1,d.current=N},[a]),m=Pt.useCallback((g={},S={},P=()=>{})=>{let{pulsate:E=!1,center:R=n||S.pulsate,fakeElement:N=!1}=S;if(g?.type==="mousedown"&&c.current){c.current=!1;return}g?.type==="touchstart"&&(c.current=!0);let O=N?null:v.current,D=O?O.getBoundingClientRect():{width:0,height:0,left:0,top:0},T,A,M;if(R||g===void 0||g.clientX===0&&g.clientY===0||!g.clientX&&!g.touches)T=Math.round(D.width/2),A=Math.round(D.height/2);else{let{clientX:U,clientY:k}=g.touches&&g.touches.length>0?g.touches[0]:g;T=Math.round(U-D.left),A=Math.round(k-D.top)}if(R)M=Math.sqrt((2*D.width**2+D.height**2)/3),M%2===0&&(M+=1);else{let U=Math.max(Math.abs((O?O.clientWidth:0)-T),T)*2+2,k=Math.max(Math.abs((O?O.clientHeight:0)-A),A)*2+2;M=Math.sqrt(U**2+k**2)}g?.touches?b.current===null&&(b.current=()=>{x({pulsate:E,rippleX:T,rippleY:A,rippleSize:M,cb:P})},u.start(cM,()=>{b.current&&(b.current(),b.current=null)})):x({pulsate:E,rippleX:T,rippleY:A,rippleSize:M,cb:P})},[n,x,u]),h=Pt.useCallback(()=>{m({},{pulsate:!0})},[m]),y=Pt.useCallback((g,S)=>{if(u.clear(),g?.type==="touchend"&&b.current){b.current(),b.current=null,u.start(0,()=>{y(g,S)});return}b.current=null,p(P=>P.length>0?P.slice(1):P),d.current=S},[u]);return Pt.useImperativeHandle(o,()=>({pulsate:h,start:m,stop:y}),[h,m,y]),(0,Hf.jsx)(yM,{className:j(Do.root,a.root,i),ref:v,...s,children:(0,Hf.jsx)(_h,{component:null,exit:!0,children:l})})}),k1=gM;function I1(e){return V("MuiButtonBase",e)}var TM=$("MuiButtonBase",["root","disabled","focusVisible"]),V1=TM;var Ff=C(I(),1),bM=e=>{let{disabled:t,focusVisible:o,focusVisibleClassName:r,classes:n}=e,i=H({root:["root",t&&"disabled",o&&"focusVisible"]},I1,n);return o&&r&&(i.root+=` ${r}`),i},vM=w("button",{name:"MuiButtonBase",slot:"Root"})({display:"inline-flex",alignItems:"center",justifyContent:"center",position:"relative",boxSizing:"border-box",WebkitTapHighlightColor:"transparent",backgroundColor:"transparent",outline:0,border:0,margin:0,borderRadius:0,padding:0,cursor:"pointer",userSelect:"none",verticalAlign:"middle",MozAppearance:"none",WebkitAppearance:"none",textDecoration:"none",color:"inherit","&::-moz-focus-inner":{borderStyle:"none"},[`&.${V1.disabled}`]:{pointerEvents:"none",cursor:"default"},"@media print":{colorAdjust:"exact"}}),xM=Br.forwardRef(function(t,o){let r=F({props:t,name:"MuiButtonBase"}),{action:n,centerRipple:a=!1,children:i,className:s,component:l="button",disabled:p=!1,disableRipple:f=!1,disableTouchRipple:d=!1,focusRipple:c=!1,focusVisibleClassName:u,LinkComponent:b="a",onBlur:v,onClick:x,onContextMenu:m,onDragLeave:h,onFocus:y,onFocusVisible:g,onKeyDown:S,onKeyUp:P,onMouseDown:E,onMouseLeave:R,onMouseUp:N,onTouchEnd:O,onTouchMove:D,onTouchStart:T,tabIndex:A=0,TouchRippleProps:M,touchRippleRef:U,type:k,...Y}=r,Z=Br.useRef(null),X=If(),Te=Tt(X.ref,U),[te,ie]=Br.useState(!1);p&&te&&ie(!1),Br.useImperativeHandle(n,()=>({focusVisible:()=>{ie(!0),Z.current.focus()}}),[]);let ne=X.shouldMount&&!f&&!p;Br.useEffect(()=>{te&&c&&!f&&X.pulsate()},[f,c,te,X]);let Je=dn(X,"start",E,d),Oe=dn(X,"stop",m,d),ze=dn(X,"stop",h,d),fe=dn(X,"stop",N,d),ot=dn(X,"stop",W=>{te&&W.preventDefault(),R&&R(W)},d),de=dn(X,"start",T,d),oe=dn(X,"stop",O,d),le=dn(X,"stop",D,d),be=dn(X,"stop",W=>{Qn(W.target)||ie(!1),v&&v(W)},!1),ee=Cp(W=>{Z.current||(Z.current=W.currentTarget),Qn(W.target)&&(ie(!0),g&&g(W)),y&&y(W)}),B=()=>{let W=Z.current;return W?W.tagName==="BUTTON"?!1:!(W.tagName==="A"&&W.href):l&&l!=="button"},se=Cp(W=>{c&&!W.repeat&&te&&W.key===" "&&X.stop(W,()=>{X.start(W)}),W.target===W.currentTarget&&B()&&W.key===" "&&W.preventDefault(),S&&S(W),W.target===W.currentTarget&&B()&&W.key==="Enter"&&!p&&(W.preventDefault(),x&&x(W))}),xe=Cp(W=>{c&&W.key===" "&&te&&!W.defaultPrevented&&X.stop(W,()=>{X.pulsate(W)}),P&&P(W),x&&W.target===W.currentTarget&&B()&&W.key===" "&&!W.defaultPrevented&&!p&&x(W)}),he=l;he==="button"&&(Y.href||Y.to)&&(he=b);let Ne={};if(he==="button"){let W=!!Y.formAction;Ne.type=k===void 0&&!W?"button":k,Ne.disabled=p}else!Y.href&&!Y.to&&(Ne.role="button"),p&&(Ne["aria-disabled"]=p);let et=Tt(o,Z),Qt={...r,centerRipple:a,component:l,disabled:p,disableRipple:f,disableTouchRipple:d,focusRipple:c,tabIndex:A,focusVisible:te},rt=bM(Qt);return(0,Ff.jsxs)(vM,{as:he,className:j(rt.root,s),owne Line truncated
`,vM=Ct.forwardRef(function(t,o){let r=H({props:t,name:"MuiTouchRipple"}),{center:n=!1,classes:a={},className:i,...s}=r,[l,p]=Ct.useState([]),f=Ct.useRef(0),d=Ct.useRef(null);Ct.useEffect(()=>{d.current&&(d.current(),d.current=null)},[l]);let c=Ct.useRef(!1),u=Zn(),b=Ct.useRef(null),v=Ct.useRef(null),x=Ct.useCallback(g=>{let{pulsate:S,rippleX:P,rippleY:E,rippleSize:R,cb:N}=g;p(O=>[...O,(0,Gf.jsx)(bM,{classes:{ripple:j(a.ripple,jo.ripple),rippleVisible:j(a.rippleVisible,jo.rippleVisible),ripplePulsate:j(a.ripplePulsate,jo.ripplePulsate),child:j(a.child,jo.child),childLeaving:j(a.childLeaving,jo.childLeaving),childPulsate:j(a.childPulsate,jo.childPulsate)},timeout:Vh,pulsate:S,rippleX:P,rippleY:E,rippleSize:R},f.current)]),f.current+=1,d.current=N},[a]),m=Ct.useCallback((g={},S={},P=()=>{})=>{let{pulsate:E=!1,center:R=n||S.pulsate,fakeElement:N=!1}=S;if(g?.type==="mousedown"&&c.current){c.current=!1;return}g?.type==="touchstart"&&(c.current=!0);let O=N?null:v.current,D=O?O.getBoundingClientRect():{width:0,height:0,left:0,top:0},T,A,M;if(R||g===void 0||g.clientX===0&&g.clientY===0||!g.clientX&&!g.touches)T=Math.round(D.width/2),A=Math.round(D.height/2);else{let{clientX:U,clientY:L}=g.touches&&g.touches.length>0?g.touches[0]:g;T=Math.round(U-D.left),A=Math.round(L-D.top)}if(R)M=Math.sqrt((2*D.width**2+D.height**2)/3),M%2===0&&(M+=1);else{let U=Math.max(Math.abs((O?O.clientWidth:0)-T),T)*2+2,L=Math.max(Math.abs((O?O.clientHeight:0)-A),A)*2+2;M=Math.sqrt(U**2+L**2)}g?.touches?b.current===null&&(b.current=()=>{x({pulsate:E,rippleX:T,rippleY:A,rippleSize:M,cb:P})},u.start(mM,()=>{b.current&&(b.current(),b.current=null)})):x({pulsate:E,rippleX:T,rippleY:A,rippleSize:M,cb:P})},[n,x,u]),h=Ct.useCallback(()=>{m({},{pulsate:!0})},[m]),y=Ct.useCallback((g,S)=>{if(u.clear(),g?.type==="touchend"&&b.current){b.current(),b.current=null,u.start(0,()=>{y(g,S)});return}b.current=null,p(P=>P.length>0?P.slice(1):P),d.current=S},[u]);return Ct.useImperativeHandle(o,()=>({pulsate:h,start:m,stop:y}),[h,m,y]),(0,Gf.jsx)(TM,{className:j(jo.root,a.root,i),ref:v,...s,children:(0,Gf.jsx)(zh,{component:null,exit:!0,children:l})})}),V1=vM;function H1(e){return I("MuiButtonBase",e)}var xM=F("MuiButtonBase",["root","disabled","focusVisible"]),F1=xM;var Yf=C(k(),1),SM=e=>{let{disabled:t,focusVisible:o,focusVisibleClassName:r,classes:n}=e,i=V({root:["root",t&&"disabled",o&&"focusVisible"]},H1,n);return o&&r&&(i.root+=` ${r}`),i},PM=w("button",{name:"MuiButtonBase",slot:"Root"})({display:"inline-flex",alignItems:"center",justifyContent:"center",position:"relative",boxSizing:"border-box",WebkitTapHighlightColor:"transparent",backgroundColor:"transparent",outline:0,border:0,margin:0,borderRadius:0,padding:0,cursor:"pointer",userSelect:"none",verticalAlign:"middle",MozAppearance:"none",WebkitAppearance:"none",textDecoration:"none",color:"inherit","&::-moz-focus-inner":{borderStyle:"none"},[`&.${F1.disabled}`]:{pointerEvents:"none",cursor:"default"},"@media print":{colorAdjust:"exact"}}),CM=kr.forwardRef(function(t,o){let r=H({props:t,name:"MuiButtonBase"}),{action:n,centerRipple:a=!1,children:i,className:s,component:l="button",disabled:p=!1,disableRipple:f=!1,disableTouchRipple:d=!1,focusRipple:c=!1,focusVisibleClassName:u,LinkComponent:b="a",onBlur:v,onClick:x,onContextMenu:m,onDragLeave:h,onFocus:y,onFocusVisible:g,onKeyDown:S,onKeyUp:P,onMouseDown:E,onMouseLeave:R,onMouseUp:N,onTouchEnd:O,onTouchMove:D,onTouchStart:T,tabIndex:A=0,TouchRippleProps:M,touchRippleRef:U,type:L,...G}=r,J=kr.useRef(null),K=$f(),he=bt(K.ref,U),[re,se]=kr.useState(!1);p&&re&&se(!1),kr.useImperativeHandle(n,()=>({focusVisible:()=>{se(!0),J.current.focus()}}),[]);let ie=K.shouldMount&&!f&&!p;kr.useEffect(()=>{re&&c&&!f&&K.pulsate()},[f,c,re,K]);let Xe=hn(K,"start",E,d),Ne=hn(K,"stop",m,d),Ce=hn(K,"stop",h,d),me=hn(K,"stop",N,d),ot=hn(K,"stop",ee=>{re&&ee.preventDefault(),R&&R(ee)},d),ge=hn(K,"start",T,d),oe=hn(K,"stop",O,d),X=hn(K,"stop",D,d),Q=hn(K,"stop",ee=>{Jn(ee.target)||se(!1),v&&v(ee)},!1),Ee=wp(ee=>{J.current||(J.current=ee.currentTarget),Jn(ee.target)&&(se(!0),g&&g(ee)),y&&y(ee)}),Y=()=>{let ee=J.current;return ee?ee.tagName==="BUTTON"?!1:!(ee.tagName==="A"&&ee.href):l&&l!=="button"},ce=wp(ee=>{c&&!ee.repeat&&re&&ee.key===" "&&K.stop(ee,()=>{K.start(ee)}),ee.target===ee.currentTarget&&Y()&&ee.key===" "&&ee.preventDefault(),S&&S(ee),ee.target===ee.currentTarget&&Y()&&ee.key==="Enter"&&!p&&(ee.preventDefault(),x&&x(ee))}),we=wp(ee=>{c&&ee.key===" "&&re&&!ee.defaultPrevented&&K.stop(ee,()=>{K.pulsate(ee)}),P&&P(ee),x&&ee.target===ee.currentTarget&&Y()&&ee.key===" "&&!ee.defaultPrevented&&!p&&x(ee)}),Te=l;Te==="button"&&(G.href||G.to)&&(Te=b);let Ae={};if(Te==="button"){let ee=!!G.formAction;Ae.type=L===void 0&&!ee?"button":L,Ae.disabled=p}else!G.href&&!G.to&&(Ae.role="button"),p&&(Ae["aria-disabled"]=p);let et=bt(o,J),Qt={...r,centerRipple:a,component:l,disabled:p,disableRipple:f,disableTouchRipple:d,focusRipple:c,tabIndex:A,focusVisible:re},rt=SM(Qt);return(0,Yf.j Line truncated
0% {
transform: rotate(0deg);
}
@@ -122,7 +122,7 @@ To suppress this warning, you need to explicitly provide the \`palette.${t}Chann
100% {
transform: rotate(360deg);
}
`,Hh=ho`
`,$h=To`
0% {
stroke-dasharray: 1px, 200px;
stroke-dashoffset: 0;
@@ -137,13 +137,13 @@ To suppress this warning, you need to explicitly provide the \`palette.${t}Chann
stroke-dasharray: 1px, 200px;
stroke-dashoffset: -126px;
}
`,MM=typeof Vh!="string"?hr`
animation: ${Vh} 1.4s linear infinite;
`:null,_M=typeof Hh!="string"?hr`
animation: ${Hh} 1.4s ease-in-out infinite;
`:null,DM=e=>{let{classes:t,variant:o,color:r,disableShrink:n}=e,a={root:["root",o,`color${q(r)}`],svg:["svg"],track:["track"],circle:["circle",`circle${q(o)}`,n&&"circleDisableShrink"]};return H(a,$1,t)},zM=w("span",{name:"MuiCircularProgress",slot:"Root",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.root,t[o.variant],t[`color${q(o.color)}`]]}})(G(({theme:e})=>({display:"inline-block",variants:[{props:{variant:"determinate"},style:{transition:e.transitions.create("transform")}},{props:{variant:"indeterminate"},style:MM||{animation:`${Vh} 1.4s linear infinite`}},...Object.entries(e.palette).filter(_e()).map(([t])=>({props:{color:t},style:{color:(e.vars||e).palette[t].main}}))]}))),jM=w("svg",{name:"MuiCircularProgress",slot:"Svg"})({display:"block"}),UM=w("circle",{name:"MuiCircularProgress",slot:"Circle",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.circle,t[`circle${q(o.variant)}`],o.disableShrink&&t.circleDisableShrink]}})(G(({theme:e})=>({stroke:"currentColor",variants:[{props:{variant:"determinate"},style:{transition:e.transitions.create("stroke-dashoffset")}},{props:{variant:"indeterminate"},style:{strokeDasharray:"80px, 200px",strokeDashoffset:0}},{props:({ownerState:t})=>t.variant==="indeterminate"&&!t.disableShrink,style:_M||{animation:`${Hh} 1.4s ease-in-out infinite`}}]}))),BM=w("circle",{name:"MuiCircularProgress",slot:"Track"})(G(({theme:e})=>({stroke:"currentColor",opacity:(e.vars||e).palette.action.activatedOpacity}))),LM=q1.forwardRef(function(t,o){let r=F({props:t,name:"MuiCircularProgress"}),{className:n,color:a="primary",disableShrink:i=!1,enableTrackSlot:s=!1,size:l=40,style:p,thickness:f=3.6,value:d=0,variant:c="indeterminate",...u}=r,b={...r,color:a,disableShrink:i,size:l,thickness:f,value:d,variant:c,enableTrackSlot:s},v=DM(b),x={},m={},h={};if(c==="determinate"){let y=2*Math.PI*((xr-f)/2);x.strokeDasharray=y.toFixed(3),h["aria-valuenow"]=Math.round(d),x.strokeDashoffset=`${((100-d)/100*y).toFixed(3)}px`,m.transform="rotate(-90deg)"}return(0,Ds.jsx)(zM,{className:j(v.root,n),style:{width:l,height:l,...m,...p},ownerState:b,ref:o,role:"progressbar",...h,...u,children:(0,Ds.jsxs)(jM,{className:v.svg,ownerState:b,viewBox:`${xr/2} ${xr/2} ${xr} ${xr}`,children:[s?(0,Ds.jsx)(BM,{className:v.track,ownerState:b,cx:xr,cy:xr,r:(xr-f)/2,fill:"none",strokeWidth:f,"aria-hidden":"true"}):null,(0,Ds.jsx)(UM,{className:v.circle,style:x,ownerState:b,cx:xr,cy:xr,r:(xr-f)/2,fill:"none",strokeWidth:f})]})})}),Zn=LM;function G1(e){return V("MuiIconButton",e)}var kM=$("MuiIconButton",["root","disabled","colorInherit","colorPrimary","colorSecondary","colorError","colorInfo","colorSuccess","colorWarning","edgeStart","edgeEnd","sizeSmall","sizeMedium","sizeLarge","loading","loadingIndicator","loadingWrapper"]),Fh=kM;var zs=C(I(),1),IM=e=>{let{classes:t,disabled:o,color:r,edge:n,size:a,loading:i}=e,s={root:["root",i&&"loading",o&&"disabled",r!=="default"&&`color${q(r)}`,n&&`edge${q(n)}`,`size${q(a)}`],loadingIndicator:["loadingIndicator"],loadingWrapper:["loadingWrapper"]};return H(s,G1,t)},VM=w(mn,{name:"MuiIconButton",slot:"Root",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.root,o.loading&&t.loading,o.color!=="default"&&t[`color${q(o.color)}`],o.edge&&t[`edge${q(o.edge)}`],t[`size${q(o.size)}`]]}})(G(({theme:e})=>({textAlign:"center",flex:"0 0 auto",fontSize:e.typography.pxToRem(24),padding:8,borderRadius:"50%",color:(e.vars||e).palette.action.active,transition:e.transitions.create("background-color",{duration:e.transitions.duration.shortest}),variants:[{props:t=>!t.disableRipple,style:{"--IconButton-hoverBg":e.alpha((e.vars||e).palette.action.active,(e.vars||e).palette.action.hoverOpacity),"&:hover":{backgroundColor:"var(--IconButton-hoverBg)","@media (hover: none)":{backgroundColor:"transparent"}}}},{props:{edge:"start"},style:{marginLeft:-12}},{props:{edge:"start",size:"small"},style:{marginLeft:-3}},{props:{edge:"end"},style:{marginRight:-12}},{props:{edge:"end",size:"small"},style:{marginRight:-3}}]})),G(({theme:e})=>({variants:[{props:{color:"inherit"},style:{color:"inherit"}},...Object.entries(e.palette).filter(_e()).map(([t])=>({props:{color:t},style:{color:(e.vars||e).palette[t].main}})),...Object.entries(e.palette).filter(_e()).map(([t])=>({props:{color:t},style:{"--IconButton-hoverBg":e.alpha((e.vars||e).palette[t].main,(e.vars||e).palette.action.hoverOpacity)}})),{props:{size:"small"},style:{padding:5,fontSize:e.typography.pxToRem(18)}},{props:{size:"large"},style:{padding:12,fontSize:e.typography.pxToRem(28)}}],[`&.${Fh.disabled}`]:{backgroundColor:"transparent",color:(e.vars||e).palette.action.disabled},[`&.${Fh.loading}`]:{color:"transparent"}}))),HM=w("span",{name:"MuiIconButton",slot:"LoadingIndicator"})(({theme:e})=>({display:"none",position:"absolute",visibility:"visible",top:"50%",left:"50%",transform:"translate(-50%, -50%)",color:(e.vars||e).palette.action.disabled,variants:[{props:{loading:!0},style:{display:"flex"}}]})),FM=Gf.forwardRef(function(t,o){ Line truncated
`&&(g.value+=" ");let E=P.boxSizing,R=Kf(P.paddingBottom)+Kf(P.paddingTop),N=Kf(P.borderBottomWidth)+Kf(P.borderTopWidth),O=g.scrollHeight;g.value="x";let D=g.scrollHeight,T=O;a&&(T=Math.max(Number(a)*D,T)),n&&(T=Math.min(Number(n)*D,T)),T=Math.max(T,D);let A=T+(E==="border-box"?R+N:0),M=Math.abs(T-O)<=1;return{outerHeightStyle:A,overflowing:M}},[n,a,t.placeholder]),v=Gn(()=>{let y=f.current,g=b();if(!y||!g||cS(g))return!1;let S=g.outerHeightStyle;return c.current!=null&&c.current!==S}),x=jo.useCallback(()=>{let y=f.current,g=b();if(!y||!g||cS(g))return;let S=g.outerHeightStyle;c.current!==S&&(c.current=S,y.style.height=`${S}px`),y.style.overflow=g.overflowing?"hidden":""},[b]),m=jo.useRef(-1);return so(()=>{let y=Es(x),g=f?.current;if(!g)return;let S=er(g);S.addEventListener("resize",y);let P;return typeof ResizeObserver<"u"&&(P=new ResizeObserver(()=>{v()&&(P.unobserve(g),cancelAnimationFrame(m.current),x(),m.current=requestAnimationFrame(()=>{P.observe(g)}))}),P.observe(g)),()=>{y.clear(),cancelAnimationFrame(m.current),S.removeEventListener("resize",y),P&&P.disconnect()}},[b,x,v]),so(()=>{x()}),(0,Bp.jsxs)(jo.Fragment,{children:[(0,Bp.jsx)("textarea",{value:s,onChange:y=>{p||x();let g=y.target,S=g.value.length,P=g.value.endsWith(`
`),E=g.selectionStart===S;P&&E&&g.setSelectionRange(S,S),r&&r(y)},ref:d,rows:a,style:i,...l}),(0,Bp.jsx)("textarea",{"aria-hidden":!0,className:t.className,readOnly:!0,ref:u,tabIndex:-1,style:{...a4.shadow,...i,paddingTop:0,paddingBottom:0}})]})}),Gh=s4;function Uo({props:e,states:t,muiFormControl:o}){return t.reduce((r,n)=>(r[n]=e[n],o&&typeof e[n]>"u"&&(r[n]=o[n]),r),{})}var fS=C(L(),1),l4=fS.createContext(void 0),Wn=l4;var dS=C(L(),1);function uo(){return dS.useContext(Wn)}function Qf(e){let t=e.activeElement;for(;t?.shadowRoot?.activeElement!=null;)t=t.shadowRoot.activeElement;return t}var gn=Qf;function mS(e){return e!=null&&!(Array.isArray(e)&&e.length===0)}function ii(e,t=!1){return e&&(mS(e.value)&&e.value!==""||t&&mS(e.defaultValue)&&e.defaultValue!=="")}function yS(e){return e.startAdornment}function hS(e){return V("MuiInputBase",e)}var p4=$("MuiInputBase",["root","formControl","focused","disabled","adornedStart","adornedEnd","error","sizeSmall","multiline","colorSecondary","fullWidth","hiddenLabel","readOnly","input","inputSizeSmall","inputMultiline","inputTypeSearch","inputAdornedStart","inputAdornedEnd","inputHiddenLabel"]),Sr=p4;var si=C(I(),1),gS,Yh="mui-auto-fill",Zf="mui-auto-fill-cancel",li=(e,t)=>{let{ownerState:o}=e;return[t.root,o.formControl&&t.formControl,o.startAdornment&&t.adornedStart,o.endAdornment&&t.adornedEnd,o.error&&t.error,o.size==="small"&&t.sizeSmall,o.multiline&&t.multiline,o.color&&t[`color${q(o.color)}`],o.fullWidth&&t.fullWidth,o.hiddenLabel&&t.hiddenLabel]},pi=(e,t)=>{let{ownerState:o}=e;return[t.input,o.size==="small"&&t.inputSizeSmall,o.multiline&&t.inputMultiline,o.type==="search"&&t.inputTypeSearch,o.startAdornment&&t.inputAdornedStart,o.endAdornment&&t.inputAdornedEnd,o.hiddenLabel&&t.inputHiddenLabel]},u4=e=>{let{classes:t,color:o,disabled:r,error:n,endAdornment:a,focused:i,formControl:s,fullWidth:l,hiddenLabel:p,multiline:f,readOnly:d,size:c,startAdornment:u,type:b}=e,v={root:["root",`color${q(o)}`,r&&"disabled",n&&"error",l&&"fullWidth",i&&"focused",s&&"formControl",c&&c!=="medium"&&`size${q(c)}`,f&&"multiline",u&&"adornedStart",a&&"adornedEnd",p&&"hiddenLabel",d&&"readOnly"],input:["input",r&&"disabled",b==="search"&&"inputTypeSearch",f&&"inputMultiline",c==="small"&&"inputSizeSmall",p&&"inputHiddenLabel",u&&"inputAdornedStart",a&&"inputAdornedEnd",d&&"readOnly"]};return H(v,hS,t)},ui=w("div",{name:"MuiInputBase",slot:"Root",overridesResolver:li})(G(({theme:e})=>({...e.typography.body1,color:(e.vars||e).palette.text.primary,lineHeight:"1.4375em",boxSizing:"border-box",position:"relative",cursor:"text",display:"inline-flex",alignItems:"center",[`&.${Sr.disabled}`]:{color:(e.vars||e).palette.text.disabled,cursor:"default"},variants:[{props:({ownerState:t})=>t.multiline,style:{padding:"4px 0 5px"}},{props:({ownerState:t,size:o})=>t.multiline&&o==="small",style:{paddingTop:1}},{props:({ownerState:t})=>t.fullWidth,style:{width:"100%"}}]}))),ci=w("input",{name:"MuiInputBase",slot:"Input",overridesResolver:pi})(G(({theme:e})=>{let t=e.palette.mode==="light",o={color:"currentColor",...e.vars?{opacity:e.vars.opacity.inputPlaceholder}:{opacity:t?.42:.5},transition:e.transitions.create("opacity",{duration:e.transitions.duration.shorter})},r={opacity:"0 !important"},n=e.vars?{opacity:e.vars.opacity.inputPlaceholder}:{opacity:t?.42:.5};return{font:"inherit",letterSpacing:"inherit",color:"currentColor",padding:"4px 0 5px",border:0,boxSizing:"content-box",background:"none",height:"1.4375em",margin:0,WebkitTapHighlightColor:"transparent",display:"block",minWidth:0,width:"100%","&::-webkit-input-placeholder":o,"&::-moz-placeholder":o,"&::-ms-input-placeholder":o,"&:focus":{outline:0},"&:invalid":{boxShadow:"none"},"&::-webkit-search-decoration":{WebkitAppearance:"none"},[`label[data-shrink=false] + .${Sr.formControl} &`]:{"&::-webkit-input-placeholder":r,"&::-moz-placeholder":r,"&::-ms-input-placeholder":r,"&:focus::-webkit-input-placeholder":n,"&:focus::-moz-placeholder":n,"&:focus::-ms-input-placeholder":n},[`&.${Sr.disabled}`]:{opacity:1,WebkitTextFillColor:(e.vars||e).palette.text.disabled},variants:[{props:({ownerState:a})=>!a.disableInjectingGlobalStyles,style:{animationName:Zf,animationDuration:"10ms","&:-webkit-autofill":{animationDuration:"5000s",animationName:Yh}}},{props:{size:"small"},style:{paddingTop:1}},{props:({ownerState:a})=>a.multiline,style:{height:"auto",resize:"none",padding:0,paddingTop:0}},{props:{type:"search"},style:{MozAppearance:"textfield"}}]}})),TS=vp({[`@keyframes ${Yh}`]:{from:{animationName:Yh}},[`@keyframes ${Zf}`]:{from:{animationName:Zf}}}),c4=Jt.forwardRef(function(t,o){let r=F({props:t,name:"MuiInputBase"}),{"aria-describedby":n,autoComplete:a,autoFocus:i,className:s,color:l,components:p={},componentsProps:f={},defaultValue:d,disabled:c,disableInjectingGlobalStyles:u,endAdornment:b,error:v,fullWidth:x=!1,id:m,inputComponent:h="input",inputProps:y={},inputRef:g,margin:S,maxRows:P,minRows:E,multiline:R=!1,name:N,onBlur:O,onChange:D,onClick Line truncated
`,zM=typeof Fh!="string"?Tr`
animation: ${Fh} 1.4s linear infinite;
`:null,jM=typeof $h!="string"?Tr`
animation: ${$h} 1.4s ease-in-out infinite;
`:null,UM=e=>{let{classes:t,variant:o,color:r,disableShrink:n}=e,a={root:["root",o,`color${$(r)}`],svg:["svg"],track:["track"],circle:["circle",`circle${$(o)}`,n&&"circleDisableShrink"]};return V(a,G1,t)},BM=w("span",{name:"MuiCircularProgress",slot:"Root",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.root,t[o.variant],t[`color${$(o.color)}`]]}})(q(({theme:e})=>({display:"inline-block",variants:[{props:{variant:"determinate"},style:{transition:e.transitions.create("transform")}},{props:{variant:"indeterminate"},style:zM||{animation:`${Fh} 1.4s linear infinite`}},...Object.entries(e.palette).filter(ze()).map(([t])=>({props:{color:t},style:{color:(e.vars||e).palette[t].main}}))]}))),LM=w("svg",{name:"MuiCircularProgress",slot:"Svg"})({display:"block"}),kM=w("circle",{name:"MuiCircularProgress",slot:"Circle",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.circle,t[`circle${$(o.variant)}`],o.disableShrink&&t.circleDisableShrink]}})(q(({theme:e})=>({stroke:"currentColor",variants:[{props:{variant:"determinate"},style:{transition:e.transitions.create("stroke-dashoffset")}},{props:{variant:"indeterminate"},style:{strokeDasharray:"80px, 200px",strokeDashoffset:0}},{props:({ownerState:t})=>t.variant==="indeterminate"&&!t.disableShrink,style:jM||{animation:`${$h} 1.4s ease-in-out infinite`}}]}))),IM=w("circle",{name:"MuiCircularProgress",slot:"Track"})(q(({theme:e})=>({stroke:"currentColor",opacity:(e.vars||e).palette.action.activatedOpacity}))),VM=Y1.forwardRef(function(t,o){let r=H({props:t,name:"MuiCircularProgress"}),{className:n,color:a="primary",disableShrink:i=!1,enableTrackSlot:s=!1,size:l=40,style:p,thickness:f=3.6,value:d=0,variant:c="indeterminate",...u}=r,b={...r,color:a,disableShrink:i,size:l,thickness:f,value:d,variant:c,enableTrackSlot:s},v=UM(b),x={},m={},h={};if(c==="determinate"){let y=2*Math.PI*((Pr-f)/2);x.strokeDasharray=y.toFixed(3),h["aria-valuenow"]=Math.round(d),x.strokeDashoffset=`${((100-d)/100*y).toFixed(3)}px`,m.transform="rotate(-90deg)"}return(0,Us.jsx)(BM,{className:j(v.root,n),style:{width:l,height:l,...m,...p},ownerState:b,ref:o,role:"progressbar",...h,...u,children:(0,Us.jsxs)(LM,{className:v.svg,ownerState:b,viewBox:`${Pr/2} ${Pr/2} ${Pr} ${Pr}`,children:[s?(0,Us.jsx)(IM,{className:v.track,ownerState:b,cx:Pr,cy:Pr,r:(Pr-f)/2,fill:"none",strokeWidth:f,"aria-hidden":"true"}):null,(0,Us.jsx)(kM,{className:v.circle,style:x,ownerState:b,cx:Pr,cy:Pr,r:(Pr-f)/2,fill:"none",strokeWidth:f})]})})}),ea=VM;function X1(e){return I("MuiIconButton",e)}var HM=F("MuiIconButton",["root","disabled","colorInherit","colorPrimary","colorSecondary","colorError","colorInfo","colorSuccess","colorWarning","edgeStart","edgeEnd","sizeSmall","sizeMedium","sizeLarge","loading","loadingIndicator","loadingWrapper"]),qh=HM;var Bs=C(k(),1),FM=e=>{let{classes:t,disabled:o,color:r,edge:n,size:a,loading:i}=e,s={root:["root",i&&"loading",o&&"disabled",r!=="default"&&`color${$(r)}`,n&&`edge${$(n)}`,`size${$(a)}`],loadingIndicator:["loadingIndicator"],loadingWrapper:["loadingWrapper"]};return V(s,X1,t)},$M=w(gn,{name:"MuiIconButton",slot:"Root",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.root,o.loading&&t.loading,o.color!=="default"&&t[`color${$(o.color)}`],o.edge&&t[`edge${$(o.edge)}`],t[`size${$(o.size)}`]]}})(q(({theme:e})=>({textAlign:"center",flex:"0 0 auto",fontSize:e.typography.pxToRem(24),padding:8,borderRadius:"50%",color:(e.vars||e).palette.action.active,transition:e.transitions.create("background-color",{duration:e.transitions.duration.shortest}),variants:[{props:t=>!t.disableRipple,style:{"--IconButton-hoverBg":e.alpha((e.vars||e).palette.action.active,(e.vars||e).palette.action.hoverOpacity),"&:hover":{backgroundColor:"var(--IconButton-hoverBg)","@media (hover: none)":{backgroundColor:"transparent"}}}},{props:{edge:"start"},style:{marginLeft:-12}},{props:{edge:"start",size:"small"},style:{marginLeft:-3}},{props:{edge:"end"},style:{marginRight:-12}},{props:{edge:"end",size:"small"},style:{marginRight:-3}}]})),q(({theme:e})=>({variants:[{props:{color:"inherit"},style:{color:"inherit"}},...Object.entries(e.palette).filter(ze()).map(([t])=>({props:{color:t},style:{color:(e.vars||e).palette[t].main}})),...Object.entries(e.palette).filter(ze()).map(([t])=>({props:{color:t},style:{"--IconButton-hoverBg":e.alpha((e.vars||e).palette[t].main,(e.vars||e).palette.action.hoverOpacity)}})),{props:{size:"small"},style:{padding:5,fontSize:e.typography.pxToRem(18)}},{props:{size:"large"},style:{padding:12,fontSize:e.typography.pxToRem(28)}}],[`&.${qh.disabled}`]:{backgroundColor:"transparent",color:(e.vars||e).palette.action.disabled},[`&.${qh.loading}`]:{color:"transparent"}}))),qM=w("span",{name:"MuiIconButton",slot:"LoadingIndicator"})(({theme:e})=>({display:"none",position:"absolute",visibility:"visible",top:"50%",left:"50%",transform:"translate(-50%, -50%)",color:(e.vars||e).palette.action.disabled,variants:[{props:{loading:!0},style:{display:"flex"}}]})),GM=Qf.forwardRef(function(t,o){ Line truncated
`&&(g.value+=" ");let E=P.boxSizing,R=Jf(P.paddingBottom)+Jf(P.paddingTop),N=Jf(P.borderBottomWidth)+Jf(P.borderTopWidth),O=g.scrollHeight;g.value="x";let D=g.scrollHeight,T=O;a&&(T=Math.max(Number(a)*D,T)),n&&(T=Math.min(Number(n)*D,T)),T=Math.max(T,D);let A=T+(E==="border-box"?R+N:0),M=Math.abs(T-O)<=1;return{outerHeightStyle:A,overflowing:M}},[n,a,t.placeholder]),v=Kn(()=>{let y=f.current,g=b();if(!y||!g||dS(g))return!1;let S=g.outerHeightStyle;return c.current!=null&&c.current!==S}),x=Bo.useCallback(()=>{let y=f.current,g=b();if(!y||!g||dS(g))return;let S=g.outerHeightStyle;c.current!==S&&(c.current=S,y.style.height=`${S}px`),y.style.overflow=g.overflowing?"hidden":""},[b]),m=Bo.useRef(-1);return so(()=>{let y=Ns(x),g=f?.current;if(!g)return;let S=tr(g);S.addEventListener("resize",y);let P;return typeof ResizeObserver<"u"&&(P=new ResizeObserver(()=>{v()&&(P.unobserve(g),cancelAnimationFrame(m.current),x(),m.current=requestAnimationFrame(()=>{P.observe(g)}))}),P.observe(g)),()=>{y.clear(),cancelAnimationFrame(m.current),S.removeEventListener("resize",y),P&&P.disconnect()}},[b,x,v]),so(()=>{x()}),(0,Hp.jsxs)(Bo.Fragment,{children:[(0,Hp.jsx)("textarea",{value:s,onChange:y=>{p||x();let g=y.target,S=g.value.length,P=g.value.endsWith(`
`),E=g.selectionStart===S;P&&E&&g.setSelectionRange(S,S),r&&r(y)},ref:d,rows:a,style:i,...l}),(0,Hp.jsx)("textarea",{"aria-hidden":!0,className:t.className,readOnly:!0,ref:u,tabIndex:-1,style:{...l4.shadow,...i,paddingTop:0,paddingBottom:0}})]})}),Xh=u4;function Lo({props:e,states:t,muiFormControl:o}){return t.reduce((r,n)=>(r[n]=e[n],o&&typeof e[n]>"u"&&(r[n]=o[n]),r),{})}var mS=C(B(),1),c4=mS.createContext(void 0),ta=c4;var yS=C(B(),1);function co(){return yS.useContext(ta)}function ed(e){let t=e.activeElement;for(;t?.shadowRoot?.activeElement!=null;)t=t.shadowRoot.activeElement;return t}var bn=ed;function hS(e){return e!=null&&!(Array.isArray(e)&&e.length===0)}function pi(e,t=!1){return e&&(hS(e.value)&&e.value!==""||t&&hS(e.defaultValue)&&e.defaultValue!=="")}function gS(e){return e.startAdornment}function TS(e){return I("MuiInputBase",e)}var f4=F("MuiInputBase",["root","formControl","focused","disabled","adornedStart","adornedEnd","error","sizeSmall","multiline","colorSecondary","fullWidth","hiddenLabel","readOnly","input","inputSizeSmall","inputMultiline","inputTypeSearch","inputAdornedStart","inputAdornedEnd","inputHiddenLabel"]),Cr=f4;var ui=C(k(),1),bS,Kh="mui-auto-fill",td="mui-auto-fill-cancel",ci=(e,t)=>{let{ownerState:o}=e;return[t.root,o.formControl&&t.formControl,o.startAdornment&&t.adornedStart,o.endAdornment&&t.adornedEnd,o.error&&t.error,o.size==="small"&&t.sizeSmall,o.multiline&&t.multiline,o.color&&t[`color${$(o.color)}`],o.fullWidth&&t.fullWidth,o.hiddenLabel&&t.hiddenLabel]},fi=(e,t)=>{let{ownerState:o}=e;return[t.input,o.size==="small"&&t.inputSizeSmall,o.multiline&&t.inputMultiline,o.type==="search"&&t.inputTypeSearch,o.startAdornment&&t.inputAdornedStart,o.endAdornment&&t.inputAdornedEnd,o.hiddenLabel&&t.inputHiddenLabel]},d4=e=>{let{classes:t,color:o,disabled:r,error:n,endAdornment:a,focused:i,formControl:s,fullWidth:l,hiddenLabel:p,multiline:f,readOnly:d,size:c,startAdornment:u,type:b}=e,v={root:["root",`color${$(o)}`,r&&"disabled",n&&"error",l&&"fullWidth",i&&"focused",s&&"formControl",c&&c!=="medium"&&`size${$(c)}`,f&&"multiline",u&&"adornedStart",a&&"adornedEnd",p&&"hiddenLabel",d&&"readOnly"],input:["input",r&&"disabled",b==="search"&&"inputTypeSearch",f&&"inputMultiline",c==="small"&&"inputSizeSmall",p&&"inputHiddenLabel",u&&"inputAdornedStart",a&&"inputAdornedEnd",d&&"readOnly"]};return V(v,TS,t)},di=w("div",{name:"MuiInputBase",slot:"Root",overridesResolver:ci})(q(({theme:e})=>({...e.typography.body1,color:(e.vars||e).palette.text.primary,lineHeight:"1.4375em",boxSizing:"border-box",position:"relative",cursor:"text",display:"inline-flex",alignItems:"center",[`&.${Cr.disabled}`]:{color:(e.vars||e).palette.text.disabled,cursor:"default"},variants:[{props:({ownerState:t})=>t.multiline,style:{padding:"4px 0 5px"}},{props:({ownerState:t,size:o})=>t.multiline&&o==="small",style:{paddingTop:1}},{props:({ownerState:t})=>t.fullWidth,style:{width:"100%"}}]}))),mi=w("input",{name:"MuiInputBase",slot:"Input",overridesResolver:fi})(q(({theme:e})=>{let t=e.palette.mode==="light",o={color:"currentColor",...e.vars?{opacity:e.vars.opacity.inputPlaceholder}:{opacity:t?.42:.5},transition:e.transitions.create("opacity",{duration:e.transitions.duration.shorter})},r={opacity:"0 !important"},n=e.vars?{opacity:e.vars.opacity.inputPlaceholder}:{opacity:t?.42:.5};return{font:"inherit",letterSpacing:"inherit",color:"currentColor",padding:"4px 0 5px",border:0,boxSizing:"content-box",background:"none",height:"1.4375em",margin:0,WebkitTapHighlightColor:"transparent",display:"block",minWidth:0,width:"100%","&::-webkit-input-placeholder":o,"&::-moz-placeholder":o,"&::-ms-input-placeholder":o,"&:focus":{outline:0},"&:invalid":{boxShadow:"none"},"&::-webkit-search-decoration":{WebkitAppearance:"none"},[`label[data-shrink=false] + .${Cr.formControl} &`]:{"&::-webkit-input-placeholder":r,"&::-moz-placeholder":r,"&::-ms-input-placeholder":r,"&:focus::-webkit-input-placeholder":n,"&:focus::-moz-placeholder":n,"&:focus::-ms-input-placeholder":n},[`&.${Cr.disabled}`]:{opacity:1,WebkitTextFillColor:(e.vars||e).palette.text.disabled},variants:[{props:({ownerState:a})=>!a.disableInjectingGlobalStyles,style:{animationName:td,animationDuration:"10ms","&:-webkit-autofill":{animationDuration:"5000s",animationName:Kh}}},{props:{size:"small"},style:{paddingTop:1}},{props:({ownerState:a})=>a.multiline,style:{height:"auto",resize:"none",padding:0,paddingTop:0}},{props:{type:"search"},style:{MozAppearance:"textfield"}}]}})),vS=Ep({[`@keyframes ${Kh}`]:{from:{animationName:Kh}},[`@keyframes ${td}`]:{from:{animationName:td}}}),m4=Jt.forwardRef(function(t,o){let r=H({props:t,name:"MuiInputBase"}),{"aria-describedby":n,autoComplete:a,autoFocus:i,className:s,color:l,components:p={},componentsProps:f={},defaultValue:d,disabled:c,disableInjectingGlobalStyles:u,endAdornment:b,error:v,fullWidth:x=!1,id:m,inputComponent:h="input",inputProps:y={},inputRef:g,margin:S,maxRows:P,minRows:E,multiline:R=!1,name:N,onBlur:O,onChange:D,onClick Line truncated
0% {
left: -35%;
right: 100%;
@@ -158,9 +158,9 @@ To suppress this warning, you need to explicitly provide the \`palette.${t}Chann
left: 100%;
right: -90%;
}
`,oD=typeof dg!="string"?hr`
animation: ${dg} 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite;
`:null,mg=ho`
`,aD=typeof yg!="string"?Tr`
animation: ${yg} 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite;
`:null,hg=To`
0% {
left: -200%;
right: 100%;
@@ -175,9 +175,9 @@ To suppress this warning, you need to explicitly provide the \`palette.${t}Chann
left: 107%;
right: -8%;
}
`,rD=typeof mg!="string"?hr`
animation: ${mg} 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) 1.15s infinite;
`:null,yg=ho`
`,iD=typeof hg!="string"?Tr`
animation: ${hg} 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) 1.15s infinite;
`:null,gg=To`
0% {
opacity: 1;
background-position: 0 -23px;
@@ -192,9 +192,9 @@ To suppress this warning, you need to explicitly provide the \`palette.${t}Chann
opacity: 1;
background-position: -200px -23px;
}
`,nD=typeof yg!="string"?hr`
animation: ${yg} 3s infinite linear;
`:null,aD=e=>{let{classes:t,variant:o,color:r}=e,n={root:["root",`color${q(r)}`,o],dashed:["dashed",`dashedColor${q(r)}`],bar1:["bar","bar1",`barColor${q(r)}`,(o==="indeterminate"||o==="query")&&"bar1Indeterminate",o==="determinate"&&"bar1Determinate",o==="buffer"&&"bar1Buffer"],bar2:["bar","bar2",o!=="buffer"&&`barColor${q(r)}`,o==="buffer"&&`color${q(r)}`,(o==="indeterminate"||o==="query")&&"bar2Indeterminate",o==="buffer"&&"bar2Buffer"]};return H(n,PP,t)},hg=(e,t)=>e.vars?e.vars.palette.LinearProgress[`${t}Bg`]:e.palette.mode==="light"?e.lighten(e.palette[t].main,.62):e.darken(e.palette[t].main,.5),iD=w("span",{name:"MuiLinearProgress",slot:"Root",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.root,t[`color${q(o.color)}`],t[o.variant]]}})(G(({theme:e})=>({position:"relative",overflow:"hidden",display:"block",height:4,zIndex:0,"@media print":{colorAdjust:"exact"},variants:[...Object.entries(e.palette).filter(_e()).map(([t])=>({props:{color:t},style:{backgroundColor:hg(e,t)}})),{props:({ownerState:t})=>t.color==="inherit"&&t.variant!=="buffer",style:{"&::before":{content:'""',position:"absolute",left:0,top:0,right:0,bottom:0,backgroundColor:"currentColor",opacity:.3}}},{props:{variant:"buffer"},style:{backgroundColor:"transparent"}},{props:{variant:"query"},style:{transform:"rotate(180deg)"}}]}))),sD=w("span",{name:"MuiLinearProgress",slot:"Dashed",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.dashed,t[`dashedColor${q(o.color)}`]]}})(G(({theme:e})=>({position:"absolute",marginTop:0,height:"100%",width:"100%",backgroundSize:"10px 10px",backgroundPosition:"0 -23px",variants:[{props:{color:"inherit"},style:{opacity:.3,backgroundImage:"radial-gradient(currentColor 0%, currentColor 16%, transparent 42%)"}},...Object.entries(e.palette).filter(_e()).map(([t])=>{let o=hg(e,t);return{props:{color:t},style:{backgroundImage:`radial-gradient(${o} 0%, ${o} 16%, transparent 42%)`}}})]})),nD||{animation:`${yg} 3s infinite linear`}),lD=w("span",{name:"MuiLinearProgress",slot:"Bar1",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.bar,t.bar1,t[`barColor${q(o.color)}`],(o.variant==="indeterminate"||o.variant==="query")&&t.bar1Indeterminate,o.variant==="determinate"&&t.bar1Determinate,o.variant==="buffer"&&t.bar1Buffer]}})(G(({theme:e})=>({width:"100%",position:"absolute",left:0,bottom:0,top:0,transition:"transform 0.2s linear",transformOrigin:"left",variants:[{props:{color:"inherit"},style:{backgroundColor:"currentColor"}},...Object.entries(e.palette).filter(_e()).map(([t])=>({props:{color:t},style:{backgroundColor:(e.vars||e).palette[t].main}})),{props:{variant:"determinate"},style:{transition:`transform .${fg}s linear`}},{props:{variant:"buffer"},style:{zIndex:1,transition:`transform .${fg}s linear`}},{props:({ownerState:t})=>t.variant==="indeterminate"||t.variant==="query",style:{width:"auto"}},{props:({ownerState:t})=>t.variant==="indeterminate"||t.variant==="query",style:oD||{animation:`${dg} 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite`}}]}))),pD=w("span",{name:"MuiLinearProgress",slot:"Bar2",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.bar,t.bar2,t[`barColor${q(o.color)}`],(o.variant==="indeterminate"||o.variant==="query")&&t.bar2Indeterminate,o.variant==="buffer"&&t.bar2Buffer]}})(G(({theme:e})=>({width:"100%",position:"absolute",left:0,bottom:0,top:0,transition:"transform 0.2s linear",transformOrigin:"left",variants:[...Object.entries(e.palette).filter(_e()).map(([t])=>({props:{color:t},style:{"--LinearProgressBar2-barColor":(e.vars||e).palette[t].main}})),{props:({ownerState:t})=>t.variant!=="buffer"&&t.color!=="inherit",style:{backgroundColor:"var(--LinearProgressBar2-barColor, currentColor)"}},{props:({ownerState:t})=>t.variant!=="buffer"&&t.color==="inherit",style:{backgroundColor:"currentColor"}},{props:{color:"inherit"},style:{opacity:.3}},...Object.entries(e.palette).filter(_e()).map(([t])=>({props:{color:t,variant:"buffer"},style:{backgroundColor:hg(e,t),transition:`transform .${fg}s linear`}})),{props:({ownerState:t})=>t.variant==="indeterminate"||t.variant==="query",style:{width:"auto"}},{props:({ownerState:t})=>t.variant==="indeterminate"||t.variant==="query",style:rD||{animation:`${mg} 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) 1.15s infinite`}}]}))),uD=CP.forwardRef(function(t,o){let r=F({props:t,name:"MuiLinearProgress"}),{className:n,color:a="primary",value:i,valueBuffer:s,variant:l="indeterminate",...p}=r,f={...r,color:a,variant:l},d=aD(f),c=sf(),u={},b={bar1:{},bar2:{}};if((l==="determinate"||l==="buffer")&&i!==void 0){u["aria-valuenow"]=Math.round(i),u["aria-valuemin"]=0,u["aria-valuemax"]=100;let v=i-100;c&&(v=-v),b.bar1.transform=`translateX(${v}%)`}if(l==="buffer"&&s!==void 0){let v=(s||0)-100;c&&(v=-v),b.bar2.transform=`translateX(${v}%)`}return(0,$s.jsxs)(iD,{className:j(d.root,n),ownerState:f,role:"progressbar",...u,ref:o,...p,children:[l==="buffer"?(0,$s.jsx)(sD,{className:d.dashed,ownerState:f}):null,(0,$s.jsx)(lD,{className:d.bar1,ownerState:f Line truncated
`,sD=typeof gg!="string"?Tr`
animation: ${gg} 3s infinite linear;
`:null,lD=e=>{let{classes:t,variant:o,color:r}=e,n={root:["root",`color${$(r)}`,o],dashed:["dashed",`dashedColor${$(r)}`],bar1:["bar","bar1",`barColor${$(r)}`,(o==="indeterminate"||o==="query")&&"bar1Indeterminate",o==="determinate"&&"bar1Determinate",o==="buffer"&&"bar1Buffer"],bar2:["bar","bar2",o!=="buffer"&&`barColor${$(r)}`,o==="buffer"&&`color${$(r)}`,(o==="indeterminate"||o==="query")&&"bar2Indeterminate",o==="buffer"&&"bar2Buffer"]};return V(n,EP,t)},Tg=(e,t)=>e.vars?e.vars.palette.LinearProgress[`${t}Bg`]:e.palette.mode==="light"?e.lighten(e.palette[t].main,.62):e.darken(e.palette[t].main,.5),pD=w("span",{name:"MuiLinearProgress",slot:"Root",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.root,t[`color${$(o.color)}`],t[o.variant]]}})(q(({theme:e})=>({position:"relative",overflow:"hidden",display:"block",height:4,zIndex:0,"@media print":{colorAdjust:"exact"},variants:[...Object.entries(e.palette).filter(ze()).map(([t])=>({props:{color:t},style:{backgroundColor:Tg(e,t)}})),{props:({ownerState:t})=>t.color==="inherit"&&t.variant!=="buffer",style:{"&::before":{content:'""',position:"absolute",left:0,top:0,right:0,bottom:0,backgroundColor:"currentColor",opacity:.3}}},{props:{variant:"buffer"},style:{backgroundColor:"transparent"}},{props:{variant:"query"},style:{transform:"rotate(180deg)"}}]}))),uD=w("span",{name:"MuiLinearProgress",slot:"Dashed",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.dashed,t[`dashedColor${$(o.color)}`]]}})(q(({theme:e})=>({position:"absolute",marginTop:0,height:"100%",width:"100%",backgroundSize:"10px 10px",backgroundPosition:"0 -23px",variants:[{props:{color:"inherit"},style:{opacity:.3,backgroundImage:"radial-gradient(currentColor 0%, currentColor 16%, transparent 42%)"}},...Object.entries(e.palette).filter(ze()).map(([t])=>{let o=Tg(e,t);return{props:{color:t},style:{backgroundImage:`radial-gradient(${o} 0%, ${o} 16%, transparent 42%)`}}})]})),sD||{animation:`${gg} 3s infinite linear`}),cD=w("span",{name:"MuiLinearProgress",slot:"Bar1",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.bar,t.bar1,t[`barColor${$(o.color)}`],(o.variant==="indeterminate"||o.variant==="query")&&t.bar1Indeterminate,o.variant==="determinate"&&t.bar1Determinate,o.variant==="buffer"&&t.bar1Buffer]}})(q(({theme:e})=>({width:"100%",position:"absolute",left:0,bottom:0,top:0,transition:"transform 0.2s linear",transformOrigin:"left",variants:[{props:{color:"inherit"},style:{backgroundColor:"currentColor"}},...Object.entries(e.palette).filter(ze()).map(([t])=>({props:{color:t},style:{backgroundColor:(e.vars||e).palette[t].main}})),{props:{variant:"determinate"},style:{transition:`transform .${mg}s linear`}},{props:{variant:"buffer"},style:{zIndex:1,transition:`transform .${mg}s linear`}},{props:({ownerState:t})=>t.variant==="indeterminate"||t.variant==="query",style:{width:"auto"}},{props:({ownerState:t})=>t.variant==="indeterminate"||t.variant==="query",style:aD||{animation:`${yg} 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite`}}]}))),fD=w("span",{name:"MuiLinearProgress",slot:"Bar2",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.bar,t.bar2,t[`barColor${$(o.color)}`],(o.variant==="indeterminate"||o.variant==="query")&&t.bar2Indeterminate,o.variant==="buffer"&&t.bar2Buffer]}})(q(({theme:e})=>({width:"100%",position:"absolute",left:0,bottom:0,top:0,transition:"transform 0.2s linear",transformOrigin:"left",variants:[...Object.entries(e.palette).filter(ze()).map(([t])=>({props:{color:t},style:{"--LinearProgressBar2-barColor":(e.vars||e).palette[t].main}})),{props:({ownerState:t})=>t.variant!=="buffer"&&t.color!=="inherit",style:{backgroundColor:"var(--LinearProgressBar2-barColor, currentColor)"}},{props:({ownerState:t})=>t.variant!=="buffer"&&t.color==="inherit",style:{backgroundColor:"currentColor"}},{props:{color:"inherit"},style:{opacity:.3}},...Object.entries(e.palette).filter(ze()).map(([t])=>({props:{color:t,variant:"buffer"},style:{backgroundColor:Tg(e,t),transition:`transform .${mg}s linear`}})),{props:({ownerState:t})=>t.variant==="indeterminate"||t.variant==="query",style:{width:"auto"}},{props:({ownerState:t})=>t.variant==="indeterminate"||t.variant==="query",style:iD||{animation:`${hg} 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) 1.15s infinite`}}]}))),dD=RP.forwardRef(function(t,o){let r=H({props:t,name:"MuiLinearProgress"}),{className:n,color:a="primary",value:i,valueBuffer:s,variant:l="indeterminate",...p}=r,f={...r,color:a,variant:l},d=lD(f),c=cf(),u={},b={bar1:{},bar2:{}};if((l==="determinate"||l==="buffer")&&i!==void 0){u["aria-valuenow"]=Math.round(i),u["aria-valuemin"]=0,u["aria-valuemax"]=100;let v=i-100;c&&(v=-v),b.bar1.transform=`translateX(${v}%)`}if(l==="buffer"&&s!==void 0){let v=(s||0)-100;c&&(v=-v),b.bar2.transform=`translateX(${v}%)`}return(0,Xs.jsxs)(pD,{className:j(d.root,n),ownerState:f,role:"progressbar",...u,ref:o,...p,children:[l==="buffer"?(0,Xs.jsx)(uD,{className:d.dashed,ownerState:f}):null,(0,Xs.jsx)(cD,{className:d.bar1,ownerState:f Line truncated
/*! Bundled license information:
react/cjs/react.production.js:
Binary file not shown.
+1 -1
View File
@@ -29,7 +29,7 @@
<script src="/appearance.js?v=b178d8b94c59"></script>
<title>XGift · Premium 兑换</title>
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<script type="module" src="/app.js?v=9ef23665d26d"></script>
<script type="module" src="/app.js?v=2c9bcd09f3d7"></script>
</head>
<body>
<div id="root"></div>
+62 -5
View File
@@ -10,6 +10,7 @@ import (
"path/filepath"
"strings"
"testing"
"time"
"xgift/internal/checkout"
"xgift/internal/vault"
)
@@ -26,7 +27,7 @@ func checkFixture(t *testing.T) *server {
t.Fatal(e)
}
t.Cleanup(func() { v.Close() })
return &server{vault: v, origin: "https://example.test", work: make(chan struct{}, 1), limits: map[string]limit{}}
return &server{vault: v, origin: "https://example.test", work: make(chan struct{}, 1), checks: make(chan struct{}, 4), limits: map[string]limit{}}
}
func fakeEligibility(t *testing.T, calls *int, id string, err error) {
@@ -67,7 +68,7 @@ func TestEligibilityCheck(t *testing.T) {
if w.Code != 200 || body["eligible"] != true || calls != 1 {
t.Fatalf("status=%d body=%s calls=%d", w.Code, w.Body.String(), calls)
}
if len(s.work) != 0 {
if len(s.work) != 0 || len(s.checks) != 0 {
t.Fatal("worker slot leaked")
}
})
@@ -102,7 +103,7 @@ func TestEligibilityCheck(t *testing.T) {
if w.Code != 503 || !strings.Contains(msg, "检测") {
t.Fatalf("status=%d body=%s", w.Code, w.Body.String())
}
if len(s.work) != 0 {
if len(s.work) != 0 || len(s.checks) != 0 {
t.Fatal("worker slot leaked")
}
})
@@ -119,7 +120,7 @@ func TestEligibilityCheck(t *testing.T) {
t.Fatalf("X called %d times for invalid input", calls)
}
})
t.Run("busy worker returns 503 instead of queueing", func(t *testing.T) {
t.Run("busy payment worker does not block checks", func(t *testing.T) {
s := checkFixture(t)
calls := 0
fakeEligibility(t, &calls, "1234", nil)
@@ -127,7 +128,7 @@ func TestEligibilityCheck(t *testing.T) {
defer func() { <-s.work }()
w := submitCheck(s, "someone")
msg, _ := checkBody(t, w)["message"].(string)
if w.Code != 503 || !strings.Contains(msg, "检测") || calls != 0 {
if w.Code != 200 || !strings.Contains(msg, "可以") || calls != 1 || len(s.work) != 1 || len(s.checks) != 0 {
t.Fatalf("status=%d body=%s calls=%d", w.Code, w.Body.String(), calls)
}
})
@@ -157,3 +158,59 @@ func TestEligibilityCheck(t *testing.T) {
}
})
}
func TestEligibilityChecksRunConcurrently(t *testing.T) {
s := checkFixture(t)
started := make(chan struct{}, cap(s.checks))
release := make(chan struct{})
done := make(chan *httptest.ResponseRecorder, cap(s.checks))
original := eligibilityCheck
eligibilityCheck = func(context.Context, *vault.Vault, string, int) (string, error) {
started <- struct{}{}
<-release
return "1234", nil
}
t.Cleanup(func() { eligibilityCheck = original })
released := false
launched := 0
defer func() {
if !released {
close(release)
}
for i := 0; i < launched; i++ {
<-done
}
}()
for i := 0; i < cap(s.checks); i++ {
launched++
go func() { done <- submitCheck(s, "someone") }()
}
for i := 0; i < cap(s.checks); i++ {
select {
case <-started:
case <-time.After(3 * time.Second):
t.Fatal("checks did not start concurrently")
}
}
if len(s.work) != 0 {
t.Fatal("checks occupied the payment worker")
}
if w := submitCheck(s, "someone"); w.Code != 503 {
t.Fatalf("unbounded checks: %d", w.Code)
}
close(release)
released = true
for launched > 0 {
w := <-done
launched--
if w.Code != 200 {
t.Errorf("check failed: %d", w.Code)
}
}
if len(s.checks) != 0 {
t.Fatal("check slot leaked")
}
if w := submitCheck(s, "someone"); w.Code != 200 {
t.Fatalf("slot not reusable: %d", w.Code)
}
}
+35
View File
@@ -0,0 +1,35 @@
package site
import (
"database/sql"
"errors"
"net/http"
"strings"
)
// lookup finds one redemption code by its full value so the admin can answer
// "where is this code and what happened to it" without paging through batches.
func (s *server) lookup(w http.ResponseWriter, r *http.Request) {
var q struct {
Code string `json:"code"`
}
if !decode(w, r, &q) {
return
}
q.Code = strings.ToUpper(strings.TrimSpace(q.Code))
if !codePattern.MatchString(q.Code) {
message(w, 400, "请填写 XG- 开头、后接 48 位十六进制字符(0-9、A-F)的完整兑换码。")
return
}
var c codeRow
e := s.db.QueryRow("SELECT id,hint,batch,months,status,username,message,created,updated,progress,COALESCE(folder_id,''),copyable FROM codes WHERE hash=?", hash(q.Code)).Scan(&c.ID, &c.Hint, &c.Batch, &c.Months, &c.Status, &c.Username, &c.Message, &c.Created, &c.Updated, &c.Progress, &c.Folder, &c.Copyable)
if errors.Is(e, sql.ErrNoRows) {
message(w, 404, "没有找到这个兑换码,请核对后重试。")
return
}
if e != nil {
message(w, 503, "暂时无法查询兑换码,请稍后重试。")
return
}
reply(w, 200, c)
}
+66
View File
@@ -0,0 +1,66 @@
package site
import (
"encoding/json"
"net/http/httptest"
"strings"
"testing"
)
func lookupRequest(s *server, body string) *httptest.ResponseRecorder {
req := httptest.NewRequest("POST", "/api/admin/lookup", strings.NewReader(body))
req.Header.Set("Content-Type", "application/json")
w := httptest.NewRecorder()
s.lookup(w, req)
return w
}
func TestLookupFindsCodeByFullValue(t *testing.T) {
s := resumeFixture(t, "review", "created")
if _, err := s.db.Exec("ALTER TABLE codes ADD COLUMN folder_id TEXT"); err != nil {
t.Fatal(err)
}
if _, err := s.db.Exec("ALTER TABLE codes ADD COLUMN copyable INTEGER DEFAULT 1"); err != nil {
t.Fatal(err)
}
w := lookupRequest(s, `{"code":"xg-`+strings.Repeat("a", 48)+`"}`)
var row codeRow
if err := json.Unmarshal(w.Body.Bytes(), &row); err != nil {
t.Fatalf("invalid JSON %q: %v", w.Body.String(), err)
}
if w.Code != 200 || row.ID != "code1" || row.Hint != "AAAA" || row.Status != "review" || row.Username != "recipient" || row.Months != 6 || !row.Copyable {
t.Fatalf("status=%d body=%s", w.Code, w.Body.String())
}
if strings.Contains(w.Body.String(), strings.Repeat("A", 48)) || strings.Contains(w.Body.String(), "1234") {
t.Fatal("lookup leaked the full code or recipient id")
}
}
func TestLookupRejectsBadInput(t *testing.T) {
s := resumeFixture(t, "review", "created")
if _, err := s.db.Exec("ALTER TABLE codes ADD COLUMN folder_id TEXT"); err != nil {
t.Fatal(err)
}
if _, err := s.db.Exec("ALTER TABLE codes ADD COLUMN copyable INTEGER DEFAULT 1"); err != nil {
t.Fatal(err)
}
for _, body := range []string{`{"code":""}`, `{"code":"XG-ABC"}`, `{"code":"` + strings.Repeat("G", 48) + `"}`} {
if w := lookupRequest(s, body); w.Code != 400 {
t.Fatalf("body %s: status=%d", body, w.Code)
}
}
if w := lookupRequest(s, `{"code":"XG-`+strings.Repeat("B", 48)+`"}`); w.Code != 404 {
t.Fatalf("unknown code: status=%d", w.Code)
}
}
func TestLookupRequiresAdmin(t *testing.T) {
s := resumeFixture(t, "review", "created")
req := httptest.NewRequest("POST", "/api/admin/lookup", strings.NewReader(`{"code":"XG-`+strings.Repeat("A", 48)+`"}`))
req.Header.Set("Content-Type", "application/json")
w := httptest.NewRecorder()
s.admin(s.lookup)(w, req)
if w.Code != 401 {
t.Fatalf("unauthenticated lookup: status=%d", w.Code)
}
}
+5 -4
View File
@@ -37,6 +37,7 @@ type recoveryBatch struct {
Created int64 `json:"created"`
Updated int64 `json:"updated"`
Last4 string `json:"last4"`
Cards int `json:"cards"`
Binding string `json:"binding,omitempty"`
Paused bool `json:"paused"`
Message string `json:"message"`
@@ -207,7 +208,7 @@ func (s *server) recoveryPreview(w http.ResponseWriter, r *http.Request) {
message(w, 409, "已有补单任务运行中,请先查看或停止。")
return
}
last4, binding, err := checkout.CardSummary(s.vault)
last4, cardCount, binding, err := checkout.CardSummary(s.vault)
if err != nil {
message(w, 503, "付款方式配置无法读取。")
return
@@ -243,7 +244,7 @@ func (s *server) recoveryPreview(w http.ResponseWriter, r *http.Request) {
}
}
q := &recoveryBatch{Mode: in.Mode, ID: token(16), State: "preview", Created: time.Now().Unix(), Last4: last4, Binding: binding, Paused: paused, Items: []recoveryItem{}}
q := &recoveryBatch{Mode: in.Mode, ID: token(16), State: "preview", Created: time.Now().Unix(), Last4: last4, Cards: cardCount, Binding: binding, Paused: paused, Items: []recoveryItem{}}
for _, id := range ids {
item, e := s.recoveryCandidate(id)
if e != nil {
@@ -319,7 +320,7 @@ func (s *server) recoveryStart(w http.ResponseWriter, r *http.Request) {
release()
}
}()
_, binding, err := checkout.CardSummary(s.vault)
_, _, binding, err := checkout.CardSummary(s.vault)
if err != nil || binding != q.Binding {
message(w, 409, "付款方式已变化,请重新预览。")
return
@@ -506,7 +507,7 @@ func (s *server) recoverOne(item recoveryItem, binding string) (state, detail st
return s.recoverOneOptions(item, binding, "pay", false)
}
func (s *server) recoverOneOptions(item recoveryItem, binding, mode string, verified bool) (state, detail string, stop bool) {
_, current, err := checkout.CardSummary(s.vault)
_, _, current, err := checkout.CardSummary(s.vault)
if err != nil || current != binding {
return "blocked", "付款方式配置变化,已停止", true
}
+8 -6
View File
@@ -48,6 +48,7 @@ type server struct {
port int
lockPath string
work chan struct{}
checks chan struct{}
jobs sync.WaitGroup
ctx context.Context
recoveryMu sync.Mutex
@@ -108,7 +109,7 @@ func Run(ctx context.Context) error {
if len(admin) < 32 {
return errors.New("admin password must contain at least 32 characters")
}
s := &server{origin: origin, adminHash: sha256.Sum256(admin), payments: os.Getenv("XGIFT_PAYMENTS_ENABLED") == "true", lockPath: filepath.Join(dir, "checkout.lock"), work: make(chan struct{}, 1), ctx: ctx, limits: map[string]limit{}}
s := &server{origin: origin, adminHash: sha256.Sum256(admin), payments: os.Getenv("XGIFT_PAYMENTS_ENABLED") == "true", lockPath: filepath.Join(dir, "checkout.lock"), work: make(chan struct{}, 1), checks: make(chan struct{}, 4), ctx: ctx, limits: map[string]limit{}}
clear(admin)
v, err := vault.Open(filepath.Join(dir, "vault.db"), os.Getenv("XGIFT_PASSWORD_FILE"), false)
if err != nil {
@@ -228,6 +229,7 @@ func Run(ctx context.Context) error {
mux.HandleFunc("GET /admin", s.admin(s.asset("admin.html", "text/html; charset=utf-8")))
mux.HandleFunc("GET /admin.js", s.admin(s.asset("admin.js", "application/javascript; charset=utf-8")))
mux.HandleFunc("GET /api/admin/codes", s.admin(s.list))
mux.HandleFunc("POST /api/admin/lookup", s.admin(s.lookup))
mux.HandleFunc("GET /api/admin/stats", s.admin(s.stats))
mux.HandleFunc("GET /api/admin/customer", s.admin(s.customerOrder))
mux.HandleFunc("GET /api/admin/recovery", s.admin(s.recoveryStatus))
@@ -481,8 +483,8 @@ func (s *server) status(w http.ResponseWriter, r *http.Request) {
var eligibilityCheck = checkout.Eligibility
// check is a read-only eligibility probe: no code lookup, no checkout, no writes.
// It stays available while payments are paused and shares the single X worker
// slot with redemptions, but never queues behind one.
// It stays available while payments are paused or running. Read-only checks
// have their own bounded concurrency and never occupy the payment worker.
func (s *server) check(w http.ResponseWriter, r *http.Request) {
var q struct {
Username string `json:"username"`
@@ -496,10 +498,10 @@ func (s *server) check(w http.ResponseWriter, r *http.Request) {
return
}
select {
case s.work <- struct{}{}:
defer func() { <-s.work }()
case s.checks <- struct{}{}:
defer func() { <-s.checks }()
default:
message(w, 503, "正在处理其他请求,请稍后重试检测。")
message(w, 503, "当前检测人数较多,请稍后重试检测。")
return
}
ctx, cancel := context.WithTimeout(r.Context(), 35*time.Second)