update 2026-11-13 00:30:06
No files matched your search
@@ -1,19 +1,19 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=clashoo
|
||||
PKG_UPSTREAM_VERSION:=1.19.33
|
||||
PKG_UPSTREAM_VERSION:=1.19.34
|
||||
PKG_UPSTREAM_TAG:=v$(PKG_UPSTREAM_VERSION)
|
||||
PKG_SHORT_SHA:=3f27ef3
|
||||
PKG_SHORT_SHA:=0455d0d
|
||||
|
||||
PKG_VERSION:=2026.11.04.$(PKG_UPSTREAM_VERSION)
|
||||
PKG_RELEASE:=3
|
||||
PKG_VERSION:=2026.11.12.$(PKG_UPSTREAM_VERSION)
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_SOURCE:=$(PKG_NAME)-stable-$(PKG_UPSTREAM_TAG)-$(PKG_SHORT_SHA).tar.gz
|
||||
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-stable-$(PKG_UPSTREAM_TAG)-$(PKG_SHORT_SHA)
|
||||
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_SOURCE_SUBDIR)
|
||||
PKG_SOURCE_URL:=https://github.com/kenzok8/openwrt-clashoo/releases/download/mihomo-src
|
||||
PKG_SOURCE_VERSION:=3f27ef39f8c96bbfbc8b0b9bb10f5c9ef60149d8
|
||||
PKG_HASH:=1ef7a4087f3805bd2624a940e2e43a0bc23719a25465c9f503aa6c11572f1321
|
||||
PKG_SOURCE_VERSION:=0455d0d28c4526937380505153e65a843d8612e8
|
||||
PKG_HASH:=d51ffc103547e91328b3e3540e558c5b6f7be3d31e6a63dc3249d101faf9cb20
|
||||
PKG_BUILD_VERSION:=$(PKG_UPSTREAM_TAG)
|
||||
|
||||
PKG_LICENSE:=GPL3.0+
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=honk
|
||||
PKG_VERSION:=2026.11.09.1
|
||||
PKG_VERSION:=2026.11.12
|
||||
PKG_RELEASE:=1
|
||||
|
||||
# Pinned honk-core revision (upstream daeuniverse/honk main), cross-compiled by
|
||||
|
||||
@@ -51,6 +51,13 @@ module_loaded() {
|
||||
[ -d "/sys/module/$1" ] || grep -q "^$1 " /proc/modules
|
||||
}
|
||||
|
||||
# 只有面板管理的 system.dae 能决定 NFQUEUE;自定义配置按开启处理。
|
||||
nfqueue_enabled() {
|
||||
[ "${settings_owner:-}" = system ] || return 0
|
||||
_nfq=$(sed -n 's/^ nfqueue_enable: \(true\|false\)$/\1/p' /etc/honk/system.dae 2>/dev/null | head -n 1)
|
||||
[ "$_nfq" != false ]
|
||||
}
|
||||
|
||||
module_available() {
|
||||
module_loaded "$1" && return 0
|
||||
module_path=$(printf '%s' "$1" | tr '_' '-')
|
||||
@@ -189,9 +196,14 @@ check_kernel() {
|
||||
[ -d /sys/fs/bpf ] && grep -q ' /sys/fs/bpf bpf ' /proc/mounts || { kernel_error=bpffs_not_mounted; fail "bpffs 未挂载到 /sys/fs/bpf,请检查内核或手工挂载"; return 1; }
|
||||
command -v ip >/dev/null 2>&1 || { kernel_error=ip_full_missing; fail "缺少 ip 命令(装 ip-full)"; return 1; }
|
||||
command -v modprobe >/dev/null 2>&1 || { kernel_error=kmod_missing; fail "缺少 modprobe 命令(装 kmod)"; return 1; }
|
||||
for module in sch_ingress cls_bpf veth nft_queue nfnetlink_queue; do
|
||||
module_available "$module" || { kernel_error="kernel_module_missing:$module"; fail "缺少内核模块 $module,请确认 kmod-sched-core / kmod-sched-bpf / kmod-veth / kmod-nft-queue 已安装"; return 1; }
|
||||
for module in sch_ingress cls_bpf veth; do
|
||||
module_available "$module" || { kernel_error="kernel_module_missing:$module"; fail "缺少内核模块 $module,请确认 kmod-sched-core / kmod-sched-bpf / kmod-veth 已安装"; return 1; }
|
||||
done
|
||||
if nfqueue_enabled; then
|
||||
for module in nft_queue nfnetlink_queue; do
|
||||
module_available "$module" || { kernel_error="kernel_module_missing:$module"; fail "缺少内核模块 $module,装 kmod-nft-queue,或在 system.dae 里设 nfqueue_enable: false"; return 1; }
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
check_conflicts() {
|
||||
@@ -396,10 +408,12 @@ cleanup_initialize() {
|
||||
|
||||
# 交还面板管理时也用它,保证两条路径生成的 system.dae 一致。
|
||||
render_runtime_system() {
|
||||
_nfq=$(sed -n 's/^ nfqueue_enable: \(true\|false\)$/\1/p' /etc/honk/system.dae 2>/dev/null | head -n 1)
|
||||
case "$_nfq" in true|false) ;; *) _nfq=true ;; esac
|
||||
printf "global {\n wan_interface: auto\n lan_interface: '%s'\n" "$1"
|
||||
printf " log_level: info\n dial_mode: domain\n allow_insecure: false\n"
|
||||
printf " auto_config_kernel_parameter: true\n data_dir: '/etc/honk'\n"
|
||||
printf " store_subscribe: true\n nfqueue_enable: true\n}\n\n"
|
||||
printf " store_subscribe: true\n nfqueue_enable: %s\n}\n\n" "$_nfq"
|
||||
printf "experimental {\n native_api {\n enabled: true\n listen: '%s:%s'\n" "$2" "$3"
|
||||
printf " password_auth: true\n allow_anonymous_loopback: false\n"
|
||||
printf " config_write: true\n ui: '/usr/share/doona'\n }\n"
|
||||
@@ -954,7 +968,7 @@ repair() {
|
||||
if [ "$initialized" = 1 ]; then system_host=$lan_ip; else system_host=127.0.0.1; fi
|
||||
if [ -r /usr/share/doona/index.html ] && [ -f /etc/honk/system.dae ] && [ ! -L /etc/honk/system.dae ] && system_config_readonly && \
|
||||
grep -Fqx ' wan_interface: auto' /etc/honk/system.dae && grep -Fqx " lan_interface: '$lan_device'" /etc/honk/system.dae && \
|
||||
grep -Fqx " data_dir: '/etc/honk'" /etc/honk/system.dae && grep -Fqx ' nfqueue_enable: true' /etc/honk/system.dae && \
|
||||
grep -Fqx " data_dir: '/etc/honk'" /etc/honk/system.dae && grep -Eqx ' nfqueue_enable: (true|false)' /etc/honk/system.dae && \
|
||||
grep -Fqx " listen: '$system_host:$listen_port'" /etc/honk/system.dae && \
|
||||
grep -Fqx " ui: '/usr/share/doona'" /etc/honk/system.dae && grep -Fqx ' password_auth: true' /etc/honk/system.dae && \
|
||||
grep -Fqx ' allow_anonymous_loopback: false' /etc/honk/system.dae && grep -Fqx ' config_write: true' /etc/honk/system.dae && clash_system_matches; then
|
||||
|
||||
@@ -598,6 +598,8 @@ validate_system_schema() {
|
||||
[ "$listen_host" = "$expected_ip" ] || [ "$listen_host" = 127.0.0.1 ] || return 1
|
||||
store_subscribe=$(sed -n 's/^ store_subscribe: \(true\|false\)$/\1/p' "$trusted_system")
|
||||
case "$store_subscribe" in true|false) ;; *) return 1 ;; esac
|
||||
nfqueue_enable=$(sed -n 's/^ nfqueue_enable: \(true\|false\)$/\1/p' "$trusted_system")
|
||||
case "$nfqueue_enable" in true|false) ;; *) nfqueue_enable=true ;; esac
|
||||
cat > "$temp_dir/system.expected" <<EOF
|
||||
global {
|
||||
wan_interface: auto
|
||||
@@ -608,7 +610,7 @@ global {
|
||||
auto_config_kernel_parameter: true
|
||||
data_dir: '/etc/honk'
|
||||
store_subscribe: $store_subscribe
|
||||
nfqueue_enable: true
|
||||
nfqueue_enable: $nfqueue_enable
|
||||
}
|
||||
|
||||
experimental {
|
||||
@@ -797,6 +799,9 @@ write_live_system() {
|
||||
live_ip=$3
|
||||
live_port=$4
|
||||
live_initialized=$5
|
||||
# 第 6 个参数决定 NFQUEUE:false 才关闭,其余按开启。
|
||||
live_nfqueue=$6
|
||||
case "$live_nfqueue" in true|false) ;; *) live_nfqueue=true ;; esac
|
||||
if [ "$live_initialized" = 1 ]; then live_host=$live_ip; else live_host=127.0.0.1; fi
|
||||
cat > "$live_system" <<EOF
|
||||
global {
|
||||
@@ -808,7 +813,7 @@ global {
|
||||
auto_config_kernel_parameter: true
|
||||
data_dir: '/etc/honk'
|
||||
store_subscribe: true
|
||||
nfqueue_enable: true
|
||||
nfqueue_enable: $live_nfqueue
|
||||
}
|
||||
|
||||
experimental {
|
||||
@@ -1061,7 +1066,9 @@ restore() {
|
||||
[ "$old_running" != 1 ] || [ "$restore_initialized" = 1 ] || { error running_service_requires_initialized_restore; return 1; }
|
||||
[ "$(sha_of "$RESTORE")" = "$archive_hash" ] || { error restore_archive_changed; return 1; }
|
||||
if [ "$(config_owner "$restore_stage/etc/honk/config.dae")" = system ]; then
|
||||
write_live_system "$restore_stage/etc/honk/system.dae" "$candidate_device" "$candidate_ip" "$u_port" "$restore_initialized" || { error system_config_render_failed; return 1; }
|
||||
restore_nfqueue=$(sed -n 's/^ nfqueue_enable: \(true\|false\)$/\1/p' "$restore_stage/etc/honk/system.dae" 2>/dev/null | head -n 1)
|
||||
case "$restore_nfqueue" in true|false) ;; *) restore_nfqueue=true ;; esac
|
||||
write_live_system "$restore_stage/etc/honk/system.dae" "$candidate_device" "$candidate_ip" "$u_port" "$restore_initialized" "$restore_nfqueue" || { error system_config_render_failed; return 1; }
|
||||
chmod 0600 "$restore_stage/etc/honk/system.dae" || { error system_config_render_failed; return 1; }
|
||||
fi
|
||||
uci -c "$uci_dir" -t "$temp_dir/uci-tmp" set "honk.main.enabled=$old_enabled" || { error restore_profile_stage_failed; return 1; }
|
||||
@@ -1155,7 +1162,7 @@ reset_data() {
|
||||
reset_ip=
|
||||
network_get_device reset_device "$u_network" || { error lan_network_unavailable; return 1; }
|
||||
network_get_ipaddr reset_ip "$u_network" || { error lan_network_unavailable; return 1; }
|
||||
write_live_system "$reset_stage/etc/honk/system.dae" "$reset_device" "$reset_ip" "$u_port" "$u_initialized" || { error system_config_render_failed; return 1; }
|
||||
write_live_system "$reset_stage/etc/honk/system.dae" "$reset_device" "$reset_ip" "$u_port" "$u_initialized" true || { error system_config_render_failed; return 1; }
|
||||
chmod 0600 "$reset_stage/etc/honk/system.dae" || { error system_config_render_failed; return 1; }
|
||||
reset_candidate=$temp_dir/reset-candidate
|
||||
mkdir -p "$reset_candidate/etc" || { error reset_stage_failed; return 1; }
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
scripts/** linguist-detectable=false
|
||||
tests/** linguist-detectable=false
|
||||
@@ -2,22 +2,63 @@ name: build-apk
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '**'
|
||||
tags:
|
||||
- 'v*'
|
||||
- 'dev-*'
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
contents: read
|
||||
|
||||
env:
|
||||
SDK_DIR: /builder
|
||||
PKG_DIR_NAME: luci-app-adguardhome-tk
|
||||
|
||||
jobs:
|
||||
regression:
|
||||
name: 回归测试
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v7
|
||||
|
||||
- name: 准备 Node.js
|
||||
uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version: '24'
|
||||
package-manager-cache: false
|
||||
|
||||
- name: 准备 Python
|
||||
uses: actions/setup-python@v7
|
||||
with:
|
||||
python-version: '3.12'
|
||||
cache: pip
|
||||
cache-dependency-path: tests/browser/requirements.txt
|
||||
|
||||
- name: 安装测试依赖
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y busybox
|
||||
python3 -m pip install -r tests/browser/requirements.txt
|
||||
python3 -m playwright install --with-deps chromium
|
||||
|
||||
- name: 服务与日志回归
|
||||
run: bash scripts/test.sh unit
|
||||
|
||||
- name: 浏览器回归
|
||||
run: bash scripts/test.sh browser
|
||||
|
||||
build:
|
||||
needs: regression
|
||||
if: github.event_name == 'workflow_dispatch' || startsWith(github.ref, 'refs/tags/')
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 90
|
||||
permissions:
|
||||
contents: write
|
||||
strategy:
|
||||
matrix:
|
||||
sdk: [x86-64-25.12.6]
|
||||
@@ -48,6 +89,9 @@ jobs:
|
||||
- name: 构建包
|
||||
run: runuser -u buildbot -- bash scripts/build-apk.sh
|
||||
|
||||
- name: 分包与安装迁移回归
|
||||
run: bash scripts/test.sh sdk
|
||||
|
||||
- name: 整理 APK 产物
|
||||
run: bash scripts/collect-apks.sh
|
||||
|
||||
|
||||
@@ -1,2 +1,5 @@
|
||||
.DS_Store
|
||||
.local
|
||||
.local
|
||||
.venv/
|
||||
__pycache__/
|
||||
*.pyc
|
||||
@@ -4,7 +4,8 @@ cd "$SDK_DIR"
|
||||
|
||||
mkdir -p package/${PKG_DIR_NAME}
|
||||
rsync -a --delete "$GITHUB_WORKSPACE/" "package/${PKG_DIR_NAME}/" \
|
||||
--exclude '.git*' --exclude '.local' --exclude '_sdk' --exclude 'dist'
|
||||
--exclude '.git*' --exclude '.local' --exclude '_sdk' --exclude 'dist' \
|
||||
--exclude 'tests' --exclude '.venv'
|
||||
|
||||
./scripts/feeds update -a
|
||||
./scripts/feeds install luci-base tar
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.."
|
||||
|
||||
case "${1:-unit}" in
|
||||
unit)
|
||||
for script in scripts/*.sh tests/sdk/*.sh; do
|
||||
bash -n "$script"
|
||||
done
|
||||
node --test tests/*.test.js
|
||||
python3 -m unittest discover -s tests -p 'test_*.py' -v
|
||||
;;
|
||||
browser)
|
||||
python3 tests/browser/test_verbose_checkbox.py
|
||||
;;
|
||||
sdk)
|
||||
# 使用 SDK 构建出的工具, 避免维护额外的编译器和 apk 副本.
|
||||
if [[ -n "${SDK_DIR:-}" ]]; then
|
||||
export PATH="$SDK_DIR/staging_dir/hostpkg/bin:$SDK_DIR/staging_dir/host/bin:$PATH"
|
||||
fi
|
||||
python3 tests/sdk/test_split_packages.py
|
||||
bash tests/sdk/test_apk_rename.sh
|
||||
;;
|
||||
*)
|
||||
echo "Usage: bash scripts/test.sh [unit|browser|sdk]" >&2
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
@@ -0,0 +1 @@
|
||||
playwright==1.64.1
|
||||
@@ -0,0 +1,36 @@
|
||||
"""从页面提取复选框逻辑, 用真实 DOM 验证布尔属性和保存后的状态."""
|
||||
from pathlib import Path
|
||||
from playwright.sync_api import sync_playwright
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
source = (ROOT / 'root/www/luci-static/resources/view/adguardhome/log.js').read_text()
|
||||
block = source[source.index("\t\t\tvar verboseToggle ="):source.index("\t\t\tvar message =")]
|
||||
with sync_playwright() as p:
|
||||
browser = p.chromium.launch()
|
||||
page = browser.new_page()
|
||||
result = page.evaluate('''async block => {
|
||||
function E(tag, attrs, children) {
|
||||
const node = document.createElement(tag);
|
||||
for (const key in attrs) if (attrs[key] != null) node.setAttribute(key, attrs[key]);
|
||||
return node;
|
||||
}
|
||||
const create = new Function('E', 'm', '_', 'callSetVerboseLog', 'var toggleStyle="";'+block+';return verboseToggle;');
|
||||
let saved = '0';
|
||||
let fail = false;
|
||||
const rpc = async enabled => { if (fail) throw Error('save failed'); saved = enabled ? '1' : '0'; return {saved:true, applied:true}; };
|
||||
const render = readonly => create(E, {data:{get:()=>saved}, readonly}, x=>x, rpc);
|
||||
const check = (ok,msg) => {if (!ok) throw Error(msg);};
|
||||
const tick = () => new Promise(resolve => setTimeout(resolve,0));
|
||||
let input = render(false); document.body.append(input);
|
||||
check(!input.checked && !input.disabled, 'default off and editable');
|
||||
input.click(); await tick();
|
||||
check(saved === '1' && render(false).checked, 'enable survives reload');
|
||||
input.click(); await tick();
|
||||
check(saved === '0' && !render(false).checked, 'disable survives reload');
|
||||
fail = true; input.click(); await tick();
|
||||
check(!input.checked && !input.disabled && saved === '0', 'failure restores state');
|
||||
check(render(true).disabled, 'readonly disabled');
|
||||
saved = undefined; check(!render(false).checked, 'missing setting defaults off');
|
||||
return 'PASS: default, enable/disable + reload, save failure, readonly, missing setting';
|
||||
}''', block)
|
||||
print(result)
|
||||
browser.close()
|
||||
@@ -0,0 +1,136 @@
|
||||
/* 用模拟的 fs/uci 执行兼容 JavaScript 的 RPC 逻辑.
|
||||
* 此处验证日志传输边界, OpenWrt 上的 ucode/LuCI 集成仍需实机验证.
|
||||
*/
|
||||
async function runLogTests(rpcSource, viewSource) {
|
||||
function check(value, message) {
|
||||
if (!value) throw new Error(message);
|
||||
}
|
||||
var limit = 262144;
|
||||
var data = 'a'.repeat(limit * 20) + 'TAIL';
|
||||
var inode = 1;
|
||||
var readSize = 0;
|
||||
var readOffset = -1;
|
||||
var closed = false;
|
||||
var rpcCode = rpcSource.replace(/^#!.*\n/, '').replace(/^import .*;\n/gm, '');
|
||||
var api = new Function('stat', 'open', 'cursor', 'int', 'length', 'die', 'b64enc', rpcCode)(
|
||||
function() { return { type: 'file', dev: { major: 0, minor: 1 }, inode: inode, size: data.length }; },
|
||||
function() {
|
||||
return {
|
||||
seek: function(offset) { readOffset = offset; return true; },
|
||||
read: function(size) { readSize = size; return data.slice(readOffset, readOffset + size); },
|
||||
close: function() { closed = true; }
|
||||
};
|
||||
},
|
||||
function() { return { get: function() { return '/tmp/test.log'; }, unload: function() {} }; },
|
||||
Math.trunc, function(s) { return s.length; }, function(s) { throw new Error(s); }, btoa
|
||||
)['luci.adguardhome'];
|
||||
var backendRead = api.getRuntimeLog.call;
|
||||
function read(request) {
|
||||
var result = backendRead(request);
|
||||
check(typeof result.content_b64 === 'string', 'binary-safe transport present');
|
||||
check(!result.content_b64.includes('\0'), 'wire text contains no NUL');
|
||||
// 模拟 rpcd 的 C 字符串传输, 检查 NUL 不会截断有效内容.
|
||||
result.content = atob(result.content_b64.split('\0')[0]);
|
||||
return result;
|
||||
}
|
||||
var initial = read({ args: { offset: 0, identity: '' } });
|
||||
check(readSize === limit && readOffset === data.length - limit && closed, 'bounded tail read');
|
||||
check(initial.content.length === limit && initial.content.endsWith('TAIL'), 'latest data returned');
|
||||
data += 'APPEND';
|
||||
var appended = read({ args: { offset: initial.offset, identity: initial.identity } });
|
||||
check(appended.content === 'APPEND' && !appended.reset, 'incremental append');
|
||||
data = '';
|
||||
var truncated = read({ args: { offset: appended.offset, identity: appended.identity } });
|
||||
check(truncated.reset && truncated.offset === 0 && truncated.content === '', 'truncate reset');
|
||||
data = 'n'.repeat(appended.offset + 100);
|
||||
inode++;
|
||||
var rotated = read({ args: { offset: appended.offset, identity: appended.identity } });
|
||||
check(rotated.reset && rotated.content.length === limit, 'replacement by larger file resets');
|
||||
data += 'x'.repeat(limit * 2);
|
||||
var lagged = read({ args: { offset: rotated.offset, identity: rotated.identity } });
|
||||
check(lagged.reset && readSize === limit && lagged.content === 'x'.repeat(limit), 'slow reader skips old backlog');
|
||||
|
||||
// 复现清空日志后写入进程仍保留原偏移量的稀疏文件.
|
||||
data = '\0'.repeat(120000) + 'visible after clear\n';
|
||||
var sparse = read({ args: { offset: 0, identity: '' } });
|
||||
check(sparse.offset === data.length, 'cursor includes sparse bytes');
|
||||
check(sparse.content.endsWith('visible after clear\n'), 'text after NUL survives rpcd transport');
|
||||
var unicodeBytes = new TextEncoder().encode('中文日志正常\n');
|
||||
var unicodeBinary = Array.from(unicodeBytes, function(b) { return String.fromCharCode(b); }).join('');
|
||||
data += unicodeBinary;
|
||||
var unicode = read({ args: { offset: sparse.offset, identity: sparse.identity } });
|
||||
check(unicode.offset === data.length && unicode.content === unicodeBinary, 'UTF-8 byte cursor remains correct');
|
||||
|
||||
var pollCallback;
|
||||
var nodes = [];
|
||||
var response;
|
||||
var pending;
|
||||
var page = new Function('view', 'rpc', 'poll', 'status', 'E', '_', 'form', 'L', viewSource)(
|
||||
{ extend: function(value) { return value; } },
|
||||
{ declare: function(spec) {
|
||||
return function() {
|
||||
if (spec.method === 'clearRuntimeLog') return Promise.resolve({ cleared: true });
|
||||
return pending || Promise.resolve(response);
|
||||
};
|
||||
} },
|
||||
{ add: function(callback) { pollCallback = callback; } },
|
||||
{ render: function() { return { node: {} }; } },
|
||||
function(tag, attrs, children) {
|
||||
var node = Object.assign({ tag: tag, children: children, style: {}, events: {},
|
||||
addEventListener: function(name, fn) { this.events[name] = fn; } }, attrs);
|
||||
nodes.push(node);
|
||||
return node;
|
||||
},
|
||||
function(text) { return text; },
|
||||
{ Map: function() {
|
||||
this.data = { get: function() { return '0'; } };
|
||||
this.section = function() { return { option: function() { return {}; } }; };
|
||||
this.render = function() {
|
||||
var logFileField = { querySelector: function() { return {}; } };
|
||||
var fields = { querySelector: function() { return logFileField; } };
|
||||
var card = {
|
||||
classList: { add: function() {} },
|
||||
querySelector: function() { return fields; },
|
||||
insertBefore: function() {}
|
||||
};
|
||||
return Promise.resolve({ querySelector: function() { return card; } });
|
||||
};
|
||||
} }, { resource: function(path) { return path; } }
|
||||
);
|
||||
await page.render(sparse);
|
||||
var area = nodes.find(function(n) { return n.tag === 'textarea'; });
|
||||
check(area.value.includes('visible after clear') && !area.value.includes('\0'), 'sparse log is visible in page');
|
||||
response = unicode;
|
||||
await pollCallback();
|
||||
check(area.value.includes('中文日志正常'), 'UTF-8 log is decoded for display');
|
||||
var clear = nodes.find(function(n) { return n.children === 'dellog'; });
|
||||
for (var i = 0; i < 12; i++) {
|
||||
response = { enabled: true, content: 'b'.repeat(limit), offset: initial.offset + (i + 1) * limit, identity: initial.identity };
|
||||
await pollCallback();
|
||||
check(area.value.length <= limit, 'frontend cache stays bounded');
|
||||
}
|
||||
response = { enabled: true, content: '', offset: 0, identity: initial.identity, reset: true };
|
||||
await pollCallback();
|
||||
check(area.value === '', 'empty truncated log clears display');
|
||||
var resolveOld;
|
||||
pending = new Promise(function(resolve) { resolveOld = resolve; });
|
||||
var oldPoll = pollCallback();
|
||||
clear.events.click();
|
||||
await Promise.resolve();
|
||||
resolveOld({ enabled: true, content: 'STALE', offset: 5, identity: initial.identity });
|
||||
await oldPoll;
|
||||
check(area.value === '', 'late poll cannot restore cleared content');
|
||||
return 'PASS: binary-safe RPC, sparse log display, UTF-8, bounded reads, rotation and clear/poll race';
|
||||
}
|
||||
|
||||
const test = require('node:test');
|
||||
|
||||
test('runtime log transport, bounded reads and clear/poll race', { timeout: 5000 }, async () => {
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const root = path.resolve(__dirname, '..');
|
||||
await runLogTests(
|
||||
fs.readFileSync(path.join(root, 'root/usr/share/rpcd/ucode/luci.adguardhome'), 'utf8'),
|
||||
fs.readFileSync(path.join(root, 'root/www/luci-static/resources/view/adguardhome/log.js'), 'utf8')
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,90 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
REPO_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
APK="${APK:-$(command -v apk || true)}"
|
||||
if [[ ! -x "$APK" ]]; then
|
||||
echo 'APK v3 is required; add it to PATH or set APK to its executable path.' >&2
|
||||
exit 1
|
||||
fi
|
||||
APK="$(realpath "$APK")"
|
||||
TEST_DIR="$(mktemp -d "${TMPDIR:-/tmp}/agh-apk-test.XXXXXX")"
|
||||
export APK TEST_DIR
|
||||
trap 'rm -rf -- "$TEST_DIR"' EXIT
|
||||
mkdir -p "$TEST_DIR/pkgs" "$TEST_DIR/bin"
|
||||
cd "$TEST_DIR"
|
||||
mkdir -p old/etc/config old/usr/lib/lua/luci/i18n new/etc/config lang/usr/lib/lua/luci/i18n
|
||||
printf original > old/etc/config/AdGuardHome
|
||||
printf translation > old/usr/lib/lua/luci/i18n/AdGuardHome.zh-cn.lmo
|
||||
cp old/etc/config/AdGuardHome new/etc/config/
|
||||
cp old/usr/lib/lua/luci/i18n/* lang/usr/lib/lua/luci/i18n/
|
||||
"$APK" mkpkg -I name:luci-app-adguardhome -I version:99.0-r1 -I arch:noarch -F old -o pkgs/old.apk
|
||||
"$APK" mkpkg -I name:luci-i18n-adguardhome-zh-cn -I version:99.0-r1 -I arch:noarch -I depends:luci-app-adguardhome -F lang -o pkgs/old-lang.apk
|
||||
"$APK" mkpkg -I name:luci-app-adguardhome-tk -I version:2.6.0-r1 -I arch:noarch -I provides:luci-app-adguardhome=2.6.0-r1 -F new -o pkgs/luci-app-adguardhome-tk-2.6.0-r1.apk
|
||||
"$APK" mkpkg -I name:luci-i18n-adguardhome-tk-zh-cn -I version:2.6.0-r1 -I arch:noarch -I depends:luci-app-adguardhome-tk -I provides:luci-i18n-adguardhome-zh-cn=2.6.0-r1 -F lang -o pkgs/luci-i18n-adguardhome-tk-zh-cn-2.6.0-r1.apk
|
||||
# 使用真实安装脚本和 APK 依赖求解器, 隔离网络和路由器服务操作.
|
||||
sed -e 's@/etc/init.d/rpcd reload@true@' -e 's@rm -f /tmp/luci-indexcache /tmp/luci-indexcache.\* /tmp/luci-modulecache/\*@true@' "$REPO_DIR/scripts/install.sh" > install.sh
|
||||
cat > bin/apk <<'SH'
|
||||
#!/bin/sh
|
||||
case "$1" in
|
||||
add|del|upgrade) command=$1; shift; set -- "$command" --no-scripts "$@" ;;
|
||||
esac
|
||||
exec "$APK" --root "$TEST_ROOT" --no-network "$@"
|
||||
SH
|
||||
cat > bin/uclient-fetch <<'SH'
|
||||
#!/bin/sh
|
||||
if [ "$1" = -qO- ]; then
|
||||
printf '{\n"tag_name": "v2.6.0-1",\n"assets": [\n{"name": "luci-app-adguardhome-tk-2.6.0-r1.apk"},\n{"name": "luci-i18n-adguardhome-tk-zh-cn-2.6.0-r1.apk"}\n]}\n'
|
||||
else
|
||||
case "$3" in *luci-i18n*) [ "${FAIL_DOWNLOAD:-0}" != 1 ] || exit 1 ;; esac
|
||||
cp "$TEST_DIR/pkgs/${3##*/}" "$2"
|
||||
fi
|
||||
SH
|
||||
chmod +x bin/*
|
||||
export PATH="$TEST_DIR/bin:$PATH"
|
||||
for scenario in fresh bundled split; do
|
||||
export TEST_ROOT="$TEST_DIR/$scenario-root"
|
||||
if [ "$scenario" = fresh ]; then
|
||||
apk --allow-untrusted --initdb add
|
||||
else
|
||||
apk --allow-untrusted --initdb add "$TEST_DIR/pkgs/old.apk"
|
||||
if [ "$scenario" = split ]; then
|
||||
# 旧版拆分后的主包不再包含翻译文件, 避免构造重复文件所有权.
|
||||
rm old/usr/lib/lua/luci/i18n/AdGuardHome.zh-cn.lmo
|
||||
"$APK" mkpkg -I name:luci-app-adguardhome -I version:99.0-r2 -I arch:noarch -F old -o pkgs/old-split.apk
|
||||
apk --allow-untrusted add "$TEST_DIR/pkgs/old-split.apk" "$TEST_DIR/pkgs/old-lang.apk"
|
||||
fi
|
||||
printf customized > "$TEST_ROOT/etc/config/AdGuardHome"
|
||||
if FAIL_DOWNLOAD=1 sh install.sh zh-cn; then exit 1; fi
|
||||
apk info | grep -qx luci-app-adguardhome
|
||||
test "$(cat "$TEST_ROOT/etc/config/AdGuardHome")" = customized
|
||||
fi
|
||||
sh install.sh zh-cn
|
||||
test "$(apk info | sort)" = "$(printf '%s\n' luci-app-adguardhome-tk luci-i18n-adguardhome-tk-zh-cn | sort)"
|
||||
test "$(wc -l < "$TEST_ROOT/etc/apk/world")" = 2
|
||||
if grep -Eq '^luci-app-adguardhome([<=>~@]|$)|^luci-i18n-adguardhome-zh-cn([<=>~@]|$)' "$TEST_ROOT/etc/apk/world"; then
|
||||
echo "FAIL: legacy world constraints remain after $scenario migration" >&2
|
||||
exit 1
|
||||
fi
|
||||
test -f "$TEST_ROOT/usr/lib/lua/luci/i18n/AdGuardHome.zh-cn.lmo"
|
||||
if [ "$scenario" != fresh ]; then test "$(cat "$TEST_ROOT/etc/config/AdGuardHome")" = customized; fi
|
||||
sh install.sh zh-cn
|
||||
"$APK" mkndx --allow-untrusted --output "$TEST_DIR/pkgs/index.adb" "$TEST_DIR/pkgs/old.apk" "$TEST_DIR/pkgs/luci-app-adguardhome-tk-2.6.0-r1.apk" "$TEST_DIR/pkgs/luci-i18n-adguardhome-tk-zh-cn-2.6.0-r1.apk"
|
||||
apk upgrade --available --allow-untrusted --repository "$TEST_DIR/pkgs/index.adb"
|
||||
test "$(apk info | sort)" = "$(printf '%s\n' luci-app-adguardhome-tk luci-i18n-adguardhome-tk-zh-cn | sort)"
|
||||
echo "PASS: $scenario migration, reinstall and upgrade with higher-version official package"
|
||||
done
|
||||
|
||||
for scenario in fresh old-split new-chinese; do
|
||||
export TEST_ROOT="$TEST_DIR/en-$scenario-root"
|
||||
case "$scenario" in
|
||||
fresh) apk --allow-untrusted --initdb add ;;
|
||||
old-split) apk --allow-untrusted --initdb add "$TEST_DIR/pkgs/old-split.apk" "$TEST_DIR/pkgs/old-lang.apk" ;;
|
||||
new-chinese) apk --allow-untrusted --initdb add "$TEST_DIR/pkgs/luci-app-adguardhome-tk-2.6.0-r1.apk" "$TEST_DIR/pkgs/luci-i18n-adguardhome-tk-zh-cn-2.6.0-r1.apk" ;;
|
||||
esac
|
||||
FAIL_DOWNLOAD=1 sh install.sh en
|
||||
test "$(apk info)" = luci-app-adguardhome-tk
|
||||
test ! -f "$TEST_ROOT/usr/lib/lua/luci/i18n/AdGuardHome.zh-cn.lmo"
|
||||
test "$(wc -l < "$TEST_ROOT/etc/apk/world")" = 1
|
||||
sh install.sh en
|
||||
echo "PASS: English $scenario installs only main package and removes old translations"
|
||||
done
|
||||
@@ -0,0 +1,54 @@
|
||||
import json, os, subprocess, tempfile
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
t=Path(tmp)
|
||||
env={**os.environ, 'PATH':str(t)+':'+os.environ['PATH']}
|
||||
# 仅模拟 SDK 的构建基础设施, 执行真实的安装规则和翻译编译器.
|
||||
(t/'rules.mk').write_text('')
|
||||
(t/'package.mk').write_text('INSTALL_DIR=mkdir -p\n')
|
||||
(t/'main').mkdir(); (t/'lang').mkdir()
|
||||
harness=f'TOPDIR:={t}\nINCLUDE_DIR:={t}\ninclude {ROOT}/Makefile\nall:\n\t$(call Package/luci-app-adguardhome-tk/install,{t}/main)\n\t$(call Package/luci-i18n-adguardhome-tk-zh-cn/install,{t}/lang)\n'
|
||||
(t/'test.mk').write_text(harness)
|
||||
subprocess.run(['make','-s','-f',str(t/'test.mk')],cwd=ROOT,env=env,check=True,stdout=subprocess.DEVNULL,timeout=30)
|
||||
assert not list((t/'main').rglob('*.lmo'))
|
||||
assert (t/'main/etc/init.d/AdGuardHome').stat().st_mode & 0o111
|
||||
assert (t/'lang/usr/lib/lua/luci/i18n/AdGuardHome.zh-cn.lmo').stat().st_size > 0
|
||||
assert len([p for p in (t/'lang').rglob('*') if p.is_file()]) == 2
|
||||
print('PASS: separated payloads, translation compilation, executable permissions')
|
||||
# 模拟下载和安装命令, 验证不同版本的附件选择与下载失败行为.
|
||||
script=(ROOT/'scripts/install.sh').read_text().replace('/etc/init.d/rpcd reload', 'true').replace('rm -f /tmp/luci-indexcache /tmp/luci-indexcache.* /tmp/luci-modulecache/*', 'true')
|
||||
(t/'install.sh').write_text(script)
|
||||
(t/'uclient-fetch').write_text('''#!/bin/sh
|
||||
if [ "$1" = -qO- ]; then cat "$TEST_DIR/release.json"; exit; fi
|
||||
case "$3" in *luci-i18n*) [ "$FAIL_TRANSLATION" != 1 ] || exit 1 ;; esac
|
||||
printf '%s' "$3" > "$2"
|
||||
''')
|
||||
(t/'apk').write_text('''#!/bin/sh
|
||||
shift 2
|
||||
for file in "$@"; do cat "$file"; echo; done > "$TEST_DIR/installed"
|
||||
''')
|
||||
for name in ['uclient-fetch','apk']: (t/name).chmod(0o755)
|
||||
for split,fail in [(False,False),(True,False),(True,True)]:
|
||||
(t/'installed').unlink(missing_ok=True)
|
||||
(t/'release.json').write_text(json.dumps({'tag_name':'v2.6.0-1','assets':[{'name':'luci-i18n-adguardhome-zh-cn-2.6.0-r1.apk'}] if split else []},indent=2))
|
||||
result=subprocess.run(['sh',str(t/'install.sh'),'zh-cn'],env={**env,'TEST_DIR':tmp,'FAIL_TRANSLATION':str(int(fail))},capture_output=True,text=True,timeout=30)
|
||||
if fail:
|
||||
assert result.returncode != 0 and not (t/'installed').exists(), result.stdout
|
||||
else:
|
||||
assert result.returncode == 0, result.stderr
|
||||
installed=(t/'installed').read_text().splitlines()
|
||||
assert len(installed)==(2 if split else 1), installed
|
||||
assert all('v2.6.0-1/' in url and url.endswith('2.6.0-r1.apk') for url in installed)
|
||||
print('PASS: legacy release, split release, failed translation download aborts installation')
|
||||
collect=['bash',str(ROOT/'scripts/collect-apks.sh')]
|
||||
(t/'sdk/bin/packages').mkdir(parents=True)
|
||||
for package in ['luci-app-adguardhome-tk','luci-i18n-adguardhome-tk-zh-cn']:
|
||||
(t/f'sdk/bin/packages/{package}-2.6.0-r1.apk').touch()
|
||||
subprocess.run(collect,env={**env,'SDK_DIR':str(t/'sdk'),'GITHUB_WORKSPACE':tmp,'PKG_DIR_NAME':'luci-app-adguardhome-tk'},check=True,timeout=30)
|
||||
assert len(list((t/'dist').glob('*.apk')))==2
|
||||
(t/'sdk/bin/packages/luci-i18n-adguardhome-tk-zh-cn-2.6.0-r1.apk').unlink()
|
||||
result=subprocess.run(collect,env={**env,'SDK_DIR':str(t/'sdk'),'GITHUB_WORKSPACE':tmp,'PKG_DIR_NAME':'luci-app-adguardhome-tk'},capture_output=True,timeout=30)
|
||||
assert result.returncode != 0
|
||||
print('PASS: collects both APKs, rejects missing translation')
|
||||
@@ -0,0 +1,113 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const assert = require('assert/strict');
|
||||
const test = require('node:test');
|
||||
const root = path.resolve(__dirname, '..');
|
||||
const source = fs.readFileSync(path.join(root, 'root/www/luci-static/resources/view/adguardhome/status.js'), 'utf8');
|
||||
let now = 10000;
|
||||
const storage = new Map();
|
||||
let info = { mode: 'dnsmasq-upstream', enabled: true, applied_mode: 'dnsmasq-upstream', applied_enabled: true, redirected: true, busy: false, binpath: '/core' };
|
||||
let running = true, fail = false, held = null, requests = 0;
|
||||
function harness() {
|
||||
const nodes = [], polls = [];
|
||||
const module = new Function('baseclass', 'rpc', 'poll', 'E', '_', 'sessionStorage', 'L', source)(
|
||||
{ extend: x => x },
|
||||
{ declare: spec => () => {
|
||||
if (spec.method === 'getCoreInfo') return Promise.resolve({ core_exists: true, config_exists: true, version: 'test' });
|
||||
if (spec.method === 'getRedirectStatus') {
|
||||
requests++;
|
||||
return held || (fail ? Promise.reject(Error('offline')) : Promise.resolve({ ...info }));
|
||||
}
|
||||
return Promise.resolve({ AdGuardHome: { instances: { instance1: { running, command: ['/core'] } } } });
|
||||
} },
|
||||
{ add: (fn, interval) => polls.push({ fn, interval }) },
|
||||
(tag, attrs, children) => { const n = { ...attrs, style: {}, textContent: children }; nodes.push(n); return n; },
|
||||
x => x,
|
||||
{ getItem: key => storage.get(key) || null, setItem: (key, value) => storage.set(key, value), removeItem: key => storage.delete(key) },
|
||||
{ url: (...parts) => '/cgi-bin/luci/' + parts.join('/') }
|
||||
);
|
||||
return { page: module.render(), nodes, polls, redirect: () => nodes[2].textContent };
|
||||
}
|
||||
const flush = async () => { for (let i = 0; i < 8; i++) await Promise.resolve(); };
|
||||
test('mode switching, timeout recovery and stale RPC replies', { timeout: 5000 }, async t => {
|
||||
const realNow = Date.now;
|
||||
Date.now = () => now;
|
||||
t.after(() => { Date.now = realNow; });
|
||||
let h = harness(); await flush();
|
||||
assert.match(h.redirect(), /Run as dnsmasq upstream server/);
|
||||
const before = requests;
|
||||
now += 1000; await h.polls[0].fn();
|
||||
assert.equal(requests, before, 'normal status does not query each second');
|
||||
now += 2000; await h.polls[0].fn();
|
||||
assert.equal(requests, before + 1);
|
||||
h.page.beginSwitch({ mode: 'exchange', enabled: true });
|
||||
assert.equal(h.redirect(), 'Switching');
|
||||
await h.page.refresh();
|
||||
assert.match(h.redirect(), /Switching/, 'old active redirect must not satisfy new mode');
|
||||
info.mode = info.applied_mode = 'exchange'; info.busy = true;
|
||||
await h.page.refresh();
|
||||
assert.match(h.redirect(), /Switching/, 'held mode lock cannot count as success');
|
||||
info.busy = false; info.redirected = false;
|
||||
await h.page.refresh();
|
||||
assert.match(h.redirect(), /Switching/, 'new UCI mode without redirect flag is not active');
|
||||
info.redirected = true; running = false;
|
||||
await h.page.refresh();
|
||||
assert.match(h.redirect(), /Switching/, 'redirect flag alone cannot imply service is running');
|
||||
assert.equal(h.nodes[1].textContent, 'NOT RUNNING');
|
||||
running = true;
|
||||
await h.page.refresh(); assert.match(h.redirect(), /Switching/, 'requires stable samples');
|
||||
await h.page.refresh(); assert.match(h.redirect(), /^Use port 53 instead of dnsmasq/);
|
||||
assert.equal(storage.size, 0);
|
||||
h.page.beginSwitch({ mode: 'redirect', enabled: true });
|
||||
now += 31000; fail = true;
|
||||
await h.page.refresh(); assert.match(h.redirect(), /Unable to read switch status/);
|
||||
assert.equal(h.nodes[1].textContent, 'Status unavailable');
|
||||
fail = false;
|
||||
h = harness(); await flush(); assert.match(h.redirect(), /not completed/, 'reload preserves pending timeout');
|
||||
info.mode = info.applied_mode = 'redirect';
|
||||
await h.page.refresh(); await h.page.refresh();
|
||||
assert.match(h.redirect(), /^Forward port 53 requests through the firewall/);
|
||||
h.page.beginSwitch({ mode: 'none', enabled: true });
|
||||
info.mode = info.applied_mode = 'none'; info.redirected = false;
|
||||
await h.page.refresh(); await h.page.refresh(); assert.equal(h.redirect(), 'Do not handle DNS');
|
||||
h.page.beginSwitch({ mode: 'none', enabled: false });
|
||||
info.enabled = info.applied_enabled = false; running = false;
|
||||
await h.page.refresh(); await h.page.refresh(); assert.match(h.redirect(), /Disabled/);
|
||||
let resolveOld; held = new Promise(resolve => resolveOld = resolve);
|
||||
const old = h.page.refresh();
|
||||
h.page.beginSwitch({ mode: 'exchange', enabled: true });
|
||||
resolveOld({ ...info }); held = null; await old;
|
||||
assert.match(h.redirect(), /Switching/, 'in-flight status cannot overwrite new action');
|
||||
await h.page.cancelSwitch(); assert.match(h.redirect(), /Disabled/);
|
||||
assert.equal(storage.size, 0);
|
||||
|
||||
const baseSource = fs.readFileSync(path.join(root, 'root/www/luci-static/resources/view/adguardhome/base.js'), 'utf8');
|
||||
let applied = 0, cancelled = 0, target;
|
||||
const base = new Function('view', 'rpc', 'ui', baseSource)(
|
||||
{ extend: x => x }, { declare: () => () => Promise.resolve({}) },
|
||||
{ changes: { apply: checked => { assert.equal(checked, true); applied++; } } }
|
||||
);
|
||||
base.redirectOption = { formvalue: () => 'exchange' };
|
||||
base.enabledOption = { formvalue: () => '1' };
|
||||
base.sharedStatus = { beginSwitch: value => target = value, cancelSwitch: () => cancelled++ };
|
||||
base.handleSave = () => Promise.reject(Error('invalid port'));
|
||||
await assert.rejects(base.handleSaveApply(null, '0'), /invalid port/);
|
||||
assert.equal(applied, 0); assert.equal(cancelled, 1);
|
||||
assert.deepEqual(target, { mode: 'exchange', enabled: true });
|
||||
base.handleSave = () => Promise.resolve();
|
||||
await base.handleSaveApply(null, '0');
|
||||
assert.equal(applied, 1);
|
||||
|
||||
const rpcSource = fs.readFileSync(path.join(root, 'root/usr/share/rpcd/ucode/luci.adguardhome'), 'utf8').replace(/^#!.*\n/, '').replace(/^import .*;\n/gm, '');
|
||||
const config = { redirect: 'exchange', enabled: '1', old_redirect: ['exchange'], old_enabled: ['1'], binpath: '/core' };
|
||||
let lock = 2;
|
||||
const api = new Function('cursor', 'type', 'trim', 'readfile', 'system', 'die', rpcSource)(
|
||||
() => ({ get: (pkg, section, name) => config[name], unload() {} }),
|
||||
x => Array.isArray(x) ? 'array' : typeof x, x => x.trim(), () => '1', () => lock,
|
||||
s => { throw Error(s); }
|
||||
)['luci.adguardhome'];
|
||||
const result = api.getRedirectStatus.call();
|
||||
assert.equal(result.applied_mode, 'exchange'); assert.equal(result.applied_enabled, true); assert.equal(result.busy, true);
|
||||
lock = 0; assert.equal(api.getRedirectStatus.call().busy, false);
|
||||
lock = 1; assert.throws(() => api.getRedirectStatus.call());
|
||||
});
|
||||
@@ -0,0 +1,201 @@
|
||||
"""用隔离的 UCI 模拟器执行真实启动脚本, 不修改路由器配置."""
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
DNS = 'dhcp.@dnsmasq[0].'
|
||||
BACKUP = 'AdGuardHome.dnsmasq_backup'
|
||||
|
||||
|
||||
class DnsmasqUpstreamTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.tmp = tempfile.TemporaryDirectory(prefix='agh-dns-test-')
|
||||
self.addCleanup(self.tmp.cleanup)
|
||||
self.path = Path(self.tmp.name)
|
||||
self.state_file = self.path / 'uci.json'
|
||||
self.env = dict(os.environ, UCI_STATE=str(self.state_file),
|
||||
TEST_DIR=str(self.path), PATH=str(self.path) + ':/usr/bin:/bin')
|
||||
stub = self.path / 'uci'
|
||||
stub.write_text('''#!/usr/bin/python3
|
||||
import json, os, sys
|
||||
from pathlib import Path
|
||||
p=Path(os.environ['UCI_STATE']); state=json.loads(p.read_text())
|
||||
args=[x for x in sys.argv[1:] if x != '-q']; op=args[0]
|
||||
arg=args[1] if len(args)>1 else ''
|
||||
key,_,value=arg.partition('=')
|
||||
key=key.replace('AdGuardHome.@AdGuardHome[0]', 'AdGuardHome.AdGuardHome')
|
||||
if op=='export':
|
||||
print(json.dumps({k:v for k,v in state.items() if k.startswith(key+'.')}, sort_keys=True)); sys.exit(0)
|
||||
if op=='get':
|
||||
if key not in state: sys.exit(1)
|
||||
print(' '.join(state[key]) if isinstance(state[key],list) else state[key])
|
||||
sys.exit(0)
|
||||
if op=='set': state[key]=value
|
||||
elif op=='delete':
|
||||
matched=[k for k in state if k==key or k.startswith(key+'.')]
|
||||
if not matched: sys.exit(1)
|
||||
for k in matched: del state[k]
|
||||
elif op=='add_list':
|
||||
if key not in state: state[key]=[]
|
||||
if not isinstance(state[key],list): state[key]=[state[key]]
|
||||
state[key].append(value)
|
||||
elif op=='del_list':
|
||||
if key not in state: sys.exit(1)
|
||||
state[key]=[x for x in state[key] if x!=value]
|
||||
if not state[key]: del state[key]
|
||||
elif op=='commit':
|
||||
if os.environ.get('FAIL_COMMIT')==key: sys.exit(1)
|
||||
elif op=='revert':
|
||||
for k in list(state):
|
||||
if k==key or k.startswith(key+'.'): del state[k]
|
||||
else: sys.exit('unsupported UCI operation: '+op)
|
||||
p.write_text(json.dumps(state))
|
||||
''')
|
||||
stub.chmod(0o755)
|
||||
source = (ROOT / 'root/etc/init.d/AdGuardHome').read_text()
|
||||
begin = source.index('save_dnsmasq_upstream_config()')
|
||||
end = source.index('\ndo_redirect() {\n', source.index('_do_redirect()'))
|
||||
self.functions = source[begin:end]
|
||||
self.functions = self.functions.replace('/etc/init.d/dnsmasq restart', 'restart_dnsmasq')
|
||||
self.functions = self.functions.replace('/var/run/AdGredir', str(self.path / 'redirect_flag'))
|
||||
self.functions = self.functions.replace('/var/lock/AdGuardHome-redirect.lock', str(self.path / 'redirect.lock'))
|
||||
self.functions += '''
|
||||
restart_dnsmasq() { echo restart >> "$TEST_DIR/restarts"; [ "$FAIL_RESTART" != 1 ]; }
|
||||
logger() { :; }
|
||||
config_get() {
|
||||
local value
|
||||
value="$(uci -q get "AdGuardHome.$2.$3")" || value="$4"
|
||||
export "$1=$value"
|
||||
}
|
||||
config_editor() { echo "$DNS_PORT"; }
|
||||
CONFIGURATION=AdGuardHome
|
||||
'''
|
||||
|
||||
def seed(self, **options):
|
||||
self.state_file.write_text(json.dumps({DNS+k: v for k, v in options.items()}))
|
||||
|
||||
def state(self):
|
||||
return json.loads(self.state_file.read_text())
|
||||
|
||||
def dns(self):
|
||||
return {k[len(DNS):]: v for k, v in self.state().items() if k.startswith(DNS)}
|
||||
|
||||
def run_shell(self, command, expected=0, **env):
|
||||
result = subprocess.run(['sh', '-c', self.functions + '\n' + command],
|
||||
env=dict(self.env, **env), capture_output=True, text=True, timeout=30)
|
||||
self.assertEqual(result.returncode, expected, result.stderr + result.stdout)
|
||||
|
||||
def test_round_trip_preserves_servers_and_custom_options(self):
|
||||
original = dict(server=['9.9.9.9', '/internal/192.168.1.2', '127.0.0.1#17450'],
|
||||
resolvfile='/etc/custom resolver.conf', noresolv='0', port='53')
|
||||
self.seed(**original)
|
||||
self.run_shell('set_forward_dnsmasq 1745')
|
||||
self.assertEqual(self.dns()['server'], ['127.0.0.1#1745', '/internal/192.168.1.2'])
|
||||
self.assertEqual(self.dns()['resolvfile'], original['resolvfile'])
|
||||
self.assertEqual(self.dns()['noresolv'], '1')
|
||||
self.run_shell('stop_forward_dnsmasq 1745')
|
||||
self.assertEqual(self.dns(), original)
|
||||
self.assertNotIn(BACKUP, self.state())
|
||||
|
||||
def test_absent_options_stay_absent(self):
|
||||
self.seed(port='53')
|
||||
self.run_shell('set_forward_dnsmasq 1745; stop_forward_dnsmasq 1745')
|
||||
self.assertEqual(self.dns(), {'port': '53'})
|
||||
|
||||
def test_explicit_empty_and_noresolv_one_preserved(self):
|
||||
original = dict(resolvfile='', noresolv='1', server=['1.1.1.1'])
|
||||
self.seed(**original)
|
||||
self.run_shell('set_forward_dnsmasq 1745; stop_forward_dnsmasq 1745')
|
||||
self.assertEqual(self.dns(), original)
|
||||
|
||||
def test_repeated_start_and_port_change_do_not_replace_snapshot(self):
|
||||
original = dict(server=['8.8.8.8'], noresolv='0')
|
||||
self.seed(**original)
|
||||
self.run_shell('set_forward_dnsmasq 1745')
|
||||
snapshot = {k:v for k,v in self.state().items() if k.startswith(BACKUP)}
|
||||
self.run_shell('set_forward_dnsmasq 1745; set_forward_dnsmasq 5353')
|
||||
self.assertEqual({k:v for k,v in self.state().items() if k.startswith(BACKUP)}, snapshot)
|
||||
self.assertEqual(self.dns()['server'], ['127.0.0.1#5353'])
|
||||
self.assertEqual(len((self.path / 'restarts').read_text().splitlines()), 2)
|
||||
self.run_shell('stop_forward_dnsmasq 5353; stop_forward_dnsmasq 5353')
|
||||
self.assertEqual(self.dns(), original)
|
||||
|
||||
def test_domain_rules_kept_but_catch_all_removed(self):
|
||||
servers = ['/#/1.1.1.1', '/example/#/8.8.8.8', '9.9.9.9',
|
||||
'/internal/192.168.1.2', '/*.test/192.168.1.3', '//192.168.1.4', '/lan/']
|
||||
self.seed(server=servers)
|
||||
self.run_shell('set_forward_dnsmasq 1745')
|
||||
self.assertEqual(self.dns()['server'], ['127.0.0.1#1745'] + servers[3:])
|
||||
self.run_shell('stop_forward_dnsmasq 1745')
|
||||
self.assertEqual(self.dns()['server'], servers)
|
||||
|
||||
def test_legacy_endpoint_removed_in_any_position_without_prefix_match(self):
|
||||
self.seed(server=['9.9.9.9', '127.0.0.1#17450', '127.0.0.1#1745'], noresolv='1')
|
||||
self.run_shell('stop_forward_dnsmasq 1745')
|
||||
self.assertEqual(self.dns()['server'], ['9.9.9.9', '127.0.0.1#17450'])
|
||||
self.run_shell('stop_forward_dnsmasq 1745')
|
||||
self.assertEqual(self.dns()['server'], ['9.9.9.9', '127.0.0.1#17450'])
|
||||
|
||||
def test_legacy_upgrade_does_not_save_old_plugin_endpoint(self):
|
||||
self.seed(server=['/internal/192.168.1.2', '127.0.0.1#1745'], noresolv='1')
|
||||
self.run_shell('set_forward_dnsmasq 1745 dnsmasq-upstream 1 1745')
|
||||
self.assertEqual(self.state()[BACKUP+'.server'], ['/internal/192.168.1.2'])
|
||||
self.run_shell('stop_forward_dnsmasq 1745')
|
||||
self.assertEqual(self.dns()['server'], ['/internal/192.168.1.2'])
|
||||
self.assertNotIn('noresolv', self.dns())
|
||||
self.assertIn('resolvfile', self.dns())
|
||||
|
||||
def test_snapshot_commit_failure_does_not_change_dns(self):
|
||||
original = dict(server=['9.9.9.9'], noresolv='0')
|
||||
self.seed(**original)
|
||||
self.run_shell('set_forward_dnsmasq 1745', expected=1, FAIL_COMMIT='AdGuardHome')
|
||||
self.assertEqual(self.dns(), original)
|
||||
self.assertFalse((self.path / 'restarts').exists())
|
||||
|
||||
def test_restore_restart_failure_keeps_snapshot_for_retry(self):
|
||||
self.seed(server=['9.9.9.9'])
|
||||
self.run_shell('set_forward_dnsmasq 1745')
|
||||
self.run_shell('stop_forward_dnsmasq 1745', expected=1, FAIL_RESTART='1')
|
||||
self.assertEqual(self.state()[BACKUP+'.ready'], '1')
|
||||
self.run_shell('stop_forward_dnsmasq 1745')
|
||||
self.assertNotIn(BACKUP, self.state())
|
||||
self.assertEqual(self.dns(), {'server': ['9.9.9.9']})
|
||||
|
||||
def test_mode_switch_and_disable_through_redirect_dispatcher(self):
|
||||
self.seed(server=['9.9.9.9'], noresolv='0', port='53')
|
||||
self.run_shell('uci set AdGuardHome.AdGuardHome.redirect=dnsmasq-upstream; _do_redirect 1', DNS_PORT='1745')
|
||||
self.assertEqual(self.dns()['server'], ['127.0.0.1#1745'])
|
||||
self.run_shell('_do_redirect 1', DNS_PORT='5353')
|
||||
self.assertEqual(self.dns()['server'], ['127.0.0.1#5353'])
|
||||
self.run_shell('uci set AdGuardHome.AdGuardHome.redirect=none; _do_redirect 1', DNS_PORT='5353')
|
||||
self.assertEqual(self.dns(), {'server':['9.9.9.9'], 'noresolv':'0', 'port':'53'})
|
||||
self.run_shell('uci set AdGuardHome.AdGuardHome.redirect=dnsmasq-upstream; _do_redirect 1', DNS_PORT='1745')
|
||||
self.run_shell('_do_redirect 0', expected=1, DNS_PORT='1745')
|
||||
self.assertEqual(self.dns(), {'server':['9.9.9.9'], 'noresolv':'0', 'port':'53'})
|
||||
|
||||
def test_dispatcher_preserves_preexisting_matching_endpoint(self):
|
||||
original = {'server': ['127.0.0.1#1745', '9.9.9.9'], 'port': '53'}
|
||||
self.seed(**original)
|
||||
self.run_shell('uci set AdGuardHome.AdGuardHome.redirect=dnsmasq-upstream; _do_redirect 1', DNS_PORT='1745')
|
||||
self.run_shell('_do_redirect 1', DNS_PORT='5353')
|
||||
self.assertEqual(self.state()[BACKUP+'.server'], original['server'])
|
||||
self.run_shell('_do_redirect 0', expected=1, DNS_PORT='5353')
|
||||
self.assertEqual(self.dns(), original)
|
||||
self.run_shell('uci set AdGuardHome.AdGuardHome.redirect=none; _do_redirect 0', expected=1, DNS_PORT='5353')
|
||||
self.assertEqual(self.dns(), original)
|
||||
|
||||
def test_overlapping_starts_keep_original_snapshot(self):
|
||||
self.seed(server=['9.9.9.9'], port='53')
|
||||
self.run_shell('uci set AdGuardHome.AdGuardHome.redirect=dnsmasq-upstream; _do_redirect 1 & first=$!; _do_redirect 1 & second=$!; wait "$first" && wait "$second"', DNS_PORT='1745')
|
||||
self.assertEqual(self.state()[BACKUP+'.server'], ['9.9.9.9'])
|
||||
self.assertEqual(self.dns()['server'], ['127.0.0.1#1745'])
|
||||
self.run_shell('_do_redirect 0', expected=1, DNS_PORT='1745')
|
||||
self.assertEqual(self.dns(), {'server': ['9.9.9.9'], 'port': '53'})
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -0,0 +1,238 @@
|
||||
"""通过端口占用模拟器执行真实启动脚本, 验证服务交接顺序."""
|
||||
import subprocess
|
||||
import unittest
|
||||
import test_dnsmasq_upstream as dns
|
||||
|
||||
|
||||
class ServiceLifecycleTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.h = dns.DnsmasqUpstreamTests('runTest')
|
||||
self.h.setUp()
|
||||
self.addCleanup(self.h.doCleanups)
|
||||
self.path = self.h.path
|
||||
source = (dns.ROOT / 'root/etc/init.d/AdGuardHome').read_text()
|
||||
lifecycle = source[source.index('start_service() {'):source.index('\nboot() {')]
|
||||
lifecycle = lifecycle.replace('/var/run/', str(self.path) + '/')
|
||||
lifecycle = lifecycle.replace('/lib/upgrade/keep.d/luci-app-adguardhome', str(self.path / 'keep'))
|
||||
self.h.functions += '\n' + lifecycle + '''
|
||||
config_load() { :; }
|
||||
config_get_bool() { config_get "$@"; }
|
||||
config_editor() {
|
||||
if [ -n "$4" ]; then cat "$TEST_DIR/yaml-port"; return; fi
|
||||
[ ! -f "$TEST_DIR/live-port" ] || { echo 'editing live config' >&2; return 1; }
|
||||
printf '%s' "$2" > "$TEST_DIR/yaml-port"
|
||||
echo "yaml:$2" >> "$TEST_DIR/events"
|
||||
}
|
||||
stop_core() {
|
||||
[ "$FAIL_STOP" != 1 ] || return 1
|
||||
if [ -f "$TEST_DIR/live-port" ]; then
|
||||
# 模拟核心正常退出时将内存中的配置写回文件.
|
||||
cat "$TEST_DIR/live-port" > "$TEST_DIR/yaml-port"
|
||||
rm "$TEST_DIR/live-port"
|
||||
echo stopped >> "$TEST_DIR/events"
|
||||
fi
|
||||
}
|
||||
restart_dnsmasq() {
|
||||
local port="$(uci -q get dhcp.@dnsmasq[0].port)"
|
||||
if [ -f "$TEST_DIR/live-port" ] && [ "$(cat "$TEST_DIR/live-port")" = "$port" ]; then
|
||||
echo 'Address in use' >&2
|
||||
return 1
|
||||
fi
|
||||
echo "dnsmasq:$port" >> "$TEST_DIR/events"
|
||||
[ "$FAIL_RESTART" != 1 ]
|
||||
}
|
||||
get_filesystem() { echo tmpfs; }
|
||||
get_tz() { SET_TZ=''; }
|
||||
procd_open_instance() { :; }
|
||||
procd_set_param() { :; }
|
||||
procd_close_instance() {
|
||||
local port="$(cat "$TEST_DIR/yaml-port")"
|
||||
[ "$port" != "$(uci -q get dhcp.@dnsmasq[0].port)" ] || return 1
|
||||
printf '%s' "$port" > "$TEST_DIR/live-port"
|
||||
echo "started:$port" >> "$TEST_DIR/events"
|
||||
}
|
||||
ubus() { echo "ubus:$3" >> "$TEST_DIR/events"; }
|
||||
start() { start_service; }
|
||||
'''
|
||||
(self.path / 'core').touch()
|
||||
(self.path / 'config.yaml').touch()
|
||||
(self.path / 'yaml-port').write_text('3053')
|
||||
self.h.seed(server=['9.9.9.9'], noresolv='0', port='53')
|
||||
self.h.run_shell('''
|
||||
uci set AdGuardHome.AdGuardHome.enabled=1
|
||||
uci set AdGuardHome.AdGuardHome.configpath="$TEST_DIR/config.yaml"
|
||||
uci set AdGuardHome.AdGuardHome.binpath="$TEST_DIR/core"
|
||||
uci set AdGuardHome.AdGuardHome.workdir="$TEST_DIR/work"
|
||||
uci set AdGuardHome.AdGuardHome.redirect=dnsmasq-upstream
|
||||
_do_redirect 1 0
|
||||
''')
|
||||
(self.path / 'live-port').write_text('3053')
|
||||
(self.path / 'events').write_text('')
|
||||
|
||||
def events(self):
|
||||
return (self.path / 'events').read_text().splitlines()
|
||||
|
||||
def exchange(self):
|
||||
self.h.run_shell('uci set AdGuardHome.AdGuardHome.redirect=exchange; reload_service')
|
||||
self.assertEqual((self.path / 'live-port').read_text(), '53')
|
||||
self.assertEqual(self.h.dns()['port'], '3053')
|
||||
|
||||
def test_upstream_to_exchange_releases_both_ports_before_start(self):
|
||||
self.exchange()
|
||||
events = self.events()
|
||||
self.assertLess(events.index('stopped'), events.index('yaml:53'))
|
||||
self.assertLess(events.index('yaml:53'), events.index('dnsmasq:3053'))
|
||||
self.assertLess(events.index('dnsmasq:3053'), events.index('started:53'))
|
||||
self.assertNotIn('ubus:event', events)
|
||||
self.assertEqual(sum(e.startswith('dnsmasq:') for e in events), 1)
|
||||
|
||||
def test_exchange_to_upstream_releases_53_before_dnsmasq(self):
|
||||
self.exchange()
|
||||
(self.path / 'events').write_text('')
|
||||
self.h.run_shell('uci set AdGuardHome.AdGuardHome.redirect=dnsmasq-upstream; reload_service')
|
||||
events = self.events()
|
||||
self.assertLess(events.index('stopped'), events.index('dnsmasq:53'))
|
||||
self.assertLess(events.index('dnsmasq:53'), events.index('started:3053'))
|
||||
self.assertEqual(self.h.dns()['server'], ['127.0.0.1#3053'])
|
||||
self.assertNotIn('ubus:event', events)
|
||||
self.assertEqual(sum(e.startswith('dnsmasq:') for e in events), 1)
|
||||
|
||||
def test_stopping_exchange_does_not_schedule_another_start(self):
|
||||
self.exchange()
|
||||
(self.path / 'events').write_text('')
|
||||
self.h.run_shell('stop_service')
|
||||
self.assertFalse((self.path / 'live-port').exists())
|
||||
self.assertEqual(self.h.dns()['port'], '53')
|
||||
self.assertNotIn('ubus:event', self.events())
|
||||
|
||||
def test_failed_stop_does_not_modify_ports(self):
|
||||
self.h.run_shell('uci set AdGuardHome.AdGuardHome.redirect=exchange; reload_service',
|
||||
expected=1, FAIL_STOP='1')
|
||||
self.assertEqual((self.path / 'yaml-port').read_text(), '3053')
|
||||
self.assertEqual(self.h.dns()['port'], '53')
|
||||
self.assertEqual(self.events(), [])
|
||||
|
||||
def test_failed_dnsmasq_restart_does_not_launch_core(self):
|
||||
self.h.run_shell('uci set AdGuardHome.AdGuardHome.redirect=exchange; reload_service',
|
||||
expected=1, FAIL_RESTART='1')
|
||||
self.assertFalse((self.path / 'live-port').exists())
|
||||
self.assertFalse(any(x.startswith('started:') for x in self.events()))
|
||||
|
||||
def test_crashed_core_is_started_with_prepared_ports(self):
|
||||
self.exchange()
|
||||
(self.path / 'live-port').unlink()
|
||||
(self.path / 'events').write_text('')
|
||||
self.h.run_shell('reload_service')
|
||||
self.assertEqual((self.path / 'live-port').read_text(), '53')
|
||||
self.assertEqual(self.events(), ['started:53'])
|
||||
|
||||
def test_retry_after_committed_port_but_failed_handoff(self):
|
||||
self.h.run_shell('uci set AdGuardHome.AdGuardHome.redirect=exchange; reload_service',
|
||||
expected=1, FAIL_RESTART='1')
|
||||
self.assertEqual(self.h.dns()['port'], '3053')
|
||||
self.assertEqual((self.path / 'yaml-port').read_text(), '53')
|
||||
self.assertEqual(self.h.state().get(dns.BACKUP + '.ready'), '1')
|
||||
(self.path / 'events').write_text('')
|
||||
self.h.run_shell('reload_service')
|
||||
self.assertEqual(self.events(), ['dnsmasq:3053', 'started:53'])
|
||||
self.assertNotIn(dns.BACKUP, self.h.state())
|
||||
|
||||
|
||||
def test_config_watcher_queues_reload_only_after_dnsmasq_handoff(self):
|
||||
self.h.run_shell('uci set AdGuardHome.AdGuardHome.redirect=exchange; _do_redirect 1')
|
||||
events = self.events()
|
||||
self.assertLess(events.index('dnsmasq:3053'), events.index('ubus:event'))
|
||||
self.assertEqual(sum(e.startswith('dnsmasq:') for e in events), 1)
|
||||
|
||||
def test_repeated_round_trips_keep_ports_and_original_upstreams(self):
|
||||
for _ in range(3):
|
||||
self.exchange()
|
||||
self.h.run_shell('uci set AdGuardHome.AdGuardHome.redirect=dnsmasq-upstream; reload_service')
|
||||
self.assertEqual((self.path / 'live-port').read_text(), '3053')
|
||||
self.assertEqual(self.h.dns()['port'], '53')
|
||||
self.assertEqual(self.h.dns()['server'], ['127.0.0.1#3053'])
|
||||
self.h.run_shell('stop_service')
|
||||
self.assertEqual(self.h.dns()['server'], ['9.9.9.9'])
|
||||
|
||||
|
||||
|
||||
class ProcessHandoffTests(unittest.TestCase):
|
||||
def test_stop_wait_start_does_not_reuse_a_live_jail(self):
|
||||
source = (dns.ROOT / 'root/etc/init.d/AdGuardHome').read_text()
|
||||
helpers = source[source.index('restart_dnsmasq()'):source.index('save_dnsmasq_upstream_config()')]
|
||||
helpers = helpers.replace('/etc/init.d/dnsmasq', 'dnsmasq_command')
|
||||
script = helpers + """
|
||||
ubus() { echo '{}'; }
|
||||
jsonfilter() { cat >/dev/null; echo 1234; }
|
||||
old_jail=1
|
||||
dnsmasq_command() {
|
||||
echo "$1"
|
||||
if [ "$1" = start ]; then [ "$old_jail" = 0 ] || return 1; fi
|
||||
}
|
||||
wait_for_pid_exit() { echo "wait:$1"; old_jail=0; }
|
||||
wait_for_dns_port_release() { echo "port:$1"; }
|
||||
restart_dnsmasq 53
|
||||
"""
|
||||
result = subprocess.run(['busybox', 'ash', '-c', script], capture_output=True, text=True, timeout=10)
|
||||
self.assertEqual(result.returncode, 0, result.stderr)
|
||||
self.assertEqual(result.stdout.splitlines(), ['stop', 'wait:1234', 'port:53', 'start', 'port:53'])
|
||||
|
||||
def test_failed_jail_stop_does_not_register_a_replacement(self):
|
||||
source = (dns.ROOT / 'root/etc/init.d/AdGuardHome').read_text()
|
||||
helpers = source[source.index('restart_dnsmasq()'):source.index('save_dnsmasq_upstream_config()')]
|
||||
helpers = helpers.replace('/etc/init.d/dnsmasq', 'dnsmasq_command')
|
||||
script = helpers + """
|
||||
ubus() { echo '{}'; }
|
||||
jsonfilter() { cat >/dev/null; echo 1234; }
|
||||
dnsmasq_command() { echo "$1"; }
|
||||
wait_for_pid_exit() { return 1; }
|
||||
logger() { :; }
|
||||
restart_dnsmasq 53
|
||||
"""
|
||||
result = subprocess.run(['busybox', 'ash', '-c', script], capture_output=True, text=True, timeout=10)
|
||||
self.assertEqual(result.returncode, 1, result.stderr)
|
||||
self.assertEqual(result.stdout.splitlines(), ['stop'])
|
||||
|
||||
def test_actual_dns_socket_handoff(self):
|
||||
import socket
|
||||
import threading
|
||||
source = (dns.ROOT / 'root/etc/init.d/AdGuardHome').read_text()
|
||||
helper = source[source.index('wait_for_dns_port_release()'):source.index('restart_dnsmasq()')]
|
||||
for family in [socket.AF_INET, socket.AF_INET6]:
|
||||
for kind in [socket.SOCK_STREAM, socket.SOCK_DGRAM]:
|
||||
with self.subTest(family=family, kind=kind):
|
||||
sock = socket.socket(family, kind)
|
||||
self.addCleanup(sock.close)
|
||||
try:
|
||||
sock.bind(('127.0.0.1' if family == socket.AF_INET else '::1', 0))
|
||||
except OSError:
|
||||
if family == socket.AF_INET6:
|
||||
continue
|
||||
raise
|
||||
if kind == socket.SOCK_STREAM:
|
||||
sock.listen()
|
||||
port = sock.getsockname()[1]
|
||||
blocked = subprocess.run(['sh', '-c', helper + f'\nsleep() {{ :; }}\nwait_for_dns_port_release {port}'], capture_output=True, text=True, timeout=10)
|
||||
self.assertEqual(blocked.returncode, 1, blocked.stderr)
|
||||
timer = threading.Timer(0.2, sock.close)
|
||||
timer.start()
|
||||
released = subprocess.run(['sh', '-c', helper + f'\nwait_for_dns_port_release {port}'], capture_output=True, text=True, timeout=5)
|
||||
timer.join()
|
||||
self.assertEqual(released.returncode, 0, released.stderr)
|
||||
|
||||
def test_stop_core_deletes_crashed_instance_without_pid(self):
|
||||
source = (dns.ROOT / 'root/etc/init.d/AdGuardHome').read_text()
|
||||
helpers = source[source.index('wait_for_pid_exit()'):source.index('save_dnsmasq_upstream_config()')]
|
||||
core = source[source.index('stop_core()'):source.index('\nagh_reload()')]
|
||||
script = helpers + core + '''
|
||||
ubus() { [ "$2" = list ] && echo '{}' || echo deleted >&2; }
|
||||
jsonfilter() { cat >/dev/null; case "$2" in *.instance1) echo '{"running":false}';; esac; }
|
||||
stop_core
|
||||
'''
|
||||
result = subprocess.run(['sh','-c',script],capture_output=True,text=True,timeout=10)
|
||||
self.assertEqual(result.returncode, 0, result.stderr)
|
||||
self.assertIn('deleted',result.stderr)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -0,0 +1,107 @@
|
||||
"""隔离更新器的文件和下载命令, 验证并发与失败后的锁释放."""
|
||||
import os
|
||||
from pathlib import Path
|
||||
import signal
|
||||
import subprocess
|
||||
import tempfile
|
||||
import time
|
||||
import unittest
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
class UpdateLockTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.tmp = tempfile.TemporaryDirectory(prefix='agh-lock-test-')
|
||||
self.addCleanup(self.tmp.cleanup)
|
||||
self.directory = Path(self.tmp.name)
|
||||
self.processes = []
|
||||
self.addCleanup(self.stop_processes)
|
||||
self.env = dict(os.environ, TEST_DIR=str(self.directory))
|
||||
self.write_executable('uci', '''#!/bin/sh
|
||||
case "$2" in
|
||||
*.binpath) echo "$TEST_DIR/core";;
|
||||
*.enabled) echo 0;;
|
||||
esac
|
||||
''')
|
||||
self.write_executable('core', '#!/bin/sh\necho "AdGuardHome version v1.2.3"\n')
|
||||
self.write_executable('uclient-fetch', '''#!/bin/sh
|
||||
touch "$TEST_DIR/ready"
|
||||
while [ ! -f "$TEST_DIR/release" ]; do sleep 0.02; done
|
||||
printf '%s\n' '{"tag_name":"v1.2.3"}'
|
||||
''')
|
||||
source = (ROOT / 'root/usr/share/AdGuardHome/update_core.sh').read_text()
|
||||
source = source.replace('PATH="/usr/sbin:/usr/bin:/sbin:/bin"',
|
||||
'PATH="$TEST_DIR:/usr/bin:/bin"')
|
||||
for path in ['/var/lock/AdGuardHome-update.lock', '/var/run/update_core_error',
|
||||
'/var/run/update_core', '/tmp/AdGuardHome_update.log']:
|
||||
source = source.replace(path, str(self.directory / Path(path).name))
|
||||
self.script = self.write_executable('updater', source)
|
||||
|
||||
def write_executable(self, name, content):
|
||||
path = self.directory / name
|
||||
path.write_text(content)
|
||||
path.chmod(0o755)
|
||||
return path
|
||||
|
||||
def start(self, *args):
|
||||
proc = subprocess.Popen(['sh', str(self.script), *args], env=self.env,
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
||||
start_new_session=True)
|
||||
self.processes.append(proc)
|
||||
return proc
|
||||
|
||||
def stop_processes(self):
|
||||
for proc in self.processes:
|
||||
if proc.poll() is None:
|
||||
os.killpg(proc.pid, signal.SIGKILL)
|
||||
proc.communicate(timeout=5)
|
||||
|
||||
def wait_ready(self):
|
||||
deadline = time.monotonic() + 5
|
||||
while not (self.directory / 'ready').exists():
|
||||
self.assertLess(time.monotonic(), deadline, 'updater did not reach downloader')
|
||||
time.sleep(0.01)
|
||||
|
||||
def test_normal_and_force_contenders_preserve_owner_state(self):
|
||||
owner = self.start()
|
||||
self.wait_ready()
|
||||
log = self.directory / 'AdGuardHome_update.log'
|
||||
before = log.read_bytes()
|
||||
for args in [(), ('force',)]:
|
||||
contender = self.start(*args)
|
||||
contender.communicate(timeout=5)
|
||||
self.assertEqual(contender.returncode, 2)
|
||||
self.assertIsNone(owner.poll())
|
||||
self.assertEqual(log.read_bytes(), before)
|
||||
self.assertTrue((self.directory / 'update_core').exists())
|
||||
self.assertFalse((self.directory / 'update_core_error').exists())
|
||||
(self.directory / 'release').touch()
|
||||
owner.communicate(timeout=5)
|
||||
self.assertEqual(owner.returncode, 0)
|
||||
self.assertFalse((self.directory / 'update_core').exists())
|
||||
self.assertTrue((self.directory / 'AdGuardHome-update.lock').exists())
|
||||
|
||||
def test_killed_owner_does_not_leave_lock_held(self):
|
||||
owner = self.start()
|
||||
self.wait_ready()
|
||||
os.killpg(owner.pid, signal.SIGKILL)
|
||||
owner.communicate(timeout=5)
|
||||
(self.directory / 'release').touch()
|
||||
successor = self.start()
|
||||
successor.communicate(timeout=5)
|
||||
self.assertEqual(successor.returncode, 0)
|
||||
self.assertFalse((self.directory / 'update_core').exists())
|
||||
|
||||
def test_failure_sets_error_and_releases_lock(self):
|
||||
self.write_executable('uclient-fetch', '#!/bin/sh\nexit 1\n')
|
||||
for _ in range(2):
|
||||
proc = self.start()
|
||||
proc.communicate(timeout=5)
|
||||
self.assertEqual(proc.returncode, 1)
|
||||
self.assertTrue((self.directory / 'update_core_error').exists())
|
||||
self.assertFalse((self.directory / 'update_core').exists())
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -0,0 +1,47 @@
|
||||
name: Build
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- v*
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build ${{ matrix.arch }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
arch:
|
||||
- aarch64_generic
|
||||
- i386_pentium-mmx
|
||||
- loongarch64_generic
|
||||
- mips_mips32
|
||||
- mipsel_24kc
|
||||
- mipsel_mips32
|
||||
- x86_64
|
||||
steps:
|
||||
- uses: actions/checkout@main
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Building packages
|
||||
uses: sbwml/openwrt-gh-action-sdk@go1.24
|
||||
env:
|
||||
ARCH: ${{ matrix.arch }}-openwrt-24.10
|
||||
FEEDNAME: packages_ci
|
||||
PACKAGES: luci-app-eqosplus
|
||||
NO_REFRESH_CHECK: true
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.arch }}
|
||||
path: bin/packages/${{ matrix.arch }}/packages_ci/*.ipk
|
||||
|
||||
- name: Upload packages
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
allowUpdates: true
|
||||
replacesArtifacts: true
|
||||
artifacts: "bin/packages/${{ matrix.arch }}/packages_ci/*.ipk"
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 sirpdboy
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,39 @@
|
||||
#
|
||||
# Copyright (C) 2006-2017 OpenWrt.org#
|
||||
# Copyright (C) 2022-2025 sirpdboy herboy2008@gmail.com https://github.com/sirpdboy/luci-app-eqosplus
|
||||
# This is free software, licensed under the GNU General Public License v2.
|
||||
# See /LICENSE for more information.
|
||||
#
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
THEME_NAME:=eqosplus
|
||||
PKG_NAME:=luci-app-$(THEME_NAME)
|
||||
|
||||
PKG_LICENSE:=Apache-2.0
|
||||
|
||||
LUCI_TITLE:=LuCI support for eqosplus.
|
||||
LUCI_DESCRIPTION:=LuCI support for Easy eqosplus(Support speed limit based on IP address).
|
||||
LUCI_DEPENDS:=+ip-full +tc +nftables +bc +kmod-ifb
|
||||
LUCI_PKGARCH:=all
|
||||
|
||||
PKG_VERSION:=1.3.0
|
||||
PKG_RELEASE:=20251128
|
||||
PKG_MAINTAINER:=sirpdboy <herboy2008@gmail.com>
|
||||
|
||||
define Build/Compile
|
||||
endef
|
||||
|
||||
define Package/$(PKG_NAME)/postinst
|
||||
#!/bin/sh
|
||||
rm -f /tmp/luci-*
|
||||
endef
|
||||
|
||||
define Package/$(PKG_NAME)/conffiles
|
||||
/etc/config/eqosplus
|
||||
endef
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
# call BuildPackage - OpenWrt buildroot signature
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
 [](https://t.me/joinchat/AAAAAEpRF88NfOK5vBXGBQ)
|
||||
|
||||
<h1 align="center">
|
||||
<br>luci-app-eqosplus<br>
|
||||
</h1>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://openwrt.org"><img alt="OpenWrt" src="https://img.shields.io/badge/OpenWrt-%E2%89%A519.07-ff0000?logo=openwrt&logoColor=white"></a>
|
||||
<a href="https://www.google.com/chrome/"><img alt="Chrome" src="https://img.shields.io/badge/Chrome-%E2%89%A5111-4285F3?logo=googlechrome&logoColor=white"></a>
|
||||
<a href="https://www.apple.com/safari/"><img alt="Safari" src="https://img.shields.io/badge/Safari-%E2%89%A516.4-000000?logo=safari&logoColor=white"></a>
|
||||
<a href="https://www.mozilla.org/firefox/"><img alt="Firefox" src="https://img.shields.io/badge/Firefox-%E2%89%A5128-FF7138?logo=firefoxbrowser&logoColor=white"></a>
|
||||
<a target="_blank" href="https://github.com/sirpdboy/luci-app-eqosplus/releases"> <img alt="GitHub release" src="https://img.shields.io/github/v/release/sirpdboy/luci-app-eqosplus"></a>
|
||||
<a href="https://github.com/sirpdboy/luci-app-eqosplus/releases"><img alt="Downloads" src="https://img.shields.io/github/downloads/sirpdboy/luci-app-eqosplus/total"></a>
|
||||
</p>
|
||||
|
||||
[中文] | [English](README.md)
|
||||
|
||||

|
||||
|
||||
Please read this page carefully, which includes precautions and instructions on how to use it.
|
||||
|
||||
## Enhanced version of EQOS with timed speed limit and added features such as timed limit.
|
||||
|
||||
### Method for downloading source code:
|
||||
|
||||
```Brach
|
||||
# downloading
|
||||
git clone https://github.com/sirpdboy/luci-app-eqosplus package/luci-app-eqosplus
|
||||
make menuconfig
|
||||
```
|
||||
### Configuration Menu
|
||||
```Brach
|
||||
make menuconfig
|
||||
# find LuCI -> Applications, select luci-app-eqosplus, save and exit
|
||||
```
|
||||
### compile
|
||||
|
||||
```Brach
|
||||
# compile
|
||||
make package/luci-app-eqosplus/compile V=s
|
||||
```
|
||||
|
||||
|
||||
## describe
|
||||
|
||||
- luci-app-eqosplus : https://github.com/sirpdboy/luci-app-eqosplus
|
||||
|
||||

|
||||
|
||||
|
||||
## interface
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
|
||||
# My other project
|
||||
|
||||
- Watch Dog : https://github.com/sirpdboy/luci-app-watchdog
|
||||
- Net Speedtest : https://github.com/sirpdboy/luci-app-netspeedtest
|
||||
- Task Plan : https://github.com/sirpdboy/luci-app-taskplan
|
||||
- Power Off Device : https://github.com/sirpdboy/luci-app-poweroffdevice
|
||||
- OpentoPD Theme : https://github.com/sirpdboy/luci-theme-opentopd
|
||||
- KuCat Theme : https://github.com/sirpdboy/luci-theme-kucat
|
||||
- KuCat Theme Config : https://github.com/sirpdboy/luci-app-kucat-config
|
||||
- NFT Time Control : https://github.com/sirpdboy/luci-app-timecontrol
|
||||
- Parent Control: https://github.com/sirpdboy/luci-theme-parentcontrol
|
||||
- Eqos Plus: https://github.com/sirpdboy/luci-app-eqosplus
|
||||
- Advanced : https://github.com/sirpdboy/luci-app-advanced
|
||||
- ddns-go : https://github.com/sirpdboy/luci-app-ddns-go
|
||||
- Advanced Plus): https://github.com/sirpdboy/luci-app-advancedplus
|
||||
- Net Wizard: https://github.com/sirpdboy/luci-app-netwizard
|
||||
- Part Exp: https://github.com/sirpdboy/luci-app-partexp
|
||||
- Lukcy: https://github.com/sirpdboy/luci-app-lukcy
|
||||
|
||||
## HELP
|
||||
|
||||
| <img src="https://img.shields.io/badge/-Alipay-F5F5F5.svg" href="#赞助支持本项目-" height="25" alt="图飞了"/> | <img src="https://img.shields.io/badge/-WeChat-F5F5F5.svg" height="25" alt="图飞了" href="#赞助支持本项目-"/> |
|
||||
| :-----------------: | :-------------: |
|
||||
| |  |
|
||||
|
||||
<a href="#readme">
|
||||
<img src="https://img.shields.io/badge/-TOP-orange.svg" alt="no" title="Return TOP" align="right"/>
|
||||
</a>
|
||||
|
||||
 [](https://t.me/joinchat/AAAAAEpRF88NfOK5vBXGBQ)
|
||||
@@ -0,0 +1,109 @@
|
||||
 [](https://t.me/joinchat/AAAAAEpRF88NfOK5vBXGBQ)
|
||||
|
||||
<h1 align="center">
|
||||
<br>luci-app-eqosplus<br>
|
||||
</h1>
|
||||
|
||||
<p align="center">
|
||||
|
||||
<a target="_blank" href="https://github.com/sirpdboy/luci-app-eqosplus/releases">
|
||||
<img src="https://img.shields.io/github/release/sirpdboy/luci-app-eqosplus.svg?style=flat-square&label=luci-app-eqosplus&colorB=green">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
[中文] | [English](README.md)
|
||||
|
||||

|
||||
|
||||
请 **认真阅读完毕** 本页面,本页面包含注意事项和如何使用。
|
||||
|
||||
## 功能说明:
|
||||
|
||||
### 定时限速1.2.2版
|
||||
#### 2023.7.19 定时限速1.2.2:增加更多日期:工作日和休息日,自定义日期1,2,3中间用逗号分隔;加入MAC地址限速,从此不用担心IPV6和IPV4的限速问题。
|
||||
|
||||
### 定时限速1.0版
|
||||
#### 2022.12.24 定时限速在eqos的加强版,加入定时限制等功能。
|
||||
|
||||
## 编译使用方法 [](#编译使用方法-)
|
||||
|
||||
将luci-app-eqosplus添加至 LEDE/OpenWRT 源码的方法。
|
||||
|
||||
### 下载源码方法一:
|
||||
编辑源码文件夹根目录feeds.conf.default并加入如下内容:
|
||||
|
||||
```Brach
|
||||
# feeds获取源码:
|
||||
src-git eqosplus https://github.com/sirpdboy/luci-app-eqosplus
|
||||
```
|
||||
```Brach
|
||||
# 更新feeds,并安装主题:
|
||||
scripts/feeds update eqosplus
|
||||
scripts/feeds install luci-app-eqosplus
|
||||
```
|
||||
|
||||
### 下载源码方法:
|
||||
```Brach
|
||||
# 下载源码
|
||||
git clone https://github.com/sirpdboy/luci-app-eqosplus package/luci-app-eqosplus
|
||||
make menuconfig
|
||||
```
|
||||
### 配置菜单
|
||||
```Brach
|
||||
make menuconfig
|
||||
# 找到 LuCI -> Applications, 选择 luci-app-eqosplus, 保存后退出。
|
||||
```
|
||||
### 编译
|
||||
```Brach
|
||||
# 编译固件
|
||||
make package/luci-app-eqosplus/compile V=s
|
||||
```
|
||||
|
||||
## 说明 [](#说明-)
|
||||
|
||||
源码来源:https://github.com/sirpdboy/luci-app-eqosplus
|
||||
|
||||
|
||||
- 你可以随意使用其中的源码,但请注明出处。
|
||||
|
||||

|
||||
|
||||
## 界面
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
# My other project
|
||||
|
||||
- 路由安全看门狗 :https://github.com/sirpdboy/luci-app-watchdog
|
||||
- 网络速度测试 :https://github.com/sirpdboy/luci-app-netspeedtest
|
||||
- 计划任务插件(原定时设置) : https://github.com/sirpdboy/luci-app-taskplan
|
||||
- 关机功能插件 : https://github.com/sirpdboy/luci-app-poweroffdevice
|
||||
- opentopd主题 : https://github.com/sirpdboy/luci-theme-opentopd
|
||||
- kucat酷猫主题: https://github.com/sirpdboy/luci-theme-kucat
|
||||
- kucat酷猫主题设置工具: https://github.com/sirpdboy/luci-app-kucat-config
|
||||
- NFT版上网时间控制插件: https://github.com/sirpdboy/luci-app-timecontrol
|
||||
- 家长控制: https://github.com/sirpdboy/luci-theme-parentcontrol
|
||||
- 定时限速: https://github.com/sirpdboy/luci-app-eqosplus
|
||||
- 系统高级设置 : https://github.com/sirpdboy/luci-app-advanced
|
||||
- ddns-go动态域名: https://github.com/sirpdboy/luci-app-ddns-go
|
||||
- 进阶设置(系统高级设置+主题设置kucat/agron/opentopd): https://github.com/sirpdboy/luci-app-advancedplus
|
||||
- 网络设置向导: https://github.com/sirpdboy/luci-app-netwizard
|
||||
- 一键分区扩容: https://github.com/sirpdboy/luci-app-partexp
|
||||
- lukcy大吉: https://github.com/sirpdboy/luci-app-lukcy
|
||||
|
||||
## 捐助
|
||||
|
||||

|
||||
|
||||
| <img src="https://img.shields.io/badge/-支付宝-F5F5F5.svg" href="#赞助支持本项目-" height="25" alt="图飞了"/> | <img src="https://img.shields.io/badge/-微信-F5F5F5.svg" height="25" alt="图飞了" href="#赞助支持本项目-"/> |
|
||||
| :-----------------: | :-------------: |
|
||||
| |  |
|
||||
|
||||
<a href="#readme">
|
||||
<img src="https://img.shields.io/badge/-返回顶部-orange.svg" alt="图飞了" title="返回顶部" align="right"/>
|
||||
</a>
|
||||
|
||||
 [](https://t.me/joinchat/AAAAAEpRF88NfOK5vBXGBQ)
|
||||
|
||||
|
After Width: | Height: | Size: 645 KiB |
|
After Width: | Height: | Size: 664 KiB |
@@ -0,0 +1,19 @@
|
||||
module("luci.controller.eqosplus", package.seeall)
|
||||
-- Copyright 2022-2023 sirpdboy <herboy2008@gmail.com>
|
||||
function index()
|
||||
if not nixio.fs.access("/etc/config/eqosplus") then return end
|
||||
entry({"admin", "control"}, firstchild(), "Control", 44).dependent = false
|
||||
|
||||
local e = entry({"admin", "control", "eqosplus"}, cbi("eqosplus"), _("Eqosplus"), 10)
|
||||
e.dependent=false
|
||||
e.acl_depends = { "luci-app-eqosplus" }
|
||||
entry({"admin", "control", "eqosplus", "status"}, call("act_status")).leaf = true
|
||||
end
|
||||
|
||||
function act_status()
|
||||
local sys = require "luci.sys"
|
||||
local e = {}
|
||||
e.status = sys.call(" busybox ps -w | grep eqosplus | grep -v grep >/dev/null ") == 0
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json(e)
|
||||
end
|
||||
@@ -0,0 +1,190 @@
|
||||
-- Copyright 2022-2023 sirpdboy <herboy2008@gmail.com>
|
||||
-- Licensed to the public under the Apache License 2.0.
|
||||
local sys = require "luci.sys"
|
||||
local ifaces = sys.net:devices()
|
||||
local WADM = require "luci.tools.webadmin"
|
||||
local ipc = require "luci.ip"
|
||||
local a, t, e
|
||||
|
||||
a = Map("eqosplus", translate("Network speed limit"))
|
||||
a.description = translate("Users can limit the network speed for uploading/downloading through MAC, IP, and IP segments (192.168.110.00-192.168.10.200). The speed unit is MB/second.")
|
||||
a.template = "eqosplus/index"
|
||||
|
||||
t = a:section(TypedSection, "eqosplus")
|
||||
t.anonymous = true
|
||||
|
||||
e = t:option(DummyValue, "eqosplus_status", translate("Status"))
|
||||
e.template = "eqosplus/eqosplus"
|
||||
e.value = translate("Collecting data...")
|
||||
|
||||
|
||||
ipi = t:option(ListValue, "ifname", translate("Interface"), translate("Set the interface used for restriction, use pppoe-wan for dialing, use WAN hardware interface for DHCP mode (such as eth1), and use br-lan for bypass mode"))
|
||||
ipi.default = "1"
|
||||
ipi:value(1,translate("Automatic settings"))
|
||||
ipi:value("br-lan", translate("br-lan (LAN Bridge)"))
|
||||
local function get_wan_interfaces()
|
||||
local result = {}
|
||||
local ubus = require "ubus"
|
||||
|
||||
local conn = ubus.connect()
|
||||
if not conn then
|
||||
return result
|
||||
end
|
||||
|
||||
local network_status = conn:call("network.interface", "dump", {})
|
||||
for _, iface in ipairs(network_status.interface) do
|
||||
if iface.interface:match("^wan") or iface.interface:match("^pppoe") or iface.proto == "pppoe" then
|
||||
local dev = iface.l3_device or iface.device
|
||||
if dev then
|
||||
table.insert(result, {
|
||||
name = dev,
|
||||
proto = iface.proto,
|
||||
logical_name = iface.interface
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
conn:close()
|
||||
return result
|
||||
end
|
||||
|
||||
local wan_ifaces = get_wan_interfaces()
|
||||
for _, iface in ipairs(wan_ifaces) do
|
||||
ipi:value(iface.name, translate(iface.name) .. (iface.proto == "pppoe" and " (PPPoE)" or " (WAN)"))
|
||||
end
|
||||
|
||||
t = a:section(TypedSection, "device")
|
||||
t.template = "cbi/tblsection"
|
||||
t.anonymous = true
|
||||
t.addremove = true
|
||||
|
||||
comment = t:option(Value, "comment", translate("Comment"))
|
||||
comment.size = 8
|
||||
|
||||
e = t:option(Flag, "enable", translate("Enabled"))
|
||||
e.rmempty = false
|
||||
e.size = 4
|
||||
|
||||
ip = t:option(Value, "mac", translate("IP/MAC"))
|
||||
ip.size = 8
|
||||
|
||||
local function get_devices()
|
||||
local devices = {}
|
||||
local seen_ips = {}
|
||||
local ubus = require "ubus"
|
||||
local conn = ubus.connect()
|
||||
|
||||
local function get_hostname(ip)
|
||||
local f = io.popen("nslookup "..ip.." 2>/dev/null | grep 'name =' | cut -d'=' -f2 | sed 's/\\.$//'")
|
||||
if f then
|
||||
local name = f:read("*l")
|
||||
f:close()
|
||||
if name and name ~= "" then
|
||||
return name:match("^%s*(.-)%s*$")
|
||||
end
|
||||
end
|
||||
local leases_file = io.open("/tmp/dhcp.leases", "r")
|
||||
if leases_file then
|
||||
for line in leases_file:lines() do
|
||||
local mac, ip_lease, _, hostname = line:match("^(%S+)%s+(%S+)%s+(%S+)%s+(%S+)")
|
||||
if ip_lease == ip and hostname ~= "*" then
|
||||
leases_file:close()
|
||||
return hostname
|
||||
end
|
||||
end
|
||||
leases_file:close()
|
||||
end
|
||||
return "unknown"
|
||||
end
|
||||
if conn then
|
||||
local leases = conn:call("dhcp", "ipv4leases", {}) or {}
|
||||
for _, lease in ipairs(leases) do
|
||||
if lease.ipaddr and lease.mac then
|
||||
local hostname = lease.hostname or get_hostname(lease.ipaddr)
|
||||
devices[#devices+1] = {
|
||||
ip = lease.ipaddr,
|
||||
mac = lease.mac:upper(),
|
||||
hostname = hostname,
|
||||
display = string.format("%s (%s) - %s", lease.ipaddr, lease.mac:upper(), hostname)
|
||||
}
|
||||
seen_ips[lease.ipaddr] = true
|
||||
end
|
||||
end
|
||||
conn:close()
|
||||
end
|
||||
local arp_cmd = io.popen("ip -4 neigh show dev br-lan 2>/dev/null")
|
||||
if arp_cmd then
|
||||
for line in arp_cmd:lines() do
|
||||
local ip_addr, mac = line:match("^(%S+)%s+.+%s+(%S+)%s+")
|
||||
if ip_addr and mac and mac ~= "00:00:00:00:00:00" and not seen_ips[ip_addr] then
|
||||
mac = mac:upper()
|
||||
local hostname = get_hostname(ip_addr)
|
||||
devices[#devices+1] = {
|
||||
ip = ip_addr,
|
||||
mac = mac,
|
||||
hostname = hostname,
|
||||
display = string.format("%s (%s) - %s", ip_addr, mac, hostname)
|
||||
}
|
||||
seen_ips[ip_addr] = true
|
||||
end
|
||||
end
|
||||
arp_cmd:close()
|
||||
end
|
||||
table.sort(devices, function(a, b) return a.ip < b.ip end)
|
||||
return devices
|
||||
end
|
||||
|
||||
local devices = get_devices()
|
||||
for _, dev in ipairs(devices) do
|
||||
ip:value(dev.ip, dev.display)
|
||||
end
|
||||
dl = t:option(Value, "download", translate("Downloads"))
|
||||
dl.default = '0.1'
|
||||
dl.size = 4
|
||||
|
||||
ul = t:option(Value, "upload", translate("Uploads"))
|
||||
ul.default = '0.1'
|
||||
ul.size = 4
|
||||
function validate_time(self, value, section)
|
||||
local hh, mm, ss
|
||||
hh, mm, ss = string.match (value, "^(%d?%d):(%d%d)$")
|
||||
hh = tonumber (hh)
|
||||
mm = tonumber (mm)
|
||||
if hh and mm and hh <= 23 and mm <= 59 then
|
||||
return value
|
||||
else
|
||||
return nil, "Time HH:MM or space"
|
||||
end
|
||||
end
|
||||
|
||||
e = t:option(Value, "timestart", translate("Start control time"))
|
||||
e.placeholder = '00:00'
|
||||
e.default = '00:00'
|
||||
e.validate = validate_time
|
||||
e.rmempty = true
|
||||
e.size = 4
|
||||
|
||||
e = t:option(Value, "timeend", translate("Stop control time"))
|
||||
e.placeholder = '00:00'
|
||||
e.default = '00:00'
|
||||
e.validate = validate_time
|
||||
e.rmempty = true
|
||||
e.size = 4
|
||||
|
||||
week=t:option(Value,"week",translate("Week Day(1~7)"))
|
||||
week.rmempty = true
|
||||
week:value('0',translate("Everyday"))
|
||||
week:value(1,translate("Monday"))
|
||||
week:value(2,translate("Tuesday"))
|
||||
week:value(3,translate("Wednesday"))
|
||||
week:value(4,translate("Thursday"))
|
||||
week:value(5,translate("Friday"))
|
||||
week:value(6,translate("Saturday"))
|
||||
week:value(7,translate("Sunday"))
|
||||
week:value('1,2,3,4,5',translate("Workday"))
|
||||
week:value('6,7',translate("Rest Day"))
|
||||
week.default='0'
|
||||
week.size = 6
|
||||
|
||||
return a
|
||||
@@ -0,0 +1,3 @@
|
||||
<%+cbi/valueheader%>
|
||||
<font class="eqosplus_status"><%=pcdata(self:cfgvalue(section) or self.default or "")%></font>
|
||||
<%+cbi/valuefooter%>
|
||||
@@ -0,0 +1,12 @@
|
||||
<% include("cbi/map") %>
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
XHR.poll(2, '<%=luci.dispatcher.build_url("admin", "control", "eqosplus", "status" )%>', null,
|
||||
function (x, result) {
|
||||
var status = document.getElementsByClassName('eqosplus_status')[0];
|
||||
status.setAttribute("style", "font-weight:bold;");
|
||||
status.setAttribute("color", result.status ? "green" : "red");
|
||||
status.innerHTML = result.status ? '<%=translate("RUNNING")%>' : '<%=translate("NOT RUNNING")%>';
|
||||
}
|
||||
)
|
||||
//]]>
|
||||
</script>
|
||||
@@ -0,0 +1,61 @@
|
||||
|
||||
msgid "Eqosplus"
|
||||
msgstr ""
|
||||
|
||||
msgid "Network speed limit"
|
||||
msgstr ""
|
||||
|
||||
msgid "Running state"
|
||||
msgstr ""
|
||||
|
||||
msgid "Not running"
|
||||
msgstr ""
|
||||
|
||||
msgid "Running"
|
||||
msgstr ""
|
||||
|
||||
msgid "Users can limit the network speed for uploading/downloading through MAC, IP, and IP segments (192.168.110.00-192.168.10.200). The speed unit is MB/second."
|
||||
msgstr ""
|
||||
|
||||
msgid "MAC/IP"
|
||||
msgstr ""
|
||||
|
||||
msgid "Downloads"
|
||||
msgstr ""
|
||||
|
||||
msgid "Uploads"
|
||||
msgstr ""
|
||||
|
||||
msgid "Comment"
|
||||
msgstr ""
|
||||
|
||||
msgid "Upload bandwidth(Mbit/s)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Download bandwidth(Mbit/s)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Start control time"
|
||||
msgstr ""
|
||||
|
||||
msgid "Stop control time"
|
||||
msgstr ""
|
||||
|
||||
msgid "Week Day(1~7)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Suggested feedback:"
|
||||
msgstr ""
|
||||
|
||||
msgid "Set the interface used for restriction, use pppoe-wan for dialing, use WAN hardware interface for DHCP mode (such as eth1), and use br-lan for bypass mode"
|
||||
msgstr ""
|
||||
|
||||
msgid "Rest Day"
|
||||
msgstr ""
|
||||
|
||||
msgid "Workday"
|
||||
msgstr ""
|
||||
|
||||
msgid "Automatic settings"
|
||||
msgstr ""
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
|
||||
msgid "Eqosplus"
|
||||
msgstr "定时限速"
|
||||
|
||||
msgid "Network speed limit"
|
||||
msgstr "定时网速限制"
|
||||
|
||||
msgid "Running state"
|
||||
msgstr "运行状态"
|
||||
|
||||
msgid "Not running"
|
||||
msgstr "未运行"
|
||||
|
||||
msgid "Running"
|
||||
msgstr "已运行"
|
||||
|
||||
msgid "Users can limit the network speed for uploading/downloading through MAC, IP.The speed unit is MB/second."
|
||||
msgstr "可以通过MAC,IP限制用户上传/下载的网速。速度单位为<font color=\"red\"><b> MB/秒 </b></font>。"
|
||||
|
||||
msgid "MAC/IP"
|
||||
msgstr "MAC/IP"
|
||||
|
||||
msgid "Downloads"
|
||||
msgstr "下载速度"
|
||||
|
||||
msgid "Uploads"
|
||||
msgstr "上传速度"
|
||||
|
||||
msgid "Comment"
|
||||
msgstr "备注"
|
||||
|
||||
msgid "Upload bandwidth(Mbit/s)"
|
||||
msgstr "上传总带宽(Mbit/s)"
|
||||
|
||||
msgid "Download bandwidth(Mbit/s)"
|
||||
msgstr "下载总带宽(Mbit/s)"
|
||||
|
||||
msgid "Start control time"
|
||||
msgstr "起控时间"
|
||||
|
||||
msgid "Stop control time"
|
||||
msgstr "停控时间"
|
||||
|
||||
msgid "Week Day(1~7)"
|
||||
msgstr "星期(1~7)"
|
||||
|
||||
msgid "Suggested feedback:"
|
||||
msgstr "建议反馈:"
|
||||
|
||||
msgid "Set the interface used for restriction, use pppoe-wan for dialing, use WAN hardware interface for DHCP mode (such as eth1), and use br-lan for bypass mode"
|
||||
msgstr "设定用来限制网络速度的接口,拨号使用pppoe-wan,DHCP模式使用WAN口的硬件接口(如:eth1),通用使用br-lan接口"
|
||||
|
||||
msgid "Rest Day"
|
||||
msgstr "休息日"
|
||||
|
||||
msgid "Workday"
|
||||
msgstr "工作日"
|
||||
|
||||
msgid "Automatic settings"
|
||||
msgstr "自动设置"
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
|
||||
msgid "Eqosplus"
|
||||
msgstr "定时限速"
|
||||
|
||||
msgid "Network speed limit"
|
||||
msgstr "定时网速限制"
|
||||
|
||||
msgid "Running state"
|
||||
msgstr "运行状态"
|
||||
|
||||
msgid "Not running"
|
||||
msgstr "未运行"
|
||||
|
||||
msgid "Running"
|
||||
msgstr "已运行"
|
||||
|
||||
msgid "Users can limit the network speed for uploading/downloading through MAC, IP, and IP segments (192.168.110.00-192.168.10.200). The speed unit is MB/second."
|
||||
msgstr "用户可以通过MAC、IP、IP段(192.168.10.100-192.168.10.200),限制上传/下载的网络速度。速度单位为MB/秒。。"
|
||||
|
||||
msgid "MAC/IP"
|
||||
msgstr "MAC/IP"
|
||||
|
||||
msgid "Downloads"
|
||||
msgstr "下载速度"
|
||||
|
||||
msgid "Uploads"
|
||||
msgstr "上传速度"
|
||||
|
||||
msgid "Comment"
|
||||
msgstr "备注"
|
||||
|
||||
msgid "Upload bandwidth(Mbit/s)"
|
||||
msgstr "上传总带宽(Mbit/s)"
|
||||
|
||||
msgid "Download bandwidth(Mbit/s)"
|
||||
msgstr "下载总带宽(Mbit/s)"
|
||||
|
||||
msgid "Start control time"
|
||||
msgstr "起控时间"
|
||||
|
||||
msgid "Stop control time"
|
||||
msgstr "停控时间"
|
||||
|
||||
msgid "Week Day(1~7)"
|
||||
msgstr "星期(1~7)"
|
||||
|
||||
msgid "Suggested feedback:"
|
||||
msgstr "建议反馈:"
|
||||
|
||||
msgid "Set the interface used for restriction, use pppoe-wan for dialing, use WAN hardware interface for DHCP mode (such as eth1), and use br-lan for bypass mode"
|
||||
msgstr "设定用来限制网络速度的接口,拨号使用pppoe-wan,DHCP模式使用WAN口的硬件接口(如:eth1),通用使用br-lan接口"
|
||||
|
||||
msgid "Rest Day"
|
||||
msgstr "休息日"
|
||||
|
||||
msgid "Workday"
|
||||
msgstr "工作日"
|
||||
|
||||
msgid "Automatic settings"
|
||||
msgstr "自动设置"
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
|
||||
config eqosplus
|
||||
option enabled '0'
|
||||
option download '1000'
|
||||
option upload '30'
|
||||
option ifname '1'
|
||||
|
||||
config device
|
||||
option timestart '00:00'
|
||||
option week '0'
|
||||
option download '1'
|
||||
option timeend '23:55'
|
||||
option upload '1'
|
||||
option mac '192.168.10.10'
|
||||
option enable '0'
|
||||
|
||||
config device
|
||||
option mac '192.168.10.10-192.168.10.200'
|
||||
option timestart '00:00'
|
||||
option timeend '00:00'
|
||||
option week '0'
|
||||
option download '0.1'
|
||||
option upload '0.1'
|
||||
option enable '0'
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
#!/bin/sh
|
||||
[ "$ACTION" = "ifup" ] && [ "$INTERFACE" = "wan" ] && {
|
||||
sleep 5
|
||||
/etc/init.d/eqosplus restart
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
#!/bin/sh /etc/rc.common
|
||||
#
|
||||
# Copyright (C) 2025 sirpdboy herboy2008@gmail.com https://github.com/sirpdboy/luci-app-eqosplus
|
||||
#
|
||||
|
||||
START=99
|
||||
USE_PROCD=1
|
||||
|
||||
NAME=eqosplus
|
||||
LOCK="/var/lock/$NAME.lock"
|
||||
CR=/etc/crontabs/root
|
||||
|
||||
start_instance() {
|
||||
procd_open_instance
|
||||
procd_set_param command /usr/bin/eqosplusctrl
|
||||
procd_set_param respawn
|
||||
procd_set_param stderr 1
|
||||
procd_close_instance
|
||||
}
|
||||
|
||||
_eqosplus_start() {
|
||||
if [ "$(grep -c 'option enable .1.' /etc/config/$NAME 2>/dev/null)" -gt "0" ]; then
|
||||
if [ x$(uci -q get turboacc.config.sw_flow) = 'x1' ] || [ x$(uci -q get turboacc.config.sfe_flow) = 'x1' ] ;then
|
||||
uci -q set turboacc.config.sw_flow='0'
|
||||
uci -q set turboacc.config.sfe_flow='0'
|
||||
uci -q set turboacc.config.hw_flow='0'
|
||||
uci commit turboacc
|
||||
/etc/init.d/turboacc restart
|
||||
fi
|
||||
touch $LOCK
|
||||
eqosplus start
|
||||
start_instance
|
||||
(crontab -l ; echo "00 1 * * * /etc/init.d/eqosplus start") | sort - | uniq - | crontab -
|
||||
fi
|
||||
}
|
||||
|
||||
start_service(){
|
||||
[ -f $LOCK ] && exit
|
||||
stop_service
|
||||
_eqosplus_start
|
||||
rm -f $LOCK
|
||||
}
|
||||
|
||||
service_triggers() {
|
||||
procd_add_reload_trigger 'eqosplus'
|
||||
}
|
||||
|
||||
stop_service(){
|
||||
kill -9 $(busybox ps -w | grep 'eqosplusctrl' | grep -v 'grep' | awk '{print $1}') >/dev/null 2>&1
|
||||
sed -i '/eqosplus/d' $CR >/dev/null 2>&1
|
||||
rm -f $LOCK 2>/dev/null
|
||||
eqosplus stop
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
#!/bin/sh
|
||||
chmod +x /etc/init.d/eqosplus /usr/bin/eqosplus*
|
||||
uci -q batch <<-EOF >/dev/null
|
||||
delete ucitrack.@eqosplus[-1]
|
||||
add ucitrack eqosplus
|
||||
set ucitrack.@eqosplus[-1].init=eqosplus
|
||||
commit ucitrack
|
||||
EOF
|
||||
|
||||
[ -s /etc/config/eqosplus ] || echo "config eqosplus" > /etc/config/eqosplus
|
||||
|
||||
rm -f /tmp/luci-indexcache
|
||||
exit 0
|
||||
@@ -0,0 +1,379 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Copyright (C) 2006 OpenWrt.org
|
||||
# Copyright 2022-2025 sirpdboy <herboy2008@gmail.com>
|
||||
|
||||
crrun=$1
|
||||
crid=$2
|
||||
NAME=eqosplus
|
||||
IDLIST="/var/$NAME.idlist"
|
||||
LOCK="/var/lock/$NAME.lock"
|
||||
TMPID="/var/$NAME.tmpid"
|
||||
LOG="/var/$NAME_log.log"
|
||||
# idlist=`uci show $NAME | grep "enable='1'" | grep "device" | grep -oE '\[.*?\]' | grep -o '[0-9]' `
|
||||
|
||||
|
||||
if [ x$(uci get $NAME.@$NAME[0].ifname 2>/dev/null) = 'x1' ]; then
|
||||
ifname=$(uci -q get network.lan.ifname)
|
||||
[ "x$ifname" = "x" ] && ifname="device" || ifname="ifname"
|
||||
dev=$(uci -q get network.wan.$ifname)
|
||||
[ ! "$dev" ] && dev=br-lan
|
||||
else
|
||||
dev=$(uci -q get $NAME.@$NAME[0].ifname 2>/dev/null)
|
||||
[ ! "$dev" ] && dev=br-lan
|
||||
fi
|
||||
|
||||
bin_nft=$(which nft)
|
||||
bin_tc=$(which tc)
|
||||
bin_ip=$(which ip)
|
||||
DEBUG=1
|
||||
|
||||
nft_type() {
|
||||
if command -v nft >/dev/null; then
|
||||
nftables_ver="true"
|
||||
fi
|
||||
}
|
||||
|
||||
# Debug functions
|
||||
dbg_nft() {
|
||||
[ "${DEBUG:-0}" -eq 0 ] || echo "DEBUG: nft $*"
|
||||
$bin_nft "$@"
|
||||
}
|
||||
|
||||
dbg_tc() {
|
||||
[ "${DEBUG:-0}" -eq 0 ] || echo "DEBUG: tc $*"
|
||||
$bin_tc "$@"
|
||||
}
|
||||
|
||||
dbg_ip() {
|
||||
[ "${DEBUG:-0}" -eq 0 ] || echo "DEBUG: ip $*"
|
||||
$bin_ip "$@"
|
||||
}
|
||||
|
||||
is_macaddr() {
|
||||
ret=1
|
||||
if echo "$1" | grep -qE '^([0-9A-Fa-f]{2}[-:]){5}[0-9A-Fa-f]{2}$'; then
|
||||
ret=0
|
||||
fi
|
||||
return $ret
|
||||
}
|
||||
|
||||
# 数值比较函数
|
||||
is_gt_zero() {
|
||||
local value=$1
|
||||
# 使用bc进行浮点数比较
|
||||
echo "$value > 0" | bc -l 2>/dev/null | grep -q 1
|
||||
}
|
||||
|
||||
# 转换为kbit
|
||||
to_kbit() {
|
||||
local mb=$1
|
||||
# MB/s 转 kbit/s: 1 MB/s = 8192 kbit/s
|
||||
echo "scale=0; $mb * 8192 / 1" | bc 2>/dev/null || echo "0"
|
||||
}
|
||||
|
||||
# Default commands
|
||||
tc="dbg_tc"
|
||||
ip="dbg_ip"
|
||||
nft="dbg_nft"
|
||||
|
||||
nft_type
|
||||
|
||||
stop_qos() {
|
||||
for face in $(tc qdisc show 2>/dev/null | grep htb | awk '{print $5}'); do
|
||||
$tc qdisc del dev $face root 2>/dev/null
|
||||
done
|
||||
|
||||
$tc qdisc del dev ${dev} root 2>/dev/null
|
||||
$tc qdisc del dev ${dev}_ifb root 2>/dev/null
|
||||
$tc qdisc del dev ${dev} ingress 2>/dev/null
|
||||
$ip link del dev ${dev}_ifb 2>/dev/null 2>&1
|
||||
|
||||
if [ -n "$nftables_ver" ]; then
|
||||
$nft delete table inet ${NAME} 2>/dev/null
|
||||
$nft delete table bridge ${NAME} 2>/dev/null
|
||||
fi
|
||||
|
||||
echo "" > "$IDLIST" 2>/dev/null
|
||||
}
|
||||
|
||||
init_qosplus() {
|
||||
|
||||
insmod sch_htb 2>/dev/null
|
||||
insmod act_mirred 2>/dev/null
|
||||
insmod ifb 2>/dev/null
|
||||
|
||||
$ip link del dev ${dev}_ifb 2>/dev/null
|
||||
$ip link add dev ${dev}_ifb name ${dev}_ifb type ifb
|
||||
$ip link set dev ${dev}_ifb up
|
||||
|
||||
$tc qdisc del dev ${dev} root 2>/dev/null
|
||||
$tc qdisc add dev ${dev} root handle 1:0 htb default 1
|
||||
$tc class add dev ${dev} parent 1:0 classid 1:1 htb rate 1000mbit ceil 1000mbit
|
||||
|
||||
$tc qdisc del dev ${dev}_ifb root 2>/dev/null
|
||||
$tc qdisc add dev ${dev}_ifb root handle 1:0 htb default 1
|
||||
$tc class add dev ${dev}_ifb parent 1:0 classid 1:1 htb rate 1000mbit ceil 1000mbit
|
||||
lanipaddr=$(uci -q get network.lan.ipaddr 2>/dev/null | awk -F '.' '{print $1"."$2"."$3".0/24"}')
|
||||
if [ -n "$lanipaddr" ]; then
|
||||
$tc filter add dev $dev parent 1:0 protocol ip prio 1 u32 match ip src "$lanipaddr" match ip dst "$lanipaddr" flowid 1:1
|
||||
$tc filter add dev ${dev}_ifb parent 1:0 protocol ip prio 1 u32 match ip src "$lanipaddr" match ip dst "$lanipaddr" flowid 1:1
|
||||
fi
|
||||
$tc qdisc del dev ${dev} ingress 2>/dev/null
|
||||
$tc qdisc add dev ${dev} ingress
|
||||
$tc filter add dev ${dev} parent ffff: protocol all prio 2 u32 match u32 0 0 flowid 1:1 action mirred egress redirect dev ${dev}_ifb
|
||||
|
||||
if [ -n "$nftables_ver" ]; then
|
||||
$nft delete table inet ${NAME} 2>/dev/null
|
||||
$nft delete table bridge ${NAME} 2>/dev/null
|
||||
|
||||
$nft add table inet ${NAME}
|
||||
|
||||
$nft add chain inet ${NAME} mark_forward { type filter hook forward priority -200\; policy accept\; }
|
||||
$nft add chain inet ${NAME} mark_output { type filter hook output priority -200\; policy accept\; }
|
||||
$nft add chain inet ${NAME} mark_postrouting { type filter hook postrouting priority -200\; policy accept\; }
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
|
||||
del_id() {
|
||||
local list_id=$1
|
||||
id=$((list_id * 10 + 1000))
|
||||
[ "${DEBUG:-0}" -eq 0 ] || echo "D: del_id $@ --$id --$mac"
|
||||
$tc filter del dev ${dev} parent 1: handle 800::$(printf "%x" $id) 2>/dev/null
|
||||
$tc class del dev ${dev} parent 1:1 classid 1:$id 2>/dev/null
|
||||
$tc filter del dev ${dev}_ifb parent 1: handle 800::$(printf "%x" $id) 2>/dev/null
|
||||
$tc class del dev ${dev}_ifb parent 1:1 classid 1:$id 2>/dev/null
|
||||
mac=$(uci -q get $NAME.@device[$list_id].mac 2>/dev/null)
|
||||
if [ -n "$nftables_ver" ] && [ -n "$mac" ]; then
|
||||
if is_macaddr "$mac"; then
|
||||
$nft delete rule inet ${NAME} mark_forward ether saddr $mac counter 2>/dev/null
|
||||
$nft delete rule inet ${NAME} mark_output ether saddr $mac counter 2>/dev/null
|
||||
$nft delete rule inet ${NAME} mark_postrouting ether saddr $mac counter 2>/dev/null
|
||||
else
|
||||
Z=$(echo $mac | awk -F '[/]' '{print $2}')
|
||||
[ -n "$Z" ] && mac=$(echo $mac | awk -F '[/]' '{print $1}') || Z=32
|
||||
$nft delete rule inet ${NAME} mark_forward ip saddr $mac/$Z counter 2>/dev/null
|
||||
$nft delete rule inet ${NAME} mark_output ip saddr $mac/$Z counter 2>/dev/null
|
||||
$nft delete rule inet ${NAME} mark_postrouting ip saddr $mac/$Z counter 2>/dev/null
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
add_mac() {
|
||||
local list_id=$1
|
||||
id=$((list_id * 10 + 1000))
|
||||
M0=$(echo $mac | cut -d : -f 1)$(echo $mac | cut -d : -f 2)
|
||||
M1=$(echo $mac | cut -d : -f 3)$(echo $mac | cut -d : -f 4)
|
||||
M2=$(echo $mac | cut -d : -f 5)$(echo $mac | cut -d : -f 6)
|
||||
[ "${DEBUG:-0}" -eq 0 ] || echo "D: add_mac $@ --id:$id --mac:$mac M012--$M0-$M1-$M2"
|
||||
|
||||
if is_gt_zero "$UL"; then
|
||||
if [ -n "$nftables_ver" ]; then
|
||||
$nft add rule inet ${NAME} mark_forward ether saddr $mac counter meta mark set $id
|
||||
$nft add rule inet ${NAME} mark_output ether saddr $mac counter meta mark set $id
|
||||
$nft add rule inet ${NAME} mark_postrouting ether saddr $mac counter meta mark set $id
|
||||
fi
|
||||
$tc class add dev ${dev}_ifb parent 1:1 classid 1:$id htb rate "${UL}kbit" ceil "${UL}kbit" prio $id burst 15k cburst 15k
|
||||
$tc qdisc add dev ${dev}_ifb parent 1:$id handle ${id}: sfq perturb 10
|
||||
|
||||
$tc filter add dev ${dev}_ifb parent 1: protocol ip prio $id handle $id fw flowid 1:$id
|
||||
|
||||
$tc filter add dev ${dev}_ifb parent 1: protocol ip prio $((id + 100)) u32 \
|
||||
match u16 0x0800 0xFFFF at -2 \
|
||||
match u16 0x${M2} 0xFFFF at -4 \
|
||||
match u32 0x${M0}${M1} 0xFFFFFFFF at -8 \
|
||||
flowid 1:$id
|
||||
fi
|
||||
if is_gt_zero "$DL"; then
|
||||
$tc class add dev ${dev} parent 1:1 classid 1:$id htb rate "${DL}kbit" ceil "${DL}kbit" prio $id burst 15k cburst 15k
|
||||
$tc qdisc add dev ${dev} parent 1:$id handle ${id}: sfq perturb 10
|
||||
|
||||
$tc filter add dev ${dev} parent 1: protocol ip prio $id u32 \
|
||||
match u16 0x0800 0xFFFF at -2 \
|
||||
match u32 0x${M1}${M2} 0xFFFFFFFF at -12 \
|
||||
match u16 0x${M0} 0xFFFF at -14 \
|
||||
flowid 1:$id
|
||||
fi
|
||||
}
|
||||
|
||||
add_ip() {
|
||||
local list_id=$1
|
||||
id=$((list_id * 10 + 1000))
|
||||
[ "${DEBUG:-0}" -eq 0 ] || echo "D: add_ip $@ --$id --$mac"
|
||||
|
||||
Z=$(echo $mac | awk -F '[/]' '{print $2}')
|
||||
[ -n "$Z" ] && mac=$(echo $mac | awk -F '[/]' '{print $1}') || Z=32
|
||||
if is_gt_zero "$UL"; then
|
||||
if [ -n "$nftables_ver" ]; then
|
||||
$nft add rule inet ${NAME} mark_forward ip saddr $mac/$Z counter meta mark set $id
|
||||
$nft add rule inet ${NAME} mark_output ip saddr $mac/$Z counter meta mark set $id
|
||||
$nft add rule inet ${NAME} mark_postrouting ip saddr $mac/$Z counter meta mark set $id
|
||||
fi
|
||||
$tc class add dev ${dev}_ifb parent 1:1 classid 1:$id htb rate "${UL}kbit" ceil "${UL}kbit" prio $id burst 15k cburst 15k
|
||||
$tc qdisc add dev ${dev}_ifb parent 1:$id handle ${id}: sfq perturb 10
|
||||
$tc filter add dev ${dev}_ifb parent 1: protocol ip prio $id handle $id fw flowid 1:$id
|
||||
$tc filter add dev ${dev}_ifb parent 1:0 prio $((id + 100)) protocol ip u32 \
|
||||
match ip src "$mac"/"$Z" \
|
||||
flowid 1:$id
|
||||
fi
|
||||
if is_gt_zero "$DL"; then
|
||||
$tc class add dev ${dev} parent 1:1 classid 1:$id htb rate "${DL}kbit" ceil "${DL}kbit" prio $id burst 15k cburst 15k
|
||||
$tc qdisc add dev ${dev} parent 1:$id handle ${id}: sfq perturb 10
|
||||
$tc filter add dev ${dev} parent 1:0 prio $id protocol ip u32 \
|
||||
match ip dst "$mac"/"$Z" \
|
||||
flowid 1:$id
|
||||
fi
|
||||
}
|
||||
|
||||
check_time() {
|
||||
local start=$1
|
||||
local end=$2
|
||||
local current=$(date +%H%M)
|
||||
local start_min=$((10#${start:0:2}*60 + 10#${start:3:2}))
|
||||
local end_min=$((10#${end:0:2}*60 + 10#${end:3:2}))
|
||||
local current_min=$((10#${current:0:2}*60 + 10#${current:2:2}))
|
||||
|
||||
if [[ $start_min -lt $end_min ]]; then
|
||||
[[ $current_min -ge $start_min && $current_min -lt $end_min ]]
|
||||
else
|
||||
[[ $current_min -ge $start_min || $current_min -lt $end_min ]]
|
||||
fi
|
||||
}
|
||||
|
||||
check_list() {
|
||||
local i=$1
|
||||
local start_time=$(uci -q get $NAME.@device[$i].timestart 2>/dev/null)
|
||||
local end_time=$(uci -q get $NAME.@device[$i].timeend 2>/dev/null)
|
||||
local wweek=$(uci -q get $NAME.@device[$i].week 2>/dev/null)
|
||||
local current_weekday=$(date +%u)
|
||||
[ -z "$start_time" ] && [ -z "$end_time" ] && [ -z "$wweek" ] && return 0
|
||||
|
||||
if [ -n "$wweek" ] && [ "$wweek" != "0" ]; then
|
||||
local day_match=0
|
||||
for day in $(echo $wweek | tr ',' ' '); do
|
||||
[ "$day" -eq "$current_weekday" ] && day_match=1 && break
|
||||
done
|
||||
[ "$day_match" -eq 0 ] && return 1
|
||||
fi
|
||||
|
||||
if [ -n "$start_time" ] && [ -n "$end_time" ]; then
|
||||
check_time "$start_time" "$end_time" || return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
case "$crrun" in
|
||||
"stop")
|
||||
stop_qos
|
||||
;;
|
||||
"start")
|
||||
stop_qos > /dev/null 2>&1
|
||||
sleep 2
|
||||
init_qosplus
|
||||
idlist=$(uci show $NAME 2>/dev/null | grep "enable='1'" | grep "device" | grep -oE '\[.*?\]' | grep -o '[0-9]' | sort -nu | sed -e 's/^/!/g' -e 's/$/!/g' > $IDLIST; cat $IDLIST 2>/dev/null | sed -e 's/!//g')
|
||||
|
||||
if [ ! -s "$IDLIST" ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
device_count=0
|
||||
for list in $(echo $idlist | sed -e 's/!//g'); do
|
||||
if check_list $list; then
|
||||
mac=$(uci -q get $NAME.@device[$list].mac 2>/dev/null)
|
||||
download_mb=$(uci -q get $NAME.@device[$list].download 2>/dev/null)
|
||||
upload_mb=$(uci -q get $NAME.@device[$list].upload 2>/dev/null)
|
||||
comment=$(uci -q get $NAME.@device[$list].comment 2>/dev/null)
|
||||
|
||||
# 转换为kbit
|
||||
DL=$(to_kbit "$download_mb")
|
||||
UL=$(to_kbit "$upload_mb")
|
||||
|
||||
if [ -n "$mac" ]; then
|
||||
if is_macaddr "$mac"; then
|
||||
add_mac $list >>$LOG
|
||||
echo "✅ MAC限速: $comment ($mac) - 下载:${download_mb}MB/s(${DL}kbit/s) 上传:${upload_mb}MB/s(${UL}kbit/s)" >>$LOG
|
||||
else
|
||||
add_ip $list >>$LOG
|
||||
echo "✅ IP限速: $comment ($mac) - 下载:${download_mb}MB/s(${DL}kbit/s) 上传:${upload_mb}MB/s(${UL}kbit/s)" >>$LOG
|
||||
fi
|
||||
device_count=$((device_count + 1))
|
||||
fi
|
||||
else
|
||||
[ -f "$IDLIST" ] && [ $(grep "!${list}!" "$IDLIST" 2>/dev/null | wc -l) -gt 0 ] && {
|
||||
del_id $list >>$LOG
|
||||
sed -i "/!$list!/d" "$IDLIST" >/dev/null 2>&1
|
||||
comment=$(uci -q get $NAME.@device[$list].comment 2>/dev/null)
|
||||
}
|
||||
fi
|
||||
done
|
||||
echo "EQOSPLUS限速服务启动完成,共配置 $device_count 个设备" >>$LOG
|
||||
echo ""
|
||||
echo "当前限速状态:" >>$LOG
|
||||
tc -s class show dev $dev | grep "rate" | head -5 >>$LOG
|
||||
tc -s class show dev ${dev}_ifb | grep "rate" | head -5 >>$LOG
|
||||
|
||||
;;
|
||||
"add")
|
||||
echo "➕ 添加限速规则..."
|
||||
for list in $(echo $crid | sed -e 's/!//g' | sed 's/,/ /g'); do
|
||||
mac=$(uci -q get $NAME.@device[$list].mac 2>/dev/null)
|
||||
download_mb=$(uci -q get $NAME.@device[$list].download 2>/dev/null)
|
||||
upload_mb=$(uci -q get $NAME.@device[$list].upload 2>/dev/null)
|
||||
comment=$(uci -q get $NAME.@device[$list].comment 2>/dev/null)
|
||||
DL=$(to_kbit "$download_mb")
|
||||
UL=$(to_kbit "$upload_mb")
|
||||
|
||||
if is_macaddr $mac; then
|
||||
add_mac $list
|
||||
echo "✅ 添加MAC限速: $comment ($mac)" >>$LOG
|
||||
else
|
||||
add_ip $list
|
||||
echo "✅ 添加IP限速: $comment ($mac)" >>$LOG
|
||||
fi
|
||||
done
|
||||
;;
|
||||
"del")
|
||||
for list in $(echo $crid | sed -e 's/!//g' | sed 's/,/ /g'); do
|
||||
comment=$(uci -q get $NAME.@device[$list].comment 2>/dev/null)
|
||||
mac=$(uci -q get $NAME.@device[$list].mac 2>/dev/null)
|
||||
del_id $list
|
||||
done
|
||||
;;
|
||||
"status")
|
||||
echo "EQOSPLUS限速服务状态"
|
||||
echo "### 网络接口: $dev ###"
|
||||
echo "# 下载队列统计 #"
|
||||
tc -s qdisc show dev $dev 2>/dev/null || echo "无下载队列"
|
||||
echo "# 下载类统计 #"
|
||||
tc -s class show dev $dev 2>/dev/null | grep -E "class htb|rate [0-9]" || echo "无下载类"
|
||||
echo "# 下载过滤器 #"
|
||||
tc -s filter show dev $dev parent 1: 2>/dev/null | head -10 || echo "无下载过滤器"
|
||||
|
||||
echo "### 虚拟接口: ${dev}_ifb ###"
|
||||
echo "# 上传队列统计 #"
|
||||
tc -s qdisc show dev ${dev}_ifb 2>/dev/null || echo "无上传队列"
|
||||
echo "# 上传类统计 #"
|
||||
tc -s class show dev ${dev}_ifb 2>/dev/null | grep -E "class htb|rate [0-9]" || echo "无上传类"
|
||||
echo "# 上传过滤器 #"
|
||||
tc -s filter show dev ${dev}_ifb parent 1: 2>/dev/null | head -10 || echo "无上传过滤器"
|
||||
|
||||
if [ -n "$nftables_ver" ]; then
|
||||
echo "### NFTables规则 ###"
|
||||
nft list table inet ${NAME} 2>/dev/null || echo "没有NFTables规则"
|
||||
else
|
||||
echo "NFTables不可用"
|
||||
fi
|
||||
|
||||
# 显示流量统计
|
||||
echo "### 流量统计 ###"
|
||||
echo "下载流量:"
|
||||
tc -s class show dev $dev 2>/dev/null | grep "Sent" | head -5
|
||||
echo "上传流量:"
|
||||
tc -s class show dev ${dev}_ifb 2>/dev/null | grep "Sent" | head -5
|
||||
;;
|
||||
|
||||
esac
|
||||
@@ -0,0 +1,63 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Copyright (C) 2006 OpenWrt.org
|
||||
# Copyright 2022-2025 sirpdboy <herboy2008@gmail.com>
|
||||
NAME=eqosplus
|
||||
IDLIST="/var/$NAME.idlist"
|
||||
TMPID="/var/$NAME.tmpid"
|
||||
|
||||
idlist=`uci show $NAME | grep "enable='1'" | grep "device" | grep -oE '\[.*?\]' | grep -o '[0-9]' `
|
||||
|
||||
check_list() {
|
||||
i=$1
|
||||
checki='0'
|
||||
start_time=$(uci -q get $NAME.@device[$i].timestart 2>/dev/null)
|
||||
end_time=$(uci -q get $NAME.@device[$i].timeend 2>/dev/null)
|
||||
wweek=`uci -q get $NAME.@device[$i].week `
|
||||
current_time=$(date +%H:%M)
|
||||
current_weekday=$(date +%u)
|
||||
for ww in `echo $wweek | sed 's/,/ /g' `; do
|
||||
if [ $current_weekday = $ww ] || [ 'x0' = x$ww ] ;then
|
||||
[ "$start_time" = "$end_time" ] && checki='1' || {
|
||||
if [ "$start_time" \< "$end_time" ]; then
|
||||
if [ "$current_time" \> "$start_time" ] && [ "$current_time" \< "$end_time" ] ; then
|
||||
checki='1'
|
||||
fi
|
||||
else
|
||||
if [ "$start_time" \> "$end_time" ] ; then
|
||||
if [ "$current_time" \< "$start_time" ] && [ "$current_time" \> "$end_time" ] ; then
|
||||
checki='1'
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
}
|
||||
fi
|
||||
done
|
||||
return
|
||||
}
|
||||
|
||||
idlistusr(){
|
||||
checki='0'
|
||||
[ -s $IDLIST ] || touch $IDLIST
|
||||
for list in $idlist ;do
|
||||
check_list $list
|
||||
if [ $checki == '1' ] ; then
|
||||
[ `cat $IDLIST 2>/dev/null | grep "!${list}!" | wc -l ` -gt 0 ] || {
|
||||
eqosplus add $list
|
||||
echo "!${list}!" >> $IDLIST ; cat $IDLIST | sort | uniq > $TMPID ;cat $TMPID >$IDLIST ;rm -rf $TMPID
|
||||
}
|
||||
else
|
||||
[ `cat $IDLIST 2>/dev/null | grep "!${list}!" | wc -l ` -gt 0 ] && {
|
||||
eqosplus del $list
|
||||
sed -i "/!$list!/d" $IDLIST >/dev/null 2>&1
|
||||
}
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
while :;do
|
||||
sleep 30
|
||||
idlistusr
|
||||
sleep 30
|
||||
done
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"luci-app-eqosplus": {
|
||||
"description": "Grant UCI access for luci-app-eqosplus",
|
||||
"read": {
|
||||
"uci": [ "eqosplus" ]
|
||||
},
|
||||
"write": {
|
||||
"uci": [ "eqosplus" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 585 KiB |
@@ -10,10 +10,8 @@ LUCI_DEPENDS:=+fastnet +luci-lib-linkeaseauth +linkease-app-entry
|
||||
# APK uses -rN; OPKG uses -N for runtime package releases.
|
||||
LUCI_EXTRA_DEPENDS:=fastnet (>=0.8.9-$(if $(CONFIG_USE_APK),r)1)
|
||||
LUCI_PKGARCH:=all
|
||||
PKG_VERSION:=0.8.9-r1
|
||||
PKG_VERSION:=0.8.9-r2
|
||||
PKG_RELEASE:=
|
||||
# Preserve LuCI translation version ordering when upgrading older git-* packages.
|
||||
PKG_PO_VERSION:=git-26.313.00000-082
|
||||
LUCI_MINIFY_CSS:=0
|
||||
LUCI_MINIFY_JS:=0
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-ghfu
|
||||
PKG_VERSION:=1.3.2
|
||||
PKG_VERSION:=1.3.3
|
||||
PKG_RELEASE:=1
|
||||
PKG_LICENSE:=GPL-3.0-only
|
||||
PKG_LICENSE_FILES:=LICENSE
|
||||
PKG_MAINTAINER:=smallprogram
|
||||
|
||||
LUCI_TITLE:=LuCI support for GitHub Firmware Upgrade
|
||||
LUCI_DEPENDS:=+luci-base +uclient-fetch +ca-bundle
|
||||
LUCI_DEPENDS:=+luci-base +wget-ssl +ca-bundle
|
||||
LUCI_PKGARCH:=all
|
||||
|
||||
ifneq ($(wildcard $(TOPDIR)/feeds/luci/luci.mk),)
|
||||
|
||||
@@ -374,12 +374,12 @@ local function fetch_previous_release_with_assets(repo, timeout, accept_header,
|
||||
end
|
||||
|
||||
fetch_github_json = function(url, timeout, accept_header)
|
||||
local cmd = "uclient-fetch -T " .. tostring(timeout) .. " -H " .. util.shellquote(accept_header) .. " -qO- " .. util.shellquote(url) .. " 2>/dev/null"
|
||||
local cmd = "wget -T " .. tostring(timeout) .. " --header=" .. util.shellquote(accept_header) .. " -qO- " .. util.shellquote(url) .. " 2>/dev/null"
|
||||
local raw = sys.exec(cmd)
|
||||
|
||||
-- Fallback for uclient-fetch variants without custom-header support.
|
||||
-- Fallback for wget variants without custom-header support.
|
||||
if not raw or raw == "" then
|
||||
local fallback = "uclient-fetch -T " .. tostring(timeout) .. " -qO- " .. util.shellquote(url) .. " 2>/dev/null"
|
||||
local fallback = "wget -T " .. tostring(timeout) .. " -qO- " .. util.shellquote(url) .. " 2>/dev/null"
|
||||
raw = sys.exec(fallback)
|
||||
end
|
||||
|
||||
@@ -593,6 +593,7 @@ function action_download()
|
||||
local repo = normalize_repo(http.formvalue("repo") or "")
|
||||
local selected_release = trim(http.formvalue("selected_release") or "")
|
||||
local keep_config = to_bool(http.formvalue("keep_config")) and "1" or "0"
|
||||
local cfg = get_cfg()
|
||||
local asset_url = trim(http.formvalue("asset_url") or "")
|
||||
local asset_name = trim(http.formvalue("asset_name") or "firmware.bin.gz")
|
||||
local asset_size = tonumber(trim(http.formvalue("asset_size") or "")) or 0
|
||||
@@ -637,6 +638,12 @@ function action_download()
|
||||
local fw_path = "/tmp/ghfu_" .. clean_name
|
||||
local progress_log = "/tmp/ghfu-download-progress.log"
|
||||
local raw_log = "/tmp/ghfu-download-raw.log"
|
||||
local download_timeout = math.floor(tonumber(cfg.fetch_timeout) or 15)
|
||||
if download_timeout < 120 then
|
||||
download_timeout = 120
|
||||
elseif download_timeout > 300 then
|
||||
download_timeout = 300
|
||||
end
|
||||
fs.unlink(progress_log)
|
||||
fs.unlink(raw_log)
|
||||
|
||||
@@ -645,10 +652,20 @@ function action_download()
|
||||
"raw_log=", util.shellquote(raw_log), "\n",
|
||||
"target=", util.shellquote(fw_path), "\n",
|
||||
"total=", tostring(math.max(0, math.floor(asset_size))), "\n",
|
||||
"timeout=", tostring(download_timeout), "\n",
|
||||
"url=", util.shellquote(asset_url), "\n",
|
||||
": > \"$progress_log\"\n",
|
||||
": > \"$raw_log\"\n",
|
||||
"uclient-fetch -qO \"$target\" \"$url\" >\"$raw_log\" 2>&1 &\n",
|
||||
"(\n",
|
||||
"if command -v wget >/dev/null 2>&1; then\n",
|
||||
" wget -T \"$timeout\" -O \"$target\" \"$url\" >\"$raw_log\" 2>&1\n",
|
||||
" rc=$?\n",
|
||||
"else\n",
|
||||
" echo \"wget is not installed\" >\"$raw_log\"\n",
|
||||
" rc=127\n",
|
||||
"fi\n",
|
||||
"exit \"$rc\"\n",
|
||||
") &\n",
|
||||
"dlpid=$!\n",
|
||||
"prev_size=0\n",
|
||||
"prev_ts=$(date +%s)\n",
|
||||
@@ -769,13 +786,13 @@ function action_download_status()
|
||||
else
|
||||
local status2, done_size, done_total, target2 = line:match("^DONE|([A-Z]+)|(%d+)|(%d+)|(.+)$")
|
||||
if status2 then
|
||||
if tonumber(done_total) and tonumber(done_total) > 0 then
|
||||
logs[#logs + 1] = tr("Download finished: ") .. human_bytes(done_size) .. "/" .. human_bytes(done_total)
|
||||
else
|
||||
logs[#logs + 1] = tr("Download finished: ") .. human_bytes(done_size)
|
||||
end
|
||||
|
||||
if status2 == "OK" then
|
||||
if tonumber(done_total) and tonumber(done_total) > 0 then
|
||||
logs[#logs + 1] = tr("Download finished: ") .. human_bytes(done_size) .. "/" .. human_bytes(done_total)
|
||||
else
|
||||
logs[#logs + 1] = tr("Download finished: ") .. human_bytes(done_size)
|
||||
end
|
||||
|
||||
local name2 = tostring(target2 or ""):match("/tmp/ghfu_(.+)$")
|
||||
if name2 and name2 ~= "" then
|
||||
logs[#logs + 1] = name2 .. tr(" downloaded successfully")
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-honk
|
||||
PKG_VERSION:=2026.11.11
|
||||
PKG_VERSION:=2026.11.12.1
|
||||
PKG_RELEASE:=1
|
||||
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
|
||||
|
||||
|
||||
@@ -180,7 +180,7 @@ return view.extend({
|
||||
E('div', { 'class': 'honk-actions' }, actions)
|
||||
]),
|
||||
E('div', { 'class': 'honk-meta' }, [
|
||||
metaItem(_('Core version'), status.core_lane === 'linux66' ? status.core_version + ' · ' + _('Linux 6.6 experimental') : status.core_version),
|
||||
metaItem(_('Core version'), status.core_version),
|
||||
metaItem(_('Doona version'), status.doona_version),
|
||||
metaItem(_('Kernel'), status.kernel)
|
||||
])
|
||||
|
||||
@@ -30,11 +30,30 @@ if command -v apk >/dev/null 2>&1; then
|
||||
}
|
||||
' | sort -V | tail -1)
|
||||
elif command -v opkg >/dev/null 2>&1; then
|
||||
installed=$(opkg status "$PKG" 2>/dev/null | awk '
|
||||
/^Version: / { version = $2 }
|
||||
/^Status: .* installed$/ { installed = 1 }
|
||||
END { if (installed) print version }
|
||||
')
|
||||
# 直接读状态文件:opkg update 占着锁时 opkg status 会失败,面板就误报未安装。
|
||||
if [ -r /usr/lib/opkg/status ]; then
|
||||
installed=$(awk -v p="$PKG" '
|
||||
$1 == "Package:" { cur = $2; ver = ""; ok = 0 }
|
||||
$1 == "Version:" { ver = $2 }
|
||||
$1 == "Status:" { ok = ($NF == "installed") }
|
||||
cur == p && ok && ver != "" { print ver; exit }
|
||||
' /usr/lib/opkg/status)
|
||||
else
|
||||
installed=$(opkg status "$PKG" 2>/dev/null | awk '
|
||||
/^Version: / { version = $2 }
|
||||
/^Status: .* installed$/ { installed = 1 }
|
||||
END { if (installed) print version }
|
||||
')
|
||||
fi
|
||||
latest=$(
|
||||
for _list in /var/opkg-lists/*; do
|
||||
[ "${_list%.sig}" = "$_list" ] || continue
|
||||
zcat "$_list" 2>/dev/null || cat "$_list" 2>/dev/null
|
||||
done | awk -v p="$PKG" '
|
||||
$1 == "Package:" { cur = $2 }
|
||||
cur == p && $1 == "Version:" { print $2 }
|
||||
' | sort -V | tail -1
|
||||
)
|
||||
fi
|
||||
|
||||
printf '%s\t%s\n' "$installed" "$latest"
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/bin/sh
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
# Background apk index refresh for the Maintenance view. Returns at once.
|
||||
# Background package index refresh for the Maintenance view. Returns at once.
|
||||
|
||||
LOCK=/tmp/luci-app-honk.idx.lock
|
||||
|
||||
@@ -10,10 +10,15 @@ if [ -f "$LOCK" ]; then
|
||||
fi
|
||||
: > "$LOCK"
|
||||
|
||||
(
|
||||
if command -v apk >/dev/null 2>&1; then
|
||||
flock -n /tmp/luci-app-honk.apk.lock apk update
|
||||
fi
|
||||
) >/dev/null 2>&1 </dev/null &
|
||||
if command -v apk >/dev/null 2>&1; then
|
||||
apk update >/dev/null 2>&1 </dev/null &
|
||||
elif command -v opkg >/dev/null 2>&1; then
|
||||
opkg update >/dev/null 2>&1 </dev/null &
|
||||
else
|
||||
exit 0
|
||||
fi
|
||||
_pid=$!
|
||||
# 有一个镜像卡住就会把 opkg 锁占死,60 秒后直接掐掉。
|
||||
( sleep 60; kill -TERM "$_pid" 2>/dev/null; sleep 5; kill -KILL "$_pid" 2>/dev/null ) >/dev/null 2>&1 &
|
||||
|
||||
exit 0
|
||||
@@ -33,6 +33,23 @@ service_running() {
|
||||
honk_lifecycle_managed_pid >/dev/null 2>&1
|
||||
}
|
||||
|
||||
# 镜像卡住时 opkg update 会一直占着锁;这里给它上闸,超时直接掐掉。
|
||||
pkg_update() {
|
||||
_limit=$1; shift
|
||||
"$@" &
|
||||
_pid=$!
|
||||
( sleep "$_limit"; kill -TERM "$_pid" 2>/dev/null ) &
|
||||
_watch=$!
|
||||
wait "$_pid" 2>/dev/null
|
||||
_rc=$?
|
||||
kill -TERM "$_watch" 2>/dev/null
|
||||
wait "$_watch" 2>/dev/null
|
||||
if [ "$_rc" != 0 ]; then
|
||||
echo "note: 索引刷新超时或被中断(${_limit}s),改用现有缓存继续"
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
restore_service_state() {
|
||||
if [ "$was_running" = 1 ]; then
|
||||
echo "--- 升级前为运行状态,重启加载新内核 ---"
|
||||
@@ -91,7 +108,7 @@ fi
|
||||
if command -v apk >/dev/null 2>&1; then
|
||||
(
|
||||
flock 9
|
||||
apk update 2>&1
|
||||
apk list "$PKG" 2>/dev/null | grep -q "^$PKG-" || pkg_update 60 apk update 2>&1
|
||||
ver=$(apk list "$PKG" 2>/dev/null | awk -v p="$PKG" '$1 ~ "^" p "-[0-9]" { v=$1; sub("^" p "-", "", v); print v }' | sort -V | tail -1)
|
||||
if [ -n "$ver" ]; then
|
||||
constraint="$PKG=$ver"
|
||||
@@ -121,6 +138,26 @@ fi
|
||||
echo "result: $PKG is at the latest available version"
|
||||
rc=0
|
||||
fi
|
||||
elif command -v opkg >/dev/null 2>&1; then
|
||||
(
|
||||
flock 9
|
||||
opkg list "$PKG" 2>/dev/null | grep -q "^$PKG - " || pkg_update 60 opkg update 2>&1
|
||||
opkg install "$PKG" 2>&1
|
||||
exit 0
|
||||
) 9>/tmp/luci-app-honk.opkg.lock
|
||||
rc=$?
|
||||
if [ "$rc" != 0 ]; then
|
||||
:
|
||||
elif ! opkg status "$PKG" 2>/dev/null | grep -q '^Status: .* installed$'; then
|
||||
echo "result: $PKG is not installed"
|
||||
rc=1
|
||||
elif opkg list-upgradable 2>/dev/null | grep -q "^${PKG} - "; then
|
||||
echo "result: $PKG still has a pending upgrade"
|
||||
rc=1
|
||||
else
|
||||
echo "result: $PKG is at the latest available version"
|
||||
rc=0
|
||||
fi
|
||||
else
|
||||
echo "no package manager found"
|
||||
exit 3
|
||||
|
||||
@@ -73,6 +73,8 @@ url_test_node() {
|
||||
fi
|
||||
sleep 2s
|
||||
probeUrl=$(config_n_get @global_other[0] url_test_url https://www.google.com/generate_204)
|
||||
# 预热代理链路,减轻首次请求的冷启动影响,提高部分节点的测试成功率和延迟稳定性
|
||||
curl --connect-timeout 3 --max-time 5 -o /dev/null -I -sk "$@" -x "$curlx" "$probeUrl" >/dev/null 2>&1
|
||||
result=$(curl --connect-timeout 3 --max-time 5 -o /dev/null -I -sk -w "%{http_code}:%{time_pretransfer}:%{time_starttransfer}" "$@" -x "$curlx" "${probeUrl}") || result=0
|
||||
# 结束 SS 插件进程
|
||||
if [ "$_type" != "socks" ]; then
|
||||
|
||||
@@ -51,6 +51,8 @@ url_test_node() {
|
||||
local curlx="socks5h://127.0.0.1:${_tmp_port}"
|
||||
sleep 2s
|
||||
local probeUrl=$(config_n_get @global_other[0] url_test_url https://www.google.com/generate_204)
|
||||
# Warm up the proxy connection to reduce cold-start effects on latency tests.
|
||||
curl --connect-timeout 3 --max-time 5 -o /dev/null -I -sk -x "$curlx" "$probeUrl" >/dev/null 2>&1
|
||||
result=$(curl --connect-timeout 3 --max-time 5 -o /dev/null -I -skL -w "%{http_code}:%{time_pretransfer}" -x ${curlx} "${probeUrl}")
|
||||
# End the SS plugin process
|
||||
local pid_file="${TMP_PATH}/url_test_${node_id}_plugin.pid"
|
||||
|
||||
@@ -9,7 +9,7 @@ LUCI_TITLE:=LuCI support for quickstart
|
||||
LUCI_DEPENDS:=+quickstart +luci-app-ttyd
|
||||
LUCI_PKGARCH:=all
|
||||
|
||||
PKG_VERSION:=0.12.10-r1
|
||||
PKG_VERSION:=0.17.1-rc20261028-r1
|
||||
# PKG_RELEASE MUST be empty for luci.mk
|
||||
PKG_RELEASE:=
|
||||
|
||||
@@ -19,4 +19,3 @@ LUCI_MINIFY_JS:=0
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
# call BuildPackage - OpenWrt buildroot signature
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
import{defineComponent as N,computed as c,openBlock as d,createBlock as y,withCtx as I,createElementVNode as e,createVNode as k,toDisplayString as l,createElementBlock as r,createTextVNode as h,createCommentVNode as g}from"/luci-static/quickstart/card-runtime-v1.js";import{N as F,_ as p,n as w}from"./app.js?v=txJtMzYh";import"./vendor.js?v=B46K-l76";const C={class:"fastnet-install","data-fastnet-install-dialog":""},_={class:"fastnet-install-product"},$={class:"fastnet-install-icon"},B={class:"fastnet-install-badge"},V={class:"fastnet-install-description",role:"status"},D={key:0,class:"fastnet-install-error",role:"alert"},U={key:1,class:"fastnet-install-note"},q={class:"fastnet-install-footer"},M={class:"fastnet-install-links"},R={href:"/cgi-bin/luci/admin/store",target:"_blank",rel:"noopener"},T=["disabled"],x={class:"fastnet-install-actions"},A=["disabled","aria-busy"],E={key:0,class:"fastnet-install-spinner","aria-hidden":"true"},P=N({__name:"FastnetInstallDialog",props:{state:{},installing:{type:Boolean},error:{}},emits:["close","install","recheck"],setup(s){const n=s,f=window.vue_lang==="en",t=(o,a)=>f?a:o,i=c(()=>n.installing||n.state==="installing"),m=c(()=>i.value?t("正在安装","Installing"):n.state==="checking"?t("检查中","Checking"):n.state==="update_required"?t("需要更新","Update needed"):n.state==="unknown"?t("待确认","Unconfirmed"):n.state==="failed"?t("安装未完成","Incomplete"):t("尚未安装","Not installed")),v=c(()=>i.value?t("正在安装 FastNet,完成后即可添加外网测速卡片。","Installing FastNet. You can add the Internet speed card once it is ready."):n.state==="checking"?t("正在确认插件和安装状态,请稍候。","Checking the plugin and installation status."):n.state==="update_required"?t("当前插件版本尚未提供可用卡片,请先升级或修复 FastNet。","Update or repair FastNet to make this card available."):n.state==="unknown"?t("暂时无法确认安装状态,请重新读取或到软件中心检查。","Reload the installation status or check FastNet in the software center."):n.state==="failed"?t("FastNet 安装未完成,请检查软件源后重试。","FastNet installation did not complete. Check the package source and retry."):t("添加外网测速模块前,需要先安装 FastNet 插件。","Install FastNet before adding the Internet speed module.")),b=c(()=>n.installing?t("正在安装","Installing"):n.state==="checking"?t("正在检查","Checking"):n.state==="installing"?t("查看安装进度","View progress"):n.state==="update_required"?t("升级或修复","Update or repair"):n.state==="failed"?t("重试安装","Retry installation"):t("安装插件","Install plugin"));return(o,a)=>(d(),y(F,{title:t("安装 FastNet 插件","Install FastNet"),onClose:a[3]||(a[3]=u=>o.$emit("close"))},{default:I(()=>[e("div",C,[e("div",_,[e("span",$,[k(p,{name:"activity"})]),e("div",null,[a[4]||(a[4]=e("strong",null,"FastNet",-1)),e("p",null,l(t("外网速率 · NAT · IPv6","Internet speed · NAT · IPv6")),1)]),e("span",B,l(m.value),1)]),e("p",V,l(v.value),1),s.error?(d(),r("div",D,[a[5]||(a[5]=e("span",{"aria-hidden":"true"},"!",-1)),e("p",null,l(s.error),1)])):(d(),r("div",U,[k(p,{name:i.value?"clock":"check"},null,8,["name"]),e("p",null,l(i.value?t("可以关闭此窗口,安装会在后台继续。","You can close this window. Installation continues in the background."):t("安装后再选择卡片位置,不会自动开始测速。","Choose a card position after installation. No speed test starts automatically.")),1)])),e("div",q,[e("div",M,[e("a",R,[h(l(t("软件中心","Software center")),1),a[6]||(a[6]=e("svg",{viewBox:"0 0 16 16","aria-hidden":"true"},[e("path",{d:"M9 3h4v4M13 3 6 10M7 3H3v10h10V9"})],-1))]),s.installing?g("",!0):(d(),r("button",{key:0,type:"button",onClick:a[0]||(a[0]=u=>o.$emit("recheck")),disabled:s.state==="checking","data-recheck-card-install":""},l(t("重新读取","Reload status")),9,T))]),e("div",x,[e("button",{type:"button",class:"fastnet-install-back",onClick:a[1]||(a[1]=u=>o.$emit("close"))},l(t("返回","Back")),1),s.state!=="unknown"?(d(),r("button",{key:0,type:"button",class:"fastnet-install-primary",disabled:s.installing||s.state==="checking","aria-busy":i.value||s.state==="checking",onClick:a[2]||(a[2]=u=>o.$emit("install")),"data-confirm-card-install":""},[i.value||s.state==="checking"?(d(),r("span",E)):g("",!0),h(l(b.value),1)],8,A)):g("",!0)])])])]),_:1},8,["title"]))}}),W=w(P,[["__scopeId","data-v-a66b8b77"]]);export{W as default};
|
||||
@@ -0,0 +1,7 @@
|
||||
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["luci-static/quickstart/FastnetInstallDialog.js","luci-static/quickstart/app.js","luci-static/quickstart/vendor.js","luci-static/quickstart/installClient.js"])))=>i.map(i=>d[i]);
|
||||
var kr=Object.defineProperty,wr=Object.defineProperties;var $r=Object.getOwnPropertyDescriptors;var ms=Object.getOwnPropertySymbols;var _l=Object.prototype.hasOwnProperty,yl=Object.prototype.propertyIsEnumerable;var fs=Math.pow,co=(s,t,n)=>t in s?kr(s,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):s[t]=n,ye=(s,t)=>{for(var n in t||(t={}))_l.call(t,n)&&co(s,n,t[n]);if(ms)for(var n of ms(t))yl.call(t,n)&&co(s,n,t[n]);return s},Ne=(s,t)=>wr(s,$r(t));var kl=(s,t)=>{var n={};for(var l in s)_l.call(s,l)&&t.indexOf(l)<0&&(n[l]=s[l]);if(s!=null&&ms)for(var l of ms(s))t.indexOf(l)<0&&yl.call(s,l)&&(n[l]=s[l]);return n};var Nn=(s,t,n)=>co(s,typeof t!="symbol"?t+"":t,n);var B=(s,t,n)=>new Promise((l,u)=>{var c=v=>{try{p(n.next(v))}catch(h){u(h)}},r=v=>{try{p(n.throw(v))}catch(h){u(h)}},p=v=>v.done?l(v.value):Promise.resolve(v.value).then(c,r);p((n=n.apply(s,t)).next())});import{defineComponent as X,computed as R,openBlock as i,createElementBlock as d,normalizeStyle as pt,createElementVNode as e,toDisplayString as a,unref as o,createCommentVNode as T,resolveComponent as At,createVNode as G,renderSlot as Ct,withDirectives as W,vModelCheckbox as gt,createBlock as Y,withCtx as pe,ref as x,watch as We,onMounted as nt,Fragment as V,renderList as oe,vModelSelect as Be,vModelText as Oe,createStaticVNode as Hn,shallowRef as Na,nextTick as ot,onUnmounted as lt,Teleport as Fo,withModifiers as Ge,normalizeClass as _e,withKeys as Qt,reactive as Xe,readonly as Cr,markRaw as Kn,onErrorCaptured as Sr,resolveDynamicComponent as Aa,mergeProps as Zl,inject as ba,Transition as fn,createApp as cn,createTextVNode as ue,provide as ma,TransitionGroup as xr,toRef as uo,onBeforeUnmount as ga,vShow as Bs,vModelRadio as Mt,createSlots as Pr,defineAsyncComponent as Tr,h as vo,isRef as Mr,Suspense as Er,render as Us,withAsyncContext as Ir,useCssVars as Dr,vModelDynamic as Lr}from"/luci-static/quickstart/card-runtime-v1.js";import{a as Ar,c as Nr,d as Fs,u as Yl,i as Or,b as zr,e as qr,f as Ql,g as Xl,h as Rr,j as ei,k as as,l as ta,o as ti,m as Vr,n as ss,p as Br,q as Ur,r as Fr}from"./vendor.js?v=B46K-l76";const Bn={language:void 0,numberFormat:new Intl.NumberFormat("en",{notation:"compact"})},tj=s=>B(null,null,function*(){const t=window.vue_lang||(navigator.language.toLowerCase().startsWith("zh")?"zh-cn":"en");let n={};const l=window.vue_lang_data||(t==="zh-cn"?"":`/luci-static/quickstart/i18n/${t}.json`);if(l)try{const r=yield Ar({url:l,method:"GET"});r.data&&(n=r.data)}catch(r){console.log(r)}const u=Nr({defaultLanguage:t,mutedLanguages:["zh-cn"],translations:n,setGlobalProperties:!1,provideDirective:!1,provideComponent:!1});s.use(u),Bn.language=u;const{$gettext:c}=u;window.$i18n=c;try{Bn.numberFormat=new Intl.NumberFormat(t,{notation:"compact"})}catch(r){console.error("Intl.NumberFormat unsupported lang",t,r)}}),Ae=()=>{if(Bn.language)return Bn.language;throw new Error("I18N Uninitialized!")},Hs=()=>({$gettext:(s,t,n)=>{if(Bn.language)return Bn.language.$gettext(s,t,n);throw new Error("I18N Uninitialized!")},$ngettext:(s,t,n,l,u)=>{if(Bn.language)return Bn.language.$ngettext(s,t,n,l,u);throw new Error("I18N Uninitialized!")}}),bs=s=>typeof s=="number"?Bn.numberFormat.format(s):"?",{$gettext:Hr}=Hs(),ni=(s,t)=>B(null,null,function*(){return new Promise((n,l)=>B(null,null,function*(){try{const u=yield fetch(s,t);if(Math.floor(u.status/100)!=2)throw u.status+" "+u.statusText;const c=ye({},u);c.data=yield u.json(),n(c)}catch(u){const c=u;l(Hr("网络异常:")+((c==null?void 0:c.message)||u))}}))});class Ho{constructor(t){Nn(this,"config",{baseURL:"",headers:{}});Nn(this,"useRequest",t=>t);Nn(this,"useResponse",t=>t);Nn(this,"useError",t=>t);t.baseURL&&(this.config.baseURL=t.baseURL),t.headers&&(this.config.headers=t.headers)}static create(t){return new Ho(t)}Do(t,n){return B(this,null,function*(){return new Promise((l,u)=>B(this,null,function*(){try{const c=this.useRequest({baseURL:this.config.baseURL,headers:this.config.headers});t=`${c.baseURL||""}${t}`,n.headers==null&&(n.headers={}),c.headers&&(n.headers=ye({},c.headers));const p=yield fetch(t,n),v=ye({},p);v.data=yield p.json(),l(this.useResponse(v))}catch(c){this.useError(c),u(c)}}))})}TEXT(t,n){return B(this,null,function*(){return new Promise((l,u)=>B(this,null,function*(){try{const c=this.useRequest({baseURL:this.config.baseURL,headers:this.config.headers});t=`${c.baseURL||""}${t}`,n.headers==null&&(n.headers={}),c.headers&&(n.headers=ye({},c.headers));const p=yield fetch(t,n),v=ye({},p);v.data=yield p.text(),l(v)}catch(c){this.useError(c),u(c)}}))})}interceptors(){const t=this;return{requset:{use(n){t.useRequest=n}},response:{use(n,l){t.useResponse=n,l&&(t.useError=l)}}}}}const ai=Ho.create({});ai.interceptors().requset.use((s=>s));ai.interceptors().response.use((s=>(s.data&&s.data.success==null&&s.data.success==0,s)));const{$gettext:si}=Hs(),Gr="/cgi-bin/luci/istore",jr="/cgi-bin/luci/admin";let Ms=!1;const Pe=(s,t)=>{if(!["GET","HEAD","OPTIONS"].includes((t.method||"GET").tLine truncated
|
||||
`+p.value+`
|
||||
`+c.value,disabled:""},null,8,pI)]),e("div",hI,[e("div",{class:"close",onClick:g,disabled:u.value},a(o(t)("关闭")),9,mI),u.value?T("",!0):(i(),d("div",{key:0,class:"next",onClick:b,disabled:u.value},a(o(t)("运行")),9,fI))])])]),_:1}))}}),gI=le(bI,[["__scopeId","data-v-3fabbd23"]]),_I={class:"actioner-container"},yI={class:"actioner-container_header"},kI={class:"tabs"},wI={class:"actioner-container_body"},$I={key:0,class:"table"},CI={class:"tr"},SI={class:"td left"},xI={class:"td left"},PI={class:"tr"},TI={class:"td left"},MI={class:"td left"},EI={class:"tr"},II={class:"td left"},DI={class:"td left"},LI=["value"],AI=["value"],NI=["value"],OI={class:"actioner-container_footer"},zI=["disabled"],qI=X({__name:"disk-info",props:{close:{type:Function,required:!0},disk:{type:Object,required:!0}},setup(s){const{$gettext:t,$ngettext:n}=Ae(),l=s,u=x(!1),c=x("info"),r=m=>{switch(c.value=m,m){case"info":break;case"attribute":g();break;case"log":h();break;case"extend":b();break}},p=()=>{u.value=!0,l.close()},v=Xe({log:"",attribute:"",extend:""}),h=()=>B(null,null,function*(){try{const m=yield we.Smart.Test.Result.POST({type:"selftest",devicePath:l.disk.path||""});if(m.data){const{result:f,error:k}=m.data;f&&f.result&&(v.log=f.result),k&&(v.log=k)}}catch(m){v.log=m}}),g=()=>B(null,null,function*(){try{const m=yield we.Smart.Attribute.Result.POST({devicePath:l.disk.path||""});if(m.data){const{result:f,error:k}=m.data;f&&f.result&&(v.attribute=f.result),k&&(v.attribute=k)}}catch(m){v.attribute=m}}),b=()=>B(null,null,function*(){try{const m=yield we.Smart.Extend.Result.POST({devicePath:l.disk.path||""});if(m.data){const{result:f,error:k}=m.data;f&&f.result&&(v.extend=f.result),k&&(v.extend=k)}}catch(m){v.extend=m}});return(m,f)=>(i(),Y(Xs,null,{default:pe(()=>[e("div",_I,[e("div",yI,[e("ul",kI,[e("li",{class:_e({"active cbi-tab":c.value=="info"}),onClick:f[0]||(f[0]=k=>r("info"))},[e("a",null,a(o(t)("设备信息")),1)],2),e("li",{class:_e({"active cbi-tab":c.value=="attribute"}),onClick:f[1]||(f[1]=k=>r("attribute"))},[e("a",null,a(o(t)("属性")),1)],2),e("li",{class:_e({"active cbi-tab":c.value=="log"}),onClick:f[2]||(f[2]=k=>r("log"))},[e("a",null,a(o(t)("自检日志")),1)],2),e("li",{class:_e({"active cbi-tab":c.value=="extend"}),onClick:f[3]||(f[3]=k=>r("extend"))},[e("a",null,a(o(t)("扩展信息")),1)],2)])]),e("div",wI,[c.value=="info"?(i(),d("table",$I,[e("tr",CI,[e("td",SI,a(o(t)("设备")),1),e("td",xI,a(s.disk.path),1)]),e("tr",PI,[e("td",TI,a(o(t)("型号")),1),e("td",MI,a(s.disk.model),1)]),e("tr",EI,[e("td",II,a(o(t)("序号")),1),e("td",DI,a(s.disk.serial),1)])])):c.value=="attribute"?(i(),d("textarea",{key:1,disabled:"",value:v.attribute},null,8,LI)):c.value=="log"?(i(),d("textarea",{key:2,disabled:"",value:v.log},null,8,AI)):c.value=="extend"?(i(),d("textarea",{key:3,disabled:"",value:v.extend},null,8,NI)):T("",!0)]),e("div",OI,[e("div",{class:"close",onClick:p,disabled:u.value},a(o(t)("关闭")),9,zI)])])]),_:1}))}}),RI=le(qI,[["__scopeId","data-v-ba5f9eb4"]]),VI=s=>{const t=document.createElement("div");document.body.appendChild(t);const n=G(CE,Ne(ye({},s),{close:()=>{l()}})),l=()=>{t.remove()};Us(n,t)},BI=s=>{const t=document.createElement("div");document.body.appendChild(t);const n=G(cI,Ne(ye({},s),{close:()=>{l()}})),l=()=>{t.remove()};Us(n,t)},UI=s=>{const t=document.createElement("div");document.body.appendChild(t);const n=G(gI,Ne(ye({},s),{close:()=>{l()}})),l=()=>{t.remove()};Us(n,t)},FI=s=>{const t=document.createElement("div");document.body.appendChild(t);const n=G(RI,Ne(ye({},s),{close:()=>{l()}})),l=()=>{t.remove()};Us(n,t)},HI={class:"cbi-section"},GI={class:"cbi-value"},jI={class:"cbi-value-title"},WI={class:"cbi-value-field"},JI={class:"cbi-checkbox"},KI=["value"],ZI={class:"cbi-value"},YI={class:"cbi-value-title"},QI={class:"cbi-value-field"},XI={class:"cbi-checkbox"},eD={value:"never"},tD={value:"sleep"},nD={value:"standby"},aD={value:"idle"},sD={class:"cbi-value-description"},oD={class:"cbi-value"},lD={class:"cbi-value-title"},iD={class:"cbi-value-field"},rD={class:"cbi-checkbox"},cD={value:0},dD=["value"],uD={class:"cbi-value-description"},vD={class:"cbi-value"},pD={class:"cbi-value-title"},hD={class:"cbi-value-field"},mD={class:"cbi-checkbox"},fD={value:0},bD=["value"],gD={class:"cbi-value-description"},_D={class:"cbi-section cbi-tblsection",id:"cbi-nfs-mount"},yD={class:"table cbi-section-table"},kD={class:"tr cbi-section-table-titles anonymous"},wD={class:"th cbi-section-table-cell","data-widget":"value"},$D={class:"th cbi-section-table-cell","data-widget":"value"},CD={class:"th cbi-section-table-cell","data-widget":"value"},SD={class:"th cbi-section-table-cell","data-widget":"value"},xD={class:"th cbi-section-table-cell","data-widget":"value"},PD={class:"th cbi-section-table-cell","data-widget":"value"},TD={class:"th cbi-section-table-cell","data-widget":"value"},MD={class:"th cbi-section-table-cell","data-widget":"value"},ED={class:"tr cbi-section-table-row"},ID={class:"td cb
Line truncated
|
||||
${n("设备和单设备例外不会被删除。")}`))try{const H=(yield t.DeviceMangement.deviceGroupsV2.POST({action:"delete_group",groupId:he.id,expectedVersion:p.value})).data.result;if(H!=null&&H.error)throw new Error(H.error.message);yield it()}catch(H){c.value=(H==null?void 0:H.message)||n("删除失败")}}),it=()=>B(null,null,function*(){var he,H,J;l.value=!0,c.value="";try{const[ge,ze,Fe]=yield Promise.all([t.DeviceMangement.deviceGroupsV2.GET(),t.DeviceMangement.deviceInventoryV2.GET(),t.DeviceMangement.gatewayTargetsV2.GET().catch(()=>null)]),Ee=ge.data.result;if(Ee!=null&&Ee.error)throw new Error(Ee.error.message);$.value=(Ee==null?void 0:Ee.groups)||[],$e.value=(Ee==null?void 0:Ee.globalPolicy)||null,S.value=(Ee==null?void 0:Ee.effective)||[],p.value=(Ee==null?void 0:Ee.version)||"",v.value=(Ee==null?void 0:Ee.timezone)||"",h.value=(Ee==null?void 0:Ee.nextEvaluationAt)||"",y.value=Ee==null?void 0:Ee.lastBatch,w.value=((he=ze.data.result)==null?void 0:he.devices)||[],C.value=((J=(H=Fe==null?void 0:Fe.data)==null?void 0:H.result)==null?void 0:J.targets)||[]}catch(ge){c.value=(ge==null?void 0:ge.message)||n("读取设备分组失败")}finally{l.value=!1}});return it(),(he,H)=>(i(),d("section",eR,[e("header",tR,[e("div",null,[e("h2",nR,a(o(n)("分组与计划")),1),e("p",null,a(o(n)("把需要相同安排的设备放在一起,一次设置联网、速度、路线、时段或流量额度。")),1)]),e("div",aR,[e("button",{type:"button",onClick:re},a(o(n)("默认规则")),1),e("button",{type:"button",class:"primary",onClick:j},a(o(n)("新建分组")),1)])]),l.value?(i(),Y(yt,{key:0,kind:"loading",title:o(n)("正在读取设备分组")},null,8,["title"])):c.value?(i(),Y(yt,{key:1,kind:"error",title:o(n)("设备分组读取失败"),description:c.value,"action-label":o(n)("重新加载"),onAction:it},null,8,["title","description","action-label"])):(i(),d(V,{key:2},[e("div",sR,[e("span",null,a(o(n)("按路由器时间执行"))+" · "+a(v.value||"—"),1),e("span",null,a(o(n)("下次检查"))+" "+a(q(h.value)),1)]),y.value&&y.value.status!=="unchanged"?(i(),d("div",{key:0,class:_e(["batch-result",y.value.status]),role:"status"},[e("strong",null,a(K(y.value.status)),1),e("span",null,a(o(n)("成功"))+" "+a(y.value.applied)+" · "+a(o(n)("跳过"))+" "+a(y.value.skipped)+" · "+a(o(n)("失败"))+" "+a(y.value.failed),1)],2)):T("",!0),!$.value.length&&!g.value?(i(),Y(yt,{key:1,kind:"empty",title:o(n)("还没有设备分组"),description:o(n)("例如创建“儿童设备”,设置晚间暂停联网和每月流量额度。")},null,8,["title","description"])):(i(),d("div",oR,[(i(!0),d(V,null,oe($.value,J=>(i(),d("article",{key:J.id,class:"group-card"},[e("div",lR,[e("div",null,[e("strong",null,a(J.name),1),e("span",null,a(J.members.length)+" "+a(o(n)("台设备")),1)]),e("span",iR,"P"+a(J.priority),1)]),e("p",null,a(O(J.policy)),1),e("div",rR,a(F(J.members)),1),e("div",cR,[e("button",{type:"button",onClick:ge=>De(J)},a(o(n)("编辑")),9,dR),e("button",{type:"button",class:"danger-link",onClick:ge=>Ze(J)},a(o(n)("删除")),9,uR)])]))),128))])),S.value.length?(i(),d("details",vR,[e("summary",null,[ue(a(o(n)("查看最终生效结果与来源"))+" ",1),e("small",null,a(Math.min(S.value.length,50))+" / "+a(S.value.length),1)]),e("div",pR,[(i(!0),d(V,null,oe(S.value.slice(0,50),J=>(i(),d("div",{key:J.deviceId},[e("span",null,[e("strong",null,a(z(J.deviceId)),1),e("small",null,a(ve(J)),1)]),e("em",null,a(ce(J.sources)),1)]))),128))])])):T("",!0),g.value?(i(),d("form",{key:4,class:"editor",onSubmit:Ge(at,["prevent"])},[e("div",hR,[e("div",null,[e("h3",null,a(m.value?o(n)("默认规则"):b.value?o(n)("编辑分组"):o(n)("新建分组")),1),e("p",null,a(m.value?o(n)("只为没有更具体规则的设备提供默认值。"):o(n)("单设备例外始终优先;多个分组冲突时,优先级较高的生效。")),1)]),e("button",{type:"button",class:"close",onClick:Ke,"aria-label":o(n)("关闭")},"×",8,mR)]),m.value?T("",!0):(i(),d("div",fR,[e("label",null,[e("span",null,a(o(n)("分组名称")),1),W(e("input",{"onUpdate:modelValue":H[0]||(H[0]=J=>_.name=J),maxlength:"64",required:"",placeholder:o(n)("例如:儿童设备")},null,8,bR),[[Oe,_.name,void 0,{trim:!0}]])])])),m.value?T("",!0):(i(),d("details",gR,[e("summary",null,a(o(n)("高级设置")),1),e("label",null,[e("span",null,a(o(n)("优先级")),1),W(e("input",{"onUpdate:modelValue":H[1]||(H[1]=J=>_.priority=J),type:"number",min:"0",max:"999"},null,512),[[Oe,_.priority,void 0,{number:!0}]]),e("small",null,a(o(n)("单设备例外始终优先;多个分组冲突时,优先级较高的生效。")),1)])])),m.value?T("",!0):(i(),d("fieldset",_R,[e("legend",null,[ue(a(o(n)("选择设备"))+" ",1),e("small",null,a(o(n)("已选择"))+" "+a(_.members.length)+" "+a(o(n)("台设备")),1)]),W(e("input",{"onUpdate:modelValue":H[2]||(H[2]=J=>f.value=J),class:"device-search",type:"search",placeholder:o(n)("搜索名称、IP 或 MAC")},null,8,yR),[[Oe,f.value,void 0,{trim:
Line truncated
|
||||
${n("影响规则")}:${Q.affectedCount}
|
||||
${n("失败时将恢复")}:${Q.rollbackScope.join("、")}`))return;u.value=!0;const ce=(yield t.DeviceMangement.networkRulesV2.APPLY(F)).data.result;if(ce!=null&&ce.error)throw new Error(ce.error.message);b.value="success",g.value=n("规则已删除"),f.value=new Set,yield D()}catch(Q){b.value="error",g.value=(Q==null?void 0:Q.message)||n("删除失败,原配置已恢复")}finally{u.value=!1}}),A=()=>E([...f.value],n("确认删除所选规则?")),U=z=>z.kind==="route"&&["unreachable","unsupported"].includes(z.status),q=z=>E([z.id],n("恢复默认路线?设备重新获取地址后生效。"));return D(),(z,N)=>(i(),d("section",SV,[e("div",xV,[e("div",null,[e("h2",PV,a(o(n)("规则台账")),1),e("p",null,a(o(n)("集中检查离线、孤立或需要修复的规则;新设置请从对应设备详情进入。")),1)])]),l.value?(i(),Y(yt,{key:0,kind:"loading",title:o(n)("正在读取网络规则")},null,8,["title"])):c.value?(i(),Y(yt,{key:1,kind:"error",title:o(n)("网络规则读取失败"),description:c.value,"action-label":o(n)("重新加载"),onAction:D},null,8,["title","description","action-label"])):(i(),d(V,{key:2},[e("div",TV,[W(e("input",{"onUpdate:modelValue":N[0]||(N[0]=F=>r.value=F),type:"search",placeholder:o(n)("搜索设备、MAC、IP 或规则")},null,8,MV),[[Oe,r.value,void 0,{trim:!0}]]),W(e("select",{"onUpdate:modelValue":N[1]||(N[1]=F=>p.value=F)},[e("option",EV,a(o(n)("全部类型")),1),e("option",IV,a(o(n)("地址预留")),1),e("option",DV,a(o(n)("上网路线")),1),e("option",LV,a(o(n)("设备限速")),1),e("option",AV,a(o(n)("联网权限")),1)],512),[[Be,p.value]]),W(e("select",{"onUpdate:modelValue":N[2]||(N[2]=F=>v.value=F)},[e("option",NV,a(o(n)("全部状态")),1),e("option",OV,a(o(n)("正常")),1),e("option",zV,a(o(n)("离线或孤立")),1),e("option",qV,a(o(n)("网关不可达")),1),e("option",RV,a(o(n)("需要修复")),1)],512),[[Be,v.value]])]),f.value.size?(i(),d("div",VV,[e("span",null,a(o(n)("已选择"))+" "+a(f.value.size)+" / 128",1),e("button",{type:"button",class:"danger",disabled:u.value,onClick:A},a(u.value?o(n)("正在应用…"):o(n)("删除所选规则")),9,BV)])):T("",!0),k.value.length?(i(),d("div",UV,[e("table",null,[e("thead",null,[e("tr",null,[e("th",null,[e("input",{type:"checkbox",checked:$.value,onChange:_,"aria-label":o(n)("选择当前结果")},null,40,FV)]),e("th",null,a(o(n)("设备")),1),e("th",null,a(o(n)("规则类型")),1),e("th",null,a(o(n)("最终设置")),1),e("th",null,a(o(n)("状态")),1)])]),e("tbody",null,[(i(!0),d(V,null,oe(k.value,F=>(i(),d("tr",{key:F.id,class:_e({orphaned:F.orphaned})},[e("td",null,[e("input",{type:"checkbox",checked:f.value.has(F.id),onChange:Z=>P(F.id),"aria-label":`${o(n)("选择")} ${F.displayName}`},null,40,HV)]),e("td",null,[e("strong",null,a(F.displayName||o(n)("未命名设备")),1),e("small",null,a(F.mac||F.ip||"—"),1)]),e("td",null,[e("span",GV,a(w(F.kind)),1)]),e("td",null,[ue(a(y(F.summary)),1),F.nextAction?(i(),d("small",jV,a(C(F.nextAction)),1)):T("",!0)]),e("td",null,[e("span",{class:_e(["state-pill",F.status])},a(S(F.status)),3),U(F)?(i(),d("button",{key:0,type:"button",class:"repair",onClick:Z=>q(F)},a(o(n)("恢复默认路线")),9,WV)):T("",!0)])],2))),128))])])])):(i(),Y(yt,{key:1,kind:"empty",title:o(n)("没有匹配的网络规则"),description:o(n)("可从设备详情添加地址、路线和使用限制。")},null,8,["title","description"])),k.value.length?(i(),d("div",JV,[(i(!0),d(V,null,oe(k.value,F=>(i(),d("article",{key:`card-${F.id}`,class:_e({orphaned:F.orphaned})},[e("label",KV,[e("input",{type:"checkbox",checked:f.value.has(F.id),onChange:Z=>P(F.id),"aria-label":`${o(n)("选择")} ${F.displayName}`},null,40,ZV)]),e("div",YV,[e("strong",null,a(F.displayName||o(n)("未命名设备")),1),e("small",null,a(F.mac||F.ip||"—"),1)]),e("span",{class:_e(["state-pill",F.status])},a(S(F.status)),3),e("div",QV,[e("span",XV,a(w(F.kind)),1),e("span",null,a(y(F.summary)),1)]),F.nextAction?(i(),d("p",eB,a(C(F.nextAction)),1)):T("",!0),U(F)?(i(),d("button",{key:1,type:"button",class:"repair",onClick:Z=>q(F)},a(o(n)("恢复默认路线")),9,tB)):T("",!0)],2))),128))])):T("",!0),g.value?(i(),d("p",{key:4,class:_e(["feedback",b.value])},a(g.value),3)):T("",!0)],64))]))}}),aB=le(nB,[["__scopeId","data-v-c463c3c8"]]),sB=new Set(["available","disabled","not_installed","unsupported","error"]),oB={internetAccess:"internet_access",speedLimit:"device_speed_limit",floatGateway:"floating_gateway",trafficInsights:"traffic_insights"},So=(s,t)=>{var l,u,c,r;const n=(r=(u=(l=s==null?void 0:s.capabilities)==null?void 0:l.items)==null?void 0:u[oB[t]])!=null?r:(c=s==null?void 0:s.capabilities)==null?void 0:c[t];return n!=null&&n.state?sB.has(n.state)?n:{state:"error",reason:"capability_state_unknown"}:{state:"error",reason:"capability_missing"}},ha=s=>!!s&&typeof s=="object"&&!Array.isArray(s),Wi=s=>ha(s)&&!s.error&&(s.success===void 0||s.success===0),lB=s=>{if(!Wi(s))return;const t=s.result;if(!ha(t)||t.error||typeo
Line truncated
|
||||
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* vue v3.5.44
|
||||
* (c) 2018-present Yuxi (Evan) You and Vue contributors
|
||||
* @license MIT
|
||||
**/var Zl,Yl;let ii,Se,pe,sn,on,zn,bt,qn,Ql,Nt,St,er;function Gn(e){let t=Object.create(null);for(let n of e.split(","))t[n]=1;return n=>n in t}let te={},Pt=[],He=()=>{},si=()=>!1,an=e=>e.charCodeAt(0)===111&&e.charCodeAt(1)===110&&(e.charCodeAt(2)>122||97>e.charCodeAt(2)),Jn=e=>e.startsWith("onUpdate:"),ie=Object.assign,tr=(e,t)=>{let n=e.indexOf(t);n>-1&&e.splice(n,1)},jo=Object.prototype.hasOwnProperty,re=(e,t)=>jo.call(e,t),H=Array.isArray,G=e=>typeof e=="function",ue=e=>typeof e=="string",De=e=>typeof e=="symbol",se=e=>e!==null&&typeof e=="object",nr=e=>(se(e)||G(e))&&G(e.then)&&G(e.catch),ce=Object.prototype.toString,Xn=e=>ue(e)&&e!=="NaN"&&e[0]!=="-"&&""+parseInt(e,10)===e,Mt=Gn(",key,ref,ref_for,ref_key,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted"),Zn=e=>{let t=Object.create(null);return n=>t[n]||(t[n]=e(n))},Vo=/-\w/g,me=Zn(e=>e.replace(Vo,t=>t.slice(1).toUpperCase())),Do=/\B([A-Z])/g,Ie=Zn(e=>e.replace(Do,"-$1").toLowerCase()),un=Zn(e=>e.charAt(0).toUpperCase()+e.slice(1)),cn=Zn(e=>e?`on${un(e)}`:""),ke=(e,t)=>!Object.is(e,t),Ht=(e,...t)=>{for(let n=0;n<e.length;n++)e[n](...t)},oi=(e,t,n,l=!1)=>{Object.defineProperty(e,t,{configurable:!0,enumerable:!1,writable:l,value:n})},Yn=e=>{let t=parseFloat(e);return isNaN(t)?e:t},Wt=e=>{let t=ue(e)?Number(e):NaN;return isNaN(t)?e:t},Qn=()=>ii||(ii="u">typeof globalThis?globalThis:"u">typeof self?self:"u">typeof window?window:"u">typeof global?global:{}),Uo=Gn("Infinity,undefined,NaN,isFinite,isNaN,parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,BigInt,console,Error,Symbol");function pn(e){if(H(e)){let t={};for(let n=0;n<e.length;n++){let l=e[n],r=ue(l)?(function(i){let s={};return i.replace(Ho,o=>o.startsWith("/*")?"":o).split(Bo).forEach(o=>{if(o){let a=o.split($o);a.length>1&&(s[a[0].trim()]=a[1].trim())}}),s})(l):pn(l);if(r)for(let i in r)t[i]=r[i]}return t}if(ue(e)||se(e))return e}let Bo=/;(?![^(]*\))/g,$o=/:([^]+)/,Ho=/"(?:[^"\\]|\\[^])*"|'(?:[^'\\]|\\[^])*'|\\[^]|\/\*[^]*?\*\//g;function fn(e){let t="";if(ue(e))t=e;else if(H(e))for(let n=0;n<e.length;n++){let l=fn(e[n]);l&&(t+=l+" ")}else if(se(e))for(let n in e)e[n]&&(t+=n+" ");return t.trim()}function Wo(e){if(!e)return null;let{class:t,style:n}=e;return t&&!ue(t)&&(e.class=fn(t)),n&&(e.style=pn(n)),e}let Ko=Gn("itemscope,allowfullscreen,formnovalidate,ismap,nomodule,novalidate,playsinline,readonly");function zo(e,t,n){if(e.length!==t.length)return!1;let l=!0;for(let r=0;l&&r<e.length;r++)l=qe(e[r],t[r],n);return l}function ai(e,t,n){if(e.size!==t.size)return!1;let l=Array.from(t),r=new Uint8Array(l.length);for(let i of e){let s=-1;for(let o=0;o<l.length;o++)if(!r[o]&&qe(i,l[o],n)){s=o;break}if(s<0)return!1;r[s]=1}return!0}function qo(e,t,n){let l,r,i,s,o=(l=e,ce.call(l)==="[object Map]"),a=(r=t,ce.call(r)==="[object Map]");if(o||a||(o=(i=e,ce.call(i)==="[object Set]"),a=(s=t,ce.call(s)==="[object Set]"),o||a))return!!o&&!!a&&ai(e,t,n);if(Object.keys(e).length!==Object.keys(t).length)return!1;for(let u in e){let f=e.hasOwnProperty(u),g=t.hasOwnProperty(u);if(f&&!g||!f&&g||!qe(e[u],t[u],n))return!1}return String(e)===String(t)}function ui(e,t,n,l){n||(n=[new Map,new Map]);let[r,i]=n;if(r.has(e)||i.has(t))return r.get(e)===t&&i.get(t)===e;r.set(e,t),i.set(t,e);let s=l(e,t,n);return r.delete(e),i.delete(t),s}function qe(e,t,n){let l,r;if(e===t)return!0;let i=(l=e,ce.call(l)==="[object Date]"),s=(r=t,ce.call(r)==="[object Date]");return i||s?!!i&&!!s&&e.getTime()===t.getTime():(i=De(e),s=De(t),i||s?e===t:(i=H(e),s=H(t),i||s?!!i&&!!s&&ui(e,t,n,zo):(i=se(e),s=se(t),i||s?!!i&&!!s&&ui(e,t,n,qo):String(e)===String(t))))}function el(e,t){return e.findIndex(n=>qe(n,t))}let ci=e=>!!(e&&e.__v_isRef===!0),pi=e=>ue(e)?e:e==null?"":H(e)||se(e)&&(e.toString===ce||!G(e.toString))?ci(e)?pi(e.value):JSON.stringify(e,fi,2):String(e),fi=(e,t)=>{let n;if(ci(t))return fi(e,t.value);if(n=t,ce.call(n)==="[object Map]")return{[`Map(${t.size})`]:[...t.entries()].reduce((l,[r,i],s)=>(l[lr(r,s)+" =>"]=i,l),{})};{let l;if(l=t,ce.call(l)==="[object Set]")return{[`Set(${t.size})`]:[...t.values()].map(r=>lr(r))};{if(De(t))return lr(t);let r;if(se(t)&&!H(t)&&(r=t,ce.call(r)!=="[object Object]"))return String(t)}}return t},lr=(e,t="")=>{var n;return De(e)?`Symbol(${(n=e.description)!=null?n:t})`:e};class rr{constructor(t=!1){this.detached=t,this._active=!0,this._on=0,this.effects=[],this.cleanups=[],this._isPaused=!1,this._warnOnRun=!0,this.__v_skip=!0,!t&&Se&&(Se.active?(this.parent=Se,this.index=(Se.scopes||(Se.scopes=[])).push(this)-1):(this._active=!1,this._warnOnRun=!1))}get active(){return this._active}pause(){if(this._active){let t,n;if(this._isPaused=!0,this.scopes){let l=this.scopes.slice();for(t=0,n=l.length;t<n;t++)l[t].pause()}for(t=0,n=this.effects.length;t<n;t++)this.effects[t].pause()}}resume(){if(this._active&&this._isPaused){let t,n;if(this._isPaused=!1,thiLine truncated
|
||||
`&&(c.tagName==="PRE"||c.tagName==="TEXTAREA")&&(J=J.slice(1));let{textContent:be}=c;be!==J&&be!==J.replace(/\r\n|\r/g,`
|
||||
`)&&(Cl(c,0)||Zt(),c.textContent=h.children)}if(V){if(U||Q||!E||48&K){let J=c.tagName.includes("-"),be=c.namespaceURI.includes("svg")?"svg":c.namespaceURI.includes("MathML")?"mathml":void 0;for(let xe in V)if(U&&(xe.endsWith("value")||xe==="indeterminate")||an(xe)&&!Mt(xe)||xe[0]==="."||J&&!Mt(xe)||F&&F.includes(xe)){var ee,X,Y;if(ee=c,X=xe,Y=V[xe],ja.has(X)&&ee.getAttribute(X)===(Y==null?null:`${Y}`))continue;l(c,xe,null,V[xe],be,y)}}else if(V.onClick)l(c,"onClick",null,V.onClick,void 0,y);else if(4&K&&tt(V.style))for(let J in V.style)V.style[J]}(ne=V&&V.onVnodeBeforeMount)&&Ve(ne,y,h),B&<(h,null,y,"beforeMount"),((ne=V&&V.onVnodeMounted)||B||ae)&&Os(()=>{ne&&Ve(ne,y,h),ae&&z.enter(c),B&<(h,null,y,"mounted")},T)}return c.nextSibling},v=(c,h,y,T,R,E,P)=>{P=P||!!h.dynamicChildren;let F=h.children,V=F.length,K=!1;for(let A=0;A<V;A++){let B=P?F[A]:F[A]=je(F[A]),z=B.type===kt;c?(z&&!P&&A+1<V&&je(F[A+1]).type===kt&&(a(r(c.data.slice(B.children.length)),y,i(c)),c.data=B.children),c=f(c,B,T,R,E,P)):z&&!B.children?a(B.el=r(""),y):(!K&&(K=!0,Cl(y,1)||Zt()),n(null,B,y,null,T,R,bl(y),E))}return c},_=(c,h,y,T,R,E)=>{let{slotScopeIds:P}=h;P&&(R=R?R.concat(P):P);let F=s(c),V=v(i(c),h,F,y,T,R,E);return V&&Yt(V)&&V.data==="]"?i(h.anchor=V):(Zt(),a(h.anchor=u("]"),F,V),V)},m=(c,h,y,T,R,E)=>{var P,F,V;if(P=c,F=h,Cl(P.parentElement,1)||(V=P).nodeType===1&&wr(V.getAttribute(Sl),1)||(function({props:B}){let z=B&&B[Sl];return typeof z=="string"&&wr(z,1)})(F)||Zt(),h.el=null,E){let B=x(c);for(;;){let z=i(c);if(z&&z!==B)o(z);else break}}let K=i(c),A=s(c);return o(c),n(null,h,A,K,y,T,bl(A),R),y&&(y.vnode.el=h.el,Pl(y,h.el)),K},x=(c,h="[",y="]")=>{let T=0;for(;c;)if((c=i(c))&&Yt(c)&&(c.data===h&&T++,c.data===y)){if(T===0)return i(c);T--}return c},N=(c,h,y)=>{let T=h.parentNode;T&&T.replaceChild(c,h);let R=y;for(;R;)R.vnode.el===h&&(R.vnode.el=R.subTree.el=c),R=R.parent},M=c=>c.nodeType===1&&c.tagName==="TEMPLATE";return[(c,h)=>{if(!h.hasChildNodes()){n(null,c,h),hl(),h._vnode=c;return}f(h.firstChild,c,null,null,null),hl(),h._vnode=c},f]}let ja=new Set(["src","srcset","href","poster"]),Sl="data-allow-mismatch",Va={0:"text",1:"children",2:"class",3:"style",4:"attribute"};function Cl(e,t){if(t===0||t===1)for(;e&&!e.hasAttribute(Sl);)e=e.parentElement;return wr(e&&e.getAttribute(Sl),t)}function wr(e,t){if(e==null)return!1;{if(e==="")return!0;let n=e.split(",");return!!(t===0&&n.includes("children"))||n.includes(Va[t])}}let Da=Qn().requestIdleCallback||(e=>setTimeout(e,1)),Ua=Qn().cancelIdleCallback||(e=>clearTimeout(e)),Ba=(e=1e4)=>t=>{let n=Da(t,{timeout:e});return()=>Ua(n)},$a=e=>(t,n)=>{let l=new IntersectionObserver(i=>{for(let s of i)if(s.isIntersecting){l.disconnect(),t();break}},e),r=i=>{if((function(s){let{top:o,left:a,bottom:u,right:f}=s.getBoundingClientRect(),{innerHeight:g,innerWidth:v}=window;return(o>0&&o<g||u>0&&u<g)&&(a>0&&a<v||f>0&&f<v)})(i))return t(),l.disconnect(),!1;if(getComputedStyle(i).display==="contents"){for(let s=0;s<i.children.length;s++)if(r(i.children[s])===!1)return!1}l.observe(i)};return n(i=>{if(i instanceof Element)return r(i)}),()=>l.disconnect()},Ha=e=>t=>{if(e){let n=matchMedia(e);if(!n.matches)return n.addEventListener("change",t,{once:!0}),()=>n.removeEventListener("change",t);t()}},Wa=(e=[])=>(t,n)=>{ue(e)&&(e=[e]);let l=!1,r=s=>{l||(l=!0,i(),t(),s.target.dispatchEvent(new s.constructor(s.type,s)))},i=()=>{n(s=>{for(let o of e)s.removeEventListener(o,r)})};return n(s=>{for(let o of e)s.addEventListener(o,r,{once:!0})}),i},pt=e=>!!e.type.__asyncLoader;function Ka(e){let t;G(e)&&(e={loader:e});let{loader:n,loadingComponent:l,errorComponent:r,delay:i=200,hydrate:s,timeout:o,suspensible:a=!0,onError:u}=e,f=null,g=0,v=()=>{let _;return f||(_=f=n().catch(m=>{if(m=m instanceof Error?m:Error(String(m)),u)return new Promise((x,N)=>{u(m,()=>x((g++,f=null,v())),()=>N(m),g+1)});throw m}).then(m=>_!==f&&f?f:(m&&(m.__esModule||m[Symbol.toStringTag]==="Module")&&(m=m.default),t=m,m)))};return Cr({name:"AsyncComponentWrapper",__asyncLoader:v,__asyncHydrate(_,m,x){let N=_.isConnected,M=!1;(m.bu||(m.bu=[])).push(()=>M=!0);let c=()=>{M||_.parentNode&&(!N||_.isConnected)&&x()},h=s?()=>{let y=s(c,T=>(function(R,E){if(Yt(R)&&R.data==="["){let P=1,F=R.nextSibling;for(;F;){if(F.nodeType===1){if(E(F)===!1)break}else if(Yt(F))if(F.data==="]"){if(--P==0)break}else F.data==="["&&P++;F=F.nextSibling}}else E(R)})(_,T));y&&(m.bum||(m.bum=[])).push(y)}:c;t?h():v().then(()=>!m.isUnmounted&&h())},get __asyncResolved(){return t},setup(){let _,m,x=Te;if(xr(x),t)return()=>xl(t,x);let N=y=>{f=null,It(y,x,13,!r)};if(a&&x.suspense||Ut)return v().then(y=>()=>xl(y,x)).catch(y=>(N(y),()=>r?fe(r,{error:y}):null));let M=_n(!1),c=_n(),h=_n(!!i);return Nn(()=>{_!=null&&clearTimeout(_),m!=null&&clearTimeout(m)}),i&&(m=setTimeout(()=>{x.isUnmounted||(h.value=!1)},i)),o!=null&&(_=setTimeout(()=>{if(!x.isUnmounted&&!M.value&&!c.value){let y=Error(`Async component timed out after ${o}ms.`);N(y),c.value=y}},o)),v().then(()=>{!x.isUnmounted&&(M
Line truncated
|
||||
`))),e[Be]=Rt(r);let i=l||r.props&&r.props.type==="number";mt(e,t?"change":"input",s=>{s.target.composing||e[Be](ei(e.value,n,i))}),(n||i)&&mt(e,"change",()=>{e.value=ei(e.value,n,i)}),t||(mt(e,"compositionstart",tc),mt(e,"compositionend",Co),mt(e,"change",Co))},mounted(e,{value:t,modifiers:{trim:n,number:l}}){let r=e[Wl];delete e[Wl],r!==void 0&&(e.type==="text"||e.type==="textarea")&&e.value!==r?e[Be](ei(e.value,n,l)):e.value=t==null?"":t},beforeUpdate(e,{value:t,oldValue:n,modifiers:{lazy:l,trim:r,number:i}},s){if(e[Be]=Rt(s),e.composing)return;let o=(i||e.type==="number")&&!/^0\d/.test(e.value)?Yn(e.value):e.value,a=t==null?"":t;if(o===a)return;let u=e.getRootNode();(u instanceof Document||u instanceof ShadowRoot)&&u.activeElement===e&&e.type!=="range"&&(l&&t===n||r&&e.value.trim()===a)||(e.value=a)}},ti={deep:!0,created(e,t,n){e[Be]=Rt(n),mt(e,"change",()=>{let l=e._modelValue,r=nn(e),i=e.checked,s=e[Be];if(H(l)){let o=el(l,r),a=o!==-1;if(i&&!a)s(l.concat(r));else if(!i&&a){let u=[...l];u.splice(o,1),s(u)}}else{let o;if(o=l,ce.call(o)==="[object Set]"){let a=new Set(l);i?a.add(r):a.delete(r),s(a)}else s(Eo(e,i))}})},mounted:xo,beforeUpdate(e,t,n){e[Be]=Rt(n),xo(e,t,n)}};function xo(e,{value:t,oldValue:n},l){let r;if(e._modelValue=t,H(t))r=el(t,l.props.value)>-1;else{let i;if(i=t,ce.call(i)==="[object Set]")r=t.has(l.props.value);else{if(t===n)return;r=qe(t,Eo(e,!0))}}e.checked!==r&&(e.checked=r)}let ni={created(e,{value:t},n){e.checked=qe(t,n.props.value),e[Be]=Rt(n),mt(e,"change",()=>{e[Be](nn(e))})},beforeUpdate(e,{value:t,oldValue:n},l){e[Be]=Rt(l),t!==n&&(e.checked=qe(t,l.props.value))}},wo={deep:!0,created(e,{value:t,modifiers:{number:n}},l){e._modelValue=t,mt(e,"change",()=>{let r,i=Array.prototype.filter.call(e.options,u=>u.selected).map(u=>n?Yn(nn(u)):nn(u)),s=e.multiple,o=s?(r=e._modelValue,ce.call(r)==="[object Set]"?new Set(i):i):i[0],a=e._pendingValue=[s,s?H(o)?i.slice():i:o];try{e[Be](o)}finally{dl(()=>{e._pendingValue===a&&(e._pendingValue=void 0)})}}),e[Be]=Rt(l)},mounted(e,{value:t}){ko(e,t)},beforeUpdate(e,{value:t},n){e._modelValue=t,e[Be]=Rt(n)},updated(e,{value:t}){let n=e._pendingValue;e._pendingValue=void 0,n&&n[0]===e.multiple&&(function(l,r,i){let s;if(!i||H(l))return qe(l,r);if(s=l,ce.call(s)==="[object Set]"){if(l.size!==r.length)return!1;for(let o of r)if(!l.has(o))return!1;return!0}return!1})(t,n[1],n[0])||ko(e,t)}};function ko(e,t){let n,l=e.multiple,r=H(t);if(!l||r||(n=t,ce.call(n)==="[object Set]")){for(let i=0,s=e.options.length;i<s;i++){let o=e.options[i],a=nn(o);if(l)if(r){let u=typeof a;u==="string"||u==="number"?o.selected=t.some(f=>String(f)===String(a)):o.selected=el(t,a)>-1}else o.selected=t.has(a);else if(qe(nn(o),t)){e.selectedIndex!==i&&(e.selectedIndex=i);return}}l||e.selectedIndex===-1||(e.selectedIndex=-1)}}function nn(e){return"_value"in e?e._value:e.value}function Eo(e,t){let n=t?"_trueValue":"_falseValue";return n in e?e[n]:t}let To={created(e,t,n){zl(e,t,n,null,"created")},mounted(e,t,n){zl(e,t,n,null,"mounted")},beforeUpdate(e,t,n,l){zl(e,t,n,l,"beforeUpdate")},updated(e,t,n,l){zl(e,t,n,l,"updated")}};function Ao(e,t){switch(e){case"SELECT":return wo;case"TEXTAREA":return Kl;default:switch(t){case"checkbox":return ti;case"radio":return ni;default:return Kl}}}function zl(e,t,n,l,r){let i=Ao(e.tagName,n.props&&n.props.type)[r];i&&i(e,t,n,l)}let nc=["ctrl","shift","alt","meta"],lc={stop:e=>e.stopPropagation(),prevent:e=>e.preventDefault(),self:e=>e.target!==e.currentTarget,ctrl:e=>!e.ctrlKey,shift:e=>!e.shiftKey,alt:e=>!e.altKey,meta:e=>!e.metaKey,left:e=>"button"in e&&e.button!==0,middle:e=>"button"in e&&e.button!==1,right:e=>"button"in e&&e.button!==2,exact:(e,t)=>nc.some(n=>e[`${n}Key`]&&!t.includes(n))},rc=(e,t)=>{if(!e)return e;let n=e._withMods||(e._withMods={}),l=t.join(".");return n[l]||(n[l]=(r,...i)=>{for(let s=0;s<t.length;s++){let o=lc[t[s]];if(o&&o(r,t))return}return e(r,...i)})},ic={esc:"escape",space:" ",up:"arrow-up",left:"arrow-left",right:"arrow-right",down:"arrow-down",delete:"backspace"},sc=(e,t)=>{let n=e._withKeys||(e._withKeys={}),l=t.join(".");return n[l]||(n[l]=r=>{if(!("key"in r))return;let i=Ie(r.key);if(t.some(s=>s===i||ic[s]===i))return e(r)})},li=ie({patchProp:ho},Js),Ro=!1;function Oo(){return Nt=Ro?Nt:ks(li),Ro=!0,Nt}let No=(...e)=>{(Nt||(Nt=Ur(li))).render(...e)},oc=(...e)=>{Oo().hydrate(...e)},ri=(...e)=>{let t=(Nt||(Nt=Ur(li))).createApp(...e),{mount:n}=t;return t.mount=l=>{let r=Fo(l);if(!r)return;let i=t._component;G(i)||i.render||i.template||(i.template=r.innerHTML),r.nodeType===1&&(r.textContent="");let s=n(r,!1,Mo(r));return r instanceof Element&&(r.removeAttribute("v-cloak"),r.setAttribute("data-v-app","")),s},t},Po=(...e)=>{let t=Oo().createApp(...e),{mount:n}=t;return t.mount=l=>{let r=Fo(l);if(r)return n(r,!0,Mo(r))},t};function Mo(e){return e instanceof SVGElement?"svg":typeof MathMLElement=="function"&&e instanceof MathMLElement?"mathml":void 0}function Fo(e){return ue(e)?document.querySelector(e):e}let Io=!1,
Line truncated
|
||||
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 5.9 KiB |
|
After Width: | Height: | Size: 6.3 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 7.9 KiB |
|
After Width: | Height: | Size: 6.4 KiB |
|
After Width: | Height: | Size: 7.5 KiB |
|
After Width: | Height: | Size: 6.7 KiB |
|
After Width: | Height: | Size: 5.9 KiB |
|
After Width: | Height: | Size: 6.5 KiB |
|
After Width: | Height: | Size: 5.5 KiB |
|
After Width: | Height: | Size: 6.0 KiB |
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"version": 2,
|
||||
"license": "project-original-ai-assisted",
|
||||
"reviewRequiredBeforePublicRelease": true,
|
||||
"icons": [
|
||||
{"key":"computer","label":"通用电脑","category":"computer","file":"computer.webp","generated":"2026-09-24"},
|
||||
{"key":"phone","label":"手机","category":"phone","file":"phone.webp","generated":"2026-09-24"},
|
||||
{"key":"tablet","label":"平板电脑","category":"tablet","file":"tablet.webp","generated":"2026-09-24"},
|
||||
{"key":"tv","label":"电视","category":"tv","file":"tv.webp","generated":"2026-09-24"},
|
||||
{"key":"network","label":"无线路由器","category":"network","file":"network.webp","generated":"2026-09-24"},
|
||||
{"key":"smart-home","label":"智能家居","category":"smart-home","file":"smart-home.webp","generated":"2026-09-24"},
|
||||
{"key":"camera","label":"摄像头","category":"camera","file":"camera.webp","generated":"2026-09-24"},
|
||||
{"key":"gaming","label":"游戏设备","category":"gaming","file":"gaming.webp","generated":"2026-09-24"},
|
||||
{"key":"storage","label":"网络存储","category":"storage","file":"storage.webp","generated":"2026-09-24"},
|
||||
{"key":"printer","label":"打印机","category":"printer","file":"printer.webp","generated":"2026-09-24"},
|
||||
{"key":"wearable","label":"穿戴设备","category":"wearable","file":"wearable.webp","generated":"2026-09-24"},
|
||||
{"key":"unknown","label":"未知设备","category":"computer","file":"unknown.webp","generated":"2026-09-24"},
|
||||
{"key":"desktop","label":"台式电脑","category":"computer","file":"desktop.webp","generated":"2026-09-25"},
|
||||
{"key":"laptop","label":"笔记本电脑","category":"computer","file":"laptop.webp","generated":"2026-09-25"},
|
||||
{"key":"smart-speaker","label":"智能音箱","category":"smart-home","file":"smart-speaker.webp","generated":"2026-09-25"},
|
||||
{"key":"smart-bulb","label":"智能灯","category":"smart-home","file":"smart-bulb.webp","generated":"2026-09-25"},
|
||||
{"key":"thermostat","label":"温控器","category":"smart-home","file":"thermostat.webp","generated":"2026-09-25"},
|
||||
{"key":"sensor","label":"传感器","category":"smart-home","file":"sensor.webp","generated":"2026-09-25"},
|
||||
{"key":"door-lock","label":"智能门锁","category":"smart-home","file":"door-lock.webp","generated":"2026-09-25"},
|
||||
{"key":"robot-vacuum","label":"扫地机器人","category":"smart-home","file":"robot-vacuum.webp","generated":"2026-09-25"},
|
||||
{"key":"air-conditioner","label":"空调","category":"smart-home","file":"air-conditioner.webp","generated":"2026-09-25"},
|
||||
{"key":"projector","label":"投影仪","category":"tv","file":"projector.webp","generated":"2026-09-25"},
|
||||
{"key":"set-top-box","label":"电视盒子","category":"tv","file":"set-top-box.webp","generated":"2026-09-25"},
|
||||
{"key":"game-console","label":"游戏主机","category":"gaming","file":"game-console.webp","generated":"2026-09-25"},
|
||||
{"key":"handheld-game","label":"掌上游戏机","category":"gaming","file":"handheld-game.webp","generated":"2026-09-25"},
|
||||
{"key":"home-server","label":"家庭服务器","category":"storage","file":"home-server.webp","generated":"2026-09-25"},
|
||||
{"key":"network-switch","label":"网络交换机","category":"network","file":"network-switch.webp","generated":"2026-09-25"},
|
||||
{"key":"access-point","label":"无线接入点","category":"network","file":"access-point.webp","generated":"2026-09-25"},
|
||||
{"key":"network-bridge","label":"网络桥接器","category":"network","file":"network-bridge.webp","generated":"2026-09-25"},
|
||||
{"key":"e-reader","label":"电子阅读器","category":"tablet","file":"e-reader.webp","generated":"2026-09-25"}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 5.5 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 5.5 KiB |
|
After Width: | Height: | Size: 8.0 KiB |
|
After Width: | Height: | Size: 6.7 KiB |
|
After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 5.8 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 5.6 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 5.4 KiB |
|
After Width: | Height: | Size: 6.9 KiB |
@@ -1 +1 @@
|
||||
{"en":{"- -自定义- -":"- -Custom- -","(请先获取IPv4上游信息)":"(Please obtain IPv4 upstream information first)","(未格式化)":"(Not formatted)","(未挂载)":"(Not mounted)","(无DNS服务器,请之后自行填写公共DNS服务器,例如 223.5.5.5)":"(No DNS server, please fill in the public DNS server later, such as 223.5.5.5)","(系统分区)":"(System partition)","(系统盘)":"(System disk)","* 表示每天":"* Means daily","* 表示每小时":"* Means hourly","* 表示每月":"* Means monthly","%{ countdown }s后 跳转新地址":"%{ countdown }s before redirecting to new address","%{ days }天":["%{ days } d ","%{ days } d "],"%{ hours }小时":["%{ hours } h","%{ hours } h"],"%{ minutes }分":[" %{ minutes } min"," %{ minutes } min"],"%{ seconds }秒":[" %{ seconds } sec"," %{ seconds } sec"],"%{status}下载服务配置向导":"%{status} download service configuration wizard","1、点击“提交”可将变更合并到非沙箱环境":"1. Click 'Submit' to merge changes into non-sandbox environment","1. 满足上述条件以后,点击“当前 IPv4 上游信息”以刷新当前连接信息,成功以后,“自动填写”按钮将被激活。(失败可再次点击)":"1. After the above conditions are met, click 'Current IPv4 Upstream Information' to refresh the current connection information. After success, the 'Auto Fill' button will be activated. (Click again if failed)","2、点击“重置”可将沙箱恢复到初始状态":"2. Click 'Reset' to restore the sandbox to its initial state","2. 点击“自动填写”,将切换到参数页并自动填写。此时依然可以自行调整参数。":"2. Click 'Auto-fill' to switch to the parameter page and auto-fill. Parameters can still be adjusted manually.","223.5.5.5":"223.5.5.5","3、点击“退出”可退出沙箱环境,并放弃沙箱中的数据":"3. Click 'Exit' to exit the sandbox environment and abandon the data in the sandbox","阿里云":"Aliyun","安装失败":"Installation Failed","安装失败,":"Installation Failed,","安装失败或超时,请检查软件源或稍候重试":"Installation Failed or Timed Out, Please Check Software Source or Retry Later","安装中...":"Installing...","半双工":"Half Duplex","保持DHCP服务设置":"Keep DHCP Service Settings","保存":"Save","保存并应用":"Save and Apply","保存成功":"Saved Successfully","保存配置":"Save Configuration","保存中...":"Saving...","备份升级":"Backup/Flash","备用DNS地址":"Backup DNS Address","备用DNS服务器":"Backup DNS Server","备用DNS服务器地址":"Backup DNS Server Address","本向导支持自动或手动配置:":"This wizard supports automatic or manual configuration:","编辑":"Edit","编辑LAN":"Edit LAN","编辑WAN":"Edit WAN","并挂载到":"And Mount to","访客":"visitor","拨号上网":"PPPoE","不格式化,使用原文件系统":"Do Not Format, Use Original File System","不支持挂载":"Not Supported for Mounting","操作":"Operation","测试时磁盘会转动,请选择合适的模式来控制磁盘转动。":"Disk will spin during testing, please choose the appropriate mode to control disk spinning.","测速":"Speedtest","插件备份":"APP Backup","查看磁盘管理信息":"Disk Actions","查看存储服务信息":"Actions","查看高级配置":"Acrions","查看更多详情":" to check details","查看教程":"View tutorial","查看日志":"View log","查看设备信息":"Check Clients","查看网络接口信息":"NIC Info","查看系统信息":"System Utils","查看详情":"View details","常规设置":"General Settings","成员":"Member","初始化成功":"Initialized Successfully","初始化中...":"Initializing...","处理中...":"Processing...","传输时自检":"Self-Test During Transfer","窗口 %{ item }":"Window %{ item }","创建":"Create","创建成功":"Created Successfully","创建计划任务":"Create Scheduled Task","创建中...":"Creating...","创建RAID":"Create RAID","磁盘":"Disk","磁盘管理":"Disk Manager","磁盘信息":"Disk Info","磁盘阵列成员:":"RAID array members:","此操作会将会删除该分区全部数据":"This operation will delete all data on this partition","此操作会将会删除该分区全部数据,并格式化成EXT4,随后自动重启进入沙箱模式,是否继续?":"This operation will delete all data on the partition and format it to EXT4, then automatically reboot into sandbox mode. Do you want to continue?","此分区为只读状态,可能无法写入数据":"This partition is read-only, data may not be writable","此文件系统不支持Docker等应用数据,建议格式化成EXT4文件系统":"This file system does not support Docker and other application data, it is recommended to format as EXT4 file system","存储服务":"Share","错误":"Error","带宽监控":"Bandwidth Monitor","待机":"Standby","待机-处于待机和睡眠模式下不检查设备。此模式下磁盘一般不旋Line truncated
|
||||
{"en":{"- -自定义- -":"- -Custom- -","(不可用)":"(not available)","(无DNS服务器,请之后自行填写公共DNS服务器,例如 223.5.5.5)":"(No DNS server, please fill in the public DNS server later, such as 223.5.5.5)","(未挂载)":"(Not mounted)","(未格式化)":"(Not formatted)","(系统分区)":"(System partition)","(系统盘)":"(System disk)","(请先获取IPv4上游信息)":"(Please obtain IPv4 upstream information first)","* 表示每天":"* Means daily","* 表示每小时":"* Means hourly","* 表示每月":"* Means monthly","%{ countdown }s后 跳转新地址":"%{ countdown }s before redirecting to new address","%{ days }天":["%{ days } d ","%{ days } d "],"%{ hours }小时":["%{ hours } h","%{ hours } h"],"%{ minutes }分":[" %{ minutes } min"," %{ minutes } min"],"%{ seconds }秒":[" %{ seconds } sec"," %{ seconds } sec"],"%{status}下载服务配置向导":"%{status} download service configuration wizard","1、点击“提交”可将变更合并到非沙箱环境":"1. Click 'Submit' to merge changes into non-sandbox environment","1. 满足上述条件以后,点击“当前 IPv4 上游信息”以刷新当前连接信息,成功以后,“自动填写”按钮将被激活。(失败可再次点击)":"1. After the above conditions are met, click 'Current IPv4 Upstream Information' to refresh the current connection information. After success, the 'Auto Fill' button will be activated. (Click again if failed)","2、点击“重置”可将沙箱恢复到初始状态":"2. Click 'Reset' to restore the sandbox to its initial state","2. 点击“自动填写”,将切换到参数页并自动填写。此时依然可以自行调整参数。":"2. Click 'Auto-fill' to switch to the parameter page and auto-fill. Parameters can still be adjusted manually.","223.5.5.5":"223.5.5.5","3、点击“退出”可退出沙箱环境,并放弃沙箱中的数据":"3. Click 'Exit' to exit the sandbox environment and abandon the data in the sandbox","Aria2高级配置":"Aria2 Adv.","CPU使用率":"CPU Usage","CPU温度":"CPU Temp.","DDNSTO":"DDNSTO","DDNSTO 是一个不需要公网IP也可以在外网访问的穿透域名服务,一个浏览器搞定内网穿透,远程访问Openwrt、远程终端、远程桌面...":"DDNSTO is a domain name penetration service that can be accessed from the Internet without a public IP. A browser can handle intranet penetration and remote access to Openwrt, remote terminal, remote desktop...","DDNSTO控制台":"DDNSTO Console","DHCP":"DHCP","DHCP 主机名(可选)":"DHCP hostname (optional)","DHCP 主机名仅支持 1~63 位英文、数字或中间连字符":"DHCP hostnames only support 1-63 digits English, numbers or middle hyphens","DHCP客户端":"DHCP Client","DHCP的IP池格式错误或超出子网范围":"DHCP IP pool format error or out of subnet range","DNS 洞察":"DNS Insights","DNS 配置方式":"DNS Configuration Method","dnspod":"dnspod","Dnspod":"Dnspod","DNS服务器":"DNS Server","DNS服务器: ":"DNS Server: ","DNS服务器地址":"DNS Server Address","DNS选项":"DNS Options","DNS配置":"DNS Settings","DNS配置已保存":"DNS Saved","DNS错误":"DNS Error","Docker根目录:":"Docker Root Directory: ","Docker迁移向导":"Docker Migration Wizard","Docker高级配置":"Docker Adv.","ID":"Id","IP":"IP","IP 地址":"IP Address","IP 地址: ":"IP Address: ","IPv4 地址":"IPv4 address","IPv4地址":"IPv4 Address","IPv4地址格式错误":"IPv4 Address Format Error","IPv4子网掩码":"IPv4 Subnet Mask","IPv4子网掩码格式错误":"IPv4 Subnet Mask Format Error","IPv6 地址策略":"IPv6 address policy","IPv6地址":"IPv6 Address","IP地址":"IP Address","IP地址版本:":"IP Version: ","IP池结束地址":"IP Pool End Address","IP池起始地址":"IP Pool Start Address","IP限速":"IP Speed Limit","iStoreOS官网":"iStoreOS","JBOD (线性)":"JBOD (Linear)","LAN 接口配置方式":"LAN Interface Configuration Method","LAN口未关联任何物理网口,可能导致路由器失联,是否继续操作?":"LAN port not associated with any physical network port, may cause router disconnection, continue?","MAC":"MAC","MAC:":"MAC:","MAC地址":"MAC address","MAC地址与IP绑定":"MAC address is tied to IP","qBittorrent高级配置":"qBittorrent Adv.","Quickstart 限速服务未就绪。请安装或启动服务后重新检查;系统不会自动改用其他方式。":"Quickstart speed limiting is not ready. Install or start the service, then check again; the system will not switch modes automatically.","RAID ( Redundant Array of Independent Disks )即独立磁盘冗余阵列,简称为「磁盘阵列」,就是用多个独立的磁盘组成在一起形成一个大的磁盘系统,从而实现比单块磁盘更好的存储性能和更高的可靠性。":"RAID (Redundant Array of Independent Disks) is a redundant array of independent disks, which uses multiple independent disks to form a large disk sysLine truncated
|
||||
@@ -1,3 +1 @@
|
||||
var go=Object.defineProperty,vo=Object.defineProperties;var bo=Object.getOwnPropertyDescriptors;var xa=Object.getOwnPropertySymbols;var ho=Object.prototype.hasOwnProperty,_o=Object.prototype.propertyIsEnumerable;var We=(o,n,a)=>n in o?go(o,n,{enumerable:!0,configurable:!0,writable:!0,value:a}):o[n]=a,st=(o,n)=>{for(var a in n||(n={}))ho.call(n,a)&&We(o,a,n[a]);if(xa)for(var a of xa(n))_o.call(n,a)&&We(o,a,n[a]);return o},vt=(o,n)=>vo(o,bo(n));var xo=(o,n)=>()=>(n||o((n={exports:{}}).exports,n),n.exports);var ve=(o,n,a)=>(We(o,typeof n!="symbol"?n+"":n,a),a);var L=(o,n,a)=>new Promise((l,u)=>{var d=g=>{try{k(a.next(g))}catch(p){u(p)}},c=g=>{try{k(a.throw(g))}catch(p){u(p)}},k=g=>g.done?l(g.value):Promise.resolve(g.value).then(d,c);k((a=a.apply(o,n)).next())});import{a as wo,c as ko,d as we,b as I,e as Q,u as e,o as r,f as s,g as t,t as i,n as ht,h as D,i as Y,r as _t,j as Yt,w as O,v as Rt,k as Ia,l as Z,m as V,p as E,q as $t,s as Pt,x as pt,F as U,y as tt,z as at,A as jt,B as ut,C as ct,D as ke,E as ee,T as St,G as Nt,H as lt,I as ft,J as xt,K as dt,L as gt,M as Bt,N as Xe,O as Ma,P as La,Q as Oa,R as ta,S as ea,U as Na,V as aa,W as Pe,X as yo,Y as oa,Z as ye,_ as Fo,$ as Eo,a0 as na,a1 as $o,a2 as Te,a3 as Co,a4 as Ie,a5 as Do,a6 as Bo,a7 as Yo,a8 as Ao,a9 as So,aa as zo,ab as Po,ac as To}from"./vendor.js?v=91daea62";var sT=xo(ae=>{const Io=function(){const n=document.createElement("link").relList;if(n&&n.supports&&n.supports("modulepreload"))return;for(const u of document.querySelectorAll('link[rel="modulepreload"]'))l(u);new MutationObserver(u=>{for(const d of u)if(d.type==="childList")for(const c of d.addedNodes)c.tagName==="LINK"&&c.rel==="modulepreload"&&l(c)}).observe(document,{childList:!0,subtree:!0});function a(u){const d={};return u.integrity&&(d.integrity=u.integrity),u.referrerpolicy&&(d.referrerPolicy=u.referrerpolicy),u.crossorigin==="use-credentials"?d.credentials="include":u.crossorigin==="anonymous"?d.credentials="omit":d.credentials="same-origin",d}function l(u){if(u.ep)return;u.ep=!0;const d=a(u);fetch(u.href,d)}};Io();const Gt={language:void 0,numberFormat:new Intl.NumberFormat("en",{notation:"compact"})},Mo=o=>L(ae,null,function*(){const n=window.vue_lang;new Date().getTime();let a={};try{const d=yield wo({url:window.vue_lang_data,method:"GET"});d.data&&(a=d.data)}catch(d){console.log(d)}const l=ko({defaultLanguage:n,mutedLanguages:["zh-cn"],translations:a,setGlobalProperties:!1,provideDirective:!1,provideComponent:!1});o.use(l),Gt.language=l;const{$gettext:u}=l;window.$i18n=u;try{Gt.numberFormat=new Intl.NumberFormat(n,{notation:"compact"})}catch(d){console.error("Intl.NumberFormat unsupported lang",n,d)}}),J=()=>{if(Gt.language)return Gt.language;throw new Error("I18N Uninitialized!")},Me=()=>({$gettext:(o,n,a)=>{if(Gt.language)return Gt.language.$gettext(o,n,a);throw new Error("I18N Uninitialized!")},$ngettext:(o,n,a,l,u)=>{if(Gt.language)return Gt.language.$ngettext(o,n,a,l,u);throw new Error("I18N Uninitialized!")}}),De=o=>typeof o=="number"?Gt.numberFormat.format(o):"?",{$gettext:Lo,$ngettext:uT}=Me(),Va=(o,n)=>L(ae,null,function*(){return new Promise((a,l)=>L(ae,null,function*(){try{const u=yield fetch(o,n);if(Math.floor(u.status/100)!=2)throw u.status+" "+u.statusText;const d=st({},u);d.data=yield u.json(),a(d)}catch(u){const d=u;l(Lo("\u7F51\u7EDC\u5F02\u5E38\uFF1A")+((d==null?void 0:d.message)||u))}}))});class ia{constructor(n){ve(this,"config",{baseURL:"",headers:{}});ve(this,"useRequest",n=>n);ve(this,"useResponse",n=>n);ve(this,"useError",n=>n);n.baseURL&&(this.config.baseURL=n.baseURL),n.headers&&(this.config.headers=n.headers)}static create(n){return new ia(n)}Do(n,a){return L(this,null,function*(){return new Promise((l,u)=>L(this,null,function*(){try{const d=this.useRequest({baseURL:this.config.baseURL,headers:this.config.headers});n=`${d.baseURL||""}${n}`,a.headers==null&&(a.headers={}),d.headers&&(a.headers=st({},d.headers));const k=yield fetch(n,a),g=st({},k);g.data=yield k.json(),l(this.useResponse(g))}catch(d){this.useError(d),u(d)}}))})}TEXT(n,a){return L(this,null,function*(){return new Promise((l,u)=>L(this,null,function*(){try{const d=this.useRequest({baseURL:this.config.baseURL,headers:this.config.headers});n=`${d.baseURL||""}${n}`,a.headers==null&&(a.headers={}),d.headers&&(a.headers=st({},d.headers));const k=yield fetch(n,a),g=st({},k);g.data=yield k.text(),l(g)}catch(d){this.useError(d),u(d)}}))})}interceptors(){const n=this;return{requset:{use(a){n.useRequest=a}},response:{use(a,l){n.useResponse=a,l&&(n.useError=l)}}}}}const Ga=ia.create({});Ga.interceptors().requset.use(o=>o);Ga.interceptors().response.use(o=>(o.data&&o.data.success==null&&o.data.success==0,o));const{$gettext:ja,$ngettext:cT}=Me(),Oo="/cgi-bin/luci/istore",No="/cgi-bin/luci/admin";let Ae=!1;const W=(o,n)=>(o.indexOf("//")==-1&&(o=`${Oo}${o}`),Va(o,n).then(a=>(a!=null&&a.data&&a.data.success==-1001&&a.data.error=="Forbidden"&&(Ae||(Ae=!0,alert(ja("\u767B\u5F55\u8FC7\u671F\uFF0C\u8BF7\u91CLine truncated
|
||||
`+k.value+`
|
||||
`+d.value,disabled:""},null,8,RF)]),t("div",WF,[t("div",{class:"close",onClick:m,disabled:u.value},i(e(a)("\u5173\u95ED")),9,HF),u.value?D("",!0):(r(),s("div",{key:0,class:"next",onClick:v,disabled:u.value},i(e(a)("\u8FD0\u884C")),9,JF))])])]),_:1}))}});var KF=N(ZF,[["__scopeId","data-v-70c3aae0"]]);const QF={class:"actioner-container"},XF={class:"actioner-container_header"},tE={class:"tabs"},eE={class:"actioner-container_body"},aE={key:0,class:"table"},oE={class:"tr"},nE={class:"td left"},iE={class:"td left"},rE={class:"tr"},sE={class:"td left"},dE={class:"td left"},lE={class:"tr"},uE={class:"td left"},cE={class:"td left"},pE=["value"],fE=["value"],mE=["value"],gE={class:"actioner-container_footer"},vE=["disabled"],bE=I({props:{close:{type:Function,required:!0},disk:{type:Object,required:!0}},setup(o){const n=o,{$gettext:a,$ngettext:l}=J(),u=E(!1),d=E("info"),c=b=>{switch(d.value=b,b){case"info":break;case"attribute":m();break;case"log":p();break;case"extend":v();break}},k=()=>{u.value=!0,n.close()},g=gt({log:"",attribute:"",extend:""}),p=()=>L(this,null,function*(){try{const b=yield G.Smart.Test.Result.POST({type:"selftest",devicePath:n.disk.path||""});if(b.data){const{result:y,error:f}=b.data;y&&y.result&&(g.log=y.result),f&&(g.log=f)}}catch(b){g.log=b}}),m=()=>L(this,null,function*(){try{const b=yield G.Smart.Attribute.Result.POST({devicePath:n.disk.path||""});if(b.data){const{result:y,error:f}=b.data;y&&y.result&&(g.attribute=y.result),f&&(g.attribute=f)}}catch(b){g.attribute=b}}),v=()=>L(this,null,function*(){try{const b=yield G.Smart.Extend.Result.POST({devicePath:n.disk.path||""});if(b.data){const{result:y,error:f}=b.data;y&&y.result&&(g.extend=y.result),f&&(g.extend=f)}}catch(b){g.extend=b}});return(b,y)=>(r(),Z(je,null,{default:V(()=>[t("div",QF,[t("div",XF,[t("ul",tE,[t("li",{class:lt({"active cbi-tab":d.value=="info"}),onClick:y[0]||(y[0]=f=>c("info"))},[t("a",null,i(e(a)("\u8BBE\u5907\u4FE1\u606F")),1)],2),t("li",{class:lt({"active cbi-tab":d.value=="attribute"}),onClick:y[1]||(y[1]=f=>c("attribute"))},[t("a",null,i(e(a)("\u5C5E\u6027")),1)],2),t("li",{class:lt({"active cbi-tab":d.value=="log"}),onClick:y[2]||(y[2]=f=>c("log"))},[t("a",null,i(e(a)("\u81EA\u68C0\u65E5\u5FD7")),1)],2),t("li",{class:lt({"active cbi-tab":d.value=="extend"}),onClick:y[3]||(y[3]=f=>c("extend"))},[t("a",null,i(e(a)("\u6269\u5C55\u4FE1\u606F")),1)],2)])]),t("div",eE,[d.value=="info"?(r(),s("table",aE,[t("tr",oE,[t("td",nE,i(e(a)("\u8BBE\u5907")),1),t("td",iE,i(o.disk.path),1)]),t("tr",rE,[t("td",sE,i(e(a)("\u578B\u53F7")),1),t("td",dE,i(o.disk.model),1)]),t("tr",lE,[t("td",uE,i(e(a)("\u5E8F\u53F7")),1),t("td",cE,i(o.disk.serial),1)])])):d.value=="attribute"?(r(),s("textarea",{key:1,disabled:"",value:e(g).attribute},null,8,pE)):d.value=="log"?(r(),s("textarea",{key:2,disabled:"",value:e(g).log},null,8,fE)):d.value=="extend"?(r(),s("textarea",{key:3,disabled:"",value:e(g).extend},null,8,mE)):D("",!0)]),t("div",gE,[t("div",{class:"close",onClick:k,disabled:u.value},i(e(a)("\u5173\u95ED")),9,vE)])])]),_:1}))}});var hE=N(bE,[["__scopeId","data-v-313197ee"]]);const _E=o=>{const n=document.createElement("div");document.body.appendChild(n);const a=Y(tF,vt(st({},o),{close:()=>{l()}})),l=()=>{n.remove()};Ie(a,n)},xE=o=>{const n=document.createElement("div");document.body.appendChild(n);const a=Y(GF,vt(st({},o),{close:()=>{l()}})),l=()=>{n.remove()};Ie(a,n)},wE=o=>{const n=document.createElement("div");document.body.appendChild(n);const a=Y(KF,vt(st({},o),{close:()=>{l()}})),l=()=>{n.remove()};Ie(a,n)},kE=o=>{const n=document.createElement("div");document.body.appendChild(n);const a=Y(hE,vt(st({},o),{close:()=>{l()}})),l=()=>{n.remove()};Ie(a,n)},yE={class:"cbi-section"},FE={class:"cbi-value"},EE={class:"cbi-value-title"},$E={class:"cbi-value-field"},CE={class:"cbi-checkbox"},DE=["value"],BE={class:"cbi-value"},YE={class:"cbi-value-title"},AE={class:"cbi-value-field"},SE={class:"cbi-checkbox"},zE={value:"never"},PE={value:"sleep"},TE={value:"standby"},IE={value:"idle"},ME={class:"cbi-value-description"},LE=t("br",null,null,-1),OE=t("br",null,null,-1),NE=t("br",null,null,-1),VE=t("br",null,null,-1),GE={class:"cbi-value"},jE={class:"cbi-value-title"},UE={class:"cbi-value-field"},qE={class:"cbi-checkbox"},RE={value:0},WE=["value"],HE={class:"cbi-value-description"},JE={class:"cbi-value"},ZE={class:"cbi-value-title"},KE={class:"cbi-value-field"},QE={class:"cbi-checkbox"},XE={value:0},t$=["value"],e$={class:"cbi-value-description"},a$={class:"cbi-section cbi-tblsection",id:"cbi-nfs-mount"},o$={class:"table cbi-section-table"},n$={class:"tr cbi-section-table-titles anonymous"},i$={class:"th cbi-section-table-cell","data-widget":"value"},r$={class:"th cbi-section-table-cell","data-widget":"value"},s$={class:"th cbi-section-table-cell","data-widget":"value"},d$={class:"th cbi-section-table-cell","data-widget":"value"},l$={class:"th cbi-section-table-cell","data-widget":"value"},u$={class:"th cbi-section-table-cell","data-widget":"value"
Line truncated
|
||||
import{createApp as c}from"/luci-static/quickstart/card-runtime-v1.js";import{i as a,A as p,S as m,a as l,b as d,c as u,d as f,e as g,f as v,p as S,g as h,h as y,j as w,k as b,E as O,l as A,r as L,m as P}from"./app.js?v=txJtMzYh";import{s as I}from"./vendor.js?v=B46K-l76";(function(){const s=document.createElement("link").relList;if(s&&s.supports&&s.supports("modulepreload"))return;for(const o of document.querySelectorAll('link[rel="modulepreload"]'))r(o);new MutationObserver(o=>{for(const t of o)if(t.type==="childList")for(const n of t.addedNodes)n.tagName==="LINK"&&n.rel==="modulepreload"&&r(n)}).observe(document,{childList:!0,subtree:!0});function i(o){const t={};return o.integrity&&(t.integrity=o.integrity),o.referrerPolicy&&(t.referrerPolicy=o.referrerPolicy),o.crossOrigin==="use-credentials"?t.credentials="include":o.crossOrigin==="anonymous"?t.credentials="omit":t.credentials="same-origin",t}function r(o){if(o.ep)return;o.ep=!0;const t=i(o);fetch(o.href,t)}})();a();const e=c(p);e.component("svg-menu",m);e.component("svg-system",l);e.component("svg-download",d);e.component("svg-store",u);e.component("svg-info",f);e.component("svg-disk",g);e.component("svg-nav",v);e.component("progress-item",S);e.component("svg-view-show",h);e.component("svg-view-hidden",y);e.component("article-item",w);e.component("switch-box",b);e.component("editable-select",O);e.use(A);e.use(L);e.use(I());P(e).finally(()=>e.mount("#app"));
|
||||
@@ -0,0 +1 @@
|
||||
var p=(m,b,s)=>new Promise((t,c)=>{var u=e=>{try{f(s.next(e))}catch(r){c(r)}},i=e=>{try{f(s.throw(e))}catch(r){c(r)}},f=e=>e.done?t(e.value):Promise.resolve(e.value).then(u,i);f((s=s.apply(m,b)).next())});import{o as y,q as E}from"./app.js?v=txJtMzYh";import"/luci-static/quickstart/card-runtime-v1.js";import"./vendor.js?v=B46K-l76";function v(m=fetch,b=y,s=t=>new Promise((c,u)=>{const i=()=>{clearTimeout(f),u(new DOMException("Aborted","AbortError"))},f=setTimeout(()=>{t==null||t.removeEventListener("abort",i),c()},3e3);t==null||t.addEventListener("abort",i,{once:!0}),t!=null&&t.aborted&&i()})){const t=(e,r)=>typeof window!="undefined"&&window.vue_lang==="en"?r:e,c=e=>{const r=E.find(n=>n.id===e);if(!r)throw Error("Unsupported card");return r.package};function u(e,r,n){return p(this,null,function*(){var l;const o=new AbortController,a=()=>o.abort(),w=setTimeout(a,8e3);n==null||n.addEventListener("abort",a,{once:!0}),n!=null&&n.aborted&&a();try{const d=yield m("/cgi-bin/luci/istore/app/"+e+"/",{method:"POST",credentials:"same-origin",redirect:"error",cache:"no-store",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:c(r)}),signal:o.signal});if(!d.ok||!((l=d.headers.get("Content-Type"))!=null&&l.includes("application/json")))throw Error([401,403].includes(d.status)?t("登录已失效或权限不足,请重新登录","Session expired or access denied. Sign in again."):t("无法读取安装状态,请稍后重试","Unable to read installation status. Try again."));const k=yield d.text();if(k.length>8192)throw Error("Invalid installation response");const h=JSON.parse(k);if(h.error||h.success!==void 0&&h.success!==0)throw Error(t("安装状态读取失败,请检查软件中心","Unable to confirm installation. Check the software center."));return h}finally{clearTimeout(w),n==null||n.removeEventListener("abort",a)}})}function i(e,r){return p(this,null,function*(){var a,w,l;const n=yield u("check",e,r),o=(a=n.result)==null?void 0:a.installation;return["idle","installing","completed","failed","unknown"].includes(o)?o==="installing"?"installing":o==="unknown"?"unknown":o==="failed"?"failed":((w=n.result)==null?void 0:w.status)==="uninstalled"?"uninstalled":((l=n.result)==null?void 0:l.status)!=="installed"?"unknown":(yield b.read(!0)).some(d=>d.id===e)?"ready":"update_required":"unknown"})}return{inspect:i,install(e,r){return p(this,null,function*(){const n=yield i(e,r);if(n!=="ready"){if(n==="unknown")throw Error(t("无法确认安装状态,请先在软件中心检查或升级 Quickstart","Installation status is unknown. Check the software center or update Quickstart."));if(n!=="installing")try{yield u("install",e,r)}catch(o){if(r!=null&&r.aborted)throw o}for(let o=0;o<60;o++){yield s(r);const a=yield i(e,r);if(a==="ready")return;if(a==="update_required")throw Error(t("插件已安装,但当前版本尚未提供可用卡片;请在软件中心升级或修复 FastNet","The installed version has no usable card. Update or repair FastNet in the software center."));if(a==="failed")throw Error(t("安装失败,请检查软件源后重试","Installation failed. Check the package source before retrying."));if(a==="unknown")throw Error(t("安装结果尚未确认,请先在软件中心检查","Installation is unconfirmed. Check the software center first."))}throw Error(t("安装结果尚未确认,请重新读取状态;后台安装可能仍在继续","Installation is unconfirmed. Reload its status; installation may still be running."))}})}}}const S=v();export{S as cardInstaller,v as createCardInstaller};
|
||||
@@ -1 +1 @@
|
||||
@keyframes bganimation-0698ba82{0%{background-position:0% 50%}50%{background-position:100% 50%}to{background-position:0% 50%}}@keyframes rotateEnter-0698ba82{0%{transform:rotateY(180deg)}10%{transform:rotateY(198deg)}20%{transform:rotateY(216deg)}30%{transform:rotateY(234deg)}40%{transform:rotateY(252deg)}50%{transform:rotateY(270deg)}60%{transform:rotateY(288deg)}70%{transform:rotateY(306deg)}80%{transform:rotateY(324deg)}90%{transform:rotateY(342deg)}to{transform:rotateY(360deg)}}@keyframes turns-0698ba82{0%{-webkit-transform:rotate(0deg)}25%{-webkit-transform:rotate(90deg)}50%{-webkit-transform:rotate(180deg)}75%{-webkit-transform:rotate(270deg)}to{-webkit-transform:rotate(360deg)}}.rotate-enter-active[data-v-0698ba82]{animation:rotateEnter-0698ba82 .7s;position:relative}.rotate-leave-active[data-v-0698ba82]{opacity:0;display:none;position:relative;z-index:-999}.app-container[data-v-0698ba82]{width:100%;background-color:var(--card-bg-color);box-shadow:var(--card-box-shadow);padding:10px 30px;border-radius:6px;position:relative}.disk-item-tooltip[data-v-0698ba82]{position:fixed;background:rgba(0,0,0,.7);z-index:10111;color:#fff;padding:.5rem 1rem;font-size:1em;min-width:200px;line-height:24px}.disk-item-tooltip[data-v-0698ba82]:after{content:"";position:absolute;bottom:-6px;border-color:#4c4c4c rgba(0,0,0,0) rgba(0,0,0,0);left:0;right:0;text-align:center;width:0;margin:0 auto;border-width:6px 8px 0;border-style:solid}#main .app-btn,#actioner .app-btn{min-height:36px}@keyframes bganimation-9bc295c2{0%{background-position:0% 50%}50%{background-position:100% 50%}to{background-position:0% 50%}}@keyframes rotateEnter-9bc295c2{0%{transform:rotateY(180deg)}10%{transform:rotateY(198deg)}20%{transform:rotateY(216deg)}30%{transform:rotateY(234deg)}40%{transform:rotateY(252deg)}50%{transform:rotateY(270deg)}60%{transform:rotateY(288deg)}70%{transform:rotateY(306deg)}80%{transform:rotateY(324deg)}90%{transform:rotateY(342deg)}to{transform:rotateY(360deg)}}@keyframes turns-9bc295c2{0%{-webkit-transform:rotate(0deg)}25%{-webkit-transform:rotate(90deg)}50%{-webkit-transform:rotate(180deg)}75%{-webkit-transform:rotate(270deg)}to{-webkit-transform:rotate(360deg)}}.rotate-enter-active[data-v-9bc295c2]{animation:rotateEnter-9bc295c2 .7s;position:relative}.rotate-leave-active[data-v-9bc295c2]{opacity:0;display:none;position:relative;z-index:-999}.app-container[data-v-9bc295c2]{width:100%;background-color:var(--card-bg-color);box-shadow:var(--card-box-shadow);padding:10px 30px;border-radius:6px;position:relative}#main[data-v-9bc295c2]{width:100%}#main[data-v-9bc295c2],#main[data-v-9bc295c2] *{-webkit-box-sizing:border-box;-webkit-tap-highlight-color:transparent;box-sizing:border-box;word-wrap:break-word;outline:none}@keyframes bganimation{0%{background-position:0% 50%}50%{background-position:100% 50%}to{background-position:0% 50%}}@keyframes rotateEnter{0%{transform:rotateY(180deg)}10%{transform:rotateY(198deg)}20%{transform:rotateY(216deg)}30%{transform:rotateY(234deg)}40%{transform:rotateY(252deg)}50%{transform:rotateY(270deg)}60%{transform:rotateY(288deg)}70%{transform:rotateY(306deg)}80%{transform:rotateY(324deg)}90%{transform:rotateY(342deg)}to{transform:rotateY(360deg)}}@keyframes turns{0%{-webkit-transform:rotate(0deg)}25%{-webkit-transform:rotate(90deg)}50%{-webkit-transform:rotate(180deg)}75%{-webkit-transform:rotate(270deg)}to{-webkit-transform:rotate(360deg)}}.rotate-enter-active{animation:rotateEnter .7s;position:relative}.rotate-leave-active{opacity:0;display:none;position:relative;z-index:-999}.app-container{width:100%;background-color:var(--card-bg-color);box-shadow:var(--card-box-shadow);padding:10px 30px;border-radius:6px;position:relative}:root{--flow-bg-color: #fff;--flow-span-color: rgba(0, 0, 0, .6);--card-bg-color: #fff;--card-box-shadow: 0 0 10px 1px #bfbfbf24;--app-container_title-color: #1e1e1e;--app-container_status-label_block: black;--item-label_key-span-color: #333;--item-label_value-span-color: #333;--app-container_status-label_bg: #f3f3f3;--item_btn-border: 1px solid #553afb;--item_btn-color: #553afb;--tit-color: #1e1e1e;--popup-bg-color: #fff;--tag-bg-color: #f5f5f5;--gradient-bg-color:linear-gradient(90deg, rgba(255,255,255,0) 0%, rgba(255,255,255,.8) 62%, rgba(255,255,255,1) 100%);--breadcrumbs-tit-color:#d6dbf8;--breadcrumbs-tit-color1:#f1f2f9;--border-color: #e5e5e5;--SystemUpdateBanner-bg-color: #eff6ff;--SystemUpdateBanner-border-color: #bedbff;--btn-border-color: #e5e5e5;--card-txt-color: #32325d;--SystemInfo-bg-color:#f9fafd}@media (prefers-color-scheme: light){:root{--flow-bg-color: #fff;--flow-span-color: rgba(0, 0, 0, .6);--card-bg-color: #fff;--card-box-shadow: 0 0 10px 1px #bfbfbf24;--app-container_title-color: #1e1e1e;--app-container_status-label_block: black;--item-label_key-span-color: #333;--item-label_value-span-color: #333;--app-container_status-label_bg: #f3f3f3;--item_btn-border: 1px solid #553afb;--item_btn-color: #553afb;--tit-color: #1e1e1e;--popup-bg-color: #fff;--tag-Line truncated
|
||||
@keyframes bganimation-4cfdbcec{0%{background-position:0% 50%}50%{background-position:100% 50%}to{background-position:0% 50%}}@keyframes rotateEnter-4cfdbcec{0%{transform:rotateY(180deg)}10%{transform:rotateY(198deg)}20%{transform:rotateY(216deg)}30%{transform:rotateY(234deg)}40%{transform:rotateY(252deg)}50%{transform:rotateY(270deg)}60%{transform:rotateY(288deg)}70%{transform:rotateY(306deg)}80%{transform:rotateY(324deg)}90%{transform:rotateY(342deg)}to{transform:rotateY(360deg)}}@keyframes turns-4cfdbcec{0%{-webkit-transform:rotate(0deg)}25%{-webkit-transform:rotate(90deg)}50%{-webkit-transform:rotate(180deg)}75%{-webkit-transform:rotate(270deg)}to{-webkit-transform:rotate(360deg)}}.rotate-enter-active[data-v-4cfdbcec]{animation:rotateEnter-4cfdbcec .7s;position:relative}.rotate-leave-active[data-v-4cfdbcec]{opacity:0;display:none;position:relative;z-index:-999}.app-container[data-v-4cfdbcec]{width:100%;background-color:var(--card-bg-color);box-shadow:var(--card-box-shadow);padding:10px 30px;border-radius:6px;position:relative}.disk-item-tooltip[data-v-4cfdbcec]{position:fixed;background:#000000b3;z-index:10111;color:#fff;padding:.5rem 1rem;font-size:1em;min-width:200px;line-height:24px}.disk-item-tooltip[data-v-4cfdbcec]:after{content:"";position:absolute;bottom:-6px;border-color:#4c4c4c rgba(0,0,0,0) rgba(0,0,0,0);left:0;right:0;text-align:center;width:0;margin:0 auto;border-width:6px 8px 0;border-style:solid}#main .app-btn,#actioner .app-btn{min-height:36px}@keyframes bganimation-425e333d{0%{background-position:0% 50%}50%{background-position:100% 50%}to{background-position:0% 50%}}@keyframes rotateEnter-425e333d{0%{transform:rotateY(180deg)}10%{transform:rotateY(198deg)}20%{transform:rotateY(216deg)}30%{transform:rotateY(234deg)}40%{transform:rotateY(252deg)}50%{transform:rotateY(270deg)}60%{transform:rotateY(288deg)}70%{transform:rotateY(306deg)}80%{transform:rotateY(324deg)}90%{transform:rotateY(342deg)}to{transform:rotateY(360deg)}}@keyframes turns-425e333d{0%{-webkit-transform:rotate(0deg)}25%{-webkit-transform:rotate(90deg)}50%{-webkit-transform:rotate(180deg)}75%{-webkit-transform:rotate(270deg)}to{-webkit-transform:rotate(360deg)}}.rotate-enter-active[data-v-425e333d]{animation:rotateEnter-425e333d .7s;position:relative}.rotate-leave-active[data-v-425e333d]{opacity:0;display:none;position:relative;z-index:-999}.app-container[data-v-425e333d]{width:100%;background-color:var(--card-bg-color);box-shadow:var(--card-box-shadow);padding:10px 30px;border-radius:6px;position:relative}#main[data-v-425e333d]{width:100%}#main[data-v-425e333d],#main[data-v-425e333d] *{-webkit-box-sizing:border-box;-webkit-tap-highlight-color:transparent;box-sizing:border-box;word-wrap:break-word;outline:none}:root{--flow-bg-color: #fff;--flow-span-color: rgba(0, 0, 0, .6);--card-bg-color: #fff;--card-box-shadow: 0 0 10px 1px #bfbfbf24;--app-container_title-color: #1e1e1e;--app-container_status-label_block: black;--item-label_key-span-color: #333;--item-label_value-span-color: #333;--app-container_status-label_bg: #f3f3f3;--item_btn-border: 1px solid #553afb;--item_btn-color: #553afb;--tit-color: #1e1e1e;--popup-bg-color: #fff;--tag-bg-color: #f5f5f5;--gradient-bg-color:linear-gradient(90deg, rgba(255,255,255,0) 0%, rgba(255,255,255,.8) 62%, rgba(255,255,255,1) 100%);--breadcrumbs-tit-color:#d6dbf8;--breadcrumbs-tit-color1:#f1f2f9;--border-color: #e5e5e5;--SystemUpdateBanner-bg-color: #eff6ff;--SystemUpdateBanner-border-color: #bedbff;--btn-border-color: #e5e5e5;--card-txt-color: #32325d;--SystemInfo-bg-color:#f9fafd;color-scheme:light}@media(prefers-color-scheme:light){:root{--flow-bg-color: #fff;--flow-span-color: rgba(0, 0, 0, .6);--card-bg-color: #fff;--card-box-shadow: 0 0 10px 1px #bfbfbf24;--app-container_title-color: #1e1e1e;--app-container_status-label_block: black;--item-label_key-span-color: #333;--item-label_value-span-color: #333;--app-container_status-label_bg: #f3f3f3;--item_btn-border: 1px solid #553afb;--item_btn-color: #553afb;--tit-color: #1e1e1e;--popup-bg-color: #fff;--tag-bg-color: #f5f5f5;--gradient-bg-color:linear-gradient(90deg, rgba(255,255,255,0) 0%, rgba(255,255,255,.8) 62%, rgba(255,255,255,1) 100%);--breadcrumbs-tit-color:#d6dbf8;--breadcrumbs-tit-color1:#f1f2f9;--border-color: #e5e5e5;--SystemUpdateBanner-bg-color: #eff6ff;--SystemUpdateBanner-border-color: #bedbff;--btn-border-color: #e5e5e5;--card-txt-color: #32325d;--SystemInfo-bg-color:#f9fafd}}@media(prefers-color-scheme:dark){:root{--flow-bg-color: transparent;--flow-span-color: #cccccc;--card-bg-color: #88888822;--card-box-shadow: 0 0 .5rem 0 rgba(0, 0, 0, .35);--app-container_title-color: #cccccc;--app-container_status-label_block: #727272;--item-label_key-span-color: #cccccc;--item-label_value-span-color: #cccccc;--app-container_status-label_bg: #0000001a;--item_btn-border: 1px solid #cccccc;--item_btn-color: #cccccc;--tit-color: #cccccc;--popup-bg-color: #000;--tag-bg-color: #1e1e1e;--gradient-bg-color:linear-gradient(90deg, rgba(0,Line truncated
|
||||
@@ -1,48 +1,30 @@
|
||||
function wv(e,t){const r=Object.create(null),n=e.split(",");for(let i=0;i<n.length;i++)r[n[i]]=!0;return t?i=>!!r[i.toLowerCase()]:i=>!!r[i]}const zx="itemscope,allowfullscreen,formnovalidate,ismap,nomodule,novalidate,readonly",Hx=wv(zx);function Q0(e){return!!e||e===""}function bv(e){if(at(e)){const t={};for(let r=0;r<e.length;r++){const n=e[r],i=Zt(n)?Gx(n):bv(n);if(i)for(const a in i)t[a]=i[a]}return t}else{if(Zt(e))return e;if(Yt(e))return e}}const $x=/;(?![^(]*\))/g,Vx=/:(.+)/;function Gx(e){const t={};return e.split($x).forEach(r=>{if(r){const n=r.split(Vx);n.length>1&&(t[n[0].trim()]=n[1].trim())}}),t}function Sv(e){let t="";if(Zt(e))t=e;else if(at(e))for(let r=0;r<e.length;r++){const n=Sv(e[r]);n&&(t+=n+" ")}else if(Yt(e))for(const r in e)e[r]&&(t+=r+" ");return t.trim()}function Ux(e,t){if(e.length!==t.length)return!1;let r=!0;for(let n=0;r&&n<e.length;n++)r=wi(e[n],t[n]);return r}function wi(e,t){if(e===t)return!0;let r=cp(e),n=cp(t);if(r||n)return r&&n?e.getTime()===t.getTime():!1;if(r=at(e),n=at(t),r||n)return r&&n?Ux(e,t):!1;if(r=Yt(e),n=Yt(t),r||n){if(!r||!n)return!1;const i=Object.keys(e).length,a=Object.keys(t).length;if(i!==a)return!1;for(const o in e){const s=e.hasOwnProperty(o),l=t.hasOwnProperty(o);if(s&&!l||!s&&l||!wi(e[o],t[o]))return!1}}return String(e)===String(t)}function xv(e,t){return e.findIndex(r=>wi(r,t))}const Iz=e=>Zt(e)?e:e==null?"":at(e)||Yt(e)&&(e.toString===t_||!gt(e.toString))?JSON.stringify(e,J0,2):String(e),J0=(e,t)=>t&&t.__v_isRef?J0(e,t.value):fa(t)?{[`Map(${t.size})`]:[...t.entries()].reduce((r,[n,i])=>(r[`${n} =>`]=i,r),{})}:Ea(t)?{[`Set(${t.size})`]:[...t.values()]}:Yt(t)&&!at(t)&&!e_(t)?String(t):t,Rt={},ua=[],fr=()=>{},Wx=()=>!1,Yx=/^on[^a-z]/,_u=e=>Yx.test(e),Tv=e=>e.startsWith("onUpdate:"),ie=Object.assign,Cv=(e,t)=>{const r=e.indexOf(t);r>-1&&e.splice(r,1)},qx=Object.prototype.hasOwnProperty,Tt=(e,t)=>qx.call(e,t),at=Array.isArray,fa=e=>wu(e)==="[object Map]",Ea=e=>wu(e)==="[object Set]",cp=e=>e instanceof Date,gt=e=>typeof e=="function",Zt=e=>typeof e=="string",Mv=e=>typeof e=="symbol",Yt=e=>e!==null&&typeof e=="object",Av=e=>Yt(e)&>(e.then)&>(e.catch),t_=Object.prototype.toString,wu=e=>t_.call(e),Xx=e=>wu(e).slice(8,-1),e_=e=>wu(e)==="[object Object]",Dv=e=>Zt(e)&&e!=="NaN"&&e[0]!=="-"&&""+parseInt(e,10)===e,ml=wv(",key,ref,ref_for,ref_key,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted"),bu=e=>{const t=Object.create(null);return r=>t[r]||(t[r]=e(r))},jx=/-(\w)/g,Ar=bu(e=>e.replace(jx,(t,r)=>r?r.toUpperCase():"")),Kx=/\B([A-Z])/g,Mi=bu(e=>e.replace(Kx,"-$1").toLowerCase()),Su=bu(e=>e.charAt(0).toUpperCase()+e.slice(1)),hf=bu(e=>e?`on${Su(e)}`:""),$o=(e,t)=>!Object.is(e,t),yl=(e,t)=>{for(let r=0;r<e.length;r++)e[r](t)},Bl=(e,t,r)=>{Object.defineProperty(e,t,{configurable:!0,enumerable:!1,value:r})},ya=e=>{const t=parseFloat(e);return isNaN(t)?e:t};let hp;const Zx=()=>hp||(hp=typeof globalThis!="undefined"?globalThis:typeof self!="undefined"?self:typeof window!="undefined"?window:typeof global!="undefined"?global:{});let Or;class r_{constructor(t=!1){this.active=!0,this.effects=[],this.cleanups=[],!t&&Or&&(this.parent=Or,this.index=(Or.scopes||(Or.scopes=[])).push(this)-1)}run(t){if(this.active)try{return Or=this,t()}finally{Or=this.parent}}on(){Or=this}off(){Or=this.parent}stop(t){if(this.active){let r,n;for(r=0,n=this.effects.length;r<n;r++)this.effects[r].stop();for(r=0,n=this.cleanups.length;r<n;r++)this.cleanups[r]();if(this.scopes)for(r=0,n=this.scopes.length;r<n;r++)this.scopes[r].stop(!0);if(this.parent&&!t){const i=this.parent.scopes.pop();i&&i!==this&&(this.parent.scopes[this.index]=i,i.index=this.index)}this.active=!1}}}function n_(e){return new r_(e)}function Qx(e,t=Or){t&&t.active&&t.effects.push(e)}const Pv=e=>{const t=new Set(e);return t.w=0,t.n=0,t},i_=e=>(e.w&Pn)>0,a_=e=>(e.n&Pn)>0,Jx=({deps:e})=>{if(e.length)for(let t=0;t<e.length;t++)e[t].w|=Pn},tT=e=>{const{deps:t}=e;if(t.length){let r=0;for(let n=0;n<t.length;n++){const i=t[n];i_(i)&&!a_(i)?i.delete(e):t[r++]=i,i.w&=~Pn,i.n&=~Pn}t.length=r}},$c=new WeakMap;let fo=0,Pn=1;const Vc=30;let xr;const pi=Symbol(""),Gc=Symbol("");class Iv{constructor(t,r=null,n){this.fn=t,this.scheduler=r,this.active=!0,this.deps=[],this.parent=void 0,Qx(this,n)}run(){if(!this.active)return this.fn();let t=xr,r=wn;for(;t;){if(t===this)return;t=t.parent}try{return this.parent=xr,xr=this,wn=!0,Pn=1<<++fo,fo<=Vc?Jx(this):vp(this),this.fn()}finally{fo<=Vc&&tT(this),Pn=1<<--fo,xr=this.parent,wn=r,this.parent=void 0}}stop(){this.active&&(vp(this),this.onStop&&this.onStop(),this.active=!1)}}function vp(e){const{deps:t}=e;if(t.length){for(let r=0;r<t.length;r++)t[r].delete(e);t.length=0}}let wn=!0;const o_=[];function La(){o_.push(wn),wn=!1}function Ra(){const e=o_.pop();wn=e===void 0?!0:e}function ke(e,t,r){if(wn&&xr){let n=$c.get(e);n||$c.set(e,n=new Map);let i=n.get(r);i||n.set(r,i=Pv()),s_(i)}}function s_(e,t){let r=!1;fo<=Vc?a_(e)||(e.n|=Pn,r=!i_(e)):r=Line truncated
|
||||
`),function(s){if(a=s.indexOf(":"),n=mf.trim(s.substr(0,a)).toLowerCase(),i=mf.trim(s.substr(a+1)),n){if(r[n]&&jM.indexOf(n)>=0)return;n==="set-cookie"?r[n]=(r[n]?r[n]:[]).concat([i]):r[n]=r[n]?r[n]+", "+i:i}}),r},Kp=Fe,ZM=Kp.isStandardBrowserEnv()?function(){var t=/(msie|trident)/i.test(navigator.userAgent),r=document.createElement("a"),n;function i(a){var o=a;return t&&(r.setAttribute("href",o),o=r.href),r.setAttribute("href",o),{href:r.href,protocol:r.protocol?r.protocol.replace(/:$/,""):"",host:r.host,search:r.search?r.search.replace(/^\?/,""):"",hash:r.hash?r.hash.replace(/^#/,""):"",hostname:r.hostname,port:r.port,pathname:r.pathname.charAt(0)==="/"?r.pathname:"/"+r.pathname}}return n=i(window.location.href),function(o){var s=Kp.isString(o)?i(o):o;return s.protocol===n.protocol&&s.host===n.host}}():function(){return function(){return!0}}(),Is=Fe,QM=VM,JM=GM,tA=l1,eA=XM,rA=KM,nA=ZM,yf=f1,Zp=function(t){return new Promise(function(n,i){var a=t.data,o=t.headers,s=t.responseType;Is.isFormData(a)&&delete o["Content-Type"];var l=new XMLHttpRequest;if(t.auth){var u=t.auth.username||"",f=t.auth.password?unescape(encodeURIComponent(t.auth.password)):"";o.Authorization="Basic "+btoa(u+":"+f)}var c=eA(t.baseURL,t.url);l.open(t.method.toUpperCase(),tA(c,t.params,t.paramsSerializer),!0),l.timeout=t.timeout;function v(){if(!!l){var d="getAllResponseHeaders"in l?rA(l.getAllResponseHeaders()):null,p=!s||s==="text"||s==="json"?l.responseText:l.response,g={data:p,status:l.status,statusText:l.statusText,headers:d,config:t,request:l};QM(n,i,g),l=null}}if("onloadend"in l?l.onloadend=v:l.onreadystatechange=function(){!l||l.readyState!==4||l.status===0&&!(l.responseURL&&l.responseURL.indexOf("file:")===0)||setTimeout(v)},l.onabort=function(){!l||(i(yf("Request aborted",t,"ECONNABORTED",l)),l=null)},l.onerror=function(){i(yf("Network Error",t,null,l)),l=null},l.ontimeout=function(){var p="timeout of "+t.timeout+"ms exceeded";t.timeoutErrorMessage&&(p=t.timeoutErrorMessage),i(yf(p,t,t.transitional&&t.transitional.clarifyTimeoutError?"ETIMEDOUT":"ECONNABORTED",l)),l=null},Is.isStandardBrowserEnv()){var h=(t.withCredentials||nA(c))&&t.xsrfCookieName?JM.read(t.xsrfCookieName):void 0;h&&(o[t.xsrfHeaderName]=h)}"setRequestHeader"in l&&Is.forEach(o,function(p,g){typeof a=="undefined"&&g.toLowerCase()==="content-type"?delete o[g]:l.setRequestHeader(g,p)}),Is.isUndefined(t.withCredentials)||(l.withCredentials=!!t.withCredentials),s&&s!=="json"&&(l.responseType=t.responseType),typeof t.onDownloadProgress=="function"&&l.addEventListener("progress",t.onDownloadProgress),typeof t.onUploadProgress=="function"&&l.upload&&l.upload.addEventListener("progress",t.onUploadProgress),t.cancelToken&&t.cancelToken.promise.then(function(p){!l||(l.abort(),i(p),l=null)}),a||(a=null),l.send(a)})},ee=Fe,Qp=zM,iA=u1,aA={"Content-Type":"application/x-www-form-urlencoded"};function Jp(e,t){!ee.isUndefined(e)&&ee.isUndefined(e["Content-Type"])&&(e["Content-Type"]=t)}function oA(){var e;return(typeof XMLHttpRequest!="undefined"||typeof process!="undefined"&&Object.prototype.toString.call(process)==="[object process]")&&(e=Zp),e}function sA(e,t,r){if(ee.isString(e))try{return(t||JSON.parse)(e),ee.trim(e)}catch(n){if(n.name!=="SyntaxError")throw n}return(r||JSON.stringify)(e)}var Eu={transitional:{silentJSONParsing:!0,forcedJSONParsing:!0,clarifyTimeoutError:!1},adapter:oA(),transformRequest:[function(t,r){return Qp(r,"Accept"),Qp(r,"Content-Type"),ee.isFormData(t)||ee.isArrayBuffer(t)||ee.isBuffer(t)||ee.isStream(t)||ee.isFile(t)||ee.isBlob(t)?t:ee.isArrayBufferView(t)?t.buffer:ee.isURLSearchParams(t)?(Jp(r,"application/x-www-form-urlencoded;charset=utf-8"),t.toString()):ee.isObject(t)||r&&r["Content-Type"]==="application/json"?(Jp(r,"application/json"),sA(t)):t}],transformResponse:[function(t){var r=this.transitional,n=r&&r.silentJSONParsing,i=r&&r.forcedJSONParsing,a=!n&&this.responseType==="json";if(a||i&&ee.isString(t)&&t.length)try{return JSON.parse(t)}catch(o){if(a)throw o.name==="SyntaxError"?iA(o,this,"E_JSON_PARSE"):o}return t}],timeout:0,xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN",maxContentLength:-1,maxBodyLength:-1,validateStatus:function(t){return t>=200&&t<300}};Eu.headers={common:{Accept:"application/json, text/plain, */*"}};ee.forEach(["delete","get","head"],function(t){Eu.headers[t]={}});ee.forEach(["post","put","patch"],function(t){Eu.headers[t]=ee.merge(aA)});var Jv=Eu,lA=Fe,uA=Jv,fA=function(t,r,n){var i=this||uA;return lA.forEach(n,function(o){t=o.call(i,t,r)}),t},c1=function(t){return!!(t&&t.__CANCEL__)},tg=Fe,_f=fA,cA=c1,hA=Jv;function wf(e){e.cancelToken&&e.cancelToken.throwIfRequested()}var vA=function(t){wf(t),t.headers=t.headers||{},t.data=_f.call(t,t.data,t.headers,t.transformRequest),t.headers=tg.merge(t.headers.common||{},t.headers[t.method]||{},t.headers),tg.forEach(["delete","get","head","post","put","patch","common"],function(i){delete t.headers[i]});var r=t.adapter||hA.adapter;return r(t).then(function(i){retur
Line truncated
|
||||
* pinia v2.0.12
|
||||
* (c) 2022 Eduardo San Martin Morote
|
||||
* @license MIT
|
||||
*/let w1;const Ru=e=>w1=e,b1=Symbol();function lh(e){return e&&typeof e=="object"&&Object.prototype.toString.call(e)==="[object Object]"&&typeof e.toJSON!="function"}var Co;(function(e){e.direct="direct",e.patchObject="patch object",e.patchFunction="patch function"})(Co||(Co={}));function Jz(){const e=n_(!0),t=e.run(()=>wa({}));let r=[],n=[];const i=_a({install(a){Ru(i),i._a=a,a.provide(b1,i),a.config.globalProperties.$pinia=i,n.forEach(o=>r.push(o)),n=[]},use(a){return!this._a&&!KA?n.push(a):r.push(a),this},_p:r,_a:null,_e:e,_s:new Map,state:t});return i}const S1=()=>{};function fg(e,t,r,n=S1){e.push(t);const i=()=>{const a=e.indexOf(t);a>-1&&(e.splice(a,1),n())};return!r&&Oa()&&Du(i),i}function Bi(e,...t){e.slice().forEach(r=>{r(...t)})}function uh(e,t){for(const r in t){const n=t[r],i=e[r];lh(i)&&lh(n)&&!Wt(n)&&!bn(n)?e[r]=uh(i,n):e[r]=n}return e}const ZA=Symbol();function QA(e){return!lh(e)||!e.hasOwnProperty(ZA)}const{assign:kr}=Object;function JA(e){return!!(Wt(e)&&e.effect)}function tD(e,t,r,n){const{state:i,actions:a,getters:o}=t,s=r.state.value[e];let l;function u(){s||(r.state.value[e]=i?i():{});const f=DT(r.state.value[e]);return kr(f,a,Object.keys(o||{}).reduce((c,v)=>(c[v]=_a(Ee(()=>{Ru(r);const h=r._s.get(e);return o[v].call(h,h)})),c),{}))}return l=x1(e,u,t,r),l.$reset=function(){const c=i?i():{};this.$patch(v=>{kr(v,c)})},l}function x1(e,t,r={},n,i){let a;const o=r.state,s=kr({actions:{}},r),l={deep:!0};let u,f,c=_a([]),v=_a([]),h;const d=n.state.value[e];!o&&!d&&(n.state.value[e]={}),wa({});function p(b){let x;u=f=!1,typeof b=="function"?(b(n.state.value[e]),x={type:Co.patchFunction,storeId:e,events:h}):(uh(n.state.value[e],b),x={type:Co.patchObject,payload:b,storeId:e,events:h}),Bv().then(()=>{u=!0}),f=!0,Bi(c,x,n.state.value[e])}const g=S1;function m(){a.stop(),c=[],v=[],n._s.delete(e)}function y(b,x){return function(){Ru(n);const T=Array.from(arguments),C=[],D=[];function P(O){C.push(O)}function A(O){D.push(O)}Bi(v,{args:T,name:b,store:w,after:P,onError:A});let L;try{L=x.apply(this&&this.$id===e?this:w,T)}catch(O){throw Bi(D,O),O}return L instanceof Promise?L.then(O=>(Bi(C,O),O)).catch(O=>(Bi(D,O),Promise.reject(O))):(Bi(C,L),L)}}const _={_p:n,$id:e,$onAction:fg.bind(null,v),$patch:p,$reset:g,$subscribe(b,x={}){const T=fg(c,b,x.detached,()=>C()),C=a.run(()=>ha(()=>n.state.value[e],D=>{(x.flush==="sync"?f:u)&&b({storeId:e,type:Co.direct,events:h},D)},kr({},l,x)));return T},$dispose:m},w=Ai(kr({},_));n._s.set(e,w);const S=n._e.run(()=>(a=n_(),a.run(()=>t())));for(const b in S){const x=S[b];if(Wt(x)&&!JA(x)||bn(x))o||(d&&QA(x)&&(Wt(x)?x.value=d[b]:uh(x,d[b])),n.state.value[e][b]=x);else if(typeof x=="function"){const T=y(b,x);S[b]=T,s.actions[b]=x}}return kr(w,S),kr(Ct(w),S),Object.defineProperty(w,"$state",{get:()=>n.state.value[e],set:b=>{p(x=>{kr(x,b)})}}),n._p.forEach(b=>{kr(w,a.run(()=>b({store:w,app:n._a,pinia:n,options:s})))}),d&&o&&r.hydrate&&r.hydrate(w.$state,d),u=!0,f=!0,w}function tH(e,t,r){let n,i;const a=typeof t=="function";typeof e=="string"?(n=e,i=a?r:t):(i=e,n=e.id);function o(s,l){const u=Oa();return s=s||u&&Je(b1),s&&Ru(s),s=w1,s._s.has(n)||(a?x1(n,t,i,s):tD(n,i,s)),s._s.get(n)}return o.$id=n,o}/*!
|
||||
* vue-router v4.0.14
|
||||
* (c) 2022 Eduardo San Martin Morote
|
||||
* @license MIT
|
||||
*/const T1=typeof Symbol=="function"&&typeof Symbol.toStringTag=="symbol",ka=e=>T1?Symbol(e):"_vr_"+e,eD=ka("rvlm"),cg=ka("rvd"),Ou=ka("r"),nd=ka("rl"),fh=ka("rvl"),ea=typeof window!="undefined";function rD(e){return e.__esModule||T1&&e[Symbol.toStringTag]==="Module"}const Lt=Object.assign;function bf(e,t){const r={};for(const n in t){const i=t[n];r[n]=Array.isArray(i)?i.map(e):e(i)}return r}const Mo=()=>{},nD=/\/$/,iD=e=>e.replace(nD,"");function Sf(e,t,r="/"){let n,i={},a="",o="";const s=t.indexOf("?"),l=t.indexOf("#",s>-1?s:0);return s>-1&&(n=t.slice(0,s),a=t.slice(s+1,l>-1?l:t.length),i=e(a)),l>-1&&(n=n||t.slice(0,l),o=t.slice(l,t.length)),n=lD(n!=null?n:t,r),{fullPath:n+(a&&"?")+a+o,path:n,query:i,hash:o}}function aD(e,t){const r=t.query?e(t.query):"";return t.path+(r&&"?")+r+(t.hash||"")}function hg(e,t){return!t||!e.toLowerCase().startsWith(t.toLowerCase())?e:e.slice(t.length)||"/"}function oD(e,t,r){const n=t.matched.length-1,i=r.matched.length-1;return n>-1&&n===i&&xa(t.matched[n],r.matched[i])&&C1(t.params,r.params)&&e(t.query)===e(r.query)&&t.hash===r.hash}function xa(e,t){return(e.aliasOf||e)===(t.aliasOf||t)}function C1(e,t){if(Object.keys(e).length!==Object.keys(t).length)return!1;for(const r in e)if(!sD(e[r],t[r]))return!1;return!0}function sD(e,t){return Array.isArray(e)?vg(e,t):Array.isArray(t)?vg(t,e):e===t}function vg(e,t){return Array.isArray(t)?e.length===t.length&&e.every((r,n)=>r===t[n]):e.length===1&&e[0]===t}function lD(e,t){if(e.startsWith("/"))return e;if(!e)return t;const r=t.split("/"),n=e.split("/");let i=r.length-1,a,o;for(a=0;a<n.length;a++)if(o=n[a],!(i===1||o==="."))if(o==="..")i--;else break;return r.slice(0,i).join("/")+"/"+n.slice(a-(a===n.length?1:0)).join("/")}var Ko;(function(e){e.pop="pop",e.push="push"})(Ko||(Ko={}));var Ao;(function(e){e.back="back",e.forward="forward",e.unknown=""})(Ao||(Ao={}));function uD(e){if(!e)if(ea){const t=document.querySelector("base");e=t&&t.getAttribute("href")||"/",e=e.replace(/^\w+:\/\/[^\/]+/,"")}else e="/";return e[0]!=="/"&&e[0]!=="#"&&(e="/"+e),iD(e)}const fD=/^[^#]+#/;function cD(e,t){return e.replace(fD,"#")+t}function hD(e,t){const r=document.documentElement.getBoundingClientRect(),n=e.getBoundingClientRect();return{behavior:t.behavior,left:n.left-r.left-(t.left||0),top:n.top-r.top-(t.top||0)}}const ku=()=>({left:window.pageXOffset,top:window.pageYOffset});function vD(e){let t;if("el"in e){const r=e.el,n=typeof r=="string"&&r.startsWith("#"),i=typeof r=="string"?n?document.getElementById(r.slice(1)):document.querySelector(r):r;if(!i)return;t=hD(i,e)}else t=e;"scrollBehavior"in document.documentElement.style?window.scrollTo(t):window.scrollTo(t.left!=null?t.left:window.pageXOffset,t.top!=null?t.top:window.pageYOffset)}function dg(e,t){return(history.state?history.state.position-t:-1)+e}const ch=new Map;function dD(e,t){ch.set(e,t)}function pD(e){const t=ch.get(e);return ch.delete(e),t}let gD=()=>location.protocol+"//"+location.host;function M1(e,t){const{pathname:r,search:n,hash:i}=t,a=e.indexOf("#");if(a>-1){let s=i.includes(e.slice(a))?e.slice(a).length:1,l=i.slice(s);return l[0]!=="/"&&(l="/"+l),hg(l,"")}return hg(r,e)+n+i}function mD(e,t,r,n){let i=[],a=[],o=null;const s=({state:v})=>{const h=M1(e,location),d=r.value,p=t.value;let g=0;if(v){if(r.value=h,t.value=v,o&&o===d){o=null;return}g=p?v.position-p.position:0}else n(h);i.forEach(m=>{m(r.value,d,{delta:g,type:Ko.pop,direction:g?g>0?Ao.forward:Ao.back:Ao.unknown})})};function l(){o=r.value}function u(v){i.push(v);const h=()=>{const d=i.indexOf(v);d>-1&&i.splice(d,1)};return a.push(h),h}function f(){const{history:v}=window;!v.state||v.replaceState(Lt({},v.state,{scroll:ku()}),"")}function c(){for(const v of a)v();a=[],window.removeEventListener("popstate",s),window.removeEventListener("beforeunload",f)}return window.addEventListener("popstate",s),window.addEventListener("beforeunload",f),{pauseListeners:l,listen:u,destroy:c}}function pg(e,t,r,n=!1,i=!1){return{back:e,current:t,forward:r,replaced:n,position:window.history.length,scroll:i?ku():null}}function yD(e){const{history:t,location:r}=window,n={value:M1(e,r)},i={value:t.state};i.value||a(n.value,{back:null,current:n.value,forward:null,position:t.length-1,replaced:!0,scroll:null},!0);function a(l,u,f){const c=e.indexOf("#"),v=c>-1?(r.host&&document.querySelector("base")?e:e.slice(c))+l:gD()+e+l;try{t[f?"replaceState":"pushState"](u,"",v),i.value=u}catch(h){console.error(h),r[f?"replace":"assign"](v)}}function o(l,u){const f=Lt({},t.state,pg(i.value.back,l,i.value.forward,!0),u,{position:i.value.position});a(l,f,!0),n.value=l}function s(l,u){const f=Lt({},i.value,t.state,{forward:l,scroll:ku()});a(f.current,f,!0);const c=Lt({},pg(n.value,l,null),{position:f.position+1},u);a(l,c,!1),n.value=l}return{location:n,state:i,push:s,replace:o}}function eH(e){e=uD(e);const t=yD(e),r=mD(e,t.state,t.location,t.replace);function n(a,o=!0){o||r.pauseListeners(),history.go(a)}const i=Lt({location:"",base:e,go:n,createHref:cD.bind(nLine truncated
|
||||
Copyright (c) Microsoft Corporation.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
PERFORMANCE OF THIS SOFTWARE.
|
||||
***************************************************************************** */var vh=function(e,t){return vh=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(r,n){r.__proto__=n}||function(r,n){for(var i in n)Object.prototype.hasOwnProperty.call(n,i)&&(r[i]=n[i])},vh(e,t)};function J(e,t){if(typeof t!="function"&&t!==null)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");vh(e,t);function r(){this.constructor=e}e.prototype=t===null?Object.create(t):(r.prototype=t.prototype,new r)}var nP=function(){function e(){this.firefox=!1,this.ie=!1,this.edge=!1,this.newEdge=!1,this.weChat=!1}return e}(),iP=function(){function e(){this.browser=new nP,this.node=!1,this.wxa=!1,this.worker=!1,this.svgSupported=!1,this.touchEventsSupported=!1,this.pointerEventsSupported=!1,this.domSupported=!1,this.transformSupported=!1,this.transform3dSupported=!1,this.hasGlobalWindow=typeof window!="undefined"}return e}(),ui=new iP;typeof wx=="object"&&typeof wx.getSystemInfoSync=="function"?(ui.wxa=!0,ui.touchEventsSupported=!0):typeof document=="undefined"&&typeof self!="undefined"?ui.worker=!0:typeof navigator=="undefined"?(ui.node=!0,ui.svgSupported=!0):aP(navigator.userAgent,ui);function aP(e,t){var r=t.browser,n=e.match(/Firefox\/([\d.]+)/),i=e.match(/MSIE\s([\d.]+)/)||e.match(/Trident\/.+?rv:(([\d.]+))/),a=e.match(/Edge?\/([\d.]+)/),o=/micromessenger/i.test(e);n&&(r.firefox=!0,r.version=n[1]),i&&(r.ie=!0,r.version=i[1]),a&&(r.edge=!0,r.version=a[1],r.newEdge=+a[1].split(".")[0]>18),o&&(r.weChat=!0),t.svgSupported=typeof SVGRect!="undefined",t.touchEventsSupported="ontouchstart"in window&&!r.ie&&!r.edge,t.pointerEventsSupported="onpointerdown"in window&&(r.edge||r.ie&&+r.version>=11),t.domSupported=typeof document!="undefined";var s=document.documentElement.style;t.transform3dSupported=(r.ie&&"transition"in s||r.edge||"WebKitCSSMatrix"in window&&"m11"in new WebKitCSSMatrix||"MozPerspective"in s)&&!("OTransition"in s),t.transformSupported=t.transform3dSupported||r.ie&&+r.version>=9}var wt=ui,ad=12,oP="sans-serif",bi=ad+"px "+oP,sP=20,lP=100,uP="007LLmW'55;N0500LLLLLLLLLL00NNNLzWW\\\\WQb\\0FWLg\\bWb\\WQ\\WrWWQ000CL5LLFLL0LL**F*gLLLL5F0LF\\FFF5.5N";function fP(e){var t={};if(typeof JSON=="undefined")return t;for(var r=0;r<e.length;r++){var n=String.fromCharCode(r+32),i=(e.charCodeAt(r)-sP)/lP;t[n]=i}return t}var cP=fP(uP),Pi={createCanvas:function(){return typeof document!="undefined"&&document.createElement("canvas")},measureText:function(){var e,t;return function(r,n){if(!e){var i=Pi.createCanvas();e=i&&i.getContext("2d")}if(e)return t!==n&&(t=e.font=n||bi),e.measureText(r);r=r||"",n=n||bi;var a=/^([0-9]*?)px$/.exec(n),o=+(a&&a[1])||ad,s=0;if(n.indexOf("mono")>=0)s=o*r.length;else for(var l=0;l<r.length;l++){var u=cP[r[l]];s+=u==null?o:u*o}return{width:s}}}(),loadImage:function(e,t,r){var n=new Image;return n.onload=t,n.onerror=r,n.src=e,n}},k1=Ln(["Function","RegExp","Date","Error","CanvasGradient","CanvasPattern","Image","Canvas"],function(e,t){return e["[object "+t+"]"]=!0,e},{}),N1=Ln(["Int8","Uint8","Uint8Clamped","Int16","Uint16","Int32","Uint32","Float32","Float64"],function(e,t){return e["[object "+t+"Array]"]=!0,e},{}),ps=Object.prototype.toString,Nu=Array.prototype,hP=Nu.forEach,vP=Nu.filter,od=Nu.slice,dP=Nu.map,Cg=function(){}.constructor,Es=Cg?Cg.prototype:null,sd="__proto__",pP=2311;function B1(){return pP++}function ld(){for(var e=[],t=0;t<arguments.length;t++)e[t]=arguments[t];typeof console!="undefined"&&console.error.apply(console,e)}function xt(e){if(e==null||typeof e!="object")return e;var t=e,r=ps.call(e);if(r==="[object Array]"){if(!Po(e)){t=[];for(var n=0,i=e.length;n<i;n++)t[n]=xt(e[n])}}else if(N1[r]){if(!Po(e)){var a=e.constructor;if(a.from)t=a.from(e);else{t=new a(e.length);for(var n=0,i=e.length;n<i;n++)t[n]=e[n]}}}else if(!k1[r]&&!Po(e)&&!Yl(e)){t={};for(var o in e)e.hasOwnProperty(o)&&o!==sd&&(t[o]=xt(e[o]))}return t}function Dt(e,t,r){if(!st(t)||!st(e))return r?xt(t):e;for(var n in t)if(t.hasOwnProperty(n)&&n!==sd){var i=e[n],a=t[n];st(a)&&st(i)&&!et(a)&&!et(i)&&!Yl(a)&&!Yl(i)&&!Mg(a)&&!Mg(i)&&!Po(a)&&!Po(i)?Dt(i,a,r):(r||!(n in e))&&(e[n]=xt(t[n]))}return e}function Y(e,t){if(Object.assign)Object.assign(e,t);else for(var r in t)t.hasOwnProperty(r)&&r!==sd&&(e[r]=t[r]);return e}function Pt(e,t,r){for(var n=Gt(t),i=0;i<n.length;i++){var a=n[i];(r?t[a]!=null:e[a]==null)&&(e[a]=t[a])}return e}Pi.createCanvas;function It(e,t){if(e){if(e.indexOf)return e.indexOf(t);for(var r=0,n=e.length;r<n;r++)if(e[r]===t)return r}return-1}function gP(e,t){var r=e.prototype;function n(){}n.prototype=t.prototype,e.prototype=new n;for(var i in r)r.hasOwnProperty(i)&&(e.prototype[i]=r[i]);e.prototype.constructor=e,e.superClass=t}function Pr(e,t,r){if(e="prototype"in e?e.prototype:e,t="prototype"in t?t.prototype:t,Object.getOwnPropertyNames)for(var n=Object.getOwnPropertyNames(t),i=0;i<n.length;i++){var a=n[i];a!=="constructor"&&(r?t[a]!=null:e[a]==null)&&(e[a]=t[a])}else Pt(Line truncated
|
||||
`),a=i.length;if(a===1)return Zg(i[0],t,r,n);for(var o=new Ot(0,0,0,0),s=0;s<i.length;s++){var l=Zg(i[s],t,r,n);s===0?o.copy(l):o.union(l)}return o}function po(e,t,r){return r==="right"?e-=t:r==="center"&&(e-=t/2),e}function na(e,t,r){return r==="middle"?e-=t/2:r==="bottom"&&(e-=t),e}function md(e){return Oe("\u56FD",e)}function Rn(e,t){return typeof e=="string"?e.lastIndexOf("%")>=0?parseFloat(e)/100*t:parseFloat(e):e}function aw(e,t,r){var n=t.position||"inside",i=t.distance!=null?t.distance:5,a=r.height,o=r.width,s=a/2,l=r.x,u=r.y,f="left",c="top";if(n instanceof Array)l+=Rn(n[0],r.width),u+=Rn(n[1],r.height),f=null,c=null;else switch(n){case"left":l-=i,u+=s,f="right",c="middle";break;case"right":l+=i+o,u+=s,c="middle";break;case"top":l+=o/2,u-=i,f="center",c="bottom";break;case"bottom":l+=o/2,u+=a+i,f="center";break;case"inside":l+=o/2,u+=s,f="center",c="middle";break;case"insideLeft":l+=i,u+=s,c="middle";break;case"insideRight":l+=o-i,u+=s,f="right",c="middle";break;case"insideTop":l+=o/2,u+=i,f="center";break;case"insideBottom":l+=o/2,u+=a-i,f="center",c="bottom";break;case"insideTopLeft":l+=i,u+=i;break;case"insideTopRight":l+=o-i,u+=i,f="right";break;case"insideBottomLeft":l+=i,u+=a-i,c="bottom";break;case"insideBottomRight":l+=o-i,u+=a-i,f="right",c="bottom";break}return e=e||{},e.x=l,e.y=u,e.align=f,e.verticalAlign=c,e}var $f="__zr_normal__",Vf=Jo.concat(["ignore"]),OI=Ln(Jo,function(e,t){return e[t]=!0,e},{ignore:!1}),Vi={},kI=new Ot(0,0,0,0),yd=function(){function e(t){this.id=B1(),this.animators=[],this.currentStates=[],this.states={},this._init(t)}return e.prototype._init=function(t){this.attr(t)},e.prototype.drift=function(t,r,n){switch(this.draggable){case"horizontal":r=0;break;case"vertical":t=0;break}var i=this.transform;i||(i=this.transform=[1,0,0,1,0,0]),i[4]+=t,i[5]+=r,this.decomposeTransform(),this.markRedraw()},e.prototype.beforeUpdate=function(){},e.prototype.afterUpdate=function(){},e.prototype.update=function(){this.updateTransform(),this.__dirty&&this.updateInnerText()},e.prototype.updateInnerText=function(t){var r=this._textContent;if(r&&(!r.ignore||t)){this.textConfig||(this.textConfig={});var n=this.textConfig,i=n.local,a=r.innerTransformable,o=void 0,s=void 0,l=!1;a.parent=i?this:null;var u=!1;if(a.copyTransform(r),n.position!=null){var f=kI;n.layoutRect?f.copy(n.layoutRect):f.copy(this.getBoundingRect()),i||f.applyTransform(this.transform),this.calculateTextPosition?this.calculateTextPosition(Vi,n,f):aw(Vi,n,f),a.x=Vi.x,a.y=Vi.y,o=Vi.align,s=Vi.verticalAlign;var c=n.origin;if(c&&n.rotation!=null){var v=void 0,h=void 0;c==="center"?(v=f.width*.5,h=f.height*.5):(v=Rn(c[0],f.width),h=Rn(c[1],f.height)),u=!0,a.originX=-a.x+v+(i?0:f.x),a.originY=-a.y+h+(i?0:f.y)}}n.rotation!=null&&(a.rotation=n.rotation);var d=n.offset;d&&(a.x+=d[0],a.y+=d[1],u||(a.originX=-d[0],a.originY=-d[1]));var p=n.inside==null?typeof n.position=="string"&&n.position.indexOf("inside")>=0:n.inside,g=this._innerTextDefaultStyle||(this._innerTextDefaultStyle={}),m=void 0,y=void 0,_=void 0;p&&this.canBeInsideText()?(m=n.insideFill,y=n.insideStroke,(m==null||m==="auto")&&(m=this.getInsideTextFill()),(y==null||y==="auto")&&(y=this.getInsideTextStroke(m),_=!0)):(m=n.outsideFill,y=n.outsideStroke,(m==null||m==="auto")&&(m=this.getOutsideFill()),(y==null||y==="auto")&&(y=this.getOutsideStroke(m),_=!0)),m=m||"#000",(m!==g.fill||y!==g.stroke||_!==g.autoStroke||o!==g.align||s!==g.verticalAlign)&&(l=!0,g.fill=m,g.stroke=y,g.autoStroke=_,g.align=o,g.verticalAlign=s,r.setDefaultTextStyle(g)),r.__dirty|=Le,l&&r.dirtyStyle(!0)}},e.prototype.canBeInsideText=function(){return!0},e.prototype.getInsideTextFill=function(){return"#fff"},e.prototype.getInsideTextStroke=function(t){return"#000"},e.prototype.getOutsideFill=function(){return this.__zr&&this.__zr.isDarkMode()?Eh:Ih},e.prototype.getOutsideStroke=function(t){var r=this.__zr&&this.__zr.getBackgroundColor(),n=typeof r=="string"&&$r(r);n||(n=[255,255,255,1]);for(var i=n[3],a=this.__zr.isDarkMode(),o=0;o<3;o++)n[o]=n[o]*i+(a?0:255)*(1-i);return n[3]=1,zu(n,"rgba")},e.prototype.traverse=function(t,r){},e.prototype.attrKV=function(t,r){t==="textConfig"?this.setTextConfig(r):t==="textContent"?this.setTextContent(r):t==="clipPath"?this.setClipPath(r):t==="extra"?(this.extra=this.extra||{},Y(this.extra,r)):this[t]=r},e.prototype.hide=function(){this.ignore=!0,this.markRedraw()},e.prototype.show=function(){this.ignore=!1,this.markRedraw()},e.prototype.attr=function(t,r){if(typeof t=="string")this.attrKV(t,r);else if(st(t))for(var n=t,i=Gt(n),a=0;a<i.length;a++){var o=i[a];this.attrKV(o,t[o])}return this.markRedraw(),this},e.prototype.saveCurrentToNormalState=function(t){this._innerSaveToNormal(t);for(var r=this._normalState,n=0;n<this.animators.length;n++){var i=this.animators[n],a=i.__fromStateTransition;if(!(i.getLoop()||a&&a!==$f)){var o=i.targetName,s=o?r[o]:r;i.saveTo(s)}}},e.prototype._innerSaveToNormal=function(t){var r=this._normalState;r||(r=this._normalState={}),t.textC
Line truncated
|
||||
* ZRender, a high performance 2d drawing library.
|
||||
*
|
||||
* Copyright (c) 2013, Baidu Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* LICENSE
|
||||
* https://github.com/ecomfe/zrender/blob/master/LICENSE.txt
|
||||
*/var Pl={},uw={};function HI(e){delete uw[e]}function $I(e){if(!e)return!1;if(typeof e=="string")return Jl(e,1)<Ph;if(e.colorStops){for(var t=e.colorStops,r=0,n=t.length,i=0;i<n;i++)r+=Jl(t[i].color,1);return r/=n,r<Ph}return!1}var VI=function(){function e(t,r,n){var i=this;this._sleepAfterStill=10,this._stillFrameAccum=0,this._needsRefresh=!0,this._needsRefreshHover=!0,this._darkMode=!1,n=n||{},this.dom=r,this.id=t;var a=new QP,o=n.renderer||"canvas";Pl[o]||(o=Gt(Pl)[0]),n.useDirtyRect=n.useDirtyRect==null?!1:n.useDirtyRect;var s=new Pl[o](r,a,n,t),l=n.ssr||s.ssrOnly;this.storage=a,this.painter=s;var u=!wt.node&&!wt.worker&&!l?new AI(s.getViewportRoot(),s.root):null;this.handler=new qP(a,s,u,s.root),this.animation=new _I({stage:{update:l?null:function(){return i._flush(!0)}}}),l||this.animation.start()}return e.prototype.add=function(t){!t||(this.storage.addRoot(t),t.addSelfToZr(this),this.refresh())},e.prototype.remove=function(t){!t||(this.storage.delRoot(t),t.removeSelfFromZr(this),this.refresh())},e.prototype.configLayer=function(t,r){this.painter.configLayer&&this.painter.configLayer(t,r),this.refresh()},e.prototype.setBackgroundColor=function(t){this.painter.setBackgroundColor&&this.painter.setBackgroundColor(t),this.refresh(),this._backgroundColor=t,this._darkMode=$I(t)},e.prototype.getBackgroundColor=function(){return this._backgroundColor},e.prototype.setDarkMode=function(t){this._darkMode=t},e.prototype.isDarkMode=function(){return this._darkMode},e.prototype.refreshImmediately=function(t){t||this.animation.update(!0),this._needsRefresh=!1,this.painter.refresh(),this._needsRefresh=!1},e.prototype.refresh=function(){this._needsRefresh=!0,this.animation.start()},e.prototype.flush=function(){this._flush(!1)},e.prototype._flush=function(t){var r,n=oa();this._needsRefresh&&(r=!0,this.refreshImmediately(t)),this._needsRefreshHover&&(r=!0,this.refreshHoverImmediately());var i=oa();r?(this._stillFrameAccum=0,this.trigger("rendered",{elapsedTime:i-n})):this._sleepAfterStill>0&&(this._stillFrameAccum++,this._stillFrameAccum>this._sleepAfterStill&&this.animation.stop())},e.prototype.setSleepAfterStill=function(t){this._sleepAfterStill=t},e.prototype.wakeUp=function(){this.animation.start(),this._stillFrameAccum=0},e.prototype.refreshHover=function(){this._needsRefreshHover=!0},e.prototype.refreshHoverImmediately=function(){this._needsRefreshHover=!1,this.painter.refreshHover&&this.painter.getType()==="canvas"&&this.painter.refreshHover()},e.prototype.resize=function(t){t=t||{},this.painter.resize(t.width,t.height),this.handler.resize()},e.prototype.clearAnimation=function(){this.animation.clear()},e.prototype.getWidth=function(){return this.painter.getWidth()},e.prototype.getHeight=function(){return this.painter.getHeight()},e.prototype.setCursorStyle=function(t){this.handler.setCursorStyle(t)},e.prototype.findHover=function(t,r){return this.handler.findHover(t,r)},e.prototype.on=function(t,r,n){return this.handler.on(t,r,n),this},e.prototype.off=function(t,r){this.handler.off(t,r)},e.prototype.trigger=function(t,r){this.handler.trigger(t,r)},e.prototype.clear=function(){for(var t=this.storage.getRoots(),r=0;r<t.length;r++)t[r]instanceof ye&&t[r].removeSelfFromZr(this);this.storage.delAllRoots(),this.painter.clear()},e.prototype.dispose=function(){this.animation.stop(),this.clear(),this.storage.dispose(),this.painter.dispose(),this.handler.dispose(),this.animation=this.storage=this.painter=this.handler=null,HI(this.id)},e}();function Qg(e,t){var r=new VI(B1(),e,t);return uw[r.id]=r,r}function GI(e,t){Pl[e]=t}var Jg=1e-4,fw=20;function UI(e){return e.replace(/^\s+|\s+$/g,"")}function Rh(e,t,r,n){var i=t[0],a=t[1],o=r[0],s=r[1],l=a-i,u=s-o;if(l===0)return u===0?o:(o+s)/2;if(n)if(l>0){if(e<=i)return o;if(e>=a)return s}else{if(e>=i)return o;if(e<=a)return s}else{if(e===i)return o;if(e===a)return s}return(e-i)/l*u+o}function Vt(e,t){switch(e){case"center":case"middle":e="50%";break;case"left":case"top":e="0%";break;case"right":case"bottom":e="100%";break}return it(e)?UI(e).match(/%$/)?parseFloat(e)/100*t:parseFloat(e):e==null?NaN:+e}function jt(e,t,r){return t==null&&(t=10),t=Math.min(Math.max(0,t),fw),e=(+e).toFixed(t),r?e:+e}function zr(e){if(e=+e,isNaN(e))return 0;if(e>1e-14){for(var t=1,r=0;r<15;r++,t*=10)if(Math.round(e*t)/t===e)return r}return WI(e)}function WI(e){var t=e.toString().toLowerCase(),r=t.indexOf("e"),n=r>0?+t.slice(r+1):0,i=r>0?r:t.length,a=t.indexOf("."),o=a<0?0:i-1-a;return Math.max(0,o-n)}function YI(e,t){var r=Math.log,n=Math.LN10,i=Math.floor(r(e[1]-e[0])/n),a=Math.round(r(Math.abs(t[1]-t[0]))/n),o=Math.min(Math.max(-i+a,0),20);return isFinite(o)?o:20}function qI(e,t,r){if(!e[t])return 0;var n=Ln(e,function(d,p){return d+(isNaN(p)?0:p)},0);if(n===0)return 0;for(var i=Math.pow(10,r),a=ct(e,function(d){return(isNaN(d)?0:d)/n*i*100}),o=i*100,s=ct(a,function(d){return Math.floor(d)}),l=Ln(s,function(d,p){return d+p},0),u=ct(a,function(d,p){return d-s[p]});l<o;){for(var f=Number.NEGATIVE_INFLine truncated
|
||||
`);i=bw(t,r,n,i);for(var o=0,s=a.length;o<s;o++)a[o]=Sw(a[o],i);return a.join(`
|
||||
`)}function bw(e,t,r,n){n=n||{};var i=Y({},n);i.font=t,r=Mt(r,"..."),i.maxIterations=Mt(n.maxIterations,2);var a=i.minChar=Mt(n.minChar,0);i.cnCharWidth=Oe("\u56FD",t);var o=i.ascCharWidth=Oe("a",t);i.placeholder=Mt(n.placeholder,"");for(var s=e=Math.max(0,e-1),l=0;l<a&&s>=o;l++)s-=o;var u=Oe(r,t);return u>s&&(r="",u=0),s=e-u,i.ellipsis=r,i.ellipsisWidth=u,i.contentWidth=s,i.containerWidth=e,i}function Sw(e,t){var r=t.containerWidth,n=t.font,i=t.contentWidth;if(!r)return"";var a=Oe(e,n);if(a<=r)return e;for(var o=0;;o++){if(a<=i||o>=t.maxIterations){e+=t.ellipsis;break}var s=o===0?ME(e,i,t.ascCharWidth,t.cnCharWidth):a>0?Math.floor(e.length*i/a):0;e=e.substr(0,s),a=Oe(e,n)}return e===""&&(e=t.placeholder),e}function ME(e,t,r,n){for(var i=0,a=0,o=e.length;a<o&&i<t;a++){var s=e.charCodeAt(a);i+=0<=s&&s<=127?r:n}return a}function AE(e,t){e!=null&&(e+="");var r=t.overflow,n=t.padding,i=t.font,a=r==="truncate",o=md(i),s=Mt(t.lineHeight,o),l=!!t.backgroundColor,u=t.lineOverflow==="truncate",f=t.width,c;f!=null&&(r==="break"||r==="breakAll")?c=e?xw(e,t.font,f,r==="breakAll",0).lines:[]:c=e?e.split(`
|
||||
`):[];var v=c.length*s,h=Mt(t.height,v);if(v>h&&u){var d=Math.floor(h/s);c=c.slice(0,d)}if(e&&a&&f!=null)for(var p=bw(f,i,t.ellipsis,{minChar:t.truncateMinChar,placeholder:t.placeholder}),g=0;g<c.length;g++)c[g]=Sw(c[g],p);for(var m=h,y=0,g=0;g<c.length;g++)y=Math.max(Oe(c[g],i),y);f==null&&(f=y);var _=y;return n&&(m+=n[0]+n[2],_+=n[1]+n[3],f+=n[1]+n[3]),l&&(_=f),{lines:c,height:h,outerWidth:_,outerHeight:m,lineHeight:s,calculatedLineHeight:o,contentWidth:y,contentHeight:v,width:f}}var DE=function(){function e(){}return e}(),im=function(){function e(t){this.tokens=[],t&&(this.tokens=t)}return e}(),PE=function(){function e(){this.width=0,this.height=0,this.contentWidth=0,this.contentHeight=0,this.outerWidth=0,this.outerHeight=0,this.lines=[]}return e}();function IE(e,t){var r=new PE;if(e!=null&&(e+=""),!e)return r;for(var n=t.width,i=t.height,a=t.overflow,o=(a==="break"||a==="breakAll")&&n!=null?{width:n,accumWidth:0,breakAll:a==="breakAll"}:null,s=Yf.lastIndex=0,l;(l=Yf.exec(e))!=null;){var u=l.index;u>s&&qf(r,e.substring(s,u),t,o),qf(r,l[2],t,o,l[1]),s=Yf.lastIndex}s<e.length&&qf(r,e.substring(s,e.length),t,o);var f=[],c=0,v=0,h=t.padding,d=a==="truncate",p=t.lineOverflow==="truncate";function g(V,K,lt){V.width=K,V.lineHeight=lt,c+=lt,v=Math.max(v,K)}t:for(var m=0;m<r.lines.length;m++){for(var y=r.lines[m],_=0,w=0,S=0;S<y.tokens.length;S++){var b=y.tokens[S],x=b.styleName&&t.rich[b.styleName]||{},T=b.textPadding=x.padding,C=T?T[1]+T[3]:0,D=b.font=x.font||t.font;b.contentHeight=md(D);var P=Mt(x.height,b.contentHeight);if(b.innerHeight=P,T&&(P+=T[0]+T[2]),b.height=P,b.lineHeight=Do(x.lineHeight,t.lineHeight,P),b.align=x&&x.align||t.align,b.verticalAlign=x&&x.verticalAlign||"middle",p&&i!=null&&c+b.lineHeight>i){S>0?(y.tokens=y.tokens.slice(0,S),g(y,w,_),r.lines=r.lines.slice(0,m+1)):r.lines=r.lines.slice(0,m);break t}var A=x.width,L=A==null||A==="auto";if(typeof A=="string"&&A.charAt(A.length-1)==="%")b.percentWidth=A,f.push(b),b.contentWidth=Oe(b.text,D);else{if(L){var O=x.backgroundColor,z=O&&O.image;z&&(z=TE(z),$u(z)&&(b.width=Math.max(b.width,z.width*P/z.height)))}var N=d&&n!=null?n-w:null;N!=null&&N<b.width?!L||N<C?(b.text="",b.width=b.contentWidth=0):(b.text=CE(b.text,N-C,D,t.ellipsis,{minChar:t.truncateMinChar}),b.width=b.contentWidth=Oe(b.text,D)):b.contentWidth=Oe(b.text,D)}b.width+=C,w+=b.width,x&&(_=Math.max(_,b.lineHeight))}g(y,w,_)}r.outerWidth=r.width=Mt(n,v),r.outerHeight=r.height=Mt(i,c),r.contentHeight=c,r.contentWidth=v,h&&(r.outerWidth+=h[1]+h[3],r.outerHeight+=h[0]+h[2]);for(var m=0;m<f.length;m++){var b=f[m],tt=b.percentWidth;b.width=parseInt(tt,10)/100*r.width}return r}function qf(e,t,r,n,i){var a=t==="",o=i&&r.rich[i]||{},s=e.lines,l=o.font||r.font,u=!1,f,c;if(n){var v=o.padding,h=v?v[1]+v[3]:0;if(o.width!=null&&o.width!=="auto"){var d=Rn(o.width,n.width)+h;s.length>0&&d+n.accumWidth>n.width&&(f=t.split(`
|
||||
`),u=!0),n.accumWidth=d}else{var p=xw(t,l,n.width,n.breakAll,n.accumWidth);n.accumWidth=p.accumWidth+h,c=p.linesWidths,f=p.lines}}else f=t.split(`
|
||||
`);for(var g=0;g<f.length;g++){var m=f[g],y=new DE;if(y.styleName=i,y.text=m,y.isLineHolder=!m&&!a,typeof o.width=="number"?y.width=o.width:y.width=c?c[g]:Oe(m,l),!g&&!u){var _=(s[s.length-1]||(s[0]=new im)).tokens,w=_.length;w===1&&_[0].isLineHolder?_[0]=y:(m||!w||a)&&_.push(y)}else s.push(new im([y]))}}function EE(e){var t=e.charCodeAt(0);return t>=33&&t<=383}var LE=Ln(",&?/;] ".split(""),function(e,t){return e[t]=!0,e},{});function RE(e){return EE(e)?!!LE[e]:!0}function xw(e,t,r,n,i){for(var a=[],o=[],s="",l="",u=0,f=0,c=0;c<e.length;c++){var v=e.charAt(c);if(v===`
|
||||
`){l&&(s+=l,f+=u),a.push(s),o.push(f),s="",l="",u=0,f=0;continue}var h=Oe(v,t),d=n?!1:!RE(v);if(a.length?f+h>r:i+f+h>r){f?(s||l)&&(d?(s||(s=l,l="",u=0,f=u),a.push(s),o.push(f-u),l+=v,u+=h,s="",f=u):(l&&(s+=l,l="",u=0),a.push(s),o.push(f),s=v,f=h)):d?(a.push(l),o.push(u),l=v,u=h):(a.push(v),o.push(h));continue}f+=h,d?(l+=v,u+=h):(l&&(s+=l,l="",u=0),s+=v)}return!a.length&&!s&&(s=e,l="",u=0),l&&(s+=l),s&&(a.push(s),o.push(f)),a.length===1&&(f+=i),{accumWidth:f,lines:a,linesWidths:o}}var Nh="__zr_style_"+Math.round(Math.random()*10),gi={shadowBlur:0,shadowOffsetX:0,shadowOffsetY:0,shadowColor:"#000",opacity:1,blend:"source-over"},Vu={style:{shadowBlur:!0,shadowOffsetX:!0,shadowOffsetY:!0,shadowColor:!0,opacity:!0}};gi[Nh]=!0;var am=["z","z2","invisible"],OE=["invisible"],kE=function(e){J(t,e);function t(r){return e.call(this,r)||this}return t.prototype._init=function(r){for(var n=Gt(r),i=0;i<n.length;i++){var a=n[i];a==="style"?this.useStyle(r[a]):e.prototype.attrKV.call(this,a,r[a])}this.style||this.useStyle({})},t.prototype.beforeBrush=function(){},t.prototype.afterBrush=function(){},t.prototype.innerBeforeBrush=function(){},t.prototype.innerAfterBrush=function(){},t.prototype.shouldBePainted=function(r,n,i,a){var o=this.transform;if(this.ignore||this.invisible||this.style.opacity===0||this.culling&&NE(this,r,n)||o&&!o[0]&&!o[3])return!1;if(i&&this.__clipPaths){for(var s=0;s<this.__clipPaths.length;++s)if(this.__clipPaths[s].isZeroArea())return!1}if(a&&this.parent)for(var l=this.parent;l;){if(l.ignore)return!1;l=l.parent}return!0},t.prototype.contain=function(r,n){return this.rectContain(r,n)},t.prototype.traverse=function(r,n){r.call(n,this)},t.prototype.rectContain=function(r,n){var i=this.transformCoordToLocal(r,n),a=this.getBoundingRect();return a.contain(i[0],i[1])},t.prototype.getPaintRect=function(){var r=this._paintRect;if(!this._paintRect||this.__dirty){var n=this.transform,i=this.getBoundingRect(),a=this.style,o=a.shadowBlur||0,s=a.shadowOffsetX||0,l=a.shadowOffsetY||0;r=this._paintRect||(this._paintRect=new Ot(0,0,0,0)),n?Ot.applyTransform(r,i,n):r.copy(i),(o||s||l)&&(r.width+=o*2+Math.abs(s),r.height+=o*2+Math.abs(l),r.x=Math.min(r.x,r.x+s-o),r.y=Math.min(r.y,r.y+l-o));var u=this.dirtyRectTolerance;r.isZero()||(r.x=Math.floor(r.x-u),r.y=Math.floor(r.y-u),r.width=Math.ceil(r.width+1+u*2),r.height=Math.ceil(r.height+1+u*2))}return r},t.prototype.setPrevPaintRect=function(r){r?(this._prevPaintRect=this._prevPaintRect||new Ot(0,0,0,0),this._prevPaintRect.copy(r)):this._prevPaintRect=null},t.prototype.getPrevPaintRect=function(){return this._prevPaintRect},t.prototype.animateStyle=function(r){return this.animate("style",r)},t.prototype.updateDuringAnimation=function(r){r==="style"?this.dirtyStyle():this.markRedraw()},t.prototype.attrKV=function(r,n){r!=="style"?e.prototype.attrKV.call(this,r,n):this.style?this.setStyle(n):this.useStyle(n)},t.prototype.setStyle=function(r,n){return typeof r=="string"?this.style[r]=n:Y(this.style,r),this.dirtyStyle(),this},t.prototype.dirtyStyle=function(r){r||this.markRedraw(),this.__dirty|=ho,this._rect&&(this._rect=null)},t.prototype.dirty=function(){this.dirtyStyle()},t.prototype.styleChanged=function(){return!!(this.__dirty&ho)},t.prototype.styleUpdated=function(){this.__dirty&=~ho},t.prototype.createStyle=function(r){return Fu(gi,r)},t.prototype.useStyle=function(r){r[Nh]||(r=this.createStyle(r)),this.__inHover?this.__hoverStyle=r:this.style=r,this.dirtyStyle()},t.prototype.isStyleObject=function(r){return r[Nh]},t.prototype._innerSaveToNormal=function(r){e.prototype._innerSaveToNormal.call(this,r);var n=this._normalState;r.style&&!n.style&&(n.style=this._mergeStyle(this.createStyle(),this.style)),this._savePrimaryToNormal(r,n,am)},t.prototype._applyStateObj=function(r,n,i,a,o,s){e.prototype._applyStateObj.call(this,r,n,i,a,o,s);var l=!(n&&a),u;if(n&&n.style?o?a?u=n.style:(u=this._mergeStyle(this.createStyle(),i.style),this._mergeStyle(u,n.style)):(u=this._mergeStyle(this.createStyle(),a?this.style:i.style),this._mergeStyle(u,n.style)):l&&(u=i.style),u)if(o){var f=this.style;if(this.style=this.createStyle(l?{}:f),l)for(var c=Gt(f),v=0;v<c.length;v++){var h=c[v];h in u&&(u[h]=u[h],this.style[h]=f[h])}for(var d=Gt(u),v=0;v<d.length;v++){var h=d[v];this.style[h]=this.style[h]}this._transitionState(r,{style:u},s,this.getAnimationStyleProps())}else this.useStyle(u);for(var p=this.__inHover?OE:am,v=0;v<p.length;v++){var h=p[v];n&&n[h]!=null?this[h]=n[h]:l&&i[h]!=null&&(this[h]=i[h])}},t.prototype._mergeStates=function(r){for(var n=e.prototype._mergeStates.call(this,r),i,a=0;a<r.length;a++){var o=r[a];o.style&&(i=i||{},this._mergeStyle(i,o.style))}return i&&(n.style=i),n},t.prototype._mergeStyle=function(r,n){return Y(r,n),r},t.prototype.getAnimationStyleProps=function(){return Vu},t.initDefaultProps=function(){var r=t.prototype;r.type="displayable",r.invisible=!1,r.z=0,r.z2=0,r.zlevel=0,r.culling=!1,r.cursor="pointer",r.rectHover=!1,r.incremental=!1,r._rect=null,r.dirty
Line truncated
|
||||
var uC=Object.defineProperty;var rg=Object.getOwnPropertySymbols;var fC=Object.prototype.hasOwnProperty,cC=Object.prototype.propertyIsEnumerable;var Zi=(t,e)=>(e=Symbol[t])?e:Symbol.for("Symbol."+t),hC=t=>{throw TypeError(t)};var ng=(t,e,r)=>e in t?uC(t,e,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[e]=r,Yn=(t,e)=>{for(var r in e||(e={}))fC.call(e,r)&&ng(t,r,e[r]);if(rg)for(var r of rg(e))cC.call(e,r)&&ng(t,r,e[r]);return t};var ur=(t,e,r)=>new Promise((n,i)=>{var a=l=>{try{s(r.next(l))}catch(u){i(u)}},o=l=>{try{s(r.throw(l))}catch(u){i(u)}},s=l=>l.done?n(l.value):Promise.resolve(l.value).then(a,o);s((r=r.apply(t,e)).next())}),$n=function(t,e){this[0]=t,this[1]=e},$f=(t,e,r)=>{var n=(s,l,u,f)=>{try{var c=r[s](l),v=(l=c.value)instanceof $n,h=c.done;Promise.resolve(v?l[0]:l).then(d=>v?n(s==="return"?s:"next",l[1]?{done:d.done,value:d.value}:d,u,f):u({value:d,done:h})).catch(d=>n("throw",d,u,f))}catch(d){f(d)}},i=(s,l,u,f)=>o[s]=c=>(l=new Promise((v,h,d)=>(d=()=>n(s,c,v,h),a?a.then(d):d())),f=()=>a===u&&(a=0),a=u=l.then(f,f),l),a,o={};return r=r.apply(t,e),o[Zi("asyncIterator")]=()=>o,i("next"),i("throw"),i("return"),o},Xf=t=>{var e=t[Zi("asyncIterator")],r=!1,n,i={};return e==null?(e=t[Zi("iterator")](),n=a=>i[a]=o=>e[a](o)):(e=e.call(t),n=a=>i[a]=o=>{if(r){if(r=!1,a==="throw")throw o;return o}return r=!0,{done:!1,value:new $n(new Promise(s=>{var l=e[a](o);l instanceof Object||hC("Object expected"),s(l)}),1)}}),i[Zi("iterator")]=()=>i,n("next"),"throw"in e?n("throw"):i.throw=a=>{throw a},"return"in e&&n("return"),i},ig=(t,e,r)=>(e=t[Zi("asyncIterator")])?e.call(t):(t=t[Zi("iterator")](),e={},r=(n,i)=>(i=t[n])&&(e[n]=a=>new Promise((o,s,l)=>(a=i.call(t,a),l=a.done,Promise.resolve(a.value).then(u=>o({value:u,done:l}),s)))),r("next"),r("return"),e);import{defineComponent as hd,ref as Pa,onMounted as vC,computed as Bt,getCurrentInstance as dC,h as eu,inject as yr,reactive as vd,watch as dd,effectScope as e1,markRaw as t1,hasInjectionContext as pC,isRef as tu,isReactive as r1,toRaw as gC,getCurrentScope as mC,onScopeDispose as yC,nextTick as n1,toRefs as _C,onUnmounted as SC,onDeactivated as bC,onActivated as wC,shallowRef as TC,unref as Mo,shallowReactive as xC,provide as qf}from"/luci-static/quickstart/card-runtime-v1.js";function i1(t,e){return function(){return t.apply(e,arguments)}}const{toString:CC}=Object.prototype,{getPrototypeOf:en}=Object,{iterator:us,toStringTag:a1}=Symbol,tn=(({hasOwnProperty:t})=>(e,r)=>t.call(e,r))(Object.prototype),o1=t=>typeof t=="string"&&(t==="__proto__"||t==="constructor"||t==="prototype"),ef=(t,e,r)=>t===Object.prototype||!r&&e===null,AC=t=>{if(!Object.isExtensible(t))return!1;const e=Object.getOwnPropertyNames(t);return Object.getOwnPropertySymbols&&e.push(...Object.getOwnPropertySymbols(t)),e.every(r=>{if(o1(r))return!1;const n=Object.getOwnPropertyDescriptor(t,r);return!!n&&n.configurable&&n.writable===!0})},pd=(t,e)=>{let r=t;const n=[];for(;r!=null;){if(n.indexOf(r)!==-1)return!1;n.push(r);const i=en(r);if(ef(r,i,r===t))return!1;if(tn(r,e))return!0;r=i}return!1},DC=(t,e)=>t!=null&&pd(t,e)?t[e]:void 0,EC=t=>{if(t==null||typeof t!="object"&&typeof t!="function")return t;const e=en(t);if(e===null&&AC(t))return t;const r=Object.create(null),n=Object.create(null),i=[];let a=t;for(;a!=null&&i.indexOf(a)===-1;){i.push(a);const o=a===t?e:en(a);if(ef(a,o,a===t))break;const s=Object.getOwnPropertyNames(a);Object.getOwnPropertySymbols&&s.push(...Object.getOwnPropertySymbols(a));for(const l of s)o1(l)||tn(n,l)||(r[l]=t[l],n[l]=!0);a=o}return r},gd=(t=>e=>{const r=CC.call(e);return t[r]||(t[r]=r.slice(8,-1).toLowerCase())})(Object.create(null)),ir=t=>(t=t.toLowerCase(),e=>gd(e)===t),tf=t=>e=>typeof e===t,{isArray:Ii}=Array,Li=tf("undefined");function Wa(t){return t!==null&&!Li(t)&&t.constructor!==null&&!Li(t.constructor)&&Rt(t.constructor.isBuffer)&&t.constructor.isBuffer(t)}const s1=ir("ArrayBuffer");function RC(t){let e;return typeof ArrayBuffer!="undefined"&&ArrayBuffer.isView?e=ArrayBuffer.isView(t):e=t&&t.buffer&&s1(t.buffer),e}const MC=tf("string"),Rt=tf("function"),PC=tf("number"),Ya=t=>t!==null&&typeof t=="object",IC=t=>t===!0||t===!1,Cl=t=>{if(!Ya(t))return!1;const e=en(t);return(e===null||e===Object.prototype||en(e)===null)&&(ef(t,e,!0)||!tn(t,a1)&&!tn(t,us))},LC=t=>{if(!Ya(t)||Wa(t))return!1;try{return Object.keys(t).length===0&&Object.getPrototypeOf(t)===Object.prototype}catch(e){return!1}},OC=ir("Date"),kC=ir("File"),NC=t=>!!(t&&typeof t.uri!="undefined"),BC=t=>t&&typeof t.getParts!="undefined",FC=ir("Blob"),zC=ir("FileList"),HC=ir("Set"),UC=t=>Ya(t)&&Rt(t.pipe);function VC(){return typeof globalThis!="undefined"?globalThis:typeof self!="undefined"?self:typeof window!="undefined"?window:typeof global!="undefined"?global:{}}const ag=VC(),og=typeof ag.FormData!="undefined"?ag.FormData:void 0,GC=t=>{if(!t)return!1;if(og&&t instanceof og)return!0;const e=en(t);if(!e||e===Object.prototype||!Rt(t.append))return!1;const r=gd(t);return r==="formdata"||r==="object"&&Rt(tLine truncated
|
||||
`).forEach(function(o){i=o.indexOf(":"),r=o.substring(0,i).trim().toLowerCase(),n=o.substring(i+1).trim();const s=E.hasOwnProp(e,r);!r||s&&E.hasOwnProp(SA,r)||(r==="set-cookie"?s?e[r].push(n):e[r]=[n]:e[r]=s?e[r]+", "+n:n)}),e};function wA(t){let e=0,r=t.length;for(;e<r;){const n=t.charCodeAt(e);if(n!==9&&n!==32)break;e+=1}for(;r>e;){const n=t.charCodeAt(r-1);if(n!==9&&n!==32)break;r-=1}return e===0&&r===t.length?t:t.slice(e,r)}const TA=new RegExp("[\\u0000-\\u0008\\u000a-\\u001f\\u007f]+","g"),xA=new RegExp("[^\\u0009\\u0020-\\u007e\\u0080-\\u00ff]+","g");function md(t,e){return E.isArray(t)?t.map(r=>md(r,e)):wA(String(t).replace(e,""))}const CA=t=>md(t,TA),AA=t=>md(t,xA);function h1(t){const e=Object.create(null);return E.forEach(t.toJSON(),(r,n)=>{e[n]=AA(r)}),e}const sg=Symbol("internals");function Za(t){return t&&String(t).trim().toLowerCase()}function Al(t){return t===!1||t==null?t:E.isArray(t)?t.map(Al):CA(String(t))}function DA(t){const e=Object.create(null),r=/([^\s,;=]+)\s*(?:=\s*([^,;]+))?/g;let n;for(;n=r.exec(t);)e[n[1]]=n[2];return e}const EA=/^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;function jf(t){let e=0,r=t.length;for(;e<r;){const n=t.charCodeAt(e);if(n!==9&&n!==32)break;e+=1}for(;r>e;){const n=t.charCodeAt(r-1);if(n!==9&&n!==32)break;r-=1}return e===0&&r===t.length?t:t.slice(e,r)}function RA(t){const e=t.length-1;if(e<1||t.charCodeAt(0)!==34||t.charCodeAt(e)!==34)return t;let r="";for(let n=1;n<e;n++){const i=t.charCodeAt(n);if(i===34||i===92&&(n+=1,n>=e))return t;r+=t[n]}return r}function MA(t){const e=Object.create(null),r=String(t);let n=0,i=!1,a=!1;function o(s){const l=jf(r.slice(n,s)),u=l.indexOf("=");if(u<1)return;const f=jf(l.slice(0,u));if(!EA.test(f))return;const c=f.toLowerCase();if(c==="__proto__"||c==="constructor"||c==="prototype")return;const v=jf(l.slice(u+1));e[c]=RA(v)}for(let s=0;s<r.length;s++){const l=r.charCodeAt(s);i?a?a=!1:l===92?a=!0:l===34&&(i=!1):l===34?i=!0:(l===44||l===59)&&(o(s),n=s+1)}return o(r.length),e}const PA=t=>/^[-_a-zA-Z0-9^`|~,!#$%&'*+.]+$/.test(t.trim()),IA="__Proto__",lg=t=>t==="__proto__"?IA:t;function Zf(t,e,r,n,i){if(E.isFunction(n))return n.call(t,e,r);if(i&&(e=r),!!E.isString(e)){if(E.isString(n))return e.indexOf(n)!==-1;if(E.isRegExp(n))return n.test(e)}}function LA(t){return t.trim().toLowerCase().replace(/([a-z\d])(\w*)/g,(e,r,n)=>r.toUpperCase()+n)}function OA(t,e){const r=E.toCamelCase(" "+e);["get","set","has"].forEach(n=>{Object.defineProperty(t,n+r,{__proto__:null,value:function(i,a,o){return this[n].call(this,e,i,a,o)},configurable:!0})})}let je=class{constructor(e){e&&this.set(e)}set(e,r,n){const i=this;function a(s,l,u){const f=Za(l);if(!f)return;const c=E.findKey(i,f);(!c||i[c]===void 0||u===!0||u===void 0&&i[c]!==!1)&&(i[lg(c||l)]=Al(s))}const o=(s,l)=>E.forEach(s,(u,f)=>a(u,f,l));if(E.isPlainObject(e)||e instanceof this.constructor)o(e,r);else if(E.isString(e)&&(e=e.trim())&&!PA(e))o(bA(e),r);else if(E.isObject(e)&&E.isSafeIterable(e)){let s=Object.create(null),l,u;for(const f of e){if(!E.isArray(f))throw new TypeError("Object iterator must return a key-value pair");u=f[0],E.hasOwnProp(s,u)?(l=s[u],s[u]=E.isArray(l)?[...l,f[1]]:[l,f[1]]):s[u]=f[1]}o(s,r)}else e!=null&&a(r,e,n);return this}get(e,r){if(e=Za(e),e){const n=E.findKey(this,e);if(n){const i=this[n];if(!r)return i;if(r===!0)return DA(i);if(E.isFunction(r))return r.call(this,i,n);if(E.isRegExp(r))return r.exec(i);throw new TypeError("parser must be boolean|regexp|function")}}}has(e,r){if(e=Za(e),e){const n=E.findKey(this,e);return!!(n&&this[n]!==void 0&&(!r||Zf(this,this[n],n,r)))}return!1}delete(e,r){const n=this;let i=!1;function a(o){if(o=Za(o),o){const s=E.findKey(n,o);s&&(!r||Zf(n,n[s],s,r))&&(delete n[s],i=!0)}}return E.isArray(e)?e.forEach(a):a(e),i}clear(e){const r=Object.keys(this);let n=r.length,i=!1;for(;n--;){const a=r[n];(!e||Zf(this,this[a],a,e,!0))&&(delete this[a],i=!0)}return i}normalize(e){const r=this,n=Object.create(null);return E.forEach(this,(i,a)=>{const o=E.findKey(n,a);if(o){r[o]=Al(i),delete r[a];return}const s=lg(e?LA(a):String(a).trim());s!==a&&delete r[a],r[s]=Al(i),n[s]=!0}),this}concat(...e){return this.constructor.concat(this,...e)}toJSON(e){const r=Object.create(null);return E.forEach(this,(n,i)=>{n!=null&&n!==!1&&(r[i]=e&&E.isArray(n)?n.join(", "):n)}),r}[Symbol.iterator](){return Object.entries(this.toJSON())[Symbol.iterator]()}toString(){return Object.entries(this.toJSON()).map(([e,r])=>e+": "+r).join(`
|
||||
`)}getSetCookie(){const e=this.get("set-cookie");return E.isArray(e)?e:e==null||e===!1?[]:[e]}get[Symbol.toStringTag](){return"AxiosHeaders"}static from(e){return e instanceof this?e:new this(e)}static parseParameters(e){return MA(e)}static concat(e,...r){const n=new this(e);return r.forEach(i=>n.set(i)),n}static accessor(e){const n=(this[sg]=this[sg]={accessors:{}}).accessors,i=this.prototype;function a(o){const s=Za(o);n[s]||(OA(i,o),n[s]=!0)}return E.isArray(e)?e.forEach(a):a(e),this}};je.accessor(["Content-Type","Content-Length","Accept","Accept-Encoding","User-Agent","Authorization"]);E.reduceDescriptors(je.prototype,({value:t},e)=>{let r=e[0].toUpperCase()+e.slice(1);return{get:()=>t,set(n){this[r]=n}}});E.freezeMethods(je);const ru="[REDACTED ****]";function kA(t){if(E.hasOwnProp(t,"toJSON"))return!0;let e=Object.getPrototypeOf(t);for(;e&&e!==Object.prototype;){if(E.hasOwnProp(e,"toJSON"))return!0;e=Object.getPrototypeOf(e)}return!1}function NA(t,e){const r=new Set(e.map(a=>String(a).toLowerCase())),n=[],i=a=>{if(a===null||typeof a!="object"||E.isBuffer(a))return a;if(n.indexOf(a)!==-1)return;a instanceof je&&(a=a.toJSON()),n.push(a);let o;if(E.isArray(a))o=[],a.forEach((s,l)=>{const u=i(s);E.isUndefined(u)||(o[l]=u)});else{if(!E.isPlainObject(a)&&kA(a))return n.pop(),a;o=Object.create(null);for(const[s,l]of Object.entries(a)){const u=r.has(s.toLowerCase())?ru:i(l);E.isUndefined(u)||(o[s]=u)}}return n.pop(),o};return i(t)}function ug(t){try{return String(t)}catch(e){return""}}function BA(t){return t.errors.map(r=>{try{return r&&r.message?ug(r.message):ug(r)}catch(n){return""}}).filter(Boolean).join("; ")||t.name||"AggregateError"}const FA=`
|
||||
Caused by: `,kh=Symbol("causeStack");function zA(t,e){const r=E.hasOwnProp(t,kh)&&t[kh];return r&&e.endsWith(r)?e.length-r.length:-1}function HA(t,e){try{const r=e&&e.stack;if(typeof r!="string"||!r)return;const n=t.stack;if(typeof n!="string"||!n)return;const i=FA+r;t.stack=n+i,Object.defineProperty(t,kh,{__proto__:null,value:i})}catch(r){}}let V=class v1 extends Error{static from(e,r,n,i,a,o){let s=e.message;!s&&E.isArray(e.errors)&&e.errors.length&&(s=BA(e));const l=new v1(s,r||e.code,n,i,a);return Object.defineProperty(l,"cause",{__proto__:null,value:e,writable:!0,enumerable:!1,configurable:!0}),l.name=e.name,HA(l,e),e.status!=null&&l.status==null&&(l.status=e.status),o&&Object.assign(l,o),l}constructor(e,r,n,i,a){super(e),Object.defineProperty(this,"message",{__proto__:null,value:e,enumerable:!0,writable:!0,configurable:!0}),this.name="AxiosError",this.isAxiosError=!0,r&&(this.code=r),n&&(this.config=n),i&&(this.request=i),a&&(this.response=a,this.status=a.status)}toJSON(){const e=this.config,r=e&&E.hasOwnProp(e,"redact")?e.redact:void 0,n=E.isArray(r)&&r.length>0?NA(e,r):E.toJSONObject(e);return{message:this.message,name:this.name,description:this.description,number:this.number,fileName:this.fileName,lineNumber:this.lineNumber,columnNumber:this.columnNumber,stack:this.stack,config:n,code:this.code,status:this.status}}};V.ERR_BAD_OPTION_VALUE="ERR_BAD_OPTION_VALUE";V.ERR_BAD_OPTION="ERR_BAD_OPTION";V.ECONNABORTED="ECONNABORTED";V.ETIMEDOUT="ETIMEDOUT";V.ECONNREFUSED="ECONNREFUSED";V.ERR_NETWORK="ERR_NETWORK";V.ERR_FR_TOO_MANY_REDIRECTS="ERR_FR_TOO_MANY_REDIRECTS";V.ERR_DEPRECATED="ERR_DEPRECATED";V.ERR_BAD_RESPONSE="ERR_BAD_RESPONSE";V.ERR_BAD_REQUEST="ERR_BAD_REQUEST";V.ERR_CANCELED="ERR_CANCELED";V.ERR_NOT_SUPPORT="ERR_NOT_SUPPORT";V.ERR_INVALID_URL="ERR_INVALID_URL";V.ERR_FORM_DATA_DEPTH_EXCEEDED="ERR_FORM_DATA_DEPTH_EXCEEDED";const UA=null,d1=100;function Nh(t){return E.isPlainObject(t)||E.isArray(t)}function p1(t){return E.endsWith(t,"[]")?t.slice(0,-2):t}function Kf(t,e,r){return t?t.concat(e).map(function(i,a){return i=p1(i),!r&&a?"["+i+"]":i}).join(r?".":""):e}function VA(t){return E.isArray(t)&&!t.some(Nh)}const GA=E.toFlatObject(E,{},null,function(e){return/^is[A-Z]/.test(e)});function rf(t,e,r){if(!E.isObject(t))throw new TypeError("target must be an object");e=e||new FormData;const n=(y,_)=>{const S=E.getSafeProp(r,y);return E.isUndefined(S)?_:S},i=n("metaTokens",!0),a=n("visitor")||p,o=n("dots",!1),s=n("indexes",!1),l=n("Blob")||typeof Blob!="undefined"&&Blob,u=n("maxDepth",d1),f=l&&E.isSpecCompliantForm(e),c=[];if(!E.isFunction(a))throw new TypeError("visitor must be a function");function v(y){if(y===null)return"";if(E.isDate(y))return y.toISOString();if(E.isBoolean(y))return y.toString();if(!f&&E.isBlob(y))throw new V("Blob is not supported. Use a Buffer instead.");if(E.isArrayBuffer(y)||E.isTypedArray(y)){if(f&&typeof l=="function")return new l([y]);throw new V("Blob is not supported. Use a Buffer instead.",V.ERR_NOT_SUPPORT)}return y}function h(y){if(y>u)throw new V("Object is too deeply nested ("+y+" levels). Max depth: "+u,V.ERR_FORM_DATA_DEPTH_EXCEEDED)}function d(y,_){if(u===1/0)return JSON.stringify(y);const S=[];return JSON.stringify(y,function(w,T){if(!E.isObject(T))return T;for(;S.length&&S[S.length-1]!==this;)S.pop();return S.push(T),h(_+S.length-1),T})}function p(y,_,S){let b=y;if(E.isReactNative(e)&&E.isReactNativeBlob(y))return e.append(Kf(S,_,o),v(y)),!1;if(y&&!S&&typeof y=="object"){if(E.endsWith(_,"{}"))_=i?_:_.slice(0,-2),y=d(y,1);else if(E.isArray(y)&&VA(y)||(E.isFileList(y)||E.endsWith(_,"[]"))&&(b=E.toArray(y)))return _=p1(_),b.forEach(function(T,C){!(E.isUndefined(T)||T===null)&&e.append(s===!0?Kf([_],C,o):s===null?_:_+"[]",v(T))}),!1}return Nh(y)?!0:(e.append(Kf(S,_,o),v(y)),!1)}const m=Object.assign(GA,{defaultVisitor:p,convertValue:v,isVisitable:Nh});function g(y,_,S=0){if(!E.isUndefined(y)){if(h(S),c.indexOf(y)!==-1)throw new Error("Circular reference detected in "+_.join("."));c.push(y),E.forEach(y,function(w,T){(!(E.isUndefined(w)||w===null)&&a.call(e,w,E.isString(T)?T.trim():T,_,m))===!0&&g(w,_?_.concat(T):[T],S+1)}),c.pop()}}if(!E.isObject(t))throw new TypeError("data must be an object");return g(t),e}function fg(t){const e={"!":"%21","'":"%27","(":"%28",")":"%29","~":"%7E","%20":"+"};return encodeURIComponent(t).replace(/[!'()~]|%20/g,function(n){return e[n]})}function yd(t,e){this._pairs=[],t&&rf(t,this,e)}const g1=yd.prototype;g1.append=function(e,r){this._pairs.push([e,r])};g1.toString=function(e){const r=e?n=>e.call(this,n,fg):fg;return this._pairs.map(function(i){return r(i[0])+"="+r(i[1])},"").join("&")};function WA(t){return encodeURIComponent(t).replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"+")}function m1(t,e,r){if(!e)return t;t=t||"";const n=E.isFunction(r)?{serialize:r}:r,i=E.getSafeProp(n,"encode")||WA,a=E.getSafeProp(n,"serialize");let o;if(a?o=a(e,n):o=E.isURLSearchParams(e)?e.toString():new yd(e,n).toString(i)
Line truncated
|
||||
`,wg=t=>String(t).replace(/\r\n|\r|\n/g,_n),Tg=t=>String(t).replace(/[\r\n"]/g,e=>e==="\r"?"%0D":e===`
|
||||
`?"%0A":"%22"),Ja=(t,e)=>{let r=0;for(let n=0;n<t.length;n++){const i=t.charCodeAt(n);e&&(i===13||i===10)?(i===13&&t.charCodeAt(n+1)===10&&n++,r+=2):i<128?r++:i<2048?r+=2:i>=55296&&i<=56319&&t.charCodeAt(n+1)>=56320&&t.charCodeAt(n+1)<=57343?(r+=4,n++):r+=3}return r};class Dl extends TypeError{constructor(e,r){super(e),this.name="FormDataError",this.reason=r}}function DD(t,e,r,n,i){if(!E.isFunction(e))throw new Dl("Blob is not supported","blob");if(!E.isString(i)||!/^[A-Za-z0-9'()+_,./:=? -]{1,70}$/.test(i)||/ $/.test(i))throw new Dl("Invalid multipart boundary","boundary");const a="--"+i+"--"+_n;let o=a.length;const s=[],l=f=>{if(o+f>r)throw n()};l(0);for(const[f,c]of t){const v=E.isString(c),h=v?Ja(c,!0):c.size;if(!Number.isFinite(h)||h<0)throw new Dl("Unsupported FormData part size","part");l(h+Ja(f,!0)+(!v&&c.name?Ja(c.name,!1):0)+(!v&&c.type?Ja(c.type,!1):0));let d="--"+i+_n+'Content-Disposition: form-data; name="'+Tg(wg(f))+'"';v||(d+='; filename="'+Tg(E.isString(c.name)?c.name:"blob")+'"'+_n+"Content-Type: "+String(c.type||"application/octet-stream").replace(/[\r\n]/g,"")),d+=_n+_n;const p=Ja(d,!1)+h+_n.length;l(p),o+=p,s.push({header:d,value:c,isString:v})}const u=[];for(const f of s)u.push(f.header,f.isString?wg(f.value):f.value,_n);return u.push(a),new e(u,{type:"multipart/form-data; boundary="+i})}function ED(t,e,r,n,i){if(!E.isFunction(e))throw new V("Blob is not supported",V.ERR_NOT_SUPPORT);if(i===void 0)if(E.isFunction(Ye.generateString))i="axios-"+Ye.generateString(36,"0123456789abcdef");else{const a=E.global.crypto;if(!a||!E.isFunction(a.getRandomValues))throw new V("Random byte generation is not supported",V.ERR_NOT_SUPPORT);const o=new Uint8Array(18);a.getRandomValues(o),i="axios-"+Array.from(o,s=>("0"+s.toString(16)).slice(-2)).join("")}try{return DD(t,e,r,n,i)}catch(a){if(a instanceof Dl){const o=a.reason==="boundary"?V.ERR_BAD_OPTION_VALUE:V.ERR_BAD_REQUEST;throw new V(a.message,o)}throw a}}const xg=t=>t>=48&&t<=57||t>=65&&t<=70||t>=97&&t<=102,P1=(t,e,r)=>e+2<r&&xg(t.charCodeAt(e+1))&&xg(t.charCodeAt(e+2)),Cg=t=>t<=57?t-48:(t&223)-55,RD=t=>t>=65&&t<=90||t>=97&&t<=122||t>=48&&t<=57||t===43||t===47||t===45||t===95,MD=t=>t===9||t===10||t===12||t===13||t===32,PD=t=>{const e=Math.floor(t/4),r=t%4;return e*3+(r===2?1:r===3?2:0)},ID=t=>{const e=t.length;let r=0;return e>0&&t.charCodeAt(e-1)===61&&(r++,e>1&&t.charCodeAt(e-2)===61&&r++),Math.floor((e-r)*3/4)},LD=t=>{const e=t.length;let r=0,n=0,i=!1;for(let a=0;a<e;a++){let o=t.charCodeAt(a);if(o===37&&P1(t,a,e)&&(o=Cg(t.charCodeAt(a+1))*16+Cg(t.charCodeAt(a+2)),a+=2),!MD(o)){if(o===61){n++;continue}if(!RD(o)||n>0){i=!0;continue}r++}}return i||n>2||n>0&&(r+n)%4!==0||r%4===1?ID(t):PD(r)},OD=(t,e,r)=>{if(!t||typeof t!="string"||!/^data:/i.test(t))return 0;const n=t.indexOf(",");if(n<0)return 0;const i=t.slice(5,n),a=t.slice(n+1);if(r.test(i))return e(a);let s=0;for(let l=0,u=a.length;l<u;l++){const f=a.charCodeAt(l);if(f===37&&P1(a,l,u))s+=1,l+=2;else if(f<128)s+=1;else if(f<2048)s+=2;else if(f>=55296&&f<=56319&&l+1<u){const c=a.charCodeAt(l+1);c>=56320&&c<=57343?(s+=4,l++):s+=3}else s+=3}return s};function kD(t){const e=typeof t=="string"?t.indexOf("#"):-1;return OD(e===-1?t:t.slice(0,e),LD,/; *base64[\t\n\f\r ]*$/i)}const bd="1.21.0",Ag=64*1024,Dg={cache:"default",redirect:"follow",referrer:"about:client",referrerPolicy:"",mode:"cors",integrity:"",keepalive:!1,priority:"auto",window:null},{isFunction:Ms}=E,ND=t=>encodeURIComponent(t).replace(/%([0-9A-F]{2})/gi,(e,r)=>String.fromCharCode(parseInt(r,16))),Eg=t=>{if(!E.isString(t))return t;try{return decodeURIComponent(t)}catch(e){return t}},Ps=(t,...e)=>{try{return!!t(...e)}catch(r){return!1}},BD=t=>{const e=t.indexOf("://");let r=t;return e!==-1&&(r=r.slice(e+3)),r.includes("@")||r.includes(":")},FD=t=>{const e=E.global!==void 0&&E.global!==null?E.global:globalThis,{ReadableStream:r,TextEncoder:n}=e;t=E.merge.call({skipUndefined:!0},{Request:e.Request,Response:e.Response,Blob:e.Blob},t);const i=E.hasOwnProp(t,"fetch")?t.fetch:void 0,{Request:a,Response:o,Blob:s}=t,l=i?Ms(i):typeof fetch=="function",u=Ms(a),f=Ms(o);if(!l)return!1;const c=l&&Ms(r),v=l&&(typeof n=="function"?(_=>S=>_.encode(S))(new n):_=>ur(null,null,function*(){return new Uint8Array(yield new a(_).arrayBuffer())})),h=u&&c&&Ps(()=>{let _=!1;const S=new a(Ye.origin,{body:new r,method:"POST",get duplex(){return _=!0,"half"}}),b=S.headers.has("Content-Type");return S.body!=null&&S.body.cancel(),_&&!b}),d=f&&c&&Ps(()=>E.isReadableStream(new o("").body)),p=Object.assign(Object.create(null),Dg);u&&!Ps(()=>new a(Ye.origin,p))&&(delete p.cache,Ps(()=>new a(Ye.origin,p))||(p.cache=Dg.cache));const m={stream:d&&(_=>_.body)};l&&["text","arrayBuffer","blob","formData","stream"].forEach(_=>{!m[_]&&(m[_]=(S,b)=>{let w=S&&S[_];if(w)return w.call(S);throw new V(`Response type '${_}' is not supported`,V.ERR_NOT_SUPPORT,b)})});const g=_=>ur(null,null,function*(){if(_==null)return 0;if(E.isBlob(_))return _.size;if(E.isArrayBufferView(_)||E.isArrayBu
Line truncated
|
||||
`+o.map(Rg).join(`
|
||||
`):" "+Rg(o[0]):"as no adapter specified";throw new V("There is no suitable adapter to dispatch the request "+s,V.ERR_NOT_SUPPORT)}return i}const L1={getAdapter:UD,adapters:wd};function tc(t){if(t.cancelToken&&t.cancelToken.throwIfRequested(),t.signal&&t.signal.aborted)throw new hs(null,t)}function Mg(t){return Math.max(0,Date.now()-t)}function rc(t){const e=E.toSafeFlatObject(t);tc(e),e.headers=je.from(E.getSafeProp(e,"headers")),e.data=Qf.call(e,e.transformRequest),["post","put","patch"].indexOf(e.method)!==-1&&e.headers.setContentType("application/x-www-form-urlencoded",!1);const r=L1.getAdapter(e.adapter||cs.adapter,e),n=Date.now();return r(e).then(function(a){tc(e),a.duration=Mg(n),e.response=a;try{a.data=Qf.call(e,e.transformResponse,a)}finally{delete e.response}return a.headers=je.from(a.headers),a},function(a){if(!x1(a)&&(tc(e),a&&a.response)){a.response.duration=Mg(n),e.response=a.response;try{a.response.data=Qf.call(e,e.transformResponse,a.response)}finally{delete e.response}a.response.headers=je.from(a.response.headers)}return Promise.reject(a)})}const nf={};["object","boolean","number","function","string","symbol"].forEach((t,e)=>{nf[t]=function(n){return typeof n===t||"a"+(e<1?"n ":" ")+t}});const Pg={};nf.transitional=function(e,r,n){function i(a,o){return"[Axios v"+bd+"] Transitional option '"+a+"'"+o+(n?". "+n:"")}return(a,o,s)=>{if(e===!1)throw new V(i(o," has been removed"+(r?" in "+r:"")),V.ERR_DEPRECATED);return r&&!Pg[o]&&(Pg[o]=!0,console.warn(i(o," has been deprecated since v"+r+" and will be removed in the near future"))),e?e(a,o,s):!0}};nf.spelling=function(e){return(r,n)=>(console.warn(`${n} is likely a misspelling of ${e}`),!0)};function VD(t,e,r){if(typeof t!="object"||t===null)throw new V("options must be an object",V.ERR_BAD_OPTION_VALUE);const n=Object.keys(t);let i=n.length;for(;i-- >0;){const a=n[i],o=Object.prototype.hasOwnProperty.call(e,a)?e[a]:void 0;if(o){const s=t[a],l=s===void 0||o(s,a,t);if(l!==!0)throw new V("option "+a+" must be "+l,V.ERR_BAD_OPTION_VALUE);continue}if(r!==!0)throw new V("Unknown option "+a,V.ERR_BAD_OPTION)}}const El={assertOptions:VD,validators:nf},Je=El.validators,nc=t=>{if(t==null||E.isPlainObject(t)||t instanceof je)return!0;try{return E.isObject(t)&&E.getSafeProp(t,Symbol.toStringTag)==="AxiosHeaders"&&["toJSON","set","get","has","delete","clear","normalize","concat","toString",Symbol.iterator].every(e=>E.isFunction(E.getSafeProp(t,e)))}catch(e){return!1}};let Ci=class{constructor(e){this.defaults=e||{},this.interceptors={request:new hg,response:new hg}}request(e,r){return ur(this,null,function*(){try{return yield this._request(e,r)}catch(n){if(n instanceof Error)try{let i={};Error.captureStackTrace?Error.captureStackTrace(i):i=new Error;const a=i.stack;let o="";if(typeof a=="string"){const s=a.indexOf(`
|
||||
`);o=s===-1?"":a.slice(s+1)}if(!n.stack)n.stack=o;else if(o){const s=o.indexOf(`
|
||||
`),l=s===-1?-1:o.indexOf(`
|
||||
`,s+1),u=l===-1?o:o.slice(l+1),f=String(n.stack),c=zA(n,f),v=c===-1?f:f.slice(0,c),h=c===-1?"":f.slice(c);v.endsWith(u)||(n.stack=v+`
|
||||
`+o+h)}}catch(i){}throw n}})}_request(e,r){typeof e=="string"?(r=r||{},r.url=e):r=e||{},r=Oi(this.defaults,r);const{transitional:n,paramsSerializer:i,headers:a}=r;n!==void 0&&El.assertOptions(n,{silentJSONParsing:Je.transitional(Je.boolean),forcedJSONParsing:Je.transitional(Je.boolean),clarifyTimeoutError:Je.transitional(Je.boolean),legacyInterceptorReqResOrdering:Je.transitional(Je.boolean),advertiseZstdAcceptEncoding:Je.transitional(Je.boolean),validateStatusUndefinedResolves:Je.transitional(Je.boolean),encodeBasicAuthUsername:Je.transitional(Je.boolean)},!1),i!=null&&(E.isFunction(i)?r.paramsSerializer={serialize:i}:El.assertOptions(i,{encode:Je.function,serialize:Je.function},!0)),r.allowAbsoluteUrls!==void 0||(E.hasOwnProp(this.defaults,"allowAbsoluteUrls")&&this.defaults.allowAbsoluteUrls!==void 0?r.allowAbsoluteUrls=this.defaults.allowAbsoluteUrls:r.allowAbsoluteUrls=!0),El.assertOptions(r,{baseUrl:Je.spelling("baseURL"),withXsrfToken:Je.spelling("withXSRFToken")},!0),r.method=(E.getSafeProp(r,"method")||E.getSafeProp(this.defaults,"method")||"get").toLowerCase();const o=E.getSafeProp(a,"common"),s=E.getSafeProp(a,r.method),l=a&&E.merge(nc(o)?o:void 0,nc(s)?s:void 0);a&&E.forEach(T1.concat("common"),m=>{nc(E.getSafeProp(a,m))&&delete a[m]}),r.headers=je.concat(l,a);const u=[];let f=!0;this.interceptors.request.forEach(function(g){if(typeof g.runWhen=="function"&&g.runWhen(r)===!1)return;f=f&&g.synchronous;const y=r.transitional||_d;y&&y.legacyInterceptorReqResOrdering?u.unshift(g.fulfilled,g.rejected):u.push(g.fulfilled,g.rejected)});const c=[];this.interceptors.response.forEach(function(g){c.push(g.fulfilled,g.rejected)});let v,h=0,d;if(!f){const m=[rc.bind(this),void 0];for(m.unshift(...u),m.push(...c),d=m.length,v=Promise.resolve(r);h<d;)v=v.then(m[h++],m[h++]);return v}d=u.length;let p=r;for(;h<d;){const m=u[h++],g=u[h++];try{p=m?m(p):p}catch(y){if(!g){v=Promise.reject(y);break}try{const _=g.call(this,y);E.isThenable(_)&&(v=Promise.resolve(_).then(()=>rc.call(this,p)))}catch(_){v=Promise.reject(_)}break}}if(!v)try{v=rc.call(this,p)}catch(m){v=Promise.reject(m)}for(h=0,d=c.length;h<d;)v=v.then(c[h++],c[h++]);return v}getUri(e){e=Oi(this.defaults,e);const r=E1(e.baseURL,e.url,e.allowAbsoluteUrls,e);return m1(r,e.params,e.paramsSerializer)}};E.forEach(["delete","get","head","options"],function(e){Ci.prototype[e]=function(r,n){return ur(this,null,function*(){return this.request(Oi(n||{},{method:e,url:r,data:n&&E.hasOwnProp(n,"data")?n.data:void 0}))})}});E.forEach(["post","put","patch","query"],function(e){function r(n){return function(a,o,s){return ur(this,null,function*(){return this.request(Oi(s||{},{method:e,headers:n?{"Content-Type":"multipart/form-data"}:{},url:a,data:o}))})}}Ci.prototype[e]=r(),e!=="query"&&(Ci.prototype[e+"Form"]=r(!0))});let GD=class O1{constructor(e){if(typeof e!="function")throw new TypeError("executor must be a function.");let r;this.promise=new Promise(function(a){r=a});const n=this;this.promise.then(i=>{if(!n._listeners)return;let a=n._listeners.length;for(;a-- >0;)n._listeners[a](i);n._listeners=null}),this.promise.then=i=>{let a;const o=new Promise(s=>{n.subscribe(s),a=s}).then(i);return o.cancel=function(){n.unsubscribe(a)},o},e(function(a,o,s){n.reason||(n.reason=new hs(a,o,s),r(n.reason))})}throwIfRequested(){if(this.reason)throw this.reason}subscribe(e){if(this.reason){e(this.reason);return}this._listeners?this._listeners.push(e):this._listeners=[e]}unsubscribe(e){if(!this._listeners)return;const r=this._listeners.indexOf(e);r!==-1&&this._listeners.splice(r,1)}toAbortSignal(){const e=new AbortController,r=n=>{e.abort(n)};return this.subscribe(r),e.signal.unsubscribe=()=>this.unsubscribe(r),e.signal}static source(){let e;return{token:new O1(function(i){e=i}),cancel:e}}};function WD(t){return function(r){return t.apply(null,r)}}function YD(t){return E.isObject(t)&&t.isAxiosError===!0}const Rl={Continue:100,SwitchingProtocols:101,Processing:102,EarlyHints:103,Ok:200,Created:201,Accepted:202,NonAuthoritativeInformation:203,NoContent:204,ResetContent:205,PartialContent:206,MultiStatus:207,AlreadyReported:208,ImUsed:226,MultipleChoices:300,MovedPermanently:301,Found:302,SeeOther:303,NotModified:304,UseProxy:305,Unused:306,TemporaryRedirect:307,PermanentRedirect:308,BadRequest:400,Unauthorized:401,PaymentRequired:402,Forbidden:403,NotFound:404,MethodNotAllowed:405,NotAcceptable:406,ProxyAuthenticationRequired:407,RequestTimeout:408,Conflict:409,Gone:410,LengthRequired:411,PreconditionFailed:412,PayloadTooLarge:413,ContentTooLarge:413,UriTooLong:414,UnsupportedMediaType:415,RangeNotSatisfiable:416,ExpectationFailed:417,ImATeapot:418,MisdirectedRequest:421,UnprocessableEntity:422,UnprocessableContent:422,Locked:423,FailedDependency:424,TooEarly:425,UpgradeRequired:426,PreconditionRequired:428,TooManyRequests:429,RequestHeaderFieldsTooLarge:431,UnavailableForLegalReasons:451,InternalServerError:500,NotImplemented:501,BadGateway:502,ServiceUnavailable:503,GatewayTimeout:504
Line truncated
|
||||
`),a=i.length;if(a===1)return Dm(i[0],e,r,n);for(var o=new le(0,0,0,0),s=0;s<i.length;s++){var l=Dm(i[s],e,r,n);s===0?o.copy(l):o.union(l)}return o}function Ba(t,e,r,n){return r==="right"?n?t+=e:t-=e:r==="center"&&(n?t+=e/2:t-=e/2),t}function Ei(t,e,r,n){return r==="middle"?n?t+=e/2:t-=e/2:r==="bottom"&&(n?t+=e:t-=e),t}function df(t){return Ir(t).stWideCharWidth}function ki(t,e){return typeof t=="string"?t.lastIndexOf("%")>=0?parseFloat(t)/100*e:parseFloat(t):t}function FS(t,e,r){var n=e.position||"inside",i=e.distance!=null?e.distance:5,a=r.height,o=r.width,s=a/2,l=r.x,u=r.y,f="left",c="top";if(n instanceof Array)l+=ki(n[0],r.width),u+=ki(n[1],r.height),f=null,c=null;else switch(n){case"left":l-=i,u+=s,f="right",c="middle";break;case"right":l+=i+o,u+=s,c="middle";break;case"top":l+=o/2,u-=i,f="center",c="bottom";break;case"bottom":l+=o/2,u+=a+i,f="center";break;case"inside":l+=o/2,u+=s,f="center",c="middle";break;case"insideLeft":l+=i,u+=s,c="middle";break;case"insideRight":l+=o-i,u+=s,f="right",c="middle";break;case"insideTop":l+=o/2,u+=i,f="center";break;case"insideBottom":l+=o/2,u+=a-i,f="center",c="bottom";break;case"insideTopLeft":l+=i,u+=i;break;case"insideTopRight":l+=o-i,u+=i,f="right";break;case"insideBottomLeft":l+=i,u+=a-i,c="bottom";break;case"insideBottomRight":l+=o-i,u+=a-i,f="right",c="bottom";break}return t=t||{},t.x=l,t.y=u,t.align=f,t.verticalAlign=c,t}var Ec="__zr_normal__",Rc=vf.concat(["ignore"]),GM=kr(vf,function(t,e){return t[e]=!0,t},{ignore:!1}),ra={},WM=new le(0,0,0,0),Hs=[],zl=0,pf=1,gf=(function(){function t(e){this.id=Md(),this.animators=[],this.currentStates=[],this.states={},this._init(e)}return t.prototype._init=function(e){this.attr(e)},t.prototype.drift=function(e,r,n){switch(this.draggable){case"horizontal":r=0;break;case"vertical":e=0;break}var i=this.transform;i||(i=this.transform=[1,0,0,1,0,0]),i[4]+=e,i[5]+=r,this.decomposeTransform(),this.markRedraw()},t.prototype.beforeUpdate=function(){},t.prototype.afterUpdate=function(){},t.prototype.update=function(){this.updateTransform(),this.__dirty&&this.updateInnerText()},t.prototype.updateInnerText=function(e){var r=this._textContent;if(r&&(!r.ignore||e)){this.textConfig||(this.textConfig={});var n=this.textConfig,i=n.local,a=r.innerTransformable,o=void 0,s=void 0,l=!1;a.parent=i?this:null;var u=!1;a.copyTransform(r);var f=n.position!=null,c=n.autoOverflowArea,v=void 0;if((c||f)&&(v=WM,n.layoutRect?v.copy(n.layoutRect):v.copy(this.getBoundingRect()),i||v.applyTransform(this.transform)),f){this.calculateTextPosition?this.calculateTextPosition(ra,n,v):FS(ra,n,v),a.x=ra.x,a.y=ra.y,o=ra.align,s=ra.verticalAlign;var h=n.origin;if(h&&n.rotation!=null){var d=void 0,p=void 0;h==="center"?(d=v.width*.5,p=v.height*.5):(d=ki(h[0],v.width),p=ki(h[1],v.height)),u=!0,a.originX=-a.x+d+(i?0:v.x),a.originY=-a.y+p+(i?0:v.y)}}n.rotation!=null&&(a.rotation=n.rotation);var m=n.offset;m&&(a.x+=m[0],a.y+=m[1],u||(a.originX=-m[0],a.originY=-m[1]));var g=this._innerTextDefaultStyle||(this._innerTextDefaultStyle={});if(c){var y=g.overflowRect=g.overflowRect||new le(0,0,0,0);a.getLocalTransform(Hs),Hn(Hs,Hs),le.copy(y,v),y.applyTransform(Hs)}else g.overflowRect=null;var _=n.inside==null?typeof n.position=="string"&&n.position.indexOf("inside")>=0:n.inside,S=void 0,b=void 0,w=void 0;_&&this.canBeInsideText()?(S=n.insideFill,b=n.insideStroke,(S==null||S==="auto")&&(S=this.getInsideTextFill()),(b==null||b==="auto")&&(b=this.getInsideTextStroke(S),w=!0)):(S=n.outsideFill,b=n.outsideStroke,(S==null||S==="auto")&&(S=this.getOutsideFill()),(b==null||b==="auto")&&(b=this.getOutsideStroke(S),w=!0)),S=S||"#000",(S!==g.fill||b!==g.stroke||w!==g.autoStroke||o!==g.align||s!==g.verticalAlign)&&(l=!0,g.fill=S,g.stroke=b,g.autoStroke=w,g.align=o,g.verticalAlign=s,r.setDefaultTextStyle(g)),r.__dirty|=Et,l&&r.dirtyStyle(!0)}},t.prototype.canBeInsideText=function(){return!0},t.prototype.getInsideTextFill=function(){return"#fff"},t.prototype.getInsideTextStroke=function(e){return"#000"},t.prototype.getOutsideFill=function(){return this.__zr&&this.__zr.isDarkMode()?hv:cv},t.prototype.getOutsideStroke=function(e){var r=this.__zr&&this.__zr.getBackgroundColor(),n=typeof r=="string"&&Ft(r);n||(n=[255,255,255,1]);for(var i=n[3],a=this.__zr.isDarkMode(),o=0;o<3;o++)n[o]=n[o]*i+(a?0:255)*(1-i);return n[3]=1,Un(n,"rgba")},t.prototype.traverse=function(e,r){},t.prototype.attrKV=function(e,r){e==="textConfig"?this.setTextConfig(r):e==="textContent"?this.setTextContent(r):e==="clipPath"?this.setClipPath(r):e==="extra"?(this.extra=this.extra||{},G(this.extra,r)):this[e]=r},t.prototype.hide=function(){this.ignore=!0,this.markRedraw()},t.prototype.show=function(){this.ignore=!1,this.markRedraw()},t.prototype.attr=function(e,r){if(typeof e=="string")this.attrKV(e,r);else if(ie(e))for(var n=e,i=Pe(n),a=0;a<i.length;a++){var o=i[a];this.attrKV(o,e[o])}return this.markRedraw(),this},t.prototype.saveCurrentToNormalState=function(e){this._innerSaveToNormal(e);for(var r=this._normalState,
Line truncated
|
||||
`);a=ab(r,n,i,a);for(var s=!1,l={},u=0,f=o.length;u<f;u++)ob(l,o[u],a),o[u]=l.textLine,s=s||l.isTruncated;t.text=o.join(`
|
||||
`),t.isTruncated=s}function ab(t,e,r,n){n=n||{};var i=G({},n);r=ne(r,"..."),i.maxIterations=ne(n.maxIterations,2);var a=i.minChar=ne(n.minChar,0),o=i.fontMeasureInfo=Ir(e),s=o.asciiCharWidth;i.placeholder=ne(n.placeholder,"");for(var l=t=Math.max(0,t-1),u=0;u<a&&l>=s;u++)l-=s;var f=Lr(o,r);return f>l&&(r="",f=0),l=t-f,i.ellipsis=r,i.ellipsisWidth=f,i.contentWidth=l,i.containerWidth=t,i}function ob(t,e,r){var n=r.containerWidth,i=r.contentWidth,a=r.fontMeasureInfo;if(!n){t.textLine="",t.isTruncated=!1;return}var o=Lr(a,e);if(o<=n){t.textLine=e,t.isTruncated=!1;return}for(var s=0;;s++){if(o<=i||s>=r.maxIterations){e+=r.ellipsis;break}var l=s===0?tI(e,i,a):o>0?Math.floor(e.length*i/o):0;e=e.substr(0,l),o=Lr(a,e)}e===""&&(e=r.placeholder),t.textLine=e,t.isTruncated=!0}function tI(t,e,r){for(var n=0,i=0,a=t.length;i<a&&n<e;i++)n+=NS(r,t.charCodeAt(i));return i}function rI(t,e,r,n){var i=$d(t),a=e.overflow,o=e.padding,s=o?o[1]+o[3]:0,l=o?o[0]+o[2]:0,u=e.font,f=a==="truncate",c=df(u),v=ne(e.lineHeight,c),h=e.lineOverflow==="truncate",d=!1,p=e.width;p==null&&r!=null&&(p=r-s);var m=e.height;m==null&&n!=null&&(m=n-l);var g;p!=null&&(a==="break"||a==="breakAll")?g=i?sb(i,e.font,p,a==="breakAll",0).lines:[]:g=i?i.split(`
|
||||
`):[];var y=g.length*v;if(m==null&&(m=y),y>m&&h){var _=Math.floor(m/v);d=d||g.length>_,g=g.slice(0,_),y=g.length*v}if(i&&f&&p!=null)for(var S=ab(p,u,e.ellipsis,{minChar:e.truncateMinChar,placeholder:e.placeholder}),b={},w=0;w<g.length;w++)ob(b,g[w],S),g[w]=b.textLine,d=d||b.isTruncated;for(var T=m,C=0,x=Ir(u),w=0;w<g.length;w++)C=Math.max(Lr(x,g[w]),C);p==null&&(p=C);var A=p;return T+=l,A+=s,{lines:g,height:m,outerWidth:A,outerHeight:T,lineHeight:v,calculatedLineHeight:c,contentWidth:C,contentHeight:y,width:p,isTruncated:d}}var nI=(function(){function t(){}return t})(),Nm=(function(){function t(e){this.tokens=[],e&&(this.tokens=e)}return t})(),iI=(function(){function t(){this.width=0,this.height=0,this.contentWidth=0,this.contentHeight=0,this.outerWidth=0,this.outerHeight=0,this.lines=[],this.isTruncated=!1}return t})();function aI(t,e,r,n,i){var a=new iI,o=$d(t);if(!o)return a;var s=e.padding,l=s?s[1]+s[3]:0,u=s?s[0]+s[2]:0,f=e.width;f==null&&r!=null&&(f=r-l);var c=e.height;c==null&&n!=null&&(c=n-u);for(var v=e.overflow,h=(v==="break"||v==="breakAll")&&f!=null?{width:f,accumWidth:0,breakAll:v==="breakAll"}:null,d=Lc.lastIndex=0,p;(p=Lc.exec(o))!=null;){var m=p.index;m>d&&Oc(a,o.substring(d,m),e,h),Oc(a,p[2],e,h,p[1]),d=Lc.lastIndex}d<o.length&&Oc(a,o.substring(d,o.length),e,h);var g=[],y=0,_=0,S=v==="truncate",b=e.lineOverflow==="truncate",w={};function T(se,L,Y){se.width=L,se.lineHeight=Y,y+=Y,_=Math.max(_,L)}e:for(var C=0;C<a.lines.length;C++){for(var x=a.lines[C],A=0,D=0,P=0;P<x.tokens.length;P++){var M=x.tokens[P],I=M.styleName&&e.rich[M.styleName]||{},k=M.textPadding=I.padding,O=k?k[1]+k[3]:0,N=M.font=I.font||e.font;M.contentHeight=df(N);var U=ne(I.height,M.contentHeight);if(M.innerHeight=U,k&&(U+=k[0]+k[2]),M.height=U,M.lineHeight=Mn(I.lineHeight,e.lineHeight,U),M.align=I&&I.align||i,M.verticalAlign=I&&I.verticalAlign||"middle",b&&c!=null&&y+M.lineHeight>c){var W=a.lines.length;P>0?(x.tokens=x.tokens.slice(0,P),T(x,D,A),a.lines=a.lines.slice(0,C+1)):a.lines=a.lines.slice(0,C),a.isTruncated=a.isTruncated||a.lines.length<W;break e}var X=I.width,Q=X==null||X==="auto";if(typeof X=="string"&&X.charAt(X.length-1)==="%")M.percentWidth=X,g.push(M),M.contentWidth=Lr(Ir(N),M.text);else{if(Q){var J=I.backgroundColor,j=J&&J.image;j&&(j=JP(j),Sf(j)&&(M.width=Math.max(M.width,j.width*U/j.height)))}var z=S&&f!=null?f-D:null;z!=null&&z<M.width?!Q||z<O?(M.text="",M.width=M.contentWidth=0):(ib(w,M.text,z-O,N,e.ellipsis,{minChar:e.truncateMinChar}),M.text=w.text,a.isTruncated=a.isTruncated||w.isTruncated,M.width=M.contentWidth=Lr(Ir(N),M.text)):M.contentWidth=Lr(Ir(N),M.text)}M.width+=O,D+=M.width,I&&(A=Math.max(A,M.lineHeight))}T(x,D,A)}a.outerWidth=a.width=ne(f,_),a.outerHeight=a.height=ne(c,y),a.contentHeight=y,a.contentWidth=_,a.outerWidth+=l,a.outerHeight+=u;for(var C=0;C<g.length;C++){var M=g[C],re=M.percentWidth;M.width=parseInt(re,10)/100*a.width}return a}function Oc(t,e,r,n,i){var a=e==="",o=i&&r.rich[i]||{},s=t.lines,l=o.font||r.font,u=!1,f,c;if(n){var v=o.padding,h=v?v[1]+v[3]:0;if(o.width!=null&&o.width!=="auto"){var d=ki(o.width,n.width)+h;s.length>0&&d+n.accumWidth>n.width&&(f=e.split(`
|
||||
`),u=!0),n.accumWidth=d}else{var p=sb(e,l,n.width,n.breakAll,n.accumWidth);n.accumWidth=p.accumWidth+h,c=p.linesWidths,f=p.lines}}f||(f=e.split(`
|
||||
`));for(var m=Ir(l),g=0;g<f.length;g++){var y=f[g],_=new nI;if(_.styleName=i,_.text=y,_.isLineHolder=!y&&!a,typeof o.width=="number"?_.width=o.width:_.width=c?c[g]:Lr(m,y),!g&&!u){var S=(s[s.length-1]||(s[0]=new Nm)).tokens,b=S.length;b===1&&S[0].isLineHolder?S[0]=_:(y||!b||a)&&S.push(_)}else s.push(new Nm([_]))}}function oI(t){var e=t.charCodeAt(0);return e>=32&&e<=591||e>=880&&e<=4351||e>=4608&&e<=5119||e>=7680&&e<=8303}var sI=kr(",&?/;] ".split(""),function(t,e){return t[e]=!0,t},{});function lI(t){return oI(t)?!!sI[t]:!0}function sb(t,e,r,n,i){for(var a=[],o=[],s="",l="",u=0,f=0,c=Ir(e),v=0;v<t.length;v++){var h=t.charAt(v);if(h===`
|
||||
`){l&&(s+=l,f+=u),a.push(s),o.push(f),s="",l="",u=0,f=0;continue}var d=NS(c,h.charCodeAt(0)),p=n?!1:!lI(h);if(a.length?f+d>r:i+f+d>r){f?(s||l)&&(p?(s||(s=l,l="",u=0,f=u),a.push(s),o.push(f-u),l+=h,u+=d,s="",f=u):(l&&(s+=l,l="",u=0),a.push(s),o.push(f),s=h,f=d)):p?(a.push(l),o.push(u),l=h,u=d):(a.push(h),o.push(d));continue}f+=d,p?(l+=h,u+=d):(l&&(s+=l,l="",u=0),s+=h)}return l&&(s+=l),s&&(a.push(s),o.push(f)),a.length===1&&(f+=i),{accumWidth:f,lines:a,linesWidths:o}}function Bm(t,e,r,n,i,a){if(t.baseX=r,t.baseY=n,t.outerWidth=t.outerHeight=null,!!e){var o=e.width*2,s=e.height*2;le.set(Fm,Ba(r,o,i),Ei(n,s,a),o,s),le.intersect(e,Fm,null,zm);var l=zm.outIntersectRect;t.outerWidth=l.width,t.outerHeight=l.height,t.baseX=Ba(l.x,l.width,i,!0),t.baseY=Ei(l.y,l.height,a,!0)}}var Fm=new le(0,0,0,0),zm={outIntersectRect:{},clamp:!0};function $d(t){return t!=null?t+="":t=""}function uI(t){var e=$d(t.text),r=t.font,n=Lr(Ir(r),e),i=df(r);return Sv(t,n,i,null)}function Sv(t,e,r,n){var i=new le(Ba(t.x||0,e,t.textAlign),Ei(t.y||0,r,t.textBaseline),e,r),a=n!=null?n:lb(t)?t.lineWidth:0;return a>0&&(i.x-=a/2,i.y-=a/2,i.width+=a,i.height+=a),i}function lb(t){var e=t.stroke;return e!=null&&e!=="none"&&t.lineWidth>0}var bv="__zr_style_"+Math.round(Math.random()*10),Ri={shadowBlur:0,shadowOffsetX:0,shadowOffsetY:0,shadowColor:"#000",opacity:1,blend:"source-over"},bf={style:{shadowBlur:!0,shadowOffsetX:!0,shadowOffsetY:!0,shadowColor:!0,opacity:!0}};Ri[bv]=!0;var Hm=["z","z2","invisible"],fI=["invisible"],Ss=(function(t){q(e,t);function e(r){return t.call(this,r)||this}return e.prototype._init=function(r){for(var n=Pe(r),i=0;i<n.length;i++){var a=n[i];a==="style"?this.useStyle(r[a]):t.prototype.attrKV.call(this,a,r[a])}this.style||this.useStyle({})},e.prototype.beforeBrush=function(r){},e.prototype.afterBrush=function(){},e.prototype.innerBeforeBrush=function(){},e.prototype.innerAfterBrush=function(){},e.prototype.shouldBePainted=function(r,n,i,a){var o=this.transform;if(this.ignore||this.invisible||this.style.opacity===0||this.culling&&cI(this,r,n)||o&&!o[0]&&!o[3])return!1;if(i&&this.__clipPaths&&this.__clipPaths.length){for(var s=0;s<this.__clipPaths.length;++s)if(this.__clipPaths[s].isZeroArea())return!1}if(a&&this.parent)for(var l=this.parent;l;){if(l.ignore)return!1;l=l.parent}return!0},e.prototype.contain=function(r,n){return this.rectContain(r,n)},e.prototype.traverse=function(r,n){r.call(n,this)},e.prototype.rectContain=function(r,n){var i=this.transformCoordToLocal(r,n),a=this.getBoundingRect();return a.contain(i[0],i[1])},e.prototype.getPaintRect=function(){var r=this._paintRect;if(!this._paintRect||this.__dirty){var n=this.transform,i=this.getBoundingRect(),a=this.style,o=a.shadowBlur||0,s=a.shadowOffsetX||0,l=a.shadowOffsetY||0;r=this._paintRect||(this._paintRect=new le(0,0,0,0)),n?le.applyTransform(r,i,n):r.copy(i),(o||s||l)&&(r.width+=o*2+Math.abs(s),r.height+=o*2+Math.abs(l),r.x=Math.min(r.x,r.x+s-o),r.y=Math.min(r.y,r.y+l-o));var u=this.dirtyRectTolerance;r.isZero()||(r.x=Math.floor(r.x-u),r.y=Math.floor(r.y-u),r.width=Math.ceil(r.width+1+u*2),r.height=Math.ceil(r.height+1+u*2))}return r},e.prototype.setPrevPaintRect=function(r){r?(this._prevPaintRect=this._prevPaintRect||new le(0,0,0,0),this._prevPaintRect.copy(r)):this._prevPaintRect=null},e.prototype.getPrevPaintRect=function(){return this._prevPaintRect},e.prototype.animateStyle=function(r){return this.animate("style",r)},e.prototype.updateDuringAnimation=function(r){r==="style"?this.dirtyStyle():this.markRedraw()},e.prototype.attrKV=function(r,n){r!=="style"?t.prototype.attrKV.call(this,r,n):this.style?this.setStyle(n):this.useStyle(n)},e.prototype.setStyle=function(r,n){return typeof r=="string"?this.style[r]=n:G(this.style,r),this.dirtyStyle(),this},e.prototype.dirtyStyle=function(r){r||this.markRedraw(),this.__dirty|=To,this._rect&&(this._rect=null)},e.prototype.dirty=function(){this.dirtyStyle()},e.prototype.styleChanged=function(){return!!(this.__dirty&To)},e.prototype.styleUpdated=function(){this.__dirty&=~To},e.prototype.createStyle=function(r){return ps(Ri,r)},e.prototype.useStyle=function(r){r[bv]||(r=this.createStyle(r)),this.style=r,this.dirtyStyle()},e.prototype._useHoverStyle=function(r){this.__hoverStyle=r},e.prototype.isStyleObject=function(r){return r[bv]},e.prototype._innerSaveToNormal=function(r){t.prototype._innerSaveToNormal.call(this,r);var n=this._normalState;r.style&&!n.style&&(n.style=this._mergeStyle(this.createStyle(),this.style)),this._savePrimaryToNormal(r,n,Hm)},e.prototype._applyStateObj=function(r,n,i,a,o,s){t.prototype._applyStateObj.call(this,r,n,i,a,o,s);var l=!(n&&a),u=this.__inHover===pf,f;if(n&&n.style?o?a?f=n.style:(f=this._mergeStyle(this.createStyle(),i.style),this._mergeStyle(f,n.style)):(f=this._mergeStyle(this.createStyle(),a?this.style:i.style),this._mergeStyle(f,n.style)):l&&(f=i.style),f)if(o){var c=this.style;if(this.style=this.createStyle(l?{}:c),l)for(var v=Pe(c),h=0;h<v.length;h++){var d=v[h];d in f&&(f[d]=f[d
Line truncated
|
||||
yyyy`);var n=ln(e),i=r?"getUTC":"get",a=n[i+"FullYear"](),o=n[i+"Month"]()+1,s=n[i+"Date"](),l=n[i+"Hours"](),u=n[i+"Minutes"](),f=n[i+"Seconds"](),c=n[i+"Milliseconds"]();return t=t.replace("MM",gt(o,2)).replace("M",o).replace("yyyy",a).replace("yy",gt(a%100+"",2)).replace("dd",gt(s,2)).replace("d",s).replace("hh",gt(l,2)).replace("h",l).replace("mm",gt(u,2)).replace("m",u).replace("ss",gt(f,2)).replace("s",f).replace("SSS",gt(c,3)),t}function R2(t){return t&&t.charAt(0).toUpperCase()+t.substr(1)}function Fi(t,e){return e=e||"transparent",te(t)?t:ie(t)&&t.colorStops&&(t.colorStops[0]||{}).color||e}function A0(t,e){if(e==="_blank"||e==="blank"){var r=window.open();r.opener=null,r.location.href=t}else window.open(t,e)}var Yl={},Jc={},Bf=(function(){function t(){this._normalMasterList=[],this._nonSeriesBoxMasterList=[]}return t.prototype.create=function(e,r){this._nonSeriesBoxMasterList=n(Yl),this._normalMasterList=n(Jc);function n(i,a){var o=[];return R(i,function(s,l){var u=s.create(e,r);o=o.concat(u||[])}),o}},t.prototype.update=function(e,r){R(this._normalMasterList,function(n){n.update&&n.update(e,r)})},t.prototype.getCoordinateSystems=function(){return this._normalMasterList.concat(this._nonSeriesBoxMasterList)},t.register=function(e,r){if(e==="matrix"||e==="calendar"){Yl[e]=r;return}Jc[e]=r},t.get=function(e){return Jc[e]||Yl[e]},t})();function M2(t){return!!Yl[t]}var P2=1,pw=2;function I2(t){gw.set(t.fullType,{getCoord2:void 0}).getCoord2=t.getCoord2}var gw=ce();function mw(t){var e=t.getShallow("coord",!0),r=P2;if(e==null){var n=gw.get(t.type);n&&n.getCoord2&&(r=pw,e=n.getCoord2(t))}return{coord:e,from:r}}var Ea=0,$l=1,L2=2;function O2(t,e){var r=t.getShallow("coordinateSystem"),n=t.getShallow("coordinateSystemUsage",!0),i=Ea;if(r){var a=t.mainType==="series";n==null&&(n=a?"data":"box"),n==="data"?(i=$l,a||(i=Ea)):n==="box"&&(i=L2,!a&&!M2(r)&&(i=Ea))}return{coordSysType:r,kind:i}}function k2(t){var e=t.targetModel,r=t.coordSysType,n=t.coordSysProvider,i=t.isDefaultDataCoordSys,a=O2(e),o=a.kind,s=a.coordSysType;if(i&&o!==$l&&(o=$l,s=r),o===Ea||s!==r)return Ea;var l=n(r,e);return l?(o===$l?e.coordinateSystem=l:e.boxCoordinateSystem=l,o):Ea}var Xl=R,N2=["left","right","top","bottom","width","height"],Qs=[["width","left","right"],["height","top","bottom"]];function bp(t,e,r,n,i){var a=0,o=0;n==null&&(n=1/0),i==null&&(i=1/0);var s=0;e.eachChild(function(l,u){var f=l.getBoundingRect(),c=e.childAt(u+1),v=c&&c.getBoundingRect(),h,d;if(t==="horizontal"){var p=f.width+(v?-v.x+f.x:0);h=a+p,h>n||l.newline?(a=0,h=p,o+=s+r,s=f.height):s=Math.max(s,f.height)}else{var m=f.height+(v?-v.y+f.y:0);d=o+m,d>i||l.newline?(a+=s+r,o=0,d=m,s=f.width):s=Math.max(s,f.width)}l.newline||(l.x=a,l.y=o,l.markRedraw(),t==="horizontal"?a=h+r:o=d+r)})}var zo=bp;Ue(bp,"vertical");Ue(bp,"horizontal");function B2(t,e){return{left:t.getShallow("left",e),top:t.getShallow("top",e),right:t.getShallow("right",e),bottom:t.getShallow("bottom",e),width:t.getShallow("width",e),height:t.getShallow("height",e)}}function F2(t,e){var r=Ff(t,e,{enableLayoutOnlyByCenter:!0}),n=t.getBoxLayoutParams(),i,a;if(r.type===Do.point)a=r.refPoint,i=sn(n,{width:e.getWidth(),height:e.getHeight()});else{var o=t.get("center"),s=K(o)?o:[o,o];i=sn(n,r.refContainer),a=r.boxCoordFrom===pw?r.refPoint:[He(s[0],i.width)+i.x,He(s[1],i.height)+i.y]}return{viewRect:i,center:a}}function z2(t,e){var r=F2(t,e),n=r.viewRect,i=r.center,a=t.get("radius");K(a)||(a=[0,a]);var o=He(n.width,e.getWidth()),s=He(n.height,e.getHeight()),l=Math.min(o,s),u=He(a[0],l/2),f=He(a[1],l/2);return{cx:i[0],cy:i[1],r0:u,r:f,viewRect:n}}function sn(t,e,r){r=Cs(r||0);var n=e.width,i=e.height,a=He(t.left,n),o=He(t.top,i),s=He(t.right,n),l=He(t.bottom,i),u=He(t.width,n),f=He(t.height,i),c=r[2]+r[0],v=r[1]+r[3],h=t.aspect;switch(isNaN(u)&&(u=n-s-v-a),isNaN(f)&&(f=i-l-c-o),h!=null&&(isNaN(u)&&isNaN(f)&&(h>n/i?u=n*.8:f=i*.8),isNaN(u)&&(u=h*f),isNaN(f)&&(f=u/h)),isNaN(a)&&(a=n-s-u-v),isNaN(o)&&(o=i-l-f-c),t.left||t.right){case"center":a=n/2-u/2-r[3];break;case"right":a=n-u-v;break}switch(t.top||t.bottom){case"middle":case"center":o=i/2-f/2-r[0];break;case"bottom":o=i-f-c;break}a=a||0,o=o||0,isNaN(u)&&(u=n-v-a-(s||0)),isNaN(f)&&(f=i-c-o-(l||0));var d=new le((e.x||0)+a+r[3],(e.y||0)+o+r[0],u,f);return d.margin=r,d}var Do={rect:1,point:2};function Ff(t,e,r){var n,i,a,o=t.boxCoordinateSystem,s;if(o){var l=mw(t),u=l.coord,f=l.from;if(o.dataToLayout){a=Do.rect,s=f;var c=o.dataToLayout(u);n=c.contentRect||c.rect}else r&&r.enableLayoutOnlyByCenter&&o.dataToPoint&&(a=Do.point,s=f,i=o.dataToPoint(u))}return a==null&&(a=Do.rect),a===Do.rect&&(n||(n={x:0,y:0,width:e.getWidth(),height:e.getHeight()}),i=[n.x+n.width/2,n.y+n.height/2]),{type:a,refContainer:n,refPoint:i,boxCoordFrom:s}}function ts(t){var e=t.layoutMode||t.constructor.layoutMode;return ie(e)?e:e?{type:e}:null}function zn(t,e,r){var n=r&&r.ignoreSize;!K(n)&&(n=[n,n]);var i=o(Qs[0],0),a=o(Qs[1],1);l(Qs[0],t,i),l(Qs[1],t,a);function o(u,f){var c={},v=0,h={},d=0
Line truncated
|
||||
`,`
|
||||
|
||||
`,`
|
||||
|
||||
|
||||
`];function os(e,t){return t.type=e,t}function Kh(e){return e.type==="section"}function Jb(e){return Kh(e)?vO:dO}function tS(e){if(Kh(e)){var t=0,r=e.blocks.length,n=r>1||r>0&&!e.noHeader;return I(e.blocks,function(i){var a=tS(i);a>=t&&(t=a+ +(n&&(!a||Kh(i)&&!i.noHeader)))}),t}return 0}function vO(e,t,r,n){var i=t.noHeader,a=pO(tS(t)),o=[],s=t.blocks||[];Wr(!s||et(s)),s=s||[];var l=e.orderMode;if(t.sortBlocks&&l){s=s.slice();var u={valueAsc:"asc",valueDesc:"desc"};if(Ca(u,l)){var f=new ZR(u[l],null);s.sort(function(d,p){return f.evaluate(d.sortParam,p.sortParam)})}else l==="seriesDesc"&&s.reverse()}I(s,function(d,p){var g=t.valueFormatter,m=Jb(d)(g?Y(Y({},e),{valueFormatter:g}):e,d,p>0?a.html:0,n);m!=null&&o.push(m)});var c=e.renderMode==="richText"?o.join(a.richText):Zh(o.join(""),i?r:a.html);if(i)return c;var v=qh(t.header,"ordinal",e.useUTC),h=Qb(n,e.renderMode).nameStyle;return e.renderMode==="richText"?eS(e,v,h)+a.richText+c:Zh('<div style="'+h+";"+Zb+';">'+Ke(v)+"</div>"+c,r)}function dO(e,t,r,n){var i=e.renderMode,a=t.noName,o=t.noValue,s=!t.markerType,l=t.name,u=e.useUTC,f=t.valueFormatter||e.valueFormatter||function(w){return w=et(w)?w:[w],ct(w,function(S,b){return qh(S,et(h)?h[b]:h,u)})};if(!(a&&o)){var c=s?"":e.markupStyleCreator.makeTooltipMarker(t.markerType,t.markerColor||"#333",i),v=a?"":qh(l,"ordinal",u),h=t.valueType,d=o?[]:f(t.value),p=!s||!a,g=!s&&a,m=Qb(n,i),y=m.nameStyle,_=m.valueStyle;return i==="richText"?(s?"":c)+(a?"":eS(e,v,y))+(o?"":yO(e,d,p,g,_)):Zh((s?"":c)+(a?"":gO(v,!s,y))+(o?"":mO(d,p,g,_)),r)}}function yy(e,t,r,n,i,a){if(!!e){var o=Jb(e),s={useUTC:i,renderMode:r,orderMode:n,markupStyleCreator:t,valueFormatter:e.valueFormatter};return o(s,e,0,a)}}function pO(e){return{html:cO[e],richText:hO[e]}}function Zh(e,t){var r='<div style="clear:both"></div>',n="margin: "+t+"px 0 0";return'<div style="'+n+";"+Zb+';">'+e+r+"</div>"}function gO(e,t,r){var n=t?"margin-left:2px":"";return'<span style="'+r+";"+n+'">'+Ke(e)+"</span>"}function mO(e,t,r,n){var i=r?"10px":"20px",a=t?"float:right;margin-left:"+i:"";return e=et(e)?e:[e],'<span style="'+a+";"+n+'">'+ct(e,function(o){return Ke(o)}).join(" ")+"</span>"}function eS(e,t,r){return e.markupStyleCreator.wrapRichTextStyle(t,r)}function yO(e,t,r,n,i){var a=[i],o=n?10:20;return r&&a.push({padding:[0,0,0,o],align:"right"}),e.markupStyleCreator.wrapRichTextStyle(et(t)?t.join(" "):t,a)}function _O(e,t){var r=e.getData().getItemVisual(t,"style"),n=r[e.visualDrawType];return Ti(n)}function rS(e,t){var r=e.get("padding");return r!=null?r:t==="richText"?[8,10]:10}var mc=function(){function e(){this.richTextStyles={},this._nextStyleNameId=vw()}return e.prototype._generateStyleName=function(){return"__EC_aUTo_"+this._nextStyleNameId++},e.prototype.makeTooltipMarker=function(t,r,n){var i=n==="richText"?this._generateStyleName():null,a=aR({color:r,type:t,renderMode:n,markerId:i});return it(a)?a:(this.richTextStyles[i]=a.style,a.content)},e.prototype.wrapRichTextStyle=function(t,r){var n={};et(r)?I(r,function(a){return Y(n,a)}):Y(n,r);var i=this._generateStyleName();return this.richTextStyles[i]=n,"{"+i+"|"+t+"}"},e}();function wO(e){var t=e.series,r=e.dataIndex,n=e.multipleSeries,i=t.getData(),a=i.mapDimensionsAll("defaultedTooltip"),o=a.length,s=t.getRawValue(r),l=et(s),u=_O(t,r),f,c,v,h;if(o>1||l&&!o){var d=bO(s,t,r,a,u);f=d.inlineValues,c=d.inlineValueTypes,v=d.blocks,h=d.inlineValues[0]}else if(o){var p=i.getDimensionInfo(a[0]);h=f=Da(i,r,a[0]),c=p.type}else h=f=l?s[0]:s;var g=wd(t),m=g&&t.name||"",y=i.getName(r),_=n?m:y;return os("section",{header:m,noHeader:n||!g,sortParam:h,blocks:[os("nameValue",{markerType:"item",markerColor:u,name:_,noName:!Tr(_),value:f,valueType:c})].concat(v||[])})}function bO(e,t,r,n,i){var a=t.getData(),o=Ln(e,function(c,v,h){var d=a.getDimensionInfo(h);return c=c||d&&d.tooltip!==!1&&d.displayName!=null},!1),s=[],l=[],u=[];n.length?I(n,function(c){f(Da(a,r,c),c)}):I(e,f);function f(c,v){var h=a.getDimensionInfo(v);!h||h.otherDims.tooltip===!1||(o?u.push(os("nameValue",{markerType:"subItem",markerColor:i,name:h.displayName,value:c,valueType:h.type})):(s.push(c),l.push(h.type)))}return{inlineValues:s,inlineValueTypes:l,blocks:u}}var an=Qt();function tl(e,t){return e.getName(t)||e.getId(t)}var SO="__universalTransitionEnabled",sf=function(e){J(t,e);function t(){var r=e!==null&&e.apply(this,arguments)||this;return r._selectedDataIndicesMap={},r}return t.prototype.init=function(r,n,i){this.seriesIndex=this.componentIndex,this.dataTask=Bo({count:TO,reset:CO}),this.dataTask.context={model:this},this.mergeDefaultAndTheme(r,i);var a=an(this).sourceManager=new fO(this);a.prepareSource();var o=this.getInitialData(r,i);wy(o,this),this.dataTask.context.data=o,an(this).dataBeforeProcessed=o,_y(this),this._initSelectedMapFromData(o)},t.prototype.mergeDefaultAndTheme=function(r,n){var i=is(this),a=i?nf(r):{},o=this.subType;$t.hasClass(o)&&(o+="Series"),Dt(r,n.getTheme().get(this.subType)),Dt(r,this.getDefaultOption()),Oh(r
Line truncated
|
||||
`];function ns(t,e){return e.type=t,e}function Nv(t){return t.type==="section"}function zw(t){return Nv(t)?YO:$O}function Hw(t){if(Nv(t)){var e=0,r=t.blocks.length,n=r>1||r>0&&!t.noHeader;return R(t.blocks,function(i){var a=Hw(i);a>=e&&(e=a+ +(n&&(!a||Nv(i)&&!i.noHeader)))}),e}return 0}function YO(t,e,r,n){var i=e.noHeader,a=XO(Hw(e)),o=[],s=e.blocks||[];Nr(!s||K(s)),s=s||[];var l=t.orderMode;if(e.sortBlocks&&l){s=s.slice();var u={valueAsc:"asc",valueDesc:"desc"};if(Mt(u,l)){var f=new DO(u[l],null);s.sort(function(p,m){return f.evaluate(p.sortParam,m.sortParam)})}else l==="seriesDesc"&&s.reverse()}R(s,function(p,m){var g=e.valueFormatter,y=zw(p)(g?G(G({},t),{valueFormatter:g}):t,p,m>0?a.html:0,n);y!=null&&o.push(y)});var c=t.renderMode==="richText"?o.join(a.richText):Bv(n,o.join(""),i?r:a.html);if(i)return c;var v=Lv(e.header,"ordinal",t.useUTC),h=Fw(n,t.renderMode).nameStyle,d=Bw(n);return t.renderMode==="richText"?Uw(t,v,h)+a.richText+c:Bv(n,'<div style="'+h+";"+d+';">'+yt(v)+"</div>"+c,r)}function $O(t,e,r,n){var i=t.renderMode,a=e.noName,o=e.noValue,s=!e.markerType,l=e.name,u=t.useUTC,f=e.valueFormatter||t.valueFormatter||function(S){return S=K(S)?S:[S],oe(S,function(b,w){return Lv(b,K(h)?h[w]:h,u)})};if(!(a&&o)){var c=s?"":t.markupStyleCreator.makeTooltipMarker(e.markerType,e.markerColor||ae.color.secondary,i),v=a?"":Lv(l,"ordinal",u),h=e.valueType,d=o?[]:f(e.value,e.rawDataIndex),p=!s||!a,m=!s&&a,g=Fw(n,i),y=g.nameStyle,_=g.valueStyle;return i==="richText"?(s?"":c)+(a?"":Uw(t,v,y))+(o?"":ZO(t,d,p,m,_)):Bv(n,(s?"":c)+(a?"":qO(v,!s,y))+(o?"":jO(d,p,m,_)),r)}}function K0(t,e,r,n,i,a){if(t){var o=zw(t),s={useUTC:i,renderMode:r,orderMode:n,markupStyleCreator:e,valueFormatter:t.valueFormatter};return o(s,t,0,a)}}function XO(t){return{html:GO[t],richText:WO[t]}}function Bv(t,e,r){var n='<div style="clear:both"></div>',i="margin: "+r+"px 0 0",a=Bw(t);return'<div style="'+i+";"+a+';">'+e+n+"</div>"}function qO(t,e,r){var n=e?"margin-left:2px":"";return'<span style="'+r+";"+n+'">'+yt(t)+"</span>"}function jO(t,e,r,n){var i=r?"10px":"20px",a=e?"float:right;margin-left:"+i:"";return t=K(t)?t:[t],'<span style="'+a+";"+n+'">'+oe(t,function(o){return yt(o)}).join(" ")+"</span>"}function Uw(t,e,r){return t.markupStyleCreator.wrapRichTextStyle(e,r)}function ZO(t,e,r,n,i){var a=[i],o=n?10:20;return r&&a.push({padding:[0,0,0,o],align:"right"}),t.markupStyleCreator.wrapRichTextStyle(K(e)?e.join(" "):e,a)}function KO(t,e){var r=t.getData().getItemVisual(e,"style"),n=r[t.visualDrawType];return Fi(n)}function Vw(t,e){var r=t.get("padding");return r!=null?r:e==="richText"?[8,10]:10}var ih=(function(){function t(){this.richTextStyles={},this._nextStyleNameId=$S()}return t.prototype._generateStyleName=function(){return"__EC_aUTo_"+this._nextStyleNameId++},t.prototype.makeTooltipMarker=function(e,r,n){var i=n==="richText"?this._generateStyleName():null,a=dw({color:r,type:e,renderMode:n,markerId:i});return te(a)?a:(this.richTextStyles[i]=a.style,a.content)},t.prototype.wrapRichTextStyle=function(e,r){var n={};K(r)?R(r,function(a){return G(n,a)}):G(n,r);var i=this._generateStyleName();return this.richTextStyles[i]=n,"{"+i+"|"+e+"}"},t})();function QO(t){var e=t.series,r=t.dataIndex,n=t.multipleSeries,i=e.getData(),a=i.mapDimensionsAll("defaultedTooltip"),o=a.length,s=e.getRawValue(r),l=K(s),u=KO(e,r),f,c,v,h;if(o>1||l&&!o){var d=JO(s,e,r,a,u);f=d.inlineValues,c=d.inlineValueTypes,v=d.blocks,h=d.inlineValues[0]}else if(o){var p=i.getDimensionInfo(a[0]);h=f=Ha(i,r,a[0]),c=p.type}else h=f=l?s[0]:s;var m=Ud(e),g=m&&e.name||"",y=i.getName(r),_=n?g:y;return ns("section",{header:g,noHeader:n||!m,sortParam:h,blocks:[ns("nameValue",{markerType:"item",markerColor:u,name:_,noName:!dr(_),value:f,valueType:c,rawDataIndex:i.getRawIndex(r)})].concat(v||[])})}function JO(t,e,r,n,i){var a=e.getData(),o=kr(t,function(c,v,h){var d=a.getDimensionInfo(h);return c=c||d&&d.tooltip!==!1&&d.displayName!=null},!1),s=[],l=[],u=[];n.length?R(n,function(c){f(Ha(a,r,c),c)}):R(t,f);function f(c,v){var h=a.getDimensionInfo(v);!h||h.otherDims.tooltip===!1||(o?u.push(ns("nameValue",{markerType:"subItem",markerColor:i,name:h.displayName,value:c,valueType:h.type})):(s.push(c),l.push(h.type)))}return{inlineValues:s,inlineValueTypes:l,blocks:u}}var dn=we();function rl(t,e){return t.getName(e)||t.getId(e)}var ek="__universalTransitionEnabled",nr=(function(t){q(e,t);function e(){var r=t!==null&&t.apply(this,arguments)||this;return r._selectedDataIndicesMap={},r}return e.prototype.init=function(r,n,i){this.seriesIndex=this.componentIndex,this.dataTask=Ho({count:rk,reset:nk}),this.dataTask.context={model:this},this.mergeDefaultAndTheme(r,i);var a=dn(this).sourceManager=new Nw(this);a.prepareSource();var o=this.getInitialData(r,i);J0(o,this),this.dataTask.context.data=o,dn(this).dataBeforeProcessed=o,Q0(this),this._initSelectedMapFromData(o)},e.prototype.mergeDefaultAndTheme=function(r,n){var i=ts(this),a=i?As(r):{},o=this.subType;Se.hasClass(o)&&(o+="Series"
Line truncated
|
||||
|
||||
`:"<br/>",m=c.join(g);this._showOrMove(s,function(){this._updateContentNotChangedOnAxis(r,u)?this._updatePosition(s,h,o[0],o[1],this._tooltipContent,u):this._showTooltipContent(s,m,u,Math.random()+"",o[0],o[1],h,null,v)})},t.prototype._showSeriesItemTooltip=function(r,n,i){var a=this._ecModel,o=Nt(n),s=o.seriesIndex,l=a.getSeriesByIndex(s),u=o.dataModel||l,f=o.dataIndex,c=o.dataType,v=u.getData(c),h=this._renderMode,d=r.positionDefault,p=lo([v.getItemModel(f),u,l&&(l.coordinateSystem||{}).model],this._tooltipModel,d?{position:d}:null),g=p.get("trigger");if(!(g!=null&&g!=="item")){var m=u.getDataParams(f,c),y=new mc;m.marker=y.makeTooltipMarker("item",Ti(m.color),h);var _=vy(u.formatTooltip(f,!1,c)),w=p.get("order"),S=p.get("valueFormatter"),b=_.frag,x=b?yy(S?Y({valueFormatter:S},b):b,y,h,w,a.get("useUTC"),p.get("textStyle")):_.text,T="item_"+u.name+"_"+f;this._showOrMove(p,function(){this._showTooltipContent(p,x,m,T,r.offsetX,r.offsetY,r.position,r.target,y)}),i({type:"showTip",dataIndexInside:f,dataIndex:v.getRawIndex(f),seriesIndex:s,from:this.uid})}},t.prototype._showComponentItemTooltip=function(r,n,i){var a=Nt(n),o=a.tooltipConfig,s=o.option||{};if(it(s)){var l=s;s={content:l,formatter:l}}var u=[s],f=this._ecModel.getComponent(a.componentMainType,a.componentIndex);f&&u.push(f),u.push({formatter:s.content});var c=r.positionDefault,v=lo(u,this._tooltipModel,c?{position:c}:null),h=v.get("content"),d=Math.random()+"",p=new mc;this._showOrMove(v,function(){var g=xt(v.get("formatterParams")||{});this._showTooltipContent(v,h,g,d,r.offsetX,r.offsetY,r.position,n,p)}),i({type:"showTip",from:this.uid})},t.prototype._showTooltipContent=function(r,n,i,a,o,s,l,u,f){if(this._ticket="",!(!r.get("showContent")||!r.get("show"))){var c=this._tooltipContent;c.setEnterable(r.get("enterable"));var v=r.get("formatter");l=l||r.get("position");var h=n,d=this._getNearestPoint([o,s],i,r.get("trigger"),r.get("borderColor")),p=d.color;if(v)if(it(v)){var g=r.ecModel.get("useUTC"),m=et(i)?i[0]:i,y=m&&m.axisType&&m.axisType.indexOf("time")>=0;h=v,y&&(h=Zu(m.axisValue,h,g)),h=Ib(h,i,!0)}else if(mt(v)){var _=Ft(function(w,S){w===this._ticket&&(c.setContent(S,f,r,p,l),this._updatePosition(r,l,o,s,c,i,u))},this);this._ticket=a,h=v(i,a,_)}else h=v;c.setContent(h,f,r,p,l),c.show(r,p),this._updatePosition(r,l,o,s,c,i,u)}},t.prototype._getNearestPoint=function(r,n,i,a){if(i==="axis"||et(n))return{color:a||(this._renderMode==="html"?"#fff":"none")};if(!et(n))return{color:a||n.color||n.borderColor}},t.prototype._updatePosition=function(r,n,i,a,o,s,l){var u=this._api.getWidth(),f=this._api.getHeight();n=n||r.get("position");var c=o.getSize(),v=r.get("align"),h=r.get("verticalAlign"),d=l&&l.getBoundingRect().clone();if(l&&d.applyTransform(l.transform),mt(n)&&(n=n([i,a],s,o.el,d,{viewSize:[u,f],contentSize:c.slice()})),et(n))i=Vt(n[0],u),a=Vt(n[1],f);else if(st(n)){var p=n;p.width=c[0],p.height=c[1];var g=Ma(p,{width:u,height:f});i=g.x,a=g.y,v=null,h=null}else if(it(n)&&l){var m=p5(n,d,c,r.get("borderWidth"));i=m[0],a=m[1]}else{var m=v5(i,a,o,u,f,v?null:20,h?null:20);i=m[0],a=m[1]}if(v&&(i-=B0(v)?c[0]/2:v==="right"?c[0]:0),h&&(a-=B0(h)?c[1]/2:h==="bottom"?c[1]:0),xx(r)){var m=d5(i,a,o,u,f);i=m[0],a=m[1]}o.moveTo(i,a)},t.prototype._updateContentNotChangedOnAxis=function(r,n){var i=this._lastDataByCoordSys,a=this._cbParamsList,o=!!i&&i.length===r.length;return o&&I(i,function(s,l){var u=s.dataByAxis||[],f=r[l]||{},c=f.dataByAxis||[];o=o&&u.length===c.length,o&&I(u,function(v,h){var d=c[h]||{},p=v.seriesDataIndices||[],g=d.seriesDataIndices||[];o=o&&v.value===d.value&&v.axisType===d.axisType&&v.axisId===d.axisId&&p.length===g.length,o&&I(p,function(m,y){var _=g[y];o=o&&m.seriesIndex===_.seriesIndex&&m.dataIndex===_.dataIndex}),a&&I(v.seriesDataIndices,function(m){var y=m.seriesIndex,_=n[y],w=a[y];_&&w&&w.data!==_.data&&(o=!1)})})}),this._lastDataByCoordSys=r,this._cbParamsList=n,!!o},t.prototype._hide=function(r){this._lastDataByCoordSys=null,r({type:"hideTip",from:this.uid})},t.prototype.dispose=function(r,n){wt.node||!n.getDom()||(Jh(this,"_updatePosition"),this._tooltipContent.dispose(),dv("itemTooltip",n))},t.type="tooltip",t}(qr);function lo(e,t,r){var n=t.ecModel,i;r?(i=new ce(r,n,n),i=new ce(t.option,i,n)):i=t;for(var a=e.length-1;a>=0;a--){var o=e[a];o&&(o instanceof ce&&(o=o.get("tooltip",!0)),it(o)&&(o={formatter:o}),o&&(i=new ce(o,i,n)))}return i}function N0(e,t){return e.dispatchAction||Ft(t.dispatchAction,t)}function v5(e,t,r,n,i,a,o){var s=r.getSize(),l=s[0],u=s[1];return a!=null&&(e+l+a+2>n?e-=l+a:e+=a),o!=null&&(t+u+o>i?t-=u+o:t+=o),[e,t]}function d5(e,t,r,n,i){var a=r.getSize(),o=a[0],s=a[1];return e=Math.min(e+o,n)-o,t=Math.min(t+s,i)-s,e=Math.max(e,0),t=Math.max(t,0),[e,t]}function p5(e,t,r,n){var i=r[0],a=r[1],o=Math.ceil(Math.SQRT2*n)+8,s=0,l=0,u=t.width,f=t.height;switch(e){case"inside":s=t.x+u/2-i/2,l=t.y+f/2-a/2;break;case"top":s=t.x+u/2-i/2,l=t.y-a-o;break;case"bottom":s=t.x+u/2-i/2,l=t.y+f+o;break;case"left":s=t.x-i-o,l=t
Line truncated
|
||||
`)){var g=new vl;g.newline=!0,u.add(g);return}var m=i.getSeriesByName(p)[0];if(!f.get(p))if(m){var y=m.getData(),_=y.getVisual("legendLineStyle")||{},w=y.getVisual("legendIcon"),S=y.getVisual("style"),b=this._createItem(m,p,d,h,n,r,_,S,w,c);b.on("click",Qi(H0,p,null,a,v)).on("mouseover",Qi(mv,m.name,null,a,v)).on("mouseout",Qi(yv,m.name,null,a,v)),f.set(p,!0)}else i.eachRawSeries(function(x){if(!f.get(p)&&x.legendVisualProvider){var T=x.legendVisualProvider;if(!T.containName(p))return;var C=T.indexOfName(p),D=T.getItemVisual(C,"style"),P=T.getItemVisual(C,"legendIcon"),A=$r(D.fill);A&&A[3]===0&&(A[3]=.2,D=Y(Y({},D),{fill:zu(A,"rgba")}));var L=this._createItem(x,p,d,h,n,r,{},D,P,c);L.on("click",Qi(H0,null,p,a,v)).on("mouseover",Qi(mv,null,p,a,v)).on("mouseout",Qi(yv,null,p,a,v)),f.set(p,!0)}},this)},this),o&&this._createSelector(o,n,a,s,l)},t.prototype._createSelector=function(r,n,i,a,o){var s=this.getSelectorGroup();gv(r,function(u){var f=u.type,c=new he({style:{x:0,y:0,align:"center",verticalAlign:"middle"},onclick:function(){i.dispatchAction({type:f==="all"?"legendAllSelect":"legendInverseSelect"})}});s.add(c);var v=n.getModel("selectorLabel"),h=n.getModel(["emphasis","selectorLabel"]);Xu(c,{normal:v,emphasis:h},{defaultText:u.title}),$h(c)})},t.prototype._createItem=function(r,n,i,a,o,s,l,u,f,c){var v=r.visualDrawType,h=o.get("itemWidth"),d=o.get("itemHeight"),p=o.isSelected(n),g=a.get("symbolRotate"),m=a.get("symbolKeepAspect"),y=a.get("icon");f=y||f||"roundRect";var _=P5(f,a,l,u,v,p),w=new vl,S=a.getModel("textStyle");if(mt(r.getLegendIcon)&&(!y||y==="inherit"))w.add(r.getLegendIcon({itemWidth:h,itemHeight:d,icon:f,iconRotate:g,itemStyle:_.itemStyle,lineStyle:_.lineStyle,symbolKeepAspect:m}));else{var b=y==="inherit"&&r.getData().getVisual("symbol")?g==="inherit"?r.getData().getVisual("symbolRotate"):g:0;w.add(I5({itemWidth:h,itemHeight:d,icon:f,iconRotate:b,itemStyle:_.itemStyle,lineStyle:_.lineStyle,symbolKeepAspect:m}))}var x=s==="left"?h+5:-5,T=s,C=o.get("formatter"),D=n;it(C)&&C?D=C.replace("{name}",n!=null?n:""):mt(C)&&(D=C(n));var P=a.get("inactiveColor");w.add(new he({style:kn(S,{text:D,x,y:d/2,fill:p?S.getTextColor():P,align:T,verticalAlign:"middle"})}));var A=new ne({shape:w.getBoundingRect(),invisible:!0}),L=a.getModel("tooltip");return L.get("show")&&Rd({el:A,componentModel:o,itemName:n,itemTooltipOption:L.option}),w.add(A),w.eachChild(function(O){O.silent=!0}),A.silent=!c,this.getContentGroup().add(w),$h(w),w.__legendDataIndex=i,w},t.prototype.layoutInner=function(r,n,i,a,o,s){var l=this.getContentGroup(),u=this.getSelectorGroup();No(r.get("orient"),l,r.get("itemGap"),i.width,i.height);var f=l.getBoundingRect(),c=[-f.x,-f.y];if(u.markRedraw(),l.markRedraw(),o){No("horizontal",u,r.get("selectorItemGap",!0));var v=u.getBoundingRect(),h=[-v.x,-v.y],d=r.get("selectorButtonGap",!0),p=r.getOrient().index,g=p===0?"width":"height",m=p===0?"height":"width",y=p===0?"y":"x";s==="end"?h[p]+=f[g]+d:c[p]+=v[g]+d,h[1-p]+=f[m]/2-v[m]/2,u.x=h[0],u.y=h[1],l.x=c[0],l.y=c[1];var _={x:0,y:0};return _[g]=f[g]+d+v[g],_[m]=Math.max(f[m],v[m]),_[y]=Math.min(0,v[y]+h[1-p]),_}else return l.x=c[0],l.y=c[1],this.group.getBoundingRect()},t.prototype.remove=function(){this.getContentGroup().removeAll(),this._isFirstRender=!0},t.type="legend.plain",t}(qr);function P5(e,t,r,n,i,a){function o(d,p){d.lineWidth==="auto"&&(d.lineWidth=p.lineWidth>0?2:0),gv(d,function(g,m){d[m]==="inherit"&&(d[m]=p[m])})}var s=t.getModel("itemStyle"),l=s.getItemStyle(),u=e.lastIndexOf("empty",0)===0?"fill":"stroke";l.decal=n.decal,l.fill==="inherit"&&(l.fill=n[i]),l.stroke==="inherit"&&(l.stroke=n[u]),l.opacity==="inherit"&&(l.opacity=(i==="fill"?n:r).opacity),o(l,n);var f=t.getModel("lineStyle"),c=f.getLineStyle();if(o(c,r),l.fill==="auto"&&(l.fill=n.fill),l.stroke==="auto"&&(l.stroke=n.fill),c.stroke==="auto"&&(c.stroke=n.fill),!a){var v=t.get("inactiveBorderWidth"),h=l[u];l.lineWidth=v==="auto"?n.lineWidth>0&&h?2:0:l.lineWidth,l.fill=t.get("inactiveColor"),l.stroke=t.get("inactiveBorderColor"),c.stroke=f.get("inactiveColor"),c.lineWidth=f.get("inactiveWidth")}return{itemStyle:l,lineStyle:c}}function I5(e){var t=e.icon||"roundRect",r=Ia(t,0,0,e.itemWidth,e.itemHeight,e.itemStyle.fill,e.symbolKeepAspect);return r.setStyle(e.itemStyle),r.rotation=(e.iconRotate||0)*Math.PI/180,r.setOrigin([e.itemWidth/2,e.itemHeight/2]),t.indexOf("empty")>-1&&(r.style.stroke=r.style.fill,r.style.fill="#fff",r.style.lineWidth=2),r}function H0(e,t,r,n){yv(e,t,r,n),r.dispatchAction({type:"legendToggleSelect",name:e!=null?e:t}),mv(e,t,r,n)}function Dx(e){for(var t=e.getZr().storage.getDisplayList(),r,n=0,i=t.length;n<i&&!(r=t[n].states.emphasis);)n++;return r&&r.hoverLayer}function mv(e,t,r,n){Dx(r)||r.dispatchAction({type:"highlight",seriesName:e,name:t,excludeSeriesId:n})}function yv(e,t,r,n){Dx(r)||r.dispatchAction({type:"downplay",seriesName:e,name:t,excludeSeriesId:n})}var Px=D5;function E5(e){var t=e.findComponents({mainType:"legend"});t&&t.length&&e.filterS
Line truncated
|
||||
`||u==="")){var f=o.isSelected(u);n.hasOwnProperty(u)?n[u]=n[u]&&f:n[u]=f}})}),e==="allSelect"||e==="inverseSelect"?{selected:n}:{name:t.name,selected:n}}function L5(e){e.registerAction("legendToggleSelect","legendselectchanged",Xt(uo,"toggleSelected")),e.registerAction("legendAllSelect","legendselectall",Xt(uo,"allSelect")),e.registerAction("legendInverseSelect","legendinverseselect",Xt(uo,"inverseSelect")),e.registerAction("legendSelect","legendselected",Xt(uo,"select")),e.registerAction("legendUnSelect","legendunselected",Xt(uo,"unSelect"))}function Ix(e){e.registerComponentModel(pv),e.registerComponentView(Px),e.registerProcessor(e.PRIORITY.PROCESSOR.SERIES_FILTER,E5),e.registerSubTypeDefaulter("legend",function(){return"plain"}),L5(e)}var R5=function(e){J(t,e);function t(){var r=e!==null&&e.apply(this,arguments)||this;return r.type=t.type,r}return t.prototype.setScrollDataIndex=function(r){this.option.scrollDataIndex=r},t.prototype.init=function(r,n,i){var a=nf(r);e.prototype.init.call(this,r,n,i),$0(this,r,a)},t.prototype.mergeOption=function(r,n){e.prototype.mergeOption.call(this,r,n),$0(this,this.option,r)},t.type="legend.scroll",t.defaultOption=q2(pv.defaultOption,{scrollDataIndex:0,pageButtonItemGap:5,pageButtonGap:null,pageButtonPosition:"end",pageFormatter:"{current}/{total}",pageIcons:{horizontal:["M0,0L12,-10L12,10z","M0,0L-12,-10L-12,10z"],vertical:["M0,0L20,0L10,-20z","M0,0L20,0L10,20z"]},pageIconColor:"#2f4554",pageIconInactiveColor:"#aaa",pageIconSize:15,pageTextStyle:{color:"#333"},animationDurationUpdate:800}),t}(pv);function $0(e,t,r){var n=e.getOrient(),i=[1,1];i[n.index]=0,Aa(t,r,{type:"box",ignoreSize:!!i})}var O5=R5,V0=ye,Nc=["width","height"],Bc=["x","y"],k5=function(e){J(t,e);function t(){var r=e!==null&&e.apply(this,arguments)||this;return r.type=t.type,r.newlineDisabled=!0,r._currentIndex=0,r}return t.prototype.init=function(){e.prototype.init.call(this),this.group.add(this._containerGroup=new V0),this._containerGroup.add(this.getContentGroup()),this.group.add(this._controllerGroup=new V0)},t.prototype.resetInner=function(){e.prototype.resetInner.call(this),this._controllerGroup.removeAll(),this._containerGroup.removeClipPath(),this._containerGroup.__rectSize=null},t.prototype.renderInner=function(r,n,i,a,o,s,l){var u=this;e.prototype.renderInner.call(this,r,n,i,a,o,s,l);var f=this._controllerGroup,c=n.get("pageIconSize",!0),v=et(c)?c:[c,c];d("pagePrev",0);var h=n.getModel("pageTextStyle");f.add(new he({name:"pageText",style:{text:"xx/xx",fill:h.getTextColor(),font:h.getFont(),verticalAlign:"middle",align:"center"},silent:!0})),d("pageNext",1);function d(p,g){var m=p+"DataIndex",y=Ld(n.get("pageIcons",!0)[n.getOrient().name][g],{onclick:Ft(u._pageGo,u,m,n,a)},{x:-v[0]/2,y:-v[1]/2,width:v[0],height:v[1]});y.name=p,f.add(y)}},t.prototype.layoutInner=function(r,n,i,a,o,s){var l=this.getSelectorGroup(),u=r.getOrient().index,f=Nc[u],c=Bc[u],v=Nc[1-u],h=Bc[1-u];o&&No("horizontal",l,r.get("selectorItemGap",!0));var d=r.get("selectorButtonGap",!0),p=l.getBoundingRect(),g=[-p.x,-p.y],m=xt(i);o&&(m[f]=i[f]-p[f]-d);var y=this._layoutContentAndController(r,a,m,u,f,v,h,c);if(o){if(s==="end")g[u]+=y[f]+d;else{var _=p[f]+d;g[u]-=_,y[c]-=_}y[f]+=p[f]+d,g[1-u]+=y[h]+y[v]/2-p[v]/2,y[v]=Math.max(y[v],p[v]),y[h]=Math.min(y[h],p[h]+g[1-u]),l.x=g[0],l.y=g[1],l.markRedraw()}return y},t.prototype._layoutContentAndController=function(r,n,i,a,o,s,l,u){var f=this.getContentGroup(),c=this._containerGroup,v=this._controllerGroup;No(r.get("orient"),f,r.get("itemGap"),a?i.width:null,a?null:i.height),No("horizontal",v,r.get("pageButtonItemGap",!0));var h=f.getBoundingRect(),d=v.getBoundingRect(),p=this._showController=h[o]>i[o],g=[-h.x,-h.y];n||(g[a]=f[u]);var m=[0,0],y=[-d.x,-d.y],_=Mt(r.get("pageButtonGap",!0),r.get("itemGap",!0));if(p){var w=r.get("pageButtonPosition",!0);w==="end"?y[a]+=i[o]-d[o]:m[a]+=d[o]+_}y[1-a]+=h[s]/2-d[s]/2,f.setPosition(g),c.setPosition(m),v.setPosition(y);var S={x:0,y:0};if(S[o]=p?i[o]:h[o],S[s]=Math.max(h[s],d[s]),S[l]=Math.min(0,d[l]+y[1-a]),c.__rectSize=i[o],p){var b={x:0,y:0};b[o]=Math.max(i[o]-d[o]-_,0),b[s]=S[s],c.setClipPath(new ne({shape:b})),c.__rectSize=b[o]}else v.eachChild(function(T){T.attr({invisible:!0,silent:!0})});var x=this._getPageInfo(r);return x.pageIndex!=null&&Dr(f,{x:x.contentPosition[0],y:x.contentPosition[1]},p?r:null),this._updatePageInfoView(r,x),S},t.prototype._pageGo=function(r,n,i){var a=this._getPageInfo(n)[r];a!=null&&i.dispatchAction({type:"legendScroll",scrollDataIndex:a,legendId:n.id})},t.prototype._updatePageInfoView=function(r,n){var i=this._controllerGroup;I(["pagePrev","pageNext"],function(f){var c=f+"DataIndex",v=n[c]!=null,h=i.childOfName(f);h&&(h.setStyle("fill",v?r.get("pageIconColor",!0):r.get("pageIconInactiveColor",!0)),h.cursor=v?"pointer":"default")});var a=i.childOfName("pageText"),o=r.get("pageFormatter"),s=n.pageIndex,l=s!=null?s+1:0,u=n.pageCount;a&&o&&a.setStyle("text",it(o)?o.replace("{current}",l==null?"":l+"").replace("{tot
Line truncated
|
||||
`:"<br/>",g=c.join(m);this._showOrMove(s,function(){this._updateContentNotChangedOnAxis(r,u)?this._updatePosition(s,h,o[0],o[1],this._tooltipContent,u):this._showTooltipContent(s,g,u,Math.random()+"",o[0],o[1],h,null,v)})},e.prototype._showSeriesItemTooltip=function(r,n,i){var a=this._ecModel,o=me(n),s=o.seriesIndex,l=a.getSeriesByIndex(s),u=o.dataModel||l,f=o.dataIndex,c=o.dataType,v=u.getData(c),h=this._renderMode,d=r.positionDefault,p=So([v.getItemModel(f),u,l&&(l.coordinateSystem||{}).model],this._tooltipModel,d?{position:d}:null),m=p.get("trigger");if(!(m!=null&&m!=="item")){var g=u.getDataParams(f,c),y=new ih;g.marker=y.makeTooltipMarker("item",Fi(g.color),h);var _=Y0(u.formatTooltip(f,!1,c)),S=p.get("order"),b=p.get("valueFormatter"),w=_.frag,T=w?K0(b?G({valueFormatter:b},w):w,y,h,S,a.get("useUTC"),p.get("textStyle")):_.text,C="item_"+u.name+"_"+f;this._showOrMove(p,function(){this._showTooltipContent(p,T,g,C,r.offsetX,r.offsetY,r.position,r.target,y)}),i({type:"showTip",dataIndexInside:f,dataIndex:v.getRawIndex(f),seriesIndex:s,from:this.uid})}},e.prototype._showComponentItemTooltip=function(r,n,i){var a=this._renderMode==="html",o=me(n),s=o.tooltipConfig,l=s.option||{},u=l.encodeHTMLContent;if(te(l)){var f=l;l={content:f,formatter:f},u=!0}u&&a&&l.content&&(l=de(l),l.content=yt(l.content));var c=[l],v=this._ecModel.getComponent(o.componentMainType,o.componentIndex);v&&c.push(v),c.push({formatter:l.content});var h=r.positionDefault,d=So(c,this._tooltipModel,h?{position:h}:null),p=d.get("content"),m=Math.random()+"",g=new ih;this._showOrMove(d,function(){var y=de(d.get("formatterParams")||{});this._showTooltipContent(d,p,y,m,r.offsetX,r.offsetY,r.position,n,g)}),i({type:"showTip",from:this.uid})},e.prototype._showTooltipContent=function(r,n,i,a,o,s,l,u,f){if(this._ticket="",!(!r.get("showContent")||!r.get("show"))){var c=this._tooltipContent;c.setEnterable(r.get("enterable"));var v=r.get("formatter");l=l||r.get("position");var h=n,d=this._getNearestPoint([o,s],i,r.get("trigger"),r.get("borderColor"),r.get("defaultBorderColor",!0)),p=d.color;if(v)if(te(v)){var m=r.ecModel.get("useUTC"),g=K(i)?i[0]:i,y=g&&g.axisType&&g.axisType.indexOf("time")>=0;h=v,y&&(h=xs(g.axisValue,h,m)),h=Sp(h,i,!0)}else if(fe(v)){var _=Ae(function(S,b){S===this._ticket&&(c.setContent(b,f,r,p,l),this._updatePosition(r,l,o,s,c,i,u))},this);this._ticket=a,h=v(i,a,_)}else h=v;c.setContent(h,f,r,p,l),c.show(r,p),this._updatePosition(r,l,o,s,c,i,u)}},e.prototype._getNearestPoint=function(r,n,i,a,o){if(i==="axis"||K(n))return{color:a||o};if(!K(n))return{color:a||n.color||n.borderColor}},e.prototype._updatePosition=function(r,n,i,a,o,s,l){var u=this._api.getWidth(),f=this._api.getHeight();n=n||r.get("position");var c=o.getSize(),v=r.get("align"),h=r.get("verticalAlign"),d=l&&l.getBoundingRect().clone();if(l&&d.applyTransform(l.transform),fe(n)&&(n=n([i,a],s,o.el,d,{viewSize:[u,f],contentSize:c.slice()})),K(n))i=He(n[0],u),a=He(n[1],f);else if(ie(n)){var p=n;p.width=c[0],p.height=c[1];var m=sn(p,{width:u,height:f});i=m.x,a=m.y,v=null,h=null}else if(te(n)&&l){var g=e3(n,d,c,r.get("borderWidth"));i=g[0],a=g[1]}else{var g=Qz(i,a,o,u,f,v?null:20,h?null:20);i=g[0],a=g[1]}if(v&&(i-=B_(v)?c[0]/2:v==="right"?c[0]:0),h&&(a-=B_(h)?c[1]/2:h==="bottom"?c[1]:0),Xx(r)){var g=Jz(i,a,o,u,f);i=g[0],a=g[1]}o.moveTo(i,a)},e.prototype._updateContentNotChangedOnAxis=function(r,n){var i=this._lastDataByCoordSys,a=this._cbParamsList,o=!!i&&i.length===r.length;return o&&R(i,function(s,l){var u=s.dataByAxis||[],f=r[l]||{},c=f.dataByAxis||[];o=o&&u.length===c.length,o&&R(u,function(v,h){var d=c[h]||{},p=v.seriesDataIndices||[],m=d.seriesDataIndices||[];o=o&&v.value===d.value&&v.axisType===d.axisType&&v.axisId===d.axisId&&p.length===m.length,o&&R(p,function(g,y){var _=m[y];o=o&&g.seriesIndex===_.seriesIndex&&g.dataIndex===_.dataIndex}),a&&R(v.seriesDataIndices,function(g){var y=g.seriesIndex,_=n[y],S=a[y];_&&S&&S.data!==_.data&&(o=!1)})})}),this._lastDataByCoordSys=r,this._cbParamsList=n,!!o},e.prototype._hide=function(r){this._lastDataByCoordSys=null,this._cbParamsList=null,r({type:"hideTip",from:this.uid})},e.prototype.dispose=function(r,n){ve.node||!n.getDom()||(zv(this,"_updatePosition"),this._tooltipContent.dispose(),od("itemTooltip",n),this._tooltipContent=null,this._tooltipModel=null,this._lastDataByCoordSys=null,this._cbParamsList=null)},e.type="tooltip",e})(Ct);function So(t,e,r){var n=e.ecModel,i;r?(i=new Le(r,n,n),i=new Le(e.option,i,n)):i=e;for(var a=t.length-1;a>=0;a--){var o=t[a];o&&(o instanceof Le&&(o=o.get("tooltip",!0)),te(o)&&(o={formatter:o}),o&&(i=new Le(o,i,n)))}return i}function N_(t,e){return t.dispatchAction||Ae(e.dispatchAction,e)}function Qz(t,e,r,n,i,a,o){var s=r.getSize(),l=s[0],u=s[1];return a!=null&&(t+l+a+2>n?t-=l+a:t+=a),o!=null&&(e+u+o>i?e-=u+o:e+=o),[t,e]}function Jz(t,e,r,n,i){var a=r.getSize(),o=a[0],s=a[1];return t=Math.min(t+o,n)-o,e=Math.min(e+s,i)-s,t=Math.max(t,0),e=Math.max(e,0),[t,e]}function e3(t,e,r,n){var i=r[0],a=r[
Line truncated
|
||||
`)){var y=new wl;y.newline=!0,u.add(y);return}var _=i.getSeriesByName(g)[0];if(!f.get(g))if(_){var S=_.getData(),b=S.getVisual("legendLineStyle")||{},w=S.getVisual("legendIcon"),T=S.getVisual("style"),C=this._createItem(_,g,p,d,n,r,b,T,w,c,a);C.on("click",da(U_,g,null,a,h)).on("mouseover",da(ud,_.name,null,a,h)).on("mouseout",da(fd,_.name,null,a,h)),i.ssr&&C.eachChild(function(x){var A=me(x);A.seriesIndex=_.seriesIndex,A.dataIndex=p,A.ssrType="legend"}),v&&C.eachChild(function(x){m.packEventData(x,n,_,p,g)}),f.set(g,!0)}else i.eachRawSeries(function(x){var A=this;if(!f.get(g)&&x.legendVisualProvider){var D=x.legendVisualProvider;if(!D.containName(g))return;var P=D.indexOfName(g),M=D.getItemVisual(P,"style"),I=D.getItemVisual(P,"legendIcon"),k=Ft(M.fill);k&&k[3]===0&&(k[3]=.2,M=G(G({},M),{fill:Un(k,"rgba")}));var O=this._createItem(x,g,p,d,n,r,{},M,I,c,a);O.on("click",da(U_,null,g,a,h)).on("mouseover",da(ud,null,g,a,h)).on("mouseout",da(fd,null,g,a,h)),i.ssr&&O.eachChild(function(N){var U=me(N);U.seriesIndex=x.seriesIndex,U.dataIndex=p,U.ssrType="legend"}),v&&O.eachChild(function(N){A.packEventData(N,n,x,p,g)}),f.set(g,!0)}},this)},this),o&&this._createSelector(o,n,a,s,l)},e.prototype.packEventData=function(r,n,i,a,o){var s={componentType:"legend",componentIndex:n.componentIndex,dataIndex:a,value:o,seriesIndex:i.seriesIndex};me(r).eventData=s},e.prototype._createSelector=function(r,n,i,a,o){var s=this.getSelectorGroup();ld(r,function(u){var f=u.type,c=new Ke({style:{x:0,y:0,align:"center",verticalAlign:"middle"},onclick:function(){i.dispatchAction({type:f==="all"?"legendAllSelect":"legendInverseSelect",legendId:n.id})}});s.add(c);var v=n.getModel("selectorLabel"),h=n.getModel(["emphasis","selectorLabel"]);Lf(c,{normal:v,emphasis:h},{defaultText:u.title}),Au(c)})},e.prototype._createItem=function(r,n,i,a,o,s,l,u,f,c,v){var h=r.visualDrawType,d=o.get("itemWidth"),p=o.get("itemHeight"),m=o.isSelected(n),g=a.get("symbolRotate"),y=a.get("symbolKeepAspect"),_=a.get("icon");f=_||f||"roundRect";var S=u3(f,a,l,u,h,m,v),b=new wl,w=a.getModel("textStyle");if(fe(r.getLegendIcon)&&(!_||_==="inherit"))b.add(r.getLegendIcon({itemWidth:d,itemHeight:p,icon:f,iconRotate:g,itemStyle:S.itemStyle,lineStyle:S.lineStyle,symbolKeepAspect:y}));else{var T=_==="inherit"&&r.getData().getVisual("symbol")?g==="inherit"?r.getData().getVisual("symbolRotate"):g:0;b.add(f3({itemWidth:d,itemHeight:p,icon:f,iconRotate:T,itemStyle:S.itemStyle,symbolKeepAspect:y}))}var C=s==="left"?d+5:-5,x=s,A=o.get("formatter"),D=n;te(A)&&A?D=A.replace("{name}",n!=null?n:""):fe(A)&&(D=A(n));var P=m?w.getTextColor():a.get("inactiveColor");b.add(new Ke({style:on(w,{text:D,x:C,y:p/2,fill:P,align:x,verticalAlign:"middle"},{inheritColor:P})}));var M=new Ge({shape:b.getBoundingRect(),style:{fill:"transparent"}}),I=a.getModel("tooltip");return I.get("show")&&Pf({el:M,componentModel:o,itemName:n,itemTooltipOption:I.option}),b.add(M),b.eachChild(function(k){k.silent=!0}),M.silent=!c,this.getContentGroup().add(b),Au(b),b.__legendDataIndex=i,b},e.prototype.layoutInner=function(r,n,i,a,o,s){var l=this.getContentGroup(),u=this.getSelectorGroup();zo(r.get("orient"),l,r.get("itemGap"),i.width,i.height);var f=l.getBoundingRect(),c=[-f.x,-f.y];if(u.markRedraw(),l.markRedraw(),o){zo("horizontal",u,r.get("selectorItemGap",!0));var v=u.getBoundingRect(),h=[-v.x,-v.y],d=r.get("selectorButtonGap",!0),p=r.getOrient().index,m=p===0?"width":"height",g=p===0?"height":"width",y=p===0?"y":"x";s==="end"?h[p]+=f[m]+d:c[p]+=v[m]+d,h[1-p]+=f[g]/2-v[g]/2,u.x=h[0],u.y=h[1],l.x=c[0],l.y=c[1];var _={x:0,y:0};return _[m]=f[m]+d+v[m],_[g]=Math.max(f[g],v[g]),_[y]=Math.min(0,v[y]+h[1-p]),_}else return l.x=c[0],l.y=c[1],this.group.getBoundingRect()},e.prototype.remove=function(){this.getContentGroup().removeAll(),this._isFirstRender=!0},e.type="legend.plain",e})(Ct);function u3(t,e,r,n,i,a,o){function s(m,g){m.lineWidth==="auto"&&(m.lineWidth=g.lineWidth>0?2:0),ld(m,function(y,_){m[_]==="inherit"&&(m[_]=g[_])})}var l=e.getModel("itemStyle"),u=l.getItemStyle(),f=t.lastIndexOf("empty",0)===0?"fill":"stroke",c=l.getShallow("decal");u.decal=!c||c==="inherit"?n.decal:Wv(c,o),u.fill==="inherit"&&(u.fill=n[i]),u.stroke==="inherit"&&(u.stroke=n[f]),u.opacity==="inherit"&&(u.opacity=(i==="fill"?n:r).opacity),s(u,n);var v=e.getModel("lineStyle"),h=v.getLineStyle();if(s(h,r),u.fill==="auto"&&(u.fill=n.fill),u.stroke==="auto"&&(u.stroke=n.fill),h.stroke==="auto"&&(h.stroke=n.fill),!a){var d=e.get("inactiveBorderWidth"),p=u[f];u.lineWidth=d==="auto"?n.lineWidth>0&&p?2:0:u.lineWidth,u.fill=e.get("inactiveColor"),u.stroke=e.get("inactiveBorderColor"),h.stroke=v.get("inactiveColor"),h.lineWidth=v.get("inactiveWidth")}return{itemStyle:u,lineStyle:h}}function f3(t){var e=t.icon||"roundRect",r=zi(e,0,0,t.itemWidth,t.itemHeight,t.itemStyle.fill,t.symbolKeepAspect);return r.setStyle(t.itemStyle),r.rotation=(t.iconRotate||0)*Math.PI/180,r.setOrigin([t.itemWidth/2,t.itemHeight/2]),e.indexOf("empty")>-1&&(r.style.stroke=r
Line truncated
|
||||
`||i==="")){var a=t.isSelected(i);Mt(r,i)?r[i]=r[i]&&a:r[i]=a}}),r}function c3(t){t.registerAction("legendToggleSelect","legendselectchanged",Ue(bo,"toggleSelected")),t.registerAction("legendAllSelect","legendselectall",Ue(bo,"allSelect")),t.registerAction("legendInverseSelect","legendinverseselect",Ue(bo,"inverseSelect")),t.registerAction("legendSelect","legendselected",Ue(bo,"select")),t.registerAction("legendUnSelect","legendunselected",Ue(bo,"unSelect"))}var h3=Wd(v3);function v3(t){var e=t.findComponents({mainType:"legend"});e&&e.length&&t.filterSeries(function(r){for(var n=0;n<e.length;n++)if(!e[n].isSelected(r.name))return!1;return!0})}function Jx(t){t.registerComponentModel(sd),t.registerComponentView(Qx),t.registerProcessor(t.PRIORITY.PROCESSOR.SERIES_FILTER,h3),t.registerSubTypeDefaulter("legend",function(){return"plain"}),c3(t)}var d3=(function(t){q(e,t);function e(){var r=t!==null&&t.apply(this,arguments)||this;return r.type=e.type,r}return e.prototype.setScrollDataIndex=function(r){this.option.scrollDataIndex=r},e.prototype.init=function(r,n,i){var a=As(r);t.prototype.init.call(this,r,n,i),G_(this,r,a)},e.prototype.mergeOption=function(r,n){t.prototype.mergeOption.call(this,r,n),G_(this,this.option,r)},e.type="legend.scroll",e.defaultOption=c2(sd.defaultOption,{scrollDataIndex:0,pageButtonItemGap:5,pageButtonGap:null,pageButtonPosition:"end",pageFormatter:"{current}/{total}",pageIcons:{horizontal:["M0,0L12,-10L12,10z","M0,0L-12,-10L-12,10z"],vertical:["M0,0L20,0L10,-20z","M0,0L20,0L10,20z"]},pageIconColor:ae.color.accent50,pageIconInactiveColor:ae.color.accent10,pageIconSize:15,pageTextStyle:{color:ae.color.tertiary},animationDurationUpdate:800}),e})(sd);function G_(t,e,r){var n=t.getOrient(),i=[1,1];i[n.index]=0,zn(e,r,{type:"box",ignoreSize:!!i})}var W_=rt,Mh=["width","height"],Ph=["x","y"],p3=(function(t){q(e,t);function e(){var r=t!==null&&t.apply(this,arguments)||this;return r.type=e.type,r.newlineDisabled=!0,r._currentIndex=0,r}return e.prototype.init=function(){t.prototype.init.call(this),this.group.add(this._containerGroup=new W_),this._containerGroup.add(this.getContentGroup()),this.group.add(this._controllerGroup=new W_)},e.prototype.resetInner=function(){t.prototype.resetInner.call(this),this._controllerGroup.removeAll(),this._containerGroup.removeClipPath(),this._containerGroup.__rectSize=null},e.prototype.renderInner=function(r,n,i,a,o,s,l){var u=this;t.prototype.renderInner.call(this,r,n,i,a,o,s,l);var f=this._controllerGroup,c=n.get("pageIconSize",!0),v=K(c)?c:[c,c];d("pagePrev",0);var h=n.getModel("pageTextStyle");f.add(new Ke({name:"pageText",style:{text:"xx/xx",fill:h.getTextColor(),font:h.getFont(),verticalAlign:"middle",align:"center"},silent:!0})),d("pageNext",1);function d(p,m){var g=p+"DataIndex",y=Mf(n.get("pageIcons",!0)[n.getOrient().name][m],{onclick:Ae(u._pageGo,u,g,n,a)},{x:-v[0]/2,y:-v[1]/2,width:v[0],height:v[1]});y.name=p,f.add(y)}},e.prototype.layoutInner=function(r,n,i,a,o,s){var l=this.getSelectorGroup(),u=r.getOrient().index,f=Mh[u],c=Ph[u],v=Mh[1-u],h=Ph[1-u];o&&zo("horizontal",l,r.get("selectorItemGap",!0));var d=r.get("selectorButtonGap",!0),p=l.getBoundingRect(),m=[-p.x,-p.y],g=de(i);o&&(g[f]=i[f]-p[f]-d);var y=this._layoutContentAndController(r,a,g,u,f,v,h,c);if(o){if(s==="end")m[u]+=y[f]+d;else{var _=p[f]+d;m[u]-=_,y[c]-=_}y[f]+=p[f]+d,m[1-u]+=y[h]+y[v]/2-p[v]/2,y[v]=Math.max(y[v],p[v]),y[h]=Math.min(y[h],p[h]+m[1-u]),l.x=m[0],l.y=m[1],l.markRedraw()}return y},e.prototype._layoutContentAndController=function(r,n,i,a,o,s,l,u){var f=this.getContentGroup(),c=this._containerGroup,v=this._controllerGroup;zo(r.get("orient"),f,r.get("itemGap"),a?i.width:null,a?null:i.height),zo("horizontal",v,r.get("pageButtonItemGap",!0));var h=f.getBoundingRect(),d=v.getBoundingRect(),p=this._showController=h[o]>i[o],m=[-h.x,-h.y];n||(m[a]=f[u]);var g=[0,0],y=[-d.x,-d.y],_=ne(r.get("pageButtonGap",!0),r.get("itemGap",!0));if(p){var S=r.get("pageButtonPosition",!0);S==="end"?y[a]+=i[o]-d[o]:g[a]+=d[o]+_}y[1-a]+=h[s]/2-d[s]/2,f.setPosition(m),c.setPosition(g),v.setPosition(y);var b={x:0,y:0};if(b[o]=p?i[o]:h[o],b[s]=Math.max(h[s],d[s]),b[l]=Math.min(0,d[l]+y[1-a]),c.__rectSize=i[o],p){var w={x:0,y:0};w[o]=Math.max(i[o]-d[o]-_,0),w[s]=b[s],c.setClipPath(new Ge({shape:w})),c.__rectSize=w[o]}else v.eachChild(function(C){C.attr({invisible:!0,silent:!0})});var T=this._getPageInfo(r);return T.pageIndex!=null&&Lt(f,{x:T.contentPosition[0],y:T.contentPosition[1]},p?r:null),this._updatePageInfoView(r,T),b},e.prototype._pageGo=function(r,n,i){var a=this._getPageInfo(n)[r];a!=null&&i.dispatchAction({type:"legendScroll",scrollDataIndex:a,legendId:n.id})},e.prototype._updatePageInfoView=function(r,n){var i=this._controllerGroup;R(["pagePrev","pageNext"],function(f){var c=f+"DataIndex",v=n[c]!=null,h=i.childOfName(f);h&&(h.setStyle("fill",v?r.get("pageIconColor",!0):r.get("pageIconInactiveColor",!0)),h.cursor=v?"pointer":"default")});var a=i.childOfName("pageText"),o=r.get("pageFormatter")
Line truncated
|
||||
@@ -2,6 +2,7 @@
|
||||
<%
|
||||
local jsonc = require "luci.jsonc"
|
||||
local uci = require "luci.model.uci".cursor()
|
||||
local asset_version = "0.17.1-rc20261028-release-6fb1035f6307"
|
||||
local features = { "_lua_force_array_" }
|
||||
local configs = {}
|
||||
if luci.sys.call("which ota >/dev/null 2>&1 && ota >/dev/null 2>&1") == 0 then
|
||||
@@ -30,13 +31,14 @@
|
||||
disable = true
|
||||
}
|
||||
end
|
||||
configs["deviceInventoryV2"] = uci:get("quickstart", "main", "device_inventory_v2") ~= "0"
|
||||
-%>
|
||||
<script>
|
||||
(function(){
|
||||
window.token = "<%=token%>";
|
||||
var vue_prefix="<%=prefix%>";
|
||||
window.vue_base = vue_prefix + '/';
|
||||
window.vue_lang_data = '/luci-static/quickstart/i18n/<%=lang%>.json<%# ?v=PKG_VERSION %>';
|
||||
window.vue_lang_data = '/luci-static/quickstart/i18n/<%=lang%>.json?v=<%=asset_version%>';
|
||||
window.vue_lang = '<%=lang%>';
|
||||
window.quickstart_features = <%=jsonc.stringify(features)%>;
|
||||
window.quickstart_configs = <%=jsonc.stringify(configs)%>;
|
||||
@@ -51,6 +53,6 @@
|
||||
</script>
|
||||
<div id="app">
|
||||
</div>
|
||||
<script type="module" crossorigin src="/luci-static/quickstart/index.js<%# ?v=PKG_VERSION %>"></script>
|
||||
<link rel="stylesheet" href="/luci-static/quickstart/style.css<%# ?v=PKG_VERSION %>">
|
||||
<script type="module" crossorigin src="/luci-static/quickstart/index.js?v=<%=asset_version%>"></script>
|
||||
<link rel="stylesheet" href="/luci-static/quickstart/style.css?v=<%=asset_version%>">
|
||||
<%+footer%>
|
||||
@@ -0,0 +1,18 @@
|
||||
Quickstart device-management release notice
|
||||
|
||||
The Quickstart backend and device-management web application are developed in
|
||||
the upstream Quickstart project under its MIT license. OpenWrt/LuCI packaging
|
||||
files retain the license notices stated in those files and packages.
|
||||
|
||||
The 30 WebP device scene icons shipped below
|
||||
/www/luci-static/quickstart/device-icons are project-original, AI-assisted
|
||||
generic illustrations generated with OpenAI's image generation tool on
|
||||
2026-09-24 and 2026-09-25. Generation required transparent backgrounds and no
|
||||
words, letters, logos, watermarks, trademarked elements, or brand-specific
|
||||
product silhouettes. Manufacturer names are rendered as ordinary text and are
|
||||
not embedded in the artwork. No artwork or logo from luci-app-oui,
|
||||
luci-app-bandix, a device manufacturer, or another third party is included.
|
||||
|
||||
The asset manifest marks product/legal review as required before a public
|
||||
release. Generative creation does not guarantee non-infringement.
|
||||
|
||||
@@ -219,7 +219,7 @@ const FS_PSTR_DEFAULT = 20;
|
||||
const PSTR = propAxis('fs-pattern-strength', 'pattern_strength', '--fs-pattern-strength', 0, 100, FS_PSTR_DEFAULT, (v) => String(v / 100));
|
||||
const PINK = enumAxis('fs-pattern-ink', 'data-pattern-ink', 'original', 'theme');
|
||||
|
||||
/* Transparency (issue #87): the cards and the menu as glass over a wallpaper, 100% = solid. The
|
||||
/* Transparency: the cards and the menu as glass over a wallpaper, 100% = solid. The
|
||||
* attribute that switches the glass on is derived, not stored: set below 100% unless the OS asks
|
||||
* for more contrast or forces colours, which a glass card cannot honour. Less transparency holds
|
||||
* back only an opacity that came from the router: Windows' "Transparency effects" switch reaches
|
||||
|
||||
@@ -111,7 +111,7 @@
|
||||
</a>
|
||||
{#
|
||||
The three chrome icons below are the same 24x24 outline differing only in path data;
|
||||
the stroke is `.fs-ico` in theme/20-shell.css, not attributes, and fs-widgets.js's
|
||||
the stroke is `.fs-ico` in theme/20-shell.css, not attributes, and fs-chrome.js's
|
||||
svgIcon() emits the same markup client-side. aria-hidden: each sits beside its own label.
|
||||
#}
|
||||
<button type="button" class="fs-railtoggle" id="fs-rail-toggle" aria-label="{{ _('Collapse menu') }}" title="{{ _('Collapse menu') }}">
|
||||
|
||||
@@ -264,7 +264,7 @@
|
||||
const solid = mq('(prefers-contrast: more)') || mq('(forced-colors: active)');
|
||||
const rt = mq('(prefers-reduced-transparency: reduce)');
|
||||
/* `p` written out, never built from `k`: mangle-tokens.sh renames only whole literals, so a
|
||||
built name set a property the sheet no longer reads (issue #89) */
|
||||
built name set a property the sheet no longer reads */
|
||||
const glass = (k, p, a) => {
|
||||
if (num(k, 0, 100, 100, p, '%') && !solid && !(rt && lsGet(k) === null)) attr(a, '');
|
||||
};
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=oxidns
|
||||
PKG_VERSION:=1.7.0
|
||||
PKG_VERSION:=1.7.1
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL:=https://github.com/svenshi/oxidns.git
|
||||
PKG_SOURCE_DATE:=2026-11-11
|
||||
PKG_SOURCE_VERSION:=a3dd95c0eebce51d3b11dc1a10b3fb5283f6228f
|
||||
PKG_SOURCE_DATE:=2026-11-12
|
||||
PKG_SOURCE_VERSION:=acc6155beec9c99bb77e3c792a681a84dcb7cb12
|
||||
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
|
||||
PKG_SOURCE:=$(PKG_SOURCE_SUBDIR).tar.zst
|
||||
PKG_MIRROR_HASH:=skip
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
! Issues: https://github.com/hagezi/dns-blocklists/issues
|
||||
! Disclaimer: https://github.com/hagezi/dns-blocklists/blob/main/README.md#disclaimer
|
||||
! Expires: 8 hours
|
||||
! Last modified: 10 Nov 2026 23:57 UTC
|
||||
! Version: 2026.1110.2357.37
|
||||
! Last modified: 11 Nov 2026 08:53 UTC
|
||||
! Version: 2026.1111.0853.51
|
||||
! Syntax: AdBlock
|
||||
! Number of entries: 3570
|
||||
! Number of entries: 3567
|
||||
!
|
||||
||ss.0001.xyz^
|
||||
||ns.00dani.me^
|
||||
@@ -174,9 +174,6 @@
|
||||
||dns.adguard.com^
|
||||
||dns-family.adguard.com^
|
||||
||dns-unfiltered.adguard.com^
|
||||
||dns.adguarddns.com^
|
||||
||family.adguarddns.com^
|
||||
||unfiltered.adguarddns.com^
|
||||
||dns.adnull.com^
|
||||
||dns.adrianlam.com^
|
||||
||adguard.adrianofrongillo.ovh^
|
||||
|
||||