diff --git a/README.md b/README.md index 2a1f917ac..d01f2b1a2 100755 --- a/README.md +++ b/README.md @@ -57,6 +57,7 @@ php artisan admin:install - 增强枚举(`BackedEnum`)字段的渲染支持 - 支持 `.5` 列宽,如 `col-sm-1.5` - 优化 HTTPS 站点的资源 URL 生成 +- **新增 URL 主键加密**:可对路由路径中的主键(如 `/admin/books/{id}/edit`)进行加密(默认 36 位 UUID 样式密文),防止直接暴露数据库主键;支持 `encrypt` / `cipher` / `cipher_salt` 配置与手动加解密 Helper,详见 [加密功能使用说明](docs/url-cipher-guide.md) ### Bug 修复 @@ -70,6 +71,18 @@ php artisan admin:install - [English documentation](http://www.dcatadmin.com/docs/en-2.x/quick-start.html) - [原项目 README(功能特性、扩展、鸣谢)](README.origin.md) +项目扩展能力专项说明: + +- [URL 主键加密功能使用说明](docs/url-cipher-guide.md) + +## 扩展包 + +| 扩展 | 描述 | dcat-admin 版本 | +| --- |----------------------------------------------|---------------| +| [zgy-dcat/wangeditor](https://github.com/gy23rm/dcat-wangeditor) | wangEditor 5 富文本编辑器表单字段 | dev-master | +| [zgy-dcat/distpicker](https://github.com/gy23rm/dcat-distpicker) | 省市区三级联动(super-eggs/dcat-distpicker 的维护 fork) |dev-master | +| [zgy-dcat/master-detail](https://github.com/gy23rm/dcat-master-detail) | 左树右表联动(Master-Detail)扩展 |dev-master | + ## 免责声明 本项目已通过测试并在实际生产环境中使用,但无法保证所有修改绝对无误,上线前请充分测试。 diff --git a/composer.json b/composer.json index 03ce78c7e..2f61cddcf 100755 --- a/composer.json +++ b/composer.json @@ -1,5 +1,5 @@ { - "name": "printnow/laravel-admin", + "name": "zgy-dcat/laravel-admin", "description": "Dcat admin 永久分叉版 / 支持 Laravel 10-13, PHP 版本限制 >= 8.1(支持 PHP 8.5)", "type": "library", "keywords": [ @@ -11,16 +11,12 @@ "laravel admin", "dcat admin" ], - "homepage": "https://github.com/PrintNow/dcat-admin", + "homepage": "https://github.com/gy23rm/dcat-admin", "license": "MIT", "authors": [ { - "name": "Shine", - "email": "i@nowtime.cc" - }, - { - "name": "jqh", - "email": "841324345@qq.com" + "name": "zgy", + "email": "gy23rm@163.com" } ], "require": { diff --git a/config/admin.php b/config/admin.php index d0471e3c0..2a8c7229b 100755 --- a/config/admin.php +++ b/config/admin.php @@ -74,6 +74,42 @@ 'middleware' => ['web', 'admin'], 'enable_session_middleware' => false, + + /* + |-------------------------------------------------------------------------- + | 主键加密 + |-------------------------------------------------------------------------- + | + | 开启后,Grid/Form 生成的路径参数中的记录主键会被加密 + | (如 /users/{id}/edit 中的 {id}),请求进入时由 admin.cipher + | 中间件自动解密,控制器拿到的永远是明文主键。 + | + | 仅加密主键;其它查询参数(过滤条件等)保持明文,不做处理。 + | + | encrypt: 是否启用 + | cipher : 加解密实现类,必须实现 \Dcat\Admin\Contracts\UrlCipher + | 当前默认 UuidCipher(AES 伪 UUID 版,密文为 36 位 UUID 格式; + | 仅支持正整数主键,范围 1 ~ 1099511627775(uint40); + | 作用域内嵌密文,从 cipher_salt 派生 AES 密钥) + | 可选 CryptCipher(配置盐混淆版;盐为空会报错) + | cipher_salt : 加解密盐(字符串),用于派生混淆字节流;必须有值,为空会抛异常 + | cipher_magic : UuidCipher 明文块第一字节魔数(默认 "\x02")。可配 int / 0x 十六进制 + | 字符串 / "\x01" 转义字符串,最终归一为单字节;加解密共用该值。 + | 注意:改动它会让旧密文无法解密(解密魔数也会变),如无必要请保持默认。 + | cipher_scopes : (历史兼容,可保留)作用域常量数组扩展,仅旧版 UuidCipher 强制校验 + | 注册用。当前实现不再强制校验作用域范围;作用域必须是 1~2 个可打印 + | ASCII 字符的短标签(如 gi / fo / bo),超长(如 book:grid.id)加密时报错。 + | 以下配置仅为历史兼容保留,可删除 + */ + 'encrypt' => env('ADMIN_ROUTE_ENCRYPT', false), + + 'cipher' => \Dcat\Admin\Support\UuidCipher::class, + + 'cipher_salt' => env('ADMIN_ROUTE_CIPHER_SALT', 'dcat_c'), + + 'cipher_magic' => "\x02", + + 'cipher_scopes' => [], ], /* diff --git a/docs/url-cipher-guide.md b/docs/url-cipher-guide.md new file mode 100644 index 000000000..d8095005a --- /dev/null +++ b/docs/url-cipher-guide.md @@ -0,0 +1,353 @@ +# dcat-admin 路由主键加密功能使用说明 + +> 适用于 `zgy-dcat/laravel-admin`(dcat-admin)的路由主键加密能力。 +> 页面 URL 中的主键(如 `/admin/books/1/edit` 里的 `1`)会被加密成不可读的密文(默认 +> **36 位 UUID 样式**),防止直接暴露数据库主键。 + +--- + +## 1. 快速开始 + +### 1.1 启用加密 + +在项目根目录 `.env` 中配置: + +```dotenv +# 是否启用 URL 主键加密 +ADMIN_ROUTE_ENCRYPT=true + +# 加解密盐(字符串,必须有值;改盐会让旧密文全部失效) +ADMIN_ROUTE_CIPHER_SALT=111 +``` + +> **注意**:`ADMIN_ROUTE_CIPHER_SALT` 必填且不能为空,否则加解密会抛异常。 +> 修改盐之前生成的密文将在修改后无法解密,请勿随意变更。 +> +> 魔数 `cipher_magic` 为可选(默认 `\x02`,一般无需配置), +> 同样参与解密校验,改动会让旧密文失效,详见 [§5 配置项详解](#5-配置项详解)。 + +启用后 `php artisan config:clear` 刷新配置缓存。 + +### 1.2 验证是否生效 + +打开任意后台列表页(如 `/admin/books`),查看「编辑 / 查看 / 删除」按钮链接: + +- 启用前:`/admin/books/1/edit` +- 启用后:`/admin/books/f5a24e32-xxxx-xxxx-xxxx-xxxxxxxxxxxx/edit`(UUID 样式密文) + +登录与权限等原有功能不受影响,控制器里拿到的主键**仍是明文**(由中间件自动解密)。 + +--- + +## 2. 加密范围 + +启用后,以下场景的 URL 主键会被加密(`encrypt=true` 时才生效,默认 `false` 完全不影响现有功能): + +| 场景 | 组件 | 说明 | +|---|---|---| +| Grid 行操作 | 编辑 / 查看 / 删除按钮 | 自动生效 | +| Delete 弹窗 | 单行 / 批量删除确认弹窗 | 不再展示明文主键 | +| Form 表单 | 编辑页提交、查看、删除 | 自动生效 | +| Show 详情页 | 编辑 / 删除按钮 | 自动生效 | +| Tree 树形列表 | 编辑 / 快速编辑 / 删除 | 自动生效 | +| 行内编辑 | `editable()`、`select()`、`switch()`、`switchGroup()` | 自动生效 | +| 行内排序 | `orderable()` 的 ↑↓ 排序请求 | 启用后自动生效 | + +**不加密**: + +- Query 字符串参数(`?filter=xx` 等)不受影响 +- **批量删除选中主键**(`data-id` / `keys`)为明文:批量删除按钮的请求 URL 是 + `resource/{id1,id2,...}`,其中 `keys` 来自 Grid 行选择器(RowSelector)的 `data-id`。 + 该通道同时被「导出选中行」复用(`ExportButton` 直接拼 `__rows__`), + 因此保持明文以兼容导出;确认弹窗已置空,不展示这些明文主键。 +- **单行删除**(Grid/Tree/Form 的删除按钮)是**加密的**:`data-url` 里的主键经 + `admin_cipher_encrypt($key, 'gi' / 'fo')` 加密,只有确认弹窗文案被置空 + (不展示明文),URL 本身是密文。 + +--- + +## 3. 作用域(Scope) + +加密时有一个「作用域」概念,用于区分同一个主键在不同上下文下的密文。 + +`UuidCipher` 把**作用域短标签本身**(1~2 个可打印 ASCII 字符)写入密文第 2-3 字节 +(右补 `\x00`)。**作用域必须是 1~2 个可打印 ASCII 字符**(如 `gi`/`fo`/`bo`), +超长(如 `grid.id`、`book:grid.id`)或中文会直接抛异常,不会静默截断: +**不再强制校验作用域注册**:只要符合长度/字符集约束即可加密;解密时读出 2 字节标签, +必须与传入的 scope 一致(不匹配返回 null,防跨场景重放)——不再校验是否 +在某个作用域数组(即不要求注册),但**标签比对是必须的**。 +> CryptCipher 无 1~2 字节限制(`[scope]:` 前缀可任意长度),但仍需与加密时一致。 + +内置约定(仅供参考,不强制): + +| 作用域 | 用途 | +|---|---| +| `gi` | Grid 行操作(编辑/查看/删除按钮) | +| `fo` | Form 表单(提交/删除/查看) | + +**`cipher_scopes` 配置为历史兼容保留**:旧版 `UuidCipher` 用它强制校验作用域注册, +当前实现不再读取做强制校验,可保留可删除: + +```php +'route' => [ + ... + // 历史兼容,可省略 + 'cipher_scopes' => [ + // 历史兼容示例(旧版用) + + ], +], +``` + +**控制器指定最终作用域(可选)**:控制器可定义 `cipherScope` 属性,其属性值**直接作为 +该控制器 URL 加密的最终作用域**(不再拼接前缀/合成)。这样同一控制器的 grid / form +URL 都使用同一个作用域隔离: + +```php +class BookController extends AdminController +{ + // cipherScope 直接是最终作用域短标签(1~2 可打印 ASCII 字符) + // 该控制器所有加密 URL 统一使用此作用域(不再用调用点的 gi/fo) + protected $cipherScope = 'bo'; +} +``` + +> **不设置 `cipherScope`** 时行为等同旧版,使用调用点的 `gi` / `fo`。 +> **解密必须传入作用域** —— 密文自带 2 字节标签/前缀,解密时需传与加密一致的 scope, +> 不匹配返回 null(防跨场景重放)。 +> **中间件解密的作用域来源**: +> - 控制器配置了 `cipherScope` → 中间件**只用它**解密;密文标签与它不一致 → 解密失败 → 404 +> (这正是"用 b1 解 bo 密文应 404"的期望行为); +> - 未配置 `cipherScope`(或闭包路由)→ 回退自动提取密文标签解密(内置 gi/fo 兼容场景)。 + +--- + +## 4. 手动加解密(公开 Helper) + +包提供两个公开全局函数,`$key`(作用域)**必填**,主键**仅支持正整数**: + +```php +// helpers.php 无 namespace,函数是全局的,直接调用即可 +$cipher = admin_cipher_encrypt(42, 'bo'); +``` + +### 4.1 加密 + +```php +$cipher = admin_cipher_encrypt(42, 'bo'); +// 返回:f5a24e32-xxxx-xxxx-xxxx-xxxxxxxxxxxx(UUID 样式密文) +// 参数:$plain 正整数主键(int,弱类型下数字字符串也能传);$key 作用域必填 +``` + +- 非正整数(`0` / `负数` / 非数字)→ 抛 `InvalidArgumentException` +- `$key` 通过类型声明 `string` 强制必填:缺参 / 传 `null` → PHP `TypeError`(不满足类型即被引擎拦截,不进入业务逻辑) +- 传空串 `''` → 抛 `InvalidArgumentException`(防产出无 scope 的密文) + +### 4.2 解密 + +```php +$plain = admin_cipher_decrypt($cipher, 'bo'); +// 返回:'42'(明文主键字符串);失败返回 null +// 参数:$cipher 密文;$key 作用域必填,需与加密时一致 +``` + +- `$key` 通过类型声明 `string` 强制必填:缺参 / 传 `null` → PHP `TypeError`;传空串 `''` → 抛 `InvalidArgumentException`(不进入解密流程) +- 传入的 `$key` 与密文内嵌 scope 不一致 → 返回 `null`(防跨场景重放) +- 解密结果非正整数 → 返回 `null` +- 页面访问走中间件:控制器配了 `cipherScope` 时用它校验(不匹配 → 404),未配置时自动提取标签解密 + +### 4.3 完整示例 + +```php +// 加密 +$cipher = admin_cipher_encrypt($book->id, 'bo'); // 'f5a24e32-...' +$url = "/admin/books/{$cipher}/edit"; + +// 解密 +$id = admin_cipher_decrypt($cipher, 'bo'); // '42' +if ($id === null) { + abort(404); +} +``` + +--- + +## 5. 配置项详解 + +`config/admin.php` 的 `route` 段: + +```php +'route' => [ + // 是否启用 URL 主键加密(默认 false) + 'encrypt' => env('ADMIN_ROUTE_ENCRYPT', false), + + // 加解密实现类,必须实现 \Dcat\Admin\Contracts\UrlCipher + // 当前默认:UuidCipher(AES 伪 UUID 版,密文 36 位 UUID 样式) + // 可选: CryptCipher(配置盐混淆版,密文 [scope]:hex) + 'cipher' => \Dcat\Admin\Support\UuidCipher::class, + + // 加解密盐(必须有值) + 'cipher_salt' => env('ADMIN_ROUTE_CIPHER_SALT', 'dcat_c'), + + // UuidCipher 明文块第一字节魔数(默认 "\x02") + // 支持:int(如 2)/ "0x02" / "\x02" 单字节字符串,最终归一为单字节。 + // 注意:此键不读 env(),只能在这里改 PHP 字面量;魔数参与解密校验, + // 改动后旧密文将无法解密(与新 salt 同理),如无必要请保持默认。 + 'cipher_magic' => "\x02", +], +``` + +### 两种内置实现对比 + +| | **UuidCipher**(默认) | **CryptCipher**(可选) | +|---|---|---| +| 密文样式 | 36 位 UUID:`f5a24e32-xxxx-...` | `[gi]:a1b2c3...`(hex) | +| 密钥派生 | AES-256 + PBKDF2(100k 迭代) | 配置盐 XOR 混淆(sha256 派生) | +| 支持主键 | 正整数 1 ~ 1099511627775(uint40) | 非负 int(无长度上限) | +| 作用域内嵌 | 2 字节字符串标签(如 gi/fo/bo) | `[scope]:` 前缀 | +| 完整性校验 | 第一字节必须为配置魔数(默认 0x02)+ 标签与传入 scope 一致 | 前缀与传入 scope 一致(靠前缀 + XOR 还原) | +| 适用场景 | 追求密文形式隐蔽、更安全 | 简单轻量、可读性略高 | + +切换实现只需改 `cipher` 配置(需要同时保证 `cipher_salt` 存在): + +```php +'cipher' => \Dcat\Admin\Support\CryptCipher::class, +``` + +> 切换后旧密文无法解密(加密算法不同),请合理安排切换时机。 + +### UuidCipher 字节布局 + +`UuidCipher` 加密前会把主键拼成一个 **16 字节明文块**(恰好一个 AES 块,无需填充), +然后整体走 AES-256-ECB 加密,hex 后拼成 36 位 UUID 样式: + +``` +┌─────────┬───────────────┬───────────────┬─────────────────┐ +│ 魔数 1B │ 作用域标签 2B │ 填充 8B │ 主键 5B(大端) │ +│ 可配置 │ 短标签 ASCII │ 0x00 全 0 │ uint40 BE │ +└─────────┴───────────────┴───────────────┴─────────────────┘ +offset: 0 1..2 3..10 11..15 +``` + +- **魔数**:默认 `0x02`,可通过 `admin.route.cipher_magic` 配置化(详见 §5), + 解密时**第一个字节必须等于配置的魔数**,否则拒绝; +- **作用域标签(2 字节)**:作用域短标签本身(1~2 个可打印 ASCII 字符) + (右补 `\x00` 到 2 字节)。**作用域必须本身是 1~2 个可打印 ASCII 字符**, + 超长/中文在加密时抛异常(不做静默截断,避免标签碰撞)。 + **不再强制校验注册**:解密时读出 2 字节 → 去掉尾部 `\x00` → 标签必须与传入 scope 一致 + (不匹配返回 null,防跨场景重放);不再校验是否在作用域数组(即不要求注册)。 +- **填充**:8 字节全 0; +- **主键(5 字节)**:主键自身的 5 字节大端表示(uint40,字节序 高→低),仅支持正整数 `1 ~ 1099511627775`。 + +> **主键上限**:`UuidCipher` 支持 uint40 主键(最大约 1.1 万亿)。如果表主键是 +> bigint / 超过 1.1 万亿,请改用 `CryptCipher`(不设此上限),或在分表后使用。 + +--- + +## 6. 自定义加密实现 + +如果内置两种都不满足,可实现 `UrlCipher` 接口: + +```php + \App\Support\MyCipher::class, +``` + +接口签名(`Contracts/UrlCipher.php`): + +```php +public function encrypt(int $plain, string $key): string; +public function decrypt(string $cipher, string $key): ?string; +``` + +--- + +## 7. 常见问题 + +### 7.1 页面 URL 还是明文? + +确认 `.env` 里 `ADMIN_ROUTE_ENCRYPT=true` 且执行了 `php artisan config:clear`。 +默认值是 `false`,不改就完全不加密(未显式配置时走 `config/admin.php` 的默认值)。 + +### 7.2 改了 salt 后所有链接打不开了? + +对,改了 `ADMIN_ROUTE_CIPHER_SALT` 会让旧密文全部失效。中间件解密失败会回退明文尝试, +但基本都会 404。**salt 定下来就别改**,或者在无存量密文时再改。 + +### 7.3 控制器里拿到的还是明文吗? + +是的。中间件负责把 URL 里的密文主键解密回明文,控制器 `$id` 收到的仍是正常的主键值, +业务代码无需改动。 + +### 7.4 Orderable 排序按钮没有加密? + +`orderable()` 是可选 displayer,需要你在 Grid 里启用才有: + +```php +$grid->column('sort')->orderable(); +``` + +启用后 ↑↓ 图标的 `data-id` 和排序 PUT 请求 URL 会自动携带密文。 + +### 7.5 手动解密失败? + +`admin_cipher_decrypt` 要求传入与加密时**一致的 scope**。**UuidCipher 和 CryptCipher 解密时 +都会校验 scope**:UuidCipher 读取内嵌的 2 字节标签与传入 `$key` 比对,不匹配返回 `null`; +CryptCipher 比对密文 `[scope]:` 前缀,不匹配返回 `null`。因此传错 scope 会返回 `null` +(防跨场景重放)——这是手动解密失败的常见原因。 + +### 7.6 改了 cipher_magic 后所有链接打不开了? + +同样会。`cipher_magic` 参与解密校验(第一字节必须等于配置值),改动后旧密文第一字节 +与新的魔数不匹配 → 解密失败。**cipher_magic 和 salt 一样,定下来就别改**; +它没有 `env()` 包裹,只能改 `config/admin.php` 里的 PHP 字面量。 + +--- + +## 8. 文件清单(涉及本次功能) + +``` +src/Contracts/UrlCipher.php # 加解密接口契约 +src/Support/UrlCipherManager.php # 统一入口(encrypt/decrypt/开关判断/expectedScope) +src/Support/CryptCipher.php # 可选实现 B:配置盐混淆版 +src/Support/UuidCipher.php # 默认实现 A:AES 伪 UUID 版(cipher_magic 配置化) +src/Http/Middleware/Cipher.php # 中间件(解密路由主键) +src/Http/Controllers/AdminController.php # cipherScope getter +src/Support/helpers.php # admin_cipher_encrypt / admin_cipher_decrypt +config/admin.php # 配置项(encrypt / cipher / cipher_salt / cipher_magic / cipher_scopes) +``` + +--- + +*文档版本:2026-08-15,对应 `UuidCipher` 默认实现。* \ No newline at end of file diff --git a/resources/assets/dcat/js/bootstrappers/DataActions.js b/resources/assets/dcat/js/bootstrappers/DataActions.js index 2ac157082..ff62a57d6 100644 --- a/resources/assets/dcat/js/bootstrappers/DataActions.js +++ b/resources/assets/dcat/js/bootstrappers/DataActions.js @@ -49,7 +49,9 @@ let defaultActions = { if (! keys.length) { return; } - let msg = 'ID - ' + keys.join(', '); + + // 不展示明文主键(批量删除确认弹窗文案置空) + let msg = ''; Dcat.confirm(lang.delete_confirm, msg, function () { Dcat.NP.start(); diff --git a/resources/dist/dcat/js/dcat-app.js b/resources/dist/dcat/js/dcat-app.js index 90b4155ac..77c21762e 100644 --- a/resources/dist/dcat/js/dcat-app.js +++ b/resources/dist/dcat/js/dcat-app.js @@ -1,2 +1,2 @@ -!function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="/",n(n.s=5)}([function(module,exports){eval(function(e,t,n,r,o,a){if(o=function(e){return(e<62?"":o(parseInt(e/62)))+((e%=62)>35?String.fromCharCode(e+29):e.toString(36))},!"".replace(/^/,String)){for(;n--;)a[o(n)]=r[n]||o(n);r=[function(e){return a[e]}],o=function(){return"\\w+"},n=1}for(;n--;)r[n]&&(e=e.replace(new RegExp("\\b"+o(n)+"\\b","g"),r[n]));return e}('!14(t,e){"4o"==1A ac&&"3d"!=1A a7?a7.ac=e():"14"==1A 83&&83.ep?83(e):t.7V=e()}(1d,14(){"8G eo";14 f(t){17(f="14"==1A 5i&&"ag"==1A 5i.en?14(t){17 1A t}:14(t){17 t&&"14"==1A 5i&&t.5Q===5i&&t!==5i.3b?"ag":1A t})(t)}14 o(t,e){1w(!(t 7P e))7K 2M 8i("ek 4A a 1j as a 14")}14 i(t,e){2g(18 n=0;n\\n <1H 1j="\').1n(k.4O,\'">\\n \\n <1H 1j="\').1n(k.1r," ").1n(B.2n,\'">\\n <34 1j="13-x-2V"><34 1j="13-x-2V-1o-1g"><34 1j="13-x-2V-1o-1k">\\n \\n <1H 1j="\').1n(k.1r," ").1n(B.4q,\'">\\n <1H 1j="\').1n(k.1r," ").1n(B.5J,\'">\\n <1H 1j="\').1n(k.1r," ").1n(B.5I,\'">\\n <1H 1j="\').1n(k.1r," ").1n(B.1f,\'">\\n <1H 1j="13-1f-35-1o-1g">\\n <34 1j="13-1f-1o-3h"> <34 1j="13-1f-1o-3c">\\n <1H 1j="13-1f-6G"> <1H 1j="13-1f-6F">\\n <1H 1j="13-1f-35-1o-1k">\\n \\n \\n <8k 1j="\').1n(k.2I,\'" 55="\').1n(k.2I,\'">\\n <3y 1U="3y" 1j="\').1n(k.3e,\'">&d3;\\n \\n <1H 1j="\').1n(k.1z,\'">\\n <1H 55="\').1n(k.1z,\'">\\n <1i 1j="\').1n(k.1i,\'" />\\n <1i 1U="2l" 1j="\').1n(k.2l,\'" />\\n <1H 1j="\').1n(k.2s,\'">\\n <1i 1U="2s" />\\n <46>\\n \\n <2b 1j="\').1n(k.2b,\'">\\n <1H 1j="\').1n(k.2v,\'">\\n <3E 2g="\').1n(k.2A,\'" 1j="\').1n(k.2A,\'">\\n <1i 1U="2A" />\\n <34 1j="\').1n(k.3E,\'">\\n \\n <2h 1j="\').1n(k.2h,\'">\\n <1H 1j="\').1n(k["4h-4l"],\'" 55="\').1n(k["4h-4l"],\'">\\n \\n <1H 1j="\').1n(k.2F,\'">\\n <3y 1U="3y" 1j="\').1n(k.4n,\'">8t\\n <3y 1U="3y" 1j="\').1n(k.3N,\'">8x\\n \\n <1H 1j="\').1n(k.3C,\'">\\n \\n \\n\').d2(/(^|\\n)\\s*/g,""),ct=14(t){1w(14(){18 t=q();t&&(t.3I.7D(t),3U([1m.5a,1m.1e],[k["26-1P"],k["1b-1q"],k["d1-1R"]]))}(),X())g("6Y 7H 1m 3S d0");3m{18 e=1m.3A("1H");e.4F=k.1h,e.38=9T;18 n=14(t){17"3a"==1A t?1m.2T(t):t}(t.29);n.37(e),14(t){18 e=2K();e.2P("cZ",t.1b?"cY":"9e"),e.2P("2o-cX",t.1b?"cW":"cV"),t.1b||e.2P("2o-3M","4M")}(t),14(t){"6M"===22.4U(t).4k&&1V(q(),k.6M)}(n),14(){18 t=U(),e=2y(t,k.1i),n=2y(t,k.2l),o=t.2T(".".1n(k.2s," 1i")),i=t.2T(".".1n(k.2s," 46")),r=2y(t,k.2b),a=t.2T(".".1n(k.2A," 1i")),s=2y(t,k.2h);e.7N=G,n.5R=G,r.5R=G,a.5R=G,s.7N=G,o.7N=14(t){G(t),i.1K=o.1K},o.5R=14(t){G(t),o.cU.1K=o.1K}}()}},9w=14(t,e){1w(t.38="",0 2O e)2g(18 n=0;n 2O e;n++)t.37(e[n].9B(!0));3m t.37(e.9B(!0))},dt=14(){1w(X())17!1;18 t=1m.3A("1H"),e={cT:"cS",cR:"cQ cP",1L:"cO"};2g(18 n 2O e)1w(e.6I(n)&&3l 0!==t.1I[n])17 e[n];17!1}();14 7R(t,e,n){M(t,n["cN"+e.cM(1)+"ad"],"6t-4b"),t.38=n[e+"cL"],t.2P("2o-3E",n[e+"cK"]),t.4F=k[e],b(t,n.2i,e+"ad"),1V(t,n[e+"cJ"])}14 8c(t,e){18 n=Z(),o=K(),i=F();e.5f||e.5e?T(n):O(n),b(n,e.2i,"2F"),7R(o,"4n",e),7R(i,"3N",e),e.7X?14(t,e,n){1V([t,e],k.2J),n.5N&&(t.1I.5E=n.5N),n.6N&&(e.1I.5E=n.6N);18 o=22.4U(t).4v("1J-1u");t.1I.82=o,t.1I.7Z=o}(o,i,e):(3U([o,i],k.2J),o.1I.5E=o.1I.82=o.1I.7Z="",i.1I.5E=i.1I.82=i.1I.7Z="")}14 8C(t,e){18 n=q();n&&(14(t,e){"3a"==1A e?t.1I.1J=e:e||1V([1m.5a,1m.1e],k["26-1P"])}(n,e.1P),!e.1P&&e.5y&&y(\'"5y" 42 7H `1P` 42 3S be 43 3S `4M`\'),14(t,e){e 2O k?1V(t,k[e]):(y(\'8H "2G" 42 53 1M 8K, 8L 3S "1l"\'),1V(t,k.1l))}(n,e.2G),14(t,e){1w(e&&"3a"==1A e){18 n="1Y-"+e;n 2O k&&1V(t,k[n])}}(n,e.1Y),b(n,e.2i,"1h"),e.6j&&1V(n,e.6j))}14 6m(t,e){t.2E&&!e.4Y||(t.2E=e.4Y)}18 bb={5g:2M 5h,3k:2M 5h,3R:2M 5h},96=14(t,e){18 n=P(U(),t);1w(n)2g(18 o 2O 14(t){2g(18 e=0;e=i.2W.23&&y("6E 56 42, 2y a9 be cG cF 2W.23 (56 cE cD cC cA 86 0)"),i.2W.2S(14(t,e){18 n=14(t){18 e=1m.3A("7z");17 1V(e,k["25-2D"]),e.38=t,e}(t);1w(r.37(n),e===a&&1V(n,k["3V-25-2D"]),e!==i.2W.23-1){18 o=14(t){18 e=1m.3A("7z");17 1V(e,k["25-2D-1o"]),t.7y&&(e.1I.1c=t.7y),e}(t);r.37(o)}})}14 8a(t,e){18 n=Q();b(n,e.2i,"4O"),7E(0,e),14(t,e){18 n=bb.3k.2k(t);1w(n&&e.1U===n.1U&&N())b(N(),e.2i,"1r");3m 1w(bc(),e.1U)1w(8b(),-1!==2d.57(B).3t(e.1U)){18 o=H(".".1n(k.1r,".").1n(B[e.1U]));T(o),b(o,e.2i,"1r"),L(o,"13-1Q-".1n(e.1U,"-1r"),e.1L)}3m g(\'8e 1U! 5k "1f", "2n", "5J", "5I" 5l "4q", 5m "\'.1n(e.1U,\'"\'))}(t,e),14(t,e){18 n=4L();1w(!e.5P)17 O(n);T(n),n.2P("8h",e.5P),n.2P("cz",e.7w),E(n,"1c",e.7u),E(n,"1E",e.8l),n.4F=k.4e,b(n,e.2i,"4e"),e.5u&&1V(n,e.5u)}(0,e),14(t,e){18 n=D();M(n,e.2I||e.5v),e.2I&&5W(e.2I,n),e.5v&&(n.8q=e.5v),b(n,e.2i,"2I")}(0,e),14(t,e){18 n=$();b(n,e.2i,"7s"),M(n,e.5U),n.2P("2o-3E",e.8u)}(0,e)}14 7r(t,e){!14(t,e){18 n=2K();E(n,"1c",e.1c),E(n,"2e",e.2e),e.1J&&(n.1I.1J=e.1J),n.4F=k.1t,e.1b?(1V([1m.5a,1m.1e],k["1b-1q"]),1V(n,k.1b)):1V(n,k.3M),b(n,e.2i,"1t"),"3a"==1A e.2i&&1V(n,e.2i),L(n,k.6Q,!e.1L)}(0,e),8C(0,e),8a(t,e),9K(t,e),8c(0,e),14(t,e){18 n=Y();M(n,e.3C),e.3C&&5W(e.3C,n),b(n,e.2i,"3C")}(0,e)}18 bc=14(){2g(18 t=R(),e=0;e22.bW&&(x.4B=4C(22.4U(1m.1e).4v("2e-1k")),1m.1e.1I.8y=x.4B+14(){1w("8z"2O 22||8A.bV)17 0;18 t=1m.3A("1H");t.1I.1c="8B",t.1I.1E="8B",t.1I.3T="8D",1m.1e.37(t);18 e=t.8m-t.bU;17 1m.1e.7D(t),e}()+"6y")}14 73(){17!!22.bT&&!!1m.bS}14 6r(){18 t=q(),e=2K();t.1I.aa("1S-2f"),e.bR<0&&(t.1I.bQ="1C-1O")}18 be=14(){1B!==x.4B&&(1m.1e.1I.8y=x.4B+"6y",x.4B=1B)},8M=14(){18 e,n=q();n.8z=14(t){e=t.29===n||!14(t){17!!(t.8w>t.bP)}(n)&&"bO"!==t.29.bN},n.bM=14(t){e&&(t.6h(),t.7d())}},8S=14(){1w(S(1m.1e,k.5L)){18 t=4C(1m.1e.1I.19,10);3U(1m.1e,k.5L),1m.1e.1I.19="",1m.1e.6g=-1*t}},8U=14(){"3d"!=1A 22&&73()&&22.6f("8W",6r)},8X=14(){m(1m.1e.8Y).2S(14(t){t.6V("3D-6e-2o-2L")?(t.2P("2o-2L",t.4W("3D-6e-2o-2L")),t.3O("3D-6e-2o-2L")):t.3O("2o-2L")})},6c={7i:2M 5h};14 7j(t,e,n){e?$t(n):(8N().3G(14(){17 $t(n)}),1y.4G.6f("7l",1y.5A,{7n:1y.41}),1y.64=!1),5z 1y.5A,5z 1y.4G,t.3I&&t.3I.7D(t),3U([1m.5a,1m.1e],[k.1q,k["1E-1D"],k["26-1P"],k["1b-1q"],k["1b-1R"]]),at()&&(be(),8S(),8U(),8X())}14 5c(t){18 e=q(),n=2K();1w(n&&!S(n,k.30)){18 o=bb.3k.2k(1d),i=6c.7i.2k(1d),r=o.9q,a=o.9o;3U(n,k.31),1V(n,k.30),dt&&j(n)?n.60(dt,14(t){t.29===n&&14(t,e,n,o){S(t,k.30)&&7j(e,n,o),bf(bb),bf(6c)}(n,e,5p(),a)}):7j(e,5p(),a),1B!==r&&"14"==1A r&&r(n),i(t||{}),5z 1d.49}}18 bf=14(t){2g(18 e 2O t)t[e]=2M 5h},$t=14(t){1B!==t&&"14"==1A t&&59(14(){t()})};14 5w(t,e,n){18 o=bb.3R.2k(t);e.2S(14(t){o[t].2Q=n})}14 7t(t,e){1w(!t)17!1;1w("2v"===t.1U)2g(18 n=t.3I.3I.4w("1i"),o=0;o"));18 t=2K(),n="3a"==1A e.29?1m.2T(e.29):e.29;(!t||t&&n&&t.3I!==n.3I)&&ct(e)}(l),2d.5F(l),1y.2U&&(1y.2U.4X(),5z 1y.2U),9j(1y.8P);18 d={1t:2K(),1h:q(),1z:U(),2F:Z(),2N:K(),3o:F(),7s:$(),3j:W(),2W:z()};bb.3R.43(1d,d),7r(1d,l),bb.3k.43(1d,l);18 p=1d.5Q;17 2M 36(14(t){14 n(t){c.7S({1K:t})}14 s(t){c.7S({6T:t})}6c.7i.43(c,t),l.4H&&(1y.2U=2M bg(14(){s("4H"),5z 1y.2U},l.4H));l.1i&&59(14(){18 t=c.3x();t&&A(t)},0);2g(18 u=14(e){(l.6l&&p.8f(),l.4T)?(c.5Z(),36.4y().3G(14(){17 l.4T(e,l.3j)}).3G(14(t){V(d.3j)||!1===t?c.4D():n(3l 0===t?e:t)})):n(e)},e=14(t){18 e=t.29,n=d.2N,o=d.3o,i=n&&(n===e||n.3X(e)),r=o&&(o===e||o.3X(e));5H(t.1U){3i"75":1w(i)1w(c.7U(),l.1i){18 a=14(){18 t=c.3x();1w(!t)17 1B;5H(l.1i){3i"2A":17 t.5G?1:0;3i"2v":17 t.5G?t.1K:1B;3i"2l":17 t.ae.23?t.ae[0]:1B;4r:17 l.9k?t.1K.aw():t.1K}}();1w(l.5D)c.9W(),36.4y().3G(14(){17 l.5D(a,l.3j)}).3G(14(t){c.6H(),c.9V(),t?c.7W(t):u(a)});3m c.3x().ax()?u(a):(c.6H(),c.7W(l.3j))}3m u(!0);3m r&&(c.7U(),s(p.4S.3N))}},o=d.1t.4w("3y"),i=0;i.13-3M{2r-3H:0 0 d6 3B(0,0,0,.4)}1e.13-26-1P .13-1q.13-19{19:0;1g:50%;-1a-16:4c(-50%);16:4c(-50%)}1e.13-26-1P .13-1q.13-19-1g,1e.13-26-1P .13-1q.13-19-1O{19:0;1g:0}1e.13-26-1P .13-1q.13-19-27,1e.13-26-1P .13-1q.13-19-1k{19:0;1k:0}1e.13-26-1P .13-1q.13-1l{19:50%;1g:50%;-1a-16:6w(-50%,-50%);16:6w(-50%,-50%)}1e.13-26-1P .13-1q.13-1l-1g,1e.13-26-1P .13-1q.13-1l-1O{19:50%;1g:0;-1a-16:28(-50%);16:28(-50%)}1e.13-26-1P .13-1q.13-1l-27,1e.13-26-1P .13-1q.13-1l-1k{19:50%;1k:0;-1a-16:28(-50%);16:28(-50%)}1e.13-26-1P .13-1q.13-1v{1v:0;1g:50%;-1a-16:4c(-50%);16:4c(-50%)}1e.13-26-1P .13-1q.13-1v-1g,1e.13-26-1P .13-1q.13-1v-1O{1v:0;1g:0}1e.13-26-1P .13-1q.13-1v-27,1e.13-26-1P .13-1q.13-1v-1k{1k:0;1v:0}.13-1h{2B:1C;2G:d7;z-3Z:d9;19:0;1k:0;1v:0;1g:0;1C-4k:5M;1S-2f:1l;2p-1z:1l;2e:.1W;3T-x:2L;1J-1u:3v;-1a-3T-da:db}.13-1h.13-19{1S-2f:1C-1O}.13-1h.13-19-1g,.13-1h.13-19-1O{1S-2f:1C-1O;2p-1z:1C-1O}.13-1h.13-19-27,.13-1h.13-19-1k{1S-2f:1C-1O;2p-1z:1C-27}.13-1h.13-1l{1S-2f:1l}.13-1h.13-1l-1g,.13-1h.13-1l-1O{1S-2f:1l;2p-1z:1C-1O}.13-1h.13-1l-27,.13-1h.13-1l-1k{1S-2f:1l;2p-1z:1C-27}.13-1h.13-1v{1S-2f:1C-27}.13-1h.13-1v-1g,.13-1h.13-1v-1O{1S-2f:1C-27;2p-1z:1C-1O}.13-1h.13-1v-27,.13-1h.13-1v-1k{1S-2f:1C-27;2p-1z:1C-27}.13-1h.13-1v-27>:4P-4Q,.13-1h.13-1v-1g>:4P-4Q,.13-1h.13-1v-1k>:4P-4Q,.13-1h.13-1v-1O>:4P-4Q,.13-1h.13-1v>:4P-4Q{1N-19:1D}.13-1h.13-1Y-6S>.13-3M{2B:1C!3f;1C:1;1S-9M:72;2p-1z:1l}.13-1h.13-1Y-5M>.13-3M{2B:1C!3f;1C:1;1S-1z:1l;2p-1z:1l}.13-1h.13-1Y-1R{1C:1;1C-4k:1R}.13-1h.13-1Y-1R.13-1v,.13-1h.13-1Y-1R.13-1l,.13-1h.13-1Y-1R.13-19{1S-2f:1l}.13-1h.13-1Y-1R.13-1v-1g,.13-1h.13-1Y-1R.13-1v-1O,.13-1h.13-1Y-1R.13-1l-1g,.13-1h.13-1Y-1R.13-1l-1O,.13-1h.13-1Y-1R.13-19-1g,.13-1h.13-1Y-1R.13-19-1O{1S-2f:1C-1O}.13-1h.13-1Y-1R.13-1v-27,.13-1h.13-1Y-1R.13-1v-1k,.13-1h.13-1Y-1R.13-1l-27,.13-1h.13-1Y-1R.13-1l-1k,.13-1h.13-1Y-1R.13-19-27,.13-1h.13-1Y-1R.13-19-1k{1S-2f:1C-27}.13-1h.13-1Y-1R>.13-3M{2B:1C!3f;1C:1;1S-1z:1l;2p-1z:1l}.13-1h:1M(.13-19):1M(.13-19-1O):1M(.13-19-27):1M(.13-19-1g):1M(.13-19-1k):1M(.13-1l-1O):1M(.13-1l-27):1M(.13-1l-1g):1M(.13-1l-1k):1M(.13-1v):1M(.13-1v-1O):1M(.13-1v-27):1M(.13-1v-1g):1M(.13-1v-1k):1M(.13-1Y-6S)>.13-3M{1N:1D}@6J 7C 6q (-2Z-51-52:1Z),(-2Z-51-52:3V){.13-1h .13-3M{1N:0!3f}}.13-1h.13-6R{6u:1J-1u .1s}.13-1h.13-1q{1J-1u:3B(0,0,0,.4)}.13-1t{2B:1Z;2G:5o;2r-5r:1x-2r;1C-4k:1R;2p-1z:1l;1c:de;4K-1c:1F%;2e:1.2x;1x:1Z;1x-2w:.2C;1J:#3Q;1T-8Z:3z;1T-2j:dh}.13-1t:2c{5B:0}.13-1t.13-2u{3T-y:2L}.13-4O{2B:1C;1C-4k:1R;1S-2f:1l}.13-2I{2G:5o;4K-1c:1F%;1N:0 0 .4u;2e:0;1u:#dj;1T-2j:1.3p;1T-3Y:69;3g-1S:1l;3g-16:1Z;6a-6d:4I-6a}.13-2F{z-3Z:1;1C-6d:6d;1S-2f:1l;2p-1z:1l;1c:1F%;1N:1.2x 1D 0}.13-2F:1M(.13-2u) .13-2J[2Q]{2z:.4}.13-2F:1M(.13-2u) .13-2J:8j{1J-4e:4R-8s(3B(0,0,0,.1),3B(0,0,0,.1))}.13-2F:1M(.13-2u) .13-2J:3V{1J-4e:4R-8s(3B(0,0,0,.2),3B(0,0,0,.2))}.13-2F.13-2u .13-2J.13-4n{2r-5r:1x-2r;1c:2.21;1E:2.21;1N:.dq;2e:0;-1a-1L:13-1p-2u 1.5s 4R 6z 6v 4x;1L:13-1p-2u 1.5s 4R 6z 6v 4x;1x:.2x 44 3v;1x-2w:1F%;1x-1u:3v;1J-1u:3v!3f;1u:3v;6s:4r;-1a-4a-2b:1Z;-4s-4a-2b:1Z;-2Z-4a-2b:1Z;4a-2b:1Z}.13-2F.13-2u .13-2J.13-3N{1N-1k:9R;1N-1g:9R}.13-2F.13-2u :1M(.13-2J).13-4n::dA{1z:\\"\\";2B:6t-4b;1c:9L;1E:9L;1N-1g:dC;-1a-1L:13-1p-2u 1.5s 4R 6z 6v 4x;1L:13-1p-2u 1.5s 4R 6z 6v 4x;1x:9m 44 #dE;1x-2w:50%;1x-1k-1u:3v;2r-3H:3K 3K 3K #3Q}.13-2J{1N:.2C;2e:.1W 2q;2r-3H:1Z;1T-3Y:dG}.13-2J:1M([2Q]){6s:8g}.13-2J.13-4n{1x:0;1x-2w:.2x;1J:77;1J-1u:#6k;1u:#3Q;1T-2j:1.32}.13-2J.13-3N{1x:0;1x-2w:.2x;1J:77;1J-1u:#dK;1u:#3Q;1T-2j:1.32}.13-2J:2c{5B:0;2r-3H:0 0 0 79 #3Q,0 0 0 dM 3B(50,1F,7T,.4)}.13-2J::-4s-2c-dN{1x:0}.13-3C{2p-1z:1l;1N:1.2x 0 0;2e:3w 0 0;1x-19:3K 44 #dO;1u:#9X;1T-2j:3w}.13-4e{4K-1c:1F%;1N:1.2x 1D}.13-3e{2G:4p;19:0;1k:0;2p-1z:1l;1c:1.2q;1E:1.2q;2e:0;3T:2L;6u:1u .1s 7g-dR;1x:1Z;1x-2w:0;5B:77;1J:0 0;1u:#4V;1T-8Z:dT;1T-2j:2.21;1o-1E:1.2;6s:8g}.13-3e:8j{-1a-16:1Z;16:1Z;1J:0 0;1u:#5b}.13-1z{z-3Z:1;2p-1z:1l;1N:0;2e:0;1u:#9X;1T-2j:1.2m;1T-3Y:87;1o-1E:4x;6a-6d:4I-6a}#13-1z{3g-1S:1l}.13-2A,.13-2l,.13-1i,.13-2v,.13-2b,.13-2h{1N:3w 1D}.13-2l,.13-1i,.13-2h{2r-5r:1x-2r;1c:1F%;6u:1x-1u .3s,2r-3H .3s;1x:3K 44 #9t;1x-2w:.39;1J:3z;2r-3H:dX 0 3K 3K 3B(0,0,0,.dY);1u:3z;1T-2j:1.2m}.13-2l.13-4N,.13-1i.13-4N,.13-2h.13-4N{1x-1u:#5b!3f;2r-3H:0 0 79 #5b!3f}.13-2l:2c,.13-1i:2c,.13-2h:2c{1x:3K 44 #dZ;5B:0;2r-3H:0 0 9m #e0}.13-2l::-1a-1i-2E,.13-1i::-1a-1i-2E,.13-2h::-1a-1i-2E{1u:#4V}.13-2l::-4s-2E,.13-1i::-4s-2E,.13-2h::-4s-2E{1u:#4V}.13-2l:-2Z-1i-2E,.13-1i:-2Z-1i-2E,.13-2h:-2Z-1i-2E{1u:#4V}.13-2l::-2Z-1i-2E,.13-1i::-2Z-1i-2E,.13-2h::-2Z-1i-2E{1u:#4V}.13-2l::2E,.13-1i::2E,.13-2h::2E{1u:#4V}.13-2s{1N:3w 1D;1J:3z}.13-2s 1i{1c:80%}.13-2s 46{1c:20%;1u:3z;1T-3Y:69;3g-1S:1l}.13-2s 1i,.13-2s 46{1E:2.1W;2e:0;1T-2j:1.2m;1o-1E:2.1W}.13-1i{1E:2.1W;2e:0 .2X}.13-1i[1U=4d]{4K-1c:e2}.13-2l{1J:3z;1T-2j:1.2m}.13-2h{1E:6.2X;2e:.2X}.13-2b{7m-1c:50%;4K-1c:1F%;2e:.2H .1W;1J:3z;1u:3z;1T-2j:1.2m}.13-2A,.13-2v{1S-2f:1l;2p-1z:1l;1J:3z;1u:3z}.13-2A 3E,.13-2v 3E{1N:0 .78;1T-2j:1.2m}.13-2A 1i,.13-2v 1i{1N:0 .4u}.13-4h-4l{2B:1Z;1S-2f:1l;2p-1z:1l;2e:.1W;3T:2L;1J:#e3;1u:#e4;1T-2j:3w;1T-3Y:87}.13-4h-4l::4j{1z:\\"!\\";2B:6t-4b;1c:1.21;7m-1c:1.21;1E:1.21;1N:0 .1W;8T:4x;1x-2w:50%;1J-1u:#5b;1u:#3Q;1T-3Y:69;1o-1E:1.21;3g-1S:1l}@e5 (-2Z-e6:4M){.13-2s 1i{1c:1F%!3f}.13-2s 46{2B:1Z}}@6J 7C 6q (-2Z-51-52:1Z),(-2Z-51-52:3V){.13-2s 1i{1c:1F%!3f}.13-2s 46{2B:1Z}}@-4s-1m 62-e7(){.13-3e:2c{5B:79 44 3B(50,1F,7T,.4)}}.13-1r{2G:5o;2r-5r:1z-2r;2p-1z:1l;1c:21;1E:21;1N:1.2x 1D 1.3p;8T:4x;1x:.2x 44 3v;1x-2w:50%;1o-1E:21;6s:4r;-1a-4a-2b:1Z;-4s-4a-2b:1Z;-2Z-4a-2b:1Z;4a-2b:1Z}.13-1r::4j{2B:1C;1S-2f:1l;1E:92%;1T-2j:3.2X}.13-1r.13-2n{1x-1u:#5b}.13-1r.13-2n .13-x-2V{2G:5o;1C-1Y:1}.13-1r.13-2n [1j^=13-x-2V-1o]{2B:4b;2G:4p;19:2.2C;1c:2.3q;1E:.2C;1x-2w:.2m;1J-1u:#5b}.13-1r.13-2n [1j^=13-x-2V-1o][1j$=1g]{1g:1.32;-1a-16:1p(1X);16:1p(1X)}.13-1r.13-2n [1j^=13-x-2V-1o][1j$=1k]{1k:3w;-1a-16:1p(-1X);16:1p(-1X)}.13-1r.13-5J{1x-1u:#e8;1u:#e9}.13-1r.13-5J::4j{1z:\\"!\\"}.13-1r.13-5I{1x-1u:#ea;1u:#eb}.13-1r.13-5I::4j{1z:\\"i\\"}.13-1r.13-4q{1x-1u:#ec;1u:#ed}.13-1r.13-4q::4j{1z:\\"?\\"}.13-1r.13-4q.13-ef-4q-2V::4j{1z:\\"؟\\"}.13-1r.13-1f{1x-1u:#7Q}.13-1r.13-1f [1j^=13-1f-35-1o]{2G:4p;1c:3.2X;1E:7.21;-1a-16:1p(1X);16:1p(1X);1x-2w:50%}.13-1r.13-1f [1j^=13-1f-35-1o][1j$=1g]{19:-.4J;1g:-2.eg;-1a-16:1p(-1X);16:1p(-1X);-1a-16-4m:3.2X 3.2X;16-4m:3.2X 3.2X;1x-2w:7.21 0 0 7.21}.13-1r.13-1f [1j^=13-1f-35-1o][1j$=1k]{19:-.9H;1g:1.3p;-1a-16:1p(-1X);16:1p(-1X);-1a-16-4m:0 3.2X;16-4m:0 3.2X;1x-2w:0 7.21 7.21 0}.13-1r.13-1f .13-1f-6G{2G:4p;z-3Z:2;19:-.2x;1g:-.2x;2r-5r:1z-2r;1c:1F%;1E:1F%;1x:.2x 44 3B(eh,ei,ej,.3);1x-2w:50%}.13-1r.13-1f .13-1f-6F{2G:4p;z-3Z:1;19:.21;1g:1.1W;1c:.4J;1E:5.1W;-1a-16:1p(-1X);16:1p(-1X)}.13-1r.13-1f [1j^=13-1f-1o]{2B:4b;2G:4p;z-3Z:2;1E:.2C;1x-2w:.2m;1J-1u:#7Q}.13-1r.13-1f [1j^=13-1f-1o][1j$=3h]{19:2.3p;1g:.3p;1c:1.5K;-1a-16:1p(1X);16:1p(1X)}.13-1r.13-1f [1j^=13-1f-1o][1j$=3c]{19:2.2H;1k:.21;1c:2.3q;-1a-16:1p(-1X);16:1p(-1X)}.13-25-3F{1S-2f:1l;1N:0 0 1.2x;2e:0;1J:3z;1T-3Y:69}.13-25-3F 7z{2B:6t-4b;2G:5o}.13-25-3F .13-25-2D{z-3Z:20;1c:2q;1E:2q;1x-2w:2q;1J:#6k;1u:#3Q;1o-1E:2q;3g-1S:1l}.13-25-3F .13-25-2D.13-3V-25-2D{1J:#6k}.13-25-3F .13-25-2D.13-3V-25-2D~.13-25-2D{1J:#8E;1u:#3Q}.13-25-3F .13-25-2D.13-3V-25-2D~.13-25-2D-1o{1J:#8E}.13-25-3F .13-25-2D-1o{z-3Z:10;1c:2.21;1E:.4u;1N:0 -3K;1J:#6k}[1j^=13]{-1a-el-em-1u:3v}.13-31{-1a-1L:13-31 .3s;1L:13-31 .3s}.13-31.13-6Q{-1a-1L:1Z;1L:1Z}.13-30{-1a-1L:13-30 .88 67;1L:13-30 .88 67}.13-30.13-6Q{-1a-1L:1Z;1L:1Z}.13-6M .13-3e{1k:1D;1g:0}.13-1Q-1f-1r .13-1f-1o-3h{-1a-1L:13-1Q-1f-1o-3h .4g;1L:13-1Q-1f-1o-3h .4g}.13-1Q-1f-1r .13-1f-1o-3c{-1a-1L:13-1Q-1f-1o-3c .4g;1L:13-1Q-1f-1o-3c .4g}.13-1Q-1f-1r .13-1f-35-1o-1k{-1a-1L:13-1p-1f-35-1o 4.8I 7g-2O;1L:13-1p-1f-35-1o 4.8I 7g-2O}.13-1Q-2n-1r{-1a-1L:13-1Q-2n-1r .5s;1L:13-1Q-2n-1r .5s}.13-1Q-2n-1r .13-x-2V{-1a-1L:13-1Q-2n-x-2V .5s;1L:13-1Q-2n-x-2V .5s}@-1a-2a 13-1p-2u{0%{-1a-16:1p(0);16:1p(0)}1F%{-1a-16:1p(5O);16:1p(5O)}}@2a 13-1p-2u{0%{-1a-16:1p(0);16:1p(0)}1F%{-1a-16:1p(5O);16:1p(5O)}}@6J eq{1e.13-1q:1M(.13-26-1P):1M(.13-1b-1q){3T-y:8D!3f}1e.13-1q:1M(.13-26-1P):1M(.13-1b-1q)>[2o-2L=4M]{2B:1Z}1e.13-1q:1M(.13-26-1P):1M(.13-1b-1q) .13-1h{2G:8O!3f}}");',0,895,"|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||swal2|function||transform|return|var|top|webkit|toast|width|this|body|success|left|container|input|class|right|center|document|concat|line|rotate|shown|icon||popup|color|bottom|if|border|Tt|content|typeof|null|flex|auto|height|100|scale|div|style|background|value|animation|not|margin|start|backdrop|animate|column|align|font|type|nt|625em|45deg|grow|none||5em|window|length||progress|no|end|translateY|target|keyframes|select|focus|Object|padding|items|for|textarea|customClass|size|get|file|125em|error|aria|justify|2em|box|range|rotateZ|loading|radio|radius|25em|it|opacity|checkbox|display|3125em|step|placeholder|actions|position|375em|title|styled|rt|hidden|new|confirmButton|in|setAttribute|disabled|inputValue|forEach|querySelector|timeout|mark|progressSteps|75em|yt|ms|hide|show|0625em||span|circular|Promise|appendChild|innerHTML|1875em|string|prototype|long|undefined|close|important|text|tip|case|validationMessage|innerParams|void|else|2deg|cancelButton|875em|9375em|key||indexOf|arguments|transparent|1em|getInput|button|inherit|createElement|rgba|footer|data|label|steps|then|shadow|parentNode|Swal|1px|running|modal|cancel|removeAttribute|ue|fff|domCache|to|overflow|ot|active|classList|contains|weight|index|tabindex|keydownListenerCapture|parameter|set|solid||output|Reflect|remaining|params|user|block|translateX|number|image|rotateX|75s|validation|405deg|before|direction|message|origin|confirm|object|absolute|question|default|moz|push|4em|getPropertyValue|querySelectorAll|normal|resolve|inputOptions|call|previousBodyPadding|parseInt|hideLoading|activeElement|className|keydownTarget|timer|break|4375em|max|_|true|inputerror|header|first|child|linear|DismissReason|preConfirm|getComputedStyle|ccc|getAttribute|stop|inputPlaceholder|apply||high|contrast|is||id|currentProgressStep|keys|previousActiveElement|setTimeout|documentElement|f27474|Qt|sweetalert2|showCancelButton|showConfirmButton|promise|WeakMap|Symbol|email|Expected|or|got|html|relative|st|Z0|sizing||zA|imageClass|titleText|Jt|toString|allowOutsideClick|delete|keydownHandler|outline|focusCancel|inputValidator|backgroundColor|freeze|checked|switch|info|warning|5625em|iosfix|row|confirmButtonColor|360deg|imageUrl|constructor|onchange|Date|inputClass|showCloseButton|onclick|tt|Pt|fire|resetValidationMessage|addEventListener|Lt|url||keydownHandlerAdded|||forwards|Unexpected|600|word|8em|Ft|wrap|previous|removeEventListener|scrollTop|preventDefault|of|customContainerClass|3085d6|showLoaderOnConfirm|gt|onmouseup|onBeforeOpen|onOpen|and|Dt|cursor|inline|transition|infinite|translate|enumerable|px|0s|writable|100deg|filter|1deg|Invalid|fix|ring|enableButtons|hasOwnProperty|media|_main|queue|rtl|cancelButtonColor|05|construct|noanimation|fade|fullscreen|dismiss|esc|hasAttribute|It|getConfirmButton|SweetAlert2|3em||remove|stretch|Nt|parseFloat|click|Array|initial|6em|2px|focusConfirm|reverseButtons|cancelButtonClass|stopPropagation|confirmButtonClass|allowEnterKey|ease|heightAuto|swalPromiseResolve|Zt|catch|keydown|min|capture|Mt|At|getTimerLeft|Bt|closeButton|Xt|imageWidth|te|imageAlt|childNodes|progressStepsDistance|li|test|https|all|removeChild|Ct|configurable|overflowY|requires|styleSheet|tel|throw|ie|Map|oninput|se|instanceof|a5dc86|pt|closePopup|150|disableButtons|Sweetalert2|showValidationMessage|buttonsStyling|update|borderRightColor||onmousedown|borderLeftColor|define||github|from|300|15s|try|kt|St|ft|splice|Unknown|showLoading|pointer|src|TypeError|hover|h2|imageHeight|offsetWidth|href|8125em|increase|innerText|isRunning|gradient|OK|closeButtonAriaLabel|Rt|scrollHeight|Cancel|paddingRight|ontouchstart|navigator|50px|mt|scroll|add8e6|busy|use|The|25s|jt|valid|defaulting|_t|Ot|static|restoreFocusTimeout|console|allowEscapeKey|zt|zoom|Wt|controls|resize|Kt|children|family|bind|duration||stopKeydownPropagation|setPrototypeOf||vt|confirmButtonText|confirmButtonAriaLabel|attributes|cancelButtonText|cancelButtonAriaLabel|name|isVisible|dialog|getPrototypeOf|__proto__|callback|started|clearTimeout|inputAutoTrim|password|3px|split|onAfterClose|hasn|onClose|scrollbarPadding|Vt|d9d9d9|qt|Ht|lt|isUpdatableParameter|ne|Boolean|argsToParams|cloneNode|finally|SweetAlert|clickConfirm|add|re|6875em|option|selected|wt|15px|self|been|defineProperties|com|inputAttributes|30px|enableConfirmButton|ut|disableConfirmButton|enableInput|disableInput|545454|blur|outerHTML|invalid|describedBy|getProgressSteps|const|swalInstance|getQueueStep|setProgressSteps|module|insertBefore|should|removeProperty|with|exports|Button|files|ul|symbol|isDeprecatedParameter|together|usage|example|nhttps|used|nshowLoaderOnConfirm|io|ajax|request|Target|||join|defined|trim|checkValidity|but|toasts|onmouseover|onmouseout|incompatible|hideProgressSteps|showProgressSteps|Enter|isComposing|Tab|shiftKey|ArrowLeft|ArrowRight|ArrowUp|ArrowDown|Left|Right|Up|Down|Escape|Esc|marginRight|Error|marginLeft|Updatable|are|listed|here|closeToast|blob|master|utils|js|closeModal|disableLoading|This|package|library|||||||||||please|include|shim|enable|browser|See|wiki||Migration||MSStream|support|userAgent|version|iPod|swal|sweetAlert|getElementsByTagName|head|iPhone|cssText|charset|UTF|iPad|URL|256|www|address|ontouchmove|tagName|INPUT|clientHeight|alignItems|offsetTop|documentMode|MSInputMethodContext|clientWidth|msMaxTouchPoints|innerHeight|isTimerRunning|increaseTimer|toggleTimer|resumeTimer|stopTimer|enableLoading|deleteQueueStep|insertQueueStep|create|either|must|expression|Super|mixin|isLoading|getValidationMessage|getFocusableElements|getFooter|getHeader|getCancelButton|getActions|getCloseButton|getIcons|getIcon|getImage|getContent|getTitle|getPopup|getContainer|clickCancel|see|isValidParameter||imageHeigth|Close|scrollTo|scrollY|scrollX|alt|starts|700|arrays|JS|like|than|less|textContent|basis|ButtonClass|ButtonAriaLabel|ButtonText|substring|showC|animationend|oanimationend|oAnimationEnd|OAnimation|webkitAnimationEnd|WebkitAnimation|nextSibling|assertive|polite|live|alert|role|initialize|has|replace|times|img|calc|10px|fixed|describedby|1060|scrolling|touch|labelledby|HTMLElement|32em|video|audio|1rem|contenteditable|595959|embed|iframe|area|sort|getClientRects|offsetHeight|46875em|warn|instead||Please|release|major|next|the|removed|after|will|5px|deprecated|999|slice|500|map|getOwnPropertyDescriptor|called|aaa|super|4px|inner|eee|initialised|ReferenceError|out|Function|serif|Proxy|sham|assign|inset|06|b4dbed|c4e6f5|defineProperty|10em|f0f0f0|666|supports|accelerator|prefix|facea8|f8bb86|9de0f6|3fc3ee|c9dae1|87adbd||arabic|0635em|165|220|134|Cannot|tap|highlight|iterator|strict|amd|print".split("|"),0,{}))},function(e,t,n){"use strict";function r(e,t){for(var n=0;n35?String.fromCharCode(e+29):e.toString(36))},!"".replace(/^/,String)){for(;n--;)a[o(n)]=r[n]||o(n);r=[function(e){return a[e]}],o=function(){return"\\w+"},n=1}for(;n--;)r[n]&&(e=e.replace(new RegExp("\\b"+o(n)+"\\b","g"),r[n]));return e}('(4(k,l){"4"===G V&&V.1Z?V(l):"21"===G 1z?2c.1z=l():k.2f=l()})(x,4(){4 k(a,b,d){7 ad?d:a}4 l(a,b,d){a="Q"===e.B?{W:"Q("+D*(-1+a)+"%,0,0)"}:"Y"===e.B?{W:"Y("+D*(-1+a)+"%,0)"}:{"1u-2b":D*(-1+a)+"%"};a.P="U "+b+"A "+d;7 a}4 q(a,b){7 0<=("2a"==G a?a:n(a)).24(" "+b+" ")}4 r(a,b){6 d=n(a),c=d+b;q(d,b)||(a.10=c.1o(1))}4 t(a,b){6 c=n(a);q(a,b)&&(b=c.H(" "+b+" "," "),a.10=b.1o(1,b.J-1))}4 n(a){7(" "+(a.10||"")+" ").H(/\\s+/1C," ")}6 c={1W:"0.2.0"},e=c.1V={1b:.1U,1e:"1Q",B:"",1g:1P,N:!0,1n:.1O,1p:1N,1t:!0,16:\'[S="11"]\',1B:\'[S="T"]\',C:"I",19:\'\'};c.1H=4(a){6 b;X(b 9 a){6 c=a[b];1h 0!==c&&a.1i(b)&&(e[b]=c)}7 x};c.j=1k;c.E=4(a){6 b=c.1m();a=k(a,e.1b,1);c.j=1===a?1k:a;6 d=c.1l(!b),p=d.F(e.16),h=e.1g,v=e.1e;d.1r;w(4(b){""===e.B&&(e.B=c.1s());m(p,l(a,h,v));1===a?(m(d,{P:"1D",1v:1}),d.1r,R(4(){m(d,{P:"U "+h+"A 1w",1v:0});R(4(){c.1x();b()},h)},h)):R(b,h)});7 x};c.1m=4(){7"1y"===G c.j};c.14=4(){c.j||c.E(0);6 a=4(){R(4(){c.j&&(c.N(),a())},e.1p)};e.N&&a();7 x};c.1A=4(a){7 a||c.j?c.15(.3+.5*13.12()).E(1):x};c.15=4(a){6 b=c.j;7 b?("1y"!==G a&&(a=(1-b)*k(13.12()*b,.1,.1E)),b=k(b+a,0,.1F),c.E(b)):c.14()};c.N=4(){7 c.15(13.12()*e.1n)};(4(){6 a=0,b=0;c.1G=4(d){y(!d||"1I"===d.1J())7 x;0===b&&c.14();a++;b++;d.1K(4(){b--;0===b?(a=0,c.1A()):c.E((a-b)/a)});7 x}})();c.1l=4(a){y(c.1d())7 8.Z("o");r(8.1j,"o-1f");6 b=8.1R("i");b.1S="o";b.1T=e.19;6 d=b.F(e.16),p=a?"-D":D*(-1+(c.j||0));a=8.F(e.C);m(d,{P:"U 0 1w",W:"Q("+p+"%,0,0)"});e.1t||(d=b.F(e.1B))&&d&&d.M&&d.M.1a(d);a!=8.I&&r(a,"o-17-C");a.1X(b);7 b};c.1x=4(){t(8.1j,"o-1f");t(8.F(e.C),"o-17-C");6 a=8.Z("o");a&&a&&a.M&&a.M.1a(a)};c.1d=4(){7!!8.Z("o")};c.1s=4(){6 a=8.I.L,b="1Y"9 a?"1c":"20"9 a?"18":"22"9 a?"A":"23"9 a?"O":"";7 b+"25"9 a?"Q":b+"26"9 a?"Y":"1u"};6 w=4(){4 a(){6 c=b.27();c&&c(a)}6 b=[];7 4(c){b.28(c);1==b.J&&a()}}(),m=4(){4 a(a){7 a.H(/^-A-/,"A-").H(/-([\\29-z])/1C,4(a,b){7 b.1q()})}4 b(b){b=a(b);6 d;y(!(d=e[b])){d=b;a:{6 u=8.I.L;y(!(b 9 u))X(6 h=c.J,f=b.2d(0).1q()+b.2e(1),g;h--;)y(g=c[h]+f,g 9 u){b=g;2g a}}d=e[d]=b}7 d}6 c=["1c","O","18","A"],e={};7 4(a,c){6 d=2h;y(2==d.J)X(g 9 c){6 e=c[g];y(1h 0!==e&&c.1i(g)){d=a;6 f=g;f=b(f);d.L[f]=e}}2i{6 g=a;f=d[1];d=d[2];f=b(f);g.L[f]=d}}}();7 c});',0,143,"||||function||var|return|document|in|||||||||div|status|||||nprogress|||||||||this|if||ms|positionUsing|parent|100|set|querySelector|typeof|replace|body|length|class|style|parentNode|trickle||transition|translate3d|setTimeout|role|spinner|all|define|transform|for|translate|getElementById|className|bar|random|Math|start|inc|barSelector|custom|Moz|template|removeChild|minimum|Webkit|isRendered|easing|busy|speed|void|hasOwnProperty|documentElement|null|render|isStarted|trickleRate|substring|trickleSpeed|toUpperCase|offsetWidth|getPositioningCSS|showSpinner|margin|opacity|linear|remove|number|exports|done|spinnerSelector|gi|none|95|994|promise|configure|resolved|state|always|icon|peg|800|02|200|ease|createElement|id|innerHTML|08|settings|version|appendChild|WebkitTransform|amd|MozTransform|object|msTransform|OTransform|indexOf|Perspective|Transform|shift|push|da|string|left|module|charAt|slice|NProgress|break|arguments|else".split("|"),0,{}))},function(module,__webpack_exports__,__webpack_require__){"use strict";function _typeof(e){return(_typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function _classCallCheck(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function _defineProperties(e,t){for(var n=0;n"));r.error(s.join("
"))}catch(e){}return}case 0:return}r.error(a||e.status+" "+n)}},{key:"handleJsonResponse",value:function handleJsonResponse(response,options){var Dcat=this.dcat,data=response.data;if(response){if("object"!==_typeof(response))return Dcat.error("error","Oops!");var then=function then(_then){switch(_then.action){case"refresh":Dcat.reload();break;case"download":window.open(_then.value,"_blank");break;case"redirect":Dcat.reload(_then.value||null);break;case"location":setTimeout((function(){_then.value?window.location=_then.value:window.location.reload()}),1e3);break;case"script":!function(){eval(_then.value)}()}};"string"==typeof response.html&&response.html&&options.target&&("function"==typeof options.html?options.html(options.target,response.html,response):$(target).html(response.html));var message=data.message||response.message;data.type||(data.type=response.status?"success":"error"),"string"==typeof message&&data.type&&message&&(data.alert?Dcat.swal[data.type](message,data.detail):Dcat[data.type](message,null,data.timeout?{timeOut:1e3*data.timeout}:{})),data.then&&then(data.then)}}}]),Ajax}()},,function(e,t,n){e.exports=n(13)},function(module,exports){var module={};eval(function(e,t,n,r,o,a){if(o=function(e){return(e<62?"":o(parseInt(e/62)))+((e%=62)>35?String.fromCharCode(e+29):e.toString(36))},!"".replace(/^/,String)){for(;n--;)a[o(n)]=r[n]||o(n);r=[function(e){return a[e]}],o=function(){return"\\w+"},n=1}for(;n--;)r[n]&&(e=e.replace(new RegExp("\\b"+o(n)+"\\b","g"),r[n]));return e}('!5(e){"5"==W 2y&&2y.6g?2y(["1Z"],e):"44"==W 2E&&2E.3W?2E.3W=5(t,r){6 R 0===r&&(r="6f"!=W Z?3F("1Z"):3F("1Z")(t)),e(r),r}:e(6e)}(5(e){"6d 6a";5 t(t){4 r=t.P;t.67()||(t.5Q(),e(t.1p).30("z").1a(r))}5 r(t){4 r=t.1p,a=e(r);7(!a.3I("[8=U],[8=1N]")){4 n=a.30("[8=U]");7(0===n.B)6;r=n[0]}4 i=r.z;7(i.1n=r,"1N"===r.8)7(R 0!==t.3G)i.1q=t.3G,i.1x=t.5O;16 7("5"==W e.J.42){4 o=a.42();i.1q=t.3g-o.3j,i.1x=t.3l-o.3p}16 i.1q=t.3g-r.5N,i.1x=t.3l-r.5L;1C(5(){i.1n=i.1q=i.1x=Q},2X)}5 a(){7(e.J.1a.3M){4 t="[1Z.z] "+1X.5K.5J.1h(1D,"");Z.2W&&Z.2W.33?Z.2W.33(t):Z.20&&Z.20.3i&&Z.20.3i(t)}}4 n=/\\r?\\n/g,i={};i.2V=R 0!==e(\'<1c 8="29">\').1Q(0).3A,i.3C=R 0!==Z.3E;4 o=!!e.J.2Q;e.J.1s=5(){7(!o)6 3.11.1f(3,1D);4 e=3.2Q.1f(3,1D);6 e&&e.1Z||"1J"==W e?e:3.11.1f(3,1D)},e.J.1a=5(t,r,n,s){5 u(r){4 a,n,i=e.1K(r,t.2O).32("&"),o=i.B,s=[];Y(a=0;a\',k).1z(f.I[c].G).2B(w)[0]):u.H(e(\'<1c 8="2C" 9="\'+c+\'">\',k).1z(f.I[c]).2B(w)[0]));f.2a||h.2B(D),v.34?v.34("35",s):v.36("38",s,!1),1C(t,15);1l{w.U()}1A(e){19.5w("z").U.1f(w)}}5r{w.1F("2c",i),w.1F("2d",o),r?w.1F("1p",r):p.3d("1p"),e(u).3e()}}5 s(t){7(!x.1b&&!X){7((O=n(v))||(a("2N 5q 5p 19"),t=L),t===A&&x)6 x.1m("1k"),R S.1P(x,"1k");7(t===L&&x)6 x.1m("3s 1m"),R S.1P(x,"V","3s 1m");7(O&&O.2A.2z!==f.1T||T){v.3B?v.3B("35",s):v.5o("38",s,!1);4 r,i="K";1l{7(T)5l"1k";4 o="1I"===f.1B||O.2u||e.5h(O);7(a("5g="+o),!o&&Z.20&&(Q===O.1G||!O.1G.3O)&&--C)6 a("49 5e 2t, 2r 2q 5d"),R 1C(s,5c);4 u=O.1G?O.1G:O.2k;x.18=u?u.3O:Q,x.1H=O.2u?O.2u:O,o&&(f.1B="1I"),x.2p=5(e){6{"2n-8":f.1B}[e.1u()]},u&&(x.17=37(u.2h("17"))||x.17,x.1j=u.2h("1j")||x.1j);4 c=(f.1B||"").1u(),l=/(2s|3b|2f)/.1o(c);7(l||f.1w){4 p=O.28("1w")[0];7(p)x.18=p.G,x.17=37(p.2h("17"))||x.17,x.1j=p.2h("1j")||x.1j;16 7(l){4 m=O.28("2w")[0],g=O.28("1G")[0];m?x.18=m.26?m.26:m.3Y:g&&(x.18=g.26?g.26:g.3Y)}}16"1I"===c&&!x.1H&&x.18&&(x.1H=q(x.18));1l{M=N(x,c,f)}1A(e){i="23",x.V=r=e||i}}1A(e){a("V 5a: ",e),i="V",x.V=r=e||i}x.1b&&(a("2g 1b"),i=Q),x.17&&(i=x.17>=58&&x.17<57||4Z===x.17?"K":"V"),"K"===i?(f.K&&f.K.1h(f.12,M,"K",x),S.4Y(x.18,"K",x),d&&e.1v.13("4U",[x,f])):i&&(R 0===r&&(r=x.1j),f.V&&f.V.1h(f.12,x,i,r),S.1P(x,"V",r),d&&e.1v.13("3v",[x,f,r])),d&&e.1v.13("4T",[x,f]),d&&!--e.2F&&e.1v.13("4P"),f.1t&&f.1t.1h(f.12,x,i),X=!0,f.1k&&31(j),1C(5(){f.2a?h.11("2o",f.1T):h.3e(),x.1H=Q},2X)}}}4 u,c,f,d,m,h,v,x,y,b,T,j,w=p[0],S=e.4N();7(S.1m=5(e){x.1m(e)},r)Y(c=0;c\',k)).4D({3N:"4C",3p:"-3P",3j:"-3P"}),v=h[0],x={1b:0,18:Q,1H:Q,17:0,1j:"n/a",4z:5(){},2p:5(){},4y:5(){},1m:5(t){4 r="1k"===t?"1k":"1b";a("4x 2g... "+r),3.1b=1;1l{v.1R.19.3R&&v.1R.19.3R("4w")}1A(e){}h.11("2o",f.1T),x.V=r,f.V&&f.V.1h(f.12,x,r,t),d&&e.1v.13("3v",[x,f,r]),f.1t&&f.1t.1h(f.12,x,r)}},(d=f.3T)&&0==e.2F++&&e.1v.13("4v"),d&&e.1v.13("4u",[x,f]),f.2e&&!1===f.2e.1h(f.12,x,f))6 f.3T&&e.2F--,S.1P(),S;7(x.1b)6 S.1P(),S;(y=w.1n)&&(b=y.9)&&!y.1g&&(f.I=f.I||{},f.I[b]=y.G,"1N"===y.8&&(f.I[b+".x"]=w.1q,f.I[b+".y"]=w.1x));4 A=1,L=2,F=e("3Z[9=40-4j]").11("2n"),E=e("3Z[9=40-1K]").11("2n");E&&F&&(f.I=f.I||{},f.I[E]=F),f.4i?i():1C(i,10);4 M,O,X,C=50,q=e.4f||5(e,t){6 Z.46?((t=21 46("4e.5f")).4a="48",t.4b(e)):t=(21 4c).4d(e,"2f/1I"),t&&t.2k&&"23"!==t.2k.47?t:Q},45=e.4g||5(e){6 Z.4h("("+e+")")},N=5(t,r,a){4 n=t.2p("2n-8")||"",i=("1I"===r||!r)&&n.2b("1I")>=0,o=i?t.1H:t.18;6 i&&"23"===o.2k.47&&e.V&&e.V("23"),a&&a.43&&(o=a.43(o,r)),"1J"==W o&&(("2s"===r||!r)&&n.2b("2s")>=0?o=45(o):("3b"===r||!r)&&n.2b("41")>=0&&e.4k(o)),o};6 S}7(!3.B)6 a("1a: 4l U 4m - 4n 4o 1y"),3;4 l,f,d,p=3;"5"==W t?t={K:t}:"1J"==W t||!1===t&&1D.B>0?(t={1d:t,P:r,1B:n},"5"==W s&&(t.K=s)):R 0===t&&(t={}),l=t.2G||t.8||3.1s("2G"),(d=(d="1J"==W(f=t.1d||3.1s("2c"))?e.4p(f):"")||Z.2A.2z||"")&&(d=(d.4q(/^([^#]+)/)||[])[1]),t=e.2M(!0,{1d:d,K:e.1O.K,8:l||e.1O.8,1T:/^4r/i.1o(Z.2A.2z||"")?"41:48":"4s:4t"},t);4 m={};7(3.13("z-2w-3V",[3,t,m]),m.3U)6 a("1a: U 3S 25 z-2w-3V 13"),3;7(t.2U&&!1===t.2U(3,t))6 a("1a: U 1b 25 2U 2t"),3;4 h=t.2O;R 0===h&&(h=e.1O.2O);4 v,g=[],x=3.2T(t.4A,g,t.4B);7(t.P){4 y=e.2S(t.P)?t.P(x):t.P;t.I=y,v=e.1K(y,h)}7(t.2R&&!1===t.2R(x,3,t))6 a("1a: U 1b 25 2R 2t"),3;7(3.13("z-U-3L",[x,3,t,m]),m.3U)6 a("1a: U 3S 25 z-U-3L 13"),3;4 b=e.1K(x,h);v&&(b=b?b+"&"+v:v),"4F"===t.8.4G()?(t.1d+=(t.1d.2b("?")>=0?"&":"?")+b,t.P=Q):t.P=b;4 T=[];7(t.1E&&T.H(5(){p.1E()}),t.2P&&T.H(5(){p.2P(t.4J)}),!t.1B&&t.1p){4 j=t.K||5(){};T.H(5(r,a,n){4 i=1D,o=t.4K?"3H":"4M";e(t.1p)[o](r).1i(5(){j.1f(3,i)})})}16 t.K&&(e.4O(t.K)?e.3y(T,t.K):T.H(t.K));7(t.K=5(e,r,a){Y(4 n=t.12||3,i=0,o=T.B;i0,D="2j/z-P",A=p.11("2d")===D||p.11("2I")===D,L=i.2V&&i.3C;a("4S :"+L);4 F,E=(k||A)&&!L;!1!==t.1U&&(t.1U||E)?t.3w?e.1Q(t.3w,5(){F=c(x)}):F=c(x):F=(k||A)&&L?5(r){Y(4 a=21 3E,n=0;n0)&&(n={1d:n,P:i,1B:o},"5"==W s&&(n.K=s)),n=n||{},n.2i=n.2i&&e.2S(e.J.1V),!n.2i&&0===3.B){4 u={s:3.1M,c:3.12};6!e.3K&&u.s?(a("2r 2q 3J, 5i 2H"),e(5(){e(u.s,u.c).2H(n)}),3):(a("5j; 5k 2v 5m 5n 1M"+(e.3K?"":" (2r 2q 3J)")),3)}6 n.2i?(e(19).2x("U.z-1e",3.1M,t).2x("2l.z-1e",3.1M,r).1V("U.z-1e",3.1M,n,t).1V("2l.z-1e",3.1M,n,r),3):3.3c().1V("U.z-1e",n,t).1V("2l.z-1e",n,r)},e.J.3c=5(){6 3.2x("U.z-1e 2l.z-1e")},e.J.2T=5(t,r,a){4 n=[];7(0===3.B)6 n;4 o,s=3[0],u=3.11("5s"),c=t||R 0===s.2v?s.28("*"):s.2v;7(c&&(c=e.5t(c)),u&&(t||/(5u|5v)\\//.1o(3a.39))&&(o=e(\':1c[z="\'+u+\'"]\').1Q()).B&&(c=(c||[]).5x(o)),!c||!c.B)6 n;e.2S(a)&&(c=e.5y(c,a));4 l,f,d,p,m,h,v;Y(l=0,h=c.B;l=t||n<0||b&&e-f>=i}function k(){var e=Date.now();if(y(e))return w(e);c=g(k,function(e){var n=e-f,r=t-(e-l);return b?Math.min(r,i-n):r}(e))}function w(e){return c=void 0,h&&o?m(e):(o=a=void 0,s)}function x(){var e=Date.now(),n=y(e);if(o=arguments,a=this,l=e,n){if(void 0===c)return v(l);if(b)return c=g(k,t),m(l)}return void 0===c&&(c=g(k,t)),s}return t=+t||0,d=r(u=n),null==u||"object"!==d&&"function"!==d||(p=!!n.leading,i=(b="maxWait"in n)?Math.max(+n.maxWait||0,t):t,h="trailing"in n?!!n.trailing:h),x.cancel=function(){void 0!==c&&clearTimeout(c),f=0,o=l=a=c=void 0},x.flush=function(){return void 0===c?s:w(Date.now())},x.pending=function(){return void 0!==c},x};function a(e){return(a="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function i(e,t){for(var n=0;ni?i:t,l=Math.ceil(c*(a/t));l=l>s?s:l,(n=n||e.split("/").pop()).length>50&&(n=n.substr(0,50)+"..."),layer.open({type:1,shade:.2,title:!1,maxmin:!1,shadeClose:!0,closeBtn:2,content:$(o),area:[c+"px",l+"px"],skin:"layui-layer-nobg",end:function(){document.body.removeChild(o)}})},o.onerror=function(){r.loading(!1),r.error(r.lang.trans("no_preview"))}}},{key:"asyncRender",value:function(e,t,n){var r=this.dcat;$.ajax(e).then((function(e){t(r.assets.resolveHtml(e,r.triggerReady).render())}),(function(e,t,o){if(n&&!1===n(e,t,o))return!1;r.handleAjaxError(e,t,o)}))}},{key:"loadFields",value:function(e,t){var n=[],r=[];t.values?"string"==typeof(r=t.values)&&(r=[r]):$(e).find("option:selected").each((function(){("0"===String(this.value)||this.value)&&r.push(this.value)})),r.length&&(t.fields.forEach((function(o,a){var i=$(e).closest(t.group).find("."+t.fields[a]);r.length&&n.push(function(e,n){Dcat.loading(),$.ajax(e).then((function(e){Dcat.loading(!1),n.find("option").remove(),$.map(e,(function(e){n.append(new Option(e[t.textField],e[t.idField],!1,!1))})),$(n).val(String(n.data("value")).split(",")).trigger("change")}))}(t.urls[a]+(t.urls[a].match(/\?/)?"&":"?")+"q="+r.join(","),i))})),$.when(n).then((function(){})))}}])&&i(t.prototype,n),r&&i(t,r),e}();function c(e){return(c="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function l(e,t){for(var n=0;n {message}
',redirect:!0,autoRemoveError:!0,before:function(){},after:function(){},success:function(){},error:function(){}},t),this.originalValues={},this.$form=$(this.options.form).first(),this._errColumns={},this.init()}var t,n,r;return t=e,(n=[{key:"init",value:function(){var e=this,t=e.options.confirm;if(!t.title)return e.submit();Dcat.confirm(t.title,t.content,(function(){e.submit()}))}},{key:"submit",value:function(){var e=this,t=e.$form,n=e.options,r=t.find('[type="submit"],.submit');e.removeErrors(),t.ajaxSubmit({data:{_token:Dcat.token},beforeSubmit:function(o,a,i){return!1!==n.before(o,a,i,e)&&!1!==U(H.before,o,a,i,e)&&!(n.validate&&(t.validator("validate"),t.find("."+n.errorClass).length>0))&&void r.buttonLoading()},success:function(t){setTimeout((function(){r.buttonLoading(!1)}),700),!1!==n.after(!0,t,e)&&!1!==n.success(t,e)&&!1!==U(H.success,t,e)&&(!1!==t.redirect&&n.redirect||t.data&&t.data.then&&(delete t.data.then,delete t.data.then,delete t.data.then),Dcat.handleJsonResponse(t))},error:function(o){if(r.buttonLoading(!1),!1!==n.after(!1,o,e)&&!1!==n.error(o,e)&&!1!==U(H.error,o,e))try{var a,i=JSON.parse(o.responseText);if(422!=o.status||!i||!Dcat.helpers.isset(i,"errors")){var s=o.responseJSON;return s&&s.message?Dcat.error(s.message):Dcat.error(o.status+" "+o.statusText)}for(a in i=i.errors,i)e._errColumns[a]=e.showError(t,a,i[a])}catch(e){return Dcat.error(o.status+" "+o.statusText)}}})}},{key:"showError",value:function(e,t,n){var r=this,o=r.queryFieldByName(e,t),a=o.closest(r.options.groupSelector);if(G(r,o).removeClass("d-none"),r.originalValues[t]=r.getFieldValue(o),o)return function(e){for(var t in a.addClass(r.options.errorClass),"string"==typeof e&&(e=[e]),e)a.find(r.options.errorContainerSelector).first().append(r.options.errorTemplate.replace("{message}",e[t]));r.options.validationErrorToastr&&Dcat.error(e.join("
"))}(n),r.options.autoRemoveError&&function(e,t,n){var r=function(){e.removeError(t,n)};t.one("change",r),t.off("blur",r).on("blur",(function(){e.isValueChanged(t,n)&&r()})),function o(){setTimeout((function(){if(t.length)return e.isValueChanged(t,n)?r():void o()}),500)}()}(r,o,t),o;Dcat.helpers.len(n)&&n.length&&Dcat.error(n.join(" \n "))}},{key:"getFieldValue",value:function(e){var t,n=[],r=e.attr("type"),o="checkbox"===r||"radio"===r;for(t=0;t")}function G(e,t){return N(e,t).find(".has-tab-error")}function U(e){var t,n,r,o=arguments,a=[];for(n in delete o[0],o=o||[])a.push(o[n]);for(t in e)if(!1===(r=e[t].apply(e[t],a)))return r}F.submitting=function(e){return"function"==typeof e&&H.before.push(e),this},F.submitted=function(e,t){return"function"==typeof e&&H.success.push(e),"function"==typeof t&&H.error.push(t),this},$.fn.form=function(e){var t=$(this);e=$.extend(e,{form:t}),t.on("submit",(function(){return!1})),t.find('[type="submit"],.submit').click((function(t){return Dcat.Form(e),!1}))};var J=F;function K(e,t){for(var n=0;n0)return!1;e.submitting=1,r.buttonLoading()},after:function(o,a){if(r.buttonLoading(!1),e.submitting=0,!1===t.saved(o,a))return!1;if(!o)return t.error(o,a);if(a.status){var i=t.success(o,a);return e._destroy(n),i}return t.error(o,a)}}),!1}}])&&K(t.prototype,n),r&&K(t,r),e}();function Q(e,t){for(var n=0;n'],X=function(){function e(t,n){!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),n=$.extend({container:t.config.pjax_container_selector,zIndex:100,width:"52px",color:t.color.dark60,background:"#fff",style:"",svg:W[0]},n);this.$container=$(n.container),$('
{svg}
'.replace("{svg}",n.svg).replace("{color}",n.color).replace("{color}",n.color).replace("{width}",n.width).replace("{style}","".concat("position:absolute;","background:").concat(n.background,";z-index:").concat(n.zIndex,";").concat(n.style))).appendTo(this.$container)}var t,n,r;return t=e,(n=[{key:"destroy",value:function(){this.$container.find(".dcat-loading").remove()}}])&&Q(t.prototype,n),r&&Q(t,r),e}();function Y(){$(".dcat-loading").remove()}var Z=function(e){e.loading=function(e){if(!1===e)return setTimeout(Y,70);e=$.extend({zIndex:999991014,width:"58px",shade:"rgba(255, 255, 255, 0.1)",background:"transparent",top:200,svg:W[0]},e);var t=$(window),n=$('
'),r=$('
');function o(){n.css({left:(t.width()-300)/2,top:(t.height()-e.top)/2})}n.appendTo("body"),e.shade&&r.appendTo("body"),t.on("resize",o),o(),n.loading(e)},$.fn.loading=function(t){return!1===t?$(this).find(".dcat-loading").remove():((t=t||{}).container=$(this),new X(e,t))},$.fn.buttonLoading=function(t){var n,r=$(this),o=r.attr("data-loading");if(!1===t)return o?(r.find(".waves-ripple").remove(),r.removeClass("disabled btn-loading waves-effect").removeAttr("disabled").removeAttr("data-loading").html(r.find("."+o).html())):r;if(o)return r;n=r.html(),o="ld-"+e.helpers.random();var a='',i=["btn","layui-layer-btn0","layui-layer-btn1"];for(var s in i)r.hasClass(i[s])&&(a=W[0].replace("{color}","currentColor").replace("{width}","50px;height:11px;"));return r.addClass("disabled btn-loading").attr("disabled",!0).attr("data-loading",o).html('\n\n").concat(a,"\n"))}};function ee(e,t){for(var n=0;n\n
\n'.replace("{id}",r.id).replace("{class}",r.options.class||"")),r.$container.appendTo("body"),r.$container.find(".slider-content").append(r.$target),new PerfectScrollbar("#".concat(r.id," .slider-content")),r.options.autoDestory&&t.onPjaxComplete((function(){r.destroy()}))}var t,n,r;return t=e,(n=[{key:"open",value:function(){this.$container.addClass("open")}},{key:"close",value:function(){this.$container.removeClass("open")}},{key:"toggle",value:function(){this.$container.toggleClass("open")}},{key:"destroy",value:function(){this.$container.remove()}}])&&ne(t.prototype,n),r&&ne(t,r),e}();function oe(e,t){for(var n=0;n255?255:e<0?0:e};t=t||0;var r=parseInt(e,16);return[n((r>>16)+t),n((r>>8&255)+t),n((255&r)+t)]}}])&&oe(t.prototype,n),r&&oe(t,r),e}();function ie(e,t){for(var n=0;n400?$(".scroll-top").fadeIn():$(".scroll-top").fadeOut()})),$(".scroll-top").click((function(){$("html, body").animate({scrollTop:0},1e3)}))}}])&&fe(t.prototype,n),r&&fe(t,r),e}();function be(e,t){for(var n=0;n35?String.fromCharCode(e+29):e.toString(36))},!"".replace(/^/,String)){for(;n--;)a[o(n)]=r[n]||o(n);r=[function(e){return a[e]}],o=function(){return"\\w+"},n=1}for(;n--;)r[n]&&(e=e.replace(new RegExp("\\b"+o(n)+"\\b","g"),r[n]));return e}('!14(t,e){"4o"==1A ac&&"3d"!=1A a7?a7.ac=e():"14"==1A 83&&83.ep?83(e):t.7V=e()}(1d,14(){"8G eo";14 f(t){17(f="14"==1A 5i&&"ag"==1A 5i.en?14(t){17 1A t}:14(t){17 t&&"14"==1A 5i&&t.5Q===5i&&t!==5i.3b?"ag":1A t})(t)}14 o(t,e){1w(!(t 7P e))7K 2M 8i("ek 4A a 1j as a 14")}14 i(t,e){2g(18 n=0;n\\n <1H 1j="\').1n(k.4O,\'">\\n \\n <1H 1j="\').1n(k.1r," ").1n(B.2n,\'">\\n <34 1j="13-x-2V"><34 1j="13-x-2V-1o-1g"><34 1j="13-x-2V-1o-1k">\\n \\n <1H 1j="\').1n(k.1r," ").1n(B.4q,\'">\\n <1H 1j="\').1n(k.1r," ").1n(B.5J,\'">\\n <1H 1j="\').1n(k.1r," ").1n(B.5I,\'">\\n <1H 1j="\').1n(k.1r," ").1n(B.1f,\'">\\n <1H 1j="13-1f-35-1o-1g">\\n <34 1j="13-1f-1o-3h"> <34 1j="13-1f-1o-3c">\\n <1H 1j="13-1f-6G"> <1H 1j="13-1f-6F">\\n <1H 1j="13-1f-35-1o-1k">\\n \\n \\n <8k 1j="\').1n(k.2I,\'" 55="\').1n(k.2I,\'">\\n <3y 1U="3y" 1j="\').1n(k.3e,\'">&d3;\\n \\n <1H 1j="\').1n(k.1z,\'">\\n <1H 55="\').1n(k.1z,\'">\\n <1i 1j="\').1n(k.1i,\'" />\\n <1i 1U="2l" 1j="\').1n(k.2l,\'" />\\n <1H 1j="\').1n(k.2s,\'">\\n <1i 1U="2s" />\\n <46>\\n \\n <2b 1j="\').1n(k.2b,\'">\\n <1H 1j="\').1n(k.2v,\'">\\n <3E 2g="\').1n(k.2A,\'" 1j="\').1n(k.2A,\'">\\n <1i 1U="2A" />\\n <34 1j="\').1n(k.3E,\'">\\n \\n <2h 1j="\').1n(k.2h,\'">\\n <1H 1j="\').1n(k["4h-4l"],\'" 55="\').1n(k["4h-4l"],\'">\\n \\n <1H 1j="\').1n(k.2F,\'">\\n <3y 1U="3y" 1j="\').1n(k.4n,\'">8t\\n <3y 1U="3y" 1j="\').1n(k.3N,\'">8x\\n \\n <1H 1j="\').1n(k.3C,\'">\\n \\n \\n\').d2(/(^|\\n)\\s*/g,""),ct=14(t){1w(14(){18 t=q();t&&(t.3I.7D(t),3U([1m.5a,1m.1e],[k["26-1P"],k["1b-1q"],k["d1-1R"]]))}(),X())g("6Y 7H 1m 3S d0");3m{18 e=1m.3A("1H");e.4F=k.1h,e.38=9T;18 n=14(t){17"3a"==1A t?1m.2T(t):t}(t.29);n.37(e),14(t){18 e=2K();e.2P("cZ",t.1b?"cY":"9e"),e.2P("2o-cX",t.1b?"cW":"cV"),t.1b||e.2P("2o-3M","4M")}(t),14(t){"6M"===22.4U(t).4k&&1V(q(),k.6M)}(n),14(){18 t=U(),e=2y(t,k.1i),n=2y(t,k.2l),o=t.2T(".".1n(k.2s," 1i")),i=t.2T(".".1n(k.2s," 46")),r=2y(t,k.2b),a=t.2T(".".1n(k.2A," 1i")),s=2y(t,k.2h);e.7N=G,n.5R=G,r.5R=G,a.5R=G,s.7N=G,o.7N=14(t){G(t),i.1K=o.1K},o.5R=14(t){G(t),o.cU.1K=o.1K}}()}},9w=14(t,e){1w(t.38="",0 2O e)2g(18 n=0;n 2O e;n++)t.37(e[n].9B(!0));3m t.37(e.9B(!0))},dt=14(){1w(X())17!1;18 t=1m.3A("1H"),e={cT:"cS",cR:"cQ cP",1L:"cO"};2g(18 n 2O e)1w(e.6I(n)&&3l 0!==t.1I[n])17 e[n];17!1}();14 7R(t,e,n){M(t,n["cN"+e.cM(1)+"ad"],"6t-4b"),t.38=n[e+"cL"],t.2P("2o-3E",n[e+"cK"]),t.4F=k[e],b(t,n.2i,e+"ad"),1V(t,n[e+"cJ"])}14 8c(t,e){18 n=Z(),o=K(),i=F();e.5f||e.5e?T(n):O(n),b(n,e.2i,"2F"),7R(o,"4n",e),7R(i,"3N",e),e.7X?14(t,e,n){1V([t,e],k.2J),n.5N&&(t.1I.5E=n.5N),n.6N&&(e.1I.5E=n.6N);18 o=22.4U(t).4v("1J-1u");t.1I.82=o,t.1I.7Z=o}(o,i,e):(3U([o,i],k.2J),o.1I.5E=o.1I.82=o.1I.7Z="",i.1I.5E=i.1I.82=i.1I.7Z="")}14 8C(t,e){18 n=q();n&&(14(t,e){"3a"==1A e?t.1I.1J=e:e||1V([1m.5a,1m.1e],k["26-1P"])}(n,e.1P),!e.1P&&e.5y&&y(\'"5y" 42 7H `1P` 42 3S be 43 3S `4M`\'),14(t,e){e 2O k?1V(t,k[e]):(y(\'8H "2G" 42 53 1M 8K, 8L 3S "1l"\'),1V(t,k.1l))}(n,e.2G),14(t,e){1w(e&&"3a"==1A e){18 n="1Y-"+e;n 2O k&&1V(t,k[n])}}(n,e.1Y),b(n,e.2i,"1h"),e.6j&&1V(n,e.6j))}14 6m(t,e){t.2E&&!e.4Y||(t.2E=e.4Y)}18 bb={5g:2M 5h,3k:2M 5h,3R:2M 5h},96=14(t,e){18 n=P(U(),t);1w(n)2g(18 o 2O 14(t){2g(18 e=0;e=i.2W.23&&y("6E 56 42, 2y a9 be cG cF 2W.23 (56 cE cD cC cA 86 0)"),i.2W.2S(14(t,e){18 n=14(t){18 e=1m.3A("7z");17 1V(e,k["25-2D"]),e.38=t,e}(t);1w(r.37(n),e===a&&1V(n,k["3V-25-2D"]),e!==i.2W.23-1){18 o=14(t){18 e=1m.3A("7z");17 1V(e,k["25-2D-1o"]),t.7y&&(e.1I.1c=t.7y),e}(t);r.37(o)}})}14 8a(t,e){18 n=Q();b(n,e.2i,"4O"),7E(0,e),14(t,e){18 n=bb.3k.2k(t);1w(n&&e.1U===n.1U&&N())b(N(),e.2i,"1r");3m 1w(bc(),e.1U)1w(8b(),-1!==2d.57(B).3t(e.1U)){18 o=H(".".1n(k.1r,".").1n(B[e.1U]));T(o),b(o,e.2i,"1r"),L(o,"13-1Q-".1n(e.1U,"-1r"),e.1L)}3m g(\'8e 1U! 5k "1f", "2n", "5J", "5I" 5l "4q", 5m "\'.1n(e.1U,\'"\'))}(t,e),14(t,e){18 n=4L();1w(!e.5P)17 O(n);T(n),n.2P("8h",e.5P),n.2P("cz",e.7w),E(n,"1c",e.7u),E(n,"1E",e.8l),n.4F=k.4e,b(n,e.2i,"4e"),e.5u&&1V(n,e.5u)}(0,e),14(t,e){18 n=D();M(n,e.2I||e.5v),e.2I&&5W(e.2I,n),e.5v&&(n.8q=e.5v),b(n,e.2i,"2I")}(0,e),14(t,e){18 n=$();b(n,e.2i,"7s"),M(n,e.5U),n.2P("2o-3E",e.8u)}(0,e)}14 7r(t,e){!14(t,e){18 n=2K();E(n,"1c",e.1c),E(n,"2e",e.2e),e.1J&&(n.1I.1J=e.1J),n.4F=k.1t,e.1b?(1V([1m.5a,1m.1e],k["1b-1q"]),1V(n,k.1b)):1V(n,k.3M),b(n,e.2i,"1t"),"3a"==1A e.2i&&1V(n,e.2i),L(n,k.6Q,!e.1L)}(0,e),8C(0,e),8a(t,e),9K(t,e),8c(0,e),14(t,e){18 n=Y();M(n,e.3C),e.3C&&5W(e.3C,n),b(n,e.2i,"3C")}(0,e)}18 bc=14(){2g(18 t=R(),e=0;e22.bW&&(x.4B=4C(22.4U(1m.1e).4v("2e-1k")),1m.1e.1I.8y=x.4B+14(){1w("8z"2O 22||8A.bV)17 0;18 t=1m.3A("1H");t.1I.1c="8B",t.1I.1E="8B",t.1I.3T="8D",1m.1e.37(t);18 e=t.8m-t.bU;17 1m.1e.7D(t),e}()+"6y")}14 73(){17!!22.bT&&!!1m.bS}14 6r(){18 t=q(),e=2K();t.1I.aa("1S-2f"),e.bR<0&&(t.1I.bQ="1C-1O")}18 be=14(){1B!==x.4B&&(1m.1e.1I.8y=x.4B+"6y",x.4B=1B)},8M=14(){18 e,n=q();n.8z=14(t){e=t.29===n||!14(t){17!!(t.8w>t.bP)}(n)&&"bO"!==t.29.bN},n.bM=14(t){e&&(t.6h(),t.7d())}},8S=14(){1w(S(1m.1e,k.5L)){18 t=4C(1m.1e.1I.19,10);3U(1m.1e,k.5L),1m.1e.1I.19="",1m.1e.6g=-1*t}},8U=14(){"3d"!=1A 22&&73()&&22.6f("8W",6r)},8X=14(){m(1m.1e.8Y).2S(14(t){t.6V("3D-6e-2o-2L")?(t.2P("2o-2L",t.4W("3D-6e-2o-2L")),t.3O("3D-6e-2o-2L")):t.3O("2o-2L")})},6c={7i:2M 5h};14 7j(t,e,n){e?$t(n):(8N().3G(14(){17 $t(n)}),1y.4G.6f("7l",1y.5A,{7n:1y.41}),1y.64=!1),5z 1y.5A,5z 1y.4G,t.3I&&t.3I.7D(t),3U([1m.5a,1m.1e],[k.1q,k["1E-1D"],k["26-1P"],k["1b-1q"],k["1b-1R"]]),at()&&(be(),8S(),8U(),8X())}14 5c(t){18 e=q(),n=2K();1w(n&&!S(n,k.30)){18 o=bb.3k.2k(1d),i=6c.7i.2k(1d),r=o.9q,a=o.9o;3U(n,k.31),1V(n,k.30),dt&&j(n)?n.60(dt,14(t){t.29===n&&14(t,e,n,o){S(t,k.30)&&7j(e,n,o),bf(bb),bf(6c)}(n,e,5p(),a)}):7j(e,5p(),a),1B!==r&&"14"==1A r&&r(n),i(t||{}),5z 1d.49}}18 bf=14(t){2g(18 e 2O t)t[e]=2M 5h},$t=14(t){1B!==t&&"14"==1A t&&59(14(){t()})};14 5w(t,e,n){18 o=bb.3R.2k(t);e.2S(14(t){o[t].2Q=n})}14 7t(t,e){1w(!t)17!1;1w("2v"===t.1U)2g(18 n=t.3I.3I.4w("1i"),o=0;o"));18 t=2K(),n="3a"==1A e.29?1m.2T(e.29):e.29;(!t||t&&n&&t.3I!==n.3I)&&ct(e)}(l),2d.5F(l),1y.2U&&(1y.2U.4X(),5z 1y.2U),9j(1y.8P);18 d={1t:2K(),1h:q(),1z:U(),2F:Z(),2N:K(),3o:F(),7s:$(),3j:W(),2W:z()};bb.3R.43(1d,d),7r(1d,l),bb.3k.43(1d,l);18 p=1d.5Q;17 2M 36(14(t){14 n(t){c.7S({1K:t})}14 s(t){c.7S({6T:t})}6c.7i.43(c,t),l.4H&&(1y.2U=2M bg(14(){s("4H"),5z 1y.2U},l.4H));l.1i&&59(14(){18 t=c.3x();t&&A(t)},0);2g(18 u=14(e){(l.6l&&p.8f(),l.4T)?(c.5Z(),36.4y().3G(14(){17 l.4T(e,l.3j)}).3G(14(t){V(d.3j)||!1===t?c.4D():n(3l 0===t?e:t)})):n(e)},e=14(t){18 e=t.29,n=d.2N,o=d.3o,i=n&&(n===e||n.3X(e)),r=o&&(o===e||o.3X(e));5H(t.1U){3i"75":1w(i)1w(c.7U(),l.1i){18 a=14(){18 t=c.3x();1w(!t)17 1B;5H(l.1i){3i"2A":17 t.5G?1:0;3i"2v":17 t.5G?t.1K:1B;3i"2l":17 t.ae.23?t.ae[0]:1B;4r:17 l.9k?t.1K.aw():t.1K}}();1w(l.5D)c.9W(),36.4y().3G(14(){17 l.5D(a,l.3j)}).3G(14(t){c.6H(),c.9V(),t?c.7W(t):u(a)});3m c.3x().ax()?u(a):(c.6H(),c.7W(l.3j))}3m u(!0);3m r&&(c.7U(),s(p.4S.3N))}},o=d.1t.4w("3y"),i=0;i.13-3M{2r-3H:0 0 d6 3B(0,0,0,.4)}1e.13-26-1P .13-1q.13-19{19:0;1g:50%;-1a-16:4c(-50%);16:4c(-50%)}1e.13-26-1P .13-1q.13-19-1g,1e.13-26-1P .13-1q.13-19-1O{19:0;1g:0}1e.13-26-1P .13-1q.13-19-27,1e.13-26-1P .13-1q.13-19-1k{19:0;1k:0}1e.13-26-1P .13-1q.13-1l{19:50%;1g:50%;-1a-16:6w(-50%,-50%);16:6w(-50%,-50%)}1e.13-26-1P .13-1q.13-1l-1g,1e.13-26-1P .13-1q.13-1l-1O{19:50%;1g:0;-1a-16:28(-50%);16:28(-50%)}1e.13-26-1P .13-1q.13-1l-27,1e.13-26-1P .13-1q.13-1l-1k{19:50%;1k:0;-1a-16:28(-50%);16:28(-50%)}1e.13-26-1P .13-1q.13-1v{1v:0;1g:50%;-1a-16:4c(-50%);16:4c(-50%)}1e.13-26-1P .13-1q.13-1v-1g,1e.13-26-1P .13-1q.13-1v-1O{1v:0;1g:0}1e.13-26-1P .13-1q.13-1v-27,1e.13-26-1P .13-1q.13-1v-1k{1k:0;1v:0}.13-1h{2B:1C;2G:d7;z-3Z:d9;19:0;1k:0;1v:0;1g:0;1C-4k:5M;1S-2f:1l;2p-1z:1l;2e:.1W;3T-x:2L;1J-1u:3v;-1a-3T-da:db}.13-1h.13-19{1S-2f:1C-1O}.13-1h.13-19-1g,.13-1h.13-19-1O{1S-2f:1C-1O;2p-1z:1C-1O}.13-1h.13-19-27,.13-1h.13-19-1k{1S-2f:1C-1O;2p-1z:1C-27}.13-1h.13-1l{1S-2f:1l}.13-1h.13-1l-1g,.13-1h.13-1l-1O{1S-2f:1l;2p-1z:1C-1O}.13-1h.13-1l-27,.13-1h.13-1l-1k{1S-2f:1l;2p-1z:1C-27}.13-1h.13-1v{1S-2f:1C-27}.13-1h.13-1v-1g,.13-1h.13-1v-1O{1S-2f:1C-27;2p-1z:1C-1O}.13-1h.13-1v-27,.13-1h.13-1v-1k{1S-2f:1C-27;2p-1z:1C-27}.13-1h.13-1v-27>:4P-4Q,.13-1h.13-1v-1g>:4P-4Q,.13-1h.13-1v-1k>:4P-4Q,.13-1h.13-1v-1O>:4P-4Q,.13-1h.13-1v>:4P-4Q{1N-19:1D}.13-1h.13-1Y-6S>.13-3M{2B:1C!3f;1C:1;1S-9M:72;2p-1z:1l}.13-1h.13-1Y-5M>.13-3M{2B:1C!3f;1C:1;1S-1z:1l;2p-1z:1l}.13-1h.13-1Y-1R{1C:1;1C-4k:1R}.13-1h.13-1Y-1R.13-1v,.13-1h.13-1Y-1R.13-1l,.13-1h.13-1Y-1R.13-19{1S-2f:1l}.13-1h.13-1Y-1R.13-1v-1g,.13-1h.13-1Y-1R.13-1v-1O,.13-1h.13-1Y-1R.13-1l-1g,.13-1h.13-1Y-1R.13-1l-1O,.13-1h.13-1Y-1R.13-19-1g,.13-1h.13-1Y-1R.13-19-1O{1S-2f:1C-1O}.13-1h.13-1Y-1R.13-1v-27,.13-1h.13-1Y-1R.13-1v-1k,.13-1h.13-1Y-1R.13-1l-27,.13-1h.13-1Y-1R.13-1l-1k,.13-1h.13-1Y-1R.13-19-27,.13-1h.13-1Y-1R.13-19-1k{1S-2f:1C-27}.13-1h.13-1Y-1R>.13-3M{2B:1C!3f;1C:1;1S-1z:1l;2p-1z:1l}.13-1h:1M(.13-19):1M(.13-19-1O):1M(.13-19-27):1M(.13-19-1g):1M(.13-19-1k):1M(.13-1l-1O):1M(.13-1l-27):1M(.13-1l-1g):1M(.13-1l-1k):1M(.13-1v):1M(.13-1v-1O):1M(.13-1v-27):1M(.13-1v-1g):1M(.13-1v-1k):1M(.13-1Y-6S)>.13-3M{1N:1D}@6J 7C 6q (-2Z-51-52:1Z),(-2Z-51-52:3V){.13-1h .13-3M{1N:0!3f}}.13-1h.13-6R{6u:1J-1u .1s}.13-1h.13-1q{1J-1u:3B(0,0,0,.4)}.13-1t{2B:1Z;2G:5o;2r-5r:1x-2r;1C-4k:1R;2p-1z:1l;1c:de;4K-1c:1F%;2e:1.2x;1x:1Z;1x-2w:.2C;1J:#3Q;1T-8Z:3z;1T-2j:dh}.13-1t:2c{5B:0}.13-1t.13-2u{3T-y:2L}.13-4O{2B:1C;1C-4k:1R;1S-2f:1l}.13-2I{2G:5o;4K-1c:1F%;1N:0 0 .4u;2e:0;1u:#dj;1T-2j:1.3p;1T-3Y:69;3g-1S:1l;3g-16:1Z;6a-6d:4I-6a}.13-2F{z-3Z:1;1C-6d:6d;1S-2f:1l;2p-1z:1l;1c:1F%;1N:1.2x 1D 0}.13-2F:1M(.13-2u) .13-2J[2Q]{2z:.4}.13-2F:1M(.13-2u) .13-2J:8j{1J-4e:4R-8s(3B(0,0,0,.1),3B(0,0,0,.1))}.13-2F:1M(.13-2u) .13-2J:3V{1J-4e:4R-8s(3B(0,0,0,.2),3B(0,0,0,.2))}.13-2F.13-2u .13-2J.13-4n{2r-5r:1x-2r;1c:2.21;1E:2.21;1N:.dq;2e:0;-1a-1L:13-1p-2u 1.5s 4R 6z 6v 4x;1L:13-1p-2u 1.5s 4R 6z 6v 4x;1x:.2x 44 3v;1x-2w:1F%;1x-1u:3v;1J-1u:3v!3f;1u:3v;6s:4r;-1a-4a-2b:1Z;-4s-4a-2b:1Z;-2Z-4a-2b:1Z;4a-2b:1Z}.13-2F.13-2u .13-2J.13-3N{1N-1k:9R;1N-1g:9R}.13-2F.13-2u :1M(.13-2J).13-4n::dA{1z:\\"\\";2B:6t-4b;1c:9L;1E:9L;1N-1g:dC;-1a-1L:13-1p-2u 1.5s 4R 6z 6v 4x;1L:13-1p-2u 1.5s 4R 6z 6v 4x;1x:9m 44 #dE;1x-2w:50%;1x-1k-1u:3v;2r-3H:3K 3K 3K #3Q}.13-2J{1N:.2C;2e:.1W 2q;2r-3H:1Z;1T-3Y:dG}.13-2J:1M([2Q]){6s:8g}.13-2J.13-4n{1x:0;1x-2w:.2x;1J:77;1J-1u:#6k;1u:#3Q;1T-2j:1.32}.13-2J.13-3N{1x:0;1x-2w:.2x;1J:77;1J-1u:#dK;1u:#3Q;1T-2j:1.32}.13-2J:2c{5B:0;2r-3H:0 0 0 79 #3Q,0 0 0 dM 3B(50,1F,7T,.4)}.13-2J::-4s-2c-dN{1x:0}.13-3C{2p-1z:1l;1N:1.2x 0 0;2e:3w 0 0;1x-19:3K 44 #dO;1u:#9X;1T-2j:3w}.13-4e{4K-1c:1F%;1N:1.2x 1D}.13-3e{2G:4p;19:0;1k:0;2p-1z:1l;1c:1.2q;1E:1.2q;2e:0;3T:2L;6u:1u .1s 7g-dR;1x:1Z;1x-2w:0;5B:77;1J:0 0;1u:#4V;1T-8Z:dT;1T-2j:2.21;1o-1E:1.2;6s:8g}.13-3e:8j{-1a-16:1Z;16:1Z;1J:0 0;1u:#5b}.13-1z{z-3Z:1;2p-1z:1l;1N:0;2e:0;1u:#9X;1T-2j:1.2m;1T-3Y:87;1o-1E:4x;6a-6d:4I-6a}#13-1z{3g-1S:1l}.13-2A,.13-2l,.13-1i,.13-2v,.13-2b,.13-2h{1N:3w 1D}.13-2l,.13-1i,.13-2h{2r-5r:1x-2r;1c:1F%;6u:1x-1u .3s,2r-3H .3s;1x:3K 44 #9t;1x-2w:.39;1J:3z;2r-3H:dX 0 3K 3K 3B(0,0,0,.dY);1u:3z;1T-2j:1.2m}.13-2l.13-4N,.13-1i.13-4N,.13-2h.13-4N{1x-1u:#5b!3f;2r-3H:0 0 79 #5b!3f}.13-2l:2c,.13-1i:2c,.13-2h:2c{1x:3K 44 #dZ;5B:0;2r-3H:0 0 9m #e0}.13-2l::-1a-1i-2E,.13-1i::-1a-1i-2E,.13-2h::-1a-1i-2E{1u:#4V}.13-2l::-4s-2E,.13-1i::-4s-2E,.13-2h::-4s-2E{1u:#4V}.13-2l:-2Z-1i-2E,.13-1i:-2Z-1i-2E,.13-2h:-2Z-1i-2E{1u:#4V}.13-2l::-2Z-1i-2E,.13-1i::-2Z-1i-2E,.13-2h::-2Z-1i-2E{1u:#4V}.13-2l::2E,.13-1i::2E,.13-2h::2E{1u:#4V}.13-2s{1N:3w 1D;1J:3z}.13-2s 1i{1c:80%}.13-2s 46{1c:20%;1u:3z;1T-3Y:69;3g-1S:1l}.13-2s 1i,.13-2s 46{1E:2.1W;2e:0;1T-2j:1.2m;1o-1E:2.1W}.13-1i{1E:2.1W;2e:0 .2X}.13-1i[1U=4d]{4K-1c:e2}.13-2l{1J:3z;1T-2j:1.2m}.13-2h{1E:6.2X;2e:.2X}.13-2b{7m-1c:50%;4K-1c:1F%;2e:.2H .1W;1J:3z;1u:3z;1T-2j:1.2m}.13-2A,.13-2v{1S-2f:1l;2p-1z:1l;1J:3z;1u:3z}.13-2A 3E,.13-2v 3E{1N:0 .78;1T-2j:1.2m}.13-2A 1i,.13-2v 1i{1N:0 .4u}.13-4h-4l{2B:1Z;1S-2f:1l;2p-1z:1l;2e:.1W;3T:2L;1J:#e3;1u:#e4;1T-2j:3w;1T-3Y:87}.13-4h-4l::4j{1z:\\"!\\";2B:6t-4b;1c:1.21;7m-1c:1.21;1E:1.21;1N:0 .1W;8T:4x;1x-2w:50%;1J-1u:#5b;1u:#3Q;1T-3Y:69;1o-1E:1.21;3g-1S:1l}@e5 (-2Z-e6:4M){.13-2s 1i{1c:1F%!3f}.13-2s 46{2B:1Z}}@6J 7C 6q (-2Z-51-52:1Z),(-2Z-51-52:3V){.13-2s 1i{1c:1F%!3f}.13-2s 46{2B:1Z}}@-4s-1m 62-e7(){.13-3e:2c{5B:79 44 3B(50,1F,7T,.4)}}.13-1r{2G:5o;2r-5r:1z-2r;2p-1z:1l;1c:21;1E:21;1N:1.2x 1D 1.3p;8T:4x;1x:.2x 44 3v;1x-2w:50%;1o-1E:21;6s:4r;-1a-4a-2b:1Z;-4s-4a-2b:1Z;-2Z-4a-2b:1Z;4a-2b:1Z}.13-1r::4j{2B:1C;1S-2f:1l;1E:92%;1T-2j:3.2X}.13-1r.13-2n{1x-1u:#5b}.13-1r.13-2n .13-x-2V{2G:5o;1C-1Y:1}.13-1r.13-2n [1j^=13-x-2V-1o]{2B:4b;2G:4p;19:2.2C;1c:2.3q;1E:.2C;1x-2w:.2m;1J-1u:#5b}.13-1r.13-2n [1j^=13-x-2V-1o][1j$=1g]{1g:1.32;-1a-16:1p(1X);16:1p(1X)}.13-1r.13-2n [1j^=13-x-2V-1o][1j$=1k]{1k:3w;-1a-16:1p(-1X);16:1p(-1X)}.13-1r.13-5J{1x-1u:#e8;1u:#e9}.13-1r.13-5J::4j{1z:\\"!\\"}.13-1r.13-5I{1x-1u:#ea;1u:#eb}.13-1r.13-5I::4j{1z:\\"i\\"}.13-1r.13-4q{1x-1u:#ec;1u:#ed}.13-1r.13-4q::4j{1z:\\"?\\"}.13-1r.13-4q.13-ef-4q-2V::4j{1z:\\"؟\\"}.13-1r.13-1f{1x-1u:#7Q}.13-1r.13-1f [1j^=13-1f-35-1o]{2G:4p;1c:3.2X;1E:7.21;-1a-16:1p(1X);16:1p(1X);1x-2w:50%}.13-1r.13-1f [1j^=13-1f-35-1o][1j$=1g]{19:-.4J;1g:-2.eg;-1a-16:1p(-1X);16:1p(-1X);-1a-16-4m:3.2X 3.2X;16-4m:3.2X 3.2X;1x-2w:7.21 0 0 7.21}.13-1r.13-1f [1j^=13-1f-35-1o][1j$=1k]{19:-.9H;1g:1.3p;-1a-16:1p(-1X);16:1p(-1X);-1a-16-4m:0 3.2X;16-4m:0 3.2X;1x-2w:0 7.21 7.21 0}.13-1r.13-1f .13-1f-6G{2G:4p;z-3Z:2;19:-.2x;1g:-.2x;2r-5r:1z-2r;1c:1F%;1E:1F%;1x:.2x 44 3B(eh,ei,ej,.3);1x-2w:50%}.13-1r.13-1f .13-1f-6F{2G:4p;z-3Z:1;19:.21;1g:1.1W;1c:.4J;1E:5.1W;-1a-16:1p(-1X);16:1p(-1X)}.13-1r.13-1f [1j^=13-1f-1o]{2B:4b;2G:4p;z-3Z:2;1E:.2C;1x-2w:.2m;1J-1u:#7Q}.13-1r.13-1f [1j^=13-1f-1o][1j$=3h]{19:2.3p;1g:.3p;1c:1.5K;-1a-16:1p(1X);16:1p(1X)}.13-1r.13-1f [1j^=13-1f-1o][1j$=3c]{19:2.2H;1k:.21;1c:2.3q;-1a-16:1p(-1X);16:1p(-1X)}.13-25-3F{1S-2f:1l;1N:0 0 1.2x;2e:0;1J:3z;1T-3Y:69}.13-25-3F 7z{2B:6t-4b;2G:5o}.13-25-3F .13-25-2D{z-3Z:20;1c:2q;1E:2q;1x-2w:2q;1J:#6k;1u:#3Q;1o-1E:2q;3g-1S:1l}.13-25-3F .13-25-2D.13-3V-25-2D{1J:#6k}.13-25-3F .13-25-2D.13-3V-25-2D~.13-25-2D{1J:#8E;1u:#3Q}.13-25-3F .13-25-2D.13-3V-25-2D~.13-25-2D-1o{1J:#8E}.13-25-3F .13-25-2D-1o{z-3Z:10;1c:2.21;1E:.4u;1N:0 -3K;1J:#6k}[1j^=13]{-1a-el-em-1u:3v}.13-31{-1a-1L:13-31 .3s;1L:13-31 .3s}.13-31.13-6Q{-1a-1L:1Z;1L:1Z}.13-30{-1a-1L:13-30 .88 67;1L:13-30 .88 67}.13-30.13-6Q{-1a-1L:1Z;1L:1Z}.13-6M .13-3e{1k:1D;1g:0}.13-1Q-1f-1r .13-1f-1o-3h{-1a-1L:13-1Q-1f-1o-3h .4g;1L:13-1Q-1f-1o-3h .4g}.13-1Q-1f-1r .13-1f-1o-3c{-1a-1L:13-1Q-1f-1o-3c .4g;1L:13-1Q-1f-1o-3c .4g}.13-1Q-1f-1r .13-1f-35-1o-1k{-1a-1L:13-1p-1f-35-1o 4.8I 7g-2O;1L:13-1p-1f-35-1o 4.8I 7g-2O}.13-1Q-2n-1r{-1a-1L:13-1Q-2n-1r .5s;1L:13-1Q-2n-1r .5s}.13-1Q-2n-1r .13-x-2V{-1a-1L:13-1Q-2n-x-2V .5s;1L:13-1Q-2n-x-2V .5s}@-1a-2a 13-1p-2u{0%{-1a-16:1p(0);16:1p(0)}1F%{-1a-16:1p(5O);16:1p(5O)}}@2a 13-1p-2u{0%{-1a-16:1p(0);16:1p(0)}1F%{-1a-16:1p(5O);16:1p(5O)}}@6J eq{1e.13-1q:1M(.13-26-1P):1M(.13-1b-1q){3T-y:8D!3f}1e.13-1q:1M(.13-26-1P):1M(.13-1b-1q)>[2o-2L=4M]{2B:1Z}1e.13-1q:1M(.13-26-1P):1M(.13-1b-1q) .13-1h{2G:8O!3f}}");',0,895,"|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||swal2|function||transform|return|var|top|webkit|toast|width|this|body|success|left|container|input|class|right|center|document|concat|line|rotate|shown|icon||popup|color|bottom|if|border|Tt|content|typeof|null|flex|auto|height|100|scale|div|style|background|value|animation|not|margin|start|backdrop|animate|column|align|font|type|nt|625em|45deg|grow|none||5em|window|length||progress|no|end|translateY|target|keyframes|select|focus|Object|padding|items|for|textarea|customClass|size|get|file|125em|error|aria|justify|2em|box|range|rotateZ|loading|radio|radius|25em|it|opacity|checkbox|display|3125em|step|placeholder|actions|position|375em|title|styled|rt|hidden|new|confirmButton|in|setAttribute|disabled|inputValue|forEach|querySelector|timeout|mark|progressSteps|75em|yt|ms|hide|show|0625em||span|circular|Promise|appendChild|innerHTML|1875em|string|prototype|long|undefined|close|important|text|tip|case|validationMessage|innerParams|void|else|2deg|cancelButton|875em|9375em|key||indexOf|arguments|transparent|1em|getInput|button|inherit|createElement|rgba|footer|data|label|steps|then|shadow|parentNode|Swal|1px|running|modal|cancel|removeAttribute|ue|fff|domCache|to|overflow|ot|active|classList|contains|weight|index|tabindex|keydownListenerCapture|parameter|set|solid||output|Reflect|remaining|params|user|block|translateX|number|image|rotateX|75s|validation|405deg|before|direction|message|origin|confirm|object|absolute|question|default|moz|push|4em|getPropertyValue|querySelectorAll|normal|resolve|inputOptions|call|previousBodyPadding|parseInt|hideLoading|activeElement|className|keydownTarget|timer|break|4375em|max|_|true|inputerror|header|first|child|linear|DismissReason|preConfirm|getComputedStyle|ccc|getAttribute|stop|inputPlaceholder|apply||high|contrast|is||id|currentProgressStep|keys|previousActiveElement|setTimeout|documentElement|f27474|Qt|sweetalert2|showCancelButton|showConfirmButton|promise|WeakMap|Symbol|email|Expected|or|got|html|relative|st|Z0|sizing||zA|imageClass|titleText|Jt|toString|allowOutsideClick|delete|keydownHandler|outline|focusCancel|inputValidator|backgroundColor|freeze|checked|switch|info|warning|5625em|iosfix|row|confirmButtonColor|360deg|imageUrl|constructor|onchange|Date|inputClass|showCloseButton|onclick|tt|Pt|fire|resetValidationMessage|addEventListener|Lt|url||keydownHandlerAdded|||forwards|Unexpected|600|word|8em|Ft|wrap|previous|removeEventListener|scrollTop|preventDefault|of|customContainerClass|3085d6|showLoaderOnConfirm|gt|onmouseup|onBeforeOpen|onOpen|and|Dt|cursor|inline|transition|infinite|translate|enumerable|px|0s|writable|100deg|filter|1deg|Invalid|fix|ring|enableButtons|hasOwnProperty|media|_main|queue|rtl|cancelButtonColor|05|construct|noanimation|fade|fullscreen|dismiss|esc|hasAttribute|It|getConfirmButton|SweetAlert2|3em||remove|stretch|Nt|parseFloat|click|Array|initial|6em|2px|focusConfirm|reverseButtons|cancelButtonClass|stopPropagation|confirmButtonClass|allowEnterKey|ease|heightAuto|swalPromiseResolve|Zt|catch|keydown|min|capture|Mt|At|getTimerLeft|Bt|closeButton|Xt|imageWidth|te|imageAlt|childNodes|progressStepsDistance|li|test|https|all|removeChild|Ct|configurable|overflowY|requires|styleSheet|tel|throw|ie|Map|oninput|se|instanceof|a5dc86|pt|closePopup|150|disableButtons|Sweetalert2|showValidationMessage|buttonsStyling|update|borderRightColor||onmousedown|borderLeftColor|define||github|from|300|15s|try|kt|St|ft|splice|Unknown|showLoading|pointer|src|TypeError|hover|h2|imageHeight|offsetWidth|href|8125em|increase|innerText|isRunning|gradient|OK|closeButtonAriaLabel|Rt|scrollHeight|Cancel|paddingRight|ontouchstart|navigator|50px|mt|scroll|add8e6|busy|use|The|25s|jt|valid|defaulting|_t|Ot|static|restoreFocusTimeout|console|allowEscapeKey|zt|zoom|Wt|controls|resize|Kt|children|family|bind|duration||stopKeydownPropagation|setPrototypeOf||vt|confirmButtonText|confirmButtonAriaLabel|attributes|cancelButtonText|cancelButtonAriaLabel|name|isVisible|dialog|getPrototypeOf|__proto__|callback|started|clearTimeout|inputAutoTrim|password|3px|split|onAfterClose|hasn|onClose|scrollbarPadding|Vt|d9d9d9|qt|Ht|lt|isUpdatableParameter|ne|Boolean|argsToParams|cloneNode|finally|SweetAlert|clickConfirm|add|re|6875em|option|selected|wt|15px|self|been|defineProperties|com|inputAttributes|30px|enableConfirmButton|ut|disableConfirmButton|enableInput|disableInput|545454|blur|outerHTML|invalid|describedBy|getProgressSteps|const|swalInstance|getQueueStep|setProgressSteps|module|insertBefore|should|removeProperty|with|exports|Button|files|ul|symbol|isDeprecatedParameter|together|usage|example|nhttps|used|nshowLoaderOnConfirm|io|ajax|request|Target|||join|defined|trim|checkValidity|but|toasts|onmouseover|onmouseout|incompatible|hideProgressSteps|showProgressSteps|Enter|isComposing|Tab|shiftKey|ArrowLeft|ArrowRight|ArrowUp|ArrowDown|Left|Right|Up|Down|Escape|Esc|marginRight|Error|marginLeft|Updatable|are|listed|here|closeToast|blob|master|utils|js|closeModal|disableLoading|This|package|library|||||||||||please|include|shim|enable|browser|See|wiki||Migration||MSStream|support|userAgent|version|iPod|swal|sweetAlert|getElementsByTagName|head|iPhone|cssText|charset|UTF|iPad|URL|256|www|address|ontouchmove|tagName|INPUT|clientHeight|alignItems|offsetTop|documentMode|MSInputMethodContext|clientWidth|msMaxTouchPoints|innerHeight|isTimerRunning|increaseTimer|toggleTimer|resumeTimer|stopTimer|enableLoading|deleteQueueStep|insertQueueStep|create|either|must|expression|Super|mixin|isLoading|getValidationMessage|getFocusableElements|getFooter|getHeader|getCancelButton|getActions|getCloseButton|getIcons|getIcon|getImage|getContent|getTitle|getPopup|getContainer|clickCancel|see|isValidParameter||imageHeigth|Close|scrollTo|scrollY|scrollX|alt|starts|700|arrays|JS|like|than|less|textContent|basis|ButtonClass|ButtonAriaLabel|ButtonText|substring|showC|animationend|oanimationend|oAnimationEnd|OAnimation|webkitAnimationEnd|WebkitAnimation|nextSibling|assertive|polite|live|alert|role|initialize|has|replace|times|img|calc|10px|fixed|describedby|1060|scrolling|touch|labelledby|HTMLElement|32em|video|audio|1rem|contenteditable|595959|embed|iframe|area|sort|getClientRects|offsetHeight|46875em|warn|instead||Please|release|major|next|the|removed|after|will|5px|deprecated|999|slice|500|map|getOwnPropertyDescriptor|called|aaa|super|4px|inner|eee|initialised|ReferenceError|out|Function|serif|Proxy|sham|assign|inset|06|b4dbed|c4e6f5|defineProperty|10em|f0f0f0|666|supports|accelerator|prefix|facea8|f8bb86|9de0f6|3fc3ee|c9dae1|87adbd||arabic|0635em|165|220|134|Cannot|tap|highlight|iterator|strict|amd|print".split("|"),0,{}))},function(e,t,n){"use strict";function r(e,t){for(var n=0;n35?String.fromCharCode(e+29):e.toString(36))},!"".replace(/^/,String)){for(;n--;)a[o(n)]=r[n]||o(n);r=[function(e){return a[e]}],o=function(){return"\\w+"},n=1}for(;n--;)r[n]&&(e=e.replace(new RegExp("\\b"+o(n)+"\\b","g"),r[n]));return e}('(4(k,l){"4"===G V&&V.1Z?V(l):"21"===G 1z?2c.1z=l():k.2f=l()})(x,4(){4 k(a,b,d){7 ad?d:a}4 l(a,b,d){a="Q"===e.B?{W:"Q("+D*(-1+a)+"%,0,0)"}:"Y"===e.B?{W:"Y("+D*(-1+a)+"%,0)"}:{"1u-2b":D*(-1+a)+"%"};a.P="U "+b+"A "+d;7 a}4 q(a,b){7 0<=("2a"==G a?a:n(a)).24(" "+b+" ")}4 r(a,b){6 d=n(a),c=d+b;q(d,b)||(a.10=c.1o(1))}4 t(a,b){6 c=n(a);q(a,b)&&(b=c.H(" "+b+" "," "),a.10=b.1o(1,b.J-1))}4 n(a){7(" "+(a.10||"")+" ").H(/\\s+/1C," ")}6 c={1W:"0.2.0"},e=c.1V={1b:.1U,1e:"1Q",B:"",1g:1P,N:!0,1n:.1O,1p:1N,1t:!0,16:\'[S="11"]\',1B:\'[S="T"]\',C:"I",19:\'\'};c.1H=4(a){6 b;X(b 9 a){6 c=a[b];1h 0!==c&&a.1i(b)&&(e[b]=c)}7 x};c.j=1k;c.E=4(a){6 b=c.1m();a=k(a,e.1b,1);c.j=1===a?1k:a;6 d=c.1l(!b),p=d.F(e.16),h=e.1g,v=e.1e;d.1r;w(4(b){""===e.B&&(e.B=c.1s());m(p,l(a,h,v));1===a?(m(d,{P:"1D",1v:1}),d.1r,R(4(){m(d,{P:"U "+h+"A 1w",1v:0});R(4(){c.1x();b()},h)},h)):R(b,h)});7 x};c.1m=4(){7"1y"===G c.j};c.14=4(){c.j||c.E(0);6 a=4(){R(4(){c.j&&(c.N(),a())},e.1p)};e.N&&a();7 x};c.1A=4(a){7 a||c.j?c.15(.3+.5*13.12()).E(1):x};c.15=4(a){6 b=c.j;7 b?("1y"!==G a&&(a=(1-b)*k(13.12()*b,.1,.1E)),b=k(b+a,0,.1F),c.E(b)):c.14()};c.N=4(){7 c.15(13.12()*e.1n)};(4(){6 a=0,b=0;c.1G=4(d){y(!d||"1I"===d.1J())7 x;0===b&&c.14();a++;b++;d.1K(4(){b--;0===b?(a=0,c.1A()):c.E((a-b)/a)});7 x}})();c.1l=4(a){y(c.1d())7 8.Z("o");r(8.1j,"o-1f");6 b=8.1R("i");b.1S="o";b.1T=e.19;6 d=b.F(e.16),p=a?"-D":D*(-1+(c.j||0));a=8.F(e.C);m(d,{P:"U 0 1w",W:"Q("+p+"%,0,0)"});e.1t||(d=b.F(e.1B))&&d&&d.M&&d.M.1a(d);a!=8.I&&r(a,"o-17-C");a.1X(b);7 b};c.1x=4(){t(8.1j,"o-1f");t(8.F(e.C),"o-17-C");6 a=8.Z("o");a&&a&&a.M&&a.M.1a(a)};c.1d=4(){7!!8.Z("o")};c.1s=4(){6 a=8.I.L,b="1Y"9 a?"1c":"20"9 a?"18":"22"9 a?"A":"23"9 a?"O":"";7 b+"25"9 a?"Q":b+"26"9 a?"Y":"1u"};6 w=4(){4 a(){6 c=b.27();c&&c(a)}6 b=[];7 4(c){b.28(c);1==b.J&&a()}}(),m=4(){4 a(a){7 a.H(/^-A-/,"A-").H(/-([\\29-z])/1C,4(a,b){7 b.1q()})}4 b(b){b=a(b);6 d;y(!(d=e[b])){d=b;a:{6 u=8.I.L;y(!(b 9 u))X(6 h=c.J,f=b.2d(0).1q()+b.2e(1),g;h--;)y(g=c[h]+f,g 9 u){b=g;2g a}}d=e[d]=b}7 d}6 c=["1c","O","18","A"],e={};7 4(a,c){6 d=2h;y(2==d.J)X(g 9 c){6 e=c[g];y(1h 0!==e&&c.1i(g)){d=a;6 f=g;f=b(f);d.L[f]=e}}2i{6 g=a;f=d[1];d=d[2];f=b(f);g.L[f]=d}}}();7 c});',0,143,"||||function||var|return|document|in|||||||||div|status|||||nprogress|||||||||this|if||ms|positionUsing|parent|100|set|querySelector|typeof|replace|body|length|class|style|parentNode|trickle||transition|translate3d|setTimeout|role|spinner|all|define|transform|for|translate|getElementById|className|bar|random|Math|start|inc|barSelector|custom|Moz|template|removeChild|minimum|Webkit|isRendered|easing|busy|speed|void|hasOwnProperty|documentElement|null|render|isStarted|trickleRate|substring|trickleSpeed|toUpperCase|offsetWidth|getPositioningCSS|showSpinner|margin|opacity|linear|remove|number|exports|done|spinnerSelector|gi|none|95|994|promise|configure|resolved|state|always|icon|peg|800|02|200|ease|createElement|id|innerHTML|08|settings|version|appendChild|WebkitTransform|amd|MozTransform|object|msTransform|OTransform|indexOf|Perspective|Transform|shift|push|da|string|left|module|charAt|slice|NProgress|break|arguments|else".split("|"),0,{}))},function(module,__webpack_exports__,__webpack_require__){"use strict";function _typeof(e){return(_typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function _classCallCheck(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function _defineProperties(e,t){for(var n=0;n"));r.error(s.join("
"))}catch(e){}return}case 0:return}r.error(a||e.status+" "+n)}},{key:"handleJsonResponse",value:function handleJsonResponse(response,options){var Dcat=this.dcat,data=response.data;if(response){if("object"!==_typeof(response))return Dcat.error("error","Oops!");var then=function then(_then){switch(_then.action){case"refresh":Dcat.reload();break;case"download":window.open(_then.value,"_blank");break;case"redirect":Dcat.reload(_then.value||null);break;case"location":setTimeout((function(){_then.value?window.location=_then.value:window.location.reload()}),1e3);break;case"script":!function(){eval(_then.value)}()}};"string"==typeof response.html&&response.html&&options.target&&("function"==typeof options.html?options.html(options.target,response.html,response):$(target).html(response.html));var message=data.message||response.message;data.type||(data.type=response.status?"success":"error"),"string"==typeof message&&data.type&&message&&(data.alert?Dcat.swal[data.type](message,data.detail):Dcat[data.type](message,null,data.timeout?{timeOut:1e3*data.timeout}:{})),data.then&&then(data.then)}}}]),Ajax}()},,function(e,t,n){e.exports=n(13)},function(module,exports){var module={};eval(function(e,t,n,r,o,a){if(o=function(e){return(e<62?"":o(parseInt(e/62)))+((e%=62)>35?String.fromCharCode(e+29):e.toString(36))},!"".replace(/^/,String)){for(;n--;)a[o(n)]=r[n]||o(n);r=[function(e){return a[e]}],o=function(){return"\\w+"},n=1}for(;n--;)r[n]&&(e=e.replace(new RegExp("\\b"+o(n)+"\\b","g"),r[n]));return e}('!5(e){"5"==W 2y&&2y.6g?2y(["1Z"],e):"44"==W 2E&&2E.3W?2E.3W=5(t,r){6 R 0===r&&(r="6f"!=W Z?3F("1Z"):3F("1Z")(t)),e(r),r}:e(6e)}(5(e){"6d 6a";5 t(t){4 r=t.P;t.67()||(t.5Q(),e(t.1p).30("z").1a(r))}5 r(t){4 r=t.1p,a=e(r);7(!a.3I("[8=U],[8=1N]")){4 n=a.30("[8=U]");7(0===n.B)6;r=n[0]}4 i=r.z;7(i.1n=r,"1N"===r.8)7(R 0!==t.3G)i.1q=t.3G,i.1x=t.5O;16 7("5"==W e.J.42){4 o=a.42();i.1q=t.3g-o.3j,i.1x=t.3l-o.3p}16 i.1q=t.3g-r.5N,i.1x=t.3l-r.5L;1C(5(){i.1n=i.1q=i.1x=Q},2X)}5 a(){7(e.J.1a.3M){4 t="[1Z.z] "+1X.5K.5J.1h(1D,"");Z.2W&&Z.2W.33?Z.2W.33(t):Z.20&&Z.20.3i&&Z.20.3i(t)}}4 n=/\\r?\\n/g,i={};i.2V=R 0!==e(\'<1c 8="29">\').1Q(0).3A,i.3C=R 0!==Z.3E;4 o=!!e.J.2Q;e.J.1s=5(){7(!o)6 3.11.1f(3,1D);4 e=3.2Q.1f(3,1D);6 e&&e.1Z||"1J"==W e?e:3.11.1f(3,1D)},e.J.1a=5(t,r,n,s){5 u(r){4 a,n,i=e.1K(r,t.2O).32("&"),o=i.B,s=[];Y(a=0;a\',k).1z(f.I[c].G).2B(w)[0]):u.H(e(\'<1c 8="2C" 9="\'+c+\'">\',k).1z(f.I[c]).2B(w)[0]));f.2a||h.2B(D),v.34?v.34("35",s):v.36("38",s,!1),1C(t,15);1l{w.U()}1A(e){19.5w("z").U.1f(w)}}5r{w.1F("2c",i),w.1F("2d",o),r?w.1F("1p",r):p.3d("1p"),e(u).3e()}}5 s(t){7(!x.1b&&!X){7((O=n(v))||(a("2N 5q 5p 19"),t=L),t===A&&x)6 x.1m("1k"),R S.1P(x,"1k");7(t===L&&x)6 x.1m("3s 1m"),R S.1P(x,"V","3s 1m");7(O&&O.2A.2z!==f.1T||T){v.3B?v.3B("35",s):v.5o("38",s,!1);4 r,i="K";1l{7(T)5l"1k";4 o="1I"===f.1B||O.2u||e.5h(O);7(a("5g="+o),!o&&Z.20&&(Q===O.1G||!O.1G.3O)&&--C)6 a("49 5e 2t, 2r 2q 5d"),R 1C(s,5c);4 u=O.1G?O.1G:O.2k;x.18=u?u.3O:Q,x.1H=O.2u?O.2u:O,o&&(f.1B="1I"),x.2p=5(e){6{"2n-8":f.1B}[e.1u()]},u&&(x.17=37(u.2h("17"))||x.17,x.1j=u.2h("1j")||x.1j);4 c=(f.1B||"").1u(),l=/(2s|3b|2f)/.1o(c);7(l||f.1w){4 p=O.28("1w")[0];7(p)x.18=p.G,x.17=37(p.2h("17"))||x.17,x.1j=p.2h("1j")||x.1j;16 7(l){4 m=O.28("2w")[0],g=O.28("1G")[0];m?x.18=m.26?m.26:m.3Y:g&&(x.18=g.26?g.26:g.3Y)}}16"1I"===c&&!x.1H&&x.18&&(x.1H=q(x.18));1l{M=N(x,c,f)}1A(e){i="23",x.V=r=e||i}}1A(e){a("V 5a: ",e),i="V",x.V=r=e||i}x.1b&&(a("2g 1b"),i=Q),x.17&&(i=x.17>=58&&x.17<57||4Z===x.17?"K":"V"),"K"===i?(f.K&&f.K.1h(f.12,M,"K",x),S.4Y(x.18,"K",x),d&&e.1v.13("4U",[x,f])):i&&(R 0===r&&(r=x.1j),f.V&&f.V.1h(f.12,x,i,r),S.1P(x,"V",r),d&&e.1v.13("3v",[x,f,r])),d&&e.1v.13("4T",[x,f]),d&&!--e.2F&&e.1v.13("4P"),f.1t&&f.1t.1h(f.12,x,i),X=!0,f.1k&&31(j),1C(5(){f.2a?h.11("2o",f.1T):h.3e(),x.1H=Q},2X)}}}4 u,c,f,d,m,h,v,x,y,b,T,j,w=p[0],S=e.4N();7(S.1m=5(e){x.1m(e)},r)Y(c=0;c\',k)).4D({3N:"4C",3p:"-3P",3j:"-3P"}),v=h[0],x={1b:0,18:Q,1H:Q,17:0,1j:"n/a",4z:5(){},2p:5(){},4y:5(){},1m:5(t){4 r="1k"===t?"1k":"1b";a("4x 2g... "+r),3.1b=1;1l{v.1R.19.3R&&v.1R.19.3R("4w")}1A(e){}h.11("2o",f.1T),x.V=r,f.V&&f.V.1h(f.12,x,r,t),d&&e.1v.13("3v",[x,f,r]),f.1t&&f.1t.1h(f.12,x,r)}},(d=f.3T)&&0==e.2F++&&e.1v.13("4v"),d&&e.1v.13("4u",[x,f]),f.2e&&!1===f.2e.1h(f.12,x,f))6 f.3T&&e.2F--,S.1P(),S;7(x.1b)6 S.1P(),S;(y=w.1n)&&(b=y.9)&&!y.1g&&(f.I=f.I||{},f.I[b]=y.G,"1N"===y.8&&(f.I[b+".x"]=w.1q,f.I[b+".y"]=w.1x));4 A=1,L=2,F=e("3Z[9=40-4j]").11("2n"),E=e("3Z[9=40-1K]").11("2n");E&&F&&(f.I=f.I||{},f.I[E]=F),f.4i?i():1C(i,10);4 M,O,X,C=50,q=e.4f||5(e,t){6 Z.46?((t=21 46("4e.5f")).4a="48",t.4b(e)):t=(21 4c).4d(e,"2f/1I"),t&&t.2k&&"23"!==t.2k.47?t:Q},45=e.4g||5(e){6 Z.4h("("+e+")")},N=5(t,r,a){4 n=t.2p("2n-8")||"",i=("1I"===r||!r)&&n.2b("1I")>=0,o=i?t.1H:t.18;6 i&&"23"===o.2k.47&&e.V&&e.V("23"),a&&a.43&&(o=a.43(o,r)),"1J"==W o&&(("2s"===r||!r)&&n.2b("2s")>=0?o=45(o):("3b"===r||!r)&&n.2b("41")>=0&&e.4k(o)),o};6 S}7(!3.B)6 a("1a: 4l U 4m - 4n 4o 1y"),3;4 l,f,d,p=3;"5"==W t?t={K:t}:"1J"==W t||!1===t&&1D.B>0?(t={1d:t,P:r,1B:n},"5"==W s&&(t.K=s)):R 0===t&&(t={}),l=t.2G||t.8||3.1s("2G"),(d=(d="1J"==W(f=t.1d||3.1s("2c"))?e.4p(f):"")||Z.2A.2z||"")&&(d=(d.4q(/^([^#]+)/)||[])[1]),t=e.2M(!0,{1d:d,K:e.1O.K,8:l||e.1O.8,1T:/^4r/i.1o(Z.2A.2z||"")?"41:48":"4s:4t"},t);4 m={};7(3.13("z-2w-3V",[3,t,m]),m.3U)6 a("1a: U 3S 25 z-2w-3V 13"),3;7(t.2U&&!1===t.2U(3,t))6 a("1a: U 1b 25 2U 2t"),3;4 h=t.2O;R 0===h&&(h=e.1O.2O);4 v,g=[],x=3.2T(t.4A,g,t.4B);7(t.P){4 y=e.2S(t.P)?t.P(x):t.P;t.I=y,v=e.1K(y,h)}7(t.2R&&!1===t.2R(x,3,t))6 a("1a: U 1b 25 2R 2t"),3;7(3.13("z-U-3L",[x,3,t,m]),m.3U)6 a("1a: U 3S 25 z-U-3L 13"),3;4 b=e.1K(x,h);v&&(b=b?b+"&"+v:v),"4F"===t.8.4G()?(t.1d+=(t.1d.2b("?")>=0?"&":"?")+b,t.P=Q):t.P=b;4 T=[];7(t.1E&&T.H(5(){p.1E()}),t.2P&&T.H(5(){p.2P(t.4J)}),!t.1B&&t.1p){4 j=t.K||5(){};T.H(5(r,a,n){4 i=1D,o=t.4K?"3H":"4M";e(t.1p)[o](r).1i(5(){j.1f(3,i)})})}16 t.K&&(e.4O(t.K)?e.3y(T,t.K):T.H(t.K));7(t.K=5(e,r,a){Y(4 n=t.12||3,i=0,o=T.B;i0,D="2j/z-P",A=p.11("2d")===D||p.11("2I")===D,L=i.2V&&i.3C;a("4S :"+L);4 F,E=(k||A)&&!L;!1!==t.1U&&(t.1U||E)?t.3w?e.1Q(t.3w,5(){F=c(x)}):F=c(x):F=(k||A)&&L?5(r){Y(4 a=21 3E,n=0;n0)&&(n={1d:n,P:i,1B:o},"5"==W s&&(n.K=s)),n=n||{},n.2i=n.2i&&e.2S(e.J.1V),!n.2i&&0===3.B){4 u={s:3.1M,c:3.12};6!e.3K&&u.s?(a("2r 2q 3J, 5i 2H"),e(5(){e(u.s,u.c).2H(n)}),3):(a("5j; 5k 2v 5m 5n 1M"+(e.3K?"":" (2r 2q 3J)")),3)}6 n.2i?(e(19).2x("U.z-1e",3.1M,t).2x("2l.z-1e",3.1M,r).1V("U.z-1e",3.1M,n,t).1V("2l.z-1e",3.1M,n,r),3):3.3c().1V("U.z-1e",n,t).1V("2l.z-1e",n,r)},e.J.3c=5(){6 3.2x("U.z-1e 2l.z-1e")},e.J.2T=5(t,r,a){4 n=[];7(0===3.B)6 n;4 o,s=3[0],u=3.11("5s"),c=t||R 0===s.2v?s.28("*"):s.2v;7(c&&(c=e.5t(c)),u&&(t||/(5u|5v)\\//.1o(3a.39))&&(o=e(\':1c[z="\'+u+\'"]\').1Q()).B&&(c=(c||[]).5x(o)),!c||!c.B)6 n;e.2S(a)&&(c=e.5y(c,a));4 l,f,d,p,m,h,v;Y(l=0,h=c.B;l=t||n<0||b&&e-f>=i}function k(){var e=Date.now();if(y(e))return w(e);c=g(k,function(e){var n=e-f,r=t-(e-l);return b?Math.min(r,i-n):r}(e))}function w(e){return c=void 0,h&&o?m(e):(o=a=void 0,s)}function x(){var e=Date.now(),n=y(e);if(o=arguments,a=this,l=e,n){if(void 0===c)return v(l);if(b)return c=g(k,t),m(l)}return void 0===c&&(c=g(k,t)),s}return t=+t||0,d=r(u=n),null==u||"object"!==d&&"function"!==d||(p=!!n.leading,i=(b="maxWait"in n)?Math.max(+n.maxWait||0,t):t,h="trailing"in n?!!n.trailing:h),x.cancel=function(){void 0!==c&&clearTimeout(c),f=0,o=l=a=c=void 0},x.flush=function(){return void 0===c?s:w(Date.now())},x.pending=function(){return void 0!==c},x};function a(e){return(a="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function i(e,t){for(var n=0;ni?i:t,l=Math.ceil(c*(a/t));l=l>s?s:l,(n=n||e.split("/").pop()).length>50&&(n=n.substr(0,50)+"..."),layer.open({type:1,shade:.2,title:!1,maxmin:!1,shadeClose:!0,closeBtn:2,content:$(o),area:[c+"px",l+"px"],skin:"layui-layer-nobg",end:function(){document.body.removeChild(o)}})},o.onerror=function(){r.loading(!1),r.error(r.lang.trans("no_preview"))}}},{key:"asyncRender",value:function(e,t,n){var r=this.dcat;$.ajax(e).then((function(e){t(r.assets.resolveHtml(e,r.triggerReady).render())}),(function(e,t,o){if(n&&!1===n(e,t,o))return!1;r.handleAjaxError(e,t,o)}))}},{key:"loadFields",value:function(e,t){var n=[],r=[];t.values?"string"==typeof(r=t.values)&&(r=[r]):$(e).find("option:selected").each((function(){("0"===String(this.value)||this.value)&&r.push(this.value)})),r.length&&(t.fields.forEach((function(o,a){var i=$(e).closest(t.group).find("."+t.fields[a]);r.length&&n.push(function(e,n){Dcat.loading(),$.ajax(e).then((function(e){Dcat.loading(!1),n.find("option").remove(),$.map(e,(function(e){n.append(new Option(e[t.textField],e[t.idField],!1,!1))})),$(n).val(String(n.data("value")).split(",")).trigger("change")}))}(t.urls[a]+(t.urls[a].match(/\?/)?"&":"?")+"q="+r.join(","),i))})),$.when(n).then((function(){})))}}])&&i(t.prototype,n),r&&i(t,r),e}();function c(e){return(c="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function l(e,t){for(var n=0;n {message}
',redirect:!0,autoRemoveError:!0,before:function(){},after:function(){},success:function(){},error:function(){}},t),this.originalValues={},this.$form=$(this.options.form).first(),this._errColumns={},this.init()}var t,n,r;return t=e,(n=[{key:"init",value:function(){var e=this,t=e.options.confirm;if(!t.title)return e.submit();Dcat.confirm(t.title,t.content,(function(){e.submit()}))}},{key:"submit",value:function(){var e=this,t=e.$form,n=e.options,r=t.find('[type="submit"],.submit');e.removeErrors(),t.ajaxSubmit({data:{_token:Dcat.token},beforeSubmit:function(o,a,i){return!1!==n.before(o,a,i,e)&&!1!==U(H.before,o,a,i,e)&&!(n.validate&&(t.validator("validate"),t.find("."+n.errorClass).length>0))&&void r.buttonLoading()},success:function(t){setTimeout((function(){r.buttonLoading(!1)}),700),!1!==n.after(!0,t,e)&&!1!==n.success(t,e)&&!1!==U(H.success,t,e)&&(!1!==t.redirect&&n.redirect||t.data&&t.data.then&&(delete t.data.then,delete t.data.then,delete t.data.then),Dcat.handleJsonResponse(t))},error:function(o){if(r.buttonLoading(!1),!1!==n.after(!1,o,e)&&!1!==n.error(o,e)&&!1!==U(H.error,o,e))try{var a,i=JSON.parse(o.responseText);if(422!=o.status||!i||!Dcat.helpers.isset(i,"errors")){var s=o.responseJSON;return s&&s.message?Dcat.error(s.message):Dcat.error(o.status+" "+o.statusText)}for(a in i=i.errors,i)e._errColumns[a]=e.showError(t,a,i[a])}catch(e){return Dcat.error(o.status+" "+o.statusText)}}})}},{key:"showError",value:function(e,t,n){var r=this,o=r.queryFieldByName(e,t),a=o.closest(r.options.groupSelector);if(G(r,o).removeClass("d-none"),r.originalValues[t]=r.getFieldValue(o),o)return function(e){for(var t in a.addClass(r.options.errorClass),"string"==typeof e&&(e=[e]),e)a.find(r.options.errorContainerSelector).first().append(r.options.errorTemplate.replace("{message}",e[t]));r.options.validationErrorToastr&&Dcat.error(e.join("
"))}(n),r.options.autoRemoveError&&function(e,t,n){var r=function(){e.removeError(t,n)};t.one("change",r),t.off("blur",r).on("blur",(function(){e.isValueChanged(t,n)&&r()})),function o(){setTimeout((function(){if(t.length)return e.isValueChanged(t,n)?r():void o()}),500)}()}(r,o,t),o;Dcat.helpers.len(n)&&n.length&&Dcat.error(n.join(" \n "))}},{key:"getFieldValue",value:function(e){var t,n=[],r=e.attr("type"),o="checkbox"===r||"radio"===r;for(t=0;t")}function G(e,t){return N(e,t).find(".has-tab-error")}function U(e){var t,n,r,o=arguments,a=[];for(n in delete o[0],o=o||[])a.push(o[n]);for(t in e)if(!1===(r=e[t].apply(e[t],a)))return r}F.submitting=function(e){return"function"==typeof e&&H.before.push(e),this},F.submitted=function(e,t){return"function"==typeof e&&H.success.push(e),"function"==typeof t&&H.error.push(t),this},$.fn.form=function(e){var t=$(this);e=$.extend(e,{form:t}),t.on("submit",(function(){return!1})),t.find('[type="submit"],.submit').click((function(t){return Dcat.Form(e),!1}))};var J=F;function K(e,t){for(var n=0;n0)return!1;e.submitting=1,r.buttonLoading()},after:function(o,a){if(r.buttonLoading(!1),e.submitting=0,!1===t.saved(o,a))return!1;if(!o)return t.error(o,a);if(a.status){var i=t.success(o,a);return e._destroy(n),i}return t.error(o,a)}}),!1}}])&&K(t.prototype,n),r&&K(t,r),e}();function Q(e,t){for(var n=0;n'],X=function(){function e(t,n){!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),n=$.extend({container:t.config.pjax_container_selector,zIndex:100,width:"52px",color:t.color.dark60,background:"#fff",style:"",svg:W[0]},n);this.$container=$(n.container),$('
{svg}
'.replace("{svg}",n.svg).replace("{color}",n.color).replace("{color}",n.color).replace("{width}",n.width).replace("{style}","".concat("position:absolute;","background:").concat(n.background,";z-index:").concat(n.zIndex,";").concat(n.style))).appendTo(this.$container)}var t,n,r;return t=e,(n=[{key:"destroy",value:function(){this.$container.find(".dcat-loading").remove()}}])&&Q(t.prototype,n),r&&Q(t,r),e}();function Y(){$(".dcat-loading").remove()}var Z=function(e){e.loading=function(e){if(!1===e)return setTimeout(Y,70);e=$.extend({zIndex:999991014,width:"58px",shade:"rgba(255, 255, 255, 0.1)",background:"transparent",top:200,svg:W[0]},e);var t=$(window),n=$('
'),r=$('
');function o(){n.css({left:(t.width()-300)/2,top:(t.height()-e.top)/2})}n.appendTo("body"),e.shade&&r.appendTo("body"),t.on("resize",o),o(),n.loading(e)},$.fn.loading=function(t){return!1===t?$(this).find(".dcat-loading").remove():((t=t||{}).container=$(this),new X(e,t))},$.fn.buttonLoading=function(t){var n,r=$(this),o=r.attr("data-loading");if(!1===t)return o?(r.find(".waves-ripple").remove(),r.removeClass("disabled btn-loading waves-effect").removeAttr("disabled").removeAttr("data-loading").html(r.find("."+o).html())):r;if(o)return r;n=r.html(),o="ld-"+e.helpers.random();var a='',i=["btn","layui-layer-btn0","layui-layer-btn1"];for(var s in i)r.hasClass(i[s])&&(a=W[0].replace("{color}","currentColor").replace("{width}","50px;height:11px;"));return r.addClass("disabled btn-loading").attr("disabled",!0).attr("data-loading",o).html('\n\n").concat(a,"\n"))}};function ee(e,t){for(var n=0;n\n
\n'.replace("{id}",r.id).replace("{class}",r.options.class||"")),r.$container.appendTo("body"),r.$container.find(".slider-content").append(r.$target),new PerfectScrollbar("#".concat(r.id," .slider-content")),r.options.autoDestory&&t.onPjaxComplete((function(){r.destroy()}))}var t,n,r;return t=e,(n=[{key:"open",value:function(){this.$container.addClass("open")}},{key:"close",value:function(){this.$container.removeClass("open")}},{key:"toggle",value:function(){this.$container.toggleClass("open")}},{key:"destroy",value:function(){this.$container.remove()}}])&&ne(t.prototype,n),r&&ne(t,r),e}();function oe(e,t){for(var n=0;n255?255:e<0?0:e};t=t||0;var r=parseInt(e,16);return[n((r>>16)+t),n((r>>8&255)+t),n((255&r)+t)]}}])&&oe(t.prototype,n),r&&oe(t,r),e}();function ie(e,t){for(var n=0;n400?$(".scroll-top").fadeIn():$(".scroll-top").fadeOut()})),$(".scroll-top").click((function(){$("html, body").animate({scrollTop:0},1e3)}))}}])&&fe(t.prototype,n),r&&fe(t,r),e}();function be(e,t){for(var n=0;n - +
@@ -55,4 +55,4 @@ }); $(selector+':checked').trigger('change') -@endif \ No newline at end of file +@endif diff --git a/resources/views/form/multipleselect.blade.php b/resources/views/form/multipleselect.blade.php index c6ed2e195..04e2d5d83 100755 --- a/resources/views/form/multipleselect.blade.php +++ b/resources/views/form/multipleselect.blade.php @@ -23,7 +23,7 @@ @include('admin::form.select-script') diff --git a/src/AdminServiceProvider.php b/src/AdminServiceProvider.php index bb31b4fa7..d6c28c378 100755 --- a/src/AdminServiceProvider.php +++ b/src/AdminServiceProvider.php @@ -3,6 +3,7 @@ namespace Dcat\Admin; use Dcat\Admin\Contracts\ExceptionHandler; +use Dcat\Admin\Support\UrlCipherManager; use Dcat\Admin\Exception\Handler; use Dcat\Admin\Extend\Manager; use Dcat\Admin\Extend\UpdateManager; @@ -65,6 +66,7 @@ class AdminServiceProvider extends ServiceProvider */ protected $routeMiddleware = [ 'admin.auth' => Http\Middleware\Authenticate::class, + 'admin.cipher' => Http\Middleware\Cipher::class, 'admin.pjax' => Http\Middleware\Pjax::class, 'admin.permission' => Http\Middleware\Permission::class, 'admin.bootstrap' => Http\Middleware\Bootstrap::class, @@ -78,6 +80,7 @@ class AdminServiceProvider extends ServiceProvider */ protected $middlewareGroups = [ 'admin' => [ + 'admin.cipher', 'admin.auth', 'admin.pjax', 'admin.bootstrap', @@ -236,6 +239,28 @@ public function registerServices() $this->app->singleton('admin.web-uploader', WebUploader::class); $this->app->singleton(ExceptionHandler::class, config('admin.exception_handler') ?: Handler::class); $this->app->singleton('admin.translator', Translator::class); + + $this->registerUrlCipher(); + } + + /** + * 注册 URL 参数加解密服务. + * + * 容器中的 `admin.cipher` 绑定的是 {@see \Dcat\Admin\Support\UrlCipherManager}, + * 它封装了单值加解密、开关判断等能力; + * 底层加解密实现默认为 {@see \Dcat\Admin\Support\CryptCipher} + * (配置盐混淆版,未配置盐时抛异常), + * 可通过配置项 `admin.route.cipher` 指定自定义 {@see \Dcat\Admin\Contracts\UrlCipher} 实现。 + */ + protected function registerUrlCipher() + { + $this->app->singleton('admin.cipher', function ($app) { + $class = config('admin.route.cipher', \Dcat\Admin\Support\CryptCipher::class); + + return new UrlCipherManager($app->make($class)); + }); + + $this->app->alias('admin.cipher', UrlCipherManager::class); } public function registerExtensions() diff --git a/src/Console/stubs/config.stub b/src/Console/stubs/config.stub index 974e6706c..8dd985298 100644 --- a/src/Console/stubs/config.stub +++ b/src/Console/stubs/config.stub @@ -72,6 +72,42 @@ return [ 'namespace' => 'App\\DummyNamespace\\Controllers', 'middleware' => ['web', 'admin'], + + /* + |-------------------------------------------------------------------------- + | 主键加密 + |-------------------------------------------------------------------------- + | + | 开启后,Grid/Form 生成的路径参数中的记录主键会被加密 + | (如 /users/{id}/edit 中的 {id}),请求进入时由 admin.cipher + | 中间件自动解密,控制器拿到的永远是明文主键。 + | + | 仅加密主键;其它查询参数(过滤条件等)保持明文,不做处理。 + | + | encrypt: 是否启用 + | cipher : 加解密实现类,必须实现 \Dcat\Admin\Contracts\UrlCipher + | 当前默认 UuidCipher(AES 伪 UUID 版,密文为 36 位 UUID 格式; + | 仅支持正整数主键,范围 1 ~ 1099511627775(uint40); + | 作用域内嵌密文,从 cipher_salt 派生 AES 密钥) + | 可选 CryptCipher(配置盐混淆版;盐为空会报错) + | cipher_salt : 加解密盐(字符串),用于派生混淆字节流;必须有值,为空会抛异常 + | cipher_magic : UuidCipher 明文块第一字节魔数(默认 "\x02")。可配 int / 0x 十六进制 + | 字符串 / "\x01" 转义字符串,最终归一为单字节;加解密共用该值。 + | 注意:改动它会让旧密文无法解密(解密魔数也会变),如无必要请保持默认。 + | cipher_scopes : (历史兼容,可保留)作用域常量数组扩展,仅旧版 UuidCipher 强制校验 + | 注册用。当前实现不再强制校验作用域范围;作用域必须是 1~2 个可打印 + | ASCII 字符的短标签(如 gi / fo / bo),超长(如 book:grid.id)加密时报错。 + | 以下配置仅为历史兼容保留,可删除 + */ + 'encrypt' => env('ADMIN_ROUTE_ENCRYPT', false), + + 'cipher' => \Dcat\Admin\Support\UuidCipher::class, + + 'cipher_salt' => env('ADMIN_ROUTE_CIPHER_SALT', 'dcat_c'), + + 'cipher_magic' => "\x02", + + 'cipher_scopes' => [], ], /* diff --git a/src/Contracts/UrlCipher.php b/src/Contracts/UrlCipher.php new file mode 100644 index 000000000..594dc6553 --- /dev/null +++ b/src/Contracts/UrlCipher.php @@ -0,0 +1,35 @@ +cipherKey($key); + return rtrim($resourcesPath, '/')."/{$key}/edit"; } @@ -947,12 +949,29 @@ public function getRedirectUrl($key, $redirectTo = null) if ($this->request->get('after-save') == 3) { // view resource + $key = $this->cipherKey($key); + return rtrim($resourcesPath, '/')."/{$key}"; } return $this->request->get(Builder::PREVIOUS_URL_KEY) ?: $this->getCurrentUrl($resourcesPath); } + /** + * 开启路由加密时,对路径参数 key 加密. + * + * @param string|int $key + * @return string + */ + protected function cipherKey(string|int $key) + { + if (! config('admin.route.encrypt', false)) { + return (string) $key; + } + + return (string) admin_cipher_encrypt($key, 'fo'); + } + /** * Check if request is from editable. * diff --git a/src/Form/Builder.php b/src/Form/Builder.php index b72cb5ef1..f9e3434ed 100755 --- a/src/Form/Builder.php +++ b/src/Form/Builder.php @@ -344,7 +344,15 @@ public function action($action = null) } if ($this->isMode(static::MODE_EDIT)) { - return $this->form->resource().'/'.$this->id; + $id = $this->id; + + if ($id === null || $id === '') { + $id = (string) $id; + } elseif (config('admin.route.encrypt', false)) { + $id = admin_cipher_encrypt($id, 'fo'); + } + + return $this->form->resource().'/'.$id; } if ($this->isMode(static::MODE_CREATE)) { diff --git a/src/Form/Tools.php b/src/Form/Tools.php index 94163cac6..12d0e6748 100755 --- a/src/Form/Tools.php +++ b/src/Form/Tools.php @@ -152,6 +152,10 @@ protected function getDeletePath() protected function getViewPath() { if ($key = $this->form->getResourceId()) { + if (config('admin.route.encrypt', false)) { + $key = admin_cipher_encrypt($key, 'fo'); + } + return $this->getListPath().'/'.$key; } diff --git a/src/Grid.php b/src/Grid.php index d0d9d42c1..695321fb1 100755 --- a/src/Grid.php +++ b/src/Grid.php @@ -564,7 +564,44 @@ public function getCreateUrl() */ public function getEditUrl($key) { - return $this->urlWithConstraints("{$this->resource()}/{$key}/edit"); + return $this->urlWithConstraints($this->makeActionUrl("{$this->resource()}/{key}/edit", $key)); + } + + /** + * 生成带路径参数加密的 action URL. + * + * @param string $urlTemplate 含 {key} 占位符的 URL 模板 + * @param string|int $key + * @return string + */ + protected function makeActionUrl(string $urlTemplate, string|int $key) + { + $key = $this->cipherKey($key); + + return str_replace('{key}', (string) $key, $urlTemplate); + } + + /** + * 开启路由加密时,对路径参数 key 加密. + * + * @param string|int $key + * @return string|int + */ + protected function cipherKey(string|int $key) + { + if (! $this->cipherEnabled()) { + return $key; + } + + return admin_cipher_encrypt($key, 'gi'); + } + + /** + * @return bool + */ + protected function cipherEnabled() + { + return (bool) config('admin.route.encrypt', false); } /** diff --git a/src/Grid/Actions/Delete.php b/src/Grid/Actions/Delete.php index c10ec4708..f29cb1dc5 100644 --- a/src/Grid/Actions/Delete.php +++ b/src/Grid/Actions/Delete.php @@ -22,7 +22,6 @@ public function render() { $this->setHtmlAttribute([ 'data-url' => $this->url(), - 'data-message' => "ID - {$this->getKey()}", 'data-action' => 'delete', 'data-redirect' => $this->redirectUrl(), ]); @@ -37,6 +36,12 @@ protected function redirectUrl() public function url() { - return "{$this->resource()}/{$this->getKey()}"; + $key = $this->getKey(); + + if (config('admin.route.encrypt', false)) { + $key = admin_cipher_encrypt($key, 'gi'); + } + + return "{$this->resource()}/{$key}"; } } diff --git a/src/Grid/Actions/Show.php b/src/Grid/Actions/Show.php index 8531c5dc3..acd960825 100644 --- a/src/Grid/Actions/Show.php +++ b/src/Grid/Actions/Show.php @@ -23,6 +23,12 @@ public function title() */ public function href() { - return $this->parent->urlWithConstraints("{$this->resource()}/{$this->getKey()}"); + $key = $this->getKey(); + + if (config('admin.route.encrypt', false)) { + $key = admin_cipher_encrypt($key, 'gi'); + } + + return $this->parent->urlWithConstraints("{$this->resource()}/{$key}"); } } diff --git a/src/Grid/Displayers/AbstractDisplayer.php b/src/Grid/Displayers/AbstractDisplayer.php index 816cba82c..ef62c83d9 100755 --- a/src/Grid/Displayers/AbstractDisplayer.php +++ b/src/Grid/Displayers/AbstractDisplayer.php @@ -116,6 +116,36 @@ public function resource() return $this->grid->resource(); } + /** + * 获取当前行主键(若开启路由加密则返回密文). + * + * @return string + */ + public function cipherKey() + { + $key = $this->getKey(); + + if ($key === null || $key === '') { + return (string) $key; + } + + if (config('admin.route.encrypt', false)) { + return admin_cipher_encrypt($key, 'gi'); + } + + return (string) $key; + } + + /** + * 生成当前行的资源 URL(路径参数主键自动加密). + * + * @return string + */ + public function cipherUrl() + { + return $this->resource().'/'.$this->cipherKey(); + } + /** * Get translation. * diff --git a/src/Grid/Displayers/Editable.php b/src/Grid/Displayers/Editable.php index 50dec58a8..0378a0f5f 100644 --- a/src/Grid/Displayers/Editable.php +++ b/src/Grid/Displayers/Editable.php @@ -64,6 +64,6 @@ protected function getSelector() protected function getUrl() { - return $this->resource().'/'.$this->getKey(); + return $this->cipherUrl(); } } diff --git a/src/Grid/Displayers/Orderable.php b/src/Grid/Displayers/Orderable.php index 977767e68..d5805debe 100644 --- a/src/Grid/Displayers/Orderable.php +++ b/src/Grid/Displayers/Orderable.php @@ -14,13 +14,21 @@ public function display() { Admin::script($this->script()); + $key = $this->getKey(); + + if ($key === null || $key === '') { + $key = (string) $key; + } elseif (config('admin.route.encrypt', false)) { + $key = admin_cipher_encrypt($key, 'gi'); + } + return << - +   - +
diff --git a/src/Grid/Displayers/Select.php b/src/Grid/Displayers/Select.php index 5f369280b..40d590cd8 100755 --- a/src/Grid/Displayers/Select.php +++ b/src/Grid/Displayers/Select.php @@ -15,14 +15,9 @@ public function display($options = [], $refresh = false) return Admin::view('admin::grid.displayer.select', [ 'column' => $this->column->getName(), 'value' => $this->value, - 'url' => $this->url(), + 'url' => $this->cipherUrl(), 'options' => $options, 'refresh' => $refresh, ]); } - - protected function url() - { - return $this->resource().'/'.$this->getKey(); - } } diff --git a/src/Grid/Displayers/SwitchDisplay.php b/src/Grid/Displayers/SwitchDisplay.php index af0fa881e..821a19fb4 100755 --- a/src/Grid/Displayers/SwitchDisplay.php +++ b/src/Grid/Displayers/SwitchDisplay.php @@ -24,16 +24,11 @@ public function display(string $color = '', $refresh = false) $column = $this->column->getName(); $checked = $this->value ? 'checked' : ''; $color = $this->color ?: Admin::color()->primary(); - $url = $this->url(); + $url = $this->cipherUrl(); return Admin::view( 'admin::grid.displayer.switch', compact('column', 'color', 'refresh', 'checked', 'url') ); } - - protected function url() - { - return $this->resource().'/'.$this->getKey(); - } } diff --git a/src/Grid/Displayers/SwitchGroup.php b/src/Grid/Displayers/SwitchGroup.php index f1adbf23c..7385e4303 100755 --- a/src/Grid/Displayers/SwitchGroup.php +++ b/src/Grid/Displayers/SwitchGroup.php @@ -24,9 +24,17 @@ public function display($columns = [], $color = '', $refresh = false) $color = $this->color ?: Admin::color()->primary(); + $key = $this->getKey(); + + if ($key === null || $key === '') { + $key = (string) $key; + } elseif (config('admin.route.encrypt', false)) { + $key = admin_cipher_encrypt($key, 'gi'); + } + return Admin::view('admin::grid.displayer.switchgroup', [ 'row' => $this->row->toArray(), - 'key' => $this->getKey(), + 'key' => $key, 'columns' => $columns, 'resource' => $this->resource(), 'color' => $color, diff --git a/src/Http/Controllers/AdminController.php b/src/Http/Controllers/AdminController.php index 5a4989861..efaced22b 100644 --- a/src/Http/Controllers/AdminController.php +++ b/src/Http/Controllers/AdminController.php @@ -43,6 +43,22 @@ protected function title() return $this->title ?: admin_trans_label(); } + /** + * 获取 URL 主键加密的最终作用域(cipherScope 属性). + * + * 子类可定义 protected $cipherScope 来直接指定该控制器 URL 加密使用的最终作用域 + * (如 'bo',不再拼接前缀/合成)。不再强制校验作用域注册,但要求 + * 值为 1~2 个可打印 ASCII 字符(超长如 'book:grid.id' 加密时报错)—— + * 加密时该值整体作为密文标签(1~2 个可打印 ASCII 字符,超出会抛异常)。 + * 外部访问走此 getter(避免直接读 protected 属性触发 PHP 可见性错误). + * + * @return string|null + */ + public function cipherScope() + { + return empty($this->cipherScope) ? null : (string) $this->cipherScope; + } + /** * Get description for following 4 action pages. * diff --git a/src/Http/Controllers/PermissionController.php b/src/Http/Controllers/PermissionController.php index 67d1bb164..ff1e860aa 100644 --- a/src/Http/Controllers/PermissionController.php +++ b/src/Http/Controllers/PermissionController.php @@ -82,13 +82,18 @@ protected function treeView() public function form() { + // 捕获控制器引用:表单事件(saved/saving 等)闭包会被 bind 到模型, + // 直接写 $this 会变成 Permission::xxx() 导致 undefined method; + // 通过 use 捕获的 $controller 始终指向控制器实例。 + $controller = $this; + $with = []; if ($bindMenu = config('admin.menu.permission_bind_menu', true)) { $with[] = 'menus'; } - return Form::make(Permission::with($with), function (Form $form) use ($bindMenu) { + return Form::make(Permission::with($with), function (Form $form) use ($bindMenu, $controller) { $permissionTable = config('admin.database.permissions_table'); $connection = config('admin.database.connection'); $permissionModel = config('admin.database.permissions_model'); @@ -125,8 +130,8 @@ public function form() $form->disableViewButton(); $form->disableViewCheck(); - })->saved(function () { - $this->flushMenuCache(); + })->saved(function () use ($controller) { + $controller->flushMenuCache(); }); } diff --git a/src/Http/Controllers/RoleController.php b/src/Http/Controllers/RoleController.php index 86c54f166..b0d19f93c 100644 --- a/src/Http/Controllers/RoleController.php +++ b/src/Http/Controllers/RoleController.php @@ -77,13 +77,18 @@ protected function detail($id) public function form() { + // 捕获控制器引用:表单事件(saved/saving 等)闭包会被 bind 到模型, + // 直接写 $this 会变成 Role::xxx() 导致 undefined method; + // 通过 use 捕获的 $controller 始终指向控制器实例。 + $controller = $this; + $with = ['permissions']; if ($bindMenu = config('admin.menu.role_bind_menu', true)) { $with[] = 'menus'; } - return Form::make(Role::with($with), function (Form $form) use ($bindMenu) { + return Form::make(Role::with($with), function (Form $form) use ($bindMenu, $controller) { $roleTable = config('admin.database.roles_table'); $connection = config('admin.database.connection'); @@ -125,8 +130,8 @@ public function form() if ($id == $roleModel::ADMINISTRATOR_ID) { $form->disableDeleteButton(); } - })->saved(function () { - $this->flushMenuCache(); + })->saved(function () use ($controller) { + $controller->flushMenuCache(); }); } diff --git a/src/Http/Middleware/Cipher.php b/src/Http/Middleware/Cipher.php new file mode 100644 index 000000000..beaeed88f --- /dev/null +++ b/src/Http/Middleware/Cipher.php @@ -0,0 +1,109 @@ +manager = $manager; + } + + public function handle(Request $request, \Closure $next) + { + if (! $this->manager->enabled()) { + return $next($request); + } + + $this->decryptRouteParameters($request); + + return $next($request); + } + + /** + * 从密文提取作用域标签:优先 UuidCipher->peekScope();CryptCipher 密文 + * 走 [scope]: 前缀正则;拿不到返回 null(视为非密文,跳过不处理). + * + * @param string $value + * @return string|null + */ + protected function extractScope(string $value): ?string + { + // CryptCipher 格式:[scope]:payload + if (preg_match('/^\[([^\]]+)\]:/', $value, $m)) { + return $m[1] !== '' ? $m[1] : null; + } + + // UuidCipher 格式:UUID 样式,标签内嵌密文中,需解密才能取 + $cipher = $this->manager->cipher(); + + if (method_exists($cipher, 'peekScope')) { + return $cipher->peekScope($value); + } + + // 无 peekScope 的实现无法自动提标签;不传 key 会破坏必填约束, + // 这里按「非密文」处理(不改动原参数)。 + return null; + } + + /** + * 解密路由路径参数(仅尝试,失败回退明文). + * + * @return void + */ + protected function decryptRouteParameters(Request $request) + { + $route = $request->route(); + + if (! $route) { + return; + } + + $parameters = $route->parameters(); + + // 解密必须用「期望作用域」而不是「密文声称的作用域」: + // 控制器配置了 cipherScope 时,URL 加密也一律用它;解密也只用它, + // 密文标签与它不一致 → 解密失败 → 参数保持密文 → 控制器 find 不到 → 404。 + // 未配置 cipherScope(或闭包路由 / 旧版内置 gi/fo 混合场景)才回退自动提取标签。 + $expected = $this->manager->expectedScope(); + + foreach ($parameters as $key => $value) { + if (! is_string($value) || $value === '') { + continue; + } + + // 解密作用域来源: + // - 有期望 scope(控制器 cipherScope)→ 直接用期望值,与密文标签比对不匹配即失败; + // - 无期望 scope(未配置 / 闭包路由)→ 手动从密文提取标签(UuidCipher 内嵌 2 字节 / + // CryptCipher [scope]: 前缀)自动解密。 + // 两种方式都满足「加解密都必传 scope」;前者更加严格(防跨场景重放)。 + $scope = $expected ?? $this->extractScope($value); + + if ($scope === null) { + continue; // 非密文(如手工输入 /users/42),不处理 + } + + $plain = $this->manager->decrypt($value, $scope); + + if ($plain !== null) { + $route->setParameter($key, $plain); + } + } + } +} \ No newline at end of file diff --git a/src/Show/Tools.php b/src/Show/Tools.php index bcddd89a0..ebd85002f 100755 --- a/src/Show/Tools.php +++ b/src/Show/Tools.php @@ -221,6 +221,10 @@ protected function getEditPath() { $key = $this->panel->parent()->getKey(); + if (config('admin.route.encrypt', false)) { + $key = admin_cipher_encrypt($key, 'gi'); + } + return $this->getListPath().'/'.$key.'/edit'; } @@ -233,6 +237,10 @@ protected function getDeletePath() { $key = $this->panel->parent()->getKey(); + if (config('admin.route.encrypt', false)) { + $key = admin_cipher_encrypt($key, 'gi'); + } + return $this->getListPath().'/'.$key; } diff --git a/src/Support/CryptCipher.php b/src/Support/CryptCipher.php new file mode 100644 index 000000000..35a210871 --- /dev/null +++ b/src/Support/CryptCipher.php @@ -0,0 +1,137 @@ + + * + * - scope 前缀同时充当「密文标识」:只有带 [xxx]: 前缀的值才会被尝试解密, + * 纯明文 URL(如手工输入 /users/42)不会落入解密逻辑,避免误伤; + * - cipher_salt 为必填项:未配置或为空时抛异常(防误用); + * - payload = hex(明文逐字节 XOR 派生密钥),URL 安全、无 base64。 + * + * 派生密钥:sha256(cipher_salt . '|' . scope) + * - 同一 cipher_salt 下不同 scope 使用不同字节流,隔离使用场景; + * - 切换 cipher_salt 后,旧链接将无法解密(属预期)。 + * + * 注意:本实现不设主键上限(非负 int 即可);未做防篡改校验(无完整性位), + * 适合追求简单轻量的场景;默认实现是 {@see UuidCipher},本类需在 + * config('admin.route.cipher') 显式指定。 + */ +class CryptCipher implements UrlCipher +{ + /** + * {@inheritdoc} + */ + public function encrypt(int $plain, string $key): string + { + // 作用域由类型系统强制必填(string $key) + $salt = $this->salt(); + + $payload = $this->obfuscate((string) $plain, $salt, $key); + + return '['.$key.']:'.$payload; + } + + /** + * {@inheritdoc} + * + * - 无 [scope]: 前缀的值视为非密文,直接返回 null(不尝试解密); + * - 作用域 `$key` **必填**(类型声明 `string`):缺参 / 传 `null` → PHP `TypeError`; + * - 严格校验作用域前缀,与传入 `$key` 不匹配返回 null。 + */ + public function decrypt(string $cipher, string $key): ?string + { + // 作用域由类型系统强制必填(string $key);随后与密文前缀比对,不匹配返回 null + + // 提取作用域前缀;无前缀视为非密文 + if (! preg_match('/^\[([^\]]+)\]:/', $cipher, $m)) { + return null; + } + + if ($key !== $m[1]) { + return null; + } + + $key = $m[1]; + $payload = substr($cipher, strlen($m[0])); + + return $this->deobfuscate($payload, $this->salt(), $key); + } + + /** + * 读取配置盐;必须配置,为空抛异常. + * + * @return string + * + * @throws \RuntimeException + */ + protected function salt(): string + { + $salt = (string) config('admin.route.cipher_salt', ''); + + if ($salt === '') { + throw new \RuntimeException('admin.route.cipher_salt 未配置或为空,请设置 cipher_salt(如 ADMIN_ROUTE_CIPHER_SALT=xxx)'); + } + + return $salt; + } + + /** + * 混淆:明文逐字节 XOR 派生密钥,再转 hex. + * + * @param string $plain + * @param string $salt + * @param string $key + * @return string + */ + protected function obfuscate(string $plain, string $salt, string $key): string + { + $derived = hash('sha256', $salt.'|'.$key, true); + + $out = ''; + $len = strlen($plain); + + for ($i = 0; $i < $len; $i++) { + $out .= $plain[$i] ^ $derived[$i % 32]; + } + + return bin2hex($out); + } + + /** + * 反混淆:hex 还原后逐字节 XOR 派生密钥;格式非法返回 null. + * + * @param string $payload + * @param string $salt + * @param string $key + * @return string|null + */ + protected function deobfuscate(string $payload, string $salt, string $key): ?string + { + if ($payload === '' || strlen($payload) % 2 !== 0 || ! ctype_xdigit($payload)) { + return null; + } + + $raw = hex2bin($payload); + + if ($raw === false) { + return null; + } + + $derived = hash('sha256', $salt.'|'.$key, true); + + $out = ''; + $len = strlen($raw); + + for ($i = 0; $i < $len; $i++) { + $out .= $raw[$i] ^ $derived[$i % 32]; + } + + return $out; + } +} \ No newline at end of file diff --git a/src/Support/UrlCipherManager.php b/src/Support/UrlCipherManager.php new file mode 100644 index 000000000..eac289833 --- /dev/null +++ b/src/Support/UrlCipherManager.php @@ -0,0 +1,204 @@ +encrypt(42, 'gi'); // 无 cipherScope → gi + * // cipherScope='bo' → bo(覆盖为控制器标签) + * $dec = $manager->decrypt($enc, 'bo'); // 解密必传 scope,需与加密时一致 + */ +class UrlCipherManager +{ + /** + * @var UrlCipher + */ + protected $cipher; + + public function __construct(UrlCipher $cipher) + { + $this->cipher = $cipher; + } + + /** + * 获取底层 cipher 实现(供中间件等读取作用域标签). + * + * @return \Dcat\Admin\Contracts\UrlCipher + */ + public function cipher(): UrlCipher + { + return $this->cipher; + } + + /** + * 加密主键值(仅支持 int;scope 可空). + * + * 若当前控制器显式配置了 cipherScope,其属性值 **直接作为最终作用域** + * (不再做 {前缀}:{scope} 拼接);否则使用传入的 $key 原样(如 gi / fo)。 + * 底层 UuidCipher 要求作用域为 1~2 个可打印 ASCII 字符(短标签), + * 超长(如完整作用域 grid.id / book:grid.id)加密时会抛异常;CryptCipher 另按其规则。 + * + * @param int $plain + * @param string $key 调用点作用域短标签(如 gi / fo),cipherScope 未配置时使用 + * @return string + */ + public function encrypt(int $plain, string $key): string + { + $identity = $this->resolveDefaultScope(); + + // 方案 D:cipherScope 就是最终作用域,不合成前缀 + if ($identity !== null) { + $key = $identity; + } + + return $this->cipher->encrypt($plain, $key); + } + + /** + * 解密主键值;失败返回 null. + * + * 作用域 $key 必填(类型 string):解密时校验与密文内嵌标签一致, + * 不一致返回 null(防跨场景重放)。页面访问由中间件提供服务: + * 控制器配置 cipherScope 时以它为唯一可接受作用域,否则自动提取密文标签。 + * + * @param string $cipher + * @param string $key 作用域标识,需与加密时一致 + * @return string|null + */ + public function decrypt(string $cipher, string $key): ?string + { + return $this->cipher->decrypt($cipher, $key); + } + + /** + * 是否启用主键加密(配置开关). + * + * @return bool + */ + public function enabled(): bool + { + return (bool) config('admin.route.encrypt', false); + } + + /** + * 当前控制器期望的作用域(供中间件解密校验使用). + * + * 加密时若控制器配置了 cipherScope,URL 一律用它加密; + * 解密时中间件也应**只用它**去解密(标签不一致 → 解密失败 → 404), + * 而不是用密文自己声称的标签(否则"解密校验作用域"形同虚设)。 + * 未配置 cipherScope / 闭包路由 → 返回 null,中间件回退自动提取标签。 + * + * @return string|null + */ + public function expectedScope(): ?string + { + return $this->resolveDefaultScope(); + } + + /** + * 控制器身份解析: + * 仅使用 $controller->cipherScope(显式配置),无则返回 null(不叠加身份); + * title / 类名均不做兜底. + * 属性为 protected 时通过公开 getter / 反射读取; + * 空串属性视为未配置;任一环节失败 / 无控制器返回 null(不抛异常). + * + * @return string|null + */ + protected function resolveDefaultScope(): ?string + { + $controller = $this->currentController(); + + if (! $controller) { + return null; + } + + // 仅使用显式配置的 cipherScope(优先公开 getter,其次反射读 protected) + $scope = $this->readControllerProperty($controller, 'cipherScope'); + + if ($scope !== null && $scope !== '') { + return (string) $scope; + } + + return null; + } + + /** + * 安全读取控制器属性(兼容 protected/private): + * - 优先调用公开 getter(如 cipherScope()); + * - 无 getter 时用反射读取(不抛异常,读不到返回 null). + * + * @param object $controller + * @param string $property + * @return mixed + */ + protected function readControllerProperty($controller, string $property) + { + if (method_exists($controller, $property)) { + try { + $value = $controller->{$property}(); + + return $value; + } catch (\Throwable $e) { + // 方法抛异常则继续尝试反射 + } + } + + if (! property_exists($controller, $property)) { + return null; + } + + try { + $ref = new \ReflectionProperty($controller, $property); + $ref->setAccessible(true); + + return $ref->getValue($controller); + } catch (\Throwable $e) { + return null; + } + } + + /** + * 获取当前请求路由绑定的控制器实例;拿不到返回 null. + * + * @return object|null + */ + protected function currentController(): ?object + { + if (! function_exists('request')) { + return null; + } + + $route = request()->route(); + + if (! $route) { + return null; + } + + // getController() 可能抛异常(路由尚未绑定 controller / 闭包路由), + // 一律按"无控制器"处理,绝不把异常抛给调用方 + try { + return $route->getController(); + } catch (\Throwable $e) { + return null; + } + } +} \ No newline at end of file diff --git a/src/Support/UuidCipher.php b/src/Support/UuidCipher.php new file mode 100644 index 000000000..f24d682f4 --- /dev/null +++ b/src/Support/UuidCipher.php @@ -0,0 +1,356 @@ + static::MAX_PRIMARY_KEY) { + throw new \InvalidArgumentException('UuidCipher 仅支持 uint40 主键(最大 1099511627775),传入了:'.$plain); + } + + $scopeLabel = $this->scopeLabel((string) $key); + + // 1. 拼 16 字节明文(一个 AES 块) + $plaintext = + $this->magic() // [0] 魔数(默认 0x02,可配置) + .str_pad($scopeLabel, 2, "\x00", STR_PAD_RIGHT) // [1..2] 作用域短标签(右补 0) + ."\x00\x00\x00\x00\x00\x00\x00\x00" // [3..10] 填充 8 字节 + .chr(($plain >> 32) & 0xFF) // [11] 主键第 1 字节(最高) + .chr(($plain >> 24) & 0xFF) // [12] 主键第 2 字节 + .chr(($plain >> 16) & 0xFF) // [13] 主键第 3 字节 + .chr(($plain >> 8) & 0xFF) // [14] 主键第 4 字节 + .chr($plain & 0xFF); // [15] 主键第 5 字节(最低) + + // 2. AES-256-ECB 加密(数据恰好 16 字节,零填充无副作用) + $cipherRaw = openssl_encrypt($plaintext, 'aes-256-ecb', $this->secret(), OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING); + + if ($cipherRaw === false) { + throw new \RuntimeException('UuidCipher AES 加密失败,请检查 admin.route.cipher_salt 配置'); + } + + // 3. 32 位 hex 统一转大写后按 8-4-4-4-12 拼成 UUID 字符串 + // (bin2hex 原生输出小写;转大写后 URL 与页面显示一致; + // 解密侧 ctype_xdigit / hex2bin 兼容大小写,新旧密文均可解) + $hex = strtoupper(bin2hex($cipherRaw)); + + return implode('-', [ + substr($hex, 0, 8), + substr($hex, 8, 4), + substr($hex, 12, 4), + substr($hex, 16, 4), + substr($hex, 20), + ]); + } + + /** + * {@inheritdoc} + * + * - 作用域 $key **必填**(类型声明 `string`):缺参 / 传 `null` → PHP `TypeError`; + * - 长度非法 / 非 32 hex / 无连字符结构 → 视为非密文,返回 null(明文不误伤); + * - AES 解密失败 → 返回 null(篡改拒绝); + * - 第一个字节必须为配置的魔数(默认 0x02),否则返回 null; + * - 第 2-3 字节读出作用域标签,必须与传入的 $key 一致,否则返回 null; + * - 主键必须为正整数(> 0),否则返回 null; + * - 成功返回明文主键字符串。 + */ + public function decrypt(string $cipher, string $key): ?string + { + // 作用域由类型系统强制必填(string $key),空串在标签比对时自然不匹配返回 null + + // 36 字符是合法 UUID 密文的最大长度,超长值直接视为非密文 + if (strlen($cipher) > 36) { + return null; + } + + $hex = str_replace('-', '', $cipher); + + if ($hex === '' || strlen($hex) !== 32 || ! ctype_xdigit($hex)) { + return null; + } + + $cipherRaw = hex2bin($hex); + + if ($cipherRaw === false || strlen($cipherRaw) !== 16) { + return null; + } + + $decrypted = openssl_decrypt($cipherRaw, 'aes-256-ecb', $this->secret(), OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING); + + if ($decrypted === false || strlen($decrypted) !== 16) { + return null; + } + + // 1. 核心校验:第一个字节必须为配置的魔数(默认 0x02) + if ($decrypted[0] !== $this->magic()) { + return null; + } + + // 2. 校验:第 2-3 字节 = 作用域标签(去掉尾部 \x00) + // 必须与传入的 $key 一致,不匹配直接拒绝(防跨场景重放) + $scopeLabel = rtrim(substr($decrypted, 1, 2), "\x00"); + + if ($scopeLabel === '' || $scopeLabel !== $key) { + return null; + } + + // 3. 主键范围校验:第 11-15 字节就是主键自身的 5 字节大端(uint40) + // 读回后必须为正整数(> 0) + $pkBytes = substr($decrypted, 11, 5); // 最后 5 字节 = 主键 5B BE + $byte = array_values(unpack('C*', $pkBytes)); // 5 个字节,各 8 位 + $plain = ($byte[0] << 32) | ($byte[1] << 24) | ($byte[2] << 16) | ($byte[3] << 8) | $byte[4]; + + if ($plain <= 0) { + return null; + } + + return (string) $plain; + } + + /** + * 作用域标签:作用域本身必须就是 1~2 个【可打印 ASCII 字符】. + * + * 密文第 2-3 字节只放得下 2 字节(1~2 个单字节字符)。 + * 超出 / 多字节(如中文 UTF-8)会静默截断或切半,造成标签碰撞与非法字节, + * 因此这里**严格校验**:不是 1~2 个可打印 ASCII 字符直接抛异常, + * 而不是偷偷截断(如 'grid.id' 7 字符必须改成 'gi' 这类短标签才能加密)。 + * + * 不校验是否「注册」——只要符合长度/字符集约束即可加密; + * 解密侧必须传入与加密一致的 scope,标签不匹配返回 null. + * + * @param string $scope + * @return string 1~2 个可打印 ASCII 字符 + * + * @throws \InvalidArgumentException + */ + protected function scopeLabel(string $scope): string + { + if ($scope === '') { + throw new \InvalidArgumentException('UuidCipher 作用域必填,传入为空'); + } + + if (strlen($scope) > 2 || ! preg_match('/^[\x21-\x7E]+$/', $scope)) { + throw new \InvalidArgumentException( + 'UuidCipher 作用域必须是 1~2 个可打印 ASCII 字符,传入了「'.$scope.'」('.strlen($scope).' 字节)。'.'请使用短标签(如 gi / fo / bo),不要传完整作用域名(如 grid.id / book:grid.id)' + ); + } + + return $scope; + } + + /** + * 提取密文内嵌的作用域标签(供中间件/调用方在解密前确定正确 scope). + * + * 与 decrypt 的区别:不校验传入 scope(其目的就是拿 scope), + * 只在密文合法时返回标签;格式非法 / AES 失败 / 魔数错(非配置值) / 标签空 → 返回 null. + * + * @param string $cipher + * @return string|null 密文内嵌的 1~2 字符标签;非法密文返回 null + */ + public function peekScope(string $cipher): ?string + { + if (strlen($cipher) > 36) { + return null; + } + + $hex = str_replace('-', '', $cipher); + + if ($hex === '' || strlen($hex) !== 32 || ! ctype_xdigit($hex)) { + return null; + } + + $cipherRaw = hex2bin($hex); + + if ($cipherRaw === false || strlen($cipherRaw) !== 16) { + return null; + } + + $decrypted = openssl_decrypt($cipherRaw, 'aes-256-ecb', $this->secret(), OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING); + + if ($decrypted === false || strlen($decrypted) !== 16 || $decrypted[0] !== $this->magic()) { + return null; + } + + $scopeLabel = rtrim(substr($decrypted, 1, 2), "\x00"); + + if ($scopeLabel === '') { + return null; + } + + return $scopeLabel; + } + + /** + * @var string|null 解析后的魔数单字节(首次使用时缓存) + */ + protected ?string $magicKey = null; + + /** + * 解析配置的魔数并缓存(默认 0x02). + * + * 取值 `admin.route.cipher_magic`,支持以下写法(最终归一为单字节字符串): + * - `"\x02"`(PHP 转义字符串,默认写法,作为字面单字节直接使用) + * - `2`(int 十进制)、`0x02`(int 十六进制) + * - `'0x02'` / `'2'`(多字节数字字符串:0x 前缀按十六进制,否则十进制) + * - `"\x01"` 等任意单字节转义字符串(字面使用) + * + * 加解密两侧共用该方法读取同一个魔数:加密写入、解密/peekScope 校验。 + * + * 注意:魔数参与解密校验,改动配置会让旧密文全部无法解密(与新 salt 同理), + * 如无必要请保持默认 `"\x02"`。 + * + * @return string 单字节魔数 + * + * @throws \InvalidArgumentException 配置值无法归一为单个字节(0 ~ 255)时 + */ + protected function magic(): string + { + if ($this->magicKey !== null) { + return $this->magicKey; + } + + $value = config('admin.route.cipher_magic', "\x02"); + + if (is_string($value) && strlen($value) === 1) { + // 单字节字符串(如 "\x02" / 'a'):当作字面字节直接使用 + $this->magicKey = $value; + + return $this->magicKey; + } + + if (is_int($value)) { + $num = $value; + } elseif (is_string($value)) { + $str = trim($value); + if (preg_match('/^0x[0-9a-fA-F]+$/', $str)) { + $num = hexdec(substr($str, 2)); + } elseif (preg_match('/^-?\d+$/', $str)) { + $num = (int) $str; + } else { + throw new \InvalidArgumentException('admin.route.cipher_magic 无法解析:传入了「'.var_export($value, true).'」(支持 int / 0x 十六进制 / 单字节字符串)'); + } + } else { + throw new \InvalidArgumentException('admin.route.cipher_magic 必须是 int 或字符串,传入了:'.gettype($value)); + } + + if ($num < 0 || $num > 255) { + throw new \InvalidArgumentException('admin.route.cipher_magic 必须在 0 ~ 255 之间(单字节),传入了:'.var_export($value, true)); + } + + $this->magicKey = chr($num); + + return $this->magicKey; + } + + /** + * 从配置派生 AES-256 密钥并缓存(PBKDF2-HMAC-SHA256);盐为空抛异常. + * + * @return string 32 字节密钥 + * + * @throws \RuntimeException + */ + protected function secret(): string + { + if ($this->secretKey !== null) { + return $this->secretKey; + } + + $salt = (string) config('admin.route.cipher_salt', ''); + + if ($salt === '') { + throw new \RuntimeException('admin.route.cipher_salt 未配置或为空,请设置 cipher_salt(如 ADMIN_ROUTE_CIPHER_SALT=xxx)'); + } + + $this->secretKey = hash_pbkdf2('sha256', $salt, static::PBKDF2_SALT, static::PBKDF2_ITERATIONS, 32, true); + + return $this->secretKey; + } +} \ No newline at end of file diff --git a/src/Support/helpers.php b/src/Support/helpers.php index 6e5a2da2b..91a6a67f4 100755 --- a/src/Support/helpers.php +++ b/src/Support/helpers.php @@ -273,9 +273,75 @@ function admin_url($path = '', $parameters = [], $secure = null) } } +if (! function_exists('admin_cipher_encrypt')) { + /** + * 加密一个 URL 参数值(仅支持正整数主键). + * + * 强校验: + * - 仅接受正整数 int,0 / 负数一律抛异常(弱类型下字符串会先被 PHP 转 int 再进入); + * - 作用域 $key 必填(缺参/传 null 是 TypeError);空串也会抛异常(防产出无 scope 的密文). + * + * @param int $plain + * @param string $key 作用域标识(如 grid.id / form.id),必填 + * @return string + * + * @throws \InvalidArgumentException 传入非正整数,或未传作用域时抛出 + */ + function admin_cipher_encrypt(int $plain, string $key) + { + if ($plain <= 0) { + throw new \InvalidArgumentException('admin_cipher_encrypt 只支持正整数主键,传入了:'.var_export($plain, true)); + } + + if ($key === '') { + throw new \InvalidArgumentException('admin_cipher_encrypt 必须传入作用域 $key(1~2 个可打印 ASCII 字符,如 gi / fo / bo)'); + } + + return app('admin.cipher')->encrypt($plain, $key); + } +} + +if (! function_exists('admin_cipher_decrypt')) { + /** + * 解密一个 URL 参数值,失败返回 null. + * + * 强校验: + * - 解密结果必须是正整数,0 / 负数 / 非数字一律返回 null(不解密); + * - 作用域 $key 必填(缺参/传 null 是 TypeError,传空串抛 InvalidArgumentException); + * - UuidCipher / CryptCipher 解密时都会校验与密文内嵌 scope 一致,不一致返回 null + * (防跨场景重放);页面访问走中间件,控制器配置 cipherScope 时以它为唯一可接受 + * 作用域,密文标签不一致 → 解密失败 → 404。 + * + * 注:底层 cipher 只会返回纯数字字符串(如 '42'),+0 转 int 后 is_int 恒真; + * 若自定义 cipher 返回了非纯数字(如 '42abc'),PHP 弱类型 +0 会截断为 42, + * 这里一律按「非正整数」处理返回 null(不信任自定义返回). + * + * @param string $cipher + * @param string $key 作用域短标签(1~2 个可打印 ASCII 字符,如 gi / fo / bo),必填;需与加密时的 scope 一致 + * @return string|null + * + * @throws \InvalidArgumentException 未传作用域时抛出 + */ + function admin_cipher_decrypt(string $cipher, string $key): ?string + { + if ($key === '') { + throw new \InvalidArgumentException('admin_cipher_decrypt 必须传入作用域 $key(1~2 个可打印 ASCII 字符,如 gi / fo / bo)'); + } + + $plain = app('admin.cipher')->decrypt($cipher, $key); + + // 解密结果必须为正整数:0 / 负数 / 非数字一律返回 null(不解密) + if ($plain === null || ! is_int($plain + 0) || $plain <= 0) { + return null; + } + + return $plain; + } +} + if (! function_exists('admin_base_path')) { /** - * Get admin url. + * Get admin base path. * * @param string $path * @return string diff --git a/src/Tree/Actions/Delete.php b/src/Tree/Actions/Delete.php index ddff4e718..85ef719b2 100644 --- a/src/Tree/Actions/Delete.php +++ b/src/Tree/Actions/Delete.php @@ -9,12 +9,16 @@ class Delete extends RowAction public function html() { $url = request()->fullUrl(); + $key = $this->getKey(); + + if (config('admin.route.encrypt', false)) { + $key = admin_cipher_encrypt($key, 'gi'); + } return <<  + data-url="{$this->resource()}/{$key}" data-action="delete">  HTML; } } diff --git a/src/Tree/Actions/Edit.php b/src/Tree/Actions/Edit.php index cec63eeda..0b7a85c2b 100644 --- a/src/Tree/Actions/Edit.php +++ b/src/Tree/Actions/Edit.php @@ -8,8 +8,14 @@ class Edit extends RowAction { public function html() { + $key = $this->getKey(); + + if (config('admin.route.encrypt', false)) { + $key = admin_cipher_encrypt($key, 'gi'); + } + return <<  +  HTML; } } diff --git a/src/Tree/Actions/QuickEdit.php b/src/Tree/Actions/QuickEdit.php index d7f23d272..39113c91b 100644 --- a/src/Tree/Actions/QuickEdit.php +++ b/src/Tree/Actions/QuickEdit.php @@ -18,8 +18,14 @@ public function html() ->success('Dcat.reload()') ->dimensions($width, $height); + $key = $this->getKey(); + + if (config('admin.route.encrypt', false)) { + $key = admin_cipher_encrypt($key, 'gi'); + } + return <<  +  HTML; } -} +} \ No newline at end of file